use of soot.tagkit.LineNumberTag 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 soot.tagkit.LineNumberTag in project soot by Sable.
the class OutFlow method jimplify.
/**
* Main.v() entry point for converting list of Instructions to Jimple statements;
* performs flow analysis, constructs Jimple statements, and fixes jumps.
* @param constant_pool constant pool of ClassFile.
* @param this_class constant pool index of the CONSTANT_Class_info object for
* this' class.
* @param clearStacks if <i>true</i> semantic stacks will be deleted after
* the process is complete.
* @return <i>true</i> if all ok, <i>false</i> if there was an error.
* @see CFG#jimplify(cp_info[], int)
* @see Stmt
*/
void jimplify(cp_info[] constant_pool, int this_class) {
Code_attribute codeAttribute = method.locate_code_attribute();
Set<Instruction> handlerInstructions = new ArraySet<Instruction>();
Map<Instruction, SootClass> handlerInstructionToException = new HashMap<Instruction, SootClass>();
Map<Instruction, TypeStack> instructionToTypeStack;
Map<Instruction, TypeStack> instructionToPostTypeStack;
{
// build graph in
buildInsnCFGfromBBCFG();
// Put in successors due to exception handlers
{
for (int i = 0; i < codeAttribute.exception_table_length; i++) {
Instruction startIns = codeAttribute.exception_table[i].start_inst;
Instruction endIns = codeAttribute.exception_table[i].end_inst;
Instruction handlerIns = codeAttribute.exception_table[i].handler_inst;
handlerInstructions.add(handlerIns);
// Determine exception to catch
{
int catchType = codeAttribute.exception_table[i].catch_type;
SootClass exception;
if (catchType != 0) {
CONSTANT_Class_info classinfo = (CONSTANT_Class_info) constant_pool[catchType];
String name = ((CONSTANT_Utf8_info) (constant_pool[classinfo.name_index])).convert();
name = name.replace('/', '.');
exception = cm.getSootClass(name);
} else
exception = cm.getSootClass("java.lang.Throwable");
handlerInstructionToException.put(handlerIns, exception);
}
if (startIns == endIns)
throw new RuntimeException("Empty catch range for exception handler");
Instruction ins = startIns;
for (; ; ) {
Instruction[] succs = ins.succs;
Instruction[] newsuccs = new Instruction[succs.length + 1];
System.arraycopy(succs, 0, newsuccs, 0, succs.length);
newsuccs[succs.length] = handlerIns;
ins.succs = newsuccs;
ins = ins.next;
if (ins == endIns || ins == null)
break;
}
}
}
}
Set<Instruction> reachableInstructions = new HashSet<Instruction>();
// Mark all the reachable instructions
{
LinkedList<Instruction> instructionsToVisit = new LinkedList<Instruction>();
reachableInstructions.add(firstInstruction);
instructionsToVisit.addLast(firstInstruction);
while (!instructionsToVisit.isEmpty()) {
Instruction ins = instructionsToVisit.removeFirst();
Instruction[] succs = ins.succs;
for (Instruction succ : succs) {
if (!reachableInstructions.contains(succ)) {
reachableInstructions.add(succ);
instructionsToVisit.addLast(succ);
}
}
}
}
/*
// Check to see if any instruction is unmarked.
{
BasicBlock b = cfg;
while(b != null)
{
Instruction ins = b.head;
while(ins != null)
{
if(!reachableInstructions.contains(ins))
throw new RuntimeException("Method to jimplify contains unreachable code! (not handled for now)");
ins = ins.next;
}
b = b.next;
}
}
*/
// Perform the flow analysis, and build up instructionToTypeStack and instructionToLocalArray
{
instructionToTypeStack = new HashMap<Instruction, TypeStack>();
instructionToPostTypeStack = new HashMap<Instruction, TypeStack>();
Set<Instruction> visitedInstructions = new HashSet<Instruction>();
List<Instruction> changedInstructions = new ArrayList<Instruction>();
TypeStack initialTypeStack;
// Build up initial type stack and initial local array (for the first instruction)
{
initialTypeStack = TypeStack.v();
// the empty stack with nothing on it.
}
// Get the loop cranked up.
{
instructionToTypeStack.put(firstInstruction, initialTypeStack);
visitedInstructions.add(firstInstruction);
changedInstructions.add(firstInstruction);
}
{
while (!changedInstructions.isEmpty()) {
Instruction ins = changedInstructions.get(0);
changedInstructions.remove(0);
OutFlow ret = processFlow(ins, instructionToTypeStack.get(ins), constant_pool);
instructionToPostTypeStack.put(ins, ret.typeStack);
Instruction[] successors = ins.succs;
for (Instruction s : successors) {
if (!visitedInstructions.contains(s)) {
if (handlerInstructions.contains(s)) {
TypeStack exceptionTypeStack = (TypeStack.v()).push(RefType.v(handlerInstructionToException.get(s).getName()));
instructionToTypeStack.put(s, exceptionTypeStack);
} else {
instructionToTypeStack.put(s, ret.typeStack);
}
visitedInstructions.add(s);
changedInstructions.add(s);
// logger.debug("adding successor: " + s);
} else {
// logger.debug("considering successor: " + s);
TypeStack newTypeStack, oldTypeStack = instructionToTypeStack.get(s);
if (handlerInstructions.contains(s)) {
// The type stack for an instruction handler should always be that of
// single object on the stack.
TypeStack exceptionTypeStack = (TypeStack.v()).push(RefType.v(handlerInstructionToException.get(s).getName()));
newTypeStack = exceptionTypeStack;
} else {
try {
newTypeStack = ret.typeStack.merge(oldTypeStack);
} catch (RuntimeException re) {
logger.debug("Considering " + s);
throw re;
}
}
if (!newTypeStack.equals(oldTypeStack)) {
changedInstructions.add(s);
// logger.debug("requires a revisit: " + s);
}
instructionToTypeStack.put(s, newTypeStack);
}
}
}
}
}
// logger.debug("Producing Jimple code...");
// Jimplify each statement
{
BasicBlock b = cfg;
while (b != null) {
Instruction ins = b.head;
b.statements = new ArrayList<Stmt>();
List<Stmt> blockStatements = b.statements;
for (; ; ) {
List<Stmt> statementsForIns = new ArrayList<Stmt>();
if (reachableInstructions.contains(ins))
generateJimple(ins, instructionToTypeStack.get(ins), instructionToPostTypeStack.get(ins), constant_pool, statementsForIns, b);
else
statementsForIns.add(Jimple.v().newNopStmt());
if (!statementsForIns.isEmpty()) {
for (int i = 0; i < statementsForIns.size(); i++) {
units.add(statementsForIns.get(i));
blockStatements.add(statementsForIns.get(i));
}
instructionToFirstStmt.put(ins, statementsForIns.get(0));
instructionToLastStmt.put(ins, statementsForIns.get(statementsForIns.size() - 1));
}
if (ins == b.tail)
break;
ins = ins.next;
}
b = b.next;
}
}
// fix up jump targets
jimpleTargetFixup();
/*
// Print out basic blocks
{
BasicBlock b = cfg;
logger.debug("Basic blocks for: " + jmethod.getName());
while(b != null)
{
Instruction ins = b.head;
while(ins != null)
{
logger.debug(""+ins.toString());
ins = ins.next;
}
b = b.next;
}
}
*/
// Insert beginCatch/endCatch statements for exception handling
{
Map<Stmt, Stmt> targetToHandler = new HashMap<Stmt, Stmt>();
for (int i = 0; i < codeAttribute.exception_table_length; i++) {
Instruction startIns = codeAttribute.exception_table[i].start_inst;
Instruction endIns = codeAttribute.exception_table[i].end_inst;
Instruction targetIns = codeAttribute.exception_table[i].handler_inst;
if (!instructionToFirstStmt.containsKey(startIns) || (endIns != null && (!instructionToLastStmt.containsKey(endIns)))) {
throw new RuntimeException("Exception range does not coincide with jimple instructions");
}
if (!instructionToFirstStmt.containsKey(targetIns)) {
throw new RuntimeException("Exception handler does not coincide with jimple instruction");
}
SootClass exception;
// Determine exception to catch
{
int catchType = codeAttribute.exception_table[i].catch_type;
if (catchType != 0) {
CONSTANT_Class_info classinfo = (CONSTANT_Class_info) constant_pool[catchType];
String name = ((CONSTANT_Utf8_info) (constant_pool[classinfo.name_index])).convert();
name = name.replace('/', '.');
exception = cm.getSootClass(name);
} else
exception = cm.getSootClass("java.lang.Throwable");
}
Stmt newTarget;
// Insert assignment of exception
{
Stmt firstTargetStmt = instructionToFirstStmt.get(targetIns);
if (targetToHandler.containsKey(firstTargetStmt))
newTarget = targetToHandler.get(firstTargetStmt);
else {
Local local = Util.v().getLocalCreatingIfNecessary(listBody, "$stack0", UnknownType.v());
newTarget = Jimple.v().newIdentityStmt(local, Jimple.v().newCaughtExceptionRef());
// changed to account for catch blocks which are also part of normal control flow
// units.insertBefore(newTarget, firstTargetStmt);
((PatchingChain<Unit>) units).insertBeforeNoRedirect(newTarget, firstTargetStmt);
targetToHandler.put(firstTargetStmt, newTarget);
if (units.getFirst() != newTarget) {
Unit prev = (Unit) units.getPredOf(newTarget);
if (prev != null && prev.fallsThrough())
units.insertAfter(Jimple.v().newGotoStmt(firstTargetStmt), prev);
}
}
}
// Insert trap
{
Stmt firstStmt = instructionToFirstStmt.get(startIns);
Stmt afterEndStmt;
if (endIns == null) {
// A kludge which isn't really correct, but
// gets us closer to correctness (until we
// clean up the rest of Soot to properly
// represent Traps which extend to the end
// of a method): if the protected code extends
// to the end of the method, use the last Stmt
// as the endUnit of the Trap, even though
// that will leave the last unit outside
// the protected area.
afterEndStmt = (Stmt) units.getLast();
} else {
afterEndStmt = instructionToLastStmt.get(endIns);
IdentityStmt catchStart = (IdentityStmt) targetToHandler.get(afterEndStmt);
// (Cast to IdentityStmt as an assertion check.)
if (catchStart != null) {
// before the old afterEndStmt.
if (catchStart != units.getPredOf(afterEndStmt)) {
throw new IllegalStateException("Assertion failure: catchStart != pred of afterEndStmt");
}
afterEndStmt = catchStart;
}
}
Trap trap = Jimple.v().newTrap(exception, firstStmt, afterEndStmt, newTarget);
listBody.getTraps().add(trap);
}
}
}
/* convert line number table to tags attached to statements */
if (Options.v().keep_line_number()) {
HashMap<Stmt, Tag> stmtstags = new HashMap<Stmt, Tag>();
LinkedList<Stmt> startstmts = new LinkedList<Stmt>();
attribute_info[] attrs = codeAttribute.attributes;
for (attribute_info element : attrs) {
if (element instanceof LineNumberTable_attribute) {
LineNumberTable_attribute lntattr = (LineNumberTable_attribute) element;
for (line_number_table_entry element0 : lntattr.line_number_table) {
Stmt start_stmt = instructionToFirstStmt.get(element0.start_inst);
if (start_stmt != null) {
LineNumberTag lntag = new LineNumberTag(element0.line_number);
stmtstags.put(start_stmt, lntag);
startstmts.add(start_stmt);
}
}
}
}
/* if the predecessor of a statement is a caughtexcetionref,
* give it the tag of its successor */
for (Iterator<Stmt> stmtIt = new ArrayList<Stmt>(stmtstags.keySet()).iterator(); stmtIt.hasNext(); ) {
final Stmt stmt = stmtIt.next();
Stmt pred = stmt;
Tag tag = stmtstags.get(stmt);
while (true) {
pred = (Stmt) units.getPredOf(pred);
if (pred == null)
break;
if (!(pred instanceof IdentityStmt))
break;
stmtstags.put(pred, tag);
pred.addTag(tag);
}
}
/* attach line number tag to each statement. */
for (int i = 0; i < startstmts.size(); i++) {
Stmt stmt = startstmts.get(i);
Tag tag = stmtstags.get(stmt);
stmt.addTag(tag);
stmt = (Stmt) units.getSuccOf(stmt);
while (stmt != null && !stmtstags.containsKey(stmt)) {
stmt.addTag(tag);
stmt = (Stmt) units.getSuccOf(stmt);
}
}
}
}
use of soot.tagkit.LineNumberTag in project soot by Sable.
the class BafASMBackend method generateMethodBody.
/*
* (non-Javadoc)
*
* @see soot.AbstractASMBackend#generateMethodBody(org.objectweb.asm.
* MethodVisitor, soot.SootMethod)
*/
@Override
protected void generateMethodBody(MethodVisitor mv, SootMethod method) {
BafBody body = getBafBody(method);
Chain<Unit> instructions = body.getUnits();
/*
* Create a label for each instruction that is the target of some branch
*/
for (UnitBox box : body.getUnitBoxes(true)) {
Unit u = box.getUnit();
if (!branchTargetLabels.containsKey(u)) {
branchTargetLabels.put(u, new Label());
}
}
Label startLabel = null;
if (Options.v().write_local_annotations()) {
startLabel = new Label();
mv.visitLabel(startLabel);
}
/*
* Handle all TRY-CATCH-blocks
*/
for (Trap trap : body.getTraps()) {
// Check if the try-block contains any statement
if (trap.getBeginUnit() != trap.getEndUnit()) {
Label start = branchTargetLabels.get(trap.getBeginUnit());
Label end = branchTargetLabels.get(trap.getEndUnit());
Label handler = branchTargetLabels.get(trap.getHandlerUnit());
String type = slashify(trap.getException().getName());
mv.visitTryCatchBlock(start, end, handler, type);
}
}
/*
* Handle local variable slots for the "this"-local and the parameters
*/
int localCount = 0;
int[] paramSlots = new int[method.getParameterCount()];
Set<Local> assignedLocals = new HashSet<Local>();
/*
* For non-static methods the first parameters and zero-slot is the
* "this"-local
*/
if (!method.isStatic()) {
++localCount;
}
for (int i = 0; i < method.getParameterCount(); ++i) {
paramSlots[i] = localCount;
localCount += sizeOfType(method.getParameterType(i));
}
for (Unit u : instructions) {
if (u instanceof IdentityInst && ((IdentityInst) u).getLeftOp() instanceof Local) {
Local l = (Local) ((IdentityInst) u).getLeftOp();
IdentityRef identity = (IdentityRef) ((IdentityInst) u).getRightOp();
int slot = 0;
if (identity instanceof ThisRef) {
if (method.isStatic())
throw new RuntimeException("Attempting to use 'this' in static method");
} else if (identity instanceof ParameterRef)
slot = paramSlots[((ParameterRef) identity).getIndex()];
else {
// Exception ref. Skip over this
continue;
}
localToSlot.put(l, slot);
assignedLocals.add(l);
}
}
for (Local local : body.getLocals()) {
if (assignedLocals.add(local)) {
localToSlot.put(local, localCount);
localCount += sizeOfType(local.getType());
}
}
// Generate the code
for (Unit u : instructions) {
if (branchTargetLabels.containsKey(u)) {
mv.visitLabel(branchTargetLabels.get(u));
}
if (u.hasTag("LineNumberTag")) {
LineNumberTag lnt = (LineNumberTag) u.getTag("LineNumberTag");
Label l;
if (branchTargetLabels.containsKey(u)) {
l = branchTargetLabels.get(u);
} else {
l = new Label();
mv.visitLabel(l);
}
mv.visitLineNumber(lnt.getLineNumber(), l);
}
generateInstruction(mv, (Inst) u);
}
// Generate the local annotations
if (Options.v().write_local_annotations()) {
Label endLabel = new Label();
mv.visitLabel(endLabel);
for (Local local : body.getLocals()) {
Integer slot = localToSlot.get(local);
if (slot != null) {
BafLocal l = (BafLocal) local;
if (l.getOriginalLocal() != null) {
Local jimpleLocal = l.getOriginalLocal();
if (jimpleLocal != null)
mv.visitLocalVariable(jimpleLocal.getName(), toTypeDesc(jimpleLocal.getType()), null, startLabel, endLabel, slot);
}
}
}
}
}
use of soot.tagkit.LineNumberTag in project soot by Sable.
the class DexBody method jimplify.
/**
* Return the jimple equivalent of this body.
*
* @param m
* the SootMethod that contains this body
*/
public Body jimplify(Body b, SootMethod m) {
final Jimple jimple = Jimple.v();
final UnknownType unknownType = UnknownType.v();
final NullConstant nullConstant = NullConstant.v();
final Options options = Options.v();
/*
* Timer t_whole_jimplification = new Timer(); Timer t_num = new
* Timer(); Timer t_null = new Timer();
*
* t_whole_jimplification.start();
*/
jBody = (JimpleBody) b;
deferredInstructions = new ArrayList<DeferableInstruction>();
instructionsToRetype = new HashSet<RetypeableInstruction>();
if (IDalvikTyper.ENABLE_DVKTYPER) {
DalvikTyper.v().clear();
}
// process method parameters and generate Jimple locals from Dalvik
// registers
List<Local> paramLocals = new LinkedList<Local>();
if (!isStatic) {
int thisRegister = numRegisters - numParameterRegisters - 1;
// generateLocal(UnknownType.v());
Local thisLocal = jimple.newLocal("$u" + thisRegister, unknownType);
jBody.getLocals().add(thisLocal);
registerLocals[thisRegister] = thisLocal;
JIdentityStmt idStmt = (JIdentityStmt) jimple.newIdentityStmt(thisLocal, jimple.newThisRef(declaringClassType));
add(idStmt);
paramLocals.add(thisLocal);
if (IDalvikTyper.ENABLE_DVKTYPER) {
DalvikTyper.v().setType(idStmt.leftBox, jBody.getMethod().getDeclaringClass().getType(), false);
}
}
{
// index of parameter type
int i = 0;
// index
int parameterRegister = numRegisters - numParameterRegisters;
// register
for (Type t : parameterTypes) {
// may
Local gen = jimple.newLocal("$u" + parameterRegister, unknownType);
// only
// use
// UnknownType
// here
// because
// the
// local
// may
// be
// reused
// with
// a
// different
// type
// later
// (before
// splitting)
jBody.getLocals().add(gen);
registerLocals[parameterRegister] = gen;
JIdentityStmt idStmt = (JIdentityStmt) jimple.newIdentityStmt(gen, jimple.newParameterRef(t, i++));
add(idStmt);
paramLocals.add(gen);
if (IDalvikTyper.ENABLE_DVKTYPER) {
DalvikTyper.v().setType(idStmt.leftBox, t, false);
}
// used later in the Dalvik bytecode
if (t instanceof LongType || t instanceof DoubleType) {
parameterRegister++;
// may
Local g = jimple.newLocal("$u" + parameterRegister, unknownType);
// only
// use
// UnknownType
// here
// because
// the
// local
// may
// be
// reused
// with
// a
// different
// type
// later
// (before
// splitting)
jBody.getLocals().add(g);
registerLocals[parameterRegister] = g;
}
parameterRegister++;
}
}
for (int i = 0; i < (numRegisters - numParameterRegisters - (isStatic ? 0 : 1)); i++) {
registerLocals[i] = jimple.newLocal("$u" + i, unknownType);
jBody.getLocals().add(registerLocals[i]);
}
// add local to store intermediate results
storeResultLocal = jimple.newLocal("$u-1", unknownType);
jBody.getLocals().add(storeResultLocal);
// process bytecode instructions
final boolean isOdex = dexFile instanceof DexBackedDexFile ? ((DexBackedDexFile) dexFile).isOdexFile() : false;
ClassPath cp = null;
if (isOdex) {
String[] sootClasspath = options.soot_classpath().split(File.pathSeparator);
List<String> classpathList = new ArrayList<String>();
for (String str : sootClasspath) classpathList.add(str);
try {
ClassPathResolver resolver = new ClassPathResolver(classpathList, classpathList, classpathList, dexFile);
cp = new ClassPath(resolver.getResolvedClassProviders().toArray(new ClassProvider[0]));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
int prevLineNumber = -1;
for (DexlibAbstractInstruction instruction : instructions) {
if (isOdex && instruction instanceof OdexInstruction)
((OdexInstruction) instruction).deOdex(dexFile, method, cp);
if (dangling != null) {
dangling.finalize(this, instruction);
dangling = null;
}
instruction.jimplify(this);
if (instruction.getLineNumber() > 0)
prevLineNumber = instruction.getLineNumber();
else {
instruction.setLineNumber(prevLineNumber);
}
}
for (DeferableInstruction instruction : deferredInstructions) {
instruction.deferredJimplify(this);
}
if (tries != null)
addTraps();
int prevLn = -1;
final boolean keepLineNumber = options.keep_line_number();
for (DexlibAbstractInstruction instruction : instructions) {
Unit unit = instruction.getUnit();
int lineNumber = unit.getJavaSourceStartLineNumber();
if (keepLineNumber && lineNumber < 0) {
if (prevLn >= 0) {
unit.addTag(new LineNumberTag(prevLn));
unit.addTag(new SourceLineNumberTag(prevLn));
}
} else {
prevLn = lineNumber;
}
}
// At this point Jimple code is generated
// Cleaning...
instructions = null;
// registerLocals = null;
// storeResultLocal = null;
instructionAtAddress.clear();
// localGenerator = null;
deferredInstructions = null;
// instructionsToRetype = null;
dangling = null;
tries = null;
/*
* We eliminate dead code. Dead code has been shown to occur under the
* following circumstances.
*
* 0006ec: 0d00 |00a2: move-exception v0 ... 0006f2: 0d00 |00a5:
* move-exception v0 ... 0x0041 - 0x008a Ljava/lang/Throwable; -> 0x00a5
* <any> -> 0x00a2
*
* Here there are two traps both over the same region. But the same
* always fires, hence rendering the code at a2 unreachable. Dead code
* yields problems during local splitting because locals within dead
* code will not be split. Hence we remove all dead code here.
*/
// Fix traps that do not catch exceptions
DexTrapStackFixer.v().transform(jBody);
// Sort out jump chains
DexJumpChainShortener.v().transform(jBody);
// Make sure that we don't have any overlapping uses due to returns
DexReturnInliner.v().transform(jBody);
// Shortcut: Reduce array initializations
DexArrayInitReducer.v().transform(jBody);
// split first to find undefined uses
getLocalSplitter().transform(jBody);
// Remove dead code and the corresponding locals before assigning types
getUnreachableCodeEliminator().transform(jBody);
DeadAssignmentEliminator.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
for (RetypeableInstruction i : instructionsToRetype) i.retype(jBody);
if (IDalvikTyper.ENABLE_DVKTYPER) {
DexReturnValuePropagator.v().transform(jBody);
getCopyPopagator().transform(jBody);
DexNullThrowTransformer.v().transform(jBody);
DalvikTyper.v().typeUntypedConstrantInDiv(jBody);
DeadAssignmentEliminator.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
DalvikTyper.v().assignType(jBody);
// jBody.validate();
jBody.validateUses();
jBody.validateValueBoxes();
// jBody.checkInit();
// Validate.validateArrays(jBody);
// jBody.checkTypes();
// jBody.checkLocals();
} else {
// t_num.start();
DexNumTransformer.v().transform(jBody);
// t_num.end();
DexReturnValuePropagator.v().transform(jBody);
getCopyPopagator().transform(jBody);
DexNullThrowTransformer.v().transform(jBody);
// t_null.start();
DexNullTransformer.v().transform(jBody);
// t_null.end();
DexIfTransformer.v().transform(jBody);
DeadAssignmentEliminator.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
// DexRefsChecker.v().transform(jBody);
DexNullArrayRefTransformer.v().transform(jBody);
}
if (IDalvikTyper.ENABLE_DVKTYPER) {
for (Local l : jBody.getLocals()) {
l.setType(unknownType);
}
}
// Remove "instanceof" checks on the null constant
DexNullInstanceofTransformer.v().transform(jBody);
TypeAssigner.v().transform(jBody);
final RefType objectType = RefType.v("java.lang.Object");
if (IDalvikTyper.ENABLE_DVKTYPER) {
for (Unit u : jBody.getUnits()) {
if (u instanceof IfStmt) {
ConditionExpr expr = (ConditionExpr) ((IfStmt) u).getCondition();
if (((expr instanceof EqExpr) || (expr instanceof NeExpr))) {
Value op1 = expr.getOp1();
Value op2 = expr.getOp2();
if (op1 instanceof Constant && op2 instanceof Local) {
Local l = (Local) op2;
Type ltype = l.getType();
if (ltype instanceof PrimType)
continue;
if (// by default
!(op1 instanceof IntConstant))
// in Dalvik
continue;
IntConstant icst = (IntConstant) op1;
int val = icst.value;
if (val != 0)
continue;
expr.setOp1(nullConstant);
} else if (op1 instanceof Local && op2 instanceof Constant) {
Local l = (Local) op1;
Type ltype = l.getType();
if (ltype instanceof PrimType)
continue;
if (// by default
!(op2 instanceof IntConstant))
// in Dalvik
continue;
IntConstant icst = (IntConstant) op2;
int val = icst.value;
if (val != 0)
continue;
expr.setOp2(nullConstant);
} else if (op1 instanceof Local && op2 instanceof Local) {
// nothing to do
} else if (op1 instanceof Constant && op2 instanceof Constant) {
if (op1 instanceof NullConstant && op2 instanceof NumericConstant) {
IntConstant nc = (IntConstant) op2;
if (nc.value != 0)
throw new RuntimeException("expected value 0 for int constant. Got " + expr);
expr.setOp2(NullConstant.v());
} else if (op2 instanceof NullConstant && op1 instanceof NumericConstant) {
IntConstant nc = (IntConstant) op1;
if (nc.value != 0)
throw new RuntimeException("expected value 0 for int constant. Got " + expr);
expr.setOp1(nullConstant);
}
} else {
throw new RuntimeException("error: do not handle if: " + u);
}
}
}
}
// For null_type locals: replace their use by NullConstant()
List<ValueBox> uses = jBody.getUseBoxes();
// List<ValueBox> defs = jBody.getDefBoxes();
List<ValueBox> toNullConstantify = new ArrayList<ValueBox>();
List<Local> toRemove = new ArrayList<Local>();
for (Local l : jBody.getLocals()) {
if (l.getType() instanceof NullType) {
toRemove.add(l);
for (ValueBox vb : uses) {
Value v = vb.getValue();
if (v == l)
toNullConstantify.add(vb);
}
}
}
for (ValueBox vb : toNullConstantify) {
System.out.println("replace valuebox '" + vb + " with null constant");
vb.setValue(nullConstant);
}
for (Local l : toRemove) {
System.out.println("removing null_type local " + l);
l.setType(objectType);
}
}
// We pack locals that are not used in overlapping regions. This may
// again lead to unused locals which we have to remove.
LocalPacker.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
LocalNameStandardizer.v().transform(jBody);
// on the fly.
if (options.wrong_staticness() == Options.wrong_staticness_fix) {
FieldStaticnessCorrector.v().transform(jBody);
MethodStaticnessCorrector.v().transform(jBody);
}
// Inline PackManager.v().getPack("jb").apply(jBody);
// Keep only transformations that have not been done
// at this point.
TrapTightener.v().transform(jBody);
TrapMinimizer.v().transform(jBody);
// LocalSplitter.v().transform(jBody);
Aggregator.v().transform(jBody);
// UnusedLocalEliminator.v().transform(jBody);
// TypeAssigner.v().transform(jBody);
// LocalPacker.v().transform(jBody);
// LocalNameStandardizer.v().transform(jBody);
// Remove if (null == null) goto x else <madness>. We can only do this
// after we have run the constant propagation as we might not be able
// to statically decide the conditions earlier.
ConditionalBranchFolder.v().transform(jBody);
// Remove unnecessary typecasts
ConstantCastEliminator.v().transform(jBody);
IdentityCastEliminator.v().transform(jBody);
// Remove unnecessary logic operations
IdentityOperationEliminator.v().transform(jBody);
// We need to run this transformer since the conditional branch folder
// might have rendered some code unreachable (well, it was unreachable
// before as well, but we didn't know).
UnreachableCodeEliminator.v().transform(jBody);
// Not sure whether we need this even though we do it earlier on as
// the earlier pass does not have type information
// CopyPropagator.v().transform(jBody);
// we might have gotten new dead assignments and unused locals through
// copy propagation and unreachable code elimination, so we have to do
// this again
DeadAssignmentEliminator.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
NopEliminator.v().transform(jBody);
// Remove unnecessary chains of return statements
DexReturnPacker.v().transform(jBody);
for (Unit u : jBody.getUnits()) {
if (u instanceof AssignStmt) {
AssignStmt ass = (AssignStmt) u;
if (ass.getRightOp() instanceof CastExpr) {
CastExpr c = (CastExpr) ass.getRightOp();
if (c.getType() instanceof NullType) {
ass.setRightOp(nullConstant);
}
}
}
if (u instanceof DefinitionStmt) {
DefinitionStmt def = (DefinitionStmt) u;
// we must manually fix the hierarchy
if (def.getLeftOp() instanceof Local && def.getRightOp() instanceof CaughtExceptionRef) {
Type t = def.getLeftOp().getType();
if (t instanceof RefType) {
RefType rt = (RefType) t;
if (rt.getSootClass().isPhantom() && !rt.getSootClass().hasSuperclass() && !rt.getSootClass().getName().equals("java.lang.Throwable"))
rt.getSootClass().setSuperclass(Scene.v().getSootClass("java.lang.Throwable"));
}
}
}
}
//
for (Local l : jBody.getLocals()) {
Type t = l.getType();
if (t instanceof NullType) {
l.setType(objectType);
}
}
return jBody;
}
use of soot.tagkit.LineNumberTag in project soot by Sable.
the class JasminClass method emitStmt.
void emitStmt(Stmt stmt) {
LineNumberTag lnTag = (LineNumberTag) stmt.getTag("LineNumberTag");
if (lnTag != null)
emit(".line " + lnTag.getLineNumber());
stmt.apply(new AbstractStmtSwitch() {
public void caseAssignStmt(AssignStmt s) {
emitAssignStmt(s);
}
public void caseIdentityStmt(IdentityStmt s) {
if (s.getRightOp() instanceof CaughtExceptionRef && s.getLeftOp() instanceof Local) {
int slot = localToSlot.get(s.getLeftOp()).intValue();
// simulate the pushing of the exception onto the
modifyStackHeight(1);
if (slot >= 0 && slot <= 3)
emit("astore_" + slot, -1);
else
emit("astore " + slot, -1);
}
}
public void caseBreakpointStmt(BreakpointStmt s) {
emit("breakpoint", 0);
}
public void caseInvokeStmt(InvokeStmt s) {
emitValue(s.getInvokeExpr());
Type returnType = ((InvokeExpr) s.getInvokeExpr()).getMethodRef().returnType();
if (!returnType.equals(VoidType.v())) {
if (sizeOfType(returnType) == 1)
emit("pop", -1);
else
emit("pop2", -2);
}
}
public void caseEnterMonitorStmt(EnterMonitorStmt s) {
emitValue(s.getOp());
emit("monitorenter", -1);
}
public void caseExitMonitorStmt(ExitMonitorStmt s) {
emitValue(s.getOp());
emit("monitorexit", -1);
}
public void caseGotoStmt(GotoStmt s) {
if (isNextGotoAJsr) {
emit("jsr " + unitToLabel.get(s.getTarget()));
isNextGotoAJsr = false;
subroutineToReturnAddressSlot.put(s.getTarget(), new Integer(returnAddressSlot));
} else
emit("goto " + unitToLabel.get(s.getTarget()));
}
public void caseIfStmt(IfStmt s) {
emitIfStmt(s);
}
public void caseLookupSwitchStmt(LookupSwitchStmt s) {
emitValue(s.getKey());
emit("lookupswitch", -1);
List<IntConstant> lookupValues = s.getLookupValues();
List<Unit> targets = s.getTargets();
for (int i = 0; i < lookupValues.size(); i++) emit(" " + lookupValues.get(i) + " : " + unitToLabel.get(targets.get(i)));
emit(" default : " + unitToLabel.get(s.getDefaultTarget()));
}
public void caseNopStmt(NopStmt s) {
emit("nop", 0);
}
public void caseRetStmt(RetStmt s) {
emit("ret " + localToSlot.get(s.getStmtAddress()), 0);
}
public void caseReturnStmt(ReturnStmt s) {
emitValue(s.getOp());
Value returnValue = s.getOp();
returnValue.getType().apply(new TypeSwitch() {
public void defaultCase(Type t) {
throw new RuntimeException("invalid return type " + t.toString());
}
public void caseDoubleType(DoubleType t) {
emit("dreturn", -2);
}
public void caseFloatType(FloatType t) {
emit("freturn", -1);
}
public void caseIntType(IntType t) {
emit("ireturn", -1);
}
public void caseByteType(ByteType t) {
emit("ireturn", -1);
}
public void caseShortType(ShortType t) {
emit("ireturn", -1);
}
public void caseCharType(CharType t) {
emit("ireturn", -1);
}
public void caseBooleanType(BooleanType t) {
emit("ireturn", -1);
}
public void caseLongType(LongType t) {
emit("lreturn", -2);
}
public void caseArrayType(ArrayType t) {
emit("areturn", -1);
}
public void caseRefType(RefType t) {
emit("areturn", -1);
}
public void caseNullType(NullType t) {
emit("areturn", -1);
}
});
}
public void caseReturnVoidStmt(ReturnVoidStmt s) {
emit("return", 0);
}
public void caseTableSwitchStmt(TableSwitchStmt s) {
emitValue(s.getKey());
emit("tableswitch " + s.getLowIndex() + " ; high = " + s.getHighIndex(), -1);
List<Unit> targets = s.getTargets();
for (int i = 0; i < targets.size(); i++) emit(" " + unitToLabel.get(targets.get(i)));
emit("default : " + unitToLabel.get(s.getDefaultTarget()));
}
public void caseThrowStmt(ThrowStmt s) {
emitValue(s.getOp());
emit("athrow", -1);
}
});
}
Aggregations