今天看了soot生成手冊的部分內容,簡單摘錄一下
Scene 表示分析所處的完整環境,可以借此設置application class(用sootclass),主類(main),point-to和call graph
SootClass 一個單獨的類,被載入soot或用soot產生
SootMethod 指class的一個方法
SootField 指class的一個成員字段
Body 中間碼,有四種表示
Body表示一個方法體,可以從中獲得一系列Collection(soot將其稱為Chain),包括本地變量聲明getLocals(),構成body的statement即getUnits(),body中處理的exception即getTraps()
以下是一段 Java 代碼以及其對應的 Jimple 代碼:
public static void main(String[] argv) throws Exception { int x = 2, y = 6; System.out.println("Hi!"); System.out.println(x * y + y); try { int z = y * x; } catch (Exception e) { throw e; } }
public static void main(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; label1: goto label3; label2: $r3 := @caughtexception; r4 = $r3; throw r4; label3: return; catch java.lang.Exception from label0 to label1 with label2; }
在 Jimple 文件的最開始是 Local 的聲明,它們存在 localChain 中,可以使用 body.getLocals() 獲得。對於一個 local r0,可以對其 r0.getName(), r0.setName(), r0.getType(), r0.setType()。
Traps 是為了支持 Java 異常處理,由一個四元組 (exception, start, stop, handler) 來描述,其中范圍包含 start 不包含 stop,在這之間的unit如果觸發了異常,就跳轉到handler。
catch java.lang.Exception from label0 to label1 with label2;
Unit 是表示 Body 代碼的,Unit 在 Jimple 中的實現是 Stmt,在 Grimp 中的實現是 Inst
通過Unit(Jimple實現為Stmt),可以檢索value的使用(getUseBoxes())和定義(getDefBoxes()),或者同時實現(getUseAndDefBoxes())
此外,還可以獲得跳轉到這個Unit的Unit(getBoxesPointingToThis()),以及這個Unit要跳轉去的Unit--(getUnitBoxes()),借此分析控制流
Unit還提供了一些方法查詢分支行為,例如fallsThrough() 和 branches()
一個單一的datum表示為Value
Value 接口是為了描述 data。Value 主要包括:Local; Constants; Expressions (Expr); ParameterRefs, CaughtExceptionRefs, ThisRefs。Expr 接口既是表達式,它接受若干個 Value 同時返回另一個 Value。例如對於 AssignStmt :
x = y + 2;
y + 2 是 AddExpr,y 是 Local, 2 是Constant。對於 Jimple,強制最多有 1 個expression,Grimp 則沒有此限制。
一個表達式具有多種實現,但一般可以認為是在一個或多個值上執行某些操作,並返回另一個值。
引用在soot中稱作boxes,分為ValueBox and UnitBox,提供對soot對象的間接訪問,不理解的話可以當做指針
對於 UnitBox,每個 Unit 必須提供 getUnitBoxes() 方法,當然對於大多數的 Unit 這個方法返回空,但是對於跳轉語句,例如 GotoStmt,該方法返回目標的 lable 的 box,而對於 SwitchStmt 則返回很多 Box。Box 的概念對於用 soot 修改代碼提供了很大的便利。例如有兩條指令
s: goto l2; ... ... l2: goto l3;
顯然這里多用了一條指令,可以用如下程序優化
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); } }
對於 ValueBox,我們可以取出一個 Unit 的 ValueBox 列表,包含這個 Unit 引用、定值了哪些 Value。我們可以用 box 實現 constant folding:如果一個 AssignStmt 計算一個 AddExpr,把兩個常量相加,我們可以靜態的計算結果,並把結果放入 UseBox。代碼如下:
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 的方法:
public List getUseBoxes(); public List getDefBoxes(); public List getUseAndDefBoxes();
public List getUnitBoxes();
public List getBoxesPointingToThis();
public boolean fallsThrough(); public boolean branches();
public void redirectJumpsToThisTo(Unit newLocation);
該方法把所有跳轉到該 unit 重定向到 newLocation。