原文链接: https://github.com/s able/soot/wiki/fundamental-soot-objects
Soot有巨大而复杂的类继承关系。 本文档介绍了最重要的类,以便于Soot的扩展开发。
对以下概念进行说明。Body,Unit,3358www.Sina.com/,Local,http://www.Sina.com
一切关于http://www.Sina.com/(s )
在Creating a class from scratch (链接: https://github.com/s able/soot/wiki/creating-a-class-from-scratch )文档中
Soot使用Value存储方法的代码。 Soot有UnitBox、ValueBox、Body和3358www.Sina.com/四种Body,分别是
请记住,“链”(chain )就像一个列表的数据结构,提供对链中元素的一定时间内的访问,例如插入和删除。
3358www.Sina.com/中的三个主要链是Body的链、Body链和Body链本例说明了这三个链中每一个链的作用。
考虑以下Java方法:
publicstaticvoidmain (string [ ] argv ) Throwsexception(intx=2,y=6; system.out.println('hi!' ); system.out.println(x*y ); try{int z=y*x; }catch(exceptione ) {throw e; }
将其转换为Jimple代码后,有以下简短的Jimple代码:
publicstaticvoidmain (Java.lang.string [ ] ) throws Java.lang.exception { Java.lang.string [ ] r0; int i0,i1,i2,$i3,$i4; java.io.PrintStream $r1,$r2; java.lang.Exception $r3,r4; r0 :=@parameter0; i0=2; i1=6; $r1=java.lang.System.out; $R1.println('hi!' '; $r2=java.lang.System.out; $i3=i0*i1; $i4=$i3 i1; $R2.println($I4 ); label0:i2=i1*i0; 标签1:谷歌标签3; label 2: $ r 3:=@ caught exception; r4=$r3; throw r4; 标签3:返回; catch Java.lang.exceptionfromlabel0to label1with label 2; } Local变量
此方法的locals位于此方法的开头:
java.lang.String[]r0;
BafBodyi0、i1、i2、$i3、$i4;
java.io.PrintStream$r1,$r2;
java.lang.Exception$r3,r4;
3358www.Sina.com/(s )收集于JimpleBody并可从ShimpleBody访问。 各个中间显示有针对GrimpBody的独自实现; 这些实现必须确保对于每个定义3358www.Sina.com/可以调用Body和Units请注意,local变量必须具有类型。
Locals
为了支持Java异常处理,请访问Soot的3358www.Sina.com/或Traps
trong>这一概念。其观点是在Java字节码中,异常处理程序是由一个多元组(异常、开始点、结束点、处理程序)表示;在开始和结束单元之间(包括开始处,但不包括结束处),如果异常被抛出,则执行处理程序。在上面这个例子中,有一个trap:
catch java.lang.Exception from label0 to label1 with label2;
Units
Body中最有意思的部分即Unit(s)链(chain),这是Body中的实际代码。Jimple用Stmt实现了Unit,Grimp则用Inst来实现。这表明每个中间表示(IR)有它自己的对语句(statement)的概念。
Jimple Stmt中的一个例子便是AssignStmt,这代表一条Jimple的分配语句。AssignStmt可能是下面这种形式:
x = y + z;
Value
代码通常会对数据进行操作。为了表示数据,Soot提供了Value接口。下面是一些不同类型的Value(s):
n Local(s)
n Constant(s)
n 表达式(Expr)
n ParameterRef(s), CaughtExceptionRef(s)和 ThisRef(s)
Expr接口,反过来,有一整套实现;其中有NewExpr和AddExpr。通常,一个Expr会对一个或多个Value(s)执行一些动作并返回另一个Value。
下面是使用Value(s)的一个例子:
x = y + 2;这是一个AssignStmt,左操作数是x,右操作数是y+2,右操作数是一个AddExpr。这个AddExpr反过来包含Value(s) y和2作为它的操作数;前一个操作数是一个Local,后一个操作数是一个Constant。
在Jimple中,我们强制要求所有的Value(s)最多包含一个表达式(contain at most 1 expression)。Grimp则没有这个限制,这使得其产生的代码很容易阅读但很难分析。
Boxes
Boxes在Soot中无处不在。主要要记住就是一个Box是一个指针,它提供对Soot对象的间接访问。
对于Box,更具描述性的名称可能是Ref。但不幸的是,在Soot中Ref代表其它的意思。
在Soot中有两类Box(es),分别为ValueBox和UnitBox。一个UnitBox包含Unit(s),一个ValueBox包含Value(s),在C++中,分别表示为(Unit*)和(Value*)。
下面将描述每一种Box。
UnitBox
某些Unit(s)可能需要包含对其它Unit(s)的引用。比如,一个GotoStmt需要知道它的目标是什么。因此,Soot提供了UnitBox,UnitBox是一个包含了一个Unit的Box。
考虑下面的Jimple代码:
x = 5; goto l2; y = 3; l2: z = 9;每个Unit都必须提供getUnitBoxes()方法,对于大多数UnitBox(es)而言,这个方法会返回一个空列表,对于GotoStmt而言,getUnitBoxes()方法将会返回包含一个元素的列表。包含一个指向l2的Box。
注意到对于SwitchStmt而言,通常getUnitBoxes()方法将会返回包含许多boxes的列表。
Box的概念对于修改代码而言最为有用。比如我们有下面一条语句s:
s: goto l2;
在l2处有一个Stmt:
l2: goto l3; 很明显,不管s的实际类型是什么,s可以指向l3而不指向l2。因此对于各种类型的Unit(s),我们可以统一做下面的事情:
public void readjustJumps(Unit s, Unit oldU, Unit newU){ Iterator ubIt = s.getUnitBoxes.iterator(); while (ubIt.hasNext()) { StmtBox tb = (StmtBox)ubIt.next(); Stmt targ = (Stmt)tb.getUnit(); if (targ == oldU) tb.setUnit(newU); }} Unit自身使用了一些与上面类似的代码,这样便能够创建PatchingChain,PatchingChain是对Chain的一种实现,它能够调整那些指向将要从Chain中删除的Unit(s)的指针。
ValueBox
类似于Unit(s),我们经常需要指向Value的指针。这由ValueBox 类表示。对于一个Unit,我们可以获得ValueBox的列表,包括在这个Unit中已使用和被定义的值(values)。
我们可以利用这些boxes来进行常数合并(constant folding):对于一个AssignStmt,其计算一个AddExpr,将两个常数值相加,我们则可以静态的将它们相加然后把结果放置到UseBox。
下面是一个合并 AddExpr 的例子:
public void foldAdds(Unit u){ Iterator ubIt = u.getUseBoxes().iterator(); while (ubIt.hasNext()) { ValueBox vb = (ValueBox) ubIt.next(); Value v = vb.getValue(); if (v instanceof AddExpr) { AddExpr ae = (AddExpr) v; Value lo = ae.getOp1(), ro = ae.getOp2(); if (lo instanceof IntConstant && ro instanceof IntConstant) { IntConstant l = (IntConstant) lo, r = (IntConstant) ro; int sum = l.value + r.value; vb.setValue(IntConstant.v(sum)); } } }} 注意到不管Unit 的类型是什么,这都适用。
Unit 重新访问
我们现在讨论任何Unit 都必须提供的几种不同的方法。
public List getUseBoxes();public List getDefBoxes();public List getUseAndDefBoxes(); 上面三个方法返回在该Unit被使用、被定义或二者兼有的ValueBox(s)的一个List(s),对于getUseBoxes(),它返回所有被使用的值(values),包括表达式以及这些表达式的组成部分。
public List getUnitBoxes(); 这个方法返回由该方法指向的的unit 的UnitBox(es)的一个List。
public List getBoxesPointingToThis(); 这个方法返回UnitBox(es)的列表,这些UnitBox都指向此Unit(即调用这个方法的Unit)。
public boolean fallsThrough();public boolean branches(); 这些方法处理该Unit之后的的执行流,前面一个方法返回真如果可以接着执行接下来的Unit,后面一个方法返回真如果执行流可能流入其他的Unit,这个Unit不是紧跟当前Unit之后的Unit。
public void redirectJumpsToThisTo(Unit newLocation); 这个方法使用getBoxesPointingToThis()来改变所有跳转至该Unit的跳转语句,将它们指向newLocation。