diff --git a/develop/callgraphs/index.html b/develop/callgraphs/index.html index 776b7986bd..7c2af28af9 100644 --- a/develop/callgraphs/index.html +++ b/develop/callgraphs/index.html @@ -1327,11 +1327,15 @@
String MAINCLASS = "dacapo.antlr.Main"; // just an example
-PTAPattern ptaPattern = new PTAPattern("insens"); // "2o"=>2OBJ, "1c"=>1CFA, etc.
-PTA pta = PTAFactory.createPTA(ptaPattern, view, MAINCLASS);
-pta.run();
-CallGraph cg = pta.getCallGraph();
+5
+6
+7
```java
+String MAINCLASS = "dacapo.antlr.Main"; // just an example
+PTAPattern ptaPattern = new PTAPattern("insens"); // "2o"=>2OBJ, "1c"=>1CFA, etc.
+PTA pta = PTAFactory.createPTA(ptaPattern, view, MAINCLASS);
+pta.run();
+CallGraph cg = pta.getCallGraph();
+```
SootUp is a complete overhaul of the good, old static analysis framework Soot.
Important
SootUp is not a version update to Soot, it is a completely new implementation written from scratch that aims to be a leaner, modernized and developer friendly successor of Soot. It is not a Drop-In Replacement! The new architecture and API, renders it not trivial to update existing projects that were built on soot. Therefore we recommend using SootUp for greenfield projects. We hope improved type safety and streamlined mechanisms will aide you implementing and debugging your analysis tool. Unfortunately not every feature has been ported - If you miss something feel free to contribute a feature you miss from good old Soot.
"},{"location":"#why-sootup","title":"Why SootUp?","text":"Over the 20+ years, SootUps predecessor Soot has evolved into a powerful framework, which is one of the most widely used tools in the static analysis community. This evolution was guided by the needs of the community and carried out with ad-hoc improvements. As a result, Soot has become a tool that can do a multitude of things, but it is heavy and hard to maintain and comprehend. So there was the need to clean up the codebase e.g. improve the software architecture, remove legacy datastructures that weren't in the Java Runtime at the time of Soots creation, enforce validation to have a sane state, removing the necessity of arcane knowledge, document it more and more - to make Soot future prove. So we introduced Design changes in SootUp, which aim to address Soot's shortcomings. The goal is a lighter library that can easily be understood and maintained to be included in other projects.
"},{"location":"#supporters","title":"Supporters","text":"The development of SootUp is financed by generous support from the German Research Foundation (DFG) and the Heinz Nixdorf Institute (HNI).
Become a sponsor!
"},{"location":"analysisinput/","title":"Analysis Input","text":"i.e. What should be analyzed. An AnalysisInputLocation
points to code input SootUp can analyze. We ship multiple Implementations that can handle different input.
Additionally you can specify a SourceType. This determines what is considered e.g. in the CallGraphs generation. Further you can specify a List of BodyInterceptors, which will optimize the raw Jimple IR that was transformed from the input.
"},{"location":"analysisinput/#java-runtime","title":"Java Runtime","text":""},{"location":"analysisinput/#java-8","title":"Java <=8","text":"The DefaultRTJaAnalysisInputLocation
points to the rt.jar of the executing JVM.
AnalysisInputLocation inputLocation = new DefaultRTJaAnalysisInputLocation();\nJavaView view = new JavaView(inputLocation);\n
To include a different Java Runtime library point to any rt.jar via a JavaClassPathAnalysisInputLocation
as its a usual .jar file.
The JRTFilesystemAnalysisInputLocation
points to the jigsawed java runtime of the executing JVM.
AnalysisInputLocation inputLocation = new JrtFileSystemAnalysisInputLocation(); \nJavaView view = new JavaView(inputLocation);\n
If you have errors like Java.lang.String, Java.lang.Object, ... you are most likely missing this AnalysisInputLocation.
"},{"location":"analysisinput/#java-bytecode","title":"Java Bytecode","text":"File-Extensions: .class, .jar, .war
The JavaClassPathAnalysisInputLocation
is the equivalent of the classpath you would pass to the java executable i.e. point to root(s) of package(s).
AnalysisInputLocation inputLocation =\n new JavaClassPathAnalysisInputLocation(\"target/\"); // points to\nJavaView view = new JavaView(inputLocation);\n
AnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation(\"myCode.jar\");\nJavaView view1 = new JavaView(inputLocation);\n\n// if you want to analyze a specific language level of a multi release jar\nAnalysisInputLocation inputLocation =\n new MultiReleaseJarAnalysisInputLocation(\"myCode.jar\", new JavaLanguage(10) );\nJavaView view2 = new JavaView(inputLocation);\n
// if you omit the package structure while pointing to a file,\n// you have to pass the omitted directories as a parameter\nAnalysisInputLocation inputLocation = new PathBasedAnalysisInputLocation.\n ClassFileBasedAnalysisInputLocation(\"Banana.class\", \"packageName.subPackage\", SourceType.Application);\nJavaView view = new JavaView(inputLocation);\n
String cp = \"myCode.jar\" + File.pathSeparator + \"dependency.jar\" + File.pathSeparator + \"target/classes/\";\nAnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation(cp);\nJavaView view = new JavaView(inputLocation);\n
"},{"location":"analysisinput/#java-sourcecode","title":"Java Sourcecode","text":"File-Extensions: .java
With the OTFCompileAnalysisInputLocation
you can point directly to .java files or pass a String with Java sourcecode. The AnalysisInputLocation delegates the data to the JavaCompiler
and transform the bytecode from the compiler to Jimple.
AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(\"Banana.java\");\nJavaView view = new JavaView(inputLocation);\n
List<Path> files = Arrays.asList(Paths.get(\"Apple.java\"), Paths.get(\"Banana.java\"));\nAnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(files);\nJavaView view = new JavaView(inputLocation);\n
String content = \"public class B{ }\";\nAnalysisInputLocation location = new OTFCompileAnalysisInputLocation(\"B.java\", content );\nJavaView view = new JavaView(location);\n
JavaSourcePathInputLocation
experimental! - points to a directory that is the root source directory (containing the package directory structure).
File-Extensions: .jimple
The JimpleAnalysisInputLocation
needs a Path to a .jimple file or a directory.
Path path = Paths.get(\"Banana.java\");\nAnalysisInputLocation jimpleLocation = new JimpleAnalysisInputLocation(path);\nJavaView view = new JavaView(jimpleLocation);\n
"},{"location":"analysisinput/#android-bytecode","title":"Android Bytecode","text":"File-Extensions: .apk
The ApkAnalysisInputLocation
is the APK frontend written for Sootup
Path path = Paths.get(\"Banana.apk\");\nAnalysisInputLocation inputLocation = new ApkAnalysisInputLocation(path, \"\", DexBodyInterceptors.Default.bodyInterceptors());\nJavaView view = new JavaView(inputLocation);\n
"},{"location":"analysisinput/#android-bytecode-with-dex2jar","title":"Android Bytecode with Dex2Jar","text":"File-Extensions: .apk
If you prefer to use dex2jar as a base to transform android apps to jimple, you can add the code below to create your own analysis input location. We used the dependency de.femtopedia.dex2jar:dex2jar:2.4.22 in the given example. We recommend to use ApkAnalysisInputLocation
Path path = Paths.get(\"Banana.apk\");\nAnalysisInputLocation inputLocation = new Dex2JarAnalysisInputLocation(path);\nJavaView view = new JavaView(inputLocation);\n
public class Dex2JarAnalysisInputLocation extends ArchiveBasedAnalysisInputLocation {\n\n public Dex2JarAnalysisInputLocation(@Nonnull Path path, @Nullable SourceType srcType) {\n super(path, srcType);\n String jarPath = dex2jar(path);\n this.path = Paths.get(jarPath);\n }\n\n private String dex2jar(Path path) {\n String apkPath = path.toAbsolutePath().toString();\n String outDir = \"./tmp/\";\n int start = apkPath.lastIndexOf(File.separator);\n int end = apkPath.lastIndexOf(\".apk\");\n String outputFile = outDir + apkPath.substring(start + 1, end) + \".jar\";\n Dex2jarCmd.main(\"-f\", apkPath, \"-o\", outputFile);\n return outputFile;\n }\n}\n
"},{"location":"analysisinput/#combining-multiple-analysisinputlocations","title":"Combining Multiple AnalysisInputLocations","text":"But what if I want to point to multiple AnalysisInputLocations?
AnalysisInputLocation mainJar = new JavaClassPathAnalysisInputLocation(\"myCode.jar\");\nAnalysisInputLocation jarA = new JavaClassPathAnalysisInputLocation(\"dependencyA.jar\");\nAnalysisInputLocation jarB = new JavaClassPathAnalysisInputLocation(\"dependencyB.jar\");\n\nList<AnalysisInputLocation> inputlocationList = Arrays.asList(mainJar, jarA, jarB);\n\nJavaView view = new JavaView(inputlocationList);\n
Of course you can combine different types of AnalysisInputLocation
s as well!
This uses mvn compile
+ JavaClassPathAnalysisInputLocation
under the hood to include a maven project.
TODO: let the code sail with the upstream boat to this doc.\n
Unfortunately its harder to extract the path of the binary result of Gradle projects in a unified way for all kinds of models - If you have a solution are looking forward to merge your contribution :-).
"},{"location":"analysisinput/#java-cli-arguments-to-configure-sootup","title":"Java cli arguments to configure SootUp","text":"We created a Utility that parses a String of java command line arguments and configures SootUp respectively.
"},{"location":"announcement/","title":"Announcements","text":""},{"location":"announcement/#release-announcement","title":"Release Announcement","text":"We would like to announce Soot\u2019s successor, SootUp.
Over more than 20 years, Soot has become one of the world\u2019s most popular academic tool for Java and Android analysis and instrumentation. We thank all of you who have used and contributed to it over the years! It was your feedback and your contributions that helped it grow into such a versatile tool!
However, over the years, the requirements for Soot have changed a lot, and given its original architecture, it was no longer quite up to the task. Soot was originally developed for ahead-of-time code transformation, particularly optimization, which has become very uncommon in Java. Current use cases center much more around powerful program analyses and program-understanding tasks.
Today we are officially releasing SootUp, a new version of Soot with a completely overhauled architecture. With SootUp, we aim to keep the best things about Soot, yet overcome a lot of its drawbacks. We very much restructured Soot, particularly abolishing the heavy use of singletons. Soot now has a concept of views; each view corresponds to some version or variant of an analyzed program, and multiple views can be kept in memory at the same time. This sets the foundation, for instance, for differential or incremental program analyses.
SootUp is a library that can easily be included in other projects, leaving those projects in control. For those who intend to use it as a framework, with inversion of control, SootUp provides additional templates that help you and novices to get started more easily. The Jimple IR has been slightly simplified, and has been made immutable by default such that internally SootUp can make use of caching where desired. Where required, Jimple transformations are still allowed, but in a systematic manner, for instance assuring that analyses depending on the transformed code are notified about its changes.
Below is an overview of what\u2019s new.
SootUp is not a drop-in replacement for Soot! Due to its completely new architecture and API it is essentially an almost complete rewrite. For a while, Soot and SootUp will coexist, as many existing tools depend on Soot, yet our maintenance efforts will henceforth be focused on SootUp, not Soot, and on extending SootUp with those capabilities that people still find missing. For now, we recommend using SootUp for greenfield projects.
For more details, check out
This Page ;-) and The SootUp repository: https://github.com/soot-oss/SootUp/
We are very much looking forward to your feedback and feature requests. To this end, best create appropriate issues in the repository.
This major upgrade of Soot was made possible by generous competitive funding by the DFG, within the project \u201cFuture-proofing the Soot Framework for Program Analysis and Transformation (FutureSoot)\u201d. It was funded in the DFG\u2019s program on Research Software Sustainability.
"},{"location":"bodyinterceptors/","title":"Body Interceptors","text":"BodyInterceptors are applied to each Body
now by default, if not overridden in the used AnalysisInputLocations. The BodyInterceptors exist to to improve and normalize the raw Jimple that was generated in an earlier step. The \"raw\" generated Jimple from the Bytecodefrontend needs a lot improvements - deficits of raw Jimple are:
Optimizations (method scope)
Standardize Jimple appearance
Soot Equivalent
BodyTransformer
"},{"location":"bodyinterceptors/#localsplitter","title":"LocalSplitter","text":"LocalSplitter is aBodyInterceptor
that attempts to identify and separate uses of a local variable (as definition) that are independent of each other by renaming local variables.
Example 1:
As shown in the example above, the local variablel1
is defined twice. It can be split up into two new local variables: l1#1
and l1#2
because the both definitions are independent of each other.
Look for foldable navigation and tabs for showing old vs new
Example 2:
In the second example, the local variablel2
is defined thrice. But it cannot be split up into three new local variables as in the first example, because its definitions in the if-branches are not independent of each other. Therefore, it can only be split up into two local variables as shown in the figure.
LocalPacker is aBodyInterceptor
that attempts to minimize the number of local variables which are used in body by reusing them, when it is possible. It corresponds to the inverse body transformation of LocalSplitter. Note: Every local variable's type should be assigned before running LocalPacker.
Example:
In the given example above, the local variablesl1
,l3
are summarized to be one local variablel1
, because they have the same type without interference with each other. Likewise, the local variablesl2
,l4
andl5
are summarized to be another local variablel2
. Although the local variablel0
doesn't interfere any other local variables, it cannot be summed up with other local variables because of its distinctive type.
WIP - currently not available!
TrapTightener is aBodyInterceptor
that shrinks the protected area covered by each Trap in a Body.
Example:
We assume in the example above that only theStmt
:l2 := 2
might throw an exception caught by theTrap
which is labeled withlabel3
. In the jimple body before running the TrapTightener, the protected area covered by the Trap contains threeStmts
:l1 := 1; l2 := 2; l2 := 3
. But an exception could only arise at theStmt
:l2 := 2
. After the implementation of TrapTightener, we will get a contractible protected area which contains only theStmt
that might throw an exception, namely theStmt
:l2 := 2
.
EmptySwitchEliminator is aBodyInterceptor
that removes empty switch statements which contain only the default case.
Example:
As shown in the example above, the switch statement in the jimple body always takes the default action. After running EmptySwitchEliminator, the switch statement is replaced with aGotoStmt
to the default case.
UnreachableCodeEliminator is aBodyInterceptor
that removes all unreachable statements.
Example:
Obviously, the code segmentl2 = 2; l3 = 3;
is unreachable. It will be removed after running the UreachableCodeEliminator.
CopyPropagator is a BodyInterceptor
that supports copy propagation and constant propagation.
CopyPropagator
\"Definition 3[Copy Propagation]: The use of a variable y in the statement z=x+y occurring at a point p can be replaced by a variable w if every path from the entry node to point p contains the same definition y=w, for the variable y, and after the definition prior to reaching p, there is no redefinition to the variable y and no redefinition to the variable w.\"
Sreekala, S. K. and Vineeth Kumar Paleri. \u201cCopy Propagation subsumes Constant Propagation.\u201d ArXiv abs/2207.03894 (2022): n. pag.
Example for global copy propagation:
Consider a code segment in the following form:
a = b;\n...\nc = use(a); // a, b, c are local variables\n
According to the copy propagation's definition, the statementc = use(a)
can be replaced withc = use(b)
iff both conditions are met:
a
is defined only one time on all the paths froma = b
toc = use(a)
.b
on any path froma = b
toc = use(a)
.In the example for global copy propagation, the first usedl1
is replaced withl0
, but the second usedl1
cannot be replaced withl3
, because the second condition is not satisfied.
Example for constant propagation:
Constant propagation is similar to copy propagation. Consider a code segment in the following form:
a = const;\n...\nb = use(a); // a, b are local variables, const is a constant\n
After perfoming the constant propagation, the statementb = use(a)
can be replaced withb = use(const)
iffa
is not redefined on any of the paths froma = const
tob = use(a)
.
Therefore, the first usedl1
in the second example can be replaced with the constant1
, but the second usedl1
cannot be replaced with the constant2
, becausel1
is redefined on the path froml1 = 2
tol4 = use(l1)
. However, it can be replaced with local variablel2
, because the both conditions of copy propagation are met.
LocalNameStandardizer is aBodyInterceptor
that assigns a generic name to each local variable. Firstly, it will sort the local variables' order alphabetically by the string representation of their type. If there are two local variables with the same type, then the LocalNameStandardizer will use the sequence of their occurrence in jimple body to determine their order. Each assigned name consists of two parts:
The following table shows the letter corresponding to each type:
Type of Local Variable Letter boolean z byte b short s int i long l float f double d char c null n unknown e reference r"},{"location":"bodyinterceptors/#staticsingleassignmentformer","title":"StaticSingleAssignmentFormer","text":"StaticSingleAssignmentFormer is aBodyInterceptor
that transforms jimple body into SSA form, so that each local variable is assigned exactly once and defined before its first use.
Example:
In the given example, the StaticSingleAssignmentFormer assigns eachIdentityStmt
andAssignStmt
to a new local variable . And each use uses the local variable which is most recently defined. Sometimes, it is impossible to determine the most recently defined local variable for a use in a join block. In this case, the StaticSingleAssignmentFormer will insert aPhiStmt
in the front of the join block to merge all most recently defined local variables and assign them a new local variable.
More to come!
"},{"location":"builtin-analyses/#locallivenessanalyser","title":"LocalLivenessAnalyser","text":"LocalLivenessAnalyser is used for querying for the list of live local variables before and after a given Stmt
.
Example:
The live local variables before and after each Stmt
will be calculated after generating an instance of LocalLivenessAnalyser as shown the example above. They can be queried by using the methods getLiveLocalsBeforeStmt
and getLiveLocalsAfterStmt
.
DomianceFinder is used for querying for the immediate dominator and dominance frontiers for a given basic block.
Example:
After generating an instance of DominanceFinder for a BlockGraph
, we will get the immediate dominator and dominance frontiers for each basic block. The both properties can be queried by using the methodsgetImmediateDominator
andgetDominanceFrontiers
.
A call graph shows the method calling relationship of a program. It is a directed graph, whose nodes represent different methods, and edges represent caller -> callee relationship.
SootUp contains several call graph construction algorithms. Below, we show how you can use each of these.
"},{"location":"callgraphs/#creating-the-type-hierarchy","title":"Creating the Type Hierarchy","text":"All the call graph construction algorithms require the view to access the type hierarchy for resolving method calls based of sub typing relationship. Below, we show how to create a type hierarchy:
SootUpSootString cpString = \"src/test/resources/Callgraph/binary\";\nList<AnalysisInputLocation> inputLocations = new ArrayList();\ninputLocations.add(new JavaClassPathAnalysisInputLocation(cpStr));\ninputLocations.add(new DefaultRuntimeAnalysisInputLocation());\n\nJavaView view = new JavaView(inputLocations);\n
String userdir = System.getProperty(\"user.dir\");\nString sootCp = userdir + File.separator + \"target\" + File.separator + \"test-classes\"+ File.pathSeparator + \"lib\"+File.separator+\"rt.jar\";\nString targetTestClassName = target.exercise1.Hierarchy.class.getName();\nG.reset();\nOptions.v().set_whole_program(true);\nOptions.v().set_soot_classpath(sootCp);\nOptions.v().set_no_bodies_for_excluded(true);\nOptions.v().process_dir();\nOptions.v().set_allow_phantom_refs(true);\nOptions.v().setPhaseOption(\"jb\", \"use-original-names:true\");\nOptions.v().set_prepend_classpath(false);\nSootClass c = Scene.v().forceResolve(targetTestClassName, SootClass.BODIES);\nif (c != null)\n c.setApplicationClass();\nScene.v().loadNecessaryClasses();\n\nHierarchy hierarchy = new Hierarchy();\n
"},{"location":"callgraphs/#defining-an-entry-method","title":"Defining an Entry Method","text":"All call graph construction algorithms require an entry method to start with. In java application, you usually define the main method. However, it is possible to define arbitrary entry methods depending on your needs. Below, we show how to define such an entry method:
SootUp (performant)SootUp (alternative)SootJavaClassType classTypeA = view.getIdentifierFactory().getClassType(\"packageNameA.A\");\n\nMethodSignature entryMethodSignature =\n view.getIdentifierFactory()\n .getMethodSignature(\n classTypeA,\n \"calc\",\n VoidType.getInstance(),\n Collections.singletonList(classTypeA)\n );\n
String methodSigStr = \"<packageNameA.A: void calc(packageNameA.A)\";\nMethodSignature entryMethodSignature = view\n .getIdentifierFactory().parseMethodSignature(methodSigStr));\n
String targetTestClassName = \"packageNameA.A\";\nSootMethod src = Scene.v().getSootClass(targetTestClassName).getMethodByName(\"doStuff\"); \n
"},{"location":"callgraphs/#class-hierarchy-analysis","title":"Class Hierarchy Analysis","text":"Class Hierarchy Analysis (CHA) algorithm is the most sound call graph construction algorithm available in SootUp. It soundly includes all implementers of an interface, when resolving a method call on an interface. You can construct a call graph with CHA as follows:
SootUpSootCallGraphAlgorithm cha = new ClassHierarchyAnalysisAlgorithm(view);\n\nCallGraph cg = cha.initialize(Collections.singletonList(entryMethodSignature));\n\ncg.callsFrom(entryMethodSignature).stream()\n .forEach(tgt -> System.out.println(entryMethodSignature + \" may call \" + tgt);\n
CHATransformer.v().transform();\nSootMethod src = Scene.v().getSootClass(targetTestClassName).getMethodByName(\"doStuff\");\nCallGraph cg = Scene.v().getCallGraph();\nIterator<MethodOrMethodContext> targets = new Targets(cg.edgesOutOf(src));\nwhile (targets.hasNext()) {\n SootMethod tgt = (SootMethod)targets.next();\n System.out.println(src + \" may call \" + tgt);\n}\n
"},{"location":"callgraphs/#rapid-type-analysis","title":"Rapid Type Analysis","text":"Rapid Type Analysis (RTA) algorithm constructs a rather precise version of the call graph that the CHA constructs. It refines CHA by considering only the instantiated implementers of an interface, when resolving a method call on an interface. You can construct a call graph with RTA as follows:
SootUpSootCallGraphAlgorithm rta = new RapidTypeAnalysisAlgorithm(view);\n\nCallGraph cg = rta.initialize(Collections.singletonList(entryMethodSignature));\n\ncg.callsFrom(entryMethodSignature).stream()\n .forEach(tgt -> System.out.println(entryMethodSignature + \" may call \" + tgt);\n
Transform sparkConfig = new Transform(\"cg.spark\", null);\nPhaseOptions.v().setPhaseOption(sparkConfig, \"enabled:true\");\nPhaseOptions.v().setPhaseOption(sparkConfig, \"rta:true\");\nPhaseOptions.v().setPhaseOption(sparkConfig, \"on-fly-cg:false\");\nMap phaseOptions = PhaseOptions.v().getPhaseOptions(sparkConfig);\nSparkTransformer.v().transform(sparkConfig.getPhaseName(), phaseOptions);\nSootMethod src = Scene.v().getSootClass(targetTestClassName).getMethodByName(\"doStuff\");\nCallGraph cg = Scene.v().getCallGraph();\nIterator<MethodOrMethodContext> targets = new Targets(cg.edgesOutOf(src));\nwhile (targets.hasNext()) {\n SootMethod tgt = (SootMethod)targets.next();\n System.out.println(src + \" may call \" + tgt);\n} \n
"},{"location":"callgraphs/#qilin-pointer-analysis","title":"Qilin Pointer Analysis","text":"Qilin builds a call graph on the fly with the pointer analysis. You can construct a call graph with Qilin as follows:
===\"SootUp\"
String MAINCLASS = \"dacapo.antlr.Main\"; // just an example\nPTAPattern ptaPattern = new PTAPattern(\"insens\"); // \"2o\"=>2OBJ, \"1c\"=>1CFA, etc.\nPTA pta = PTAFactory.createPTA(ptaPattern, view, MAINCLASS);\npta.run();\nCallGraph cg = pta.getCallGraph();\n
"},{"location":"codepropertygraphs/","title":"Code Property Graphs","text":""},{"location":"codepropertygraphs/#dependencies","title":"Dependencies","text":"MavenGradle <dependency>\n<groupId>org.soot-oss</groupId>\n<artifactId>sootup.codepropertygraph</artifactId>\n<version>1.3.0</version>\n</dependency>\n
compile \"org.soot-oss:sootup.codepropertygraph:1.3.0\"\n
Code Property Graphs (CPGs) are a representation of program code that combines different code representations into a single graph. This unified representation includes abstract syntax trees (ASTs), control flow graphs (CFGs), control dependence graphs (CDGs), and data dependence graphs (DDGs). CPGs enable comprehensive analysis, which makes them a powerful tool for detecting vulnerabilities and understanding code structure. For further details, refer to this thesis.
"},{"location":"codepropertygraphs/#usage-example","title":"Usage Example","text":"In this example, we will demonstrate how to create a CPG for a vulnerable Java method and use it to identify a potential vulnerability.
"},{"location":"codepropertygraphs/#vulnerable-java-code","title":"Vulnerable Java Code","text":"Let's assume we have the following vulnerable Java code in a file named VulnerableClass.java
:
public class VulnerableClass {\n public void vulnerableMethod(String userInput) {\n if (userInput.equals(\"admin\")) {\n System.out.println(\"Welcome, admin!\");\n }\n }\n}\n
"},{"location":"codepropertygraphs/#step-1-obtain-a-sootmethod","title":"Step 1: Obtain a SootMethod","text":"First, we assume we have a SootMethod
for the vulnerableMethod
. For instructions on how to obtain a SootMethod
, refer to Retrieving a Method.
We can create the CPG subgraphs using the creators.
ASTCFGCDGDDGpublic class AstExample {\n\n public static void main(String[] args) {\n // Assuming `sootMethod` is obtained from the setup step\n SootMethod vulnerableMethod = getVulnerableMethod();\n\n // Create the AST subgraph\n AstCreator astCreator = new AstCreator();\n PropertyGraph astGraph = astCreator.createGraph(vulnerableMethod);\n\n // Print the DOT representation of the AST\n System.out.println(astGraph.toDotGraph());\n }\n}\n
public class CfgExample {\n\n public static void main(String[] args) {\n // Assuming `sootMethod` is obtained from the setup step\n SootMethod vulnerableMethod = getVulnerableMethod();\n\n // Create the CFG subgraph \n CfgCreator cfgCreator = new CfgCreator();\n PropertyGraph cfgGraph = cfgCreator.createGraph(vulnerableMethod);\n\n // Print the DOT representation of the CFG\n System.out.println(cfgGraph.toDotGraph());\n }\n}\n
public class CdgExample {\n\n public static void main(String[] args) {\n // Assuming `sootMethod` is obtained from the setup step\n SootMethod vulnerableMethod = getVulnerableMethod();\n\n // Create the CDG subgraph\n CdgCreator cdgCreator = new CdgCreator();\n PropertyGraph cdgGraph = cdgCreator.createGraph(vulnerableMethod);\n\n // Print the DOT representation of the CDG\n System.out.println(cdgGraph.toDotGraph());\n }\n}\n
public class DdgExample {\n\n public static void main(String[] args) {\n // Assuming `sootMethod` is obtained from the setup step\n SootMethod vulnerableMethod = getVulnerableMethod();\n\n // Create the DDG subgraph\n DdgCreator ddgCreator = new DdgCreator();\n PropertyGraph ddgGraph = ddgCreator.createGraph(vulnerableMethod);\n\n // Print the DOT representation of the DDG\n System.out.println(ddgGraph.toDotGraph());\n }\n}\n
We can create the combined CPG graph using the CpgCreator
.
public class CpgExample {\n\n public static void main(String[] args) {\n // Assuming `sootMethod` is obtained from the setup step\n SootMethod vulnerableMethod = getVulnerableMethod();\n\n AstCreator astCreator = new AstCreator();\n CfgCreator cfgCreator = new CfgCreator();\n CdgCreator cdgCreator = new CdgCreator();\n DdgCreator ddgCreator = new DdgCreator();\n\n // Create the combined CPG\n CpgCreator cpgCreator = new CpgCreator(astCreator, cfgCreator, cdgCreator, ddgCreator);\n PropertyGraph cpg = cpgCreator.createCpg(vulnerableMethod);\n\n // Print the DOT representation of the CPG\n System.out.println(cpg.toDotGraph());\n }\n}\n
"},{"location":"codepropertygraphs/#step-3-analyzing-the-cpg","title":"Step 3: Analyzing the CPG","text":"With the CPG created, you can now analyze it for vulnerabilities. For example, you can check for potential injection vulnerabilities by analyzing data flow dependencies.
SootUppublic class VulnerabilityAnalysis {\n\n public static void main(String[] args) {\n // Assuming `cpg` is the PropertyGraph created in the previous step\n for (DdgEdge edge : cpg.getEdges(DdgEdge.class)) {\n StmtGraphNode source = (StmtGraphNode) edge.getSource();\n StmtGraphNode destination = (StmtGraphNode) edge.getDestination();\n\n if (isPotentiallyVulnerable(source, destination)) {\n System.out.println(\"Potential vulnerability found between: \");\n System.out.println(\"Source: \" + source.getStmt());\n System.out.println(\"Destination: \" + destination.getStmt());\n }\n }\n }\n\n private static boolean isPotentiallyVulnerable(StmtGraphNode source, StmtGraphNode destination) {\n // Implement your vulnerability detection logic here\n return source.getStmt().toString().contains(\"userInput\") && \n destination.getStmt() instanceof JInvokeStmt && \n destination.getStmt().toString().contains(\"println\");\n }\n}\n
In this example, we check for data flow dependencies between the userInput
variable and any println
calls, which could indicate a potential injection vulnerability.
Similarly, we can define our own queries to detect specific patterns that identify common vulnerabilities.
"},{"location":"docguide/","title":"Docguide","text":""},{"location":"docguide/#general","title":"General","text":""},{"location":"docguide/#mkdocsextensions","title":"MkDocsExtensions","text":""},{"location":"docguide/#tooltip","title":"Tooltip","text":"Hover me
"},{"location":"docguide/#example-file-inclusion","title":"Example File inclusion","text":"this enables that tutorial code can be tested and will fail if its not up to date anymore :)
package sootup.examples.basicSetup;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Collections;\nimport org.junit.jupiter.api.Tag;\nimport org.junit.jupiter.api.Test;\nimport sootup.core.inputlocation.AnalysisInputLocation;\nimport sootup.core.jimple.common.expr.JVirtualInvokeExpr;\nimport sootup.core.jimple.common.stmt.JInvokeStmt;\nimport sootup.core.model.SootClass;\nimport sootup.core.model.SootMethod;\nimport sootup.core.model.SourceType;\nimport sootup.core.signatures.MethodSignature;\nimport sootup.core.types.ClassType;\nimport sootup.core.views.View;\nimport sootup.java.bytecode.frontend.inputlocation.PathBasedAnalysisInputLocation;\nimport sootup.java.core.language.JavaJimple;\nimport sootup.java.core.views.JavaView;\n\n/** This example illustrates how to create and use a new Soot Project. */\n@Tag(\"Java8\")\npublic class BasicSetupTest {\n\n @Test\n public void createByteCodeProject() {\n // Create a AnalysisInputLocation, which points to a directory. All class files will be loaded\n // from the directory\n Path pathToBinary = Paths.get(\"src/test/resources/BasicSetup/binary\");\n AnalysisInputLocation inputLocation =\n PathBasedAnalysisInputLocation.create(pathToBinary, SourceType.Application);\n\n // Create a view for project, which allows us to retrieve classes\n View view = new JavaView(inputLocation);\n\n // Create a signature for the class we want to analyze\n ClassType classType = view.getIdentifierFactory().getClassType(\"HelloWorld\");\n\n // Create a signature for the method we want to analyze\n MethodSignature methodSignature =\n view.getIdentifierFactory()\n .getMethodSignature(\n classType, \"main\", \"void\", Collections.singletonList(\"java.lang.String[]\"));\n\n // Assert that class is present\n assertTrue(view.getClass(classType).isPresent());\n\n // Retrieve class\n SootClass sootClass = view.getClass(classType).get();\n\n // Retrieve method\n view.getMethod(methodSignature);\n\n // Alternatively:\n assertTrue(sootClass.getMethod(methodSignature.getSubSignature()).isPresent());\n SootMethod sootMethod = sootClass.getMethod(methodSignature.getSubSignature()).get();\n\n // Read jimple code of method\n System.out.println(sootMethod.getBody());\n\n // Assert that Hello world print is present\n assertTrue(\n sootMethod.getBody().getStmts().stream()\n .anyMatch(\n stmt ->\n stmt instanceof JInvokeStmt\n && ((JInvokeStmt) stmt).getInvokeExpr().get() instanceof JVirtualInvokeExpr\n && ((JInvokeStmt) stmt)\n .getInvokeExpr()\n .get()\n .getArg(0)\n .equivTo(JavaJimple.getInstance().newStringConstant(\"Hello World!\"))));\n }\n}\n
"},{"location":"examples/","title":"SootUp Example projects","text":"Some examples that use SootUp to get insights about a Java program.
Download
The Examples can be cloned or downloaded from our Example Repository.
"},{"location":"faq/","title":"Frequently Asked Questions","text":""},{"location":"faq/#how-to-setup-the-soot-dependency-in-maven-gradle","title":"How to setup the soot dependency (in Maven, Gradle)?","text":"See Installation.
"},{"location":"faq/#how-to-retreive-a-sootclass-or-sootmethod","title":"How to retreive a SootClass or SootMethod?","text":"See Getting Started.
"},{"location":"faq/#is-there-a-github-template-to-quickstart-into-development-with-sootup","title":"Is there a github template to quickstart into development with SootUp?","text":"Not yet.
"},{"location":"faq/#error-while-using-the-sourcecodefrontend","title":"Error while using the Sourcecodefrontend","text":"Please make sure to use Java8 to execute.
"},{"location":"faq/#exception-provider-jrt-not-found","title":"Exception: Provider \"jrt\" not found","text":"java.lang.ExceptionInInitializerError\n at inputlocation.sootup.java.bytecode.frontend.JrtFileSystemAnalysisInputLocationTest.getClassSource(JrtFileSystemAnalysisInputLocationTest.java:28)\n ...\nCaused by: java.nio.file.ProviderNotFoundException: Provider \"jrt\" not found\n
To execute SootUp with JavaModules support please make sure you run the code at least the Java9 Runtime."},{"location":"faq/#how-to-solve-a-concurrentmodificationexception","title":"How to solve a ConcurrentModificationException?","text":"Copy the Iterator into an intermediate Collection.
final StmtGraph<?> stmtGraph = builder.getStmtGraph();\n for (Stmt stmt : Lists.newArrayList(stmtGraph)){\n ...\n }\n}\n
"},{"location":"faq/#how-can-i-visualize-a-stmtgraph","title":"How can I visualize a StmtGraph?","text":"There exists a tool, that converts a StmtGraph to the Graphviz Dot Language.
DotExporter.buildGraph( stmtgraph );\n
or create a convenient link with the exported stmtgraph as HTTP GET Parameter DotExporter.createUrlToWebeditor( stmtgraph );\n
"},{"location":"faq/#the-sourcecodefrontend","title":"The Sourcecodefrontend...","text":"is in a experimental state! If you wish to use it, please consider to contribute.
"},{"location":"faq/#is-there-a-way-to-use-code-exploration-and-syntax-highlighting-features-in-my-ide-for-jimple-files","title":"Is there a way to use code exploration and syntax highlighting features in my IDE for .jimple files?","text":"Try JimpeLsp or the vscode plugin
"},{"location":"faq/#is-there-a-way-to-use-syntax-highlighting-of-jimple-in-my-paper-thesis","title":"Is there a way to use syntax highlighting of .jimple in my paper, thesis, ...?","text":"Have a look at LspLexer4Pygments. Its the same syntax highlighting you see here in the documentation. You can export it to LaTex as well.
"},{"location":"faq/#how-to-add-an-entry-in-this-list-ie-your-question-is-not-answered-here","title":"How to ... add an entry in this list? i.e. Your question is not answered here?","text":"Feel free to start a Discussion.
"},{"location":"getting-started/","title":"First Steps with SootUp","text":"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.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
AnalysisInputLocation inputLocation = \n new JavaClassPathAnalysisInputLocation(\"path2Binary\");\n\nJavaView view = new JavaView(inputLocation);\n
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).
AnalysisInputLocation inputLocation = \n new JavaSourcePathAnalysisInputLocation(\"path2Source\");\n\nJavaView view = new JavaView(inputLocation);\n
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
Path pathToJimple = Paths.get(\"path2Jimple\");\n\nAnalysisInputLocation inputLocation = \n new JimpleAnalysisInputLocation(pathToJimple);\n\nJimpleView view = new JimpleView(inputLocation);\n
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:
JavaView view = new JavaView(inputLocations, new LRUCacheProvider(50));\n
"},{"location":"getting-started/#retrieving-a-class","title":"Retrieving a Class","text":"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
package example;\n\npublic class HelloWorld {\n\n public HelloWorld() {\n\n }\n\n public static void main(String[] args) {\n HelloWorld hw = new HelloWorld();\n hw.hello();\n }\n\n public void hello() {\n\n }\n\n}\n
Then, we could define the ClassType
of the HelloWorld
class as follows:
Defining a ClassType
JavaClassType classType = \n view.getIdentifierFactory().getClassType(\"example.HelloWorld\");\n
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
JavaSootClass sootClass = view.getClass(classType).get();\n
"},{"location":"getting-started/#retrieving-a-method","title":"Retrieving a Method","text":"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
PureParse from StringMethodSignature methodSignature =\n view\n .getIdentifierFactory()\n .getMethodSignature(\n \"main\", // method name\n classType,\n \"void\", // return type\n Collections.singletonList(\"java.lang.String[]\")); // args\n
MethodSignature methodSignature =\n view\n .getIdentifierFactory()\n .parseMethodSignature(\n \"<packageName.classType: void main(java.lang.String[])>\");\n
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
Optional<SootMethod> opt = view.getMethod(methodSignature);\n\nif(!opt.isPresent()){\n return;\n}\nSootMethod method = opt.get();\nSystem.out.println(method.getModifiers());\n
Alternatively, we can also retrieve a SootMethod
from SootClass
that contains it.
Retrieving a SootMethod from a SootClass
MethodSubSignature mss = methodSignature.getSubSignature()\nOptional<JavaSootMethod> opt = sootClass.getMethod(mss);\n\nif(opt.isPresent()){\n JavaSootMethod method = opt.get();\n}\n
"},{"location":"getting-started/#retrieving-the-control-flow-graph-of-a-method","title":"Retrieving the Control-Flow Graph of a Method","text":"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
StmtGraph<?> graph = sootMethod.getBody().getStmtGraph();\n
"},{"location":"getting-started/#using-the-stmtgraph","title":"Using the StmtGraph","text":"StmtGraph StmtsStmtGraph BlocksStmtGraph DotExport for( Stmt stmt : graph.nodes()){\n // pseudo topological order as Stmts would be serialized to a Jimple file.\n}\n\nfor( Stmt stmt : graph.nodes()){\n // Stmts are unordered!\n}\n
List<BasicBlock<?>> blocks = graph.getBlocks();\nfor( BasicBlock<?> block : blocks){\n // e.g. check if its a merge point\n if(block.getPredecessors().size() > 1){\n ...\n }\n\n // e.g. check if its a branching point\n if(block.getSuccessors().size() > 1){\n // or use block.getTail() instanceof BranchingStmt\n ...\n }\n\n // e.g. check if thrown exceptions would be caught in this method\n if(!block.getExceptionalSuccessors().isEmpty()){\n ...\n }\n}\n
String urlToWebeditor = DotExporter.createUrlToWebeditor(this);\nSystem.out.println(urlToWebeditor);\n
Access a complete example of the code used above
Download BasicSetup.java
"},{"location":"installation/","title":"Installation","text":""},{"location":"installation/#use-the-latest-develop-branch","title":"Use the latest develop branch","text":"For configuration options of your build tool please visit SootUp on Jitpack.io
"},{"location":"installation/#use-releases-on-maven-central","title":"Use Releases on Maven Central","text":"The code below shows you how to import all submodules of the SootUp repository. You can import fewer modules if your use case allows it.
Add the following dependencies to your pom.xml
/ build.gradle
.
<dependencies>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.core</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.java.core</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.java.sourcecode.frontend</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.java.bytecode.frontend</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.jimple.frontend</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.apk.frontend</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.callgraph</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.analysis.intraprocedural</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.analysis.interprocedural</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.qilin</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.codepropertygraph</artifactId>\n <version>1.3.0</version>\n </dependency>\n</dependencies>\n
repositories {\n mavenCentral()\n google()\n}\n\ncompile \"org.soot-oss:sootup.core:1.3.0\"\ncompile \"org.soot-oss:sootup.java.core:1.3.0\"\ncompile \"org.soot-oss:sootup.java.sourcecode.frontend:1.3.0\"\ncompile \"org.soot-oss:sootup.java.bytecode.frontend:1.3.0\"\ncompile \"org.soot-oss:sootup.jimple.frontend:1.3.0\"\ncompile \"org.soot-oss:sootup.apk.frontend:1.3.0\"\ncompile \"org.soot-oss:sootup.callgraph:1.3.0\"\ncompile \"org.soot-oss:sootup.analysis.intraprocedural:1.3.0\"\ncompile \"org.soot-oss:sootup.analysis.interprocedural:1.3.0\"\ncompile \"org.soot-oss:sootup.qilin:1.3.0\"\ncompile \"org.soot-oss:sootup.codepropertygraph:1.3.0\"\n
"},{"location":"installation/#build-from-source","title":"Build from Source","text":"If you'd like to get the most recent changes, you can build SootUp from source yourself and install it into your local maven repository.
git clone https://github.com/secure-software-engineering/SootUp.git\nmvn install\n
"},{"location":"jimple-body/","title":"Jimple Body","text":"A SootMethod Body
consists of the Modifiers
and its StmtGraph
- SootUps Control Flow Graph Structure. The StmtGraph models the flow of Stmts.
Learn more about the types of Stmts.
"},{"location":"jimple-body/#traps","title":"Traps","text":"A Trap is a mechanism to model exceptional flow. A Trap represents the try-catch (finally) construct and therefore defines the type of the caught exception, the try-catch range (from-to) and the actual code that handles the exception (handler). In serialized(!) Jimple Labels are used to denote from,to and handler Stmts.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void divideExample(int, int)\n {\n int x, y, $stack4;\n java.io.PrintStream $stack5, $stack7;\n java.lang.Exception $stack6;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n y := @parameter1: int;\n\n label1:\n $stack5 = <java.lang.System: java.io.PrintStream out>;\n $stack4 = x / y;\n virtualinvoke $stack5.<java.io.PrintStream: void println(int)>($stack4);\n\n label2:\n goto label4;\n\n label3:\n $stack6 := @caughtexception;\n $stack7 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack7.<java.io.PrintStream: \n void println(java.lang.String)>(\"Exception caught\");\n\n label4:\n return;\n\n catch java.lang.Exception from label1 to label2 with label3;\n }\n}\n/*\n By calling getTraps() method, we can get the Traip chain.\n For the above jimple code, we have the below trap:\n Trap :\n begin : $stack5 = <java.lang.System: java.io.PrintStream out>\n end : goto [?= return]\n handler: $stack6 := @caughtexception\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void divideExample(int x, int y){\n try {\n System.out.println(x / y);\n }catch (Exception e){\n System.out.println(\"Exception caught\");\n }\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic divideExample(II)V\n TRYCATCHBLOCK L0 L1 L2 java/lang/Exception\n L0\n LINENUMBER 6 L0\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 1\n ILOAD 2\n IDIV\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L1\n LINENUMBER 9 L1\n GOTO L3\n L2\n LINENUMBER 7 L2\n FRAME SAME1 java/lang/Exception\n ASTORE 3\n L4\n LINENUMBER 8 L4\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Exception caught\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L3\n LINENUMBER 10 L3\n FRAME SAME\n RETURN\n L5\n LOCALVARIABLE e Ljava/lang/Exception; L4 L3 3\n LOCALVARIABLE this Land Ttarget/exercise1/DemoClass; L0 L5 0\n LOCALVARIABLE x I L0 L5 1\n LOCALVARIABLE y I L0 L5 2\n MAXSTACK = 3\n MAXLOCALS = 4\n}\n
"},{"location":"jimple-stmts/","title":"Jimple Stmt (\"Statement\")","text":"Stmts represent instructions of the JVM. Jimple is a 3-address form code so there are max 3 operands used in a (\"manipulating\") Stmt - i.e. this does not apply to invokes as this is just operand/parameter passing.
Stmts can be roughly grouped by the amount of successors (in the StmtGraph
of a Body
of a Method
).
FallsThroughStmt
has always one successor - it basically represents program counter++
.BranchingStmt
can have one, two or even n successors.A BranchingStmt's job is to model the jumps or conditional branching flow between Stmts.
"},{"location":"jimple-stmts/#jgotostmt","title":"JGotoStmt","text":"represents unconditional jumps to another Stmt.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n public static void sampleMethod()\n {\n int i;\n i = 0;\n\n label1:\n if i >= 5 goto label3;\n if i != 3 goto label2;\n goto label3;\n\n label2:\n i = i + 1;\n goto label1;\n\n label3:\n return;\n }\n}\n/*\n Here for statements \"goto label3;\" and \"goto label1;\", \n we have two instances of JGotoStmt : \n \"goto[?=return]\" and \"goto[?=(branch)]\".\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public static void sampleMethod(){\n label1:\n for (int i = 0; i < 5; i++){\n if(i == 3){\n break label1;\n }\n }\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x9\npublic static sampleMethod()V\n L0\n LINENUMBER 6 L0\n ICONST_0\n ISTORE 0\n L1\n FRAME APPEND [I]\n ILOAD 0\n ICONST_5\n IF_ICMPGE L2\n L3\n LINENUMBER 7 L3\n ILOAD 0\n ICONST_3\n IF_ICMPNE L4\n L5\n LINENUMBER 8 L5\n GOTO L2\n L4\n LINENUMBER 6 L4\n FRAME SAME\n IINC 0 1\n GOTO L1\n L2\n LINENUMBER 11 L2\n FRAME CHOP 1\n RETURN\n LOCALVARIABLE i I L1 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
"},{"location":"jimple-stmts/#jifstmt","title":"JIfStmt","text":"For conditional jumps depending on the result of the conditional expression AbstractConditionExpr
which needs to have boolean result. If the conditional expression is false, the next Stmt is the successor as the JIFStmt is also a FallsthroughStmt
. Therefore, the JIfStmt has two successor Stmt's.
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public static void sampleMethod(int)\n {\n int x, $stack1;\n java.io.PrintStream $stack2, $stack3;\n\n x := @parameter0: int;\n\n $stack1 = x % 2;\n if $stack1 != 0 goto label1;\n\n $stack3 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack3.<java.io.PrintStream: \n void println(java.lang.String)>(\"Even\");\n goto label2;\n\n label1:\n $stack2 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack2.<java.io.PrintStream: \n void println(java.lang.String)>(\"Odd\");\n\n label2:\n return;\n }\n}\n/*\n For statement \"if $stack1 != 0 goto label1;\", \n we have an instance of JIfStmt :\n \"if $stack1 != 0 goto $stack2 \n = <java.lang.System:java.io.PrintStream out>\".\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public static void sampleMethod(int x){\n if(x % 2 == 0){\n System.out.println(\"Even\");\n }else{\n System.out.println(\"Odd\");\n }\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x9\npublic static sampleMethod(I)V\n L0\n LINENUMBER 5 L0\n ILOAD 0\n ICONST_2\n IREM\n IFNE L1\n L2\n LINENUMBER 6 L2\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Even\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n GOTO L3\n L1\n LINENUMBER 8 L1\n FRAME SAME\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Odd\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L3\n LINENUMBER 10 L3\n FRAME SAME\n RETURN\n L4\n LOCALVARIABLE x I L0 L4 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
"},{"location":"jimple-stmts/#jswitchstmt","title":"JSwitchStmt","text":"for conditional flow that behaves like a switch-case. It has #numberOfCaseLabels+1 (for default) successor Stmt's.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void switchExample(int)\n {\n int x;\n java.io.PrintStream $stack2, $stack3, $stack4;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n\n lookupswitch(x)\n {\n case 1: goto label1;\n case 2: goto label2;\n default: goto label3;\n };\n\n label1:\n $stack3 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack3.<java.io.PrintStream: \n void println(java.lang.String)>(\"Input 1\");\n goto label4;\n\n label2:\n $stack2 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack2.<java.io.PrintStream: \n void println(java.lang.String)>(\"Input 2\");\n goto label4;\n\n label3:\n $stack4 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack4.<java.io.PrintStream: \n void println(java.lang.String)>(\"Input more than 2\");\n\n label4:\n return;\n }\n}\n/*\n Here for below statement:\n lookupswitch(x)\n {\n case 1: goto label1;\n case 2: goto label2;\n default: goto label3;\n };\n\n we have an instance of JLookupSwitchStmt :\n lookupswitch(x) \n { \n case 1: goto $stack3 \n = <java.lang.System: java.io.PrintStream out>; \n case 2: goto $stack2 \n = <java.lang.System: java.io.PrintStream out>; \n default: goto $stack4 \n = <java.lang.System: java.io.PrintStream out>; \n }\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void switchExample(int x){\n switch (x){\n case 1:\n System.out.println(\"Input 1\");\n break;\n\n case 2:\n System.out.println(\"Input 2\");\n break;\n\n default:\n System.out.println(\"Input more than 2\");\n break;\n\n }\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic switchExample(I)V\n L0\n LINENUMBER 5 L0\n ILOAD 1\n LOOKUPSWITCH\n 1: L1\n 2: L2\n default: L3\n L1\n LINENUMBER 7 L1\n FRAME SAME\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Input 1\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L4\n LINENUMBER 8 L4\n GOTO L5\n L2\n LINENUMBER 11 L2\n FRAME SAME\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Input 2\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L6\n LINENUMBER 12 L6\n GOTO L5\n L3\n LINENUMBER 15 L3\n FRAME SAME\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Input more than 2\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L5\n LINENUMBER 19 L5\n FRAME SAME\n RETURN\n L7\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L7 0\n LOCALVARIABLE x I L0 L7 1\n MAXSTACK = 2\n MAXLOCALS = 2\n}\n
"},{"location":"jimple-stmts/#fallsthrough-stmts","title":"FallsThrough Stmts","text":"The execution of a FallsthroughStmt goes on with the following Stmt (if no exception was thrown).
"},{"location":"jimple-stmts/#jinvokestmt","title":"JInvokeStmt","text":"transfers the control flow to another method until the called method returns.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void print(int)\n {\n target.exercise1.DemoClass this;\n int x, a;\n java.io.PrintStream $stack4, $stack6;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n\n a = virtualinvoke this.<target.exercise1.DemoClass: int increment(int)>(x);\n $stack4 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack4.<java.io.PrintStream: void println(int)>(a);\n\n a = virtualinvoke this.<target.exercise1.DemoClass: int increment(int)>(a);\n $stack6 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack6.<java.io.PrintStream: void println(int)>(a);\n\n return;\n }\n\n public int increment(int)\n {\n int x, $stack2;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n\n $stack2 = x + 1;\n return $stack2;\n }\n}\n/*\n \"specialinvoke this.<java.lang.Object: void <init>()>()\", \n \"virtualinvoke this.<target.exercise1.DemoClass: int increment(int)>(x)\", \n \"virtualinvoke this.<target.exercise1.DemoClass: int increment(int)>(a)\" \n are JInvokeStmts.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void print(int x){\n int a = increment(x);\n System.out.println(a);\n a = increment(a);\n System.out.println(a);\n }\n public int increment(int x){\n return x + 1;\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic print(I)V\n L0\n LINENUMBER 5 L0\n ALOAD 0\n ILOAD 1\n INVOKEVIRTUAL target/exercise1/DemoClass.increment (I)I\n ISTORE 2\n L1\n LINENUMBER 6 L1\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 2\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L2\n LINENUMBER 7 L2\n ALOAD 0\n ILOAD 2\n INVOKEVIRTUAL target/exercise1/DemoClass.increment (I)I\n ISTORE 2\n L3\n LINENUMBER 8 L3\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 2\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L4\n LINENUMBER 9 L4\n RETURN\n L5\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L5 0\n LOCALVARIABLE x I L0 L5 1\n LOCALVARIABLE a I L1 L5 2\n MAXSTACK = 2\n MAXLOCALS = 3\n\n// access flags 0x1\npublic increment(I)I\n L0\n LINENUMBER 11 L0\n ILOAD 1\n ICONST_1\n IADD\n IRETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n LOCALVARIABLE x I L0 L1 1\n MAXSTACK = 2\n MAXLOCALS = 2\n}\n
"},{"location":"jimple-stmts/#jassignstmt","title":"JAssignStmt","text":"assigns a Value from the right hand-side to the left hand-side. Left hand-side of an assignment can be a Local referencing a variable (i.e. a Local) or a FieldRef referencing a Field. Right hand-side of an assignment can be an expression (Expr), a Local, a FieldRef or a Constant.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n this.<target.exercise1.DemoClass: int counter> = 0;\n return;\n }\n\n public int updateCounter()\n {\n target.exercise1.DemoClass this;\n int $stack1, $stack2, $stack3;\n\n this := @this: target.exercise1.DemoClass;\n\n $stack1 = this.<target.exercise1.DemoClass: int counter>;\n $stack2 = $stack1 + 1;\n this.<target.exercise1.DemoClass: int counter> = $stack2;\n $stack3 = this.<target.exercise1.DemoClass: int counter>;\n\n return $stack3;\n }\n}\n/*\n \"this.<target.exercise1.DemoClass: int counter> = 0\", \n \"$stack1 = this.<target.exercise1.DemoClass: int counter>\",\n \"$stack2 = $stack1 + 1\"\n \"this.<target.exercise1.DemoClass: int counter> = $stack2\"\n \"$stack3 = this.<target.exercise1.DemoClass: int counter>\"\n are JAssignStmts.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n private int counter = 0;\n public int updateCounter(){\n counter = counter + 1;\n return counter;\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x2\nprivate I counter\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 4 L1\n ALOAD 0\n ICONST_0\n PUTFIELD target/exercise1/DemoClass.counter : I\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n\n// access flags 0x1\npublic updateCounter()I\n L0\n LINENUMBER 6 L0\n ALOAD 0\n ALOAD 0\n GETFIELD target/exercise1/DemoClass.counter : I\n ICONST_1\n IADD\n PUTFIELD target/exercise1/DemoClass.counter : I\n L1\n LINENUMBER 7 L1\n ALOAD 0\n GETFIELD target/exercise1/DemoClass.counter : I\n IRETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 3\n MAXLOCALS = 1\n}\n
"},{"location":"jimple-stmts/#jidentitystmt","title":"JIdentityStmt","text":"is similar to the JAssignStmt
and but handles assignments of IdentityRef
s to make implicit assignments explicit into the StmtGraph
.
Local
via JParameterRef
like @parameter0: int
refering to the first argument of the method (which is of Type int in this case).Local
via JCaughtExceptionRef
like @caughtexception: java.lang.NullpointerException
this
Variable to a Local
via a JThisRef
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void DemoClass(int)\n {\n target.exercise1.DemoClass this;\n int counter;\n\n this := @this: target.exercise1.DemoClass;\n counter := @parameter0: int;\n this.<target.exercise1.DemoClass: int counter> = counter;\n return;\n }\n}\n/*\n \"this := @this: target.exercise1.DemoClass\" and \n \"counter := @parameter0: int\" are JIdentityStmts\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n private int counter;\n public void DemoClass(int counter){\n this.counter = counter;\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x2\nprivate I counter\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic DemoClass(I)V\n L0\n LINENUMBER 6 L0\n ALOAD 0\n ILOAD 1\n PUTFIELD target/exercise1/DemoClass.counter : I\n L1\n LINENUMBER 7 L1\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n LOCALVARIABLE counter I L0 L2 1\n MAXSTACK = 2\n MAXLOCALS = 2\n}\n
"},{"location":"jimple-stmts/#jentermonitorstmt-jexitmonitorstmt","title":"JEnterMonitorStmt & JExitMonitorStmt","text":"marks synchronized blocks of code from JEnterMonitorStmt to JExitMonitorStmt.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n this.<target.exercise1.DemoClass: int counter> = 0;\n return;\n }\n\n public int updateCounter()\n {\n target.exercise1.DemoClass this;\n int $stack4, $stack5, $stack7;\n java.lang.Throwable $stack8;\n\n this := @this: target.exercise1.DemoClass;\n\n entermonitor this;\n\n label1:\n $stack4 = this.<target.exercise1.DemoClass: int counter>;\n $stack5 = $stack4 + 1;\n this.<target.exercise1.DemoClass: int counter> = $stack5;\n\n exitmonitor this;\n\n label2:\n goto label5;\n\n label3:\n $stack8 := @caughtexception;\n\n exitmonitor this;\n\n label4:\n throw $stack8;\n\n label5:\n $stack7 = this.<target.exercise1.DemoClass: int counter>;\n return $stack7;\n\n catch java.lang.Throwable from label1 to label2 with label3;\n catch java.lang.Throwable from label3 to label4 with label3;\n }\n}\n/*\n \"entermonitor this\" is JEnterMonitorStmt.\n \"exitmonitor this\" is JExitMonitorStmt.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n private int counter = 0;\n public int updateCounter(){\n synchronized (this) {\n counter = counter + 1;\n }\n return counter;\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x2\nprivate I counter\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 4 L1\n ALOAD 0\n ICONST_0\n PUTFIELD target/exercise1/DemoClass.counter : I\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n\n// access flags 0x1\npublic updateCounter()I\n TRYCATCHBLOCK L0 L1 L2 null\n TRYCATCHBLOCK L2 L3 L2 null\n L4\n LINENUMBER 6 L4\n ALOAD 0\n DUP\n ASTORE 1\n MONITORENTER\n L0\n LINENUMBER 7 L0\n ALOAD 0\n ALOAD 0\n GETFIELD target/exercise1/DemoClass.counter : I\n ICONST_1\n IADD\n PUTFIELD target/exercise1/DemoClass.counter : I\n L5\n LINENUMBER 8 L5\n ALOAD 1\n MONITOREXIT\n L1\n GOTO L6\n L2\n FRAME FULL [target/exercise1/DemoClass java/lang/Object] \n [java/lang/Throwable]\n ASTORE 2\n ALOAD 1\n MONITOREXIT\n L3\n ALOAD 2\n ATHROW\n L6\n LINENUMBER 9 L6\n FRAME CHOP 1\n ALOAD 0\n GETFIELD target/exercise1/DemoClass.counter : I\n IRETURN\n L7\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L4 L7 0\n MAXSTACK = 3\n MAXLOCALS = 3\n}\n
"},{"location":"jimple-stmts/#jretstmt","title":"JRetStmt","text":"// TODO: java 1.6 spec
"},{"location":"jimple-stmts/#jbreakpointstmt","title":"JBreakpointStmt","text":"models a Breakpoint set by a Debugger. Therefore, not really relevant for static analyses but useful for code generation.
"},{"location":"jimple-stmts/#other-stmts","title":"Other Stmts","text":""},{"location":"jimple-stmts/#jreturnstmt-jreturnvoidstmt","title":"JReturnStmt & JReturnVoidStmt","text":"They end the execution/flow inside the current method and return (a value) to its caller.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public int increment(int)\n {\n int x, $stack2;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n\n $stack2 = x + 1;\n return $stack2;\n }\n\n public void print()\n {\n java.io.PrintStream $stack1;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n $stack1 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack1.<java.io.PrintStream: \n void println(java.lang.String)>(\"Inside method print\");\n return;\n }\n}\n/*\n \"return $stack2\" is JReturnStmt.\n \"return\" is JReturnVoidStmt.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public int increment(int x){\n return x + 1;\n }\n public void print(){\n System.out.println(\"Inside method print\");\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic increment(I)I\n L0\n LINENUMBER 5 L0\n ILOAD 1\n ICONST_1\n IADD\n IRETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n LOCALVARIABLE x I L0 L1 1\n MAXSTACK = 2\n MAXLOCALS = 2\n\n// access flags 0x1\npublic print()V\n L0\n LINENUMBER 8 L0\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Inside method print\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L1\n LINENUMBER 9 L1\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
"},{"location":"jimple-stmts/#jthrowstmt","title":"JThrowStmt","text":"Ends the execution inside the current Method if the thrown exception is not caught by a Trap, which redirects the execution to an exceptionhandler.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void divideExample(int, int)\n {\n int y, x, $stack6;\n java.lang.StringBuilder $stack3, $stack5, $stack7;\n java.io.PrintStream $stack4;\n java.lang.String $stack8;\n java.lang.RuntimeException $stack9;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n y := @parameter1: int;\n\n if y != 0 goto label1;\n\n $stack9 = new java.lang.RuntimeException;\n specialinvoke $stack9.<java.lang.RuntimeException: \n void <init>(java.lang.String)>(\"Divide by zero error\");\n throw $stack9;\n\n label1:\n $stack4 = <java.lang.System: java.io.PrintStream out>;\n $stack3 = new java.lang.StringBuilder;\n specialinvoke $stack3.<java.lang.StringBuilder: void <init>()>();\n\n $stack5 = virtualinvoke $stack3.<java.lang.StringBuilder: \n java.lang.StringBuilder append(java.lang.String)>(\"Divide result : \");\n $stack6 = x / y;\n $stack7 = virtualinvoke $stack5.<java.lang.StringBuilder: \n java.lang.StringBuilder append(int)>($stack6);\n $stack8 = virtualinvoke $stack7.<java.lang.StringBuilder: \n java.lang.String toString()>();\n\n virtualinvoke $stack4.<java.io.PrintStream: \n void println(java.lang.String)>($stack8);\n return;\n }\n}\n/*\n \"throw $stack9\" is JThrowStmt.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void divideExample(int x, int y){\n if(y == 0){\n throw new RuntimeException(\"Divide by zero error\");\n }\n System.out.println(\"Divide result : \" + x / y);\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic divideExample(II)V\n L0\n LINENUMBER 5 L0\n ILOAD 2\n IFNE L1\n L2\n LINENUMBER 6 L2\n NEW java/lang/RuntimeException\n DUP\n LDC \"Divide by zero error\"\n INVOKESPECIAL java/lang/RuntimeException.<init> \n (Ljava/lang/String;)V\n ATHROW\n L1\n LINENUMBER 8 L1\n FRAME SAME\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n NEW java/lang/StringBuilder\n DUP\n INVOKESPECIAL java/lang/StringBuilder.<init> ()V\n LDC \"Divide result : \"\n INVOKEVIRTUAL java/lang/StringBuilder.append \n (Ljava/lang/String;)Ljava/lang/StringBuilder;\n ILOAD 1\n ILOAD 2\n IDIV\n INVOKEVIRTUAL java/lang/StringBuilder.append \n (I)Ljava/lang/StringBuilder;\n INVOKEVIRTUAL java/lang/StringBuilder.toString \n ()Ljava/lang/String;\n INVOKEVIRTUAL java/io/PrintStream.println \n (Ljava/lang/String;)V\n L3\n LINENUMBER 9 L3\n RETURN\n L4\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L4 0\n LOCALVARIABLE x I L0 L4 1\n LOCALVARIABLE y I L0 L4 2\n MAXSTACK = 4\n MAXLOCALS = 3\n}\n
"},{"location":"jimple-stmts/#good-to-know","title":"Good to know","text":"A lot of the SootUp APIs return the Stmt
Interface. To determine and handle its subtypes you can make use of instanceof.
List<Stmt> stmts = ... ;\n for( Stmt stms : stmts ){\n if(stmt instanceof JAssignStmt){\n // found a JAssignStmt\n Value rhsOp = ((JAssignStmt) stmt).getRightOp();\n ...\n }else if(stmt instanceof JInvokeStmt){\n // found a JInvokeStmt\n JInvokeStmt ivkStmt = ((JInvokeStmt) stmt);\n MethodSignature rhsOp = ivkStmt.getInvokeExpr().getMethodSignature();\n ...\n }else ...\n }\n
But this could escalate to a huge if-else-tree - almost a forest. To mitigate such scenario you can implement a subclass of AbstractStmtVisitor
. Just subclass the methods to the respective Stmts you need to handle. This is visitor acts like a switch-case, implemented via two dynamic calls.
List<Stmt> stmts = ...;\n AbstractStmtVisitor visitor = new AbstractStmtVisitor<Integer>() {\n private int ifStmtsCounter = 0;\n @Override\n public void caseIfStmt(@Nonnull JIfStmt stmt) {\n ifStmtsCounter++;\n setResult(ifStmtCounter);\n }\n };\n\n for( Stmt stms : stmts ){\n stmt.accept(visitor);\n }\n\n int amountOfIfStmts = visitor.getResult();\n
Sidenote: Of course its possible can create a subclass instead of an anonymous class.
"},{"location":"jimple-types/","title":"Jimple Types","text":"represents primary types i.e. non-reference types and non-void
"},{"location":"jimple-types/#primarytype","title":"PrimaryType","text":"BooleanType
ByteType
CharType
ShortType
IntType
LongType
DoubleType
FloatType
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n\n public void display()\n {\n java.io.PrintStream $stack11, $stack13, $stack15, \n $stack17, $stack19, $stack21, $stack23, $stack25;\n int $stack12, $stack14, $stack16, $stack18;\n long $stack20;\n double $stack22;\n float $stack24;\n target.exercise1.DemoClass this;\n boolean $stack26;\n\n this := @this: target.exercise1.DemoClass;\n\n $stack11 = <java.lang.System: java.io.PrintStream out>;\n\n goto label1;\n\n label1:\n $stack26 = 0;\n virtualinvoke $stack11.<java.io.PrintStream: \n void println(boolean)>($stack26);\n\n $stack13 = <java.lang.System: java.io.PrintStream out>;\n $stack12 = 127 - 1;\n virtualinvoke $stack13.<java.io.PrintStream: \n void println(int)>($stack12);\n\n $stack15 = <java.lang.System: java.io.PrintStream out>;\n $stack14 = 97 + 1;\n virtualinvoke $stack15.<java.io.PrintStream: \n void println(int)>($stack14);\n\n $stack17 = <java.lang.System: java.io.PrintStream out>;\n $stack16 = 1123 + 1;\n virtualinvoke $stack17.<java.io.PrintStream: \n void println(int)>($stack16);\n\n $stack19 = <java.lang.System: java.io.PrintStream out>;\n $stack18 = 123456 + 1;\n virtualinvoke $stack19.<java.io.PrintStream: \n void println(int)>($stack18);\n\n $stack21 = <java.lang.System: java.io.PrintStream out>;\n $stack20 = 10L + 1L;\n virtualinvoke $stack21.<java.io.PrintStream: \n void println(long)>($stack20);\n\n $stack23 = <java.lang.System: java.io.PrintStream out>;\n $stack22 = 10.1 + 1.0;\n virtualinvoke $stack23.<java.io.PrintStream: \n void println(double)>($stack22);\n\n $stack25 = <java.lang.System: java.io.PrintStream out>;\n $stack24 = 10.1F + 1.0F;\n virtualinvoke $stack25.<java.io.PrintStream: \n void println(float)>($stack24);\n\n return;\n }\n}\n/*\n The JimpleLocal $stack12, $stack14, $stack16, $stack18 are of IntType. \n Similarly, $stack20 is of LongType, $stack22 is of DoubleType and so on.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void display(){\n boolean varBoolean = true;\n byte varByte = 127;\n char varChar = 'a';\n short varShort = 1123;\n int varInt = 123456;\n long varLong = 10L;\n double varDouble = 10.10;\n float varFloat = 10.10f;\n\n System.out.println(!varBoolean);\n System.out.println(varByte-1);\n System.out.println(varChar+1);\n System.out.println(varShort+1);\n System.out.println(varInt+1);\n System.out.println(varLong+1);\n System.out.println(varDouble+1);\n System.out.println(varFloat+1);\n\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic display()V\n L0\n LINENUMBER 5 L0\n ICONST_1\n ISTORE 1\n L1\n LINENUMBER 6 L1\n BIPUSH 127\n ISTORE 2\n L2\n LINENUMBER 7 L2\n BIPUSH 97\n ISTORE 3\n L3\n LINENUMBER 8 L3\n SIPUSH 1123\n ISTORE 4\n L4\n LINENUMBER 9 L4\n LDC 123456\n ISTORE 5\n L5\n LINENUMBER 10 L5\n LDC 10\n LSTORE 6\n L6\n LINENUMBER 11 L6\n LDC 10.1\n DSTORE 8\n L7\n LINENUMBER 12 L7\n LDC 10.1\n FSTORE 10\n L8\n LINENUMBER 14 L8\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 1\n IFNE L9\n ICONST_1\n GOTO L10\n L9\n FRAME FULL [target/exercise1/DemoClass I I I I I J D F] \n [java/io/PrintStream]\n ICONST_0\n L10\n FRAME FULL [target/exercise1/DemoClass I I I I I J D F] \n [java/io/PrintStream I]\n INVOKEVIRTUAL java/io/PrintStream.println (Z)V\n L11\n LINENUMBER 15 L11\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 2\n ICONST_1\n ISUB\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L12\n LINENUMBER 16 L12\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 3\n ICONST_1\n IADD\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L13\n LINENUMBER 17 L13\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 4\n ICONST_1\n IADD\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L14\n LINENUMBER 18 L14\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 5\n ICONST_1\n IADD\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L15\n LINENUMBER 19 L15\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LLOAD 6\n LCONST_1\n LADD\n INVOKEVIRTUAL java/io/PrintStream.println (J)V\n L16\n LINENUMBER 20 L16\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n DLOAD 8\n DCONST_1\n DADD\n INVOKEVIRTUAL java/io/PrintStream.println (D)V\n L17\n LINENUMBER 21 L17\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n FLOAD 10\n FCONST_1\n FADD\n INVOKEVIRTUAL java/io/PrintStream.println (F)V\n L18\n LINENUMBER 23 L18\n RETURN\n L19\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L19 0\n LOCALVARIABLE varBoolean Z L1 L19 1\n LOCALVARIABLE varByte B L2 L19 2\n LOCALVARIABLE varChar C L3 L19 3\n LOCALVARIABLE varShort S L4 L19 4\n LOCALVARIABLE varInt I L5 L19 5\n LOCALVARIABLE varLong J L6 L19 6\n LOCALVARIABLE varDouble D L7 L19 8\n LOCALVARIABLE varFloat F L8 L19 10\n MAXSTACK = 5\n MAXLOCALS = 11\n}\n
"},{"location":"jimple-types/#referencetype","title":"ReferenceType","text":"(Java)ClassType
- represents the type of a Class.ArrayType
- represents an array.NullType
- assignable to one of the other ReferenceTypes.public class target.exercise1.DemoClass extends java.lang.Object\n{\npublic void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public target.exercise1.DemoClass getObject(target.exercise1.DemoClass)\n {\n target.exercise1.DemoClass obj, this;\n this := @this: target.exercise1.DemoClass;\n obj := @parameter0: target.exercise1.DemoClass;\n return obj;\n }\n\n public void compute(boolean)\n {\n int[] b;\n java.io.PrintStream $stack5, $stack6;\n boolean check;\n target.exercise1.DemoClass this;\n int i;\n null_type r0;\n java.lang.NullPointerException soot0;\n this := @this: target.exercise1.DemoClass;\n check := @parameter0: boolean;\n b = newarray (int)[5];\n i = 0;\n\n label1:\n if i >= 5 goto label3;\n if check == 0 goto label2;\n r0 = (null_type) i;\n soot0 = new java.lang.NullPointerException;\n specialinvoke soot0.<java.lang.NullPointerException: \n void <init>(java.lang.String)>\n (\"This statement would have triggered an Exception: a[i#1] = r0\");\n throw soot0;\n\n label2:\n b[i] = i;\n i = i + 1;\n goto label1;\n\n label3:\n $stack5 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack5.<java.io.PrintStream: \n void println(java.lang.Object)>(b);\n $stack6 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack6.<java.io.PrintStream: \n void println(java.lang.Object)>(null);\n return;\n }\n}\n/*\n The Local b is of ArrayType,\n and Local r0 is of NullType.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n\n public DemoClass getObject(DemoClass obj){\n return obj;\n }\n\n public void compute(boolean check){\n int a[] = null;\n int b[] = new int[5];\n for (int i = 0; i < 5; i++) {\n if(check){\n a[i] = i;\n }\n b[i] = i;\n }\n System.out.println(b);\n System.out.println(a);\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic getObject(Ltarget/exercise1/DemoClass;)Ltarget/exercise1/DemoClass;\n L0\n LINENUMBER 6 L0\n ALOAD 1\n ARETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n LOCALVARIABLE obj Ltarget/exercise1/DemoClass; L0 L1 1\n MAXSTACK = 1\n MAXLOCALS = 2\n\n// access flags 0x1\npublic compute(Z)V\n L0\n LINENUMBER 10 L0\n ACONST_NULL\n ASTORE 2\n L1\n LINENUMBER 11 L1\n ICONST_5\n NEWARRAY T_INT\n ASTORE 3\n L2\n LINENUMBER 12 L2\n ICONST_0\n ISTORE 4\n L3\n FRAME APPEND [[I [I I]\n ILOAD 4\n ICONST_5\n IF_ICMPGE L4\n L5\n LINENUMBER 13 L5\n ILOAD 1\n IFEQ L6\n L7\n LINENUMBER 14 L7\n ALOAD 2\n ILOAD 4\n ILOAD 4\n IASTORE\n L6\n LINENUMBER 16 L6\n FRAME SAME\n ALOAD 3\n ILOAD 4\n ILOAD 4\n IASTORE\n L8\n LINENUMBER 12 L8\n IINC 4 1\n GOTO L3\n L4\n LINENUMBER 18 L4\n FRAME CHOP 1\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ALOAD 3\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V\n L9\n LINENUMBER 19 L9\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ALOAD 2\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V\n L10\n LINENUMBER 20 L10\n RETURN\n L11\n LOCALVARIABLE i I L3 L4 4\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L11 0\n LOCALVARIABLE check Z L0 L11 1\n LOCALVARIABLE a [I L1 L11 2\n LOCALVARIABLE b [I L2 L11 3\n MAXSTACK = 3\n MAXLOCALS = 5\n}\n
"},{"location":"jimple-types/#voidtype","title":"VoidType","text":"Used as a possible return type of a method.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void voidMethod()\n {\n java.io.PrintStream $stack1;\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n $stack1 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack1.<java.io.PrintStream: \n void println(java.lang.String)>(\"In voidMethod().\");\n return;\n }\n}\n/*\n For the SootMethod - <target.exercise1.DemoClass: void voidMethod()>, \n returnType is instance of VoidType.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void voidMethod(){\n System.out.println(\"In voidMethod().\");\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic voidMethod()V\n L0\n LINENUMBER 5 L0\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"In voidMethod().\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L1\n LINENUMBER 6 L1\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
"},{"location":"jimple-values/","title":"Jimple Values","text":""},{"location":"jimple-values/#immediate","title":"Immediate","text":"An Immediate
has a given Type and consists of a Local (\"a Variable\", \"Something that contains a Value\") or a Constant (\"Something that is a Value\").
i0 \n
A Local is a variable and its scope is inside its method i.e. no referencing from outside a method. Values can be assigned to Locals via JIdentityStmt or JAssignStmt.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void compute()\n {\n java.io.PrintStream $stack2, $stack3;\n target.exercise1.DemoClass this;\n int local2;\n\n this := @this: target.exercise1.DemoClass;\n $stack2 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack2.<java.io.PrintStream: void println(int)>(1);\n\n local2 = this.<target.exercise1.DemoClass: int global>;\n $stack3 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack3.<java.io.PrintStream: void println(int)>(local2);\n return;\n }\n}\n/*\n $stack2, this, $stack3, local2 are all Locals.\n\n \"this := @this: target.exercise1.DemoClass\" is a JIdentityStmt assigning to a Local.\n\n \"$stack2 = <java.lang.System: java.io.PrintStream out>\", \n \"local2 = this.<target.exercise1.DemoClass: int global>\", \n \"$stack3 = <java.lang.System: java.io.PrintStream out>\" \n are JAssignStmts assigning to a Local.\n\n*/ \n
package target.exercise1;\n\npublic class DemoClass {\n\n private int global;\n\n public void compute(){\n int local;\n local = 1;\n System.out.println(local);\n local = this.global;\n System.out.println(local);\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x2\nprivate I global\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic compute()V\n L0\n LINENUMBER 9 L0\n ICONST_1\n ISTORE 1\n L1\n LINENUMBER 10 L1\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 1\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L2\n LINENUMBER 11 L2\n ALOAD 0\n GETFIELD target/exercise1/DemoClass.global : I\n ISTORE 1\n L3\n LINENUMBER 12 L3\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 1\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L4\n LINENUMBER 14 L4\n RETURN\n L5\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L5 0\n LOCALVARIABLE local I L1 L5 1\n MAXSTACK = 2\n MAXLOCALS = 2\n}\n
"},{"location":"jimple-values/#constant","title":"Constant","text":"represents an actual value itself like 42
or \"This is a String\"
. Constants are usually assigned to Local
s or Ref
s. There exists a constant entity for every Primitive Type.
An expression is a language construct that calculates an operation and returns a value. E.g. a binary operation AbstracBinopExpr
such as an addition a + b
, an AbstractInvokeExpr
such as virtualinvoke $stack2.<java.io.PrintStream: void println(int)>(1);
or an UnaryExpr
such as !valid
. And a bunch more!
$arr[1] = 42;\n$anotherLocal = arr[99];\n
referencing an array position."},{"location":"jimple-values/#jfieldref","title":"JFieldRef","text":"JFieldRef
s are referencing a SootField
via its FieldSignature
JStaticFieldRef
like <SomePackage.ExampleClass: fieldname>
JInstanceFieldRef
like r1.<SomePackage.ExampleClass: fieldname>
You can see the JInstanceFieldRef has the corresponding Local instance that points to the instance of the object which is holding the field.The IdentityRef makes those implicit special value assignments explicit.
"},{"location":"jimple-values/#jthisref","title":"JThisRef","text":"@this: package.fruit.Banana\n
represents the this pointer of the current class."},{"location":"jimple-values/#jcaughtexceptionref","title":"JCaughtExceptionRef","text":"@caughtexception\n
represents the value of the thrown exception (caught by this exceptionhandler)."},{"location":"jimple-values/#jparameterref","title":"JParameterRef","text":"i0 := @parameter0\ni1 := @parameter1 \n
represents a parameter of a method, identified by its index."},{"location":"jimple-values/#good-to-know","title":"Good to know","text":"A lot of the SootUp APIs return the Value
Interface. To determine and handle its subtypes you can make use of instanceof.
Value op = assignStmt.getRightOp();\n if(op instanceof Local){\n // found a Local\n ...\n }else if(stmt instanceof Constant){\n // found a Constant\n ...\n }else ...\n
But this could escalate to a huge if-else-tree - almost a forest. To mitigate such scenario you can implement a subclass of AbstractValueVisitor
. Just subclass the methods to the respective Value
s you need to handle. This is visitor acts like a switch-case, implemented via two dynamic calls.
Value op = assignStmt.getRightOp() ;\n AbstractValueVisitor visitor = new AbstractValueVisitor<Integer>() {\n private int intConstantCounter = 0;\n @Override\n public void caseConstant(@Nonnull Constant c) {\n intConstantCounter++;\n setResult(intConstantCounter);\n }\n };\n\n op.accept(visitor);\n int amountOfIfStmts = visitor.getResult();\n
If you only need a visitor for a subset of Value, you can consider ImmediateVisitor, ConstantVisitor, ExprVisitor, RefVisitor. Sidenote: Of course its possible can create a subclass instead of an anonymous class.
"},{"location":"jimple/","title":"Jimple","text":"What is Jimple? Jimple is the intermediate representation IR of Soot, and thus SootUp. Soot's intention is to provide a simplified way to analyze JVM bytecode. JVM bytecode is stack-based, which makes it difficult for program analysis. Java source code, on the other hand, is also not quite suitable for program analysis, due to its nested structures. Therefore, Jimple aims to bring the best of both worlds, a non-stack-based and flat (non-nested) representation. For this purpose Jimple was designed as a representation of JVM bytecode which is human readable.
Info
To learn more about jimple, refer to the thesis by Raja Vallee-Rai.
Lets have a look at the following Jimple code representing Java code of a HelloWorld
class.
public class HelloWorld extends java.lang.Object\n{\n public void <init>()\n {\n HelloWorld r0;\n r0 := @this: HelloWorld;\n specialinvoke r0.<java.lang.Object: void <init>()>();\n return;\n }\n\n public static void main(java.lang.String[])\n {\n java.lang.String[] r0;\n java.io.PrintStream r1;\n\n r0 := @parameter0: java.lang.String[];\n r1 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke r1.<java.io.PrintStream: \n void println(java.lang.String)>(\"Hello world!\");\n return;\n }\n}\n
public class HelloWorld {\n\n public HelloWorld() {\n\n }\n\n public static void main(String[] var0) {\n System.out.println(\"Hello World!\");\n }\n\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class analysis/HelloWorld {\n\n// compiled from: HelloWorld.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 4 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 6 L1\n RETURN\n L2\n LOCALVARIABLE this Lanalysis/HelloWorld; L0 L2 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x9\npublic static main([Ljava/lang/String;)V\n L0\n LINENUMBER 9 L0\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Hello World!\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L1\n LINENUMBER 10 L1\n RETURN\n L2\n LOCALVARIABLE var0 [Ljava/lang/String; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
The Java Sourcecode is the easiest representation - So why all the fuzz and just use that? Sometimes we have no access to the sourcecode but have a binary with the bytecode. For most People reading bytecode is not that intuitive. So SootUp generates Jimple from the bytecode. Jimple is very verbose, but makes everything explicit, that the JVM does implicitly and transforms the stack-machine strategy by a register-machine strategy i.e. Variable (Local
) handling .
Jimple mimics the JVMs class file structure. Therefore it is object oriented. A Single Class (or Interface) per file. Three-Address-Code which means there are no nested expressions. (nested expressions can be modeled via Locals that store intermediate calculation results.)
"},{"location":"jimple/#signatures-and-classtypes","title":"Signatures and ClassTypes","text":"Signatures are used to identify Classes,Methods or Fields uniquely/globally. Sidenote: Locals, do not have a signature, since they are referenced within method boundaries.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n\n specialinvoke this.<java.lang.Object: void <init>()>();\n this.<target.exercise1.DemoClass: double pi> = 3.14;\n return;\n }\n\n public void demoMethod()\n {\n java.io.PrintStream $stack3, $stack5;\n java.lang.StringBuilder $stack4, $stack6, $stack7;\n java.lang.String $stack8;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n $stack3 = <java.lang.System: java.io.PrintStream out>;\n\n virtualinvoke $stack3.<java.io.PrintStream: \n void println(java.lang.String)>(\"pi : 3.14\");\n $stack5 = <java.lang.System: java.io.PrintStream out>;\n $stack4 = new java.lang.StringBuilder;\n\n specialinvoke $stack4.<java.lang.StringBuilder: void <init>()>();\n $stack6 = virtualinvoke $stack4.<java.lang.StringBuilder: \n java.lang.StringBuilder append(java.lang.String)>\n (\"pi : \");\n $stack7 = virtualinvoke $stack6.<java.lang.StringBuilder: \n java.lang.StringBuilder append(double)>(3.1415);\n $stack8 = virtualinvoke $stack7.<java.lang.StringBuilder: \n java.lang.String toString()>();\n\n virtualinvoke $stack5.<java.io.PrintStream: \n void println(java.lang.String)>($stack8);\n return;\n }\n}\n/*\n For JInstanceFieldRef \"this.<target.exercise1.DemoClass: double pi>\" \n signature is <target.exercise1.DemoClass: double pi>\n Similarly, we have other signatures like \n <java.lang.Object: void <init>()>, \n <java.io.PrintStream: void println(java.lang.String)> \n and so on. \n*/\n
package target.exercise1;\n\npublic class DemoClass {\n private final double pi = 3.14;\n\n public void demoMethod(){\n double localPi = 3.1415;\n System.out.println(\"pi : \" + pi);\n System.out.println(\"pi : \" + localPi);\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x12\nprivate final D pi = 3.14\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 4 L1\n ALOAD 0\n LDC 3.14\n PUTFIELD target/exercise1/DemoClass.pi : D\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 3\n MAXLOCALS = 1\n\n// access flags 0x1\npublic demoMethod()V\n L0\n LINENUMBER 6 L0\n LDC 3.1415\n DSTORE 1\n L1\n LINENUMBER 7 L1\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"pi : 3.14\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L2\n LINENUMBER 8 L2\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n NEW java/lang/StringBuilder\n DUP\n INVOKESPECIAL java/lang/StringBuilder.<init> ()V\n LDC \"pi : \"\n INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)\n Ljava/lang/StringBuilder;\n DLOAD 1\n INVOKEVIRTUAL java/lang/StringBuilder.append (D)Ljava/lang/StringBuilder;\n INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L3\n LINENUMBER 9 L3\n RETURN\n L4\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L4 0\n LOCALVARIABLE localPi D L1 L4 1\n MAXSTACK = 4\n MAXLOCALS = 3\n}\n
"},{"location":"jimple/#sootclass","title":"SootClass","text":"A SootClass
consists of SootFields and SootMethods. It is referenced by its global identifier the ClassType
like java.lang.String
.
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n}\n
package target.exercise1;\n\npublic class DemoClass {}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n}\n
"},{"location":"jimple/#sootfield","title":"SootField","text":"A SootField is a piece of memory which can store a value that is accessible according to its visibility modifier. It is referenced by its FieldSignature like <java.lang.String: int hash>
.
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n this.<target.exercise1.DemoClass: double pi> = 3.14;\n return;\n }\n}\n/*\n \"this.<target.exercise1.DemoClass: double pi>\" is JInstanceFieldRef\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n private final double pi = 3.14;\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x12\nprivate final D pi = 3.14\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 4 L1\n ALOAD 0\n LDC 3.14\n PUTFIELD target/exercise1/DemoClass.pi : D\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 3\n MAXLOCALS = 1\n}\n
"},{"location":"jimple/#sootmethod-and-its-body","title":"SootMethod and its Body","text":"The interesting part is a method. A method is a \"piece of code\" that can be executed. It is referenced by its MethodSignature like <java.lang.Object: java.lang.String toString()>
.
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n virtualinvoke this.<target.exercise1.DemoClass: \n void demoMethod()>();\n return;\n }\n\n public void demoMethod()\n {\n java.io.PrintStream $stack1;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n $stack1 = <java.lang.System: java.io.PrintStream out>;\n\n virtualinvoke $stack1.<java.io.PrintStream: \n void println(java.lang.String)>(\"Inside method.\");\n return;\n }\n}\n/*\n \"<target.exercise1.DemoClass: void demoMethod()>\" \n and \"<target.exercise1.DemoClass: void <init>()>\" \n are instances of SootMethod \n*/\n
package target.exercise1;\n\npublic class DemoClass {\n DemoClass(){\n demoMethod();\n }\n public void demoMethod(){\n System.out.println(\"Inside method.\");\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x0\n<init>()V\n L0\n LINENUMBER 5 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 6 L1\n ALOAD 0\n INVOKEVIRTUAL target/exercise1/DemoClass.demoMethod ()V\n L2\n LINENUMBER 7 L2\n RETURN\n L3\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L3 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic demoMethod()V\n L0\n LINENUMBER 10 L0\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Inside method.\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L1\n LINENUMBER 11 L1\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
More about the Body of the SootMethod.
"},{"location":"migrating/","title":"Migration Help","text":""},{"location":"migrating/#version-130","title":"Version 1.3.0","text":"Stream<ClassType>
instead of Collection<ClassType>
. The simplest fix to have the same behaviour as before would be to collect the Stream on your own ( e.g. via .collect(Collectors.toList())
).Below we show a comparison of the code so far with the same functionality in sootup.
SootUpSootAnalysisInputLocation<JavaSootClass> inputLocation =\nnew JavaClassPathAnalysisInputLocation(\"path2Binary\");\n\nJavaView view = new JavaView(inputLocation);\n\nJavaClassType classType = \n view.getIdentifierFactory().getClassType(\"HelloWorld\");\n\nMethodSignature methodSignature =\n view\n .getIdentifierFactory()\n .getMethodSignature(\n \"main\", classType, \"void\",\n Collections.singletonList(\"java.lang.String[]\"));\n\nJavaSootClass sootClass = view.getClass(classType).get();\n\nMethodSubSignature mss = methodSignature.getSubSignature();\nJavaSootMethod sootMethod = sootClass.getMethod(mss).get();\n\nsootMethod.getBody().getStmts();\n
G.reset();\nString userdir = System.getProperty(\"user.dir\");\nString sootCp = \n userdir \n + File.separator \n + \"target\" \n + File.separator \n + \"test-classes\"\n + File.pathSeparator + \"lib\"+File.separator+\"rt.jar\";\n\nOptions.v().set_soot_classpath(sootCp);\nOptions.v().set_whole_program(true);\nOptions.v().setPhaseOption(\"cg.cha\", \"on\");\nOptions.v().setPhaseOption(\"cg\", \"all-reachable:true\");\nOptions.v().set_no_bodies_for_excluded(true);\nOptions.v().set_allow_phantom_refs(true);\nOptions.v().setPhaseOption(\"jb\", \"use-original-names:true\");\nOptions.v().set_prepend_classpath(false);\n\nScene.v().addBasicClass(\"java.lang.StringBuilder\");\nSootClass c = \n Scene.v().forceResolve(targetTestClassName, SootClass.BODIES);\nif (c != null) {\n c.setApplicationClass();\n}\nScene.v().loadNecessaryClasses();\n\nSootMethod method;\nfor (SootClass c : Scene.v().getApplicationClasses()) {\n if(c.getName().equals(\"example.HelloWorld\")){\n for (SootMethod m : c.getMethods()) {\n if (!m.hasActiveBody()) {\n continue;\n }\n if (m.getName().equals(\"entryPoint\")) {\n method = m;\n break;\n }\n }\n }\n}\n\nmethod.getActiveBody().getUnits();\n
"},{"location":"qilin/","title":"Incorporate Qilin Pointer Analysis","text":""},{"location":"qilin/#dependencies","title":"Dependencies","text":"MavenGradle <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.java.sourcecode</artifactId>\n <version>1.3.0</version>\n</dependency>\n
compile \"org.soot-oss:sootup.qilin:1.3.0\"\n
"},{"location":"qilin/#how-to-create-a-pointer-analysis","title":"How to create a pointer analysis","text":"WIP: Beware most likely the API will change so you only need to specify SootUp objects!
One can create an Andersen's context-insensitive analysis with following code:
JavaString entrypoint = \"dacapo.antlr.Main\";\nPTAPattern ptaPattern = new PTAPattern(\"insens\");\nPTA pta = PTAFactory.createPTA(ptaPattern, view, entrypoint);\npta.run();\n
Users must specify the program's View
, select a PTAPattern
(indicating the desired types of pointer analyses to perform), and designate the entrypoint
- which is serving as the entry point for the analysis.
First, we can use Qilin's pointer analysis to get a On-the-Fly constructed callgraph:
OnFlyCallGraph cg = pta.getCallGraph();\n
Second, we can use it to get the points-to results for some interested local variables, fields, etc.
PointsToSet pts0 = pta.reachingObjects(method, v0);\nPointsToSet pts1 = pta.reachingObjects(method, v1, f); // PTS(v1.f)\n
Third, we can check whether two variables, a
and b
, are aliases by checking whether there is an object that exists in both of their points-to sets.
Qilin does not currently offer a isMayAlias
API within the PTA class. However, a similar functionality can be found in qilin.test.util.AliasAssertion
with the method: boolean isMayAlias(PTA pta, Value va, Value vb)
This method allows to check for potential aliasing between two values given a PTA instance.
Qilin's toolbox includes a rich set of pointer analyses, which are given below:
Note that the symbol k used in the table should be replaced with a concrete small constant like 1 or 2.
PTA patterns Description Reference insens Andersen's context-insensitive analysis Paper kc k-callsite-sensitive pointer analysis (denoted kCFA). Paper ko k-object-sensitive pointer analysis (denoted kOBJ). Paper kt k-type-sensitive pointer analysis (denoted kTYPE). Paper kh hybrid k-object-sensitive pointer analysis. Paper kht hybrid k-type-sensitive pointer analysis. Paper B-2o BEAN-guided 2OBJ. Only k=2 is supported. Paper D-2o Data-driven 2OBJ. Only k=2 is supported. Paper D-2c Data-driven 2CFA. Only k=2 is supported. Paper M-ko MAHJONG-guided kOBJ. Paper M-kc MAHJONG-guided kCFA. Paper E-ko EAGLE-guided kOBJ. Paper T-ko TURNER-guided kOBJ. Paper Z-ko ZIPPER-guided kOBJ. Paper Z-kc ZIPPER-guided kCFA. Paper Z-ko -cd The context debloated version of ZIPPER-guided kOBJ. Paper ko -cd -cda=CONCH The context debloated version of kOBJ using Conch. Paper ko -cd -cda=DEBLOATERX The context debloated version of kOBJ using DebloaterX. Paper s-kc SELECTX-guided kCFA. Paper"},{"location":"tool_setup/","title":"From Prototype to an intuitive Tool","text":"How was the parameter order again? For a lot of cli tools we see an arbitrary order of cli parameters, different options for giving a working directory etc.. So in the wild you can see a lot from run.sh/run.bat to make files just to reorder arguments to execute a tool.
In SootUp we thought we could help on improving this madness while saving your time.
The command line parser mimics the options the java executable accepts - at least for what is supported by SootUp. This makes it very simple to just copy the execution paramaters you use for execution, to use them more or less as is four the analysis tool.
"},{"location":"tool_setup/#dependencies","title":"Dependencies","text":"MavenGradle<dependency>\n <groupId>commons-cli</groupId>\n <artifactId>commons-cli</artifactId>\n <version>1.8.0</version>\n</dependency>\n
implementation(\"commons-cli:commons-cli:1.8.0\")\n
"},{"location":"tool_setup/#java-code","title":"Java Code","text":"```java\n\nclass SootUpConfiguration{\n // TODO incorporate from downstream\n}\n\n```\n
We are happy if you steal the following code to create a tool where the setup is just simple.
"},{"location":"tools/","title":"Who uses SootUp","text":"The TypeHierarchy models the relationship of Classes or Interfaces of a OOP program.
"},{"location":"typehierarchy/#creating-typehierarchy","title":"Creating TypeHierarchy","text":"SootUpSootString cpString = \"src/test/resources/Callgraph/binary\";\nList<AnalysisInputLocation> inputLocations = new ArrayList();\ninputLocations.add(new JavaClassPathAnalysisInputLocation(cpStr));\ninputLocations.add(new DefaultRuntimeAnalysisInputLocation());\n\nJavaView view = new JavaView(inputLocations);\nTypeHierarchy typehierarchy = view.getTypeHierarchy();\n
String userdir = System.getProperty(\"user.dir\");\nString sootCp = userdir + File.separator + \"target\" + File.separator + \"test-classes\"+ File.pathSeparator + \"lib\"+File.separator+\"rt.jar\";\n\nString targetTestClassName = target.exercise1.Hierarchy.class.getName();\nG.reset();\nOptions.v().set_whole_program(true);\nOptions.v().set_soot_classpath(sootCp);\nOptions.v().set_no_bodies_for_excluded(true);\nOptions.v().process_dir();\nOptions.v().set_allow_phantom_refs(true);\nOptions.v().setPhaseOption(\"jb\", \"use-original-names:true\");\nOptions.v().set_prepend_classpath(false);\nSootClass c = Scene.v().forceResolve(targetTestClassName, SootClass.BODIES);\nif (c != null)\n c.setApplicationClass();\nScene.v().loadNecessaryClasses();\n\nHierarchy hierarchy = new Hierarchy();\n
"},{"location":"typehierarchy/#create-a-javaclasstype","title":"Create a JavaClassType","text":"SootUpSoot JavaClassType classTypeA = view.getIdentifierFactory().getClassType(\"packageName.A\");\nJavaClassType classTypeB = view.getIdentifierFactory().getClassType(\"packageName.B\");\nJavaClassType classTypeC = view.getIdentifierFactory().getClassType(\"packageName.C\");\n
String targetTestClassName = \"packageNameA.A\";\nSootClass methodA = Scene.v().getSootClass(targetTestClassName);\n
"},{"location":"typehierarchy/#query-the-typehierarchy","title":"Query the TypeHierarchy","text":""},{"location":"typehierarchy/#classes","title":"Classes","text":" // if the assertion fails, the following methods will throw an Exception (you don't have to call it - it's just to illustrate the assumption)\n assert typehierarchy.contains(classTypeA);\n\n typehierarchy.superclassOf(classTypeA);\n\n typehierarchy.subclassesOf(classTypeA);\n\n typehierarchy.isSubtypeOf(classTypeA, classTypeB);\n
"},{"location":"typehierarchy/#interfaces","title":"Interfaces","text":" JavaClassType iterableInterface = view.getIdentifierFactory().getClassType(\"java.lang.Iterable\");\n\n // if any of the assertions fail, the following methods will throw an Exception (you don't have to call these - it's just to illustrate the assumptions)\n assert typehierarchy.contains(iterableInterface);\n assert typehierarchy.isInterface(iterableInterface);\n\n // transitive relations as well\n typehierarchy.implementedInterfacesOf(iterableInterface);\n typehierarchy.implementersOf(iterableInterface);\n\n // only the direct related relations\n typehierarchy.directlyImplementedInterfacesOf(iterableInterface);\n typehierarchy.directlyExtendedInterfacesOf(iterableInterface);\n
"},{"location":"whatsnew/","title":"What's new in SootUp?","text":""},{"location":"whatsnew/#library-by-default","title":"Library by default","text":"While Soot is a library and a stand-alone command-line application. SootUp, on the other hand, is designed to be a core library. It assumes that it is embedded in a client application that owns the thread of control. It can be extended with a command-line interface, included in other software projects as a library, or integrated into IDEs with JimpleLSP.
"},{"location":"whatsnew/#modular-architecture","title":"Modular Architecture","text":"SootUp has a modular architecture, which enables its clients to include only the necessary functionality to their applications.
Singletons offer a single view of a single program version, which makes it impossible to analyze multiple programs or multiple versions of the same program. SootUp does not make use of singletons such the Scene
class in the old Soot any more. It enables analyzing multiple programs simultaneously.
Soot's JastAdd-based java frontend is not maintained anymore. In SootUp, we use WALA's well-maintained source code frontend, which will not only allow Soot to analyze Java source code, but also JavaScript and Python.
"},{"location":"whatsnew/#immutable-by-design","title":"Immutable by Design","text":"SootUp has been designed with the goal of immutability in mind. This makes sharing objects between several entities easier, because there is no need to worry about unintended changes to other entities.
"},{"location":"whatsnew/#withers-instead-of-setters","title":"Withers instead of Setters","text":"Due to the goal of immutability, many classes do not have setters anymore. For example, a Body
does not have a method setStmts(List<Stmt> stmts)
. Instead, a method called withStmts(List<Stmt> stmts)
has been added. This does not modify the original instance, but returns a copy of the Body but with the provided stmts
in its instance. This concept of so-called with
-ers can be found all throughout SootUp.
A simplified example
class Body {\n final List<Stmt> stmts;\n final List<Local> locals;\n\n Body(List<Stmt> stmts, List<Local> locals) {\n this.stmts = stmts;\n this.locals = locals;\n } \n\n Body withStmts(List<Stmt> stmts) { return new Body(stmts, this.locals); }\n Body withLocals(List<Local> locals) { return new Body(this.stmts, locals); }\n}\n
"},{"location":"whatsnew/#intermediate-representation","title":"Intermediate Representation","text":"Jimple is the only intermediate representation (IR) in SootUp. We modified it slightly to be able to accommodate different programming languages in the future.
"},{"location":"write_analyses/","title":"Write your own Interprocedural Dataflow Analysis","text":""},{"location":"write_analyses/#dependencies","title":"Dependencies","text":"MavenGradle<dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.analysis</artifactId>\n <version></version>\n</dependency>\n
compile \"org.soot-oss:sootup.analysis:1.3.0\"\n
"},{"location":"write_analyses/#useful-knowledge","title":"Useful Knowledge","text":"Background Knowledge as online lectures are available on YouTube.
Taint Analysis, TypeState Analysis, Linear Constant Propagation, ...
// TODO incorporate & guide through examples\n\nIn the meantime please have a look into the test cases of the\nanalysis submodule to see example implementations of interprocedural\ndata-flow analysis via the IFDS or IDE Framework.\n
"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"What's SootUp?","text":"SootUp is a complete overhaul of the good, old static analysis framework Soot.
Important
SootUp is not a version update to Soot, it is a completely new implementation written from scratch that aims to be a leaner, modernized and developer friendly successor of Soot. It is not a Drop-In Replacement! The new architecture and API, renders it not trivial to update existing projects that were built on soot. Therefore we recommend using SootUp for greenfield projects. We hope improved type safety and streamlined mechanisms will aide you implementing and debugging your analysis tool. Unfortunately not every feature has been ported - If you miss something feel free to contribute a feature you miss from good old Soot.
"},{"location":"#why-sootup","title":"Why SootUp?","text":"Over the 20+ years, SootUps predecessor Soot has evolved into a powerful framework, which is one of the most widely used tools in the static analysis community. This evolution was guided by the needs of the community and carried out with ad-hoc improvements. As a result, Soot has become a tool that can do a multitude of things, but it is heavy and hard to maintain and comprehend. So there was the need to clean up the codebase e.g. improve the software architecture, remove legacy datastructures that weren't in the Java Runtime at the time of Soots creation, enforce validation to have a sane state, removing the necessity of arcane knowledge, document it more and more - to make Soot future prove. So we introduced Design changes in SootUp, which aim to address Soot's shortcomings. The goal is a lighter library that can easily be understood and maintained to be included in other projects.
"},{"location":"#supporters","title":"Supporters","text":"The development of SootUp is financed by generous support from the German Research Foundation (DFG) and the Heinz Nixdorf Institute (HNI).
Become a sponsor!
"},{"location":"analysisinput/","title":"Analysis Input","text":"i.e. What should be analyzed. An AnalysisInputLocation
points to code input SootUp can analyze. We ship multiple Implementations that can handle different input.
Additionally you can specify a SourceType. This determines what is considered e.g. in the CallGraphs generation. Further you can specify a List of BodyInterceptors, which will optimize the raw Jimple IR that was transformed from the input.
"},{"location":"analysisinput/#java-runtime","title":"Java Runtime","text":""},{"location":"analysisinput/#java-8","title":"Java <=8","text":"The DefaultRTJaAnalysisInputLocation
points to the rt.jar of the executing JVM.
AnalysisInputLocation inputLocation = new DefaultRTJaAnalysisInputLocation();\nJavaView view = new JavaView(inputLocation);\n
To include a different Java Runtime library point to any rt.jar via a JavaClassPathAnalysisInputLocation
as its a usual .jar file.
The JRTFilesystemAnalysisInputLocation
points to the jigsawed java runtime of the executing JVM.
AnalysisInputLocation inputLocation = new JrtFileSystemAnalysisInputLocation(); \nJavaView view = new JavaView(inputLocation);\n
If you have errors like Java.lang.String, Java.lang.Object, ... you are most likely missing this AnalysisInputLocation.
"},{"location":"analysisinput/#java-bytecode","title":"Java Bytecode","text":"File-Extensions: .class, .jar, .war
The JavaClassPathAnalysisInputLocation
is the equivalent of the classpath you would pass to the java executable i.e. point to root(s) of package(s).
AnalysisInputLocation inputLocation =\n new JavaClassPathAnalysisInputLocation(\"target/\"); // points to\nJavaView view = new JavaView(inputLocation);\n
AnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation(\"myCode.jar\");\nJavaView view1 = new JavaView(inputLocation);\n\n// if you want to analyze a specific language level of a multi release jar\nAnalysisInputLocation inputLocation =\n new MultiReleaseJarAnalysisInputLocation(\"myCode.jar\", new JavaLanguage(10) );\nJavaView view2 = new JavaView(inputLocation);\n
// if you omit the package structure while pointing to a file,\n// you have to pass the omitted directories as a parameter\nAnalysisInputLocation inputLocation = new PathBasedAnalysisInputLocation.\n ClassFileBasedAnalysisInputLocation(\"Banana.class\", \"packageName.subPackage\", SourceType.Application);\nJavaView view = new JavaView(inputLocation);\n
String cp = \"myCode.jar\" + File.pathSeparator + \"dependency.jar\" + File.pathSeparator + \"target/classes/\";\nAnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation(cp);\nJavaView view = new JavaView(inputLocation);\n
"},{"location":"analysisinput/#java-sourcecode","title":"Java Sourcecode","text":"File-Extensions: .java
With the OTFCompileAnalysisInputLocation
you can point directly to .java files or pass a String with Java sourcecode. The AnalysisInputLocation delegates the data to the JavaCompiler
and transform the bytecode from the compiler to Jimple.
AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(\"Banana.java\");\nJavaView view = new JavaView(inputLocation);\n
List<Path> files = Arrays.asList(Paths.get(\"Apple.java\"), Paths.get(\"Banana.java\"));\nAnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(files);\nJavaView view = new JavaView(inputLocation);\n
String content = \"public class B{ }\";\nAnalysisInputLocation location = new OTFCompileAnalysisInputLocation(\"B.java\", content );\nJavaView view = new JavaView(location);\n
JavaSourcePathInputLocation
experimental! - points to a directory that is the root source directory (containing the package directory structure).
File-Extensions: .jimple
The JimpleAnalysisInputLocation
needs a Path to a .jimple file or a directory.
Path path = Paths.get(\"Banana.java\");\nAnalysisInputLocation jimpleLocation = new JimpleAnalysisInputLocation(path);\nJavaView view = new JavaView(jimpleLocation);\n
"},{"location":"analysisinput/#android-bytecode","title":"Android Bytecode","text":"File-Extensions: .apk
The ApkAnalysisInputLocation
is the APK frontend written for Sootup
Path path = Paths.get(\"Banana.apk\");\nAnalysisInputLocation inputLocation = new ApkAnalysisInputLocation(path, \"\", DexBodyInterceptors.Default.bodyInterceptors());\nJavaView view = new JavaView(inputLocation);\n
"},{"location":"analysisinput/#android-bytecode-with-dex2jar","title":"Android Bytecode with Dex2Jar","text":"File-Extensions: .apk
If you prefer to use dex2jar as a base to transform android apps to jimple, you can add the code below to create your own analysis input location. We used the dependency de.femtopedia.dex2jar:dex2jar:2.4.22 in the given example. We recommend to use ApkAnalysisInputLocation
Path path = Paths.get(\"Banana.apk\");\nAnalysisInputLocation inputLocation = new Dex2JarAnalysisInputLocation(path);\nJavaView view = new JavaView(inputLocation);\n
public class Dex2JarAnalysisInputLocation extends ArchiveBasedAnalysisInputLocation {\n\n public Dex2JarAnalysisInputLocation(@Nonnull Path path, @Nullable SourceType srcType) {\n super(path, srcType);\n String jarPath = dex2jar(path);\n this.path = Paths.get(jarPath);\n }\n\n private String dex2jar(Path path) {\n String apkPath = path.toAbsolutePath().toString();\n String outDir = \"./tmp/\";\n int start = apkPath.lastIndexOf(File.separator);\n int end = apkPath.lastIndexOf(\".apk\");\n String outputFile = outDir + apkPath.substring(start + 1, end) + \".jar\";\n Dex2jarCmd.main(\"-f\", apkPath, \"-o\", outputFile);\n return outputFile;\n }\n}\n
"},{"location":"analysisinput/#combining-multiple-analysisinputlocations","title":"Combining Multiple AnalysisInputLocations","text":"But what if I want to point to multiple AnalysisInputLocations?
AnalysisInputLocation mainJar = new JavaClassPathAnalysisInputLocation(\"myCode.jar\");\nAnalysisInputLocation jarA = new JavaClassPathAnalysisInputLocation(\"dependencyA.jar\");\nAnalysisInputLocation jarB = new JavaClassPathAnalysisInputLocation(\"dependencyB.jar\");\n\nList<AnalysisInputLocation> inputlocationList = Arrays.asList(mainJar, jarA, jarB);\n\nJavaView view = new JavaView(inputlocationList);\n
Of course you can combine different types of AnalysisInputLocation
s as well!
This uses mvn compile
+ JavaClassPathAnalysisInputLocation
under the hood to include a maven project.
TODO: let the code sail with the upstream boat to this doc.\n
Unfortunately its harder to extract the path of the binary result of Gradle projects in a unified way for all kinds of models - If you have a solution are looking forward to merge your contribution :-).
"},{"location":"analysisinput/#java-cli-arguments-to-configure-sootup","title":"Java cli arguments to configure SootUp","text":"We created a Utility that parses a String of java command line arguments and configures SootUp respectively.
"},{"location":"announcement/","title":"Announcements","text":""},{"location":"announcement/#release-announcement","title":"Release Announcement","text":"We would like to announce Soot\u2019s successor, SootUp.
Over more than 20 years, Soot has become one of the world\u2019s most popular academic tool for Java and Android analysis and instrumentation. We thank all of you who have used and contributed to it over the years! It was your feedback and your contributions that helped it grow into such a versatile tool!
However, over the years, the requirements for Soot have changed a lot, and given its original architecture, it was no longer quite up to the task. Soot was originally developed for ahead-of-time code transformation, particularly optimization, which has become very uncommon in Java. Current use cases center much more around powerful program analyses and program-understanding tasks.
Today we are officially releasing SootUp, a new version of Soot with a completely overhauled architecture. With SootUp, we aim to keep the best things about Soot, yet overcome a lot of its drawbacks. We very much restructured Soot, particularly abolishing the heavy use of singletons. Soot now has a concept of views; each view corresponds to some version or variant of an analyzed program, and multiple views can be kept in memory at the same time. This sets the foundation, for instance, for differential or incremental program analyses.
SootUp is a library that can easily be included in other projects, leaving those projects in control. For those who intend to use it as a framework, with inversion of control, SootUp provides additional templates that help you and novices to get started more easily. The Jimple IR has been slightly simplified, and has been made immutable by default such that internally SootUp can make use of caching where desired. Where required, Jimple transformations are still allowed, but in a systematic manner, for instance assuring that analyses depending on the transformed code are notified about its changes.
Below is an overview of what\u2019s new.
SootUp is not a drop-in replacement for Soot! Due to its completely new architecture and API it is essentially an almost complete rewrite. For a while, Soot and SootUp will coexist, as many existing tools depend on Soot, yet our maintenance efforts will henceforth be focused on SootUp, not Soot, and on extending SootUp with those capabilities that people still find missing. For now, we recommend using SootUp for greenfield projects.
For more details, check out
This Page ;-) and The SootUp repository: https://github.com/soot-oss/SootUp/
We are very much looking forward to your feedback and feature requests. To this end, best create appropriate issues in the repository.
This major upgrade of Soot was made possible by generous competitive funding by the DFG, within the project \u201cFuture-proofing the Soot Framework for Program Analysis and Transformation (FutureSoot)\u201d. It was funded in the DFG\u2019s program on Research Software Sustainability.
"},{"location":"bodyinterceptors/","title":"Body Interceptors","text":"BodyInterceptors are applied to each Body
now by default, if not overridden in the used AnalysisInputLocations. The BodyInterceptors exist to to improve and normalize the raw Jimple that was generated in an earlier step. The \"raw\" generated Jimple from the Bytecodefrontend needs a lot improvements - deficits of raw Jimple are:
Optimizations (method scope)
Standardize Jimple appearance
Soot Equivalent
BodyTransformer
"},{"location":"bodyinterceptors/#localsplitter","title":"LocalSplitter","text":"LocalSplitter is aBodyInterceptor
that attempts to identify and separate uses of a local variable (as definition) that are independent of each other by renaming local variables.
Example 1:
As shown in the example above, the local variablel1
is defined twice. It can be split up into two new local variables: l1#1
and l1#2
because the both definitions are independent of each other.
Look for foldable navigation and tabs for showing old vs new
Example 2:
In the second example, the local variablel2
is defined thrice. But it cannot be split up into three new local variables as in the first example, because its definitions in the if-branches are not independent of each other. Therefore, it can only be split up into two local variables as shown in the figure.
LocalPacker is aBodyInterceptor
that attempts to minimize the number of local variables which are used in body by reusing them, when it is possible. It corresponds to the inverse body transformation of LocalSplitter. Note: Every local variable's type should be assigned before running LocalPacker.
Example:
In the given example above, the local variablesl1
,l3
are summarized to be one local variablel1
, because they have the same type without interference with each other. Likewise, the local variablesl2
,l4
andl5
are summarized to be another local variablel2
. Although the local variablel0
doesn't interfere any other local variables, it cannot be summed up with other local variables because of its distinctive type.
WIP - currently not available!
TrapTightener is aBodyInterceptor
that shrinks the protected area covered by each Trap in a Body.
Example:
We assume in the example above that only theStmt
:l2 := 2
might throw an exception caught by theTrap
which is labeled withlabel3
. In the jimple body before running the TrapTightener, the protected area covered by the Trap contains threeStmts
:l1 := 1; l2 := 2; l2 := 3
. But an exception could only arise at theStmt
:l2 := 2
. After the implementation of TrapTightener, we will get a contractible protected area which contains only theStmt
that might throw an exception, namely theStmt
:l2 := 2
.
EmptySwitchEliminator is aBodyInterceptor
that removes empty switch statements which contain only the default case.
Example:
As shown in the example above, the switch statement in the jimple body always takes the default action. After running EmptySwitchEliminator, the switch statement is replaced with aGotoStmt
to the default case.
UnreachableCodeEliminator is aBodyInterceptor
that removes all unreachable statements.
Example:
Obviously, the code segmentl2 = 2; l3 = 3;
is unreachable. It will be removed after running the UreachableCodeEliminator.
CopyPropagator is a BodyInterceptor
that supports copy propagation and constant propagation.
CopyPropagator
\"Definition 3[Copy Propagation]: The use of a variable y in the statement z=x+y occurring at a point p can be replaced by a variable w if every path from the entry node to point p contains the same definition y=w, for the variable y, and after the definition prior to reaching p, there is no redefinition to the variable y and no redefinition to the variable w.\"
Sreekala, S. K. and Vineeth Kumar Paleri. \u201cCopy Propagation subsumes Constant Propagation.\u201d ArXiv abs/2207.03894 (2022): n. pag.
Example for global copy propagation:
Consider a code segment in the following form:
a = b;\n...\nc = use(a); // a, b, c are local variables\n
According to the copy propagation's definition, the statementc = use(a)
can be replaced withc = use(b)
iff both conditions are met:
a
is defined only one time on all the paths froma = b
toc = use(a)
.b
on any path froma = b
toc = use(a)
.In the example for global copy propagation, the first usedl1
is replaced withl0
, but the second usedl1
cannot be replaced withl3
, because the second condition is not satisfied.
Example for constant propagation:
Constant propagation is similar to copy propagation. Consider a code segment in the following form:
a = const;\n...\nb = use(a); // a, b are local variables, const is a constant\n
After perfoming the constant propagation, the statementb = use(a)
can be replaced withb = use(const)
iffa
is not redefined on any of the paths froma = const
tob = use(a)
.
Therefore, the first usedl1
in the second example can be replaced with the constant1
, but the second usedl1
cannot be replaced with the constant2
, becausel1
is redefined on the path froml1 = 2
tol4 = use(l1)
. However, it can be replaced with local variablel2
, because the both conditions of copy propagation are met.
LocalNameStandardizer is aBodyInterceptor
that assigns a generic name to each local variable. Firstly, it will sort the local variables' order alphabetically by the string representation of their type. If there are two local variables with the same type, then the LocalNameStandardizer will use the sequence of their occurrence in jimple body to determine their order. Each assigned name consists of two parts:
The following table shows the letter corresponding to each type:
Type of Local Variable Letter boolean z byte b short s int i long l float f double d char c null n unknown e reference r"},{"location":"bodyinterceptors/#staticsingleassignmentformer","title":"StaticSingleAssignmentFormer","text":"StaticSingleAssignmentFormer is aBodyInterceptor
that transforms jimple body into SSA form, so that each local variable is assigned exactly once and defined before its first use.
Example:
In the given example, the StaticSingleAssignmentFormer assigns eachIdentityStmt
andAssignStmt
to a new local variable . And each use uses the local variable which is most recently defined. Sometimes, it is impossible to determine the most recently defined local variable for a use in a join block. In this case, the StaticSingleAssignmentFormer will insert aPhiStmt
in the front of the join block to merge all most recently defined local variables and assign them a new local variable.
More to come!
"},{"location":"builtin-analyses/#locallivenessanalyser","title":"LocalLivenessAnalyser","text":"LocalLivenessAnalyser is used for querying for the list of live local variables before and after a given Stmt
.
Example:
The live local variables before and after each Stmt
will be calculated after generating an instance of LocalLivenessAnalyser as shown the example above. They can be queried by using the methods getLiveLocalsBeforeStmt
and getLiveLocalsAfterStmt
.
DomianceFinder is used for querying for the immediate dominator and dominance frontiers for a given basic block.
Example:
After generating an instance of DominanceFinder for a BlockGraph
, we will get the immediate dominator and dominance frontiers for each basic block. The both properties can be queried by using the methodsgetImmediateDominator
andgetDominanceFrontiers
.
A call graph shows the method calling relationship of a program. It is a directed graph, whose nodes represent different methods, and edges represent caller -> callee relationship.
SootUp contains several call graph construction algorithms. Below, we show how you can use each of these.
"},{"location":"callgraphs/#creating-the-type-hierarchy","title":"Creating the Type Hierarchy","text":"All the call graph construction algorithms require the view to access the type hierarchy for resolving method calls based of sub typing relationship. Below, we show how to create a type hierarchy:
SootUpSootString cpString = \"src/test/resources/Callgraph/binary\";\nList<AnalysisInputLocation> inputLocations = new ArrayList();\ninputLocations.add(new JavaClassPathAnalysisInputLocation(cpStr));\ninputLocations.add(new DefaultRuntimeAnalysisInputLocation());\n\nJavaView view = new JavaView(inputLocations);\n
String userdir = System.getProperty(\"user.dir\");\nString sootCp = userdir + File.separator + \"target\" + File.separator + \"test-classes\"+ File.pathSeparator + \"lib\"+File.separator+\"rt.jar\";\nString targetTestClassName = target.exercise1.Hierarchy.class.getName();\nG.reset();\nOptions.v().set_whole_program(true);\nOptions.v().set_soot_classpath(sootCp);\nOptions.v().set_no_bodies_for_excluded(true);\nOptions.v().process_dir();\nOptions.v().set_allow_phantom_refs(true);\nOptions.v().setPhaseOption(\"jb\", \"use-original-names:true\");\nOptions.v().set_prepend_classpath(false);\nSootClass c = Scene.v().forceResolve(targetTestClassName, SootClass.BODIES);\nif (c != null)\n c.setApplicationClass();\nScene.v().loadNecessaryClasses();\n\nHierarchy hierarchy = new Hierarchy();\n
"},{"location":"callgraphs/#defining-an-entry-method","title":"Defining an Entry Method","text":"All call graph construction algorithms require an entry method to start with. In java application, you usually define the main method. However, it is possible to define arbitrary entry methods depending on your needs. Below, we show how to define such an entry method:
SootUp (performant)SootUp (alternative)SootJavaClassType classTypeA = view.getIdentifierFactory().getClassType(\"packageNameA.A\");\n\nMethodSignature entryMethodSignature =\n view.getIdentifierFactory()\n .getMethodSignature(\n classTypeA,\n \"calc\",\n VoidType.getInstance(),\n Collections.singletonList(classTypeA)\n );\n
String methodSigStr = \"<packageNameA.A: void calc(packageNameA.A)\";\nMethodSignature entryMethodSignature = view\n .getIdentifierFactory().parseMethodSignature(methodSigStr));\n
String targetTestClassName = \"packageNameA.A\";\nSootMethod src = Scene.v().getSootClass(targetTestClassName).getMethodByName(\"doStuff\"); \n
"},{"location":"callgraphs/#class-hierarchy-analysis","title":"Class Hierarchy Analysis","text":"Class Hierarchy Analysis (CHA) algorithm is the most sound call graph construction algorithm available in SootUp. It soundly includes all implementers of an interface, when resolving a method call on an interface. You can construct a call graph with CHA as follows:
SootUpSootCallGraphAlgorithm cha = new ClassHierarchyAnalysisAlgorithm(view);\n\nCallGraph cg = cha.initialize(Collections.singletonList(entryMethodSignature));\n\ncg.callsFrom(entryMethodSignature).stream()\n .forEach(tgt -> System.out.println(entryMethodSignature + \" may call \" + tgt);\n
CHATransformer.v().transform();\nSootMethod src = Scene.v().getSootClass(targetTestClassName).getMethodByName(\"doStuff\");\nCallGraph cg = Scene.v().getCallGraph();\nIterator<MethodOrMethodContext> targets = new Targets(cg.edgesOutOf(src));\nwhile (targets.hasNext()) {\n SootMethod tgt = (SootMethod)targets.next();\n System.out.println(src + \" may call \" + tgt);\n}\n
"},{"location":"callgraphs/#rapid-type-analysis","title":"Rapid Type Analysis","text":"Rapid Type Analysis (RTA) algorithm constructs a rather precise version of the call graph that the CHA constructs. It refines CHA by considering only the instantiated implementers of an interface, when resolving a method call on an interface. You can construct a call graph with RTA as follows:
SootUpSootCallGraphAlgorithm rta = new RapidTypeAnalysisAlgorithm(view);\n\nCallGraph cg = rta.initialize(Collections.singletonList(entryMethodSignature));\n\ncg.callsFrom(entryMethodSignature).stream()\n .forEach(tgt -> System.out.println(entryMethodSignature + \" may call \" + tgt);\n
Transform sparkConfig = new Transform(\"cg.spark\", null);\nPhaseOptions.v().setPhaseOption(sparkConfig, \"enabled:true\");\nPhaseOptions.v().setPhaseOption(sparkConfig, \"rta:true\");\nPhaseOptions.v().setPhaseOption(sparkConfig, \"on-fly-cg:false\");\nMap phaseOptions = PhaseOptions.v().getPhaseOptions(sparkConfig);\nSparkTransformer.v().transform(sparkConfig.getPhaseName(), phaseOptions);\nSootMethod src = Scene.v().getSootClass(targetTestClassName).getMethodByName(\"doStuff\");\nCallGraph cg = Scene.v().getCallGraph();\nIterator<MethodOrMethodContext> targets = new Targets(cg.edgesOutOf(src));\nwhile (targets.hasNext()) {\n SootMethod tgt = (SootMethod)targets.next();\n System.out.println(src + \" may call \" + tgt);\n} \n
"},{"location":"callgraphs/#qilin-pointer-analysis","title":"Qilin Pointer Analysis","text":"Qilin builds a call graph on the fly with the pointer analysis. You can construct a call graph with Qilin as follows:
===\"SootUp\"
```java\nString MAINCLASS = \"dacapo.antlr.Main\"; // just an example\nPTAPattern ptaPattern = new PTAPattern(\"insens\"); // \"2o\"=>2OBJ, \"1c\"=>1CFA, etc.\nPTA pta = PTAFactory.createPTA(ptaPattern, view, MAINCLASS);\npta.run();\nCallGraph cg = pta.getCallGraph();\n```\n
"},{"location":"codepropertygraphs/","title":"Code Property Graphs","text":""},{"location":"codepropertygraphs/#dependencies","title":"Dependencies","text":"MavenGradle <dependency>\n<groupId>org.soot-oss</groupId>\n<artifactId>sootup.codepropertygraph</artifactId>\n<version>1.3.0</version>\n</dependency>\n
compile \"org.soot-oss:sootup.codepropertygraph:1.3.0\"\n
Code Property Graphs (CPGs) are a representation of program code that combines different code representations into a single graph. This unified representation includes abstract syntax trees (ASTs), control flow graphs (CFGs), control dependence graphs (CDGs), and data dependence graphs (DDGs). CPGs enable comprehensive analysis, which makes them a powerful tool for detecting vulnerabilities and understanding code structure. For further details, refer to this thesis.
"},{"location":"codepropertygraphs/#usage-example","title":"Usage Example","text":"In this example, we will demonstrate how to create a CPG for a vulnerable Java method and use it to identify a potential vulnerability.
"},{"location":"codepropertygraphs/#vulnerable-java-code","title":"Vulnerable Java Code","text":"Let's assume we have the following vulnerable Java code in a file named VulnerableClass.java
:
public class VulnerableClass {\n public void vulnerableMethod(String userInput) {\n if (userInput.equals(\"admin\")) {\n System.out.println(\"Welcome, admin!\");\n }\n }\n}\n
"},{"location":"codepropertygraphs/#step-1-obtain-a-sootmethod","title":"Step 1: Obtain a SootMethod","text":"First, we assume we have a SootMethod
for the vulnerableMethod
. For instructions on how to obtain a SootMethod
, refer to Retrieving a Method.
We can create the CPG subgraphs using the creators.
ASTCFGCDGDDGpublic class AstExample {\n\n public static void main(String[] args) {\n // Assuming `sootMethod` is obtained from the setup step\n SootMethod vulnerableMethod = getVulnerableMethod();\n\n // Create the AST subgraph\n AstCreator astCreator = new AstCreator();\n PropertyGraph astGraph = astCreator.createGraph(vulnerableMethod);\n\n // Print the DOT representation of the AST\n System.out.println(astGraph.toDotGraph());\n }\n}\n
public class CfgExample {\n\n public static void main(String[] args) {\n // Assuming `sootMethod` is obtained from the setup step\n SootMethod vulnerableMethod = getVulnerableMethod();\n\n // Create the CFG subgraph \n CfgCreator cfgCreator = new CfgCreator();\n PropertyGraph cfgGraph = cfgCreator.createGraph(vulnerableMethod);\n\n // Print the DOT representation of the CFG\n System.out.println(cfgGraph.toDotGraph());\n }\n}\n
public class CdgExample {\n\n public static void main(String[] args) {\n // Assuming `sootMethod` is obtained from the setup step\n SootMethod vulnerableMethod = getVulnerableMethod();\n\n // Create the CDG subgraph\n CdgCreator cdgCreator = new CdgCreator();\n PropertyGraph cdgGraph = cdgCreator.createGraph(vulnerableMethod);\n\n // Print the DOT representation of the CDG\n System.out.println(cdgGraph.toDotGraph());\n }\n}\n
public class DdgExample {\n\n public static void main(String[] args) {\n // Assuming `sootMethod` is obtained from the setup step\n SootMethod vulnerableMethod = getVulnerableMethod();\n\n // Create the DDG subgraph\n DdgCreator ddgCreator = new DdgCreator();\n PropertyGraph ddgGraph = ddgCreator.createGraph(vulnerableMethod);\n\n // Print the DOT representation of the DDG\n System.out.println(ddgGraph.toDotGraph());\n }\n}\n
We can create the combined CPG graph using the CpgCreator
.
public class CpgExample {\n\n public static void main(String[] args) {\n // Assuming `sootMethod` is obtained from the setup step\n SootMethod vulnerableMethod = getVulnerableMethod();\n\n AstCreator astCreator = new AstCreator();\n CfgCreator cfgCreator = new CfgCreator();\n CdgCreator cdgCreator = new CdgCreator();\n DdgCreator ddgCreator = new DdgCreator();\n\n // Create the combined CPG\n CpgCreator cpgCreator = new CpgCreator(astCreator, cfgCreator, cdgCreator, ddgCreator);\n PropertyGraph cpg = cpgCreator.createCpg(vulnerableMethod);\n\n // Print the DOT representation of the CPG\n System.out.println(cpg.toDotGraph());\n }\n}\n
"},{"location":"codepropertygraphs/#step-3-analyzing-the-cpg","title":"Step 3: Analyzing the CPG","text":"With the CPG created, you can now analyze it for vulnerabilities. For example, you can check for potential injection vulnerabilities by analyzing data flow dependencies.
SootUppublic class VulnerabilityAnalysis {\n\n public static void main(String[] args) {\n // Assuming `cpg` is the PropertyGraph created in the previous step\n for (DdgEdge edge : cpg.getEdges(DdgEdge.class)) {\n StmtGraphNode source = (StmtGraphNode) edge.getSource();\n StmtGraphNode destination = (StmtGraphNode) edge.getDestination();\n\n if (isPotentiallyVulnerable(source, destination)) {\n System.out.println(\"Potential vulnerability found between: \");\n System.out.println(\"Source: \" + source.getStmt());\n System.out.println(\"Destination: \" + destination.getStmt());\n }\n }\n }\n\n private static boolean isPotentiallyVulnerable(StmtGraphNode source, StmtGraphNode destination) {\n // Implement your vulnerability detection logic here\n return source.getStmt().toString().contains(\"userInput\") && \n destination.getStmt() instanceof JInvokeStmt && \n destination.getStmt().toString().contains(\"println\");\n }\n}\n
In this example, we check for data flow dependencies between the userInput
variable and any println
calls, which could indicate a potential injection vulnerability.
Similarly, we can define our own queries to detect specific patterns that identify common vulnerabilities.
"},{"location":"docguide/","title":"Docguide","text":""},{"location":"docguide/#general","title":"General","text":""},{"location":"docguide/#mkdocsextensions","title":"MkDocsExtensions","text":""},{"location":"docguide/#tooltip","title":"Tooltip","text":"Hover me
"},{"location":"docguide/#example-file-inclusion","title":"Example File inclusion","text":"this enables that tutorial code can be tested and will fail if its not up to date anymore :)
package sootup.examples.basicSetup;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Collections;\nimport org.junit.jupiter.api.Tag;\nimport org.junit.jupiter.api.Test;\nimport sootup.core.inputlocation.AnalysisInputLocation;\nimport sootup.core.jimple.common.expr.JVirtualInvokeExpr;\nimport sootup.core.jimple.common.stmt.JInvokeStmt;\nimport sootup.core.model.SootClass;\nimport sootup.core.model.SootMethod;\nimport sootup.core.model.SourceType;\nimport sootup.core.signatures.MethodSignature;\nimport sootup.core.types.ClassType;\nimport sootup.core.views.View;\nimport sootup.java.bytecode.frontend.inputlocation.PathBasedAnalysisInputLocation;\nimport sootup.java.core.language.JavaJimple;\nimport sootup.java.core.views.JavaView;\n\n/** This example illustrates how to create and use a new Soot Project. */\n@Tag(\"Java8\")\npublic class BasicSetupTest {\n\n @Test\n public void createByteCodeProject() {\n // Create a AnalysisInputLocation, which points to a directory. All class files will be loaded\n // from the directory\n Path pathToBinary = Paths.get(\"src/test/resources/BasicSetup/binary\");\n AnalysisInputLocation inputLocation =\n PathBasedAnalysisInputLocation.create(pathToBinary, SourceType.Application);\n\n // Create a view for project, which allows us to retrieve classes\n View view = new JavaView(inputLocation);\n\n // Create a signature for the class we want to analyze\n ClassType classType = view.getIdentifierFactory().getClassType(\"HelloWorld\");\n\n // Create a signature for the method we want to analyze\n MethodSignature methodSignature =\n view.getIdentifierFactory()\n .getMethodSignature(\n classType, \"main\", \"void\", Collections.singletonList(\"java.lang.String[]\"));\n\n // Assert that class is present\n assertTrue(view.getClass(classType).isPresent());\n\n // Retrieve class\n SootClass sootClass = view.getClass(classType).get();\n\n // Retrieve method\n view.getMethod(methodSignature);\n\n // Alternatively:\n assertTrue(sootClass.getMethod(methodSignature.getSubSignature()).isPresent());\n SootMethod sootMethod = sootClass.getMethod(methodSignature.getSubSignature()).get();\n\n // Read jimple code of method\n System.out.println(sootMethod.getBody());\n\n // Assert that Hello world print is present\n assertTrue(\n sootMethod.getBody().getStmts().stream()\n .anyMatch(\n stmt ->\n stmt instanceof JInvokeStmt\n && ((JInvokeStmt) stmt).getInvokeExpr().get() instanceof JVirtualInvokeExpr\n && ((JInvokeStmt) stmt)\n .getInvokeExpr()\n .get()\n .getArg(0)\n .equivTo(JavaJimple.getInstance().newStringConstant(\"Hello World!\"))));\n }\n}\n
"},{"location":"examples/","title":"SootUp Example projects","text":"Some examples that use SootUp to get insights about a Java program.
Download
The Examples can be cloned or downloaded from our Example Repository.
"},{"location":"faq/","title":"Frequently Asked Questions","text":""},{"location":"faq/#how-to-setup-the-soot-dependency-in-maven-gradle","title":"How to setup the soot dependency (in Maven, Gradle)?","text":"See Installation.
"},{"location":"faq/#how-to-retreive-a-sootclass-or-sootmethod","title":"How to retreive a SootClass or SootMethod?","text":"See Getting Started.
"},{"location":"faq/#is-there-a-github-template-to-quickstart-into-development-with-sootup","title":"Is there a github template to quickstart into development with SootUp?","text":"Not yet.
"},{"location":"faq/#error-while-using-the-sourcecodefrontend","title":"Error while using the Sourcecodefrontend","text":"Please make sure to use Java8 to execute.
"},{"location":"faq/#exception-provider-jrt-not-found","title":"Exception: Provider \"jrt\" not found","text":"java.lang.ExceptionInInitializerError\n at inputlocation.sootup.java.bytecode.frontend.JrtFileSystemAnalysisInputLocationTest.getClassSource(JrtFileSystemAnalysisInputLocationTest.java:28)\n ...\nCaused by: java.nio.file.ProviderNotFoundException: Provider \"jrt\" not found\n
To execute SootUp with JavaModules support please make sure you run the code at least the Java9 Runtime."},{"location":"faq/#how-to-solve-a-concurrentmodificationexception","title":"How to solve a ConcurrentModificationException?","text":"Copy the Iterator into an intermediate Collection.
final StmtGraph<?> stmtGraph = builder.getStmtGraph();\n for (Stmt stmt : Lists.newArrayList(stmtGraph)){\n ...\n }\n}\n
"},{"location":"faq/#how-can-i-visualize-a-stmtgraph","title":"How can I visualize a StmtGraph?","text":"There exists a tool, that converts a StmtGraph to the Graphviz Dot Language.
DotExporter.buildGraph( stmtgraph );\n
or create a convenient link with the exported stmtgraph as HTTP GET Parameter DotExporter.createUrlToWebeditor( stmtgraph );\n
"},{"location":"faq/#the-sourcecodefrontend","title":"The Sourcecodefrontend...","text":"is in a experimental state! If you wish to use it, please consider to contribute.
"},{"location":"faq/#is-there-a-way-to-use-code-exploration-and-syntax-highlighting-features-in-my-ide-for-jimple-files","title":"Is there a way to use code exploration and syntax highlighting features in my IDE for .jimple files?","text":"Try JimpeLsp or the vscode plugin
"},{"location":"faq/#is-there-a-way-to-use-syntax-highlighting-of-jimple-in-my-paper-thesis","title":"Is there a way to use syntax highlighting of .jimple in my paper, thesis, ...?","text":"Have a look at LspLexer4Pygments. Its the same syntax highlighting you see here in the documentation. You can export it to LaTex as well.
"},{"location":"faq/#how-to-add-an-entry-in-this-list-ie-your-question-is-not-answered-here","title":"How to ... add an entry in this list? i.e. Your question is not answered here?","text":"Feel free to start a Discussion.
"},{"location":"getting-started/","title":"First Steps with SootUp","text":"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.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
AnalysisInputLocation inputLocation = \n new JavaClassPathAnalysisInputLocation(\"path2Binary\");\n\nJavaView view = new JavaView(inputLocation);\n
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).
AnalysisInputLocation inputLocation = \n new JavaSourcePathAnalysisInputLocation(\"path2Source\");\n\nJavaView view = new JavaView(inputLocation);\n
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
Path pathToJimple = Paths.get(\"path2Jimple\");\n\nAnalysisInputLocation inputLocation = \n new JimpleAnalysisInputLocation(pathToJimple);\n\nJimpleView view = new JimpleView(inputLocation);\n
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:
JavaView view = new JavaView(inputLocations, new LRUCacheProvider(50));\n
"},{"location":"getting-started/#retrieving-a-class","title":"Retrieving a Class","text":"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
package example;\n\npublic class HelloWorld {\n\n public HelloWorld() {\n\n }\n\n public static void main(String[] args) {\n HelloWorld hw = new HelloWorld();\n hw.hello();\n }\n\n public void hello() {\n\n }\n\n}\n
Then, we could define the ClassType
of the HelloWorld
class as follows:
Defining a ClassType
JavaClassType classType = \n view.getIdentifierFactory().getClassType(\"example.HelloWorld\");\n
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
JavaSootClass sootClass = view.getClass(classType).get();\n
"},{"location":"getting-started/#retrieving-a-method","title":"Retrieving a Method","text":"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
PureParse from StringMethodSignature methodSignature =\n view\n .getIdentifierFactory()\n .getMethodSignature(\n \"main\", // method name\n classType,\n \"void\", // return type\n Collections.singletonList(\"java.lang.String[]\")); // args\n
MethodSignature methodSignature =\n view\n .getIdentifierFactory()\n .parseMethodSignature(\n \"<packageName.classType: void main(java.lang.String[])>\");\n
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
Optional<SootMethod> opt = view.getMethod(methodSignature);\n\nif(!opt.isPresent()){\n return;\n}\nSootMethod method = opt.get();\nSystem.out.println(method.getModifiers());\n
Alternatively, we can also retrieve a SootMethod
from SootClass
that contains it.
Retrieving a SootMethod from a SootClass
MethodSubSignature mss = methodSignature.getSubSignature()\nOptional<JavaSootMethod> opt = sootClass.getMethod(mss);\n\nif(opt.isPresent()){\n JavaSootMethod method = opt.get();\n}\n
"},{"location":"getting-started/#retrieving-the-control-flow-graph-of-a-method","title":"Retrieving the Control-Flow Graph of a Method","text":"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
StmtGraph<?> graph = sootMethod.getBody().getStmtGraph();\n
"},{"location":"getting-started/#using-the-stmtgraph","title":"Using the StmtGraph","text":"StmtGraph StmtsStmtGraph BlocksStmtGraph DotExport for( Stmt stmt : graph.nodes()){\n // pseudo topological order as Stmts would be serialized to a Jimple file.\n}\n\nfor( Stmt stmt : graph.nodes()){\n // Stmts are unordered!\n}\n
List<BasicBlock<?>> blocks = graph.getBlocks();\nfor( BasicBlock<?> block : blocks){\n // e.g. check if its a merge point\n if(block.getPredecessors().size() > 1){\n ...\n }\n\n // e.g. check if its a branching point\n if(block.getSuccessors().size() > 1){\n // or use block.getTail() instanceof BranchingStmt\n ...\n }\n\n // e.g. check if thrown exceptions would be caught in this method\n if(!block.getExceptionalSuccessors().isEmpty()){\n ...\n }\n}\n
String urlToWebeditor = DotExporter.createUrlToWebeditor(this);\nSystem.out.println(urlToWebeditor);\n
Access a complete example of the code used above
Download BasicSetup.java
"},{"location":"installation/","title":"Installation","text":""},{"location":"installation/#use-the-latest-develop-branch","title":"Use the latest develop branch","text":"For configuration options of your build tool please visit SootUp on Jitpack.io
"},{"location":"installation/#use-releases-on-maven-central","title":"Use Releases on Maven Central","text":"The code below shows you how to import all submodules of the SootUp repository. You can import fewer modules if your use case allows it.
Add the following dependencies to your pom.xml
/ build.gradle
.
<dependencies>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.core</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.java.core</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.java.sourcecode.frontend</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.java.bytecode.frontend</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.jimple.frontend</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.apk.frontend</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.callgraph</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.analysis.intraprocedural</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.analysis.interprocedural</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.qilin</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.codepropertygraph</artifactId>\n <version>1.3.0</version>\n </dependency>\n</dependencies>\n
repositories {\n mavenCentral()\n google()\n}\n\ncompile \"org.soot-oss:sootup.core:1.3.0\"\ncompile \"org.soot-oss:sootup.java.core:1.3.0\"\ncompile \"org.soot-oss:sootup.java.sourcecode.frontend:1.3.0\"\ncompile \"org.soot-oss:sootup.java.bytecode.frontend:1.3.0\"\ncompile \"org.soot-oss:sootup.jimple.frontend:1.3.0\"\ncompile \"org.soot-oss:sootup.apk.frontend:1.3.0\"\ncompile \"org.soot-oss:sootup.callgraph:1.3.0\"\ncompile \"org.soot-oss:sootup.analysis.intraprocedural:1.3.0\"\ncompile \"org.soot-oss:sootup.analysis.interprocedural:1.3.0\"\ncompile \"org.soot-oss:sootup.qilin:1.3.0\"\ncompile \"org.soot-oss:sootup.codepropertygraph:1.3.0\"\n
"},{"location":"installation/#build-from-source","title":"Build from Source","text":"If you'd like to get the most recent changes, you can build SootUp from source yourself and install it into your local maven repository.
git clone https://github.com/secure-software-engineering/SootUp.git\nmvn install\n
"},{"location":"jimple-body/","title":"Jimple Body","text":"A SootMethod Body
consists of the Modifiers
and its StmtGraph
- SootUps Control Flow Graph Structure. The StmtGraph models the flow of Stmts.
Learn more about the types of Stmts.
"},{"location":"jimple-body/#traps","title":"Traps","text":"A Trap is a mechanism to model exceptional flow. A Trap represents the try-catch (finally) construct and therefore defines the type of the caught exception, the try-catch range (from-to) and the actual code that handles the exception (handler). In serialized(!) Jimple Labels are used to denote from,to and handler Stmts.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void divideExample(int, int)\n {\n int x, y, $stack4;\n java.io.PrintStream $stack5, $stack7;\n java.lang.Exception $stack6;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n y := @parameter1: int;\n\n label1:\n $stack5 = <java.lang.System: java.io.PrintStream out>;\n $stack4 = x / y;\n virtualinvoke $stack5.<java.io.PrintStream: void println(int)>($stack4);\n\n label2:\n goto label4;\n\n label3:\n $stack6 := @caughtexception;\n $stack7 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack7.<java.io.PrintStream: \n void println(java.lang.String)>(\"Exception caught\");\n\n label4:\n return;\n\n catch java.lang.Exception from label1 to label2 with label3;\n }\n}\n/*\n By calling getTraps() method, we can get the Traip chain.\n For the above jimple code, we have the below trap:\n Trap :\n begin : $stack5 = <java.lang.System: java.io.PrintStream out>\n end : goto [?= return]\n handler: $stack6 := @caughtexception\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void divideExample(int x, int y){\n try {\n System.out.println(x / y);\n }catch (Exception e){\n System.out.println(\"Exception caught\");\n }\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic divideExample(II)V\n TRYCATCHBLOCK L0 L1 L2 java/lang/Exception\n L0\n LINENUMBER 6 L0\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 1\n ILOAD 2\n IDIV\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L1\n LINENUMBER 9 L1\n GOTO L3\n L2\n LINENUMBER 7 L2\n FRAME SAME1 java/lang/Exception\n ASTORE 3\n L4\n LINENUMBER 8 L4\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Exception caught\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L3\n LINENUMBER 10 L3\n FRAME SAME\n RETURN\n L5\n LOCALVARIABLE e Ljava/lang/Exception; L4 L3 3\n LOCALVARIABLE this Land Ttarget/exercise1/DemoClass; L0 L5 0\n LOCALVARIABLE x I L0 L5 1\n LOCALVARIABLE y I L0 L5 2\n MAXSTACK = 3\n MAXLOCALS = 4\n}\n
"},{"location":"jimple-stmts/","title":"Jimple Stmt (\"Statement\")","text":"Stmts represent instructions of the JVM. Jimple is a 3-address form code so there are max 3 operands used in a (\"manipulating\") Stmt - i.e. this does not apply to invokes as this is just operand/parameter passing.
Stmts can be roughly grouped by the amount of successors (in the StmtGraph
of a Body
of a Method
).
FallsThroughStmt
has always one successor - it basically represents program counter++
.BranchingStmt
can have one, two or even n successors.A BranchingStmt's job is to model the jumps or conditional branching flow between Stmts.
"},{"location":"jimple-stmts/#jgotostmt","title":"JGotoStmt","text":"represents unconditional jumps to another Stmt.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n public static void sampleMethod()\n {\n int i;\n i = 0;\n\n label1:\n if i >= 5 goto label3;\n if i != 3 goto label2;\n goto label3;\n\n label2:\n i = i + 1;\n goto label1;\n\n label3:\n return;\n }\n}\n/*\n Here for statements \"goto label3;\" and \"goto label1;\", \n we have two instances of JGotoStmt : \n \"goto[?=return]\" and \"goto[?=(branch)]\".\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public static void sampleMethod(){\n label1:\n for (int i = 0; i < 5; i++){\n if(i == 3){\n break label1;\n }\n }\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x9\npublic static sampleMethod()V\n L0\n LINENUMBER 6 L0\n ICONST_0\n ISTORE 0\n L1\n FRAME APPEND [I]\n ILOAD 0\n ICONST_5\n IF_ICMPGE L2\n L3\n LINENUMBER 7 L3\n ILOAD 0\n ICONST_3\n IF_ICMPNE L4\n L5\n LINENUMBER 8 L5\n GOTO L2\n L4\n LINENUMBER 6 L4\n FRAME SAME\n IINC 0 1\n GOTO L1\n L2\n LINENUMBER 11 L2\n FRAME CHOP 1\n RETURN\n LOCALVARIABLE i I L1 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
"},{"location":"jimple-stmts/#jifstmt","title":"JIfStmt","text":"For conditional jumps depending on the result of the conditional expression AbstractConditionExpr
which needs to have boolean result. If the conditional expression is false, the next Stmt is the successor as the JIFStmt is also a FallsthroughStmt
. Therefore, the JIfStmt has two successor Stmt's.
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public static void sampleMethod(int)\n {\n int x, $stack1;\n java.io.PrintStream $stack2, $stack3;\n\n x := @parameter0: int;\n\n $stack1 = x % 2;\n if $stack1 != 0 goto label1;\n\n $stack3 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack3.<java.io.PrintStream: \n void println(java.lang.String)>(\"Even\");\n goto label2;\n\n label1:\n $stack2 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack2.<java.io.PrintStream: \n void println(java.lang.String)>(\"Odd\");\n\n label2:\n return;\n }\n}\n/*\n For statement \"if $stack1 != 0 goto label1;\", \n we have an instance of JIfStmt :\n \"if $stack1 != 0 goto $stack2 \n = <java.lang.System:java.io.PrintStream out>\".\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public static void sampleMethod(int x){\n if(x % 2 == 0){\n System.out.println(\"Even\");\n }else{\n System.out.println(\"Odd\");\n }\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x9\npublic static sampleMethod(I)V\n L0\n LINENUMBER 5 L0\n ILOAD 0\n ICONST_2\n IREM\n IFNE L1\n L2\n LINENUMBER 6 L2\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Even\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n GOTO L3\n L1\n LINENUMBER 8 L1\n FRAME SAME\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Odd\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L3\n LINENUMBER 10 L3\n FRAME SAME\n RETURN\n L4\n LOCALVARIABLE x I L0 L4 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
"},{"location":"jimple-stmts/#jswitchstmt","title":"JSwitchStmt","text":"for conditional flow that behaves like a switch-case. It has #numberOfCaseLabels+1 (for default) successor Stmt's.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void switchExample(int)\n {\n int x;\n java.io.PrintStream $stack2, $stack3, $stack4;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n\n lookupswitch(x)\n {\n case 1: goto label1;\n case 2: goto label2;\n default: goto label3;\n };\n\n label1:\n $stack3 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack3.<java.io.PrintStream: \n void println(java.lang.String)>(\"Input 1\");\n goto label4;\n\n label2:\n $stack2 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack2.<java.io.PrintStream: \n void println(java.lang.String)>(\"Input 2\");\n goto label4;\n\n label3:\n $stack4 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack4.<java.io.PrintStream: \n void println(java.lang.String)>(\"Input more than 2\");\n\n label4:\n return;\n }\n}\n/*\n Here for below statement:\n lookupswitch(x)\n {\n case 1: goto label1;\n case 2: goto label2;\n default: goto label3;\n };\n\n we have an instance of JLookupSwitchStmt :\n lookupswitch(x) \n { \n case 1: goto $stack3 \n = <java.lang.System: java.io.PrintStream out>; \n case 2: goto $stack2 \n = <java.lang.System: java.io.PrintStream out>; \n default: goto $stack4 \n = <java.lang.System: java.io.PrintStream out>; \n }\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void switchExample(int x){\n switch (x){\n case 1:\n System.out.println(\"Input 1\");\n break;\n\n case 2:\n System.out.println(\"Input 2\");\n break;\n\n default:\n System.out.println(\"Input more than 2\");\n break;\n\n }\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic switchExample(I)V\n L0\n LINENUMBER 5 L0\n ILOAD 1\n LOOKUPSWITCH\n 1: L1\n 2: L2\n default: L3\n L1\n LINENUMBER 7 L1\n FRAME SAME\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Input 1\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L4\n LINENUMBER 8 L4\n GOTO L5\n L2\n LINENUMBER 11 L2\n FRAME SAME\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Input 2\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L6\n LINENUMBER 12 L6\n GOTO L5\n L3\n LINENUMBER 15 L3\n FRAME SAME\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Input more than 2\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L5\n LINENUMBER 19 L5\n FRAME SAME\n RETURN\n L7\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L7 0\n LOCALVARIABLE x I L0 L7 1\n MAXSTACK = 2\n MAXLOCALS = 2\n}\n
"},{"location":"jimple-stmts/#fallsthrough-stmts","title":"FallsThrough Stmts","text":"The execution of a FallsthroughStmt goes on with the following Stmt (if no exception was thrown).
"},{"location":"jimple-stmts/#jinvokestmt","title":"JInvokeStmt","text":"transfers the control flow to another method until the called method returns.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void print(int)\n {\n target.exercise1.DemoClass this;\n int x, a;\n java.io.PrintStream $stack4, $stack6;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n\n a = virtualinvoke this.<target.exercise1.DemoClass: int increment(int)>(x);\n $stack4 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack4.<java.io.PrintStream: void println(int)>(a);\n\n a = virtualinvoke this.<target.exercise1.DemoClass: int increment(int)>(a);\n $stack6 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack6.<java.io.PrintStream: void println(int)>(a);\n\n return;\n }\n\n public int increment(int)\n {\n int x, $stack2;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n\n $stack2 = x + 1;\n return $stack2;\n }\n}\n/*\n \"specialinvoke this.<java.lang.Object: void <init>()>()\", \n \"virtualinvoke this.<target.exercise1.DemoClass: int increment(int)>(x)\", \n \"virtualinvoke this.<target.exercise1.DemoClass: int increment(int)>(a)\" \n are JInvokeStmts.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void print(int x){\n int a = increment(x);\n System.out.println(a);\n a = increment(a);\n System.out.println(a);\n }\n public int increment(int x){\n return x + 1;\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic print(I)V\n L0\n LINENUMBER 5 L0\n ALOAD 0\n ILOAD 1\n INVOKEVIRTUAL target/exercise1/DemoClass.increment (I)I\n ISTORE 2\n L1\n LINENUMBER 6 L1\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 2\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L2\n LINENUMBER 7 L2\n ALOAD 0\n ILOAD 2\n INVOKEVIRTUAL target/exercise1/DemoClass.increment (I)I\n ISTORE 2\n L3\n LINENUMBER 8 L3\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 2\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L4\n LINENUMBER 9 L4\n RETURN\n L5\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L5 0\n LOCALVARIABLE x I L0 L5 1\n LOCALVARIABLE a I L1 L5 2\n MAXSTACK = 2\n MAXLOCALS = 3\n\n// access flags 0x1\npublic increment(I)I\n L0\n LINENUMBER 11 L0\n ILOAD 1\n ICONST_1\n IADD\n IRETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n LOCALVARIABLE x I L0 L1 1\n MAXSTACK = 2\n MAXLOCALS = 2\n}\n
"},{"location":"jimple-stmts/#jassignstmt","title":"JAssignStmt","text":"assigns a Value from the right hand-side to the left hand-side. Left hand-side of an assignment can be a Local referencing a variable (i.e. a Local) or a FieldRef referencing a Field. Right hand-side of an assignment can be an expression (Expr), a Local, a FieldRef or a Constant.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n this.<target.exercise1.DemoClass: int counter> = 0;\n return;\n }\n\n public int updateCounter()\n {\n target.exercise1.DemoClass this;\n int $stack1, $stack2, $stack3;\n\n this := @this: target.exercise1.DemoClass;\n\n $stack1 = this.<target.exercise1.DemoClass: int counter>;\n $stack2 = $stack1 + 1;\n this.<target.exercise1.DemoClass: int counter> = $stack2;\n $stack3 = this.<target.exercise1.DemoClass: int counter>;\n\n return $stack3;\n }\n}\n/*\n \"this.<target.exercise1.DemoClass: int counter> = 0\", \n \"$stack1 = this.<target.exercise1.DemoClass: int counter>\",\n \"$stack2 = $stack1 + 1\"\n \"this.<target.exercise1.DemoClass: int counter> = $stack2\"\n \"$stack3 = this.<target.exercise1.DemoClass: int counter>\"\n are JAssignStmts.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n private int counter = 0;\n public int updateCounter(){\n counter = counter + 1;\n return counter;\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x2\nprivate I counter\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 4 L1\n ALOAD 0\n ICONST_0\n PUTFIELD target/exercise1/DemoClass.counter : I\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n\n// access flags 0x1\npublic updateCounter()I\n L0\n LINENUMBER 6 L0\n ALOAD 0\n ALOAD 0\n GETFIELD target/exercise1/DemoClass.counter : I\n ICONST_1\n IADD\n PUTFIELD target/exercise1/DemoClass.counter : I\n L1\n LINENUMBER 7 L1\n ALOAD 0\n GETFIELD target/exercise1/DemoClass.counter : I\n IRETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 3\n MAXLOCALS = 1\n}\n
"},{"location":"jimple-stmts/#jidentitystmt","title":"JIdentityStmt","text":"is similar to the JAssignStmt
and but handles assignments of IdentityRef
s to make implicit assignments explicit into the StmtGraph
.
Local
via JParameterRef
like @parameter0: int
refering to the first argument of the method (which is of Type int in this case).Local
via JCaughtExceptionRef
like @caughtexception: java.lang.NullpointerException
this
Variable to a Local
via a JThisRef
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void DemoClass(int)\n {\n target.exercise1.DemoClass this;\n int counter;\n\n this := @this: target.exercise1.DemoClass;\n counter := @parameter0: int;\n this.<target.exercise1.DemoClass: int counter> = counter;\n return;\n }\n}\n/*\n \"this := @this: target.exercise1.DemoClass\" and \n \"counter := @parameter0: int\" are JIdentityStmts\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n private int counter;\n public void DemoClass(int counter){\n this.counter = counter;\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x2\nprivate I counter\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic DemoClass(I)V\n L0\n LINENUMBER 6 L0\n ALOAD 0\n ILOAD 1\n PUTFIELD target/exercise1/DemoClass.counter : I\n L1\n LINENUMBER 7 L1\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n LOCALVARIABLE counter I L0 L2 1\n MAXSTACK = 2\n MAXLOCALS = 2\n}\n
"},{"location":"jimple-stmts/#jentermonitorstmt-jexitmonitorstmt","title":"JEnterMonitorStmt & JExitMonitorStmt","text":"marks synchronized blocks of code from JEnterMonitorStmt to JExitMonitorStmt.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n this.<target.exercise1.DemoClass: int counter> = 0;\n return;\n }\n\n public int updateCounter()\n {\n target.exercise1.DemoClass this;\n int $stack4, $stack5, $stack7;\n java.lang.Throwable $stack8;\n\n this := @this: target.exercise1.DemoClass;\n\n entermonitor this;\n\n label1:\n $stack4 = this.<target.exercise1.DemoClass: int counter>;\n $stack5 = $stack4 + 1;\n this.<target.exercise1.DemoClass: int counter> = $stack5;\n\n exitmonitor this;\n\n label2:\n goto label5;\n\n label3:\n $stack8 := @caughtexception;\n\n exitmonitor this;\n\n label4:\n throw $stack8;\n\n label5:\n $stack7 = this.<target.exercise1.DemoClass: int counter>;\n return $stack7;\n\n catch java.lang.Throwable from label1 to label2 with label3;\n catch java.lang.Throwable from label3 to label4 with label3;\n }\n}\n/*\n \"entermonitor this\" is JEnterMonitorStmt.\n \"exitmonitor this\" is JExitMonitorStmt.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n private int counter = 0;\n public int updateCounter(){\n synchronized (this) {\n counter = counter + 1;\n }\n return counter;\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x2\nprivate I counter\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 4 L1\n ALOAD 0\n ICONST_0\n PUTFIELD target/exercise1/DemoClass.counter : I\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n\n// access flags 0x1\npublic updateCounter()I\n TRYCATCHBLOCK L0 L1 L2 null\n TRYCATCHBLOCK L2 L3 L2 null\n L4\n LINENUMBER 6 L4\n ALOAD 0\n DUP\n ASTORE 1\n MONITORENTER\n L0\n LINENUMBER 7 L0\n ALOAD 0\n ALOAD 0\n GETFIELD target/exercise1/DemoClass.counter : I\n ICONST_1\n IADD\n PUTFIELD target/exercise1/DemoClass.counter : I\n L5\n LINENUMBER 8 L5\n ALOAD 1\n MONITOREXIT\n L1\n GOTO L6\n L2\n FRAME FULL [target/exercise1/DemoClass java/lang/Object] \n [java/lang/Throwable]\n ASTORE 2\n ALOAD 1\n MONITOREXIT\n L3\n ALOAD 2\n ATHROW\n L6\n LINENUMBER 9 L6\n FRAME CHOP 1\n ALOAD 0\n GETFIELD target/exercise1/DemoClass.counter : I\n IRETURN\n L7\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L4 L7 0\n MAXSTACK = 3\n MAXLOCALS = 3\n}\n
"},{"location":"jimple-stmts/#jretstmt","title":"JRetStmt","text":"// TODO: java 1.6 spec
"},{"location":"jimple-stmts/#jbreakpointstmt","title":"JBreakpointStmt","text":"models a Breakpoint set by a Debugger. Therefore, not really relevant for static analyses but useful for code generation.
"},{"location":"jimple-stmts/#other-stmts","title":"Other Stmts","text":""},{"location":"jimple-stmts/#jreturnstmt-jreturnvoidstmt","title":"JReturnStmt & JReturnVoidStmt","text":"They end the execution/flow inside the current method and return (a value) to its caller.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public int increment(int)\n {\n int x, $stack2;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n\n $stack2 = x + 1;\n return $stack2;\n }\n\n public void print()\n {\n java.io.PrintStream $stack1;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n $stack1 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack1.<java.io.PrintStream: \n void println(java.lang.String)>(\"Inside method print\");\n return;\n }\n}\n/*\n \"return $stack2\" is JReturnStmt.\n \"return\" is JReturnVoidStmt.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public int increment(int x){\n return x + 1;\n }\n public void print(){\n System.out.println(\"Inside method print\");\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic increment(I)I\n L0\n LINENUMBER 5 L0\n ILOAD 1\n ICONST_1\n IADD\n IRETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n LOCALVARIABLE x I L0 L1 1\n MAXSTACK = 2\n MAXLOCALS = 2\n\n// access flags 0x1\npublic print()V\n L0\n LINENUMBER 8 L0\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Inside method print\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L1\n LINENUMBER 9 L1\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
"},{"location":"jimple-stmts/#jthrowstmt","title":"JThrowStmt","text":"Ends the execution inside the current Method if the thrown exception is not caught by a Trap, which redirects the execution to an exceptionhandler.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void divideExample(int, int)\n {\n int y, x, $stack6;\n java.lang.StringBuilder $stack3, $stack5, $stack7;\n java.io.PrintStream $stack4;\n java.lang.String $stack8;\n java.lang.RuntimeException $stack9;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n x := @parameter0: int;\n y := @parameter1: int;\n\n if y != 0 goto label1;\n\n $stack9 = new java.lang.RuntimeException;\n specialinvoke $stack9.<java.lang.RuntimeException: \n void <init>(java.lang.String)>(\"Divide by zero error\");\n throw $stack9;\n\n label1:\n $stack4 = <java.lang.System: java.io.PrintStream out>;\n $stack3 = new java.lang.StringBuilder;\n specialinvoke $stack3.<java.lang.StringBuilder: void <init>()>();\n\n $stack5 = virtualinvoke $stack3.<java.lang.StringBuilder: \n java.lang.StringBuilder append(java.lang.String)>(\"Divide result : \");\n $stack6 = x / y;\n $stack7 = virtualinvoke $stack5.<java.lang.StringBuilder: \n java.lang.StringBuilder append(int)>($stack6);\n $stack8 = virtualinvoke $stack7.<java.lang.StringBuilder: \n java.lang.String toString()>();\n\n virtualinvoke $stack4.<java.io.PrintStream: \n void println(java.lang.String)>($stack8);\n return;\n }\n}\n/*\n \"throw $stack9\" is JThrowStmt.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void divideExample(int x, int y){\n if(y == 0){\n throw new RuntimeException(\"Divide by zero error\");\n }\n System.out.println(\"Divide result : \" + x / y);\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic divideExample(II)V\n L0\n LINENUMBER 5 L0\n ILOAD 2\n IFNE L1\n L2\n LINENUMBER 6 L2\n NEW java/lang/RuntimeException\n DUP\n LDC \"Divide by zero error\"\n INVOKESPECIAL java/lang/RuntimeException.<init> \n (Ljava/lang/String;)V\n ATHROW\n L1\n LINENUMBER 8 L1\n FRAME SAME\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n NEW java/lang/StringBuilder\n DUP\n INVOKESPECIAL java/lang/StringBuilder.<init> ()V\n LDC \"Divide result : \"\n INVOKEVIRTUAL java/lang/StringBuilder.append \n (Ljava/lang/String;)Ljava/lang/StringBuilder;\n ILOAD 1\n ILOAD 2\n IDIV\n INVOKEVIRTUAL java/lang/StringBuilder.append \n (I)Ljava/lang/StringBuilder;\n INVOKEVIRTUAL java/lang/StringBuilder.toString \n ()Ljava/lang/String;\n INVOKEVIRTUAL java/io/PrintStream.println \n (Ljava/lang/String;)V\n L3\n LINENUMBER 9 L3\n RETURN\n L4\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L4 0\n LOCALVARIABLE x I L0 L4 1\n LOCALVARIABLE y I L0 L4 2\n MAXSTACK = 4\n MAXLOCALS = 3\n}\n
"},{"location":"jimple-stmts/#good-to-know","title":"Good to know","text":"A lot of the SootUp APIs return the Stmt
Interface. To determine and handle its subtypes you can make use of instanceof.
List<Stmt> stmts = ... ;\n for( Stmt stms : stmts ){\n if(stmt instanceof JAssignStmt){\n // found a JAssignStmt\n Value rhsOp = ((JAssignStmt) stmt).getRightOp();\n ...\n }else if(stmt instanceof JInvokeStmt){\n // found a JInvokeStmt\n JInvokeStmt ivkStmt = ((JInvokeStmt) stmt);\n MethodSignature rhsOp = ivkStmt.getInvokeExpr().getMethodSignature();\n ...\n }else ...\n }\n
But this could escalate to a huge if-else-tree - almost a forest. To mitigate such scenario you can implement a subclass of AbstractStmtVisitor
. Just subclass the methods to the respective Stmts you need to handle. This is visitor acts like a switch-case, implemented via two dynamic calls.
List<Stmt> stmts = ...;\n AbstractStmtVisitor visitor = new AbstractStmtVisitor<Integer>() {\n private int ifStmtsCounter = 0;\n @Override\n public void caseIfStmt(@Nonnull JIfStmt stmt) {\n ifStmtsCounter++;\n setResult(ifStmtCounter);\n }\n };\n\n for( Stmt stms : stmts ){\n stmt.accept(visitor);\n }\n\n int amountOfIfStmts = visitor.getResult();\n
Sidenote: Of course its possible can create a subclass instead of an anonymous class.
"},{"location":"jimple-types/","title":"Jimple Types","text":"represents primary types i.e. non-reference types and non-void
"},{"location":"jimple-types/#primarytype","title":"PrimaryType","text":"BooleanType
ByteType
CharType
ShortType
IntType
LongType
DoubleType
FloatType
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n\n public void display()\n {\n java.io.PrintStream $stack11, $stack13, $stack15, \n $stack17, $stack19, $stack21, $stack23, $stack25;\n int $stack12, $stack14, $stack16, $stack18;\n long $stack20;\n double $stack22;\n float $stack24;\n target.exercise1.DemoClass this;\n boolean $stack26;\n\n this := @this: target.exercise1.DemoClass;\n\n $stack11 = <java.lang.System: java.io.PrintStream out>;\n\n goto label1;\n\n label1:\n $stack26 = 0;\n virtualinvoke $stack11.<java.io.PrintStream: \n void println(boolean)>($stack26);\n\n $stack13 = <java.lang.System: java.io.PrintStream out>;\n $stack12 = 127 - 1;\n virtualinvoke $stack13.<java.io.PrintStream: \n void println(int)>($stack12);\n\n $stack15 = <java.lang.System: java.io.PrintStream out>;\n $stack14 = 97 + 1;\n virtualinvoke $stack15.<java.io.PrintStream: \n void println(int)>($stack14);\n\n $stack17 = <java.lang.System: java.io.PrintStream out>;\n $stack16 = 1123 + 1;\n virtualinvoke $stack17.<java.io.PrintStream: \n void println(int)>($stack16);\n\n $stack19 = <java.lang.System: java.io.PrintStream out>;\n $stack18 = 123456 + 1;\n virtualinvoke $stack19.<java.io.PrintStream: \n void println(int)>($stack18);\n\n $stack21 = <java.lang.System: java.io.PrintStream out>;\n $stack20 = 10L + 1L;\n virtualinvoke $stack21.<java.io.PrintStream: \n void println(long)>($stack20);\n\n $stack23 = <java.lang.System: java.io.PrintStream out>;\n $stack22 = 10.1 + 1.0;\n virtualinvoke $stack23.<java.io.PrintStream: \n void println(double)>($stack22);\n\n $stack25 = <java.lang.System: java.io.PrintStream out>;\n $stack24 = 10.1F + 1.0F;\n virtualinvoke $stack25.<java.io.PrintStream: \n void println(float)>($stack24);\n\n return;\n }\n}\n/*\n The JimpleLocal $stack12, $stack14, $stack16, $stack18 are of IntType. \n Similarly, $stack20 is of LongType, $stack22 is of DoubleType and so on.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void display(){\n boolean varBoolean = true;\n byte varByte = 127;\n char varChar = 'a';\n short varShort = 1123;\n int varInt = 123456;\n long varLong = 10L;\n double varDouble = 10.10;\n float varFloat = 10.10f;\n\n System.out.println(!varBoolean);\n System.out.println(varByte-1);\n System.out.println(varChar+1);\n System.out.println(varShort+1);\n System.out.println(varInt+1);\n System.out.println(varLong+1);\n System.out.println(varDouble+1);\n System.out.println(varFloat+1);\n\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic display()V\n L0\n LINENUMBER 5 L0\n ICONST_1\n ISTORE 1\n L1\n LINENUMBER 6 L1\n BIPUSH 127\n ISTORE 2\n L2\n LINENUMBER 7 L2\n BIPUSH 97\n ISTORE 3\n L3\n LINENUMBER 8 L3\n SIPUSH 1123\n ISTORE 4\n L4\n LINENUMBER 9 L4\n LDC 123456\n ISTORE 5\n L5\n LINENUMBER 10 L5\n LDC 10\n LSTORE 6\n L6\n LINENUMBER 11 L6\n LDC 10.1\n DSTORE 8\n L7\n LINENUMBER 12 L7\n LDC 10.1\n FSTORE 10\n L8\n LINENUMBER 14 L8\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 1\n IFNE L9\n ICONST_1\n GOTO L10\n L9\n FRAME FULL [target/exercise1/DemoClass I I I I I J D F] \n [java/io/PrintStream]\n ICONST_0\n L10\n FRAME FULL [target/exercise1/DemoClass I I I I I J D F] \n [java/io/PrintStream I]\n INVOKEVIRTUAL java/io/PrintStream.println (Z)V\n L11\n LINENUMBER 15 L11\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 2\n ICONST_1\n ISUB\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L12\n LINENUMBER 16 L12\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 3\n ICONST_1\n IADD\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L13\n LINENUMBER 17 L13\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 4\n ICONST_1\n IADD\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L14\n LINENUMBER 18 L14\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 5\n ICONST_1\n IADD\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L15\n LINENUMBER 19 L15\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LLOAD 6\n LCONST_1\n LADD\n INVOKEVIRTUAL java/io/PrintStream.println (J)V\n L16\n LINENUMBER 20 L16\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n DLOAD 8\n DCONST_1\n DADD\n INVOKEVIRTUAL java/io/PrintStream.println (D)V\n L17\n LINENUMBER 21 L17\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n FLOAD 10\n FCONST_1\n FADD\n INVOKEVIRTUAL java/io/PrintStream.println (F)V\n L18\n LINENUMBER 23 L18\n RETURN\n L19\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L19 0\n LOCALVARIABLE varBoolean Z L1 L19 1\n LOCALVARIABLE varByte B L2 L19 2\n LOCALVARIABLE varChar C L3 L19 3\n LOCALVARIABLE varShort S L4 L19 4\n LOCALVARIABLE varInt I L5 L19 5\n LOCALVARIABLE varLong J L6 L19 6\n LOCALVARIABLE varDouble D L7 L19 8\n LOCALVARIABLE varFloat F L8 L19 10\n MAXSTACK = 5\n MAXLOCALS = 11\n}\n
"},{"location":"jimple-types/#referencetype","title":"ReferenceType","text":"(Java)ClassType
- represents the type of a Class.ArrayType
- represents an array.NullType
- assignable to one of the other ReferenceTypes.public class target.exercise1.DemoClass extends java.lang.Object\n{\npublic void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public target.exercise1.DemoClass getObject(target.exercise1.DemoClass)\n {\n target.exercise1.DemoClass obj, this;\n this := @this: target.exercise1.DemoClass;\n obj := @parameter0: target.exercise1.DemoClass;\n return obj;\n }\n\n public void compute(boolean)\n {\n int[] b;\n java.io.PrintStream $stack5, $stack6;\n boolean check;\n target.exercise1.DemoClass this;\n int i;\n null_type r0;\n java.lang.NullPointerException soot0;\n this := @this: target.exercise1.DemoClass;\n check := @parameter0: boolean;\n b = newarray (int)[5];\n i = 0;\n\n label1:\n if i >= 5 goto label3;\n if check == 0 goto label2;\n r0 = (null_type) i;\n soot0 = new java.lang.NullPointerException;\n specialinvoke soot0.<java.lang.NullPointerException: \n void <init>(java.lang.String)>\n (\"This statement would have triggered an Exception: a[i#1] = r0\");\n throw soot0;\n\n label2:\n b[i] = i;\n i = i + 1;\n goto label1;\n\n label3:\n $stack5 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack5.<java.io.PrintStream: \n void println(java.lang.Object)>(b);\n $stack6 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack6.<java.io.PrintStream: \n void println(java.lang.Object)>(null);\n return;\n }\n}\n/*\n The Local b is of ArrayType,\n and Local r0 is of NullType.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n\n public DemoClass getObject(DemoClass obj){\n return obj;\n }\n\n public void compute(boolean check){\n int a[] = null;\n int b[] = new int[5];\n for (int i = 0; i < 5; i++) {\n if(check){\n a[i] = i;\n }\n b[i] = i;\n }\n System.out.println(b);\n System.out.println(a);\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic getObject(Ltarget/exercise1/DemoClass;)Ltarget/exercise1/DemoClass;\n L0\n LINENUMBER 6 L0\n ALOAD 1\n ARETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n LOCALVARIABLE obj Ltarget/exercise1/DemoClass; L0 L1 1\n MAXSTACK = 1\n MAXLOCALS = 2\n\n// access flags 0x1\npublic compute(Z)V\n L0\n LINENUMBER 10 L0\n ACONST_NULL\n ASTORE 2\n L1\n LINENUMBER 11 L1\n ICONST_5\n NEWARRAY T_INT\n ASTORE 3\n L2\n LINENUMBER 12 L2\n ICONST_0\n ISTORE 4\n L3\n FRAME APPEND [[I [I I]\n ILOAD 4\n ICONST_5\n IF_ICMPGE L4\n L5\n LINENUMBER 13 L5\n ILOAD 1\n IFEQ L6\n L7\n LINENUMBER 14 L7\n ALOAD 2\n ILOAD 4\n ILOAD 4\n IASTORE\n L6\n LINENUMBER 16 L6\n FRAME SAME\n ALOAD 3\n ILOAD 4\n ILOAD 4\n IASTORE\n L8\n LINENUMBER 12 L8\n IINC 4 1\n GOTO L3\n L4\n LINENUMBER 18 L4\n FRAME CHOP 1\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ALOAD 3\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V\n L9\n LINENUMBER 19 L9\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ALOAD 2\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V\n L10\n LINENUMBER 20 L10\n RETURN\n L11\n LOCALVARIABLE i I L3 L4 4\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L11 0\n LOCALVARIABLE check Z L0 L11 1\n LOCALVARIABLE a [I L1 L11 2\n LOCALVARIABLE b [I L2 L11 3\n MAXSTACK = 3\n MAXLOCALS = 5\n}\n
"},{"location":"jimple-types/#voidtype","title":"VoidType","text":"Used as a possible return type of a method.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void voidMethod()\n {\n java.io.PrintStream $stack1;\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n $stack1 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack1.<java.io.PrintStream: \n void println(java.lang.String)>(\"In voidMethod().\");\n return;\n }\n}\n/*\n For the SootMethod - <target.exercise1.DemoClass: void voidMethod()>, \n returnType is instance of VoidType.\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n public void voidMethod(){\n System.out.println(\"In voidMethod().\");\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic voidMethod()V\n L0\n LINENUMBER 5 L0\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"In voidMethod().\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L1\n LINENUMBER 6 L1\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
"},{"location":"jimple-values/","title":"Jimple Values","text":""},{"location":"jimple-values/#immediate","title":"Immediate","text":"An Immediate
has a given Type and consists of a Local (\"a Variable\", \"Something that contains a Value\") or a Constant (\"Something that is a Value\").
i0 \n
A Local is a variable and its scope is inside its method i.e. no referencing from outside a method. Values can be assigned to Locals via JIdentityStmt or JAssignStmt.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n\n public void compute()\n {\n java.io.PrintStream $stack2, $stack3;\n target.exercise1.DemoClass this;\n int local2;\n\n this := @this: target.exercise1.DemoClass;\n $stack2 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack2.<java.io.PrintStream: void println(int)>(1);\n\n local2 = this.<target.exercise1.DemoClass: int global>;\n $stack3 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack3.<java.io.PrintStream: void println(int)>(local2);\n return;\n }\n}\n/*\n $stack2, this, $stack3, local2 are all Locals.\n\n \"this := @this: target.exercise1.DemoClass\" is a JIdentityStmt assigning to a Local.\n\n \"$stack2 = <java.lang.System: java.io.PrintStream out>\", \n \"local2 = this.<target.exercise1.DemoClass: int global>\", \n \"$stack3 = <java.lang.System: java.io.PrintStream out>\" \n are JAssignStmts assigning to a Local.\n\n*/ \n
package target.exercise1;\n\npublic class DemoClass {\n\n private int global;\n\n public void compute(){\n int local;\n local = 1;\n System.out.println(local);\n local = this.global;\n System.out.println(local);\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x2\nprivate I global\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic compute()V\n L0\n LINENUMBER 9 L0\n ICONST_1\n ISTORE 1\n L1\n LINENUMBER 10 L1\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 1\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L2\n LINENUMBER 11 L2\n ALOAD 0\n GETFIELD target/exercise1/DemoClass.global : I\n ISTORE 1\n L3\n LINENUMBER 12 L3\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n ILOAD 1\n INVOKEVIRTUAL java/io/PrintStream.println (I)V\n L4\n LINENUMBER 14 L4\n RETURN\n L5\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L5 0\n LOCALVARIABLE local I L1 L5 1\n MAXSTACK = 2\n MAXLOCALS = 2\n}\n
"},{"location":"jimple-values/#constant","title":"Constant","text":"represents an actual value itself like 42
or \"This is a String\"
. Constants are usually assigned to Local
s or Ref
s. There exists a constant entity for every Primitive Type.
An expression is a language construct that calculates an operation and returns a value. E.g. a binary operation AbstracBinopExpr
such as an addition a + b
, an AbstractInvokeExpr
such as virtualinvoke $stack2.<java.io.PrintStream: void println(int)>(1);
or an UnaryExpr
such as !valid
. And a bunch more!
$arr[1] = 42;\n$anotherLocal = arr[99];\n
referencing an array position."},{"location":"jimple-values/#jfieldref","title":"JFieldRef","text":"JFieldRef
s are referencing a SootField
via its FieldSignature
JStaticFieldRef
like <SomePackage.ExampleClass: fieldname>
JInstanceFieldRef
like r1.<SomePackage.ExampleClass: fieldname>
You can see the JInstanceFieldRef has the corresponding Local instance that points to the instance of the object which is holding the field.The IdentityRef makes those implicit special value assignments explicit.
"},{"location":"jimple-values/#jthisref","title":"JThisRef","text":"@this: package.fruit.Banana\n
represents the this pointer of the current class."},{"location":"jimple-values/#jcaughtexceptionref","title":"JCaughtExceptionRef","text":"@caughtexception\n
represents the value of the thrown exception (caught by this exceptionhandler)."},{"location":"jimple-values/#jparameterref","title":"JParameterRef","text":"i0 := @parameter0\ni1 := @parameter1 \n
represents a parameter of a method, identified by its index."},{"location":"jimple-values/#good-to-know","title":"Good to know","text":"A lot of the SootUp APIs return the Value
Interface. To determine and handle its subtypes you can make use of instanceof.
Value op = assignStmt.getRightOp();\n if(op instanceof Local){\n // found a Local\n ...\n }else if(stmt instanceof Constant){\n // found a Constant\n ...\n }else ...\n
But this could escalate to a huge if-else-tree - almost a forest. To mitigate such scenario you can implement a subclass of AbstractValueVisitor
. Just subclass the methods to the respective Value
s you need to handle. This is visitor acts like a switch-case, implemented via two dynamic calls.
Value op = assignStmt.getRightOp() ;\n AbstractValueVisitor visitor = new AbstractValueVisitor<Integer>() {\n private int intConstantCounter = 0;\n @Override\n public void caseConstant(@Nonnull Constant c) {\n intConstantCounter++;\n setResult(intConstantCounter);\n }\n };\n\n op.accept(visitor);\n int amountOfIfStmts = visitor.getResult();\n
If you only need a visitor for a subset of Value, you can consider ImmediateVisitor, ConstantVisitor, ExprVisitor, RefVisitor. Sidenote: Of course its possible can create a subclass instead of an anonymous class.
"},{"location":"jimple/","title":"Jimple","text":"What is Jimple? Jimple is the intermediate representation IR of Soot, and thus SootUp. Soot's intention is to provide a simplified way to analyze JVM bytecode. JVM bytecode is stack-based, which makes it difficult for program analysis. Java source code, on the other hand, is also not quite suitable for program analysis, due to its nested structures. Therefore, Jimple aims to bring the best of both worlds, a non-stack-based and flat (non-nested) representation. For this purpose Jimple was designed as a representation of JVM bytecode which is human readable.
Info
To learn more about jimple, refer to the thesis by Raja Vallee-Rai.
Lets have a look at the following Jimple code representing Java code of a HelloWorld
class.
public class HelloWorld extends java.lang.Object\n{\n public void <init>()\n {\n HelloWorld r0;\n r0 := @this: HelloWorld;\n specialinvoke r0.<java.lang.Object: void <init>()>();\n return;\n }\n\n public static void main(java.lang.String[])\n {\n java.lang.String[] r0;\n java.io.PrintStream r1;\n\n r0 := @parameter0: java.lang.String[];\n r1 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke r1.<java.io.PrintStream: \n void println(java.lang.String)>(\"Hello world!\");\n return;\n }\n}\n
public class HelloWorld {\n\n public HelloWorld() {\n\n }\n\n public static void main(String[] var0) {\n System.out.println(\"Hello World!\");\n }\n\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class analysis/HelloWorld {\n\n// compiled from: HelloWorld.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 4 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 6 L1\n RETURN\n L2\n LOCALVARIABLE this Lanalysis/HelloWorld; L0 L2 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x9\npublic static main([Ljava/lang/String;)V\n L0\n LINENUMBER 9 L0\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Hello World!\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L1\n LINENUMBER 10 L1\n RETURN\n L2\n LOCALVARIABLE var0 [Ljava/lang/String; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
The Java Sourcecode is the easiest representation - So why all the fuzz and just use that? Sometimes we have no access to the sourcecode but have a binary with the bytecode. For most People reading bytecode is not that intuitive. So SootUp generates Jimple from the bytecode. Jimple is very verbose, but makes everything explicit, that the JVM does implicitly and transforms the stack-machine strategy by a register-machine strategy i.e. Variable (Local
) handling .
Jimple mimics the JVMs class file structure. Therefore it is object oriented. A Single Class (or Interface) per file. Three-Address-Code which means there are no nested expressions. (nested expressions can be modeled via Locals that store intermediate calculation results.)
"},{"location":"jimple/#signatures-and-classtypes","title":"Signatures and ClassTypes","text":"Signatures are used to identify Classes,Methods or Fields uniquely/globally. Sidenote: Locals, do not have a signature, since they are referenced within method boundaries.
JimpleJavaBytecodepublic class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n\n specialinvoke this.<java.lang.Object: void <init>()>();\n this.<target.exercise1.DemoClass: double pi> = 3.14;\n return;\n }\n\n public void demoMethod()\n {\n java.io.PrintStream $stack3, $stack5;\n java.lang.StringBuilder $stack4, $stack6, $stack7;\n java.lang.String $stack8;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n $stack3 = <java.lang.System: java.io.PrintStream out>;\n\n virtualinvoke $stack3.<java.io.PrintStream: \n void println(java.lang.String)>(\"pi : 3.14\");\n $stack5 = <java.lang.System: java.io.PrintStream out>;\n $stack4 = new java.lang.StringBuilder;\n\n specialinvoke $stack4.<java.lang.StringBuilder: void <init>()>();\n $stack6 = virtualinvoke $stack4.<java.lang.StringBuilder: \n java.lang.StringBuilder append(java.lang.String)>\n (\"pi : \");\n $stack7 = virtualinvoke $stack6.<java.lang.StringBuilder: \n java.lang.StringBuilder append(double)>(3.1415);\n $stack8 = virtualinvoke $stack7.<java.lang.StringBuilder: \n java.lang.String toString()>();\n\n virtualinvoke $stack5.<java.io.PrintStream: \n void println(java.lang.String)>($stack8);\n return;\n }\n}\n/*\n For JInstanceFieldRef \"this.<target.exercise1.DemoClass: double pi>\" \n signature is <target.exercise1.DemoClass: double pi>\n Similarly, we have other signatures like \n <java.lang.Object: void <init>()>, \n <java.io.PrintStream: void println(java.lang.String)> \n and so on. \n*/\n
package target.exercise1;\n\npublic class DemoClass {\n private final double pi = 3.14;\n\n public void demoMethod(){\n double localPi = 3.1415;\n System.out.println(\"pi : \" + pi);\n System.out.println(\"pi : \" + localPi);\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x12\nprivate final D pi = 3.14\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 4 L1\n ALOAD 0\n LDC 3.14\n PUTFIELD target/exercise1/DemoClass.pi : D\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 3\n MAXLOCALS = 1\n\n// access flags 0x1\npublic demoMethod()V\n L0\n LINENUMBER 6 L0\n LDC 3.1415\n DSTORE 1\n L1\n LINENUMBER 7 L1\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"pi : 3.14\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L2\n LINENUMBER 8 L2\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n NEW java/lang/StringBuilder\n DUP\n INVOKESPECIAL java/lang/StringBuilder.<init> ()V\n LDC \"pi : \"\n INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)\n Ljava/lang/StringBuilder;\n DLOAD 1\n INVOKEVIRTUAL java/lang/StringBuilder.append (D)Ljava/lang/StringBuilder;\n INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L3\n LINENUMBER 9 L3\n RETURN\n L4\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L4 0\n LOCALVARIABLE localPi D L1 L4 1\n MAXSTACK = 4\n MAXLOCALS = 3\n}\n
"},{"location":"jimple/#sootclass","title":"SootClass","text":"A SootClass
consists of SootFields and SootMethods. It is referenced by its global identifier the ClassType
like java.lang.String
.
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n return;\n }\n}\n
package target.exercise1;\n\npublic class DemoClass {}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n RETURN\n L1\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0\n MAXSTACK = 1\n MAXLOCALS = 1\n}\n
"},{"location":"jimple/#sootfield","title":"SootField","text":"A SootField is a piece of memory which can store a value that is accessible according to its visibility modifier. It is referenced by its FieldSignature like <java.lang.String: int hash>
.
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n this.<target.exercise1.DemoClass: double pi> = 3.14;\n return;\n }\n}\n/*\n \"this.<target.exercise1.DemoClass: double pi>\" is JInstanceFieldRef\n*/\n
package target.exercise1;\n\npublic class DemoClass {\n private final double pi = 3.14;\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x12\nprivate final D pi = 3.14\n\n// access flags 0x1\npublic <init>()V\n L0\n LINENUMBER 3 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 4 L1\n ALOAD 0\n LDC 3.14\n PUTFIELD target/exercise1/DemoClass.pi : D\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 3\n MAXLOCALS = 1\n}\n
"},{"location":"jimple/#sootmethod-and-its-body","title":"SootMethod and its Body","text":"The interesting part is a method. A method is a \"piece of code\" that can be executed. It is referenced by its MethodSignature like <java.lang.Object: java.lang.String toString()>
.
public class target.exercise1.DemoClass extends java.lang.Object\n{\n public void <init>()\n {\n target.exercise1.DemoClass this;\n this := @this: target.exercise1.DemoClass;\n specialinvoke this.<java.lang.Object: void <init>()>();\n virtualinvoke this.<target.exercise1.DemoClass: \n void demoMethod()>();\n return;\n }\n\n public void demoMethod()\n {\n java.io.PrintStream $stack1;\n target.exercise1.DemoClass this;\n\n this := @this: target.exercise1.DemoClass;\n $stack1 = <java.lang.System: java.io.PrintStream out>;\n\n virtualinvoke $stack1.<java.io.PrintStream: \n void println(java.lang.String)>(\"Inside method.\");\n return;\n }\n}\n/*\n \"<target.exercise1.DemoClass: void demoMethod()>\" \n and \"<target.exercise1.DemoClass: void <init>()>\" \n are instances of SootMethod \n*/\n
package target.exercise1;\n\npublic class DemoClass {\n DemoClass(){\n demoMethod();\n }\n public void demoMethod(){\n System.out.println(\"Inside method.\");\n }\n}\n
// class version 52.0 (52)\n// access flags 0x21\npublic class target/exercise1/DemoClass {\n\n// compiled from: DemoClass.java\n\n// access flags 0x0\n<init>()V\n L0\n LINENUMBER 5 L0\n ALOAD 0\n INVOKESPECIAL java/lang/Object.<init> ()V\n L1\n LINENUMBER 6 L1\n ALOAD 0\n INVOKEVIRTUAL target/exercise1/DemoClass.demoMethod ()V\n L2\n LINENUMBER 7 L2\n RETURN\n L3\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L3 0\n MAXSTACK = 1\n MAXLOCALS = 1\n\n// access flags 0x1\npublic demoMethod()V\n L0\n LINENUMBER 10 L0\n GETSTATIC java/lang/System.out : Ljava/io/PrintStream;\n LDC \"Inside method.\"\n INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V\n L1\n LINENUMBER 11 L1\n RETURN\n L2\n LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0\n MAXSTACK = 2\n MAXLOCALS = 1\n}\n
More about the Body of the SootMethod.
"},{"location":"migrating/","title":"Migration Help","text":""},{"location":"migrating/#version-130","title":"Version 1.3.0","text":"Stream<ClassType>
instead of Collection<ClassType>
. The simplest fix to have the same behaviour as before would be to collect the Stream on your own ( e.g. via .collect(Collectors.toList())
).Below we show a comparison of the code so far with the same functionality in sootup.
SootUpSootAnalysisInputLocation<JavaSootClass> inputLocation =\nnew JavaClassPathAnalysisInputLocation(\"path2Binary\");\n\nJavaView view = new JavaView(inputLocation);\n\nJavaClassType classType = \n view.getIdentifierFactory().getClassType(\"HelloWorld\");\n\nMethodSignature methodSignature =\n view\n .getIdentifierFactory()\n .getMethodSignature(\n \"main\", classType, \"void\",\n Collections.singletonList(\"java.lang.String[]\"));\n\nJavaSootClass sootClass = view.getClass(classType).get();\n\nMethodSubSignature mss = methodSignature.getSubSignature();\nJavaSootMethod sootMethod = sootClass.getMethod(mss).get();\n\nsootMethod.getBody().getStmts();\n
G.reset();\nString userdir = System.getProperty(\"user.dir\");\nString sootCp = \n userdir \n + File.separator \n + \"target\" \n + File.separator \n + \"test-classes\"\n + File.pathSeparator + \"lib\"+File.separator+\"rt.jar\";\n\nOptions.v().set_soot_classpath(sootCp);\nOptions.v().set_whole_program(true);\nOptions.v().setPhaseOption(\"cg.cha\", \"on\");\nOptions.v().setPhaseOption(\"cg\", \"all-reachable:true\");\nOptions.v().set_no_bodies_for_excluded(true);\nOptions.v().set_allow_phantom_refs(true);\nOptions.v().setPhaseOption(\"jb\", \"use-original-names:true\");\nOptions.v().set_prepend_classpath(false);\n\nScene.v().addBasicClass(\"java.lang.StringBuilder\");\nSootClass c = \n Scene.v().forceResolve(targetTestClassName, SootClass.BODIES);\nif (c != null) {\n c.setApplicationClass();\n}\nScene.v().loadNecessaryClasses();\n\nSootMethod method;\nfor (SootClass c : Scene.v().getApplicationClasses()) {\n if(c.getName().equals(\"example.HelloWorld\")){\n for (SootMethod m : c.getMethods()) {\n if (!m.hasActiveBody()) {\n continue;\n }\n if (m.getName().equals(\"entryPoint\")) {\n method = m;\n break;\n }\n }\n }\n}\n\nmethod.getActiveBody().getUnits();\n
"},{"location":"qilin/","title":"Incorporate Qilin Pointer Analysis","text":""},{"location":"qilin/#dependencies","title":"Dependencies","text":"MavenGradle <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.java.sourcecode</artifactId>\n <version>1.3.0</version>\n</dependency>\n
compile \"org.soot-oss:sootup.qilin:1.3.0\"\n
"},{"location":"qilin/#how-to-create-a-pointer-analysis","title":"How to create a pointer analysis","text":"WIP: Beware most likely the API will change so you only need to specify SootUp objects!
One can create an Andersen's context-insensitive analysis with following code:
JavaString entrypoint = \"dacapo.antlr.Main\";\nPTAPattern ptaPattern = new PTAPattern(\"insens\");\nPTA pta = PTAFactory.createPTA(ptaPattern, view, entrypoint);\npta.run();\n
Users must specify the program's View
, select a PTAPattern
(indicating the desired types of pointer analyses to perform), and designate the entrypoint
- which is serving as the entry point for the analysis.
First, we can use Qilin's pointer analysis to get a On-the-Fly constructed callgraph:
OnFlyCallGraph cg = pta.getCallGraph();\n
Second, we can use it to get the points-to results for some interested local variables, fields, etc.
PointsToSet pts0 = pta.reachingObjects(method, v0);\nPointsToSet pts1 = pta.reachingObjects(method, v1, f); // PTS(v1.f)\n
Third, we can check whether two variables, a
and b
, are aliases by checking whether there is an object that exists in both of their points-to sets.
Qilin does not currently offer a isMayAlias
API within the PTA class. However, a similar functionality can be found in qilin.test.util.AliasAssertion
with the method: boolean isMayAlias(PTA pta, Value va, Value vb)
This method allows to check for potential aliasing between two values given a PTA instance.
Qilin's toolbox includes a rich set of pointer analyses, which are given below:
Note that the symbol k used in the table should be replaced with a concrete small constant like 1 or 2.
PTA patterns Description Reference insens Andersen's context-insensitive analysis Paper kc k-callsite-sensitive pointer analysis (denoted kCFA). Paper ko k-object-sensitive pointer analysis (denoted kOBJ). Paper kt k-type-sensitive pointer analysis (denoted kTYPE). Paper kh hybrid k-object-sensitive pointer analysis. Paper kht hybrid k-type-sensitive pointer analysis. Paper B-2o BEAN-guided 2OBJ. Only k=2 is supported. Paper D-2o Data-driven 2OBJ. Only k=2 is supported. Paper D-2c Data-driven 2CFA. Only k=2 is supported. Paper M-ko MAHJONG-guided kOBJ. Paper M-kc MAHJONG-guided kCFA. Paper E-ko EAGLE-guided kOBJ. Paper T-ko TURNER-guided kOBJ. Paper Z-ko ZIPPER-guided kOBJ. Paper Z-kc ZIPPER-guided kCFA. Paper Z-ko -cd The context debloated version of ZIPPER-guided kOBJ. Paper ko -cd -cda=CONCH The context debloated version of kOBJ using Conch. Paper ko -cd -cda=DEBLOATERX The context debloated version of kOBJ using DebloaterX. Paper s-kc SELECTX-guided kCFA. Paper"},{"location":"tool_setup/","title":"From Prototype to an intuitive Tool","text":"How was the parameter order again? For a lot of cli tools we see an arbitrary order of cli parameters, different options for giving a working directory etc.. So in the wild you can see a lot from run.sh/run.bat to make files just to reorder arguments to execute a tool.
In SootUp we thought we could help on improving this madness while saving your time.
The command line parser mimics the options the java executable accepts - at least for what is supported by SootUp. This makes it very simple to just copy the execution paramaters you use for execution, to use them more or less as is four the analysis tool.
"},{"location":"tool_setup/#dependencies","title":"Dependencies","text":"MavenGradle<dependency>\n <groupId>commons-cli</groupId>\n <artifactId>commons-cli</artifactId>\n <version>1.8.0</version>\n</dependency>\n
implementation(\"commons-cli:commons-cli:1.8.0\")\n
"},{"location":"tool_setup/#java-code","title":"Java Code","text":"```java\n\nclass SootUpConfiguration{\n // TODO incorporate from downstream\n}\n\n```\n
We are happy if you steal the following code to create a tool where the setup is just simple.
"},{"location":"tools/","title":"Who uses SootUp","text":"The TypeHierarchy models the relationship of Classes or Interfaces of a OOP program.
"},{"location":"typehierarchy/#creating-typehierarchy","title":"Creating TypeHierarchy","text":"SootUpSootString cpString = \"src/test/resources/Callgraph/binary\";\nList<AnalysisInputLocation> inputLocations = new ArrayList();\ninputLocations.add(new JavaClassPathAnalysisInputLocation(cpStr));\ninputLocations.add(new DefaultRuntimeAnalysisInputLocation());\n\nJavaView view = new JavaView(inputLocations);\nTypeHierarchy typehierarchy = view.getTypeHierarchy();\n
String userdir = System.getProperty(\"user.dir\");\nString sootCp = userdir + File.separator + \"target\" + File.separator + \"test-classes\"+ File.pathSeparator + \"lib\"+File.separator+\"rt.jar\";\n\nString targetTestClassName = target.exercise1.Hierarchy.class.getName();\nG.reset();\nOptions.v().set_whole_program(true);\nOptions.v().set_soot_classpath(sootCp);\nOptions.v().set_no_bodies_for_excluded(true);\nOptions.v().process_dir();\nOptions.v().set_allow_phantom_refs(true);\nOptions.v().setPhaseOption(\"jb\", \"use-original-names:true\");\nOptions.v().set_prepend_classpath(false);\nSootClass c = Scene.v().forceResolve(targetTestClassName, SootClass.BODIES);\nif (c != null)\n c.setApplicationClass();\nScene.v().loadNecessaryClasses();\n\nHierarchy hierarchy = new Hierarchy();\n
"},{"location":"typehierarchy/#create-a-javaclasstype","title":"Create a JavaClassType","text":"SootUpSoot JavaClassType classTypeA = view.getIdentifierFactory().getClassType(\"packageName.A\");\nJavaClassType classTypeB = view.getIdentifierFactory().getClassType(\"packageName.B\");\nJavaClassType classTypeC = view.getIdentifierFactory().getClassType(\"packageName.C\");\n
String targetTestClassName = \"packageNameA.A\";\nSootClass methodA = Scene.v().getSootClass(targetTestClassName);\n
"},{"location":"typehierarchy/#query-the-typehierarchy","title":"Query the TypeHierarchy","text":""},{"location":"typehierarchy/#classes","title":"Classes","text":" // if the assertion fails, the following methods will throw an Exception (you don't have to call it - it's just to illustrate the assumption)\n assert typehierarchy.contains(classTypeA);\n\n typehierarchy.superclassOf(classTypeA);\n\n typehierarchy.subclassesOf(classTypeA);\n\n typehierarchy.isSubtypeOf(classTypeA, classTypeB);\n
"},{"location":"typehierarchy/#interfaces","title":"Interfaces","text":" JavaClassType iterableInterface = view.getIdentifierFactory().getClassType(\"java.lang.Iterable\");\n\n // if any of the assertions fail, the following methods will throw an Exception (you don't have to call these - it's just to illustrate the assumptions)\n assert typehierarchy.contains(iterableInterface);\n assert typehierarchy.isInterface(iterableInterface);\n\n // transitive relations as well\n typehierarchy.implementedInterfacesOf(iterableInterface);\n typehierarchy.implementersOf(iterableInterface);\n\n // only the direct related relations\n typehierarchy.directlyImplementedInterfacesOf(iterableInterface);\n typehierarchy.directlyExtendedInterfacesOf(iterableInterface);\n
"},{"location":"whatsnew/","title":"What's new in SootUp?","text":""},{"location":"whatsnew/#library-by-default","title":"Library by default","text":"While Soot is a library and a stand-alone command-line application. SootUp, on the other hand, is designed to be a core library. It assumes that it is embedded in a client application that owns the thread of control. It can be extended with a command-line interface, included in other software projects as a library, or integrated into IDEs with JimpleLSP.
"},{"location":"whatsnew/#modular-architecture","title":"Modular Architecture","text":"SootUp has a modular architecture, which enables its clients to include only the necessary functionality to their applications.
Singletons offer a single view of a single program version, which makes it impossible to analyze multiple programs or multiple versions of the same program. SootUp does not make use of singletons such the Scene
class in the old Soot any more. It enables analyzing multiple programs simultaneously.
Soot's JastAdd-based java frontend is not maintained anymore. In SootUp, we use WALA's well-maintained source code frontend, which will not only allow Soot to analyze Java source code, but also JavaScript and Python.
"},{"location":"whatsnew/#immutable-by-design","title":"Immutable by Design","text":"SootUp has been designed with the goal of immutability in mind. This makes sharing objects between several entities easier, because there is no need to worry about unintended changes to other entities.
"},{"location":"whatsnew/#withers-instead-of-setters","title":"Withers instead of Setters","text":"Due to the goal of immutability, many classes do not have setters anymore. For example, a Body
does not have a method setStmts(List<Stmt> stmts)
. Instead, a method called withStmts(List<Stmt> stmts)
has been added. This does not modify the original instance, but returns a copy of the Body but with the provided stmts
in its instance. This concept of so-called with
-ers can be found all throughout SootUp.
A simplified example
class Body {\n final List<Stmt> stmts;\n final List<Local> locals;\n\n Body(List<Stmt> stmts, List<Local> locals) {\n this.stmts = stmts;\n this.locals = locals;\n } \n\n Body withStmts(List<Stmt> stmts) { return new Body(stmts, this.locals); }\n Body withLocals(List<Local> locals) { return new Body(this.stmts, locals); }\n}\n
"},{"location":"whatsnew/#intermediate-representation","title":"Intermediate Representation","text":"Jimple is the only intermediate representation (IR) in SootUp. We modified it slightly to be able to accommodate different programming languages in the future.
"},{"location":"write_analyses/","title":"Write your own Interprocedural Dataflow Analysis","text":""},{"location":"write_analyses/#dependencies","title":"Dependencies","text":"MavenGradle<dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.analysis</artifactId>\n <version></version>\n</dependency>\n
compile \"org.soot-oss:sootup.analysis:1.3.0\"\n
"},{"location":"write_analyses/#useful-knowledge","title":"Useful Knowledge","text":"Background Knowledge as online lectures are available on YouTube.
Taint Analysis, TypeState Analysis, Linear Constant Propagation, ...
// TODO incorporate & guide through examples\n\nIn the meantime please have a look into the test cases of the\nanalysis submodule to see example implementations of interprocedural\ndata-flow analysis via the IFDS or IDE Framework.\n
"}]}
\ No newline at end of file