本文参考
Using Soot to instrument a class file
目标
- 怎样用 soot 对一个 class 文件 inspect
- 怎样用为 class 文件插桩的方法对程序 profile
用例子说明
Task:为下面这个 TestInvoke.java 程序统计 InvokeStatic 指令的运行次数。
class TestInvoke {
private static int calls=0;
public static void main(String[] args) {
for (int i=0; i<10; i++) {
foo();
}
System.out.println("I made "+calls+" static calls");
}
private static void foo(){
calls++;
bar();
}
private static void bar(){
calls++;
}
}
为了记录计数器,我写了一个助手类 MyCounter 如下
/* The counter class */
public class MyCounter {
/* the counter, initialize to zero */
private static int c = 0;
/**
* increases the counter by <pre>howmany</pre>
* @param howmany, the increment of the counter.
*/
public static synchronized void increase(int howmany) {
c += howmany;
}
/**
* reports the counter content.
*/
public static synchronized void report() {
System.err.println("counter : " + c);
}
}
现在我新建一个包装类来为 Soot 添加一个 phase。目的是插入 profiling 的指令,然后调用 soot.Main.main()。这个driver 类的 main method 添加了一个命名为 “jtp.instrumenter” 的 transformation phase 到 soot 的 “jtp” pack。当 MainDriver 对 soot.Main.main 发起调用时,Soot 能从 PackManager 中得知一个新的 phase 被注册了,并且它的 internalTransform 方法会被 soot 调用。以下是 MainDriver.java:
/* Usage: java MainDriver [soot-options] appClass
*/
/* import necessary soot packages */
import soot.*;
public class MainDriver {
public static void main(String[] args) {
/* check the arguments */
if (args.length == 0) {
System.err.println("Usage: java MainDriver [options] classname");
System.exit(0);
}
/* add a phase to trans