use of soot.PatchingChain in project soot by Sable.
the class DavaBody method copy_Body.
/*
* Copy and patch a GrimpBody so that it can be used to output Java.
*/
private void copy_Body(Body body) {
if (!(body instanceof GrimpBody))
throw new RuntimeException("You can only create a DavaBody from a GrimpBody!");
GrimpBody grimpBody = (GrimpBody) body;
/*
* Import body contents from Grimp.
*/
{
HashMap<Switchable, Switchable> bindings = new HashMap<Switchable, Switchable>();
HashMap<Unit, Unit> reverse_binding = new HashMap<Unit, Unit>();
// Clone units in body's statement list
for (Unit original : grimpBody.getUnits()) {
Unit copy = (Unit) original.clone();
// Add cloned unit to our unitChain.
getUnits().addLast(copy);
// Build old <-> new map to be able to patch up references to other units
// within the cloned units. (these are still refering to the original
// unit objects).
bindings.put(original, copy);
reverse_binding.put(copy, original);
}
// patch up the switch statments
for (Unit u : getUnits()) {
Stmt s = (Stmt) u;
if (s instanceof TableSwitchStmt) {
TableSwitchStmt ts = (TableSwitchStmt) s;
TableSwitchStmt original_switch = (TableSwitchStmt) reverse_binding.get(u);
ts.setDefaultTarget((Unit) bindings.get(original_switch.getDefaultTarget()));
LinkedList<Unit> new_target_list = new LinkedList<Unit>();
int target_count = ts.getHighIndex() - ts.getLowIndex() + 1;
for (int i = 0; i < target_count; i++) new_target_list.add((Unit) bindings.get(original_switch.getTarget(i)));
ts.setTargets(new_target_list);
}
if (s instanceof LookupSwitchStmt) {
LookupSwitchStmt ls = (LookupSwitchStmt) s;
LookupSwitchStmt original_switch = (LookupSwitchStmt) reverse_binding.get(u);
ls.setDefaultTarget((Unit) bindings.get(original_switch.getDefaultTarget()));
Unit[] new_target_list = new Unit[original_switch.getTargetCount()];
for (int i = 0; i < original_switch.getTargetCount(); i++) new_target_list[i] = (Unit) (bindings.get(original_switch.getTarget(i)));
ls.setTargets(new_target_list);
ls.setLookupValues(original_switch.getLookupValues());
}
}
// Clone locals.
for (Local original : grimpBody.getLocals()) {
Local copy = Dava.v().newLocal(original.getName(), original.getType());
getLocals().add(copy);
// Build old <-> new mapping.
bindings.put(original, copy);
}
// Patch up references within units using our (old <-> new) map.
for (UnitBox box : getAllUnitBoxes()) {
Unit newObject, oldObject = box.getUnit();
// it's clone.
if ((newObject = (Unit) bindings.get(oldObject)) != null)
box.setUnit(newObject);
}
// backpatch all local variables.
for (ValueBox vb : getUseAndDefBoxes()) {
if (vb.getValue() instanceof Local)
vb.setValue((Value) bindings.get(vb.getValue()));
}
// clone the traps
for (Trap originalTrap : grimpBody.getTraps()) {
Trap cloneTrap = (Trap) originalTrap.clone();
Unit handlerUnit = (Unit) bindings.get(originalTrap.getHandlerUnit());
cloneTrap.setHandlerUnit(handlerUnit);
cloneTrap.setBeginUnit((Unit) bindings.get(originalTrap.getBeginUnit()));
cloneTrap.setEndUnit((Unit) bindings.get(originalTrap.getEndUnit()));
getTraps().add(cloneTrap);
}
}
/*
* Add one level of indirection to "if", "switch", and exceptional control flow.
* This allows for easy handling of breaks, continues and exceptional loops.
*/
{
PatchingChain<Unit> units = getUnits();
Iterator<Unit> it = units.snapshotIterator();
while (it.hasNext()) {
Unit u = it.next();
Stmt s = (Stmt) u;
if (s instanceof IfStmt) {
IfStmt ifs = (IfStmt) s;
JGotoStmt jgs = new JGotoStmt((Unit) units.getSuccOf(u));
units.insertAfter(jgs, u);
JGotoStmt jumper = new JGotoStmt((Unit) ifs.getTarget());
units.insertAfter(jumper, jgs);
ifs.setTarget((Unit) jumper);
} else if (s instanceof TableSwitchStmt) {
TableSwitchStmt tss = (TableSwitchStmt) s;
int targetCount = tss.getHighIndex() - tss.getLowIndex() + 1;
for (int i = 0; i < targetCount; i++) {
JGotoStmt jgs = new JGotoStmt((Unit) tss.getTarget(i));
units.insertAfter(jgs, tss);
tss.setTarget(i, (Unit) jgs);
}
JGotoStmt jgs = new JGotoStmt((Unit) tss.getDefaultTarget());
units.insertAfter(jgs, tss);
tss.setDefaultTarget((Unit) jgs);
} else if (s instanceof LookupSwitchStmt) {
LookupSwitchStmt lss = (LookupSwitchStmt) s;
for (int i = 0; i < lss.getTargetCount(); i++) {
JGotoStmt jgs = new JGotoStmt((Unit) lss.getTarget(i));
units.insertAfter(jgs, lss);
lss.setTarget(i, (Unit) jgs);
}
JGotoStmt jgs = new JGotoStmt((Unit) lss.getDefaultTarget());
units.insertAfter(jgs, lss);
lss.setDefaultTarget((Unit) jgs);
}
}
for (Trap t : getTraps()) {
JGotoStmt jgs = new JGotoStmt((Unit) t.getHandlerUnit());
units.addLast(jgs);
t.setHandlerUnit((Unit) jgs);
}
}
/*
* Fix up the grimp representations of statements so they can be compiled as java.
*/
{
for (Local l : getLocals()) {
Type t = l.getType();
if (t instanceof RefType) {
RefType rt = (RefType) t;
String className = rt.getSootClass().toString();
String packageName = rt.getSootClass().getJavaPackageName();
String classPackageName = packageName;
if (className.lastIndexOf('.') > 0) {
// 0 doesnt make sense
classPackageName = className.substring(0, className.lastIndexOf('.'));
}
if (!packageName.equals(classPackageName))
throw new DecompilationException("Unable to retrieve package name for identifier. Please report to developer.");
addToImportList(className);
// addPackage(rt.getSootClass().getJavaPackageName());
}
}
for (Unit u : getUnits()) {
Stmt s = (Stmt) u;
if (s instanceof IfStmt)
javafy(((IfStmt) s).getConditionBox());
else if (s instanceof ThrowStmt)
javafy(((ThrowStmt) s).getOpBox());
else if (s instanceof TableSwitchStmt)
javafy(((TableSwitchStmt) s).getKeyBox());
else if (s instanceof LookupSwitchStmt)
javafy(((LookupSwitchStmt) s).getKeyBox());
else if (s instanceof MonitorStmt)
javafy(((MonitorStmt) s).getOpBox());
else if (s instanceof DefinitionStmt) {
DefinitionStmt ds = (DefinitionStmt) s;
javafy(ds.getRightOpBox());
javafy(ds.getLeftOpBox());
if (ds.getRightOp() instanceof IntConstant)
ds.getRightOpBox().setValue(DIntConstant.v(((IntConstant) ds.getRightOp()).value, ds.getLeftOp().getType()));
} else if (s instanceof ReturnStmt) {
ReturnStmt rs = (ReturnStmt) s;
if (rs.getOp() instanceof IntConstant)
rs.getOpBox().setValue(DIntConstant.v(((IntConstant) rs.getOp()).value, body.getMethod().getReturnType()));
else
javafy(rs.getOpBox());
} else if (s instanceof InvokeStmt)
javafy(((InvokeStmt) s).getInvokeExprBox());
}
}
/*
* Convert references to "this" and parameters.
*/
{
for (Unit u : getUnits()) {
Stmt s = (Stmt) u;
if (s instanceof IdentityStmt) {
IdentityStmt ids = (IdentityStmt) s;
Value ids_rightOp = ids.getRightOp();
Value ids_leftOp = ids.getLeftOp();
if ((ids_leftOp instanceof Local) && (ids_rightOp instanceof ThisRef)) {
Local thisLocal = (Local) ids_leftOp;
thisLocals.add(thisLocal);
thisLocal.setName("this");
}
}
if (s instanceof DefinitionStmt) {
DefinitionStmt ds = (DefinitionStmt) s;
Value rightOp = ds.getRightOp();
if (rightOp instanceof ParameterRef)
pMap.put(((ParameterRef) rightOp).getIndex(), ds.getLeftOp());
if (rightOp instanceof CaughtExceptionRef)
caughtrefs.add((CaughtExceptionRef) rightOp);
}
}
}
/*
* Fix up the calls to other constructors. Note, this is seriously underbuilt.
*/
{
for (Unit u : getUnits()) {
Stmt s = (Stmt) u;
if (s instanceof InvokeStmt) {
InvokeStmt ivs = (InvokeStmt) s;
Value ie = ivs.getInvokeExpr();
if (ie instanceof InstanceInvokeExpr) {
InstanceInvokeExpr iie = (InstanceInvokeExpr) ie;
Value base = iie.getBase();
if ((base instanceof Local) && (((Local) base).getName().equals("this"))) {
SootMethodRef m = iie.getMethodRef();
String name = m.name();
if ((name.equals(SootMethod.constructorName)) || (name.equals(SootMethod.staticInitializerName))) {
if (constructorUnit != null)
throw new RuntimeException("More than one candidate for constructor found.");
constructorExpr = iie;
constructorUnit = (Unit) s;
}
}
}
}
}
}
}
use of soot.PatchingChain 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.PatchingChain in project soot by Sable.
the class BuildIntermediateAppClasses method internalTransform.
protected void internalTransform(String phaseName, Map<String, String> options) {
if (output) {
out.println("Building Intermediate Classes...");
}
BodyBuilder.retrieveAllBodies();
// iterate through application classes, build intermediate classes
Iterator<SootClass> it = Scene.v().getApplicationClasses().snapshotIterator();
while (it.hasNext()) {
List<SootMethod> initMethodsToRewrite = new ArrayList<>();
Map<String, SootMethod> methodsToAdd = new HashMap<>();
SootClass sc = it.next();
SootClass originalSuperclass = sc.getSuperclass();
if (output) {
out.println("Processing " + sc.getName() + " with super " + originalSuperclass.getName());
}
Iterator<SootMethod> methodIterator = sc.methodIterator();
while (methodIterator.hasNext()) {
SootMethod method = methodIterator.next();
if (!method.isConcrete()) {
continue;
}
try {
method.getActiveBody();
} catch (Exception e) {
if (method.retrieveActiveBody() == null)
throw new RuntimeException(method.getSignature() + " has no body. This was not expected dude.");
}
String subSig = method.getSubSignature();
if (subSig.equals("void main(java.lang.String[])") && method.isPublic() && method.isStatic()) {
// skip the main method - it needs to be named 'main'
continue;
} else if (subSig.indexOf("init>(") > 0) {
if (subSig.startsWith("void <init>(")) {
initMethodsToRewrite.add(method);
}
// skip constructors, just add for rewriting at the end
continue;
} else {
Scene.v().releaseActiveHierarchy();
findAccessibleInSuperClassesBySubSig(sc, subSig).ifPresent(m -> methodsToAdd.put(subSig, m));
}
}
if (methodsToAdd.size() > 0) {
final String fullName = ClassRenamer.v().getNewName(ClassRenamer.getPackageName(sc.getName()), null);
if (output) {
out.println("\tBuilding " + fullName);
}
// make non-final soot class
SootClass mediatingClass = new SootClass(fullName, sc.getModifiers() & (~Modifier.FINAL));
Main.IntermediateAppClasses.add(mediatingClass);
mediatingClass.setSuperclass(originalSuperclass);
Scene.v().addClass(mediatingClass);
mediatingClass.setApplicationClass();
mediatingClass.setInScene(true);
ThisRef thisRef = new ThisRef(mediatingClass.getType());
for (String subSig : methodsToAdd.keySet()) {
SootMethod originalSuperclassMethod = methodsToAdd.get(subSig);
List<Type> paramTypes = originalSuperclassMethod.getParameterTypes();
Type returnType = originalSuperclassMethod.getReturnType();
List<SootClass> exceptions = originalSuperclassMethod.getExceptions();
int modifiers = originalSuperclassMethod.getModifiers() & ~Modifier.ABSTRACT & ~Modifier.NATIVE;
SootMethod newMethod;
{
// build new junk method to call original method
String newMethodName = MethodRenamer.v().getNewName();
newMethod = Scene.v().makeSootMethod(newMethodName, paramTypes, returnType, modifiers, exceptions);
mediatingClass.addMethod(newMethod);
Body body = Jimple.v().newBody(newMethod);
newMethod.setActiveBody(body);
Chain<Local> locals = body.getLocals();
PatchingChain<Unit> units = body.getUnits();
BodyBuilder.buildThisLocal(units, thisRef, locals);
BodyBuilder.buildParameterLocals(units, locals, paramTypes);
if (returnType instanceof VoidType) {
units.add(Jimple.v().newReturnVoidStmt());
} else if (returnType instanceof PrimType) {
units.add(Jimple.v().newReturnStmt(IntConstant.v(0)));
} else {
units.add(Jimple.v().newReturnStmt(NullConstant.v()));
}
newmethods++;
}
// end build new junk method to call original method
{
// build copy of old method
newMethod = Scene.v().makeSootMethod(originalSuperclassMethod.getName(), paramTypes, returnType, modifiers, exceptions);
mediatingClass.addMethod(newMethod);
Body body = Jimple.v().newBody(newMethod);
newMethod.setActiveBody(body);
Chain<Local> locals = body.getLocals();
PatchingChain<Unit> units = body.getUnits();
Local ths = BodyBuilder.buildThisLocal(units, thisRef, locals);
List<Local> args = BodyBuilder.buildParameterLocals(units, locals, paramTypes);
SootMethodRef superclassMethodRef = originalSuperclassMethod.makeRef();
if (returnType instanceof VoidType) {
units.add(Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(ths, superclassMethodRef, args)));
units.add(Jimple.v().newReturnVoidStmt());
} else {
Local loc = Jimple.v().newLocal("retValue", returnType);
body.getLocals().add(loc);
units.add(Jimple.v().newAssignStmt(loc, Jimple.v().newSpecialInvokeExpr(ths, superclassMethodRef, args)));
units.add(Jimple.v().newReturnStmt(loc));
}
newmethods++;
}
// end build copy of old method
}
sc.setSuperclass(mediatingClass);
// rewrite class init methods to call the proper superclass inits
int i = initMethodsToRewrite.size();
while (i-- > 0) {
SootMethod im = initMethodsToRewrite.remove(i);
Body b = im.getActiveBody();
Local thisLocal = b.getThisLocal();
Iterator<Unit> uIt = b.getUnits().snapshotIterator();
while (uIt.hasNext()) {
for (ValueBox valueBox : uIt.next().getUseBoxes()) {
Value v = valueBox.getValue();
if (v instanceof SpecialInvokeExpr) {
SpecialInvokeExpr sie = (SpecialInvokeExpr) v;
SootMethodRef smr = sie.getMethodRef();
if (sie.getBase().equivTo(thisLocal) && smr.declaringClass().getName().equals(originalSuperclass.getName()) && smr.getSubSignature().getString().startsWith("void " + constructorName)) {
SootMethod newSuperInit;
if (!mediatingClass.declaresMethod(constructorName, smr.parameterTypes())) {
List<Type> paramTypes = smr.parameterTypes();
newSuperInit = Scene.v().makeSootMethod(constructorName, paramTypes, smr.returnType());
mediatingClass.addMethod(newSuperInit);
JimpleBody body = Jimple.v().newBody(newSuperInit);
newSuperInit.setActiveBody(body);
PatchingChain<Unit> initUnits = body.getUnits();
Collection<Local> locals = body.getLocals();
Local ths = BodyBuilder.buildThisLocal(initUnits, thisRef, locals);
List<Local> args = BodyBuilder.buildParameterLocals(initUnits, locals, paramTypes);
initUnits.add(Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(ths, smr, args)));
initUnits.add(Jimple.v().newReturnVoidStmt());
} else {
newSuperInit = mediatingClass.getMethod(constructorName, smr.parameterTypes());
}
sie.setMethodRef(newSuperInit.makeRef());
}
}
}
}
}
// end of rewrite class init methods to call the proper superclass inits
}
}
newclasses = Main.IntermediateAppClasses.size();
Scene.v().releaseActiveHierarchy();
Scene.v().getActiveHierarchy();
Scene.v().setFastHierarchy(new FastHierarchy());
}
Aggregations