private boolean needsAnalyzed() { for (Instruction instruction: methodImpl.getInstructions()) { if (instruction.getOpcode().odexOnly()) { return true; } } return false; }
private void fixIncompatRegs(Insn insn, InstructionIterator allInsns) { List<Register> regs = insn.getRegs(); BitSet incompatRegs = insn.getIncompatibleRegs(); Register resultReg = regs.get(0); // do we have an incompatible result reg? boolean hasResultReg = insn.getOpcode().setsRegister() || insn.getOpcode().setsWideRegister(); boolean isResultRegIncompat = incompatRegs.get(0); // is there an incompat result reg which is not also used as a source // (like in /2addr)? if (hasResultReg && isResultRegIncompat && !insn.getOpcode().name.endsWith("/2addr") && !insn.getOpcode().name.equals("check-cast")) { // yes, so pretend result reg is compatible, since it will get a // special move incompatRegs.clear(0); } // handle normal incompatible regs, if any: add moves if (incompatRegs.cardinality() > 0) { addMovesForIncompatRegs(insn, allInsns, regs, incompatRegs); } // handle incompatible result reg. This is for three-operand // instructions // in which the result register is out of scope. For /2addr // instructions, // we need to coherently move source and result, so this is already done // in addMovesForIncompatRegs. if (hasResultReg && isResultRegIncompat) { Register resultRegClone = resultReg.clone(); addMoveForIncompatResultReg(allInsns, resultRegClone, resultReg, insn); } }
if (currentTry != null && instructionOpcode.canThrow()) { exceptionHandlers[i] = currentExceptionHandlers; int instructionCodeAddress = getInstructionAddress(instruction); if (instruction.instruction.getOpcode().canContinue()) { if (currentInstructionIndex == analyzedInstructions.size() - 1) { throw new AnalysisException("Execution can continue past the last instruction");
if (opcode.odexOnly()) { if (!isAllowedOdex(opcode)) { writer.write("#disallowed odex opcode\n"); writer.write(", "); writeLiteral(writer); if (instruction.getOpcode().setsWideRegister()) { writeCommentIfLikelyDouble(writer); } else {
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); } } }
private static Set<Integer> getExceptionHandlerAddresses(ExecutionGraphManipulator manipulator) { int[] allAddresses = manipulator.getAddresses(); Arrays.sort(allAddresses); int highestAddress = allAddresses[allAddresses.length - 1]; Set<Integer> handlerAddresses = new HashSet<>(); List<BuilderTryBlock> tryBlocks = manipulator.getTryBlocks(); for (BuilderTryBlock tryBlock : tryBlocks) { List<? extends BuilderExceptionHandler> handlers = tryBlock.getExceptionHandlers(); for (BuilderExceptionHandler handler : handlers) { int address = handler.getHandlerCodeAddress(); BuilderInstruction instruction = manipulator.getInstruction(address); while (address < highestAddress) { // Add all instructions until return, goto, etc. handlerAddresses.add(address); address += instruction.getCodeUnits(); instruction = manipulator.getInstruction(address); if (!instruction.getOpcode().canContinue()) { break; } } } } return handlerAddresses; }
public int getMinimumRegsNeeded() { BitSet incompatRegs = getIncompatibleRegs(); int resultNeed = 0; int miscRegsNeed = 0; boolean hasResult = opc.setsRegister(); if (hasResult && incompatRegs.get(0)) { resultNeed = SootToDexUtils.getDexWords(regs.get(0).getType()); } for (int i = hasResult ? 1 : 0; i < regs.size(); i++) { if (incompatRegs.get(i)) { miscRegsNeed += SootToDexUtils.getDexWords(regs.get(i).getType()); } } // The /2addr instruction format takes two operands and overwrites the // first operand register with the result. The result register is thus // not free to overlap as we still need to provide input data in it. // add-long/2addr r0 r0 -> 2 registers // add-int r0 r0 r2 -> 2 registers, re-use result register if (opc.name.endsWith("/2addr")) { return resultNeed + miscRegsNeed; } else { return Math.max(resultNeed, miscRegsNeed); } }
public boolean setsWideRegister() { return instruction.getOpcode().setsWideRegister(); }
public Opcodes(int api) { opcodesByValue = new Opcode[256]; opcodesByName = Maps.newHashMap(); for (Opcode opcode: Opcode.values()) { if (!opcode.format.isPayloadFormat) { if (api <= opcode.getMaxApi() && api >= opcode.getMinApi()) { opcodesByValue[opcode.value] = opcode; opcodesByName.put(opcode.name.toLowerCase(), opcode); } } } }
@Override public String toString() { return opc.toString() + " " + regs; }
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); }
protected boolean isInvokeInit() { if (instruction == null || !instruction.getOpcode().canInitializeReference()) { return false; } ReferenceInstruction instruction = (ReferenceInstruction)this.instruction; Reference reference = instruction.getReference(); if (reference instanceof MethodReference) { return ((MethodReference)reference).getName().equals("<init>"); } return false; }
for (Opcode opcode: Opcode.values()) { RangeMap<Integer, Short> versionToValueMap;
if (opcode.odexOnly()) { if (!isAllowedOdex(opcode)) { writer.write("#disallowed odex opcode\n"); writer.write(", "); writeLiteral(writer); if (instruction.getOpcode().setsWideRegister()) { writeCommentIfLikelyDouble(writer); } else {
/** * True if the instruction can throw an exception * @see com.ibm.wala.shrikeBT.IInstruction#isPEI() */ public boolean isPEI() { return opcode.canThrow(); }
/** * True if the instruction can continue. * @see com.ibm.wala.shrikeBT.IInstruction#isFallThrough() */ public boolean isFallThrough() { return opcode.canContinue(); }
public boolean setsRegister() { return instruction.getOpcode().setsRegister(); }
+ inst.getOpcode().toString() + " in " + eMethod.getDefiningClass() + ':' + eMethod.getName());
private void analyzeMoveResult(@Nonnull AnalyzedInstruction analyzedInstruction) { AnalyzedInstruction previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex-1); if (!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); }
public boolean isInvokeInit() { if (!instruction.getOpcode().canInitializeReference()) { return false; } ReferenceInstruction instruction = (ReferenceInstruction)this.instruction; Reference reference = instruction.getReference(); if (reference instanceof MethodReference) { return ((MethodReference)reference).getName().equals("<init>"); } return false; }