diff --git a/_preview/404.html b/_preview/404.html deleted file mode 100644 index 7dff33e4839..00000000000 --- a/_preview/404.html +++ /dev/null @@ -1,961 +0,0 @@ - - - -
- - - - - - - - - - - - - - -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
.
An AnalysisInputLocation tells SootUp what code input it should analyze.
-If you have errors like Java.lang.String, Java.lang.Object, ... you are most likely missing this AnalysisInput.
-We created a Utility that parses a String of java command line arguments and configures SootUp respectively.
- - - - - - - - - - - - - -We would like to announce Soot’s successor, SootUp.
-Over more than 20 years, Soot has become one of the world’s 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’s 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 -* The SootUp home page: https://soot-oss.github.io/SootUp/, 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 “Future-proofing the Soot Framework for Program Analysis -and Transformation (FutureSoot)”. It was funded in the DFG’s program on Research Software Sustainability.
- - - - - - - - - - - - - -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:
Method scoped optimisations: -- ConditionalBranchFolder: removes tautologic ifs that are always true/false - if we can determine it in the scope of the method. -- EmptySwitchEliminator: removes switches that are not really switching -- ConstantPropagatorAndFolder: calculates constant values before runtime -- CastAndReturnInliner: Removes merging flows to a single return -- UnreachableCodeEliminator: speaks for itself. -- TrapTightener
-Make Local names standardized: -- LocalNameStandardizer: numbers Locals with the scheme: type-initial + number of type occurence
-Soot Equivalent
- -Below, we show how these BodyInterceptors work for the users who are interested in their internal workings.
-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 aBodyInterceptor
that supports the global copy propagation and constant propagation.
Example for global copy propagation:
- -Consider a code segment in the following form:
-1 -2 -3 |
|
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:
-1 -2 -3 |
|
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 | -
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.
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.
-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:
-1 -2 -3 -4 -5 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 |
|
All the 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:
-1 -2 -3 -4 -5 -6 -7 -8 -9 |
|
1 |
|
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:
-1 -2 -3 -4 -5 -6 -7 |
|
1 -2 -3 -4 -5 -6 -7 -8 |
|
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:
-1 -2 -3 -4 -5 -6 -7 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 |
|
Variable Type Analysis (VTA) algorithm further refines the call graph that the RTA constructs. It refines RTA by considering only the assigned instantiations of the implementers of an interface, when resolving a method call on an interface. -When considering assignments, we usually need to consider pointer (points-to) relationship.
-Info
-VTA algorithm was implemented using the Spark pointer analysis framework. -A reimplementation of Spark in SootUp is currently under development.
-Spark requires an initial call graph to begin with. You can use one of the call graphs that we have constructed above. You can construct a call graph with VTA as follows:
-1 -2 -3 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 |
|
Hover me
-this enables that tutorial code can be tested and will fail if its not up to date anymore :)
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 |
|
See Installation.
-See Getting Started.
-Not yet.
-Please make sure to use Java8 to execute.
-1 -2 -3 -4 |
|
Copy the Iterator into an intermediate Collection. -
1 -2 -3 -4 -5 |
|
There exists a tool, that converts a StmtGraph to the Graphviz Dot Language. -
1 |
|
1 |
|
Try JimpeLsp.
-Have a look at LspLexer4Pygments.
-Feel free to start a Discussion.
- - - - - - - - - - - - - -This page walks you through the core data structures, as well as shows how to get started with SootUp.
-Before you get started with the SootUp library, it helps to learn about the following core data structures:
-AnalysisInputLocation
: points to the target code to be analyzed.Soot Equivalent
-It corresponds to the cp
option, which specifies the classpath for Soot to find classes to be analyzed.
View
: presents the code/classes under analysis.Soot Equivalent
-It corresponds to the Scene
class, but it is not a singleton. So it is possible to instantiate multiple views simultaneously.
SootClass
: represents a class loaded into the View
.
SootMethod
: represents a method of a class.
SootField
: represents a field of a class.
Body
: represents a method body in Jimple.
StmtGraph
: represents the control flow graph of a method body in Jimple statements.
You can use bytecode analysis typically when you do not have access to the source code of the target program. Following example shows how to create a view for analyzing Java bytecode.
-Create a view to analyze Java bytecode
-1 -2 -3 -4 |
|
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
-The source code frontend is experimental and should only be used for testing purposes. You should compile the code for analysis first and use the bytecode frontend instead.
-Create a view to analyze Java source code
-1 -2 -3 -4 |
|
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 project to analyze jimple code
-1 -2 -3 -4 -5 -6 |
|
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 50 classes, and always replaces the least recently used class by a newly retrieved one, use the following call:
1 |
|
Each class is identified with a unique signature adhering to Java identifier rules, therefore you first need to specify the class signature (ClassType
) as shown below.
Let's say the following is the target program that we want to analyze:
-Target Program
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 |
|
Then, we could define the ClassType
of the HelloWorld
class as follows:
Defining a ClassType
-1 -2 |
|
Once we have a ClassType
that identifies the HelloWorld
class, we can use it to retrieve the corresponding SootClass
object from the view
as shown below:
Retrieving a SootClass
-1 |
|
Like the classes, methods also have an identifier which we call MethodSignature
. For instance, we can define the method signature for identifying the main
method of the HelloWorld
class as follows:
Defining a MethodSignature
-1 -2 -3 -4 -5 -6 -7 -8 |
|
Once we have a MethodSignature
that identifies the main
method of the HelloWorld
class, we can use it to retrieve the corresponding SootMethod
object from the view
as shown below:
Retrieving a SootMethod from the View
-1 -2 -3 -4 -5 |
|
Alternatively, we can also retrieve a SootMethod
from SootClass
that contains it.
Retrieving a SootMethod from a SootClass
-1 -2 -3 -4 -5 |
|
Each SootMethod
contains a Control-Flow Graph (CFG) which is represented via the StmtGraph
. This structure is usually used for program analysis. You can retrieve the CFG of a SootMethod
as follows:
Retrieving the CFG of a SootMethod
-1 |
|
Access or Download all of the code used above
- -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.
-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.
-The development of SootUp is financed by generous support from the German Research Foundation (DFG) and -the Heinz Nixdorf Institute (HNI).
-- | - | - |
For configuration options of your build tool please visit SootUp on Jitpack.io
-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
.
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 |
|
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. -
1 -2 |
|
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.
-It might help to visualize how the Jimple version of a Java code looks like. Have a look at the following example on the HelloWorld
class.
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 |
|
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.)
-A class consists of Fields and Methods. -It is referenced by its ClassType.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 |
|
1 -2 -3 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 |
|
A Field is a piece of memory which can store a value that is accessible according to its visibility modifier. -It is referenced by its FieldSignature.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 |
|
1 -2 -3 -4 -5 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 |
|
The interesting part is a method. A method is a "piece of code" that can be executed. -It is referenced by its MethodSignature and contains a StmtGraph that models the sequence of single instructions/statements (Stmts).
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 |
|
Signatures are required for identifying or referencing things across a method, such as Classes, Interfaces, Methods or Fields. -Locals, on the other hand, do not need signatures, since they are referenced within method boundaries.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 |
|
A Trap is a mechanism to model exceptional flow.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 |
|
The main piece of Jimple is a Statement (Stmt). Stmts represent that can be executed by the JVM.
-A BranchingStmt's job is to model the flow between Stmts.
-for unconditional flow.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 |
|
for conditional flow depending on boolean Expression (AbstractConditionExpr) so they have two successor Stmt's.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 |
|
for conditional flow that behaves like a switch-case. It has #numberOfCaseLabels+1 (for default) successor Stmt's.
-All other Stmts are not manipulating the flow, which means they have a single successor Stmt as long as they are not exiting the flow inside a method.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 |
|
They end the execution/flow inside the current method and return (a value) to its caller.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 |
|
Ends the execution inside the current Method if the thrown exception is not caught by a Trap, which redirects the execution to an exceptionhandler.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 |
|
transfers the control flow to another method until the called method returns.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 |
|
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.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 |
|
1 -2 -3 -4 -5 -6 -7 -8 -9 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 |
|
is semantically like the JAssignStmt and handles assignments of IdentityRef's to make implicit assignments explicit into the StmtGraph.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 |
|
1 -2 -3 -4 -5 -6 -7 -8 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 |
|
marks synchronized blocks of code from JEnterMonitorStmt to JExitMonitorStmt.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 |
|
models a Breakpoint set by a Debugger (usually not relevant for static analyses)
-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").
-VoidType
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 |
|
1 -2 -3 -4 -5 -6 -7 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 |
|
BooleanType, ByteType, CharType, ShortType, IntType, LongType, DoubleType, FloatType
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 - 38 - 39 - 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 - 48 - 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - 57 - 58 - 59 - 60 - 61 - 62 - 63 - 64 - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - 74 - 75 - 76 - 77 - 78 - 79 - 80 - 81 - 82 - 83 - 84 - 85 - 86 - 87 - 88 - 89 - 90 - 91 - 92 - 93 - 94 - 95 - 96 - 97 - 98 - 99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 |
|
ClassType, -ArrayType -NullType
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 |
|
jimple
-i0
-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.
```jimple
-public class target.exercise1.DemoClass extends java.lang.Object
-{
- public void
public void compute() - { - java.io.PrintStream $stack2, $stack3; - target.exercise1.DemoClass this; - int local#2;
-1 -2 -3 -4 -5 -6 -7 -8 |
|
} -} -/* - $stack2, this, $stack3, local#2 are all JimpleLocal.
-"this := @this: target.exercise1.DemoClass" is JIdentityStmt
-"$stack2 =
*/
-```
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 |
|
represents a value itself. don't confuse it with a variable/Local which has a immutable (i.e. final) attribute.
-There exists a constant entity for every Type - that way all value types can have a representation.
-An expression is a language construct that returns a value. E.g. a binary operation such as addition.
-jimple
-$arr[1]
-referencing a position inside an array.
jimple
-<SomePackage.ExampleClass: fieldname>
-// or
-r1.<SomePackage.ExampleClass: fieldname>
-referencing a Field via its FieldSignature and if necessary (i.e. with JInstanceFieldRef) the corresponding Local instance that points to the object instance.
The IdentityRef makes those implicit special value assignments explicit.
-jimple
-@this: package.fruit.Banana
-represents the this pointer of the current class.
jimple
-@caughtexception
-represents the value of the thrown exception (caught by this exceptionhandler).
jimple
-i0 := @parameter0
-i1 := @parameter1
-represents a parameter of a method, identified by its index.
see QilinPTA.
-1 -2 -3 -4 -5 |
|
1 |
|
// TODO
- - - - - - - - - - - - - -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":"advanced-topics/","title":"Functionalities and Utilities","text":""},{"location":"advanced-topics/#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
.
An AnalysisInputLocation tells SootUp what code input it should analyze.
"},{"location":"analysisinputlocations/#java-runtime","title":"Java Runtime","text":"If you have errors like Java.lang.String, Java.lang.Object, ... you are most likely missing this AnalysisInput.
"},{"location":"analysisinputlocations/#java-bytecode-class-jar-war","title":"Java Bytecode .class, .jar, .war","text":"We created a Utility that parses a String of java command line arguments and configures SootUp respectively.
"},{"location":"announce/","title":"Announcements","text":""},{"location":"announce/#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 * The SootUp home page: https://soot-oss.github.io/SootUp/, 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:
Method scoped optimisations: - ConditionalBranchFolder: removes tautologic ifs that are always true/false - if we can determine it in the scope of the method. - EmptySwitchEliminator: removes switches that are not really switching - ConstantPropagatorAndFolder: calculates constant values before runtime - CastAndReturnInliner: Removes merging flows to a single return - UnreachableCodeEliminator: speaks for itself. - TrapTightener
Make Local names standardized: - LocalNameStandardizer: numbers Locals with the scheme: type-initial + number of type occurence
Soot Equivalent
BodyTransformer
Below, we show how these BodyInterceptors work for the users who are interested in their internal workings.
"},{"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 aBodyInterceptor
that supports the global copy propagation and constant propagation.
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.
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":"call-graph-construction/#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:
SootUpSootList<AnalysisInputLocation> inputLocations = new ArrayList();\ninputLocations.add(new JavaClassPathAnalysisInputLocation(\"src/test/resources/Callgraph/binary\"));\ninputLocations.add(new DefaultRTJarAnalysisInputLocation());\n\nJavaView view = new JavaView(inputLocations);\n
String targetTestClassName = target.exercise1.Hierarchy.class.getName();\nG.reset();\nString userdir = System.getProperty(\"user.dir\");\nString sootCp = userdir + File.separator + \"target\" + File.separator + \"test-classes\"+ File.pathSeparator + \"lib\"+File.separator+\"rt.jar\";\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":"call-graph-construction/#defining-an-entry-method","title":"Defining an Entry Method","text":"All the 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:
SootUpSootJavaClassType classTypeA = view.getIdentifierFactory().getClassType(\"A\");\n\nMethodSignature entryMethodSignature =\n view.getIdentifierFactory()\n .getMethodSignature(\n classTypeA,\n JavaIdentifierFactory.getInstance()\n .getMethodSubSignature(\n \"calc\", VoidType.getInstance(), Collections.singletonList(classTypeA))); \n
SootMethod src = Scene.v().getSootClass(targetTestClassName).getMethodByName(\"doStuff\"); \n
"},{"location":"call-graph-construction/#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 = \n new ClassHierarchyAnalysisAlgorithm(view);\n\nCallGraph cg = \n cha.initialize(Collections.singletonList(entryMethodSignature));\n\nSystem.out.println(cg);\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":"call-graph-construction/#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 = \n new RapidTypeAnalysisAlgorithm(view);\n\nCallGraph cg = \n rta.initialize(Collections.singletonList(entryMethodSignature));\n\nSystem.out.println(cg);\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":"call-graph-construction/#variable-type-analysis","title":"Variable Type Analysis","text":"Variable Type Analysis (VTA) algorithm further refines the call graph that the RTA constructs. It refines RTA by considering only the assigned instantiations of the implementers of an interface, when resolving a method call on an interface. When considering assignments, we usually need to consider pointer (points-to) relationship.
Info
VTA algorithm was implemented using the Spark pointer analysis framework. A reimplementation of Spark in SootUp is currently under development.
Spark requires an initial call graph to begin with. You can use one of the call graphs that we have constructed above. You can construct a call graph with VTA as follows:
SootUpSootSpark spark = new Spark.Builder(view, callGraph).vta(true).build();\nspark.analyze();\nCallGraph vtaCAllGraph = spark.getCallGraph();\n
Transform sparkConfig = new Transform(\"cg.spark\", null);\nPhaseOptions.v().setPhaseOption(sparkConfig, \"enabled:true\");\nPhaseOptions.v().setPhaseOption(sparkConfig, \"vta: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":"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.signatures.MethodSignature;\nimport sootup.core.types.ClassType;\nimport sootup.core.views.View;\nimport sootup.java.bytecode.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 BasicSetup {\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 = PathBasedAnalysisInputLocation.create(pathToBinary, null);\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 && stmt.getInvokeExpr() instanceof JVirtualInvokeExpr\n && stmt.getInvokeExpr()\n .getArg(0)\n .equivTo(JavaJimple.getInstance().newStringConstant(\"Hello World!\"))));\n }\n}\n
"},{"location":"examples/","title":"SootUp Example projects","text":"Example code to help getting start with SootUp Here we will provide some examples that uses SootUp to provide insights about a Java program. The Examples can be cloned or downloaded from our Example Repository.
We have included all the five projects in 5 different branches under SootUp-Examples with detailed explanation about the project.
"},{"location":"examples/#basicsetupexample","title":"BasicSetupExample","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 sootup.java.bytecode.inputlocation.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/#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.
"},{"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.
"},{"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":"General Usage of SootUp","text":"This page walks you through the core data structures, as well as shows how to get started with SootUp.
"},{"location":"getting-started/#the-core-datastructures","title":"The core datastructures","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 to be analyzed.Soot Equivalent
It corresponds to the cp
option, which specifies the classpath for Soot to find classes to be analyzed.
View
: presents the code/classes under analysis.Soot Equivalent
It corresponds to the Scene
class, but it is not a singleton. So it is possible to instantiate multiple views simultaneously.
SootClass
: represents a class loaded into the View
.
SootMethod
: represents a method of a class.
SootField
: represents a field of a class.
Body
: represents a method body in Jimple.
StmtGraph
: represents the control flow graph of a method body in Jimple statements.
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
The source code frontend is experimental and should only be used for testing purposes. You should compile the code for analysis first and use the bytecode frontend instead.
Create a view to analyze Java source code
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 project 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 50 classes, and always replaces the least recently used class by a newly retrieved one, use the following call:
JavaView view = new JavaView(Collections.singletonList(inputLocation), 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
MethodSignature 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
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 SootMethod method = opt.get();\n}\n
Alternatively, we can also retrieve a SootMethod
from SootClass
that contains it.
Retrieving a SootMethod from a SootClass
Optional<JavaSootMethod> opt = sootClass.getMethod(methodSignature.getSubSignature());\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
sootMethod.getBody().getStmts();\n
Access or Download all of the code used above
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</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.java.bytecode</artifactId>\n <version>1.3.0</version>\n </dependency>\n <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.jimple.parser</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</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</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:1.3.0\"\ncompile \"org.soot-oss:sootup.java.bytecode:1.3.0\"\ncompile \"org.soot-oss:sootup.jimple.parser:1.3.0\"\ncompile \"org.soot-oss:sootup.callgraph:1.3.0\"\ncompile \"org.soot-oss:sootup.analysis:1.3.0\"\ncompile \"org.soot-oss:sootup.qilin: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/","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.
It might help to visualize how the Jimple version of a Java code looks like. Have a look at the following example on the 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
"},{"location":"jimple/#jimple-grammar-structure","title":"Jimple Grammar Structure","text":"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/#class-or-interface","title":"Class (or Interface)","text":"A class consists of Fields and Methods. It is referenced by its ClassType.
JimpleJavaByte Codepublic 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/#field","title":"Field","text":"A Field is a piece of memory which can store a value that is accessible according to its visibility modifier. It is referenced by its FieldSignature.
JimpleJavaByte Codepublic 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/#method-and-the-body","title":"Method and the 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 and contains a StmtGraph that models the sequence of single instructions/statements (Stmts).
JimpleJavaByte Codepublic 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
"},{"location":"jimple/#signatures","title":"Signatures","text":"Signatures are required for identifying or referencing things across a method, such as Classes, Interfaces, Methods or Fields. Locals, on the other hand, do not need signatures, since they are referenced within method boundaries.
JimpleJavaByte Codepublic 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/#trap","title":"Trap","text":"A Trap is a mechanism to model exceptional flow.
JimpleJavaByte Codepublic 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 Ltarget/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/#stmt","title":"Stmt","text":"The main piece of Jimple is a Statement (Stmt). Stmts represent that can be executed by the JVM.
"},{"location":"jimple/#branching-statements","title":"Branching Statements","text":"A BranchingStmt's job is to model the flow between Stmts.
"},{"location":"jimple/#jgotostmt","title":"JGotoStmt","text":"for unconditional flow.
JimpleJavaByte Codepublic 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/#jifstmt","title":"JIfStmt","text":"for conditional flow depending on boolean Expression (AbstractConditionExpr) so they have two successor Stmt's.
JimpleJavaByte Codepublic 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/#jswitchstmt","title":"JSwitchStmt","text":"for conditional flow that behaves like a switch-case. It has #numberOfCaseLabels+1 (for default) successor Stmt's.
All other Stmts are not manipulating the flow, which means they have a single successor Stmt as long as they are not exiting the flow inside a method.
JimpleJavaByte Codepublic 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/#jreturnstmt-jreturnvoidstmt","title":"JReturnStmt & JReturnVoidStmt","text":"They end the execution/flow inside the current method and return (a value) to its caller.
JimpleJavaByte Codepublic 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/#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.
JimpleJavaByte Codepublic 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/#jinvokestmt","title":"JInvokeStmt","text":"transfers the control flow to another method until the called method returns.
JimpleJavaByte Codepublic 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: \n int increment(int)>(x);\n $stack4 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack4.<java.io.PrintStream: \n void println(int)>(a);\n\n a = virtualinvoke this.<target.exercise1.DemoClass: \n int increment(int)>(a);\n $stack6 = <java.lang.System: java.io.PrintStream out>;\n virtualinvoke $stack6.<java.io.PrintStream: \n 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/#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.
JimpleJavaByte Codepublic 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/#jidentitystmt","title":"JIdentityStmt","text":"is semantically like the JAssignStmt and handles assignments of IdentityRef's to make implicit assignments explicit into the StmtGraph.
JimpleJavaByte Codepublic 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/#jentermonitorstmt-jexitmonitorstmt","title":"JEnterMonitorStmt & JExitMonitorStmt","text":"marks synchronized blocks of code from JEnterMonitorStmt to JExitMonitorStmt.
JimpleJavaByte Codepublic 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/#jretstmt","title":"JRetStmt","text":""},{"location":"jimple/#jbreakpointstmt","title":"JBreakpointStmt","text":"models a Breakpoint set by a Debugger (usually not relevant for static analyses)
"},{"location":"jimple/#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\").
"},{"location":"jimple/#type","title":"Type","text":"VoidType
JimpleJavaByte Codepublic 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/#primarytype","title":"PrimaryType","text":"BooleanType, ByteType, CharType, ShortType, IntType, LongType, DoubleType, FloatType
JimpleJavaByte Codepublic 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/#referencetype","title":"ReferenceType","text":"ClassType, ArrayType NullType
JimpleJavaByte Codepublic 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 JimpleLocal b is of ArrayType,\n and JimpleLocal 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/#local","title":"Local","text":"jimple i0
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.
```jimple public class target.exercise1.DemoClass extends java.lang.Object { public void () { target.exercise1.DemoClass this; this := @this: target.exercise1.DemoClass; specialinvoke this.()>(); return; }
public void compute() { java.io.PrintStream $stack2, $stack3; target.exercise1.DemoClass this; int local#2;
this := @this: target.exercise1.DemoClass;\n$stack2 = <java.lang.System: java.io.PrintStream out>;\nvirtualinvoke $stack2.<java.io.PrintStream: void println(int)>(1);\n\nlocal#2 = this.<target.exercise1.DemoClass: int global>;\n$stack3 = <java.lang.System: java.io.PrintStream out>;\nvirtualinvoke $stack3.<java.io.PrintStream: void println(int)>(local#2);\nreturn;\n
} } /* $stack2, this, $stack3, local#2 are all JimpleLocal.
\"this := @this: target.exercise1.DemoClass\" is JIdentityStmt
\"$stack2 = \", \"local#2 = this.\", \"$stack3 = \" are JAssignStmt
*/ ```
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/#constant","title":"Constant","text":"represents a value itself. don't confuse it with a variable/Local which has a immutable (i.e. final) attribute.
There exists a constant entity for every Type - that way all value types can have a representation.
"},{"location":"jimple/#expr","title":"Expr","text":"An expression is a language construct that returns a value. E.g. a binary operation such as addition.
"},{"location":"jimple/#ref","title":"Ref","text":""},{"location":"jimple/#jarrayref","title":"JArrayRef","text":"jimple $arr[1]
referencing a position inside an array.
jimple <SomePackage.ExampleClass: fieldname> // or r1.<SomePackage.ExampleClass: fieldname>
referencing a Field via its FieldSignature and if necessary (i.e. with JInstanceFieldRef) the corresponding Local instance that points to the object instance.
The IdentityRef makes those implicit special value assignments explicit.
"},{"location":"jimple/#jthisref","title":"JThisRef","text":"jimple @this: package.fruit.Banana
represents the this pointer of the current class.
jimple @caughtexception
represents the value of the thrown exception (caught by this exceptionhandler).
jimple i0 := @parameter0 i1 := @parameter1
represents a parameter of a method, identified by its index.
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\nJavaSootMethod sootMethod = sootClass.getMethod(methodSignature.getSubSignature()).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":"see QilinPTA.
"},{"location":"qilin/#dependencies","title":"Dependencies","text":"MavenGradle <dependency>\n <groupId>org.soot-oss</groupId>\n <artifactId>sootup.java.sourcecode</artifactId>\n <version></version>\n </dependency>\n
compile \"org.soot-oss:sootup.qilin:1.3.0\"\n
"},{"location":"qilin/#how-to","title":"How to","text":"// TODO
"},{"location":"tool_ux/","title":"From Prototype to user friendly 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 and calling 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.
Dependencies:
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_ux/#java-code","title":"Java Code","text":"class SootUpConfiguration{\n // TODO incorporate\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":"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
If you wish to implement an interprocedural data-flow analysis via the IFDS or IDE Framework please have a look at the test cases in the sootup.analysis submodule.
"}]} \ No newline at end of file diff --git a/_preview/sitemap.xml b/_preview/sitemap.xml deleted file mode 100644 index f586a560098..00000000000 --- a/_preview/sitemap.xml +++ /dev/null @@ -1,93 +0,0 @@ - -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 and calling 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.
-Dependencies:
-1 -2 -3 -4 -5 |
|
1 |
|
1 -2 -3 |
|
We are happy if you steal the following code to create a tool where the setup is just simple.
- - - - - - - - - - - - - -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.
-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.
-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.
-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
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 |
|
Jimple is the only intermediate representation (IR) in SootUp. We modified it slightly to be able to accommodate different programming languages in the future.
- - - - - - - - - - - - - -1 -2 -3 -4 -5 |
|
1 |
|
Background Knowledge as online lectures are available on YouTube.
- -Taint Analysis, TypeState Analysis, Linear Constant Propagation, ...
-1 |
|
If you wish to implement an interprocedural data-flow analysis via the IFDS or IDE Framework please have a look at the test cases in the sootup.analysis submodule.
- - - - - - - - - - - - - -Access or Download all of the code used above
Below we show a comparison of the code so far with the same functionality in sootup.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 |
|
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 |
|
Example code to help getting start with SootUp
-1) Here we will provide some examples that uses SootUp to provide insights about a Java program. The repository that contains the examples can be found in [https://github.com/soot-oss/SootUp-Examples.git].
-2) There are mainly 5 projects to be considered under SootUp.
- a) BasicSetupExample
- b) BodyInterceptorExample
- c) CallGraphExample
- d) ClassHierarchyExample
- e) MutatingSootClassExample
3) We have included all the five projects in 5 different branches under SootUp-Examples with detailed explanation about the project.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 |
|
b) BodyInterceptor - 1) package sootup.examples; - defines the package name for the Java class. - 2) import statement - defines various classes and interfaces from different packages that the program uses. - 3) public class BodyInterceptor - declares a public class named "BodyInterceptor". - 4) Then we have created a main method in which is the entry point for the code. - 5) Then we have created an AnalysisInputLocation pointing to a directory with class files to be loaded. It specifies that the DeadAssignmentEliminator interceptor should be applied to these classes. - 6) Then created a View that initializes a JavaView with the specified inputLocation, allowing interaction with the classes for analysis. - 7) Then have created a ClassType and MethodSignature which is used for analysis. The signature contains method name, return type and parameters. - 8) Then we check for the existence of the class and method in the given view. - 9) If they exist, a SootClass and SootMethod objects are used to retrieve the same. - 10) Then prints the body of the SootMethod object. - 11) Then we check if the interceptor worked. ie here we check if the DeadAssignmentEliminator interceptor has successfully removed a specific assignment (l1 = 3) from the method's body. It does this by looking through all statements (JAssignStmt) in the method body and checking if the assignment is not present. - 12) Then it prints the result of the interceptor check.
-c) CallGraphExample
- 1) package sootup.examples; - defines the package name for the Java class.
- 2) import statement - defines various classes and interfaces from different packages that the program uses.
- 3) public class CallgraphExample - declares a public class named "CallGraphExample".
- 4) Then we have created a main method in which is the entry point for the code.
- 5) List
d) ClassHierarchyExample - 1) package sootup.examples; - defines the package name for the Java class. - 2) import statement - defines various classes and interfaces from different packages that the program uses. - 3) public class ClassHierarchy - declares a public class named "ClassHierarchy". - 4) Then we have created a main method in which is the entry point for the code. - 5) Then creates a list of AnalysisInputLocation objects. These specify where Soot should look for Java class files for analysis. Two locations are added: one for the project's binary directory and another for the default Java runtime library (rt.jar). - 6) Initializes a JavaView object with the previously created input locations. - 7) Initializes a ViewTypeHierarchy object using the view. This object will be used to analyze the class hierarchy. - 8) Then we have created two ClassTypes. These lines get JavaClassType objects for classes "A" and "C". These types are used for further hierarchy analysis. - 9) Checks the direct subclasses of class "C". It verifies if all direct subclasses are "D" using two different methods: comparing class names and fully qualified names. - 10) Then prints a message based on whether all direct subtypes of "C" are correctly identified as "D". - 11) Retrieves and checks the superclasses of class "C". It then verifies if these superclasses include class "A" and java.lang.Object, printing a message based on the result.
-1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 |
|
The development of SootUp is financed by generous support from the German Research Foundation (DFG) and the Heinz Nixdorf Institute (HNI).
-repositories {
- mavenCentral()
- google()
-}
-
-compile "org.soot-oss:sootup.core:1.3.0"
-compile "org.soot-oss:sootup.java.core:1.3.0"
-compile "org.soot-oss:sootup.java.sourcecode:1.3.0"
-compile "org.soot-oss:sootup.java.bytecode:1.3.0"
-compile "org.soot-oss:sootup.jimple.parser:1.3.0"
-compile "org.soot-oss:sootup.callgraph:1.3.0"
-compile "org.soot-oss:sootup.analysis:1.3.0"
+12
+13
repositories {
+ mavenCentral()
+ google()
+}
+
+compile "org.soot-oss:sootup.core:1.3.0"
+compile "org.soot-oss:sootup.java.core:1.3.0"
+compile "org.soot-oss:sootup.java.sourcecode:1.3.0"
+compile "org.soot-oss:sootup.java.bytecode:1.3.0"
+compile "org.soot-oss:sootup.jimple.parser:1.3.0"
+compile "org.soot-oss:sootup.callgraph:1.3.0"
+compile "org.soot-oss:sootup.analysis:1.3.0"
+compile "org.soot-oss:sootup.qilin:1.3.0"
see QilinPTA.
1 |
|