使用bcel时构造方法的堆栈图 [英] Construct the stackmap of method while using bcel
问题描述
我正在尝试bcel通过在特定指令之前插入invoke来修改方法. 看来,我的检测将导致不同的stackmap表,而bcel包本身无法自动生成该表. 因此,我检测到的类文件包含旧的stackmap表,这将导致jvm错误. 我曾尝试过使用removeCodeAttributes(MethodGen的方法)来删除所有代码属性.例如,它可以在简单的情况下工作,例如包装函数.就我而言,它现在无法正常工作.
I am trying bcel to modify a method by inserting invoke before specific instructions. It seems that my instrumentation would result in a different stackmap table, which can not be auto-generated by the bcel package itself. So, my instrumented class file contains the old stackmap table, which would cause error with jvm. I haved tried with removeCodeAttributes, the method of MethodGen, that can remove all the code attributes. It can work in simple cases, a wrapped function, for example. And it can not work in my case now.
public class Insert{
public static void main(String[] args) throws ClassFormatException, IOException{
Insert isrt = new Insert();
String className = "StringBuilder.class";
JavaClass jclzz = new ClassParser(className).parse();
ClassGen cgen = new ClassGen(jclzz);
ConstantPoolGen cpgen = cgen.getConstantPool();
MethodGen mgen = new MethodGen(jclzz.getMethods()[1], className, cpgen);
InstructionFactory ifac = new InstructionFactory(cgen);
InstructionList ilist = mgen.getInstructionList();
for (InstructionHandle ihandle : ilist.getInstructionHandles()){
System.out.println(ihandle.toString());
}
InstructionFinder f = new InstructionFinder(ilist);
InstructionHandle[] insert_pos = (InstructionHandle[])(f.search("invokevirtual").next());
Instruction inserted_inst = ifac.createInvoke("java.lang.System", "currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC);
System.out.println(inserted_inst.toString());
ilist.insert(insert_pos[0], inserted_inst);
mgen.setMaxStack();
mgen.setMaxLocals();
mgen.removeCodeAttributes();
cgen.replaceMethod(jclzz.getMethods()[1], mgen.getMethod());
ilist.dispose();
//output the file
FileOutputStream fos = new FileOutputStream(className);
cgen.getJavaClass().dump(fos);
fos.close();
}
}
推荐答案
删除StackMapTable
并不是解决错误的StackMapTable
的适当解决方案.重要的引用是:
Removing a StackMapTable
is not a proper solution for fixing a wrong StackMapTable
. The important cite is:
4.7.4 . StackMapTable属性
在版本号为50.0或更高版本的
class
文件中,如果方法的Code
属性没有StackMapTable
属性,则它具有隐式堆栈映射属性(§4.10.1 ).此隐式堆栈映射属性等效于StackMapTable
属性,其中number_of_entries
等于零.
4.7.4. The StackMapTable Attribute
In a
class
file whose version number is 50.0 or above, if a method'sCode
attribute does not have aStackMapTable
attribute, it has an implicit stack map attribute (§4.10.1). This implicit stack map attribute is equivalent to aStackMapTable
attribute withnumber_of_entries
equal to zero.
由于StackMapTable
必须为每个分支目标都具有显式条目,所以这样的隐式StackMapTable
仅适用于无分支方法.但是在这些情况下,该方法通常通常都没有明确的StackMapTable
,因此您就不会遇到这个问题(除非该方法具有您的仪器删除的分支).
Since a StackMapTable
must have explicit entries for every branch target, such an implicit StackMapTable
will work with branch-free methods only. But in these cases, the method usually doesn’t have an explicit StackMapTable
anyway, so you wouldn’t have that problem then (unless the method had branches which your instrumentation removed).
另一个结论是,如果将类文件版本号修补为下面的 50
值,则可以删除StackMapTable
.当然,仅当您不需要版本50
或更高版本中引入的任何类文件功能时,这才是解决方案……
Another conclusion is that you can get away with removing the StackMapTable
, if you patch the class file version number to a value below 50
. Of course, this is only a solution if you don’t need any class file feature introduced in version 50
or newer…
有一段宽限期,在该宽限期内,JVM支持对StackMapTable
损坏的类文件使用后备模式,仅适用于您这样的情况,而该工具的支持不是最新的. (请参见 -XX:+FailoverToOldVerifier
或 -XX:-UseSplitVerifier
)但是宽限期现在已经结束,并且该支持已被拒绝,即Java 8 JVM不再支持回退模式.
There was a grace period in which JVMs supported a fall-back mode for class files with broken StackMapTable
s just for scenarios like yours, where the tool support is not up-to-date. (See -XX:+FailoverToOldVerifier
or -XX:-UseSplitVerifier
) But the grace period is over now and that support has been declined, i.e. Java 8 JVMs do not support the fall-back mode anymore.
如果您想跟上Java开发并使用可能使用这些新版本功能的较新的类文件,那么您只有两种选择:
If you want to keep up with the Java development and instrument newer class files which might use features of these new versions you have only two choices:
- 手动计算正确的
StackMapTable
- 使用支持计算正确的
StackMapTable
属性的工具,例如ASM
,(请参阅 java -bytecode-asm )支持它
- Calculate the correct
StackMapTable
manually - Use a tool which supports calculating the correct
StackMapTable
attributes, e.g.ASM
, (see java-bytecode-asm) does support it
这篇关于使用bcel时构造方法的堆栈图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!