Search in sources :

Example 11 with Insn

use of soot.toDex.instructions.Insn in project soot by Sable.

the class DexPrinter method insertIntermediateJump.

/**
 * Creates an intermediate jump instruction between the original jump
 * instruction and its target
 *
 * @param targetInsPos
 *            The jump target index
 * @param jumpInsPos
 *            The position of the jump instruction
 * @param stmtV
 *            The statement visitor used for constructing the instructions
 * @param instructions
 *            The list of Dalvik instructions
 * @param labelAssigner
 *            The label assigner to be used for creating new labels
 */
private void insertIntermediateJump(int targetInsPos, int jumpInsPos, StmtVisitor stmtV, List<BuilderInstruction> instructions, LabelAssigner labelAssigner) {
    // Get the original jump instruction
    BuilderInstruction originalJumpInstruction = instructions.get(jumpInsPos);
    Insn originalJumpInsn = stmtV.getInsnForInstruction(originalJumpInstruction);
    if (originalJumpInsn == null)
        return;
    if (!(originalJumpInsn instanceof InsnWithOffset))
        throw new RuntimeException("Unexpected jump instruction target");
    InsnWithOffset offsetInsn = (InsnWithOffset) originalJumpInsn;
    // If this is goto instruction, we can just replace it
    if (originalJumpInsn instanceof Insn10t) {
        if (originalJumpInsn.getOpcode() == Opcode.GOTO) {
            Insn30t newJump = new Insn30t(Opcode.GOTO_32);
            newJump.setTarget(((Insn10t) originalJumpInsn).getTarget());
            BuilderInstruction newJumpInstruction = newJump.getRealInsn(labelAssigner);
            instructions.remove(jumpInsPos);
            instructions.add(jumpInsPos, newJumpInstruction);
            stmtV.fakeNewInsn(stmtV.getStmtForInstruction(originalJumpInstruction), newJump, newJumpInstruction);
            return;
        }
    }
    // Find a position where we can jump to
    int distance = Math.max(targetInsPos, jumpInsPos) - Math.min(targetInsPos, jumpInsPos);
    if (distance == 0)
        return;
    int newJumpIdx = Math.min(targetInsPos, jumpInsPos) + (distance / 2);
    int sign = (int) Math.signum(targetInsPos - jumpInsPos);
    // label may otherwise be attached to the wrong statement
    do {
        Stmt newStmt = stmtV.getStmtForInstruction(instructions.get(newJumpIdx));
        Stmt prevStmt = newJumpIdx > 0 ? stmtV.getStmtForInstruction(instructions.get(newJumpIdx - 1)) : null;
        if (newStmt == null || newStmt == prevStmt) {
            newJumpIdx -= sign;
            if (newJumpIdx < 0 || newJumpIdx >= instructions.size())
                throw new RuntimeException("No position for inserting intermediate " + "jump instruction found");
        } else
            break;
    } while (true);
    // Create a jump instruction from the middle to the end
    NopStmt nop = Jimple.v().newNopStmt();
    Insn30t newJump = new Insn30t(Opcode.GOTO_32);
    newJump.setTarget(stmtV.getStmtForInstruction(instructions.get(targetInsPos)));
    BuilderInstruction newJumpInstruction = newJump.getRealInsn(labelAssigner);
    instructions.add(newJumpIdx, newJumpInstruction);
    stmtV.fakeNewInsn(nop, newJump, newJumpInstruction);
    // We have added something, so we need to fix indices
    if (newJumpIdx <= jumpInsPos)
        jumpInsPos++;
    if (newJumpIdx <= targetInsPos)
        targetInsPos++;
    // Jump from the original instruction to the new one in the middle
    offsetInsn.setTarget(nop);
    BuilderInstruction replacementJumpInstruction = offsetInsn.getRealInsn(labelAssigner);
    assert instructions.get(jumpInsPos) == originalJumpInstruction;
    instructions.remove(jumpInsPos);
    instructions.add(jumpInsPos, replacementJumpInstruction);
    stmtV.fakeNewInsn(stmtV.getStmtForInstruction(originalJumpInstruction), originalJumpInsn, replacementJumpInstruction);
    // Our indices are still fine, because we just replaced something
    Stmt afterNewJump = stmtV.getStmtForInstruction(instructions.get(newJumpIdx + 1));
    // Make the original control flow jump around the new artificial jump
    // instruction
    Insn10t jumpAround = new Insn10t(Opcode.GOTO);
    jumpAround.setTarget(afterNewJump);
    BuilderInstruction jumpAroundInstruction = jumpAround.getRealInsn(labelAssigner);
    instructions.add(newJumpIdx, jumpAroundInstruction);
    stmtV.fakeNewInsn(Jimple.v().newNopStmt(), jumpAround, jumpAroundInstruction);
}
Also used : Insn(soot.toDex.instructions.Insn) Insn30t(soot.toDex.instructions.Insn30t) BuilderInstruction(org.jf.dexlib2.builder.BuilderInstruction) Insn10t(soot.toDex.instructions.Insn10t) NopStmt(soot.jimple.NopStmt) InsnWithOffset(soot.toDex.instructions.InsnWithOffset) NopStmt(soot.jimple.NopStmt) Stmt(soot.jimple.Stmt) IdentityStmt(soot.jimple.IdentityStmt) MonitorStmt(soot.jimple.MonitorStmt)

