From a6bf1ed0fe3a8cf0ffc51d45baf81ec2baee1d6f Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Wed, 9 Sep 2009 06:38:01 +0000 Subject: [PATCH] store types as strings, to allow for intermediate types that don't exist in the dex file git-svn-id: https://smali.googlecode.com/svn/trunk@451 55b6fa8a-2a1e-11de-a435-ffa8d773f76a --- .../java/org/jf/dexlib/Util/DeodexUtil.java | 187 ++++++++---------- .../java/org/jf/dexlib/Util/Deodexerant.java | 80 ++++---- 2 files changed, 121 insertions(+), 146 deletions(-) diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java b/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java index 1f9f8f0d..6b7250cd 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/DeodexUtil.java @@ -262,7 +262,8 @@ public class DeodexUtil { insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); assert nextInstruction != null; if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { - nextInstruction.registerReferenceType = inlineMethod.methodIdItem.getPrototype().getReturnType(); + nextInstruction.registerReferenceType = + inlineMethod.methodIdItem.getPrototype().getReturnType().getTypeDescriptor(); } return true; @@ -296,7 +297,7 @@ public class DeodexUtil { return false; } - TypeIdItem type = i.registerTypes[registerNum]; + String type = i.registerTypes[registerNum]; if (type == null) { return false; } @@ -304,7 +305,7 @@ public class DeodexUtil { FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); if (field == null) { throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + - " for class: " + type.getTypeDescriptor()); + " for class: " + type); } String fieldType = field.getFieldType().getTypeDescriptor(); @@ -358,7 +359,7 @@ public class DeodexUtil { return false; } - TypeIdItem type = i.registerTypes[registerNum]; + String type = i.registerTypes[registerNum]; if (type == null) { return false; } @@ -366,7 +367,7 @@ public class DeodexUtil { FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); if (field == null) { throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + - " for class: " + type.getTypeDescriptor()); + " for class: " + type); } assert field.getFieldType().getTypeDescriptor().charAt(0) == 'J' || @@ -399,7 +400,7 @@ public class DeodexUtil { return false; } - TypeIdItem type = i.registerTypes[registerNum]; + String type = i.registerTypes[registerNum]; if (type == null) { return false; } @@ -407,7 +408,7 @@ public class DeodexUtil { FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); if (field == null) { throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + - " for class: " + type.getTypeDescriptor()); + " for class: " + type); } assert field.getFieldType().getTypeDescriptor().charAt(0) == 'L' || @@ -415,7 +416,7 @@ public class DeodexUtil { i.fixedInstruction = new Instruction22csf(Opcode.IGET_OBJECT, (Instruction22cs)i.instruction, field); - i.updateRegisterReferenceType(field.getFieldType()); + i.updateRegisterReferenceType(field.getFieldType().getTypeDescriptor()); return true; } case IPUT_QUICK: @@ -442,7 +443,7 @@ public class DeodexUtil { return false; } - TypeIdItem type = i.registerTypes[registerNum]; + String type = i.registerTypes[registerNum]; if (type == null) { return false; } @@ -450,7 +451,7 @@ public class DeodexUtil { FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); if (field == null) { throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + - " for class: " + type.getTypeDescriptor()); + " for class: " + type); } String fieldType = field.getFieldType().getTypeDescriptor(); @@ -504,7 +505,7 @@ public class DeodexUtil { return false; } - TypeIdItem type = i.registerTypes[registerNum]; + String type = i.registerTypes[registerNum]; if (type == null) { return false; } @@ -512,7 +513,7 @@ public class DeodexUtil { FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); if (field == null) { throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + - " for class: " + type.getTypeDescriptor()); + " for class: " + type); } assert field.getFieldType().getTypeDescriptor().charAt(0) == 'J' || @@ -546,7 +547,7 @@ public class DeodexUtil { return false; } - TypeIdItem type = i.registerTypes[registerNum]; + String type = i.registerTypes[registerNum]; if (type == null) { return false; } @@ -554,7 +555,7 @@ public class DeodexUtil { FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); if (field == null) { throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + - " for class: " + type.getTypeDescriptor()); + " for class: " + type); } assert field.getFieldType().getTypeDescriptor().charAt(0) == 'L' || @@ -588,7 +589,7 @@ public class DeodexUtil { return false; } - TypeIdItem type = i.registerTypes[registerNum]; + String type = i.registerTypes[registerNum]; if (type == null) { return false; } @@ -596,7 +597,7 @@ public class DeodexUtil { MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), false); if (method == null) { throw new RuntimeException("Could not find the virtual method with vtable index " + - ins.getMethodIndex() + " for class: " + type.getTypeDescriptor()); + ins.getMethodIndex() + " for class: " + type); } i.fixedInstruction = new Instruction35msf(Opcode.INVOKE_VIRTUAL, (Instruction35ms)i.instruction, @@ -605,7 +606,8 @@ public class DeodexUtil { insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); assert nextInstruction != null; if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { - nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); + nextInstruction.updateRegisterReferenceType( + method.getPrototype().getReturnType().getTypeDescriptor()); } return true; } @@ -633,7 +635,7 @@ public class DeodexUtil { return false; } - TypeIdItem type = i.registerTypes[registerNum]; + String type = i.registerTypes[registerNum]; if (type == null) { return false; } @@ -641,7 +643,7 @@ public class DeodexUtil { MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), false); if (method == null) { throw new RuntimeException("Could not find the virtual method with vtable index " + - ins.getMethodIndex() + " for class: " + type.getTypeDescriptor()); + ins.getMethodIndex() + " for class: " + type); } i.fixedInstruction = new Instruction3rmsf(Opcode.INVOKE_VIRTUAL_RANGE, (Instruction3rms)i.instruction, @@ -650,7 +652,8 @@ public class DeodexUtil { insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); assert nextInstruction != null; if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { - nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); + nextInstruction.updateRegisterReferenceType( + method.getPrototype().getReturnType().getTypeDescriptor()); } return true; } @@ -678,7 +681,7 @@ public class DeodexUtil { return false; } - TypeIdItem type = i.registerTypes[registerNum]; + String type = i.registerTypes[registerNum]; if (type == null) { return false; } @@ -686,7 +689,7 @@ public class DeodexUtil { MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), true); if (method == null) { throw new RuntimeException("Could not find the super method with vtable index " + - ins.getMethodIndex() + " for class: " + type.getTypeDescriptor()); + ins.getMethodIndex() + " for class: " + type); } i.fixedInstruction = new Instruction35msf(Opcode.INVOKE_SUPER, (Instruction35ms)i.instruction, @@ -695,7 +698,8 @@ public class DeodexUtil { insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); assert nextInstruction != null; if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { - nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); + nextInstruction.updateRegisterReferenceType( + method.getPrototype().getReturnType().getTypeDescriptor()); } return true; } @@ -723,7 +727,7 @@ public class DeodexUtil { return false; } - TypeIdItem type = i.registerTypes[registerNum]; + String type = i.registerTypes[registerNum]; if (type == null) { return false; } @@ -731,7 +735,7 @@ public class DeodexUtil { MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), true); if (method == null) { throw new RuntimeException("Could not find the super method with vtable index " + - ins.getMethodIndex() + " for class: " + type.getTypeDescriptor()); + ins.getMethodIndex() + " for class: " + type); } i.fixedInstruction = new Instruction3rmsf(Opcode.INVOKE_SUPER_RANGE, (Instruction3rms)i.instruction, @@ -740,7 +744,8 @@ public class DeodexUtil { insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); assert nextInstruction != null; if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { - nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); + nextInstruction.updateRegisterReferenceType( + method.getPrototype().getReturnType().getTypeDescriptor()); } return true; } @@ -826,7 +831,7 @@ public class DeodexUtil { * if setsRegister is true, and the register type is a reference, this is the * reference type of the register, or null if not known yet. */ - public TypeIdItem registerReferenceType; + public String registerReferenceType; /** * Stores a "fake" fixed instruction, which is included in the instruction list that deodexerizeCode produces @@ -856,7 +861,7 @@ public class DeodexUtil { public boolean fixed = false; public final RegisterType[] registerMap; - public final TypeIdItem[] registerTypes; + public final String[] registerTypes; public insn(CodeItem codeItem, Instruction instruction, SparseArray insnsMap, int offset) { this.codeItem = codeItem; @@ -889,7 +894,7 @@ public class DeodexUtil { } registerMap = new RegisterType[codeItem.getRegisterCount()]; - registerTypes = new TypeIdItem[codeItem.getRegisterCount()]; + registerTypes = new String[codeItem.getRegisterCount()]; for (int i=0; i exceptionTypes = new ArrayList(1); + List exceptionTypes = new ArrayList(1); for (CodeItem.TryItem tryItem: codeItem.getTries()) { if (tryItem.encodedCatchHandler.catchAllHandlerAddress == this.offset) { //if this is a catch all handler, the only possible type is Ljava/lang/Throwable; - registerReferenceType = TypeIdItem.getInternedTypeIdItem(codeItem.getDexFile(), - "Ljava/lang/Throwable;"); + registerReferenceType = "Ljava/lang/Throwable;"; //it's possible that Ljava/lang/Throwable; hasn't be interned into the dex file. since //we've turned off interning for the current dex file, we will just get a null back. @@ -1130,7 +1134,7 @@ public class DeodexUtil { for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) { if (handler.handlerAddress == this.offset) { - exceptionTypes.add(handler.exceptionType); + exceptionTypes.add(handler.exceptionType.getTypeDescriptor()); } } } @@ -1174,8 +1178,7 @@ public class DeodexUtil { setsRegister = true; registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); registerType = RegisterType.Reference; - registerReferenceType = TypeIdItem.getInternedTypeIdItem(this.codeItem.getDexFile(), - "Ljava/lang/String;"); + registerReferenceType = "Ljava/lang/String;"; break; } case CONST_CLASS: @@ -1183,8 +1186,7 @@ public class DeodexUtil { setsRegister = true; registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); registerType = RegisterType.Reference; - registerReferenceType = TypeIdItem.getInternedTypeIdItem(this.codeItem.getDexFile(), - "Ljava/lang/Class;"); + registerReferenceType = "Ljava/lang/Class;"; break; } case CHECK_CAST: @@ -1194,7 +1196,8 @@ public class DeodexUtil { setsRegister = true; registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); registerType = RegisterType.Reference; - registerReferenceType = (TypeIdItem)((InstructionWithReference)instruction).getReferencedItem(); + registerReferenceType = + ((TypeIdItem)((InstructionWithReference)instruction).getReferencedItem()).getTypeDescriptor(); break; } case IGET_OBJECT: @@ -1204,7 +1207,7 @@ public class DeodexUtil { registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); registerType = RegisterType.Reference; registerReferenceType = ((FieldIdItem)((InstructionWithReference)instruction).getReferencedItem()) - .getFieldType(); + .getFieldType().getTypeDescriptor(); break; } } @@ -1214,59 +1217,31 @@ public class DeodexUtil { addSuccessor(getInstructionAtOffset(offset + instruction.getSize()/2)); } - private TypeIdItem findCommonSuperclass(TypeIdItem item1, TypeIdItem item2) { - if (item1 == item2) { - return item1; + private String findCommonSuperclass(String type1, String type2) { + if (type1 == null) { + return type2; } - if (item1 == null) { - return item2; - } - if (item2 == null) { - return item1; - } - - String superclass = - deodexerant.lookupCommonSuperclass(item1.getTypeDescriptor(), item2.getTypeDescriptor()); - - TypeIdItem superType = TypeIdItem.getInternedTypeIdItem(codeItem.getDexFile(), superclass); - //if the class isn't interned, let's see if we can find a superclass that is interned. This should be safe - //because there should be no fields or methods specific to this type being referenced.. otherwise it would - //already be interned - //TODO: array types need to be handled correctly - while (superType == null && superclass != null) { - superclass = deodexerant.lookupSuperclass(superclass); - if (superclass != null) { - superType = TypeIdItem.getInternedTypeIdItem(codeItem.getDexFile(), superclass); - } - } - //we might not find anything. if so, just return null. This should be ok, due to the same reasoning as - //above - return superType; - } - - private TypeIdItem findCommonSuperclass(List exceptionTypes) { - assert exceptionTypes.size() > 1; - - String superclass = exceptionTypes.get(0).getTypeDescriptor(); - - for (int i=1; i exceptionTypes) { + assert exceptionTypes.size() > 1; + + String supertype = exceptionTypes.get(0); + + for (int i=1; i vtableMap = new HashMap(); + private final HashMap vtableMap = new HashMap(); private final HashMap cachedCommonSuperclassLookup = new HashMap(); private InlineMethod[] inlineMethods; @@ -101,13 +101,7 @@ public class Deodexerant { String methodParams = m.group(3); String methodRet = m.group(4); - TypeIdItem classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, classType); - if (classTypeItem == null) { - inlineMethods[i] = null; - continue; - } - - MethodIdItem method = parseAndResolveMethod(classTypeItem, methodName, methodParams, methodRet); + MethodIdItem method = parseAndResolveMethod(classType, methodName, methodParams, methodRet); if (method == null) { inlineMethods[i] = null; continue; @@ -129,13 +123,26 @@ public class Deodexerant { return inlineMethods[inlineMethodIndex]; } - public FieldIdItem lookupField(TypeIdItem type, int fieldOffset) { - ClassData classData = getClassData(type); + private TypeIdItem resolveTypeOrSupertype(String type) { + TypeIdItem typeItem = TypeIdItem.getInternedTypeIdItem(dexFile, type); + while (typeItem == null) { + type = lookupSuperclass(type); + if (type == null) { + throw new RuntimeException("Could not find the type or a supertype of " + type + " in the dex file"); + } + + typeItem = TypeIdItem.getInternedTypeIdItem(dexFile, type); + } + return typeItem; + } + + public FieldIdItem lookupField(String type, int fieldOffset) { + ClassData classData = getClassData(type); return classData.lookupField(fieldOffset); } - private ClassData getClassData(TypeIdItem type) { + private ClassData getClassData(String type) { ClassData classData = vtableMap.get(type); if (classData == null) { classData = new ClassData(type); @@ -144,22 +151,12 @@ public class Deodexerant { return classData; } - public MethodIdItem lookupVirtualMethod(TypeIdItem type, int methodIndex, boolean lookupSuper) { + public MethodIdItem lookupVirtualMethod(String classType, int methodIndex, boolean lookupSuper) { if (lookupSuper) { - String classType = type.getTypeDescriptor(); - - do - { - classType = lookupSuperclass(type.getTypeDescriptor()); - if (classType == null) { - throw new RuntimeException("Could not find any superclass for type " + type.getTypeDescriptor() + - " in the dex file"); - } - type = TypeIdItem.getInternedTypeIdItem(dexFile, classType); - } while (type == null); + classType = lookupSuperclass(classType); } - ClassData classData = getClassData(type); + ClassData classData = getClassData(classType); return classData.lookupMethod(methodIndex); } @@ -260,8 +257,10 @@ public class Deodexerant { } } - private MethodIdItem parseAndResolveMethod(TypeIdItem classType, String methodName, String methodParams, + private MethodIdItem parseAndResolveMethod(String classType, String methodName, String methodParams, String methodRet) { + TypeIdItem classTypeItem = resolveTypeOrSupertype(classType); + StringIdItem methodNameItem = StringIdItem.getInternedStringIdItem(dexFile, methodName); if (methodNameItem == null) { return null; @@ -347,17 +346,17 @@ public class Deodexerant { MethodIdItem methodIdItem; do { - methodIdItem = MethodIdItem.getInternedMethodIdItem(dexFile, classType, protoItem, methodNameItem); + methodIdItem = MethodIdItem.getInternedMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem); if (methodIdItem != null) { return methodIdItem; } - String superclassDescriptor = lookupSuperclass(classType.getTypeDescriptor()); - classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); + String superclassDescriptor = lookupSuperclass(classTypeItem.getTypeDescriptor()); + classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); - while (classType == null && superclassDescriptor != null) { + while (classTypeItem == null && superclassDescriptor != null) { superclassDescriptor = lookupSuperclass(superclassDescriptor); - classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); + classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); } } while (classType != null); throw new RuntimeException("Could not find method in dex file"); @@ -368,13 +367,14 @@ public class Deodexerant { //private static final Pattern fieldPattern = Pattern.compile("(\\[*L[^;]+;)->([^:]+):(.+)"); - private FieldIdItem parseAndResolveField(TypeIdItem classType, String field) { + private FieldIdItem parseAndResolveField(String classType, String field) { //expecting a string like someField:Lfield/type; String[] parts = field.split(":"); if (parts.length != 2) { throw new RuntimeException("Invalid field descriptor " + field); } + TypeIdItem classTypeItem = resolveTypeOrSupertype(classType); String fieldName = parts[0]; String fieldType = parts[1]; @@ -391,17 +391,17 @@ public class Deodexerant { FieldIdItem fieldIdItem; do { - fieldIdItem = FieldIdItem.getInternedFieldIdItem(dexFile, classType, fieldTypeItem, fieldNameItem); + fieldIdItem = FieldIdItem.getInternedFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem); if (fieldIdItem != null) { return fieldIdItem; } - String superclassDescriptor = lookupSuperclass(classType.getTypeDescriptor()); - classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); + String superclassDescriptor = lookupSuperclass(classTypeItem.getTypeDescriptor()); + classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); - while (classType == null && superclassDescriptor != null) { + while (classTypeItem == null && superclassDescriptor != null) { superclassDescriptor = lookupSuperclass(superclassDescriptor); - classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); + classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); } } while (classType != null); @@ -434,7 +434,7 @@ public class Deodexerant { private class ClassData { - private final TypeIdItem ClassType; + private final String ClassType; private boolean vtableLoaded = false; private String[] methodNames; @@ -447,7 +447,7 @@ public class Deodexerant { private SparseArray resolvedFields; - public ClassData(TypeIdItem classType) { + public ClassData(String classType) { this.ClassType = classType; } @@ -487,7 +487,7 @@ public class Deodexerant { } private void loadvtable() { - List responseLines = sendMultilineCommand("V " + ClassType.getTypeDescriptor()); + List responseLines = sendMultilineCommand("V " + ClassType); methodNames = new String[responseLines.size()]; methodParams = new String[responseLines.size()]; @@ -516,7 +516,7 @@ public class Deodexerant { } private void loadFields() { - List responseLines = sendMultilineCommand("F " + ClassType.getTypeDescriptor()); + List responseLines = sendMultilineCommand("F " + ClassType); instanceFields = new SparseArray(responseLines.size()); resolvedFields = new SparseArray(responseLines.size());