Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
soot.dava.toolkits.base.AST.transformations.SuperFirstStmtHandler Maven / Gradle / Ivy
package soot.dava.toolkits.base.AST.transformations;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2005 - 2006 Nomair A. Naeem ([email protected] )
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import soot.BooleanType;
import soot.ByteType;
import soot.CharType;
import soot.DoubleType;
import soot.FloatType;
import soot.G;
import soot.IntType;
import soot.Local;
import soot.LongType;
import soot.PrimType;
import soot.RefType;
import soot.Scene;
import soot.ShortType;
import soot.SootClass;
import soot.SootMethod;
import soot.SootMethodRef;
import soot.Type;
import soot.Unit;
import soot.Value;
import soot.VoidType;
import soot.dava.CorruptASTException;
import soot.dava.Dava;
import soot.dava.DavaBody;
import soot.dava.DecompilationException;
import soot.dava.internal.AST.ASTMethodNode;
import soot.dava.internal.AST.ASTNode;
import soot.dava.internal.AST.ASTStatementSequenceNode;
import soot.dava.internal.asg.AugmentedStmt;
import soot.dava.internal.javaRep.DIntConstant;
import soot.dava.internal.javaRep.DNewInvokeExpr;
import soot.dava.internal.javaRep.DSpecialInvokeExpr;
import soot.dava.internal.javaRep.DStaticInvokeExpr;
import soot.dava.internal.javaRep.DVariableDeclarationStmt;
import soot.dava.internal.javaRep.DVirtualInvokeExpr;
import soot.dava.toolkits.base.AST.analysis.DepthFirstAdapter;
import soot.dava.toolkits.base.AST.traversals.ASTParentNodeFinder;
import soot.dava.toolkits.base.AST.traversals.ASTUsesAndDefs;
import soot.dava.toolkits.base.AST.traversals.AllDefinitionsFinder;
import soot.grimp.internal.GAssignStmt;
import soot.grimp.internal.GCastExpr;
import soot.grimp.internal.GInvokeStmt;
import soot.grimp.internal.GReturnStmt;
import soot.jimple.DefinitionStmt;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.Stmt;
import soot.jimple.internal.JimpleLocal;
public class SuperFirstStmtHandler extends DepthFirstAdapter {
public final boolean DEBUG = false;
ASTMethodNode originalASTMethod; // contains the entire method which was
// being decompiled
DavaBody originalDavaBody; // originalASTMethod.getDavaBody
Unit originalConstructorUnit; // contains this.init<>
InstanceInvokeExpr originalConstructorExpr; // contains the expr within the
// ConstructorUni
SootMethod originalSootMethod; // originalDavaBody.getMethod();
SootClass originalSootClass; // originalSootMethod.getDeclaringClass();
Map originalPMap;
List argsOneTypes = null; // initialized to the ParameterTypes of the
// original method
List argsOneValues = null; // initialized to the values of these parameters
// of the original method
List argsTwoValues = null; // initialized to the Parameter values of the
// call to super
List argsTwoTypes = null; // initialized to the ParameterTypes of the call
// to super
// PreInit fields
SootMethod newSootPreInitMethod = null;// only initialized by createMethod
DavaBody newPreInitDavaBody = null; // only initialized by createMethod
ASTMethodNode newASTPreInitMethod = null; // only initialized by
// createNewASTPreInitMethod
// Constructor fields
SootMethod newConstructor = null; // initialized by createNewConstructor
DavaBody newConstructorDavaBody = null; // initialized by
// createNewConstructor
ASTMethodNode newASTConstructorMethod = null; // only initialized by
// createNewASTConstructor
List mustInitialize;
int mustInitializeIndex = 0;
public SuperFirstStmtHandler(ASTMethodNode AST) {
this.originalASTMethod = AST;
initialize();
}
public SuperFirstStmtHandler(boolean verbose, ASTMethodNode AST) {
super(verbose);
this.originalASTMethod = AST;
initialize();
}
public void initialize() {
originalDavaBody = originalASTMethod.getDavaBody();
originalConstructorUnit = originalDavaBody.get_ConstructorUnit();
originalConstructorExpr = originalDavaBody.get_ConstructorExpr();
if (originalConstructorExpr != null) {
// should get the values and the types of these into lists for later
// use
argsTwoValues = originalConstructorExpr.getArgs();
argsTwoTypes = new ArrayList();
// get also the types of these args
Iterator valIt = argsTwoValues.iterator();
while (valIt.hasNext()) {
Value val = (Value) valIt.next();
Type type = val.getType();
argsTwoTypes.add(type);
}
}
originalSootMethod = originalDavaBody.getMethod();
originalSootClass = originalSootMethod.getDeclaringClass();
originalPMap = originalDavaBody.get_ParamMap();
argsOneTypes = originalSootMethod.getParameterTypes();
// initialize argsOneValues
argsOneValues = new ArrayList();
Iterator typeIt = argsOneTypes.iterator();
int count = 0;
while (typeIt.hasNext()) {
Type t = (Type) typeIt.next();
argsOneValues.add(originalPMap.get(new Integer(count)));
count++;
}
}
/*
* looking for an init stmt
*/
public void inASTStatementSequenceNode(ASTStatementSequenceNode node) {
for (AugmentedStmt as : node.getStatements()) {
Unit u = as.get_Stmt();
if (u == originalConstructorUnit) {
// System.out.println("Found the constructorUnit"+u);
// ONE: make sure the parent of the super() call is an
// ASTMethodNode
ASTParentNodeFinder parentFinder = new ASTParentNodeFinder();
originalASTMethod.apply(parentFinder);
Object tempParent = parentFinder.getParentOf(node);
if (tempParent != originalASTMethod) {
// System.out.println("ASTMethod node is not the parent of
// constructorUnit");
// notice since we cant remove one call of super there is no
// point
// in trying to remove any other calls to super
removeInit();
return;
}
// only gets here if the call to super is not nested within some
// other construct
/**********************************************************/
/****************** CREATING PREINIT METHOD ***************/
/**********************************************************/
// CREATE UNIQUE METHOD
createSootPreInitMethod(); // new method is initalized in
// newSootPreInitMethod
// Create ASTMethodNode for this SootMethod
createNewASTPreInitMethod(node); // the field
// newASTPreInitMethod is
// initialized
// newASTPreInitMethod should be non null if we can go ahead
if (newASTPreInitMethod == null) {
// could not create ASTMethodNode for some reason or the
// other
// just silently return
// System.out.println(">>>>>>>>>>>>>>>>Couldnt not create
// ASTMethodNode for the new PreInitMethod");
removeInit();
return;
}
if (!finalizePreInitMethod()) {
// shouldnt be creating PreInit
// System.out.println(">>>>>>>>>>>>>>SHOULDNT BE CREATING
// PREINIT");
removeInit();
return;
}
/**********************************************************/
/************** CREATING NEW CONSTRUCTOR ******************/
/**********************************************************/
// create SootMethod for the constructor
createNewConstructor();
createNewASTConstructor(node);
if (!createCallToSuper()) {
// could not create call to super
// still safe to simply exit
// System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>Could not
// create call to super...SuperFirstStmtHandler");
removeInit();
return;
}
finalizeConstructor();
/**********************************************************/
/************** CHANGE ORIGINAL CONSTRUCTOR ***************/
/**********************************************************/
if (changeOriginalAST()) {
// System.out.println("Done Done Done");
debug("SuperFirstStmtHandler....inASTStatementSeuqneNode", "Added PreInit");
G.v().SootMethodAddedByDava = true;
G.v().SootMethodsAdded.add(newSootPreInitMethod);
G.v().SootMethodsAdded.add(newConstructor);
/**********************************************************/
/****************** CREATING INNER CLASS ******************/
/**********************************************************/
// notice that inner class is created by DavaPrinter in the
// printTo method
// all we do is set a Global to true and later on when the
// SootClass is being
// output the inner class will be output also
G.v().SootClassNeedsDavaSuperHandlerClass.add(originalSootClass);
// System.out.println("\n\nSet SootMethodAddedByDava to
// true\n\n");
}
}
}
}
/*
* When we havent created the indirection to take care of super bug be it cos we dont need to or that we CANT cos of some
* limitation....should atleast remove the jimple this.init call from the statements
*/
public void removeInit() {
// remove constructorUnit from originalASTMethod
List newBody = new ArrayList();
List subBody = originalASTMethod.get_SubBodies();
if (subBody.size() != 1) {
return;
}
List oldBody = (List) subBody.get(0);
Iterator oldIt = oldBody.iterator();
while (oldIt.hasNext()) {
// going through each node in the old body
ASTNode node = (ASTNode) oldIt.next();
// copy the node as is unless its an ASTStatementSequence
if (!(node instanceof ASTStatementSequenceNode)) {
newBody.add(node);
continue;
}
// if the node is an ASTStatementSequenceNode
// copy all stmts unless it is a constructorUnit
ASTStatementSequenceNode seqNode = (ASTStatementSequenceNode) node;
List newStmtList = new ArrayList();
for (AugmentedStmt augStmt : seqNode.getStatements()) {
Stmt stmtTemp = augStmt.get_Stmt();
if (stmtTemp == originalConstructorUnit) {
// do nothing
} else {
newStmtList.add(augStmt);
}
}
if (newStmtList.size() != 0) {
newBody.add(new ASTStatementSequenceNode(newStmtList));
}
}
originalASTMethod.replaceBody(newBody);
}
/*
* Remove the entire body and replace with the statement this(args1, B.preInit(args1));
*/
public boolean changeOriginalAST() {
// originalDavaBody has to be changed
// fix up the call within the constructorUnit....the args should be
// argsOne followed by a method call to preInit
if (originalConstructorExpr == null) {
// hmm that means there was no call to super in the original code
// System.out.println("originalConstructorExpr is null");
return false;
}
List thisArgList = new ArrayList();
thisArgList.addAll(argsOneValues);
DStaticInvokeExpr newInvokeExpr = new DStaticInvokeExpr(newSootPreInitMethod.makeRef(), argsOneValues);
thisArgList.add(newInvokeExpr);
// the methodRef of themethod to be called is the new constructor we
// created
InstanceInvokeExpr tempExpr
= new DSpecialInvokeExpr(originalConstructorExpr.getBase(), newConstructor.makeRef(), thisArgList);
originalDavaBody.set_ConstructorExpr(tempExpr);
// create Invoke Stmt with tempExpr as the expression
GInvokeStmt s = new GInvokeStmt(tempExpr);
originalDavaBody.set_ConstructorUnit(s);
// originalASTMethod has to be made empty
originalASTMethod.setDeclarations(new ASTStatementSequenceNode(new ArrayList()));
originalASTMethod.replaceBody(new ArrayList());
return true;
}
private SootMethodRef makeMethodRef(String methodName, ArrayList args) {
// make MethodRef for methodName
SootMethod method = Scene.v().makeSootMethod(methodName, args, RefType.v("java.lang.Object"));
// set the declaring class of new method to be the DavaSuperHandler
// class
method.setDeclaringClass(new SootClass("DavaSuperHandler"));
return method.makeRef();
}
/*
* super( (CAST-TYPE)handler.get(0), ((CAST-TYPE)handler.get(1)).CONVERSION(), .......);
*
* returns false if we cant create the call to super
*/
private boolean createCallToSuper() {
// check that whether this call is even to be made or not
if (originalConstructorExpr == null) {
// hmm that means there was no call to super in the original code
// System.out.println("originalConstructorExpr is null");
return false;
}
// System.out.println("ConstructorExpr is non null...call to super has
// to be made");
// find the parent class of the current method being decompiled
SootClass parentClass = originalSootClass.getSuperclass();
// retrieve the constructor of the super class that we want to call
// remember argsTwoTypes contains the ParameterType to the call to the
// super method
if (!(parentClass.declaresMethod("", argsTwoTypes))) {
// System.out.println("parentClass does not have a constructor with
// this name and ParamTypes");
return false;
}
SootMethod superConstructor = parentClass.getMethod("", argsTwoTypes);
// create InstanceInvokeExpr
// need Value base: this??
// need SootMethod Ref...make sootmethoref of the super constructor
// found
// need list of thisLocals.........try empty arrayList since it doesnt
// seem to be used anywhere??
List argsForConstructor = new ArrayList();
int count = 0;
// have to make arg as "handler.get(0)"
// create new ReftType for DavaSuperHandler
RefType type = (new SootClass("DavaSuperHandler")).getType();
// make JimpleLocal to be used in each arg
Local jimpleLocal = new JimpleLocal("handler", type);// takes care of
// handler
// make reference to a method of name get takes one int arg belongs to
// DavaSuperHandler
ArrayList tempList = new ArrayList();
tempList.add(IntType.v());
SootMethodRef getMethodRef = makeMethodRef("get", tempList);
List tempArgList = null;
Iterator typeIt = argsTwoTypes.iterator();
while (typeIt.hasNext()) {
Type tempType = (Type) typeIt.next();
DIntConstant arg = DIntConstant.v(count, IntType.v());// takes care
// of the
// index
count++;
tempArgList = new ArrayList();
tempArgList.add(arg);
DVirtualInvokeExpr tempInvokeExpr
= new DVirtualInvokeExpr(jimpleLocal, getMethodRef, tempArgList, new HashSet());
// NECESASARY CASTING OR RETRIEVAL OF PRIM TYPES TO BE DONE HERE
Value toAddExpr = getProperCasting(tempType, tempInvokeExpr);
if (toAddExpr == null) {
throw new DecompilationException("UNABLE TO CREATE TOADDEXPR:" + tempType);
}
// the above virtualInvokeExpr is one of the args for the
// constructor
argsForConstructor.add(toAddExpr);
}
mustInitializeIndex = count;
// we are done with creating all necessary args to the virtualinvoke
// expr constructor
DVirtualInvokeExpr virtualInvoke = new DVirtualInvokeExpr(originalConstructorExpr.getBase(), superConstructor.makeRef(),
argsForConstructor, new HashSet());
// set the constructors constructorExpr
newConstructorDavaBody.set_ConstructorExpr(virtualInvoke);
// create Invoke Stmt with virtualInvoke as the expression
GInvokeStmt s = new GInvokeStmt(virtualInvoke);
newConstructorDavaBody.set_ConstructorUnit(s);
// return true if super call created
return true;
}
public Value getProperCasting(Type tempType, DVirtualInvokeExpr tempInvokeExpr) {
if (tempType instanceof RefType) {
// System.out.println("This is a reftype:"+tempType);
return new GCastExpr(tempInvokeExpr, tempType);
} else if (tempType instanceof PrimType) {
PrimType t = (PrimType) tempType;
// BooleanType, ByteType, CharType, DoubleType, FloatType, IntType,
// LongType, ShortType
if (t == BooleanType.v()) {
Value tempExpr = new GCastExpr(tempInvokeExpr, RefType.v("java.lang.Boolean"));
// booleanValue
SootMethod tempMethod = Scene.v().makeSootMethod("booleanValue", new ArrayList(), BooleanType.v());
tempMethod.setDeclaringClass(new SootClass("java.lang.Boolean"));
SootMethodRef tempMethodRef = tempMethod.makeRef();
return new DVirtualInvokeExpr(tempExpr, tempMethodRef, new ArrayList(), new HashSet());
} else if (t == ByteType.v()) {
Value tempExpr = new GCastExpr(tempInvokeExpr, RefType.v("java.lang.Byte"));
// byteValue
SootMethod tempMethod = Scene.v().makeSootMethod("byteValue", new ArrayList(), ByteType.v());
tempMethod.setDeclaringClass(new SootClass("java.lang.Byte"));
SootMethodRef tempMethodRef = tempMethod.makeRef();
return new DVirtualInvokeExpr(tempExpr, tempMethodRef, new ArrayList(), new HashSet());
} else if (t == CharType.v()) {
Value tempExpr = new GCastExpr(tempInvokeExpr, RefType.v("java.lang.Character"));
// charValue
SootMethod tempMethod = Scene.v().makeSootMethod("charValue", new ArrayList(), CharType.v());
tempMethod.setDeclaringClass(new SootClass("java.lang.Character"));
SootMethodRef tempMethodRef = tempMethod.makeRef();
return new DVirtualInvokeExpr(tempExpr, tempMethodRef, new ArrayList(), new HashSet());
} else if (t == DoubleType.v()) {
Value tempExpr = new GCastExpr(tempInvokeExpr, RefType.v("java.lang.Double"));
// doubleValue
SootMethod tempMethod = Scene.v().makeSootMethod("doubleValue", new ArrayList(), DoubleType.v());
tempMethod.setDeclaringClass(new SootClass("java.lang.Double"));
SootMethodRef tempMethodRef = tempMethod.makeRef();
return new DVirtualInvokeExpr(tempExpr, tempMethodRef, new ArrayList(), new HashSet());
} else if (t == FloatType.v()) {
Value tempExpr = new GCastExpr(tempInvokeExpr, RefType.v("java.lang.Float"));
// floatValue
SootMethod tempMethod = Scene.v().makeSootMethod("floatValue", new ArrayList(), FloatType.v());
tempMethod.setDeclaringClass(new SootClass("java.lang.Float"));
SootMethodRef tempMethodRef = tempMethod.makeRef();
return new DVirtualInvokeExpr(tempExpr, tempMethodRef, new ArrayList(), new HashSet());
} else if (t == IntType.v()) {
Value tempExpr = new GCastExpr(tempInvokeExpr, RefType.v("java.lang.Integer"));
// intValue
SootMethod tempMethod = Scene.v().makeSootMethod("intValue", new ArrayList(), IntType.v());
tempMethod.setDeclaringClass(new SootClass("java.lang.Integer"));
SootMethodRef tempMethodRef = tempMethod.makeRef();
return new DVirtualInvokeExpr(tempExpr, tempMethodRef, new ArrayList(), new HashSet());
} else if (t == LongType.v()) {
Value tempExpr = new GCastExpr(tempInvokeExpr, RefType.v("java.lang.Long"));
// longValue
SootMethod tempMethod = Scene.v().makeSootMethod("longValue", new ArrayList(), LongType.v());
tempMethod.setDeclaringClass(new SootClass("java.lang.Long"));
SootMethodRef tempMethodRef = tempMethod.makeRef();
return new DVirtualInvokeExpr(tempExpr, tempMethodRef, new ArrayList(), new HashSet());
} else if (t == ShortType.v()) {
Value tempExpr = new GCastExpr(tempInvokeExpr, RefType.v("java.lang.Short"));
// shortValue
SootMethod tempMethod = Scene.v().makeSootMethod("shortValue", new ArrayList(), ShortType.v());
tempMethod.setDeclaringClass(new SootClass("java.lang.Short"));
SootMethodRef tempMethodRef = tempMethod.makeRef();
return new DVirtualInvokeExpr(tempExpr, tempMethodRef, new ArrayList(), new HashSet());
} else {
throw new DecompilationException("Unhandle primType:" + tempType);
}
} else {
throw new DecompilationException("The type:" + tempType + " was not a reftye or primtype. PLEASE REPORT.");
}
}
private void finalizeConstructor() {
// set davaBody...totally redundant but have to do as this is checked by
// toString of ASTMethodNode
newASTConstructorMethod.setDavaBody(newConstructorDavaBody);
newConstructorDavaBody.getUnits().clear();
newConstructorDavaBody.getUnits().addLast(newASTConstructorMethod);
System.out.println("Setting declaring class of method" + newConstructor.getSubSignature());
newConstructor.setDeclaringClass(originalSootClass);
}
// method should return false if the PreInit body(ASTBody that is) is empty
// meaning there is no need to create it all
private boolean finalizePreInitMethod() {
// set davaBody...totally redundant but have to do as this is checked by
// toString of ASTMethodNode
newASTPreInitMethod.setDavaBody(newPreInitDavaBody);
// newPreInitDavaBody is the active body
newPreInitDavaBody.getUnits().clear();
newPreInitDavaBody.getUnits().addLast(newASTPreInitMethod);
// check whether there is something in side the ASTBody
// if its empty (maybe there were only declarations and that got removed
// then no point in creating the preInit method
List subBodies = newASTPreInitMethod.get_SubBodies();
if (subBodies.size() != 1) {
return false;
}
List body = (List) subBodies.get(0);
// body is NOT allowed to contain one declaration node with whatever in
// it
// after that it is NOT allowed all ASTStatement nodes with empty bodies
Iterator it = body.iterator();
boolean empty = true; // indicating that method is empty
while (it.hasNext()) {
ASTNode tempNode = (ASTNode) it.next();
if (!(tempNode instanceof ASTStatementSequenceNode)) {
// found some node other than stmtseq...body not empty return
// true
empty = false;
break;
}
List stmts = ((ASTStatementSequenceNode) tempNode).getStatements();
// all declaration stmts are allowed
for (AugmentedStmt as : stmts) {
Stmt s = as.get_Stmt();
if (!(s instanceof DVariableDeclarationStmt)) {
empty = false;
break;
}
}
if (!empty) {
break;
}
}
if (empty) {
// System.out.println("Method is empty not creating it");
return false;// should not be creating the method
}
// about to return true enter all DavaSuperHandler stmts to make it part
// of the preinit method
createDavaStoreStmts();
return true;
}
public void createNewASTConstructor(ASTStatementSequenceNode initNode) {
List newConstructorBody = new ArrayList();
List newStmts = new ArrayList();
/*
* add any definitions to live variables that might be in body X
*/
// we have gotten argsTwoType size() out of the handler so thats the
// index count
// mustInitialize has the live variables that need to be initialized
// create new ReftType for DavaSuperHandler
RefType type = (new SootClass("DavaSuperHandler")).getType();
// make JimpleLocal to be used in each arg
Local jimpleLocal = new JimpleLocal("handler", type);// takes care of
// handler
// make reference to a method of name get takes one int arg belongs to
// DavaSuperHandler
ArrayList tempList = new ArrayList();
tempList.add(IntType.v());
SootMethodRef getMethodRef = makeMethodRef("get", tempList);
// Iterator typeIt = argsTwoTypes.iterator();
if (mustInitialize != null) {
Iterator initIt = mustInitialize.iterator();
while (initIt.hasNext()) {
Local initLocal = initIt.next();
Type tempType = initLocal.getType();
DIntConstant arg = DIntConstant.v(mustInitializeIndex, IntType.v());// takes
// care
// of
// the
// index
mustInitializeIndex++;
ArrayList tempArgList = new ArrayList();
tempArgList.add(arg);
DVirtualInvokeExpr tempInvokeExpr
= new DVirtualInvokeExpr(jimpleLocal, getMethodRef, tempArgList, new HashSet());
// NECESASARY CASTING OR RETRIEVAL OF PRIM TYPES TO BE DONE HERE
Value toAddExpr = getProperCasting(tempType, tempInvokeExpr);
if (toAddExpr == null) {
throw new DecompilationException("UNABLE TO CREATE TOADDEXPR:" + tempType);
}
// need to create a def stmt with the local on the left and
// toAddExpr on the right
GAssignStmt assign = new GAssignStmt(initLocal, toAddExpr);
newStmts.add(new AugmentedStmt(assign));
}
}
// add any statements following the this. statement
Iterator it = initNode.getStatements().iterator();
while (it.hasNext()) {
AugmentedStmt augStmt = (AugmentedStmt) it.next();
Stmt stmtTemp = augStmt.get_Stmt();
if (stmtTemp == originalConstructorUnit) {
break;
}
}
while (it.hasNext()) {
/*
* notice we dont need to clone these because these will be removed from the other method from which we are copying
* these
*/
newStmts.add(it.next());
}
if (newStmts.size() > 0) {
newConstructorBody.add(new ASTStatementSequenceNode(newStmts));
}
// adding body Y now
List originalASTMethodSubBodies = originalASTMethod.get_SubBodies();
if (originalASTMethodSubBodies.size() != 1) {
throw new CorruptASTException("size of ASTMethodNode subBody not 1");
}
List oldASTBody = (List) originalASTMethodSubBodies.get(0);
Iterator itOld = oldASTBody.iterator();
boolean sanity = false;
while (itOld.hasNext()) {
// going through originalASTMethodNode's ASTNodes
ASTNode tempNode = (ASTNode) itOld.next();
// enter only if its not the initNode
if (tempNode instanceof ASTStatementSequenceNode) {
if ((((ASTStatementSequenceNode) tempNode).getStatements()).equals(initNode.getStatements())) {
sanity = true;
break;
}
}
}
if (!sanity) {
// means we never found the initNode which shouldnt happen
throw new DecompilationException("never found the init node");
}
// so we have found the init node
// Y are all the nodes following the initNode
while (itOld.hasNext()) {
newConstructorBody.add(itOld.next());
}
// setDeclarations in newNode
// The LocalVariableCleaner which is called in the end of DavaBody will
// clear up any declarations that are not required
List newConstructorDeclarations = new ArrayList();
for (AugmentedStmt as : originalASTMethod.getDeclarations().getStatements()) {
DVariableDeclarationStmt varDecStmt = (DVariableDeclarationStmt) as.get_Stmt();
newConstructorDeclarations.add(new AugmentedStmt((DVariableDeclarationStmt) varDecStmt.clone()));
}
ASTStatementSequenceNode newDecs = new ASTStatementSequenceNode(new ArrayList());
if (newConstructorDeclarations.size() > 0) {
newDecs = new ASTStatementSequenceNode(newConstructorDeclarations);
// DONT FORGET TO SET THE DECLARATIONS IN THE METHOD ONCE IT IS
// CREATED
// newASTConstructorMethod.setDeclarations(newDecs);
// declarations are always the first element
newConstructorBody.add(0, newDecs);
}
// so we have any declarations followed by body Y
// have to put the newConstructorBody into an list of subBodies which
// goes into the newASTConstructorMethod
newASTConstructorMethod = new ASTMethodNode(newConstructorBody);
// dont forget to set the declarations
newASTConstructorMethod.setDeclarations(newDecs);
}
private void createNewConstructor() {
// the constructor name has to be
String uniqueName = "";
// NOTICE args of this constructor are argsOne followed by the
// DavaSuperHandler
List args = new ArrayList();
args.addAll(argsOneTypes);
// create new ReftType for DavaSuperHandler
RefType type = (new SootClass("DavaSuperHandler")).getType();
args.add(type);
// create SOOTMETHOD
newConstructor = Scene.v().makeSootMethod(uniqueName, args, IntType.v());
// set the declaring class of new method to be the originalSootClass
newConstructor.setDeclaringClass(originalSootClass);
// set method to public
newConstructor.setModifiers(soot.Modifier.PUBLIC);
// initalize a new DavaBody, notice this causes all DavaBody vars to be
// null
newConstructorDavaBody = Dava.v().newBody(newConstructor);
// setting params is really important if you want the args to have
// proper names in the new method
// make a copy of the originalHashMap
Map tempMap = new HashMap();
Iterator typeIt = argsOneTypes.iterator();
int count = 0;
while (typeIt.hasNext()) {
Type t = (Type) typeIt.next();
tempMap.put(new Integer(count), originalPMap.get(new Integer(count)));
count++;
}
// add the DavaSuperHandler var name in the Parameters
tempMap.put(new Integer(argsOneTypes.size()), "handler");
// add the ParamMap to the constructor's DavaBody
newConstructorDavaBody.set_ParamMap(tempMap);
// set as activeBody
newConstructor.setActiveBody(newConstructorDavaBody);
}
/*
* January 23rd New Algorithm Leave originalASTMethod unchanged Clone everything and copy only those which are needed in
* the newASTPreInitMethod
*/
private void createNewASTPreInitMethod(ASTStatementSequenceNode initNode) {
List newPreinitBody = new ArrayList();
// start adding ASTNodes into newPreinitBody from the
// originalASTMethod's body until we reach initNode
List originalASTMethodSubBodies = originalASTMethod.get_SubBodies();
if (originalASTMethodSubBodies.size() != 1) {
throw new CorruptASTException("size of ASTMethodNode subBody not 1");
}
List oldASTBody = (List) originalASTMethodSubBodies.get(0);
Iterator it = oldASTBody.iterator();
boolean sanity = false;
while (it.hasNext()) {
// going through originalASTMethodNode's ASTNodes
ASTNode tempNode = (ASTNode) it.next();
// enter only if its not the initNode
if (tempNode instanceof ASTStatementSequenceNode) {
if ((((ASTStatementSequenceNode) tempNode).getStatements()).equals(initNode.getStatements())) {
sanity = true;
break;
} else {
// this was not the initNode so we add
newPreinitBody.add(tempNode);
}
} else {
// not a stmtseq so simply add it
newPreinitBody.add(tempNode);
}
}
if (!sanity) {
// means we never found the initNode which shouldnt happen
throw new DecompilationException("never found the init node");
}
// at this moment newPreinitBody contains all of X except for any stmts
// above the this.init call in the stmtseq node
// copy those
List newStmts = new ArrayList();
for (AugmentedStmt augStmt : initNode.getStatements()) {
Stmt stmtTemp = augStmt.get_Stmt();
if (stmtTemp == originalConstructorUnit) {
break;
}
// adding any stmt until constructorUnit into topList for
// newMethodNode
/*
* notice we dont need to clone these because these will be removed from the other method from which we are copying
* these
*/
newStmts.add(augStmt);
}
if (newStmts.size() > 0) {
newPreinitBody.add(new ASTStatementSequenceNode(newStmts));
}
// setDeclarations in newNode
// The LocalVariableCleaner which is called in the end of DavaBody will
// clear up any declarations that are not required
List newPreinitDeclarations = new ArrayList();
for (AugmentedStmt as : originalASTMethod.getDeclarations().getStatements()) {
DVariableDeclarationStmt varDecStmt = (DVariableDeclarationStmt) as.get_Stmt();
newPreinitDeclarations.add(new AugmentedStmt((DVariableDeclarationStmt) varDecStmt.clone()));
}
ASTStatementSequenceNode newDecs = new ASTStatementSequenceNode(new ArrayList());
if (newPreinitDeclarations.size() > 0) {
newDecs = new ASTStatementSequenceNode(newPreinitDeclarations);
// DONT FORGET TO SET THE DECLARATIONS IN THE METHOD ONCE IT IS
// CREATED
// newASTPreInitMethod.setDeclarations(newDecs);
// when we copied the body X the first Node copied was the
// Declarations from the originalASTMethod
// replace that with this new one
newPreinitBody.remove(0);
newPreinitBody.add(0, newDecs);
}
// At this moment we have the newPreInitBody containing declarations
// followed by code X
// we need to check whether this actually contains anything cos
// otherwise super is infact the first stmt
if (newPreinitBody.size() < 1) {
// System.out.println("Method node empty doing nothing returning");
newASTPreInitMethod = null;// meaning ASTMethodNode for this method
// not created
return;
}
// so we have any declarations followed by body X
// NEXT THING SHOULD BE CODE TO CREATE A DAVAHANDLER AND STORE THE ARGS
// TO SUPER IN IT
// HOWEVER WE WILL DELAY THIS TILL UNTIL WE ARE READY TO FINALIZE the
// PREINIT
// reason for delaying is that even though we know that the body is not
// empty the body
// could be made empty by the transformations which act in the finalize
// method
// have to put the newPreinitBody into an list of subBodies which goes
// into the newASTPreInitMethod
newASTPreInitMethod = new ASTMethodNode(newPreinitBody);
// dont forget to set the declarations
newASTPreInitMethod.setDeclarations(newDecs);
}
/*
* Create a unique private static method name starts with preInit
*/
private void createSootPreInitMethod() {
// get a unique name for the method
String uniqueName = getUniqueName();
// NOTICE WE ARE DEFINING ARGS AS SAME AS THE ORIGINAL METHOD
newSootPreInitMethod = Scene.v().makeSootMethod(uniqueName, argsOneTypes, (new SootClass("DavaSuperHandler")).getType());
// set the declaring class of new method to be the originalSootClass
newSootPreInitMethod.setDeclaringClass(originalSootClass);
// set method to private and static
newSootPreInitMethod.setModifiers(soot.Modifier.PRIVATE | soot.Modifier.STATIC);
// initalize a new DavaBody, notice this causes all DavaBody vars to be
// null
newPreInitDavaBody = Dava.v().newBody(newSootPreInitMethod);
// setting params is really important if you want the args to have
// proper names in the new method
newPreInitDavaBody.set_ParamMap(originalPMap);
// set as activeBody
newSootPreInitMethod.setActiveBody(newPreInitDavaBody);
}
/*
* Check the sootClass that it doesnt have a name we have suggested ALSO VERY IMPORTANT TO CHECK THE NAMES IN THE
* SOOTMETHODSADDED Variable since these will be added to this sootclass by the PackManager
*/
private String getUniqueName() {
String toReturn = "preInit";
int counter = 0;
List methodList = originalSootClass.getMethods();
boolean done = false; // havent found the name
while (!done) {
// as long as name not found
done = true; // assume name found
Iterator it = methodList.iterator();
while (it.hasNext()) {
Object temp = it.next();
if (temp instanceof SootMethod) {
SootMethod method = (SootMethod) temp;
String name = method.getName();
if (toReturn.compareTo(name) == 0) {
// method exists with this name so change the name
counter++;
toReturn = "preInit" + counter;
done = false; // name was not found
break;// breaks the inner while since the name has been
// changed
}
} else {
throw new DecompilationException("SootClass returned a non SootMethod method");
}
}
// if we get here this means that the orignal names are different
// check the to be added names also
it = G.v().SootMethodsAdded.iterator();
while (it.hasNext()) {
// are sure its a sootMethod
SootMethod method = (SootMethod) it.next();
String name = method.getName();
if (toReturn.compareTo(name) == 0) {
// method exists with this name so change the name
counter++;
toReturn = "preInit" + counter;
done = false; // name was not found
break;// breaks the inner while since the name has been
// changed
}
}
} // end outer while
return toReturn;
}
/*
* Create the following code:
*
* DavaSuperHandler handler; handler = new DavaSuperHandler(); //code to evaluate all args in args2
*
* //evaluate 1st arg in args2 --------- handler.store(firstArg);
*
* //evaluate 2nd arg in args2 --------- handler.store(secondArg);
*
* //AND SO ON TILL ALL ARGS ARE FINISHED
*
* return handler;
*/
private void createDavaStoreStmts() {
List davaHandlerStmts = new ArrayList();
// create object of DavaSuperHandler handler
SootClass sootClass = new SootClass("DavaSuperHandler");
Type localType = sootClass.getType();
Local newLocal = new JimpleLocal("handler", localType);
/*
* Create * DavaSuperHandler handler; *
*/
DVariableDeclarationStmt varStmt = null;
varStmt = new DVariableDeclarationStmt(localType, newPreInitDavaBody);
varStmt.addLocal(newLocal);
AugmentedStmt as = new AugmentedStmt(varStmt);
davaHandlerStmts.add(as);
/*
* create * handler = new DavaSuperHandler(); *
*/
// create RHS
DNewInvokeExpr invokeExpr
= new DNewInvokeExpr(RefType.v(sootClass), makeMethodRef("DavaSuperHandler", new ArrayList()), new ArrayList());
// create LHS
GAssignStmt initialization = new GAssignStmt(newLocal, invokeExpr);
// add to stmts
davaHandlerStmts.add(new AugmentedStmt(initialization));
/*
* create * handler.store(firstArg); *
*/
// best done in a loop for all args
Iterator typeIt = argsTwoTypes.iterator();
Iterator valIt = argsTwoValues.iterator();
// make reference to a method of name store takes one Object arg belongs
// to DavaSuperHandler
ArrayList tempList = new ArrayList();
tempList.add(RefType.v("java.lang.Object"));// SHOULD BE OBJECT
SootMethod method = Scene.v().makeSootMethod("store", tempList, VoidType.v());
// set the declaring class of new method to be the DavaSuperHandler
// class
method.setDeclaringClass(sootClass);
SootMethodRef getMethodRef = method.makeRef();
// everything is ready all we need is the object argument before we can
// create the invokeStmt with the invokeexpr
// once that is done wrap it in augmented stmt and add to
// davaHandlerStmt
while (typeIt.hasNext() && valIt.hasNext()) {
Type tempType = (Type) typeIt.next();
Value tempVal = (Value) valIt.next();
AugmentedStmt toAdd = createStmtAccordingToType(tempType, tempVal, newLocal, getMethodRef);
davaHandlerStmts.add(toAdd);
} // end of going through all the types and vals
// sanity check
if (typeIt.hasNext() || valIt.hasNext()) {
throw new DecompilationException("Error creating DavaHandler stmts");
}
/*
* code to add defs
*/
List uniqueLocals = addDefsToLiveVariables();
Iterator localIt = uniqueLocals.iterator();
while (localIt.hasNext()) {
Local local = localIt.next();
AugmentedStmt toAdd = createStmtAccordingToType(local.getType(), local, newLocal, getMethodRef);
davaHandlerStmts.add(toAdd);
}
// set the mustInitialize field to uniqueLocals so that before Y we can
// assign these locals
mustInitialize = uniqueLocals;
/*
* create * return handler; *
*/
GReturnStmt returnStmt = new GReturnStmt(newLocal);
davaHandlerStmts.add(new AugmentedStmt(returnStmt));
// the appropriate dava handler stmts are all in place within
// davaHandlerStmts
// store them in an ASTSTatementSequenceNode
ASTStatementSequenceNode addedNode = new ASTStatementSequenceNode(davaHandlerStmts);
// add to method body
List subBodies = newASTPreInitMethod.get_SubBodies();
if (subBodies.size() != 1) {
throw new CorruptASTException("ASTMethodNode does not have one subBody");
}
List body = (List) subBodies.get(0);
body.add(addedNode);
newASTPreInitMethod.replaceBody(body);
}
public AugmentedStmt createStmtAccordingToType(Type tempType, Value tempVal, Local newLocal, SootMethodRef getMethodRef) {
if (tempType instanceof RefType) {
// simply add this to the handler using handler.store(tempVal);
// System.out.println("This is a reftype:"+tempType);
return createAugmentedStmtToAdd(newLocal, getMethodRef, tempVal);
} else if (tempType instanceof PrimType) {
// The value is a primitive type
// create wrapper object new Integer(tempVal)
PrimType t = (PrimType) tempType;
// create ArgList to be sent to DNewInvokeExpr constructor
ArrayList argList = new ArrayList();
argList.add(tempVal);
// BooleanType, ByteType, CharType, DoubleType, FloatType, IntType,
// LongType, ShortType
if (t == BooleanType.v()) {
// create TypeList to be sent to makeMethodRef
ArrayList typeList = new ArrayList();
typeList.add(IntType.v());
DNewInvokeExpr argForStore
= new DNewInvokeExpr(RefType.v("java.lang.Boolean"), makeMethodRef("Boolean", typeList), argList);
return createAugmentedStmtToAdd(newLocal, getMethodRef, argForStore);
} else if (t == ByteType.v()) {
// create TypeList to be sent to makeMethodRef
ArrayList typeList = new ArrayList();
typeList.add(ByteType.v());
DNewInvokeExpr argForStore
= new DNewInvokeExpr(RefType.v("java.lang.Byte"), makeMethodRef("Byte", typeList), argList);
return createAugmentedStmtToAdd(newLocal, getMethodRef, argForStore);
} else if (t == CharType.v()) {
// create TypeList to be sent to makeMethodRef
ArrayList typeList = new ArrayList();
typeList.add(CharType.v());
DNewInvokeExpr argForStore
= new DNewInvokeExpr(RefType.v("java.lang.Character"), makeMethodRef("Character", typeList), argList);
return createAugmentedStmtToAdd(newLocal, getMethodRef, argForStore);
} else if (t == DoubleType.v()) {
// create TypeList to be sent to makeMethodRef
ArrayList typeList = new ArrayList();
typeList.add(DoubleType.v());
DNewInvokeExpr argForStore
= new DNewInvokeExpr(RefType.v("java.lang.Double"), makeMethodRef("Double", typeList), argList);
return createAugmentedStmtToAdd(newLocal, getMethodRef, argForStore);
} else if (t == FloatType.v()) {
// create TypeList to be sent to makeMethodRef
ArrayList typeList = new ArrayList();
typeList.add(FloatType.v());
DNewInvokeExpr argForStore
= new DNewInvokeExpr(RefType.v("java.lang.Float"), makeMethodRef("Float", typeList), argList);
return createAugmentedStmtToAdd(newLocal, getMethodRef, argForStore);
} else if (t == IntType.v()) {
// create TypeList to be sent to makeMethodRef
ArrayList typeList = new ArrayList();
typeList.add(IntType.v());
DNewInvokeExpr argForStore
= new DNewInvokeExpr(RefType.v("java.lang.Integer"), makeMethodRef("Integer", typeList), argList);
return createAugmentedStmtToAdd(newLocal, getMethodRef, argForStore);
} else if (t == LongType.v()) {
// create TypeList to be sent to makeMethodRef
ArrayList typeList = new ArrayList();
typeList.add(LongType.v());
DNewInvokeExpr argForStore
= new DNewInvokeExpr(RefType.v("java.lang.Long"), makeMethodRef("Long", typeList), argList);
return createAugmentedStmtToAdd(newLocal, getMethodRef, argForStore);
} else if (t == ShortType.v()) {
// create TypeList to be sent to makeMethodRef
ArrayList typeList = new ArrayList();
typeList.add(ShortType.v());
DNewInvokeExpr argForStore
= new DNewInvokeExpr(RefType.v("java.lang.Short"), makeMethodRef("Short", typeList), argList);
return createAugmentedStmtToAdd(newLocal, getMethodRef, argForStore);
} else {
throw new DecompilationException("UNHANDLED PRIMTYPE:" + tempType);
}
} // end of primitivetypes
else {
throw new DecompilationException("The type:" + tempType + " is neither a reftype or a primtype");
}
}
/*
* newASTPreInitMethod at time of invocation just contains body X find all defs for this body
*/
private List addDefsToLiveVariables() {
// get all defs within x
AllDefinitionsFinder finder = new AllDefinitionsFinder();
newASTPreInitMethod.apply(finder);
List allDefs = finder.getAllDefs();
List uniqueLocals = new ArrayList();
List uniqueLocalDefs = new ArrayList();
// remove any defs for fields, and any which are done multiple times
Iterator it = allDefs.iterator();
while (it.hasNext()) {
DefinitionStmt s = it.next();
Value left = s.getLeftOp();
if (left instanceof Local) {
if (uniqueLocals.contains(left)) {
// a def for this local already encountered
int index = uniqueLocals.indexOf(left);
uniqueLocals.remove(index);
uniqueLocalDefs.remove(index);
} else {
// no def for this local yet
uniqueLocals.add((Local) left);
uniqueLocalDefs.add(s);
}
}
}
// at this point unique locals contains all locals defined and
// uniqueLocaldef list has a list of the corresponding definitions
// Now remove those unique locals and localdefs whose stmtseq node does
// not have the ASTMEthodNode as a parent
// This is a conservative step!!
ASTParentNodeFinder parentFinder = new ASTParentNodeFinder();
newASTPreInitMethod.apply(parentFinder);
List toRemoveDefs = new ArrayList();
it = uniqueLocalDefs.iterator();
while (it.hasNext()) {
DefinitionStmt s = it.next();
Object parent = parentFinder.getParentOf(s);
if (parent == null || (!(parent instanceof ASTStatementSequenceNode))) {
// shouldnt happen but if it does add this s to toRemove list
toRemoveDefs.add(s);
}
// parent is an ASTStatementsequence node. check that its parent is
// the ASTMethodNode
Object grandParent = parentFinder.getParentOf(parent);
if (grandParent == null || (!(grandParent instanceof ASTMethodNode))) {
// can happen if obfuscators are really smart. add s to toRemove
// list
toRemoveDefs.add(s);
}
}
// remove any defs and corresponding locals if present in the
// toRemoveDefs list
it = toRemoveDefs.iterator();
while (it.hasNext()) {
DefinitionStmt s = it.next();
int index = uniqueLocalDefs.indexOf(s);
uniqueLocals.remove(index);
uniqueLocalDefs.remove(index);
}
// the uniqueLocalDefs contains all those definitions to unique locals
// which are not deeply nested in the X body
// find all the uses of these definitions in the original method body
toRemoveDefs = new ArrayList();
ASTUsesAndDefs uDdU = new ASTUsesAndDefs(originalASTMethod);
originalASTMethod.apply(uDdU);
it = uniqueLocalDefs.iterator();
while (it.hasNext()) {
DefinitionStmt s = it.next();
Object temp = uDdU.getDUChain(s);
if (temp == null) {
// couldnt find uses
toRemoveDefs.add(s);
continue;
}
ArrayList uses = (ArrayList) temp;
// the uses list contains all stmts / nodes which use the
// definedLocal
// check if uses is non-empty
if (uses.size() == 0) {
toRemoveDefs.add(s);
}
// check for all the non zero uses
Iterator useIt = uses.iterator();
boolean onlyInConstructorUnit = true;
while (useIt.hasNext()) {
// a use is either a statement or a node(condition, synch,
// switch , for etc)
Object tempUse = useIt.next();
if (tempUse != originalConstructorUnit) {
onlyInConstructorUnit = false;
}
}
if (onlyInConstructorUnit) {
// mark it to be removed
toRemoveDefs.add(s);
}
}
// remove any defs and corresponding locals if present in the
// toRemoveDefs list
it = toRemoveDefs.iterator();
while (it.hasNext()) {
DefinitionStmt s = it.next();
int index = uniqueLocalDefs.indexOf(s);
uniqueLocals.remove(index);
uniqueLocalDefs.remove(index);
}
// the remaining uniquelocals are the ones which are needed for body Y
return uniqueLocals;
}
private AugmentedStmt createAugmentedStmtToAdd(Local newLocal, SootMethodRef getMethodRef, Value tempVal) {
ArrayList tempArgList = new ArrayList();
tempArgList.add(tempVal);
DVirtualInvokeExpr tempInvokeExpr = new DVirtualInvokeExpr(newLocal, getMethodRef, tempArgList, new HashSet());
// create Invoke Stmt with virtualInvoke as the expression
GInvokeStmt s = new GInvokeStmt(tempInvokeExpr);
return new AugmentedStmt(s);
}
public void debug(String methodName, String debug) {
if (DEBUG) {
System.out.println(methodName + " DEBUG: " + debug);
}
}
}