use of org.jf.dexlib2.builder.MethodImplementationBuilder in project soot by Sable.
the class DexPrinter method addRegisterAssignmentDebugInfo.
private void addRegisterAssignmentDebugInfo(LocalRegisterAssignmentInformation registerAssignment, Map<Local, Integer> seenRegisters, MethodImplementationBuilder builder) {
Local local = registerAssignment.getLocal();
String dexLocalType = SootToDexUtils.getDexTypeDescriptor(local.getType());
StringReference localName = new ImmutableStringReference(local.getName());
Register reg = registerAssignment.getRegister();
int register = reg.getNumber();
Integer beforeRegister = seenRegisters.get(local);
if (beforeRegister != null) {
if (beforeRegister == register)
// No change
return;
builder.addEndLocal(beforeRegister);
}
builder.addStartLocal(register, localName, new ImmutableTypeReference(dexLocalType), new ImmutableStringReference(""));
seenRegisters.put(local, register);
}
use of org.jf.dexlib2.builder.MethodImplementationBuilder in project soot by Sable.
the class DexPrinter method toMethodImplementation.
private MethodImplementation toMethodImplementation(SootMethod m) {
if (m.isAbstract() || m.isNative()) {
return null;
}
Body activeBody = m.retrieveActiveBody();
// when installing the app
if (m.getName().contains("<") || m.getName().equals(">"))
if (!m.getName().equals("<init>") && !m.getName().equals("<clinit>"))
throw new RuntimeException("Invalid method name: " + m.getName());
// Switch statements may not be empty in dex, so we have to fix this
// first
EmptySwitchEliminator.v().transform(activeBody);
// Dalvik requires synchronized methods to have explicit monitor calls,
// so we insert them here. See
// http://milk.com/kodebase/dalvik-docs-mirror/docs/debugger.html
// We cannot place this upon the developer since it is only required
// for Dalvik, but not for other targets.
SynchronizedMethodTransformer.v().transform(activeBody);
// Tries may not start or end at units which have no corresponding
// Dalvik
// instructions such as IdentityStmts. We reduce the traps to start at
// the
// first "real" instruction. We could also use a TrapTigthener, but that
// would be too expensive for what we need here.
FastDexTrapTightener.v().transform(activeBody);
// Look for sequences of array element assignments that we can collapse
// into bulk initializations
DexArrayInitDetector initDetector = new DexArrayInitDetector();
initDetector.constructArrayInitializations(activeBody);
initDetector.fixTraps(activeBody);
// Split the tries since Dalvik does not supported nested try/catch
// blocks
TrapSplitter.v().transform(activeBody);
// word count of incoming parameters
int inWords = SootToDexUtils.getDexWords(m.getParameterTypes());
if (!m.isStatic()) {
// extra word for "this"
inWords++;
}
// word count of max outgoing parameters
Collection<Unit> units = activeBody.getUnits();
// register count = parameters + additional registers, depending on the
// dex instructions generated (e.g. locals used and constants loaded)
StmtVisitor stmtV = new StmtVisitor(m, initDetector);
Chain<Trap> traps = activeBody.getTraps();
Set<Unit> trapReferences = new HashSet<Unit>(traps.size() * 3);
for (Trap t : activeBody.getTraps()) {
trapReferences.add(t.getBeginUnit());
trapReferences.add(t.getEndUnit());
trapReferences.add(t.getHandlerUnit());
}
toInstructions(units, stmtV, trapReferences);
int registerCount = stmtV.getRegisterCount();
if (inWords > registerCount) {
/*
* as the Dalvik VM moves the parameters into the last registers, the "in" word
* count must be at least equal to the register count. a smaller register count
* could occur if soot generated the method body, see e.g. the handling of
* phantom refs in SootMethodRefImpl.resolve(StringBuffer): the body has no
* locals for the ParameterRefs, it just throws an error.
*
* we satisfy the verifier by just increasing the register count, since calling
* phantom refs will lead to an error anyway.
*/
registerCount = inWords;
}
MethodImplementationBuilder builder = new MethodImplementationBuilder(registerCount);
LabelAssigner labelAssinger = new LabelAssigner(builder);
List<BuilderInstruction> instructions = stmtV.getRealInsns(labelAssinger);
fixLongJumps(instructions, labelAssinger, stmtV);
Map<Local, Integer> seenRegisters = new HashMap<Local, Integer>();
Map<Instruction, LocalRegisterAssignmentInformation> instructionRegisterMap = stmtV.getInstructionRegisterMap();
if (Options.v().write_local_annotations()) {
for (LocalRegisterAssignmentInformation assignment : stmtV.getParameterInstructionsList()) {
// (at least not if it exists with exactly this name)
if (assignment.getLocal().getName().equals("this"))
continue;
addRegisterAssignmentDebugInfo(assignment, seenRegisters, builder);
}
}
for (BuilderInstruction ins : instructions) {
Stmt origStmt = stmtV.getStmtForInstruction(ins);
// If this is a switch payload, we need to place the label
if (stmtV.getInstructionPayloadMap().containsKey(ins))
builder.addLabel(labelAssinger.getLabelName(stmtV.getInstructionPayloadMap().get(ins)));
if (origStmt != null) {
// Do we need a label here because this a trap handler?
if (trapReferences.contains(origStmt))
labelAssinger.getOrCreateLabel(origStmt);
// Add the label if the statement has one
String labelName = labelAssinger.getLabelName(origStmt);
if (labelName != null && !builder.getLabel(labelName).isPlaced())
builder.addLabel(labelName);
// Add the tags
if (stmtV.getStmtForInstruction(ins) != null) {
List<Tag> tags = origStmt.getTags();
for (Tag t : tags) {
if (t instanceof LineNumberTag) {
LineNumberTag lnt = (LineNumberTag) t;
builder.addLineNumber(lnt.getLineNumber());
} else if (t instanceof SourceFileTag) {
SourceFileTag sft = (SourceFileTag) t;
builder.addSetSourceFile(new ImmutableStringReference(sft.getSourceFile()));
}
}
}
}
builder.addInstruction(ins);
LocalRegisterAssignmentInformation registerAssignmentTag = instructionRegisterMap.get(ins);
if (registerAssignmentTag != null) {
// Add start local debugging information: Register -> Local
// assignment
addRegisterAssignmentDebugInfo(registerAssignmentTag, seenRegisters, builder);
}
}
for (int registersLeft : seenRegisters.values()) builder.addEndLocal(registersLeft);
toTries(activeBody.getTraps(), stmtV, builder, labelAssinger);
// Make sure that all labels have been placed by now
for (Label lbl : labelAssinger.getAllLabels()) if (!lbl.isPlaced())
throw new RuntimeException("Label not placed: " + lbl);
return builder.getMethodImplementation();
}
use of org.jf.dexlib2.builder.MethodImplementationBuilder in project smali by JesusFreke.
the class PayloadAlignmentTest method testSparseSwitchAlignment.
@Test
public void testSparseSwitchAlignment() {
MethodImplementationBuilder implBuilder = new MethodImplementationBuilder(10);
implBuilder.addLabel("switch_target_1");
implBuilder.addInstruction(new BuilderInstruction10t(Opcode.GOTO, implBuilder.getLabel("goto_target")));
implBuilder.addLabel("switch_payload");
implBuilder.addInstruction(new BuilderSparseSwitchPayload(Lists.newArrayList(new SwitchLabelElement(0, implBuilder.getLabel("switch_target_1")), new SwitchLabelElement(5, implBuilder.getLabel("switch_target_2")), new SwitchLabelElement(10, implBuilder.getLabel("switch_target_3")))));
implBuilder.addLabel("goto_target");
implBuilder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
implBuilder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
implBuilder.addLabel("switch_target_2");
implBuilder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
implBuilder.addLabel("switch_target_3");
implBuilder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
implBuilder.addInstruction(new BuilderInstruction31t(Opcode.SPARSE_SWITCH, 0, implBuilder.getLabel("switch_payload")));
List<Instruction> instructions = Lists.newArrayList(implBuilder.getMethodImplementation().getInstructions());
checkInstructions(instructions, new Opcode[] { Opcode.GOTO, Opcode.NOP, Opcode.SPARSE_SWITCH_PAYLOAD, Opcode.NOP, Opcode.NOP, Opcode.NOP, Opcode.NOP, Opcode.SPARSE_SWITCH });
OffsetInstruction gotoInstruction = (OffsetInstruction) instructions.get(0);
Assert.assertEquals(16, gotoInstruction.getCodeOffset());
SparseSwitchPayload payload = (SparseSwitchPayload) instructions.get(2);
Assert.assertEquals(3, payload.getSwitchElements().size());
Assert.assertEquals(-20, payload.getSwitchElements().get(0).getOffset());
Assert.assertEquals(-2, payload.getSwitchElements().get(1).getOffset());
Assert.assertEquals(-1, payload.getSwitchElements().get(2).getOffset());
OffsetInstruction referent = (OffsetInstruction) instructions.get(7);
Assert.assertEquals(-18, referent.getCodeOffset());
}
use of org.jf.dexlib2.builder.MethodImplementationBuilder in project smali by JesusFreke.
the class PayloadAlignmentTest method testPayloadAlignmentAddNopWithReferent.
@Test
public void testPayloadAlignmentAddNopWithReferent() {
MethodImplementationBuilder implBuilder = new MethodImplementationBuilder(10);
Label label = implBuilder.getLabel("array_payload");
implBuilder.addInstruction(new BuilderInstruction31t(Opcode.FILL_ARRAY_DATA, 0, label));
implBuilder.addInstruction(new BuilderInstruction12x(Opcode.MOVE, 0, 0));
implBuilder.addInstruction(new BuilderInstruction12x(Opcode.MOVE, 0, 0));
implBuilder.addInstruction(new BuilderInstruction12x(Opcode.MOVE, 0, 0));
implBuilder.addInstruction(new BuilderInstruction12x(Opcode.MOVE, 0, 0));
implBuilder.addLabel("array_payload");
implBuilder.addInstruction(new BuilderArrayPayload(4, null));
List<Instruction> instructions = Lists.newArrayList(implBuilder.getMethodImplementation().getInstructions());
checkInstructions(instructions, new Opcode[] { Opcode.FILL_ARRAY_DATA, Opcode.MOVE, Opcode.MOVE, Opcode.MOVE, Opcode.MOVE, Opcode.NOP, Opcode.ARRAY_PAYLOAD });
Instruction31t referent = (Instruction31t) instructions.get(0);
Assert.assertEquals(8, referent.getCodeOffset());
}
use of org.jf.dexlib2.builder.MethodImplementationBuilder in project smali by JesusFreke.
the class PayloadAlignmentTest method testPackedSwitchAlignment.
@Test
public void testPackedSwitchAlignment() {
MethodImplementationBuilder implBuilder = new MethodImplementationBuilder(10);
implBuilder.addLabel("switch_target_1");
implBuilder.addInstruction(new BuilderInstruction10t(Opcode.GOTO, implBuilder.getLabel("goto_target")));
implBuilder.addLabel("switch_payload");
implBuilder.addInstruction(new BuilderPackedSwitchPayload(0, Lists.newArrayList(implBuilder.getLabel("switch_target_1"), implBuilder.getLabel("switch_target_2"), implBuilder.getLabel("switch_target_3"))));
implBuilder.addLabel("goto_target");
implBuilder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
implBuilder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
implBuilder.addLabel("switch_target_2");
implBuilder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
implBuilder.addLabel("switch_target_3");
implBuilder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
implBuilder.addInstruction(new BuilderInstruction31t(Opcode.PACKED_SWITCH, 0, implBuilder.getLabel("switch_payload")));
List<Instruction> instructions = Lists.newArrayList(implBuilder.getMethodImplementation().getInstructions());
checkInstructions(instructions, new Opcode[] { Opcode.GOTO, Opcode.NOP, Opcode.PACKED_SWITCH_PAYLOAD, Opcode.NOP, Opcode.NOP, Opcode.NOP, Opcode.NOP, Opcode.PACKED_SWITCH });
OffsetInstruction gotoInstruction = (OffsetInstruction) instructions.get(0);
Assert.assertEquals(12, gotoInstruction.getCodeOffset());
PackedSwitchPayload payload = (PackedSwitchPayload) instructions.get(2);
Assert.assertEquals(3, payload.getSwitchElements().size());
Assert.assertEquals(-16, payload.getSwitchElements().get(0).getOffset());
Assert.assertEquals(-2, payload.getSwitchElements().get(1).getOffset());
Assert.assertEquals(-1, payload.getSwitchElements().get(2).getOffset());
OffsetInstruction referent = (OffsetInstruction) instructions.get(7);
Assert.assertEquals(-14, referent.getCodeOffset());
}
Aggregations