我的目标是在某些Java字节码的每个基本块的开头处检测少量代码。目的是通过基本块记录执行路径。目前,我正在使用Javassist在方法的开头和结尾处检测一些代码,但是我已经遇到了使用Javassist API编写更精细字节码位置的问题。
Javassist为我提供了一个Block [],它代表了方法中的所有基本块。基本块可以报告它们的字节码位置,因此我知道我的仪器需要去哪里。我想要使用的Javassist的工具是CtMethod.insertAt(int sourceCodeLineNumber,String newSourceCode),但是它使用源代码行号而不是字节码行号,这会导致this问题中说明的问题(我很确定到目前为止还没有解决这个问题)。
问题:当变量本身来自Javassist instrumentation 时,如何使用检测为方法中的变量赋值。我最好不必使用其他工具,但是我现在可以得到任何帮助。
使用Javassist声明变量:
//m is a CtMethod
try { m.addLocalVariable("someVar", ClassPool.getDefault().get("SomePackage.SomeClass")); }
catch (NotFoundException e) { e.printStackTrace(); }
我最糟糕的情况是以某种方式推断javassist工具的堆栈变量,并使用遍历整个方法/类的迭代器插入字节码,但那真的很讨厌。我的方法只有一个整数输入(块ID)和void输出,所以Java字节码在每个基本块的开头都是这样的:
ALOAD 6 //6 is my new Javassist variable ID, however I don't think I can get Javassist to actually tell it to me
ICONST_1 //My parameters, which is an int. I'd have to switch statement between ICONST, SIPUSH, and ALOAD depending on basic block's index size
INVOKEVIRTUAL SomePackage/SomeClass.SomeMethod(I)V
答案 0 :(得分:1)
我发现从ConstPool表中获取变量ID的最佳方法是在插入变量后测试最大大小
try { m.addLocalVariable(mse, ClassPool.getDefault().get("org.javadynamicanalyzer.MethodStackEntry")); }
catch (NotFoundException e) { e.printStackTrace(); }
int mseCSindex=m.getMethodInfo().getCodeAttribute().getMaxLocals()-1;
接下来,我需要表中的invokevirtual索引。这有点令人讨厌。下面的代码在ConstPool表中搜索我正在寻找的函数。我正在搜索的功能在org.javadyanmicanalyzer.MethodStackEntry.setBlockID(int)
。
int virtFunIndex=-1;
boolean found=false;
while(found==false){
++virtFunIndex;
try{
int id=cp.isMember("org.javadynamicanalyzer.MethodStackEntry", "setBlockIndex", virtFunIndex);
if(id!=0){
found=true;
}
}
catch(NullPointerException | ClassCastException e){}
}
最后,我需要检测每个块的开头:
int len=new ControlFlow(m).basicBlocks().length;
for(int i=0; i<len; ++i){
Block thisbb=new ControlFlow(m).basicBlocks()[i]; //we have to re-evaluate the control flow every time we add new code
CodeIterator itr=m.getMethodInfo().getCodeAttribute().iterator();
int pos=thisbb.position();
byte[] newCode=new byte[]{Bytecode.ALOAD, //loads the mse class
mseCSindex, //my mse local variable
Bytecode.ICONST_0, //the input to the virtual function
Bytecode.INVOKEVIRTUAL, //execute the virtual function
(byte) virtFunIndex>>8, //virtual function's address
(byte) virtFunIndex && 0xFF};
int n = itr.insertAt(pos, newCode);
}
它很乱,有可能彻底毁灭自己,但它有效!