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
This commit is contained in:
JesusFreke@JesusFreke.com
2009-09-09 06:38:01 +00:00
parent c3deed2751
commit a6bf1ed0fe
2 changed files with 121 additions and 146 deletions

View File

@ -262,7 +262,8 @@ public class DeodexUtil {
insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2); insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2);
assert nextInstruction != null; assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.registerReferenceType = inlineMethod.methodIdItem.getPrototype().getReturnType(); nextInstruction.registerReferenceType =
inlineMethod.methodIdItem.getPrototype().getReturnType().getTypeDescriptor();
} }
return true; return true;
@ -296,7 +297,7 @@ public class DeodexUtil {
return false; return false;
} }
TypeIdItem type = i.registerTypes[registerNum]; String type = i.registerTypes[registerNum];
if (type == null) { if (type == null) {
return false; return false;
} }
@ -304,7 +305,7 @@ public class DeodexUtil {
FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset());
if (field == null) { if (field == null) {
throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() +
" for class: " + type.getTypeDescriptor()); " for class: " + type);
} }
String fieldType = field.getFieldType().getTypeDescriptor(); String fieldType = field.getFieldType().getTypeDescriptor();
@ -358,7 +359,7 @@ public class DeodexUtil {
return false; return false;
} }
TypeIdItem type = i.registerTypes[registerNum]; String type = i.registerTypes[registerNum];
if (type == null) { if (type == null) {
return false; return false;
} }
@ -366,7 +367,7 @@ public class DeodexUtil {
FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset());
if (field == null) { if (field == null) {
throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + 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' || assert field.getFieldType().getTypeDescriptor().charAt(0) == 'J' ||
@ -399,7 +400,7 @@ public class DeodexUtil {
return false; return false;
} }
TypeIdItem type = i.registerTypes[registerNum]; String type = i.registerTypes[registerNum];
if (type == null) { if (type == null) {
return false; return false;
} }
@ -407,7 +408,7 @@ public class DeodexUtil {
FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset());
if (field == null) { if (field == null) {
throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + 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' || 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.fixedInstruction = new Instruction22csf(Opcode.IGET_OBJECT, (Instruction22cs)i.instruction, field);
i.updateRegisterReferenceType(field.getFieldType()); i.updateRegisterReferenceType(field.getFieldType().getTypeDescriptor());
return true; return true;
} }
case IPUT_QUICK: case IPUT_QUICK:
@ -442,7 +443,7 @@ public class DeodexUtil {
return false; return false;
} }
TypeIdItem type = i.registerTypes[registerNum]; String type = i.registerTypes[registerNum];
if (type == null) { if (type == null) {
return false; return false;
} }
@ -450,7 +451,7 @@ public class DeodexUtil {
FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset());
if (field == null) { if (field == null) {
throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() +
" for class: " + type.getTypeDescriptor()); " for class: " + type);
} }
String fieldType = field.getFieldType().getTypeDescriptor(); String fieldType = field.getFieldType().getTypeDescriptor();
@ -504,7 +505,7 @@ public class DeodexUtil {
return false; return false;
} }
TypeIdItem type = i.registerTypes[registerNum]; String type = i.registerTypes[registerNum];
if (type == null) { if (type == null) {
return false; return false;
} }
@ -512,7 +513,7 @@ public class DeodexUtil {
FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset());
if (field == null) { if (field == null) {
throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + 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' || assert field.getFieldType().getTypeDescriptor().charAt(0) == 'J' ||
@ -546,7 +547,7 @@ public class DeodexUtil {
return false; return false;
} }
TypeIdItem type = i.registerTypes[registerNum]; String type = i.registerTypes[registerNum];
if (type == null) { if (type == null) {
return false; return false;
} }
@ -554,7 +555,7 @@ public class DeodexUtil {
FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset()); FieldIdItem field = deodexerant.lookupField(type, ins.getFieldOffset());
if (field == null) { if (field == null) {
throw new RuntimeException("Could not find the field with offset " + ins.getFieldOffset() + 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' || assert field.getFieldType().getTypeDescriptor().charAt(0) == 'L' ||
@ -588,7 +589,7 @@ public class DeodexUtil {
return false; return false;
} }
TypeIdItem type = i.registerTypes[registerNum]; String type = i.registerTypes[registerNum];
if (type == null) { if (type == null) {
return false; return false;
} }
@ -596,7 +597,7 @@ public class DeodexUtil {
MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), false); MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), false);
if (method == null) { if (method == null) {
throw new RuntimeException("Could not find the virtual method with vtable index " + 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, 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); insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2);
assert nextInstruction != null; assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); nextInstruction.updateRegisterReferenceType(
method.getPrototype().getReturnType().getTypeDescriptor());
} }
return true; return true;
} }
@ -633,7 +635,7 @@ public class DeodexUtil {
return false; return false;
} }
TypeIdItem type = i.registerTypes[registerNum]; String type = i.registerTypes[registerNum];
if (type == null) { if (type == null) {
return false; return false;
} }
@ -641,7 +643,7 @@ public class DeodexUtil {
MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), false); MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), false);
if (method == null) { if (method == null) {
throw new RuntimeException("Could not find the virtual method with vtable index " + 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, 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); insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2);
assert nextInstruction != null; assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); nextInstruction.updateRegisterReferenceType(
method.getPrototype().getReturnType().getTypeDescriptor());
} }
return true; return true;
} }
@ -678,7 +681,7 @@ public class DeodexUtil {
return false; return false;
} }
TypeIdItem type = i.registerTypes[registerNum]; String type = i.registerTypes[registerNum];
if (type == null) { if (type == null) {
return false; return false;
} }
@ -686,7 +689,7 @@ public class DeodexUtil {
MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), true); MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), true);
if (method == null) { if (method == null) {
throw new RuntimeException("Could not find the super method with vtable index " + 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, 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); insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2);
assert nextInstruction != null; assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); nextInstruction.updateRegisterReferenceType(
method.getPrototype().getReturnType().getTypeDescriptor());
} }
return true; return true;
} }
@ -723,7 +727,7 @@ public class DeodexUtil {
return false; return false;
} }
TypeIdItem type = i.registerTypes[registerNum]; String type = i.registerTypes[registerNum];
if (type == null) { if (type == null) {
return false; return false;
} }
@ -731,7 +735,7 @@ public class DeodexUtil {
MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), true); MethodIdItem method = deodexerant.lookupVirtualMethod(type, ins.getMethodIndex(), true);
if (method == null) { if (method == null) {
throw new RuntimeException("Could not find the super method with vtable index " + 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, 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); insn nextInstruction = i.getInstructionAtOffset(i.offset + i.instruction.getSize()/2);
assert nextInstruction != null; assert nextInstruction != null;
if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) { if (nextInstruction.instruction.opcode == Opcode.MOVE_RESULT_OBJECT) {
nextInstruction.updateRegisterReferenceType(method.getPrototype().getReturnType()); nextInstruction.updateRegisterReferenceType(
method.getPrototype().getReturnType().getTypeDescriptor());
} }
return true; return true;
} }
@ -826,7 +831,7 @@ public class DeodexUtil {
* if setsRegister is true, and the register type is a reference, this is the * 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. * 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 * 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 boolean fixed = false;
public final RegisterType[] registerMap; public final RegisterType[] registerMap;
public final TypeIdItem[] registerTypes; public final String[] registerTypes;
public insn(CodeItem codeItem, Instruction instruction, SparseArray<insn> insnsMap, int offset) { public insn(CodeItem codeItem, Instruction instruction, SparseArray<insn> insnsMap, int offset) {
this.codeItem = codeItem; this.codeItem = codeItem;
@ -889,7 +894,7 @@ public class DeodexUtil {
} }
registerMap = new RegisterType[codeItem.getRegisterCount()]; registerMap = new RegisterType[codeItem.getRegisterCount()];
registerTypes = new TypeIdItem[codeItem.getRegisterCount()]; registerTypes = new String[codeItem.getRegisterCount()];
for (int i=0; i<registerMap.length; i++) { for (int i=0; i<registerMap.length; i++) {
registerMap[i] = RegisterType.Unknown; registerMap[i] = RegisterType.Unknown;
@ -1112,12 +1117,11 @@ public class DeodexUtil {
registerType = RegisterType.Reference; registerType = RegisterType.Reference;
//typically, there will only be a single exception type for a particular handler block, so optimize //typically, there will only be a single exception type for a particular handler block, so optimize
//the array size for that case, but support the case of multiple exception types as well //the array size for that case, but support the case of multiple exception types as well
List<TypeIdItem> exceptionTypes = new ArrayList<TypeIdItem>(1); List<String> exceptionTypes = new ArrayList<String>(1);
for (CodeItem.TryItem tryItem: codeItem.getTries()) { for (CodeItem.TryItem tryItem: codeItem.getTries()) {
if (tryItem.encodedCatchHandler.catchAllHandlerAddress == this.offset) { if (tryItem.encodedCatchHandler.catchAllHandlerAddress == this.offset) {
//if this is a catch all handler, the only possible type is Ljava/lang/Throwable; //if this is a catch all handler, the only possible type is Ljava/lang/Throwable;
registerReferenceType = TypeIdItem.getInternedTypeIdItem(codeItem.getDexFile(), registerReferenceType = "Ljava/lang/Throwable;";
"Ljava/lang/Throwable;");
//it's possible that Ljava/lang/Throwable; hasn't be interned into the dex file. since //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. //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) { for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
if (handler.handlerAddress == this.offset) { if (handler.handlerAddress == this.offset) {
exceptionTypes.add(handler.exceptionType); exceptionTypes.add(handler.exceptionType.getTypeDescriptor());
} }
} }
} }
@ -1174,8 +1178,7 @@ public class DeodexUtil {
setsRegister = true; setsRegister = true;
registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); registerNum = ((SingleRegisterInstruction)instruction).getRegisterA();
registerType = RegisterType.Reference; registerType = RegisterType.Reference;
registerReferenceType = TypeIdItem.getInternedTypeIdItem(this.codeItem.getDexFile(), registerReferenceType = "Ljava/lang/String;";
"Ljava/lang/String;");
break; break;
} }
case CONST_CLASS: case CONST_CLASS:
@ -1183,8 +1186,7 @@ public class DeodexUtil {
setsRegister = true; setsRegister = true;
registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); registerNum = ((SingleRegisterInstruction)instruction).getRegisterA();
registerType = RegisterType.Reference; registerType = RegisterType.Reference;
registerReferenceType = TypeIdItem.getInternedTypeIdItem(this.codeItem.getDexFile(), registerReferenceType = "Ljava/lang/Class;";
"Ljava/lang/Class;");
break; break;
} }
case CHECK_CAST: case CHECK_CAST:
@ -1194,7 +1196,8 @@ public class DeodexUtil {
setsRegister = true; setsRegister = true;
registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); registerNum = ((SingleRegisterInstruction)instruction).getRegisterA();
registerType = RegisterType.Reference; registerType = RegisterType.Reference;
registerReferenceType = (TypeIdItem)((InstructionWithReference)instruction).getReferencedItem(); registerReferenceType =
((TypeIdItem)((InstructionWithReference)instruction).getReferencedItem()).getTypeDescriptor();
break; break;
} }
case IGET_OBJECT: case IGET_OBJECT:
@ -1204,7 +1207,7 @@ public class DeodexUtil {
registerNum = ((SingleRegisterInstruction)instruction).getRegisterA(); registerNum = ((SingleRegisterInstruction)instruction).getRegisterA();
registerType = RegisterType.Reference; registerType = RegisterType.Reference;
registerReferenceType = ((FieldIdItem)((InstructionWithReference)instruction).getReferencedItem()) registerReferenceType = ((FieldIdItem)((InstructionWithReference)instruction).getReferencedItem())
.getFieldType(); .getFieldType().getTypeDescriptor();
break; break;
} }
} }
@ -1214,59 +1217,31 @@ public class DeodexUtil {
addSuccessor(getInstructionAtOffset(offset + instruction.getSize()/2)); addSuccessor(getInstructionAtOffset(offset + instruction.getSize()/2));
} }
private TypeIdItem findCommonSuperclass(TypeIdItem item1, TypeIdItem item2) { private String findCommonSuperclass(String type1, String type2) {
if (item1 == item2) { if (type1 == null) {
return item1; return type2;
} }
if (item1 == null) { if (type2 == null) {
return item2; return type1;
}
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<TypeIdItem> exceptionTypes) {
assert exceptionTypes.size() > 1;
String superclass = exceptionTypes.get(0).getTypeDescriptor();
for (int i=1; i<exceptionTypes.size(); i++) {
superclass = deodexerant.lookupCommonSuperclass(superclass, exceptionTypes.get(i).getTypeDescriptor());
} }
TypeIdItem superType = TypeIdItem.getInternedTypeIdItem(codeItem.getDexFile(), superclass); if (type1.equals(type2)) {
//if the class isn't interned, let's see if we can find a superclass that is interned. This should be safe return type1;
//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 deodexerant.lookupCommonSuperclass(type1, type2);
return superType; }
private String findCommonSuperclass(List<String> exceptionTypes) {
assert exceptionTypes.size() > 1;
String supertype = exceptionTypes.get(0);
for (int i=1; i<exceptionTypes.size(); i++) {
supertype = deodexerant.lookupCommonSuperclass(supertype, exceptionTypes.get(i));
}
return supertype;
} }
private void addSuccessor(insn i) { private void addSuccessor(insn i) {
@ -1281,7 +1256,7 @@ public class DeodexUtil {
} }
} }
private TypeIdItem getReturnType(Instruction instruction) { private String getReturnType(Instruction instruction) {
switch (instruction.opcode) { switch (instruction.opcode) {
case INVOKE_DIRECT: case INVOKE_DIRECT:
case INVOKE_INTERFACE: case INVOKE_INTERFACE:
@ -1294,10 +1269,10 @@ public class DeodexUtil {
case INVOKE_SUPER_RANGE: case INVOKE_SUPER_RANGE:
case INVOKE_VIRTUAL_RANGE: case INVOKE_VIRTUAL_RANGE:
return ((MethodIdItem)((InstructionWithReference)instruction).getReferencedItem()).getPrototype(). return ((MethodIdItem)((InstructionWithReference)instruction).getReferencedItem()).getPrototype().
getReturnType(); getReturnType().getTypeDescriptor();
case FILLED_NEW_ARRAY: case FILLED_NEW_ARRAY:
case FILLED_NEW_ARRAY_RANGE: case FILLED_NEW_ARRAY_RANGE:
return (TypeIdItem)((InstructionWithReference)instruction).getReferencedItem(); return ((TypeIdItem)((InstructionWithReference)instruction).getReferencedItem()).getTypeDescriptor();
} }
return null; return null;
} }
@ -1312,7 +1287,7 @@ public class DeodexUtil {
if ((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue()) == 0) { if ((codeItem.getParent().accessFlags & AccessFlags.STATIC.getValue()) == 0) {
int thisRegister = methodRegisters - paramRegisters - 1; int thisRegister = methodRegisters - paramRegisters - 1;
registerMap[thisRegister] = RegisterType.Reference; registerMap[thisRegister] = RegisterType.Reference;
registerTypes[thisRegister] = method.getContainingClass(); registerTypes[thisRegister] = method.getContainingClass().getTypeDescriptor();
} }
int paramRegister = methodRegisters - paramRegisters; int paramRegister = methodRegisters - paramRegisters;
@ -1336,7 +1311,7 @@ public class DeodexUtil {
case 'L': case 'L':
case '[': case '[':
registerMap[paramRegister] = RegisterType.Reference; registerMap[paramRegister] = RegisterType.Reference;
registerTypes[paramRegister++] = paramType; registerTypes[paramRegister++] = paramType.getTypeDescriptor();
break; break;
default: default:
assert false; assert false;
@ -1352,7 +1327,7 @@ public class DeodexUtil {
} }
} }
public void updateRegisterReferenceType(TypeIdItem type) { public void updateRegisterReferenceType(String type) {
this.registerReferenceType = type; this.registerReferenceType = type;
this.propogateRegisters(); this.propogateRegisters();
} }
@ -1392,9 +1367,9 @@ public class DeodexUtil {
nextInsn.registerMap[i] = regType; nextInsn.registerMap[i] = regType;
} }
if (regType == RegisterType.Reference) { if (regType == RegisterType.Reference) {
TypeIdItem regReferenceType = findCommonSuperclass(registerTypes[i], String regReferenceType = findCommonSuperclass(registerTypes[i],
nextInsn.registerTypes[i]); nextInsn.registerTypes[i]);
if (regReferenceType != nextInsn.registerTypes[i]) { if (!regReferenceType.equals(nextInsn.registerTypes[i])) {
//see comment above for loop //see comment above for loop
if (i == nextInsn.objectRegisterNum) { if (i == nextInsn.objectRegisterNum) {
nextInsn.fixedInstruction = null; nextInsn.fixedInstruction = null;
@ -1413,7 +1388,7 @@ public class DeodexUtil {
} }
if (registerType == RegisterType.Reference) { if (registerType == RegisterType.Reference) {
if (registerReferenceType != null) { if (registerReferenceType != null) {
if (nextInsn.registerTypes[registerNum] != registerReferenceType) { if (!registerReferenceType.equals(nextInsn.registerTypes[registerNum])) {
//see comment above for loop //see comment above for loop
if (registerNum == nextInsn.objectRegisterNum) { if (registerNum == nextInsn.objectRegisterNum) {
nextInsn.fixedInstruction = null; nextInsn.fixedInstruction = null;
@ -1423,8 +1398,11 @@ public class DeodexUtil {
nextInsn.registerTypes[registerNum] = registerReferenceType; nextInsn.registerTypes[registerNum] = registerReferenceType;
} }
} else { } else {
TypeIdItem type = destRegisterType(); String type = destRegisterType();
if (type != nextInsn.registerTypes[registerNum]) { String nextType = nextInsn.registerTypes[registerNum];
if ((type == null && nextType == null) ||
!type.equals(nextInsn.registerTypes[registerNum])) {
//see comment above for loop //see comment above for loop
if (registerNum == nextInsn.objectRegisterNum) { if (registerNum == nextInsn.objectRegisterNum) {
nextInsn.fixedInstruction = null; nextInsn.fixedInstruction = null;
@ -1450,7 +1428,7 @@ public class DeodexUtil {
} }
} }
private TypeIdItem destRegisterType() { private String destRegisterType() {
if (registerReferenceType != null) { if (registerReferenceType != null) {
return registerReferenceType; return registerReferenceType;
} }
@ -1471,16 +1449,13 @@ public class DeodexUtil {
assert registerMap[registerNum] == RegisterType.Reference || assert registerMap[registerNum] == RegisterType.Reference ||
registerMap[registerNum] == RegisterType.Null; registerMap[registerNum] == RegisterType.Null;
TypeIdItem type = registerTypes[registerNum]; String type = registerTypes[registerNum];
if (type == null) { if (type == null) {
return null; return null;
} }
String typeDescriptor = type.getTypeDescriptor(); assert type.charAt(0) == '[';
assert typeDescriptor.charAt(0) == '['; return type.substring(1);
//TODO: probably need to try to lookup the supertype if not found
return TypeIdItem.getInternedTypeIdItem(codeItem.getDexFile(),
typeDescriptor.substring(1));
} }
case MOVE_RESULT_OBJECT: case MOVE_RESULT_OBJECT:
case IGET_OBJECT_QUICK: case IGET_OBJECT_QUICK:

View File

@ -45,7 +45,7 @@ public class Deodexerant {
private final String host; private final String host;
private final int port; private final int port;
private final HashMap<TypeIdItem, ClassData> vtableMap = new HashMap<TypeIdItem, ClassData>(); private final HashMap<String, ClassData> vtableMap = new HashMap<String, ClassData>();
private final HashMap<CommonSuperclassLookup, String> cachedCommonSuperclassLookup = private final HashMap<CommonSuperclassLookup, String> cachedCommonSuperclassLookup =
new HashMap<CommonSuperclassLookup, String>(); new HashMap<CommonSuperclassLookup, String>();
private InlineMethod[] inlineMethods; private InlineMethod[] inlineMethods;
@ -101,13 +101,7 @@ public class Deodexerant {
String methodParams = m.group(3); String methodParams = m.group(3);
String methodRet = m.group(4); String methodRet = m.group(4);
TypeIdItem classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, classType); MethodIdItem method = parseAndResolveMethod(classType, methodName, methodParams, methodRet);
if (classTypeItem == null) {
inlineMethods[i] = null;
continue;
}
MethodIdItem method = parseAndResolveMethod(classTypeItem, methodName, methodParams, methodRet);
if (method == null) { if (method == null) {
inlineMethods[i] = null; inlineMethods[i] = null;
continue; continue;
@ -129,13 +123,26 @@ public class Deodexerant {
return inlineMethods[inlineMethodIndex]; return inlineMethods[inlineMethodIndex];
} }
public FieldIdItem lookupField(TypeIdItem type, int fieldOffset) { private TypeIdItem resolveTypeOrSupertype(String type) {
ClassData classData = getClassData(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); return classData.lookupField(fieldOffset);
} }
private ClassData getClassData(TypeIdItem type) { private ClassData getClassData(String type) {
ClassData classData = vtableMap.get(type); ClassData classData = vtableMap.get(type);
if (classData == null) { if (classData == null) {
classData = new ClassData(type); classData = new ClassData(type);
@ -144,22 +151,12 @@ public class Deodexerant {
return classData; return classData;
} }
public MethodIdItem lookupVirtualMethod(TypeIdItem type, int methodIndex, boolean lookupSuper) { public MethodIdItem lookupVirtualMethod(String classType, int methodIndex, boolean lookupSuper) {
if (lookupSuper) { if (lookupSuper) {
String classType = type.getTypeDescriptor(); classType = lookupSuperclass(classType);
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);
} }
ClassData classData = getClassData(type); ClassData classData = getClassData(classType);
return classData.lookupMethod(methodIndex); 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) { String methodRet) {
TypeIdItem classTypeItem = resolveTypeOrSupertype(classType);
StringIdItem methodNameItem = StringIdItem.getInternedStringIdItem(dexFile, methodName); StringIdItem methodNameItem = StringIdItem.getInternedStringIdItem(dexFile, methodName);
if (methodNameItem == null) { if (methodNameItem == null) {
return null; return null;
@ -347,17 +346,17 @@ public class Deodexerant {
MethodIdItem methodIdItem; MethodIdItem methodIdItem;
do { do {
methodIdItem = MethodIdItem.getInternedMethodIdItem(dexFile, classType, protoItem, methodNameItem); methodIdItem = MethodIdItem.getInternedMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem);
if (methodIdItem != null) { if (methodIdItem != null) {
return methodIdItem; return methodIdItem;
} }
String superclassDescriptor = lookupSuperclass(classType.getTypeDescriptor()); String superclassDescriptor = lookupSuperclass(classTypeItem.getTypeDescriptor());
classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor);
while (classType == null && superclassDescriptor != null) { while (classTypeItem == null && superclassDescriptor != null) {
superclassDescriptor = lookupSuperclass(superclassDescriptor); superclassDescriptor = lookupSuperclass(superclassDescriptor);
classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor);
} }
} while (classType != null); } while (classType != null);
throw new RuntimeException("Could not find method in dex file"); 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 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; //expecting a string like someField:Lfield/type;
String[] parts = field.split(":"); String[] parts = field.split(":");
if (parts.length != 2) { if (parts.length != 2) {
throw new RuntimeException("Invalid field descriptor " + field); throw new RuntimeException("Invalid field descriptor " + field);
} }
TypeIdItem classTypeItem = resolveTypeOrSupertype(classType);
String fieldName = parts[0]; String fieldName = parts[0];
String fieldType = parts[1]; String fieldType = parts[1];
@ -391,17 +391,17 @@ public class Deodexerant {
FieldIdItem fieldIdItem; FieldIdItem fieldIdItem;
do { do {
fieldIdItem = FieldIdItem.getInternedFieldIdItem(dexFile, classType, fieldTypeItem, fieldNameItem); fieldIdItem = FieldIdItem.getInternedFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem);
if (fieldIdItem != null) { if (fieldIdItem != null) {
return fieldIdItem; return fieldIdItem;
} }
String superclassDescriptor = lookupSuperclass(classType.getTypeDescriptor()); String superclassDescriptor = lookupSuperclass(classTypeItem.getTypeDescriptor());
classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor);
while (classType == null && superclassDescriptor != null) { while (classTypeItem == null && superclassDescriptor != null) {
superclassDescriptor = lookupSuperclass(superclassDescriptor); superclassDescriptor = lookupSuperclass(superclassDescriptor);
classType = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor); classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, superclassDescriptor);
} }
} while (classType != null); } while (classType != null);
@ -434,7 +434,7 @@ public class Deodexerant {
private class ClassData { private class ClassData {
private final TypeIdItem ClassType; private final String ClassType;
private boolean vtableLoaded = false; private boolean vtableLoaded = false;
private String[] methodNames; private String[] methodNames;
@ -447,7 +447,7 @@ public class Deodexerant {
private SparseArray<FieldIdItem> resolvedFields; private SparseArray<FieldIdItem> resolvedFields;
public ClassData(TypeIdItem classType) { public ClassData(String classType) {
this.ClassType = classType; this.ClassType = classType;
} }
@ -487,7 +487,7 @@ public class Deodexerant {
} }
private void loadvtable() { private void loadvtable() {
List<String> responseLines = sendMultilineCommand("V " + ClassType.getTypeDescriptor()); List<String> responseLines = sendMultilineCommand("V " + ClassType);
methodNames = new String[responseLines.size()]; methodNames = new String[responseLines.size()];
methodParams = new String[responseLines.size()]; methodParams = new String[responseLines.size()];
@ -516,7 +516,7 @@ public class Deodexerant {
} }
private void loadFields() { private void loadFields() {
List<String> responseLines = sendMultilineCommand("F " + ClassType.getTypeDescriptor()); List<String> responseLines = sendMultilineCommand("F " + ClassType);
instanceFields = new SparseArray<String>(responseLines.size()); instanceFields = new SparseArray<String>(responseLines.size());
resolvedFields = new SparseArray<FieldIdItem>(responseLines.size()); resolvedFields = new SparseArray<FieldIdItem>(responseLines.size());