[Soot-list] About generating call graph

Rongxin Wu wurx at cse.ust.hk
Mon Jun 24 03:35:56 EDT 2013


Dear All,
    When I use cg.spark to analyze the following source code, I came across
some problems.


public class TestCallGraph {

public void methodA() {
System.out.println("method A!");
}
 public void methodB() {
methodC();
TestCallGraphB testCallGraphB = new TestCallGraphB();
testCallGraphB.anotherMethod();
}
 public void methodC() {
System.out.println("method C!");
}

/**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
TestCallGraph testCallGraph = new TestCallGraph();
testCallGraph.methodA();
}

}

class TestCallGraphB{
public void anotherMethod(){
System.out.println("anothre method!");
}
}




The attachment is the source code that I used to analyze the call graph.
Also, I put the source code in this mail as following:


package test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import soot.PackManager;
import soot.Scene;
import soot.SceneTransformer;
import soot.SootClass;
import soot.SootMethod;
import soot.Transform;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.Edge;
import soot.options.Options;

public class GenerateCallGraph extends SceneTransformer {
public static final String PHASE_NAME = "wjtp.generateCallGraph";
private Map phaseOptions = new HashMap();
private ArrayList<String> defaultSootOptions = new ArrayList<String>();
private ArrayList<String> entryPoints;

@SuppressWarnings("unchecked")
public GenerateCallGraph() {

phaseOptions.put("cg",
"enabled:true,all-reachable:true,implicit-entry:true");
phaseOptions.put("cg.spark", "enabled:true,vta:true");
phaseOptions.put(PHASE_NAME, "on");
defaultSootOptions.add("-keep-line-number");
defaultSootOptions.add("-keep-bytecode-offset");
defaultSootOptions.add("-pp");
defaultSootOptions.add("-w");
}

public static void usage() {
System.out.println("usage:");
System.out
.println("java -jar GenerateCallGraph.jar [--soot-classpath ...]
[--process-dir ...] [--entry-point ...]");
System.out
.print("--soot-classpath classPath   (multiple classpaths can be speparated
by comma)"
+ "\t");
System.out
.print("--process-dir processDir  (multiple dirs can be assigned by
multiple times)"
+ "\t");
System.out
.print("--entry-point  (multple entry points can be assigned by multiple
times)"
+ "\t");
}

public String[] parse_options(String[] args) {
ArrayList<String> proessDirs = new ArrayList<String>();
String classPath = "";
if (args.length == 0) {
usage();
System.exit(1);
}
@SuppressWarnings("rawtypes")
List sootArgs = new ArrayList();
for (int i = 0, n = args.length; i < n; i++) {
if (args[i].equals("--soot-class-path")
|| args[i].equals("-soot-class-path")
|| args[i].equals("--soot-classpath")
|| args[i].equals("-soot-classpath")) {
// Pass classpaths without treating ":" as a method specifier.
sootArgs.add(args[i]);
sootArgs.add(args[++i]);
classPath = args[i];
} else if (args[i].equals("--process-dir")
|| args[i].equals("-process-dir")) {
sootArgs.add(args[i]);
sootArgs.add(args[++i]);
proessDirs.add(args[i]);
} else if (args[i].equals("--entry-point")
|| args[i].equals("-entry-point")) {
int smpos = args[++i].indexOf(':');
if (smpos == -1) {
sootArgs.add(args[i]);
} else {
String clsname = args[i].substring(0, smpos);
sootArgs.add(clsname);
if (entryPoints == null) {
entryPoints = new ArrayList<String>();
}
entryPoints.add(args[i]);
}
} else {
sootArgs.add(args[i]);
}
}

for (Object key : phaseOptions.keySet()) {
sootArgs.add("--p");
sootArgs.add(key);
sootArgs.add(phaseOptions.get(key));
}
for (Object option : defaultSootOptions) {
sootArgs.add(option);
}

// initialize the entry points
Options.v().set_whole_program(true);
Options.v().set_prepend_classpath(true);
Options.v().set_process_dir(proessDirs);

Options.v().set_soot_classpath(classPath);
if (entryPoints != null) {
for (String entryPoint : entryPoints) {
int smpos = entryPoint.indexOf(':');
if (smpos != -1) {
String className = entryPoint.substring(0, smpos);
String methname = entryPoint.substring(smpos + 1);
Scene.v().loadNecessaryClasses();
SootClass cl = Scene.v().loadClassAndSupport(className);
cl.setApplicationClass();
SootClass a = Scene.v().getSootClass(className);
SootMethod m = a.getMethodByName(methname);
try {
if (Scene.v().getEntryPoints() == null) {
ArrayList<SootMethod> entryPointMethods = new ArrayList<SootMethod>();
Scene.v().setEntryPoints(entryPointMethods);
}
} catch (Exception e) {
ArrayList<SootMethod> entryPointMethods = new ArrayList<SootMethod>();
Scene.v().setEntryPoints(entryPointMethods);
}
if (!Scene.v().getEntryPoints().contains(m)) {
Scene.v().getEntryPoints().add(m);
}
}
}
}
Options.v().set_soot_classpath("");
String[] sootArgsArray = new String[sootArgs.size()];
return (String[]) sootArgs.toArray(sootArgsArray);
}

@Override
protected void internalTransform(String phaseName, Map options) {
CallGraph callGraph = Scene.v().getCallGraph();
for (SootClass klass : Scene.v().getApplicationClasses()) {
for (SootMethod method : klass.getMethods()) {
if (!method.hasActiveBody()) {
continue;
}
Iterator<Edge> edges = callGraph.edgesOutOf(method);
while (edges.hasNext()) {
Edge edge = edges.next();
SootMethod calleeMethod = (SootMethod) edge.getTgt();
System.out.println(method.getSignature()+"\t"+calleeMethod.getSignature());
}
}
}
}
/**
 * @param args
 */
public static void main(String[] args) {
GenerateCallGraph generateCallGraph = new GenerateCallGraph();
Transform instrumentTransformer = new Transform(PHASE_NAME,
generateCallGraph);
PackManager.v().getPack("wjtp").add(instrumentTransformer);
args = generateCallGraph.parse_options(args);
soot.Main.main(args);
}

}



    Looking forward to your reply. Thanks very much.

