protected void writeOpcode(IndentingWriter writer) throws IOException { writer.write(instruction.getOpcode().name); }
private boolean isDead(int address) { Op op = manipulator.getOp(address); log.debug("Dead test @{} for: {}", address, op); if (exceptionHandlingAddresses.contains(address)) { // If virtual execution was perfect, unvisited exception handling code could safely be removed provided // you also removed the try/catch but that level of accuracy is difficult. Instead, compromise by not // removing unvisited code, but try and remove for other reasons such as dead assignment. return false; } if (manipulator.wasAddressReached(address)) { return false; } if (op instanceof GotoOp) { // These are handled specifically by isUselessBranch return false; } if (op instanceof NopOp) { int nextAddress = address + op.getLocation().getInstruction().getCodeUnits(); Opcode nextOp = manipulator.getLocation(nextAddress).getInstruction().getOpcode(); if (nextOp == Opcode.ARRAY_PAYLOAD) { // Necessary nop padding return false; } } return true; }
public void removeInstruction(int index) { if (index >= instructionList.size() - 1) { throw new IndexOutOfBoundsException(); } MethodLocation toRemove = instructionList.get(index); toRemove.instruction = null; MethodLocation next = instructionList.get(index + 1); toRemove.mergeInto(next); instructionList.remove(index); int codeAddress = toRemove.codeAddress; for (int i = index; i < instructionList.size(); i++) { MethodLocation location = instructionList.get(i); location.index = i; location.codeAddress = codeAddress; Instruction instruction = location.getInstruction(); if (instruction != null) { codeAddress += instruction.getCodeUnits(); } else { assert i == instructionList.size() - 1; } } this.fixInstructions = true; }
public void replaceInstruction(int index, @Nonnull BuilderInstruction replacementInstruction) { if (index >= instructionList.size() - 1) { throw new IndexOutOfBoundsException(); } MethodLocation replaceLocation = instructionList.get(index); replacementInstruction.location = replaceLocation; BuilderInstruction old = replaceLocation.instruction; assert old != null; old.location = null; replaceLocation.instruction = replacementInstruction; // TODO: factor out index/address fix up loop int codeAddress = replaceLocation.codeAddress + replaceLocation.instruction.getCodeUnits(); for (int i = index + 1; i < instructionList.size(); i++) { MethodLocation location = instructionList.get(i); location.codeAddress = codeAddress; Instruction instruction = location.getInstruction(); if (instruction != null) { codeAddress += instruction.getCodeUnits(); } else { assert i == instructionList.size() - 1; } } this.fixInstructions = true; }
/** * Resolve an Instruction from a dexlib instruction. * * @param instruction * the corresponding dexlib instruction * @param codeAddress * the byte code address of the instruction */ public static DexlibAbstractInstruction fromInstruction(Instruction instruction, int codeAddress) { return fromOpcode(instruction.getOpcode(), instruction, codeAddress); }
Opcode opcode = instruction.getOpcode(); currentCodeAddress += instruction.getCodeUnits();
/** * Extracts the list of dalvik instructions from dexlib and converts them into our own instruction data model * * @param code * The dexlib method implementation */ protected void extractDexInstructions(MethodImplementation code) { int address = 0; for (Instruction instruction : code.getInstructions()) { DexlibAbstractInstruction dexInstruction = fromInstruction(instruction, address); instructions.add(dexInstruction); instructionAtAddress.put(address, dexInstruction); address += instruction.getCodeUnits(); } }
@Override boolean isUsedAsFloatingPoint(DexBody body, int register) { int source = ((TwoRegisterInstruction) instruction).getRegisterB(); Opcode opcode = instruction.getOpcode(); switch (opcode) { case NEG_FLOAT: case NEG_DOUBLE: return source == register; default: return false; } } }
codeAddress += instruction.getCodeUnits(); index++; for (final Instruction instruction : methodImplementation.getInstructions()) { final MethodLocation location = instructionList.get(index); final Opcode opcode = instruction.getOpcode(); if (opcode == Opcode.PACKED_SWITCH_PAYLOAD || opcode == Opcode.SPARSE_SWITCH_PAYLOAD) { switchPayloadTasks.add(new Task() {
public static MethodLocation getNextLocation(MethodLocation location, TIntObjectMap<MethodLocation> addressToLocation) { int address = location.getCodeAddress(); int nextAddress = address + location.getInstruction().getCodeUnits(); return addressToLocation.get(nextAddress); }
public Instruction findSwitchPayload(int targetOffset, Opcode type) { int targetIndex; try { targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset); } catch (InvalidInstructionOffset ex) { throw new InvalidSwitchPayload(targetOffset); } //TODO: does dalvik let you pad with multiple nops? //TODO: does dalvik let a switch instruction point to a non-payload instruction? Instruction instruction = instructions.get(targetIndex); if (instruction.getOpcode() != type) { // maybe it's pointing to a NOP padding instruction. Look at the next instruction if (instruction.getOpcode() == Opcode.NOP) { targetIndex += 1; if (targetIndex < instructions.size()) { instruction = instructions.get(targetIndex); if (instruction.getOpcode() == type) { return instruction; } } } throw new InvalidSwitchPayload(targetOffset); } else { return instruction; } }
if (instruction.getInstruction().getOpcode().format == Format.UnresolvedOdexInstruction) { methodItems.add(new CommentedOutMethodItem( InstructionMethodItemFactory.makeInstructionFormatMethodItem( !instruction.getInstruction().getOpcode().format.isPayloadFormat) { methodItems.add( new PreInstructionRegisterInfoMethodItem(classDef.options.registerInfo, currentCodeAddress += instruction.getInstruction().getCodeUnits();
int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
public int findPayloadOffset(int targetOffset, Opcode type) { int targetIndex; try { targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset); } catch (InvalidInstructionOffset ex) { throw new InvalidSwitchPayload(targetOffset); } //TODO: does dalvik let you pad with multiple nops? //TODO: does dalvik let a switch instruction point to a non-payload instruction? Instruction instruction = instructions.get(targetIndex); if (instruction.getOpcode() != type) { // maybe it's pointing to a NOP padding instruction. Look at the next instruction if (instruction.getOpcode() == Opcode.NOP) { targetIndex += 1; if (targetIndex < instructions.size()) { instruction = instructions.get(targetIndex); if (instruction.getOpcode() == type) { return instructionOffsetMap.getInstructionCodeOffset(targetIndex); } } } throw new InvalidSwitchPayload(targetOffset); } else { return targetOffset; } }
instructions.get(instructions.size()-1).getCodeUnits(); Opcode opcode = instruction.getOpcode(); if (opcode == Opcode.PACKED_SWITCH) { boolean valid = true; ((Instruction31t)instruction).getRegisterA(), targetOffset-codeOffset)); effectiveInstructions.add(payloadInstruction); endOffset += payloadInstruction.getCodeUnits(); ((Instruction31t)instruction).getRegisterA(), targetOffset-codeOffset)); effectiveInstructions.add(payloadInstruction); endOffset += payloadInstruction.getCodeUnits();
@Override protected Stmt switchStatement(DexBody body, Instruction targetData, Local key) { PackedSwitchPayload i = (PackedSwitchPayload) targetData; List<? extends SwitchElement> seList = i.getSwitchElements(); // the default target always follows the switch statement int defaultTargetAddress = codeAddress + instruction.getCodeUnits(); Unit defaultTarget = body.instructionAtAddress(defaultTargetAddress).getUnit(); List<IntConstant> lookupValues = new ArrayList<IntConstant>(); List<Unit> targets = new ArrayList<Unit>(); for (SwitchElement se : seList) { lookupValues.add(IntConstant.v(se.getKey())); int offset = se.getOffset(); targets.add(body.instructionAtAddress(codeAddress + offset).getUnit()); } LookupSwitchStmt switchStmt = Jimple.v().newLookupSwitchStmt(key, lookupValues, targets, defaultTarget); setUnit(switchStmt); if (IDalvikTyper.ENABLE_DVKTYPER) { DalvikTyper.v().setType(switchStmt.getKeyBox(), IntType.v(), true); } return switchStmt; }
private boolean needsAnalyzed() { for (Instruction instruction: methodImpl.getInstructions()) { if (instruction.getOpcode().odexOnly()) { return true; } } return false; }
new AnalyzedInstruction(this, instruction, i, registerCount)); assert analyzedInstructions.indexOfKey(currentCodeAddress) == i; currentCodeAddress += instruction.getCodeUnits(); for (int i=0; i< analyzedInstructions.size(); i++) { AnalyzedInstruction instruction = analyzedInstructions.valueAt(i); Opcode instructionOpcode = instruction.instruction.getOpcode(); currentCodeAddress = getInstructionAddress(instruction); Opcode instructionOpcode = instruction.instruction.getOpcode(); int instructionCodeAddress = getInstructionAddress(instruction); if (instruction.instruction.getOpcode().canContinue()) { if (currentInstructionIndex == analyzedInstructions.size() - 1) { throw new AnalysisException("Execution can continue past the last instruction");
@Override protected Stmt switchStatement(DexBody body, Instruction targetData, Local key) { SparseSwitchPayload i = (SparseSwitchPayload) targetData; List<? extends SwitchElement> seList = i.getSwitchElements(); // the default target always follows the switch statement int defaultTargetAddress = codeAddress + instruction.getCodeUnits(); Unit defaultTarget = body.instructionAtAddress(defaultTargetAddress).getUnit(); List<IntConstant> lookupValues = new ArrayList<IntConstant>(); List<Unit> targets = new ArrayList<Unit>(); for (SwitchElement se : seList) { lookupValues.add(IntConstant.v(se.getKey())); int offset = se.getOffset(); targets.add(body.instructionAtAddress(codeAddress + offset).getUnit()); } LookupSwitchStmt switchStmt = Jimple.v().newLookupSwitchStmt(key, lookupValues, targets, defaultTarget); setUnit(switchStmt); addTags(switchStmt); if (IDalvikTyper.ENABLE_DVKTYPER) { DalvikTyper.v().setType(switchStmt.getKeyBox(), IntType.v(), true); } return switchStmt; }
private void addPredecessorSuccessor(@Nonnull AnalyzedInstruction predecessor, @Nonnull AnalyzedInstruction successor, @Nonnull AnalyzedInstruction[][] exceptionHandlers, @Nonnull BitSet instructionsToProcess, boolean allowMoveException) { if (!allowMoveException && successor.instruction.getOpcode() == Opcode.MOVE_EXCEPTION) { throw new AnalysisException("Execution can pass from the " + predecessor.instruction.getOpcode().name + " instruction at code address 0x" + Integer.toHexString(getInstructionAddress(predecessor)) + " to the move-exception instruction at address 0x" + Integer.toHexString(getInstructionAddress(successor))); } if (!successor.addPredecessor(predecessor)) { return; } predecessor.addSuccessor(successor); instructionsToProcess.set(successor.getInstructionIndex()); //if the successor can throw an instruction, then we need to add the exception handlers as additional //successors to the predecessor (and then apply this same logic recursively if needed) //Technically, we should handle the monitor-exit instruction as a special case. The exception is actually //thrown *after* the instruction executes, instead of "before" the instruction executes, lke for any other //instruction. But since it doesn't modify any registers, we can treat it like any other instruction. AnalyzedInstruction[] exceptionHandlersForSuccessor = exceptionHandlers[successor.instructionIndex]; if (exceptionHandlersForSuccessor != null) { //the item for this instruction in exceptionHandlersForSuccessor should only be set if this instruction //can throw an exception assert successor.instruction.getOpcode().canThrow(); for (AnalyzedInstruction exceptionHandler: exceptionHandlersForSuccessor) { addPredecessorSuccessor(predecessor, exceptionHandler, exceptionHandlers, instructionsToProcess, true); } } }