Handle a rare case where deodexing an instruction invalidates a previously deodexed instruction somewhere else because of the new register information available

git-svn-id: https://smali.googlecode.com/svn/trunk@448 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2009-09-09 04:21:20 +00:00
parent 8b260a1d81
commit 726d88404d

View File

@ -195,26 +195,21 @@ public class DeodexUtil {
public List<Instruction> deodexerizeCode(CodeItem codeItem) { public List<Instruction> deodexerizeCode(CodeItem codeItem) {
List<insn> insns = makeInsnList(codeItem); List<insn> insns = makeInsnList(codeItem);
byte[] encodedInstructions = codeItem.getEncodedInstructions().clone();
boolean didSomething; boolean didSomething;
boolean somethingLeftToDo; boolean somethingLeftToDo;
do { do {
int offset = 0;
didSomething = false; didSomething = false;
somethingLeftToDo = false; somethingLeftToDo = false;
for (insn i: insns) { for (insn i: insns) {
if (i.instruction.opcode.odexOnly && i.fixedInstruction == null) { if (i.instruction.opcode.odexOnly && i.fixedInstruction == null) {
if (deodexInstruction(i, offset, encodedInstructions)) { if (deodexInstruction(i)) {
didSomething = true; didSomething = true;
} else { } else {
somethingLeftToDo = true; somethingLeftToDo = true;
} }
} }
offset += i.instruction.getSize()/2;
} }
} while (didSomething && somethingLeftToDo); } while (didSomething);
if (somethingLeftToDo) { if (somethingLeftToDo) {
System.err.println("warning: could not fully deodex the method " + System.err.println("warning: could not fully deodex the method " +
codeItem.getParent().method.getContainingClass().getTypeDescriptor() + "->" + codeItem.getParent().method.getContainingClass().getTypeDescriptor() + "->" +
@ -234,7 +229,7 @@ public class DeodexUtil {
return instructions; return instructions;
} }
private boolean deodexInstruction(insn i, int offset, byte[] encodedInstructions) { private boolean deodexInstruction(insn i) {
switch (i.instruction.opcode) { switch (i.instruction.opcode) {
case INVOKE_EXECUTE_INLINE: case INVOKE_EXECUTE_INLINE:
{ {
@ -838,6 +833,12 @@ public class DeodexUtil {
*/ */
public Instruction fixedInstruction; public Instruction fixedInstruction;
/**
* This is only used for odexed instructions, and should contain the register num of the object reference
* that the instruction acts on. More specifically, it's only for odexed instructions that require the
* type of the object register in order to look up the correct information.
*/
public int objectRegisterNum = -1;
/** /**
* Whether this instruction can be the first instruction to successfully execute. This could be the first * Whether this instruction can be the first instruction to successfully execute. This could be the first
@ -864,6 +865,29 @@ public class DeodexUtil {
this.canThrow = DeodexUtil.instructionThrowTable.get(instruction.opcode.value & 0xFF); this.canThrow = DeodexUtil.instructionThrowTable.get(instruction.opcode.value & 0xFF);
this.insnsMap = insnsMap; this.insnsMap = insnsMap;
if (instruction.opcode.odexOnly) {
switch (instruction.opcode) {
case IGET_QUICK:
case IGET_WIDE_QUICK:
case IGET_OBJECT_QUICK:
case IPUT_QUICK:
case IPUT_WIDE_QUICK:
case IPUT_OBJECT_QUICK:
objectRegisterNum = ((Instruction22cs)instruction).getRegisterB();
break;
case INVOKE_VIRTUAL_QUICK:
case INVOKE_SUPER_QUICK:
objectRegisterNum = ((Instruction35ms)instruction).getRegisterD();
break;
case INVOKE_VIRTUAL_RANGE_QUICK:
case INVOKE_SUPER_RANGE_QUICK:
objectRegisterNum = ((Instruction3rms)instruction).getStartRegister();
break;
default:
break;
}
}
registerMap = new RegisterType[codeItem.getRegisterCount()]; registerMap = new RegisterType[codeItem.getRegisterCount()];
registerTypes = new TypeIdItem[codeItem.getRegisterCount()]; registerTypes = new TypeIdItem[codeItem.getRegisterCount()];
@ -1348,6 +1372,13 @@ public class DeodexUtil {
} }
} }
//if the next instruction is an odexed instruction and requires the type of it's object
//register to figure out the correct method/field to use, then objectRegisterNum will
//be set to the register number containing the object reference that it uses.
//if that instruction has already been fixed, but we have newer information and update
//the register type, we need to clear out the fixed instruction, so it gets re-fixed,
//with the new register information
for (insn nextInsn: successors) { for (insn nextInsn: successors) {
boolean somethingChanged = false; boolean somethingChanged = false;
@ -1367,6 +1398,10 @@ public class DeodexUtil {
TypeIdItem regReferenceType = findCommonSuperclass(registerTypes[i], TypeIdItem regReferenceType = findCommonSuperclass(registerTypes[i],
nextInsn.registerTypes[i]); nextInsn.registerTypes[i]);
if (regReferenceType != nextInsn.registerTypes[i]) { if (regReferenceType != nextInsn.registerTypes[i]) {
//see comment above for loop
if (i == nextInsn.objectRegisterNum) {
nextInsn.fixedInstruction = null;
}
somethingChanged = true; somethingChanged = true;
nextInsn.registerTypes[i] = regReferenceType; nextInsn.registerTypes[i] = regReferenceType;
} }
@ -1382,12 +1417,22 @@ public class DeodexUtil {
if (registerType == RegisterType.Reference) { if (registerType == RegisterType.Reference) {
if (registerReferenceType != null) { if (registerReferenceType != null) {
if (nextInsn.registerTypes[registerNum] != registerReferenceType) { if (nextInsn.registerTypes[registerNum] != registerReferenceType) {
//see comment above for loop
if (registerNum == nextInsn.objectRegisterNum) {
nextInsn.fixedInstruction = null;
}
somethingChanged = true; somethingChanged = true;
nextInsn.registerTypes[registerNum] = registerReferenceType; nextInsn.registerTypes[registerNum] = registerReferenceType;
} }
} else { } else {
TypeIdItem type = destRegisterType(); TypeIdItem type = destRegisterType();
if (type != nextInsn.registerTypes[registerNum]) { if (type != nextInsn.registerTypes[registerNum]) {
//see comment above for loop
if (registerNum == nextInsn.objectRegisterNum) {
nextInsn.fixedInstruction = null;
}
somethingChanged = true; somethingChanged = true;
nextInsn.registerTypes[registerNum] = type; nextInsn.registerTypes[registerNum] = type;
} }