Best Regards,
Yours

Rongxin WU
2013/June/24









The command that I used is:
java -Xmx4096m test.GenerateCallGraph --soot-classpath
C:\workspace3\ThreadExample\bin -pp -process-dir
C:\workspace3\ThreadExample\bin -d sootOutput -w -entry-point
TestCallGraph:main -entry-point TestCallGraph:methodB


Since I would like to add more entry points as I expect, I write the above
source code. However, I cannot get a complete call graph as I wish. The
following is the call graph that I obtained. TestCallGraph.methodB's call
graph is incomplete. The call edge from  TestCallGraph.methodB to
 TestCallGraph.methodC is missed. I found many cases like this. It seems
that, if the method is not a main function even it is an entry point, the
method call the other member function, then this edge will be missed.


<TestCallGraphB: void <init>()> <java.lang.Object: void <init>()>
<TestCallGraphB: void anotherMethod()> <java.lang.System: void <clinit>()>
<TestCallGraphB: void anotherMethod()> <java.io.PrintStream: void
println(java.lang.String)>
<TestCallGraphB: void anotherMethod()> <java.lang.Object: void <clinit>()>
<TestCallGraph: void <init>()> <java.lang.Object: void <init>()>
<TestCallGraph: void methodA()> <java.lang.System: void <clinit>()>
<TestCallGraph: void methodA()> <java.io.PrintStream: void
println(java.lang.String)>
<TestCallGraph: void methodA()> <java.lang.Object: void <clinit>()>
<TestCallGraph: void methodB()> <java.lang.Object: void <clinit>()>
<TestCallGraph: void methodB()> <TestCallGraphB: void anotherMethod()>
<TestCallGraph: void methodB()> <TestCallGraphB: void <init>()>
<TestCallGraph: void main(java.lang.String[])> <java.lang.Object: void
<clinit>()>
<TestCallGraph: void main(java.lang.String[])> <TestCallGraph: void
methodA()>
<TestCallGraph: void main(java.lang.String[])> <TestCallGraph: void
<init>()>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mailman.cs.mcgill.ca/pipermail/soot-list/attachments/20130624/c4aca48a/attachment-0001.html 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: GenerateCallGraph.java
Type: application/octet-stream
Size: 5508 bytes
Desc: not available
Url : http://mailman.cs.mcgill.ca/pipermail/soot-list/attachments/20130624/c4aca48a/attachment-0001.obj 


More information about the Soot-list mailing list