使用bcel时构造方法的堆栈图 [英] Construct the stackmap of method while using bcel

查看:89
本文介绍了使用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's Code attribute does not have a StackMapTable attribute, it has an implicit stack map attribute (§4.10.1). This implicit stack map attribute is equivalent to a StackMapTable attribute with number_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 StackMapTables 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,(请参阅)支持它
  • 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