use of soot.Unit in project soot by Sable.
the class StmtTemplatePrinter method caseLookupSwitchStmt.
public void caseLookupSwitchStmt(LookupSwitchStmt stmt) {
p.openBlock();
String keyVarName = printValueAssignment(stmt.getKey(), "key");
p.println("List<IntConstant> lookupValues = new LinkedList<IntConstant>();");
int i = 0;
for (IntConstant c : (List<IntConstant>) stmt.getLookupValues()) {
vtp.suggestVariableName("lookupValue" + i);
c.apply(vtp);
i++;
p.println("lookupValues.add(lookupValue" + i + ");");
}
p.println("List<Unit> targets = new LinkedList<Unit>();");
for (Unit u : stmt.getTargets()) {
String nameOfJumpTarget = nameOfJumpTarget(u);
p.println("targets.add(" + nameOfJumpTarget + ")");
}
Unit defaultTarget = stmt.getDefaultTarget();
p.println("Unit defaultTarget=" + defaultTarget.toString() + ";");
printStmt(stmt, keyVarName, "lookupValues", "targets", "defaultTarget");
p.closeBlock();
}
use of soot.Unit in project soot by Sable.
the class TrapSplitter method internalTransform.
@Override
protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
// If we have less then two traps, there's nothing to do here
if (b.getTraps().size() < 2)
return;
// Look for overlapping traps
TrapOverlap to;
while ((to = getNextOverlap(b)) != null) {
// If one of the two traps is empty, we remove it
if (to.t1.getBeginUnit() == to.t1.getEndUnit()) {
b.getTraps().remove(to.t1);
continue;
}
if (to.t2.getBeginUnit() == to.t2.getEndUnit()) {
b.getTraps().remove(to.t2);
continue;
}
// t1start..t2start -> t1'start...t1'end,t2start...
if (to.t1.getBeginUnit() != to.t2Start) {
// We need to split off t1.start - predOf(t2.splitUnit). If both traps
// start at the same statement, this range is empty, so we have checked
// that.
Trap newTrap = Jimple.v().newTrap(to.t1.getException(), to.t1.getBeginUnit(), to.t2Start, to.t1.getHandlerUnit());
safeAddTrap(b, newTrap, to.t1);
to.t1.setBeginUnit(to.t2Start);
} else // (t1start, t2start) ... t1end ... t2end
if (to.t1.getBeginUnit() == to.t2.getBeginUnit()) {
Unit firstEndUnit = to.t1.getBeginUnit();
while (firstEndUnit != to.t1.getEndUnit() && firstEndUnit != to.t2.getEndUnit()) firstEndUnit = b.getUnits().getSuccOf(firstEndUnit);
if (firstEndUnit == to.t1.getEndUnit()) {
if (to.t1.getException() != to.t2.getException()) {
Trap newTrap = Jimple.v().newTrap(to.t2.getException(), to.t1.getBeginUnit(), firstEndUnit, to.t2.getHandlerUnit());
safeAddTrap(b, newTrap, to.t2);
} else if (to.t1.getHandlerUnit() != to.t2.getHandlerUnit()) {
// Traps t1 and t2 catch the same exception, but have different handlers
//
// The JVM specification (2.10 Exceptions) says:
// "At run time, when an exception is thrown, the Java
// Virtual Machine searches the exception handlers of the current method in the order
// that they appear in the corresponding exception handler table in the class file,
// starting from the beginning of that table. Note that the Java Virtual Machine does
// not enforce nesting of or any ordering of the exception table entries of a method.
// The exception handling semantics of the Java programming language are implemented
// only through cooperation with the compiler (3.12)."
//
// 3.12
// "The nesting of catch clauses is represented only in the exception table. The Java
// Virtual Machine does not enforce nesting of or any ordering of the exception table
// entries (2.10). However, because try-catch constructs are structured, a compiler
// can always order the entries of the exception handler table such that, for any thrown
// exception and any program counter value in that method, the first exception handler
// that matches the thrown exception corresponds to the innermost matching catch clause."
//
// t1 is first, so it stays the same.
// t2 is reduced
Trap newTrap = Jimple.v().newTrap(to.t1.getException(), to.t1.getBeginUnit(), firstEndUnit, to.t1.getHandlerUnit());
safeAddTrap(b, newTrap, to.t1);
}
to.t2.setBeginUnit(firstEndUnit);
} else if (firstEndUnit == to.t2.getEndUnit()) {
if (to.t1.getException() != to.t2.getException()) {
Trap newTrap2 = Jimple.v().newTrap(to.t1.getException(), to.t1.getBeginUnit(), firstEndUnit, to.t1.getHandlerUnit());
safeAddTrap(b, newTrap2, to.t1);
to.t1.setBeginUnit(firstEndUnit);
} else if (to.t1.getHandlerUnit() != to.t2.getHandlerUnit()) {
// If t2 ends first, t2 is useless.
b.getTraps().remove(to.t2);
} else {
to.t1.setBeginUnit(firstEndUnit);
}
}
}
}
}
use of soot.Unit in project soot by Sable.
the class Shimple method redirectToPreds.
/**
* If you are removing a Unit from a Unit chain which contains
* PhiExpr's, you might want to call this utility function in
* order to update any PhiExpr pointers to the Unit to point to
* the Unit's predecessor(s). This function will not modify
* "branch target" UnitBoxes.
*
* <p> Normally you should not have to call this function
* directly, since patching is taken care of Shimple's internal
* implementation of PatchingChain.
*/
public static void redirectToPreds(Body body, Unit remove) {
boolean debug = Options.v().debug();
if (body instanceof ShimpleBody)
debug |= ((ShimpleBody) body).getOptions().debug();
Chain<Unit> units = body.getUnits();
/* Determine whether we should continue processing or not. */
List<UnitBox> boxesPointingToThis = remove.getBoxesPointingToThis();
if (boxesPointingToThis.isEmpty())
return;
for (UnitBox pointer : boxesPointingToThis) {
// continue iteration from where we left off.
if (!pointer.isBranchTarget())
break;
}
/* Ok, continuing... */
Set<Unit> preds = new HashSet<Unit>();
Set<PhiExpr> phis = new HashSet<PhiExpr>();
// find fall-through pred
if (!remove.equals(units.getFirst())) {
Unit possiblePred = (Unit) units.getPredOf(remove);
if (possiblePred.fallsThrough())
preds.add(possiblePred);
}
// find the rest of the preds and all Phi's that point to remove
for (Unit unit : units) {
for (UnitBox targetBox : unit.getUnitBoxes()) {
if (remove.equals(targetBox.getUnit())) {
if (targetBox.isBranchTarget())
preds.add(unit);
else {
PhiExpr phiExpr = Shimple.getPhiExpr(unit);
if (phiExpr != null)
phis.add(phiExpr);
}
}
}
}
if (phis.size() == 0) {
if (debug)
logger.warn("Orphaned UnitBoxes to " + remove + "? Shimple.redirectToPreds is giving up.");
return;
}
if (preds.size() == 0) {
if (debug)
logger.warn("Shimple.redirectToPreds couldn't find any predecessors for " + remove + " in " + body.getMethod() + ".");
if (!remove.equals(units.getFirst())) {
Unit pred = (Unit) units.getPredOf(remove);
if (debug)
logger.warn("Falling back to immediate chain predecessor: " + pred + ".");
preds.add(pred);
} else if (!remove.equals(units.getLast())) {
Unit succ = (Unit) units.getSuccOf(remove);
if (debug)
logger.warn("Falling back to immediate chain successor: " + succ + ".");
preds.add(succ);
} else
throw new RuntimeException("Assertion failed.");
}
/* At this point we have found all the preds and relevant Phi's */
/* Each Phi needs an argument for each pred. */
Iterator<PhiExpr> phiIt = phis.iterator();
while (phiIt.hasNext()) {
PhiExpr phiExpr = phiIt.next();
ValueUnitPair argBox = phiExpr.getArgBox(remove);
if (argBox == null)
throw new RuntimeException("Assertion failed.");
// now we've got the value!
Value arg = argBox.getValue();
phiExpr.removeArg(argBox);
// add new arguments to Phi
Iterator<Unit> predsIt = preds.iterator();
while (predsIt.hasNext()) {
Unit pred = predsIt.next();
phiExpr.addArg(arg, pred);
}
}
}
use of soot.Unit in project soot by Sable.
the class TagAggregator method internalTransform.
protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
BafBody body = (BafBody) b;
LinkedList<Tag> tags = new LinkedList<Tag>();
LinkedList<Unit> units = new LinkedList<Unit>();
/* aggregate all tags */
for (Iterator<Unit> unitIt = body.getUnits().iterator(); unitIt.hasNext(); ) {
final Unit unit = unitIt.next();
for (Iterator<Tag> tagIt = unit.getTags().iterator(); tagIt.hasNext(); ) {
final Tag tag = tagIt.next();
if (wantTag(tag))
considerTag(tag, unit, tags, units);
}
}
if (units.size() > 0) {
b.addTag(new CodeAttribute(aggregatedName(), new LinkedList<Unit>(units), new LinkedList<Tag>(tags)));
}
fini();
}
use of soot.Unit 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);
}
}
}
}
Aggregations