Skip to content

First Steps with SootUp

Before you get started with the SootUp library, it helps to learn about the following core data structures:

  • AnalysisInputLocation : points to the target code that shall be loaded into the View.

  • View: handles the representation of the code you configured it to analyze.

  • SootClass: represents a class. Can be loaded from the View via a ClassType identifier.

  • SootMethod: represents a method of a class - loaded from the View via a MethodSignature identifier.
  • SootField: represents a field of a class - loaded from the View via a FieldSignature identifier.
  • Body: represents a method body of a SootMethod.
  • StmtGraph: represents the control flow graph of a Body. Stmt's represent actual Instructions.

Creating a View

You can use bytecode analysis typically when you do not have access to the source code of the target program. Following example shows how to create a view for analyzing Java bytecode.

Create a view to analyze Java bytecode

1
2
3
4
AnalysisInputLocation inputLocation = 
        new JavaClassPathAnalysisInputLocation("path2Binary");

JavaView view = new JavaView(inputLocation);

If you have access to the source code, it is also possible to create a view for analyzing source code. Following example shows how to create view for analyzing Java source code.

Experimental! - Create a view to analyze Java source code

The source code frontend is experimental and should only be used for testing purposes. Usually you should compile the code for analysis first and use the bytecode frontend instead (see above).

1
2
3
4
AnalysisInputLocation inputLocation = 
        new JavaSourcePathAnalysisInputLocation("path2Source");

JavaView view = new JavaView(inputLocation);

If you have a Jimple file, you can create a view for analyzing jimple code directly. Following example shows how to create a view for analyzing jimple code.

Create a view to analyze jimple code

1
2
3
4
5
6
Path pathToJimple = Paths.get("path2Jimple");

AnalysisInputLocation inputLocation = 
        new JimpleAnalysisInputLocation(pathToJimple);

JimpleView view = new JimpleView(inputLocation);

By default, whenever a class is retrieved, it will be permanently stored in a cache. If you do not want retrieved classes to be stored indefinetly, you can instead provide a different CacheProvider to the created view. To for example use an LRUCache instead, which stores at most e.g. 50 classes, and always replaces the least recently used class by a newly retrieved one, use the following call:

1
JavaView view = new JavaView(inputLocations, new LRUCacheProvider(50));

Retrieving a Class

Each class is identified with a unique signature adhering to Java identifier rules, therefore you first need to specify the class signature (ClassType) as shown below.

Let's say the following is the target program that we want to analyze:

Target Program

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package example;

public class HelloWorld {

  public HelloWorld() {

  }

  public static void main(String[] args) {
    HelloWorld hw = new HelloWorld();
    hw.hello();
  }

  public void hello() {

  }

}

Then, we could define the ClassType of the HelloWorld class as follows:

Defining a ClassType

1
2
JavaClassType classType = 
        view.getIdentifierFactory().getClassType("example.HelloWorld");

Once we have a ClassType that identifies the HelloWorld class, we can use it to retrieve the corresponding SootClass object from the view as shown below:

Retrieving a SootClass

1
JavaSootClass sootClass = view.getClass(classType).get();

Retrieving a Method

Like the classes, methods also have an identifier which we call MethodSignature. For instance, we can define the method signature for identifying the main method of the HelloWorld class as follows:

Defining a MethodSignature

1
2
3
4
5
6
7
8
MethodSignature methodSignature =
    view
        .getIdentifierFactory()
        .getMethodSignature(
            "main", // method name
            classType,
            "void", // return type
            Collections.singletonList("java.lang.String[]")); // args
1
2
3
4
5
MethodSignature methodSignature =
    view
        .getIdentifierFactory()
        .parseMethodSignature(
            "<packageName.classType: void main(java.lang.String[])>");

Once we have a MethodSignature that identifies the main method of the HelloWorld class, we can use it to retrieve the corresponding SootMethod object from the view as shown below:

Retrieving a SootMethod from the View

1
2
3
4
5
6
7
Optional<SootMethod> opt = view.getMethod(methodSignature);

if(!opt.isPresent()){
    return;
}
SootMethod method = opt.get();
System.out.println(method.getModifiers());

Alternatively, we can also retrieve a SootMethod from SootClass that contains it.

Retrieving a SootMethod from a SootClass

1
2
3
4
5
6
MethodSubSignature mss = methodSignature.getSubSignature()
Optional<JavaSootMethod> opt = sootClass.getMethod(mss);

if(opt.isPresent()){
  JavaSootMethod method = opt.get();
}

Retrieving the Control-Flow Graph of a Method

Each SootMethod contains a Control-Flow Graph (CFG) which is represented via the StmtGraph. This structure is usually used for program analysis. You can retrieve the CFG of a SootMethod as follows:

Retrieving the CFG of a SootMethod

1
StmtGraph<?> graph = sootMethod.getBody().getStmtGraph();

Using the StmtGraph

1
2
3
4
5
6
7
for( Stmt stmt : graph.nodes()){
    // pseudo topological order as Stmts would be serialized to a Jimple file.
}

for( Stmt stmt : graph.nodes()){
    // Stmts are unordered!
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
List<BasicBlock<?>> blocks = graph.getBlocks();
for( BasicBlock<?> block : blocks){
    // e.g. check if its a merge point
    if(block.getPredecessors().size() > 1){
        ...
    }

    // e.g. check if its a branching point
    if(block.getSuccessors().size() > 1){
        // or use block.getTail() instanceof BranchingStmt
        ...
    }

    // e.g. check if thrown exceptions would be caught in this method
    if(!block.getExceptionalSuccessors().isEmpty()){
        ...
    }
}
1
2
String urlToWebeditor = DotExporter.createUrlToWebeditor(this);
System.out.println(urlToWebeditor);

Access a complete example of the code used above

Download BasicSetup.java