use of org.jf.dexlib2.iface.MethodImplementation in project smali by JesusFreke.
the class ClassPool method internCode.
private void internCode(@Nonnull Method method) {
// this also handles parameter names, which aren't directly tied to the MethodImplementation, even though the debug items are
boolean hasInstruction = false;
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
for (Instruction instruction : methodImpl.getInstructions()) {
hasInstruction = true;
if (instruction instanceof ReferenceInstruction) {
Reference reference = ((ReferenceInstruction) instruction).getReference();
switch(instruction.getOpcode().referenceType) {
case ReferenceType.STRING:
dexPool.stringSection.intern((StringReference) reference);
break;
case ReferenceType.TYPE:
dexPool.typeSection.intern(((TypeReference) reference).getType());
break;
case ReferenceType.FIELD:
dexPool.fieldSection.intern((FieldReference) reference);
break;
case ReferenceType.METHOD:
dexPool.methodSection.intern((MethodReference) reference);
break;
case ReferenceType.CALL_SITE:
dexPool.callSiteSection.intern((CallSiteReference) reference);
break;
default:
throw new ExceptionWithContext("Unrecognized reference type: %d", instruction.getOpcode().referenceType);
}
}
}
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
if (!hasInstruction && tryBlocks.size() > 0) {
throw new ExceptionWithContext("Method %s has no instructions, but has try blocks.", method);
}
for (TryBlock<? extends ExceptionHandler> tryBlock : methodImpl.getTryBlocks()) {
for (ExceptionHandler handler : tryBlock.getExceptionHandlers()) {
dexPool.typeSection.internNullable(handler.getExceptionType());
}
}
}
}
use of org.jf.dexlib2.iface.MethodImplementation in project smali by JesusFreke.
the class ClassPool method internDebug.
private void internDebug(@Nonnull Method method) {
for (MethodParameter param : method.getParameters()) {
String paramName = param.getName();
if (paramName != null) {
dexPool.stringSection.intern(paramName);
}
}
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
for (DebugItem debugItem : methodImpl.getDebugItems()) {
switch(debugItem.getDebugItemType()) {
case DebugItemType.START_LOCAL:
StartLocal startLocal = (StartLocal) debugItem;
dexPool.stringSection.internNullable(startLocal.getName());
dexPool.typeSection.internNullable(startLocal.getType());
dexPool.stringSection.internNullable(startLocal.getSignature());
break;
case DebugItemType.SET_SOURCE_FILE:
dexPool.stringSection.internNullable(((SetSourceFile) debugItem).getSourceFile());
break;
}
}
}
}
use of org.jf.dexlib2.iface.MethodImplementation in project tinker by Tencent.
the class DexDiffDecoder method generateChangedClassesDexFile.
@SuppressWarnings("NewApi")
private void generateChangedClassesDexFile() throws IOException {
final String dexMode = config.mDexRaw ? "raw" : "jar";
List<File> oldDexList = new ArrayList<>();
List<File> newDexList = new ArrayList<>();
for (AbstractMap.SimpleEntry<File, File> oldAndNewDexFilePair : oldAndNewDexFilePairList) {
File oldDexFile = oldAndNewDexFilePair.getKey();
File newDexFile = oldAndNewDexFilePair.getValue();
if (oldDexFile != null) {
oldDexList.add(oldDexFile);
}
if (newDexFile != null) {
newDexList.add(newDexFile);
}
}
DexGroup oldDexGroup = DexGroup.wrap(oldDexList);
DexGroup newDexGroup = DexGroup.wrap(newDexList);
ChangedClassesDexClassInfoCollector collector = new ChangedClassesDexClassInfoCollector();
collector.setExcludedClassPatterns(config.mDexLoaderPattern);
collector.setLogger(dexPatcherLoggerBridge);
collector.setIncludeRefererToRefererAffectedClasses(true);
Set<DexClassInfo> classInfosInChangedClassesDex = collector.doCollect(oldDexGroup, newDexGroup);
Set<Dex> owners = new HashSet<>();
Map<Dex, Set<String>> ownerToDescOfChangedClassesMap = new HashMap<>();
for (DexClassInfo classInfo : classInfosInChangedClassesDex) {
owners.add(classInfo.owner);
Set<String> descOfChangedClasses = ownerToDescOfChangedClassesMap.get(classInfo.owner);
if (descOfChangedClasses == null) {
descOfChangedClasses = new HashSet<>();
ownerToDescOfChangedClassesMap.put(classInfo.owner, descOfChangedClasses);
}
descOfChangedClasses.add(classInfo.classDesc);
}
StringBuilder metaBuilder = new StringBuilder();
int changedDexId = 1;
for (Dex dex : owners) {
Set<String> descOfChangedClassesInCurrDex = ownerToDescOfChangedClassesMap.get(dex);
DexFile dexFile = new DexBackedDexFile(org.jf.dexlib2.Opcodes.forApi(20), dex.getBytes());
boolean isCurrentDexHasChangedClass = false;
for (org.jf.dexlib2.iface.ClassDef classDef : dexFile.getClasses()) {
if (descOfChangedClassesInCurrDex.contains(classDef.getType())) {
isCurrentDexHasChangedClass = true;
break;
}
}
if (!isCurrentDexHasChangedClass) {
continue;
}
DexBuilder dexBuilder = new DexBuilder(Opcodes.forApi(23));
for (org.jf.dexlib2.iface.ClassDef classDef : dexFile.getClasses()) {
if (!descOfChangedClassesInCurrDex.contains(classDef.getType())) {
continue;
}
Logger.d("Class %s will be added into changed classes dex ...", classDef.getType());
List<BuilderField> builderFields = new ArrayList<>();
for (Field field : classDef.getFields()) {
final BuilderField builderField = dexBuilder.internField(field.getDefiningClass(), field.getName(), field.getType(), field.getAccessFlags(), field.getInitialValue(), field.getAnnotations());
builderFields.add(builderField);
}
List<BuilderMethod> builderMethods = new ArrayList<>();
for (Method method : classDef.getMethods()) {
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
methodImpl = new BuilderMutableMethodImplementation(dexBuilder, methodImpl);
}
BuilderMethod builderMethod = dexBuilder.internMethod(method.getDefiningClass(), method.getName(), method.getParameters(), method.getReturnType(), method.getAccessFlags(), method.getAnnotations(), methodImpl);
builderMethods.add(builderMethod);
}
dexBuilder.internClassDef(classDef.getType(), classDef.getAccessFlags(), classDef.getSuperclass(), classDef.getInterfaces(), classDef.getSourceFile(), classDef.getAnnotations(), builderFields, builderMethods);
}
// Write constructed changed classes dex to file and record it in meta file.
String changedDexName = null;
if (changedDexId == 1) {
changedDexName = "classes.dex";
} else {
changedDexName = "classes" + changedDexId + ".dex";
}
final File dest = new File(config.mTempResultDir + "/" + changedDexName);
final FileDataStore fileDataStore = new FileDataStore(dest);
dexBuilder.writeTo(fileDataStore);
final String md5 = MD5.getMD5(dest);
appendMetaLine(metaBuilder, changedDexName, "", md5, md5, 0, 0, 0, dexMode);
++changedDexId;
}
final String meta = metaBuilder.toString();
Logger.d("\nDexDecoder:write changed classes dex meta file data:\n%s", meta);
metaWriter.writeLineToInfoFile(meta);
}
use of org.jf.dexlib2.iface.MethodImplementation in project tinker by Tencent.
the class DexDiffDecoder method checkIfLoaderClassesReferToNonLoaderClasses.
private void checkIfLoaderClassesReferToNonLoaderClasses() throws IOException, TinkerPatchException {
boolean hasInvalidCases = false;
for (File dexFile : oldDexFiles) {
Logger.d("Check if loader classes in " + dexFile.getName() + " refer to any classes that is not in loader class patterns.");
final DexFile dex = DexFileFactory.loadDexFile(dexFile, Opcodes.forApi(29));
for (org.jf.dexlib2.iface.ClassDef classDef : dex.getClasses()) {
final String currClassDesc = classDef.getType();
if (!Utils.isStringMatchesPatterns(currClassDesc, loaderClassPatterns)) {
continue;
}
for (Field field : classDef.getFields()) {
final String currFieldTypeDesc = field.getType();
if (!isReferenceFromLoaderClassValid(currFieldTypeDesc)) {
Logger.e("FATAL: field '%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", field.getName(), currClassDesc, currFieldTypeDesc);
hasInvalidCases = true;
}
}
for (Method method : classDef.getMethods()) {
boolean isCurrentMethodInvalid = false;
final String currMethodRetTypeDesc = method.getReturnType();
if (!isReferenceFromLoaderClassValid(currMethodRetTypeDesc)) {
Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, currMethodRetTypeDesc);
isCurrentMethodInvalid = true;
} else {
for (CharSequence paramTypeDesc : method.getParameterTypes()) {
if (!isReferenceFromLoaderClassValid(paramTypeDesc.toString())) {
Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, paramTypeDesc);
isCurrentMethodInvalid = true;
break;
}
}
}
check_method_impl: {
final MethodImplementation methodImpl = method.getImplementation();
if (methodImpl == null) {
break check_method_impl;
}
final Iterable<? extends Instruction> insns = methodImpl.getInstructions();
if (!insns.iterator().hasNext()) {
break check_method_impl;
}
for (Instruction insn : insns) {
if (insn instanceof ReferenceInstruction) {
final ReferenceInstruction refInsn = (ReferenceInstruction) insn;
switch(refInsn.getReferenceType()) {
case ReferenceType.TYPE:
{
final TypeReference typeRefInsn = (TypeReference) refInsn.getReference();
final String refereeTypeDesc = typeRefInsn.getType();
if (isReferenceFromLoaderClassValid(refereeTypeDesc)) {
break;
}
Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, refereeTypeDesc);
isCurrentMethodInvalid = true;
break;
}
case ReferenceType.FIELD:
{
final FieldReference fieldRefInsn = (FieldReference) refInsn.getReference();
final String refereeFieldName = fieldRefInsn.getName();
final String refereeFieldDefTypeDesc = fieldRefInsn.getDefiningClass();
if (isReferenceFromLoaderClassValid(refereeFieldDefTypeDesc)) {
break;
}
Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to field '%s' in class '%s' which " + "is not in loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, refereeFieldName, refereeFieldDefTypeDesc);
isCurrentMethodInvalid = true;
break;
}
case ReferenceType.METHOD:
{
final MethodReference methodRefInsn = (MethodReference) refInsn.getReference();
final String refereeMethodName = methodRefInsn.getName();
final Collection<? extends CharSequence> refereeMethodParamTypes = methodRefInsn.getParameterTypes();
final String refereeMethodRetType = methodRefInsn.getReturnType();
final String refereeMethodDefClassDesc = methodRefInsn.getDefiningClass();
if (isReferenceFromLoaderClassValid(refereeMethodDefClassDesc)) {
break;
}
Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to method '%s:%s' in class '%s' which " + "is not in loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, refereeMethodName, MethodUtil.getShorty(refereeMethodParamTypes, refereeMethodRetType), refereeMethodDefClassDesc);
isCurrentMethodInvalid = true;
break;
}
default:
{
break;
}
}
}
}
}
if (isCurrentMethodInvalid) {
hasInvalidCases = true;
}
}
}
}
if (hasInvalidCases) {
throw new TinkerPatchException("There are fatal reasons that cause Tinker interrupt" + " patch generating procedure, see logs above.");
}
}
use of org.jf.dexlib2.iface.MethodImplementation in project smali by JesusFreke.
the class InstructionMethodItemTest method testInvalidReference.
@Test
public void testInvalidReference() throws IOException {
Instruction21c instruction = new Instruction21c() {
@Override
public int getRegisterA() {
return 0;
}
@Nonnull
@Override
public Reference getReference() {
return new BaseStringReference() {
@Override
public void validateReference() throws InvalidReferenceException {
throw new InvalidReferenceException("blahblahblah");
}
@Nonnull
@Override
public String getString() {
throw new RuntimeException("invalid reference");
}
};
}
@Override
public int getReferenceType() {
return ReferenceType.STRING;
}
@Override
public Opcode getOpcode() {
return Opcode.CONST_STRING;
}
@Override
public int getCodeUnits() {
return Format.Format21c.size / 2;
}
};
MethodImplementation methodImplementation = new MethodImplementation() {
@Override
public int getRegisterCount() {
return 1;
}
@Nonnull
@Override
public Iterable<? extends Instruction> getInstructions() {
return ImmutableList.of(instruction);
}
@Nonnull
@Override
public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks() {
return ImmutableList.of();
}
@Nonnull
@Override
public Iterable<? extends DebugItem> getDebugItems() {
return ImmutableList.of();
}
};
Method method = new TestMethod(methodImplementation);
ClassDefinition classDefinition = new ClassDefinition(new BaksmaliOptions(), new TestClassDef());
MethodDefinition methodDefinition = new MethodDefinition(classDefinition, method, methodImplementation);
methodDefinition.registerFormatter = new RegisterFormatter(new BaksmaliOptions(), 1, 0);
InstructionMethodItem methodItem = new InstructionMethodItem<Instruction21c>(methodDefinition, 0, instruction);
StringWriter stringWriter = new StringWriter();
BaksmaliWriter writer = new BaksmaliWriter(stringWriter);
methodItem.writeTo(writer);
Assert.assertEquals("#Invalid reference\n#const-string v0, blahblahblah\nnop", stringWriter.toString());
}
Aggregations