Skip to content

Soot migration

Alexey Volkov edited this page Dec 13, 2022 · 10 revisions

Soot migration

Terminology:

Soot JacoDB
bytecode storage - JacoDB
scope of visible classes Scene JcClasspath
class SootClass JcClassOrInterface
class method SootMethod JcMethod
class field SootField JcField
type (with generics substitution) - JcJvmType
3-address bytecode representation JimpleBody JcRawInstList
control flow graph ClassicCompleteUnitGraph JcGraph
class hierarchy Hierarchy HierarchyExt
call graph CallGraph UsagesExt

Recommendations

  1. do not forget to close resource: JcClasspath, JacoDB.
  2. Creating classpath is a heavy operation involving I/O. All jars/folders passed to classpath are checked for:
    1. processed before
    2. has changed since processed before
    3. processing if they are not processed As a result good code should try to reuse classpath instance. After that it's recommended to call close method to take JacoDB possibility to delete processed resources that are out-of-date with file-system
  3. If there is a chance that code will call for class hierarchies then it's better to install InMemoryHierarchy feature.
  4. Persist data in file system is usable if your code base is huge enough or live after process restart is possible.
  5. Install only features that are required for this database.

Operations

create storage

Soot JacoDB
// points to specific runtime version
G.v().initJdk(new G.JreInfo(location, version)); 
Options options = Options.v();
options.set_soot_classpath(files);
Scene.v().loadNecessaryClasses();
PackManager.v().runPacks();
val db = jacodb {
    // points to specific runtime version
    useJavaRuntime(runtimeFolder)
    // jars to process
    loadByteCode(listOf(jar1, jar2))
    // persist all information to improve performance between restarts
    persistent(location = "/home/user/jcdb.db", clearOnStart = false)
}
val classpath = db.classpath(listOf(jar1))

find class

Soot JacoDB
SootClass clazz = Scene.v().getSootClass("java.lang.String");
val clazz = classpath.findClassOrNull("java.lang.String")

Get 3-address bytecode representation

Soot JacoDB
SootClass clazz = Scene.v().getSootClass("java.lang.String");
clazz.getMethod("length", Lists.emptyList()).retrieveActiveBody()
val clazz = classpath.findClassOrNull("java.lang.String") ?: throw  IllegalStateException()
classpath.findMethod("length").instructionList()

Get control flow graph

Soot JacoDB
new ClassicCompleteUnitGraph(sootMmthod.getActiveBody());
val cfg = jcMethod.instructionList().graph()

Hierarchy

Soot JacoDB
Hierarchy h = new Hierarchy();
h.getDirectSubclassesOf(clazz);
h.getDirectSubinterfacesOf(clazz);
val db = jacodb {
    // highly recommend to install this extension
    install(InMemoryHierarchy)
}

val ext = classpath.hierarchyExt()
ext.findSubClasses(clazz, allHierarchy = true)
ext.findOverrides(method)

Call graph/Usages

Soot JacoDB
CallGraph cg = new CallGraph();
cg.edgesInto(edge);
cg.edgesOutOf(edge);
val db = jacodb {
    // highly recommend to install InMemoryHierarchy extension
    install(Usages, InMemoryHierarchy)
}

val ext = classpath.usagesExt()
ext.findUsages(field, FieldUsageMode.READ)
ext.findUsages(field, FieldUsageMode.WRITE)
ext.findUsages(method)

Clone this wiki locally