Example 12 with Insn

use of soot.toDex.instructions.Insn in project soot by Sable.

the class DexPrinter method fixLongJumps.

/**
 * Fixes long jumps that exceed the maximum distance for the respective jump
 * type
 *
 * @param instructions
 *            The list of generated dalvik instructions
 * @param labelAssigner
 *            The label assigner that maps statements to labels
 * @param stmtV
 *            The statement visitor used to produce the dalvik instructions
 */
private void fixLongJumps(List<BuilderInstruction> instructions, LabelAssigner labelAssigner, StmtVisitor stmtV) {
    // Only construct the maps once and update them afterwards
    Map<Instruction, Integer> instructionsToIndex = new HashMap<Instruction, Integer>();
    List<Integer> instructionsToOffsets = new ArrayList<Integer>();
    Map<Label, Integer> labelsToOffsets = new HashMap<Label, Integer>();
    Map<Label, Integer> labelsToIndex = new HashMap<Label, Integer>();
    boolean hasChanged;
    l0: do {
        // Look for changes anew every time
        hasChanged = false;
        instructionsToOffsets.clear();
        // Build a mapping between instructions and offsets
        {
            int offset = 0;
            int idx = 0;
            for (BuilderInstruction bi : instructions) {
                instructionsToIndex.put(bi, idx);
                instructionsToOffsets.add(offset);
                Stmt origStmt = stmtV.getStmtForInstruction(bi);
                if (origStmt != null) {
                    Label lbl = labelAssigner.getLabelUnsafe(origStmt);
                    if (lbl != null) {
                        labelsToOffsets.put(lbl, offset);
                        labelsToIndex.put(lbl, idx);
                    }
                }
                offset += (bi.getFormat().size / 2);
                idx++;
            }
        }
        // Look for references to labels
        for (int j = 0; j < instructions.size(); j++) {
            BuilderInstruction bj = instructions.get(j);
            if (bj instanceof BuilderOffsetInstruction) {
                BuilderOffsetInstruction boj = (BuilderOffsetInstruction) bj;
                // Compute the distance between the instructions
                Insn jumpInsn = stmtV.getInsnForInstruction(boj);
                if (jumpInsn instanceof InsnWithOffset) {
                    InsnWithOffset offsetInsn = (InsnWithOffset) jumpInsn;
                    Integer targetOffset = labelsToOffsets.get(boj.getTarget());
                    if (targetOffset == null)
                        continue;
                    int distance = instructionsToOffsets.get(j) - targetOffset;
                    if (Math.abs(distance) > offsetInsn.getMaxJumpOffset()) {
                        // We need intermediate jumps
                        insertIntermediateJump(labelsToIndex.get(boj.getTarget()), j, stmtV, instructions, labelAssigner);
                        hasChanged = true;
                        continue l0;
                    }
                }
            }
        }
    } while (hasChanged);
}
Also used : Insn(soot.toDex.instructions.Insn) BuilderOffsetInstruction(org.jf.dexlib2.builder.BuilderOffsetInstruction) LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) BuilderInstruction(org.jf.dexlib2.builder.BuilderInstruction) ArrayList(java.util.ArrayList) Label(org.jf.dexlib2.builder.Label) InsnWithOffset(soot.toDex.instructions.InsnWithOffset) BuilderOffsetInstruction(org.jf.dexlib2.builder.BuilderOffsetInstruction) BuilderInstruction(org.jf.dexlib2.builder.BuilderInstruction) Instruction(org.jf.dexlib2.iface.instruction.Instruction) NopStmt(soot.jimple.NopStmt) Stmt(soot.jimple.Stmt) IdentityStmt(soot.jimple.IdentityStmt) MonitorStmt(soot.jimple.MonitorStmt)

Aggregations

Insn (soot.toDex.instructions.Insn)12 AddressInsn (soot.toDex.instructions.AddressInsn)9 TwoRegInsn (soot.toDex.instructions.TwoRegInsn)6 BuilderInstruction (org.jf.dexlib2.builder.BuilderInstruction)3 IdentityStmt (soot.jimple.IdentityStmt)3 MonitorStmt (soot.jimple.MonitorStmt)3 NopStmt (soot.jimple.NopStmt)3 Stmt (soot.jimple.Stmt)3 ArrayList (java.util.ArrayList)2 InsnWithOffset (soot.toDex.instructions.InsnWithOffset)2 HashMap (java.util.HashMap)1 LinkedHashMap (java.util.LinkedHashMap)1 Opcode (org.jf.dexlib2.Opcode)1 BuilderOffsetInstruction (org.jf.dexlib2.builder.BuilderOffsetInstruction)1 Label (org.jf.dexlib2.builder.Label)1 Instruction (org.jf.dexlib2.iface.instruction.Instruction)1 Local (soot.Local)1 Value (soot.Value)1 AssignStmt (soot.jimple.AssignStmt)1 BreakpointStmt (soot.jimple.BreakpointStmt)1