protected void writeOpcode(IndentingWriter writer) throws IOException { writer.write(instruction.getOpcode().name); }
/** * 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); }
@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; } } }
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; } }
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; } }
private boolean needsAnalyzed() { for (Instruction instruction: methodImpl.getInstructions()) { if (instruction.getOpcode().odexOnly()) { return true; } } return false; }
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); } } }
public Op create(MethodLocation location) { Instruction instruction = location.getInstruction(); Opcode opcode = instruction.getOpcode(); OpFactory opFactory = getOpFactory(opcode); return opFactory.create(location, addressToLocation, vm); }
private void fixInstructions(@Nonnull MutableMethodImplementation methodImplementation) { List<? extends Instruction> instructions = methodImplementation.getInstructions(); for (int i=0; i<instructions.size(); i++) { Instruction instruction = instructions.get(i); if (instruction.getOpcode() == Opcode.CONST_STRING) { if (stringSection.getItemIndex( (StringRef)((ReferenceInstruction)instruction).getReference()) >= 65536) { methodImplementation.replaceInstruction(i, new BuilderInstruction31c(Opcode.CONST_STRING_JUMBO, ((OneRegisterInstruction)instruction).getRegisterA(), ((ReferenceInstruction)instruction).getReference())); } } } }
private void analyzeMoveResult(@Nonnull AnalyzedInstruction analyzedInstruction) { AnalyzedInstruction previousInstruction = null; if (analyzedInstruction.instructionIndex > 0) { previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex-1); } if (previousInstruction == null || !previousInstruction.instruction.getOpcode().setsResult()) { throw new AnalysisException(analyzedInstruction.instruction.getOpcode().name + " must occur after an " + "invoke-*/fill-new-array instruction"); } RegisterType resultRegisterType; ReferenceInstruction invokeInstruction = (ReferenceInstruction)previousInstruction.instruction; Reference reference = invokeInstruction.getReference(); if (reference instanceof MethodReference) { resultRegisterType = RegisterType.getRegisterType(classPath, ((MethodReference)reference).getReturnType()); } else { resultRegisterType = RegisterType.getRegisterType(classPath, (TypeReference)reference); } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, resultRegisterType); }
Opcode opcode = instruction.getOpcode();
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; }
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() {
Instruction previousInstruction = previousLocation.instruction; assert previousInstruction != null; if (previousInstruction.getOpcode() == Opcode.NOP) { removeInstruction(previousIndex); index--;
if (instruction instanceof ReferenceInstruction) { Reference reference = ((ReferenceInstruction)instruction).getReference(); switch (instruction.getOpcode().referenceType) { case ReferenceType.STRING: dexPool.stringSection.intern((StringReference)reference); default: throw new ExceptionWithContext("Unrecognized reference type: %d", instruction.getOpcode().referenceType);
private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { FieldReference field = (FieldReference)((ReferenceInstruction)analyzedInstruction.instruction).getReference(); String fieldType = field.getType(); Opcode originalOpcode = analyzedInstruction.instruction.getOpcode(); Opcode opcode = classPath.getFieldInstructionMapper().getAndCheckDeodexedOpcode( fieldType, originalOpcode); Instruction deodexedInstruction; if (originalOpcode.isStaticFieldAccessor()) { OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.instruction; deodexedInstruction = new ImmutableInstruction21c(opcode, instruction.getRegisterA(), field); } else { TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; deodexedInstruction = new ImmutableInstruction22c(opcode, instruction.getRegisterA(), instruction.getRegisterB(), field); } analyzedInstruction.setDeodexedInstruction(deodexedInstruction); if (analyzeResult) { analyzeInstruction(analyzedInstruction); } return true; }
private static void testEquals(Instruction expectedInstr, Instruction actualInstr) { assertEquals(expectedInstr.getOpcode(), actualInstr.getOpcode()); if (expectedInstr instanceof OneRegisterInstruction) { OneRegisterInstruction expected = (OneRegisterInstruction) expectedInstr; OneRegisterInstruction actual = (OneRegisterInstruction) actualInstr; assertEquals(expected.getRegisterA(), actual.getRegisterA()); } if (expectedInstr instanceof NarrowLiteralInstruction) { NarrowLiteralInstruction expected = (NarrowLiteralInstruction) expectedInstr; NarrowLiteralInstruction actual = (NarrowLiteralInstruction) actualInstr; assertEquals(expected.getNarrowLiteral(), actual.getNarrowLiteral()); } if (expectedInstr instanceof WideLiteralInstruction) { WideLiteralInstruction expected = (WideLiteralInstruction) expectedInstr; WideLiteralInstruction actual = (WideLiteralInstruction) actualInstr; assertEquals(expected.getWideLiteral(), actual.getWideLiteral()); } if (expectedInstr instanceof ReferenceInstruction) { ReferenceInstruction expected = (ReferenceInstruction) expectedInstr; ReferenceInstruction actual = (ReferenceInstruction) actualInstr; assertEquals(expected.getReferenceType(), actual.getReferenceType()); assertEquals(expected.getReference(), actual.getReference()); } }
/** * Return the appropriate Jimple Expression according to the OpCode */ private Value getExpression(Local source) { Opcode opcode = instruction.getOpcode(); switch (opcode) { case NEG_INT: setTag(new IntOpTag()); return Jimple.v().newNegExpr(source); case NEG_LONG: setTag(new LongOpTag()); return Jimple.v().newNegExpr(source); case NEG_FLOAT: setTag(new FloatOpTag()); return Jimple.v().newNegExpr(source); case NEG_DOUBLE: setTag(new DoubleOpTag()); return Jimple.v().newNegExpr(source); case NOT_LONG: setTag(new LongOpTag()); return getNotLongExpr(source); case NOT_INT: setTag(new IntOpTag()); return getNotIntExpr(source); default: throw new RuntimeException("Invalid Opcode: " + opcode); } }
private void convertAndSetInstruction(@Nonnull MethodLocation location, int[] codeAddressToIndex, @Nonnull Instruction instruction) { switch (instruction.getOpcode().format) { case Format10t: setInstruction(location, newBuilderInstruction10t(location.codeAddress, return; default: throw new ExceptionWithContext("Instruction format %s not supported", instruction.getOpcode().format);