2015-06-21 55 views
1

我在做Java字節碼分析。我想跟蹤每個局部變量的狀態變化。這個想法非常像一個調試器。例如,我有一個像使用ASM 5.0的字節碼檢測。注入跟蹤器以跟蹤局部變量

public class Foo { 

public void main() { 
    printOne(); 
} 

public void printOne() {  
    int i=11110; 
    String hello="hello"; 
} 

一個Java源代碼,通過使用ASM 5.0我可以訪問行號,本地變量名,mehtod名字,VAR指令等。訪客看起來像下面

@Override 
    public void visitLineNumber(int line, Label start) { 
     System.out.println("line: "+line+" "); 
     mv.visitLineNumber(line, start); 

    } 

    @Override 
    public void visitLocalVariable(String name, String desc,String signature, Label start, Label end, int index) { 
     System.out.println("local variable:"+name); 
     mv.visitLocalVariable(name, desc, signature, start, end, index); 

    } 

    @Override 
    public void visitVarInsn(int opcode, int var) { 
     System.out.println("var instruction"+Integer.toHexString(opcode)); 
     mv.visitVarInsn(opcode, var); 
    } 

    @Override 
    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { 
     System.out.println("method"); 
     mv.visitMethodInsn(opcode, owner, name, desc, itf); 
    } 

的問題是我在哪裏注入示蹤劑(只是一個靜態方法調用),並尋找變量值的堆棧,並傳遞到示蹤劑參數?

mv.visitMethodInsn(Opcodes.INVOKESTATIC, "path/to/Tracer", "trace", "(Ljava/lang/String;)V",false); 
+0

你有沒有試過尋找現有的調試工具? – Antimony

+0

@銻是的,但我想自己實現一個調試器。 –

回答

2

你不能對訪客做你想做的事。訪問者只訪問聲明的局部變量,存儲在LocalVariableTable可選LocalVariableTable屬性的類文件Code屬性(請參見specification here)。這給出了局部變量的簽名,但不會告訴你任何有關在運行時發生的值。爲此,您需要分析字節碼中的loadstore指令(等等),正如您所說的那樣,它將有效地編寫調試器。

原則上,您可以訪問代碼,查找存儲在您感興趣的局部變量索引中的所有操作碼,並插入檢測代碼以將新值傳遞給您自己的某種報告方法,但這會是很多工作來重新實現調試器已經做的事情。

重申:LocalVariableTable不包含值。它是元數據描述局部變量 - 它們的名稱,類型等 - 存儲在類文件中以利於調試器。它是一個可選屬性,僅在編譯時包含調試信息時才創建。在運行時,執行代碼不使用LocalVariableTable。本地變量值本身駐留在堆棧上,在運行時分配。我認爲你需要退後一步,思考你想達到的目標。你想知道本地變量在運行時採用什麼值。直到運行時才能知道

你不能在類文件中指出一個調試器,並詢問「局部變量x的值是什麼?」。該信息在類文件中不存在。這甚至不是一個有意義的問題。您必須運行該程序以在其上使用調試器。調試器暫停執行並在特定時間點查看執行堆棧上的值。您的asm訪問者類正在查看類文件,而不是正在運行的代碼或執行堆棧。

什麼可知知道,是運行時棧上局部變量值的位置索引。這是傳遞給本地變量訪問者的索引參數。您需要獲取該索引參數並分析該方法的字節碼,以查找將值存儲到該索引處的變量中的所有操作碼。這些代表了局部變量的值可能變化的方法中的點。然後,您可以插入額外的字節碼來調用您自己的報告方法,並在指定的索引處傳遞本地變量的值。然後你必須運行你已經安裝的代碼。毋庸置疑,沒有一個是爲了那個膽小鬼!

+0

謝謝你的建議。在ASM中是否有一種方法可以用來根據變量索引在localVariableTable中獲取值? –

+0

LocalVariableTable可能不是您想象的。我更新了答案,重申爲什麼你不能做你想做的事。 –