Created
November 10, 2011 11:22
-
-
Save monperrus/1354641 to your computer and use it in GitHub Desktop.
Static analysis to extract method calls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This program makes a static analysis in | |
* order to extract method calls of a directory containing Java bytecode . | |
* | |
* It uses the Soot library. | |
* | |
* Usage: | |
* 1. Change the classpath and the directoryToAnalyze variable | |
* 2. run java -cp bin:soot.jar mm.soot.MethodCallCollector | |
* 3. look at /tmp/data.dat | |
* | |
* For instance, running MethodCallCollector on itself outputs: | |
* | |
* <pre> | |
* Analyzing bin | |
* [-cp, .:/opt/jdk1.6.0_23/jre/lib/rt.jar:/opt/jdk1.6.0_23/lib/tools.jar:/opt/jdk1.6.0_23/jre/lib/jsse.jar:bin:bin:data-mining-for-software-engineering/soot-2.4.0.jar, -process-dir, bin, -include, org.apache.] | |
* Transforming mm.soot.MethodCallCollector$1... | |
* 0 java.lang.StringBuilder <init> append | |
* 1 java.util.Iterator next hasNext | |
* 2 soot.jimple.AssignStmt getLeftOp getRightOp | |
* 3 soot.Body getLocals getUnits getMethod | |
* 4 java.lang.StringBuilder <init> append | |
* 5 java.util.Iterator next hasNext | |
* 6 soot.jimple.InstanceInvokeExpr getBase getMethod | |
* 7 java.util.Iterator next hasNext | |
* 8 soot.PatchingChain iterator iterator | |
* 9 java.util.Iterator next hasNext | |
* 10 soot.Local getType getName | |
* 11 java.lang.StringBuilder <init> append | |
* 12 java.util.Iterator next hasNext | |
* 13 soot.jimple.Stmt containsInvokeExpr getInvokeExpr getTag | |
* 14 java.util.HashMap put get get get values <init> | |
* Transforming mm.soot.Variable... | |
* 15 java.lang.StringBuilder <init> append | |
* 16 java.lang.StringBuilder <init> append | |
* 17 java.lang.StringBuilder <init> append | |
* 18 java.util.Iterator next hasNext hasNext | |
* Transforming mm.soot.MethodCallCollector... | |
* 19 java.util.StringTokenizer nextToken hasMoreTokens <init> | |
* 20 java.lang.StringBuilder <init> append | |
* 21 java.io.File <init> exists | |
* 22 java.util.Iterator next hasNext | |
* 23 java.lang.StringBuilder <init> append | |
* 24 java.lang.StringBuilder <init> append | |
* 25 java.util.Iterator next hasNext | |
* </pre> | |
* | |
* @author Eric Bodden | |
* @author Martin Monperrus | |
* GNU General Public License | |
* | |
*/ | |
package mm.soot; | |
import java.io.BufferedWriter; | |
import java.io.File; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.io.Writer; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.StringTokenizer; | |
import soot.Body; | |
import soot.BodyTransformer; | |
import soot.Local; | |
import soot.PackManager; | |
import soot.PatchingChain; | |
import soot.Scene; | |
import soot.Transform; | |
import soot.Unit; | |
import soot.Value; | |
import soot.jimple.AssignStmt; | |
import soot.jimple.InstanceInvokeExpr; | |
import soot.jimple.InvokeExpr; | |
import soot.jimple.Stmt; | |
import soot.options.Options; | |
import soot.tagkit.SourceLnPosTag; | |
import soot.util.Chain; | |
public class MethodCallCollector { | |
static String directoryToAnalyze = "/path/to/bin"; | |
/** the classpath given to soot, it is system dependent | |
* On Windows, use a semi-column as separator | |
* Note that you may use rt.jar, tools.jar and jsse.jar from a Linux installation even on Windows or Mac, | |
* because these jars are used by Soot (and not by the JVM) | |
*/ | |
static List<String> lSootClasspath = new ArrayList<String>(); | |
static void init() { | |
lSootClasspath.add("/opt/jdk1.6.0_23/jre/lib/rt.jar"); | |
lSootClasspath.add("/opt/jdk1.6.0_23/lib/tools.jar"); | |
lSootClasspath.add("/opt/jdk1.6.0_23/jre/lib/jsse.jar"); | |
lSootClasspath.add(directoryToAnalyze); | |
StringTokenizer st = new StringTokenizer(System.getProperty("java.class.path"), classpathDelimiter); | |
while (st.hasMoreTokens()) {lSootClasspath.add(st.nextToken());} | |
} | |
/** The file in which the traces are put */ | |
static String datasetFileName = "/tmp/data.dat"; | |
public static void main(String[] args) throws Exception{ | |
if (args.length == 1) { | |
directoryToAnalyze = args[0]; | |
} | |
init(); | |
for(String file : lSootClasspath) { | |
if (!new File(file).exists()) { | |
throw new IllegalArgumentException(file + " does not exist"); | |
} | |
} | |
System.err.println("Analyzing "+directoryToAnalyze); | |
MethodCallCollector analyzer = new MethodCallCollector(); | |
analyzer.analyze(directoryToAnalyze); | |
} | |
public void analyze(String toBeAnalyzed) throws Exception{ | |
appOut = new BufferedWriter(new FileWriter(datasetFileName)); | |
PackManager.v().getPack("jtp").add( | |
new Transform("jtp.myTransform", new BodyTransformer() { | |
protected void internalTransform(Body body, String phase, Map options) { | |
//System.out.println("IN METHOD: " + body.getMethod().getName()); | |
Chain<Local> locals = body.getLocals(); | |
HashMap<String, Variable> variables = new HashMap<String, Variable>(); | |
// first getting Locals | |
for(Local l:locals) { // for each variable of the method | |
Variable aVariable = new Variable(); | |
aVariable.location="!"; | |
//System.out.println(l); | |
aVariable.type = l.getType().toString(); | |
variables.put(l.getName(),aVariable); | |
} | |
PatchingChain<Unit> units = body.getUnits(); | |
for (Unit u: units) { // for each statement | |
Stmt s = (Stmt)u; | |
//System.out.println(s+"-"+s.getClass()); | |
if (s.containsInvokeExpr()) { | |
InvokeExpr invokeExpr = s.getInvokeExpr(); | |
//System.out.println(invokeExpr); | |
if (invokeExpr instanceof InstanceInvokeExpr) { | |
InstanceInvokeExpr instanceInvokeExpr = (InstanceInvokeExpr) invokeExpr; | |
Value v = instanceInvokeExpr.getBase(); | |
Variable aVariable = variables.get(((Local)v).getName()); | |
if (aVariable.location.equals("!")) { | |
SourceLnPosTag tag = (SourceLnPosTag) s.getTag("SourceLnPosTag"); | |
if(tag!=null) { | |
aVariable.location = body.getMethod().getDeclaringClass()+":"+tag.startLn(); | |
} else{ | |
aVariable.location = "Unknown"; | |
} | |
} | |
// we can add this method call | |
aVariable.methodCalls.add(instanceInvokeExpr.getMethod().getName()); | |
} | |
} | |
} | |
// simple resolving | |
for (Unit u: units) { // for each statement | |
//System.out.println(u+" /// "+u.getClass()); | |
Stmt s = (Stmt)u; | |
if (s instanceof AssignStmt) { | |
AssignStmt ass = (AssignStmt)s; | |
//System.out.println(ass); | |
Value left = ass.getLeftOp(); | |
Value right = ass.getRightOp(); | |
if (left instanceof Local && right instanceof Local) { | |
Variable vleft = variables.get(((Local)left).getName()); | |
Variable vright = variables.get(((Local)right).getName()); | |
for (String mc: vright.methodCalls) { | |
vleft.methodCalls.add(mc); | |
} | |
} | |
} | |
} | |
// output the variables | |
for (Variable aVariable: variables.values()) { | |
if ((aVariable.methodCalls.size()>1) ) { | |
System.out.println((nbTraces++)+" "+aVariable); | |
try { | |
appOut.write(aVariable+"\n"); | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
} | |
} // end internalTransform | |
} /* end new Transform */)); | |
String sootClasspath = "."; | |
for (String jar : lSootClasspath) { sootClasspath+=classpathDelimiter+jar;} | |
String[] myArgs = | |
{ | |
"-cp", sootClasspath, | |
"-process-dir", toBeAnalyzed, | |
"-include","org.apache." /* by default, org.apache. is discarded by soot */ | |
}; | |
Options.v().parse( myArgs); | |
Options.v().set_keep_line_number(true); | |
Options.v().set_output_format(Options.output_format_none); | |
System.err.println(Arrays.toString(myArgs)); | |
Scene.v().loadNecessaryClasses(); | |
PackManager.v().runPacks(); | |
PackManager.v().writeOutput(); | |
appOut.close(); | |
} | |
/** The number of collected traces */ | |
int nbTraces; | |
static String classpathDelimiter =":"; | |
Writer appOut ; | |
} | |
/** used to store traces */ | |
class Variable { | |
String location = "!"; | |
String type = "!"; | |
Local l; | |
List<String> methodCalls = new ArrayList<String>(); | |
public String toString() { | |
String callString = ""; | |
for (Iterator<String> iterator = methodCalls.iterator(); iterator.hasNext();) { | |
String call = iterator.next(); | |
callString += call; | |
if(iterator.hasNext()) { | |
callString += " "; | |
} | |
} | |
//return location + " " + type + " " + callString; | |
return type + " " + callString; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment