Java 如何通过ASM捕获字节码中的运行时异常

Java 如何通过ASM捕获字节码中的运行时异常,java,java-bytecode-asm,Java,Java Bytecode Asm,我试图通过异常捕获运行时异常。我能够捕获常见的方法退出事件。 但是,控件从未在opcode==opcode.ATHROW中到达 我认为我把这些事件称为是做错了什么 以下是我的示例代码: public void visitCode() { // mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); // mv.visitLdcIns

我试图通过异常捕获运行时异常。我能够捕获常见的方法退出事件。 但是,控件从未在
opcode==opcode.ATHROW
中到达

我认为我把这些事件称为是做错了什么

以下是我的示例代码:

 public void visitCode() { 
//          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 
//          mv.visitLdcInsn("Entering method "  + fQMethodName); 
//          mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream","println","(Ljava/lang/String;)V"); 
            }


     @Override
    public void visitInsn(int opcode)
    {



         if (opcode == Opcodes.ATHROW)
         {
                          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;");

          mv.visitLdcInsn("Exiting on exception " );         
             mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
                    "(Ljava/lang/String;)V");
         }


        super.visitInsn(opcode);
    }


         public void visitMethodInsn(int opcode, String owner, String name,
                   String desc) {


                  super.visitMethodInsn(opcode, owner, name, desc);
                    //                
                  if (opcode == Opcodes.ATHROW)
                  {
                                              mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;");

                   mv.visitLdcInsn("Exiting on exception " + name);         
                      mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
                            "(Ljava/lang/String;)V");
                  }
                  else if (!name.equals("println")
                    && !name.equals("<init>")
                    && (opcode == Opcodes.INVOKEVIRTUAL || opcode == Opcodes.INVOKESPECIAL
                      || opcode == Opcodes.INVOKESTATIC || opcode == Opcodes.INVOKEDYNAMIC)) {




                      this.currentMethod = name;

                   onFinally(opcode);
                  }
                 }

                 private void onFinally(int opcode) {
                                          mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err",
                    "Ljava/io/PrintStream;");
                  mv.visitLdcInsn("Returning to " + fQMethodName + " from " + currentMethod);
                  mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
                    "(Ljava/lang/String;)V");
                 }

我的意图是添加动态try-catch块,如果抛出任何异常,请打印它。

RuntimeException
s不需要抛出
athrow
指令。
idiv
irem
指令可以抛出一个
算术异常
getfield
putfield
invoke…
指令可以抛出一个
NullPointerException
,举几个例子。所以在这些地方找不到athrow指令


拦截所有这些异常的唯一方法是插入一个处理代码的异常处理程序,如果愿意,可以重新抛出异常。

您知道实际的RuntimeException是在哪里抛出的吗?如果它是由JRE本身抛出的,那么这将不起作用,因为(我猜)您没有在java包中转换类(您无论如何都不应该这样做)。您的最新更新是否起作用?我也想在方法中添加try-catch块。请回复。我已经添加了
标签
声明并访问了它们。我还尝试了
visittrychtblock
方法。但是,在那之后,我不能再继续了。在这方面你能帮我一点忙吗?它正确吗?
mv.visittrychtblock(lTryBlockStart,lTryBlockEnd,lCatchBlockStart,“java/lang/Exception”);超级访问方法(操作码、所有者、名称、描述);mv.visitLabel(lTryBlockEnd);mv.visitJumpInsn(org.objectweb.asm.Opcodes.GOTO,lCatchBlockEnd);mv.visitLabel(lCatchBlockStart);mv.visitVarInsn(org.objectweb.asm.Opcodes.ASTORE,1);mv.visitVarInsn(org.objectweb.asm.Opcodes.ALOAD,1);mv.visitMethodInsn(org.objectweb.asm.Opcodes.INVOKEVIRTUAL,“java/lang/Exception”,“printStackTrace”,“V”);mv.visitLabel(lCatchBlockEnd);}
这超出了评论的范围;我建议为此打开一个新问题。我已编辑了该问题。请查收。提前感谢。
ldc
与调用方法无关。如果您的方法是类
foo.Bar
中的
publicstaticvoidexceptionoccurrend(Throwable){}
,那么只需执行
aload_1
将参数放在堆栈上,后跟
visitMethodInsn(Opcodes.INVOKESTATIC,“foo/Bar”,“exceptionoccurrend”,“(Ljava/lang/Throwable;)V)
public void visitCode() 
    {

        super.visitCode();

        this.visitTryCatchBlock(lblTryBlockStart, lblTryBlockEnd, lblCatchExceptionBlockStart, "java/lang/Exception");
        this.visitLabel(lblTryBlockStart);

    }  



    public void visitMaxs(int maxStack, int maxLocals)
    {
        // visit try block end label
        this.visitLabel(lblTryBlockEnd);
        // visit normal execution exit block
        this.visitJumpInsn(Opcodes.GOTO, exitBlock);

        // visit catch exception block
        this.visitLabel(lblCatchExceptionBlockStart);
        // store the exception
        this.visitVarInsn(Opcodes.ASTORE, 1);
        // load the exception
        this.visitVarInsn(Opcodes.ALOAD, 1);
        // call printStackTrace()
        //this.visitInsn(Opcodes.ATHROW);
        this.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V");


        // exit from this dynamic block
        this.visitLabel(exitBlock);

        super.visitMaxs(maxStack+2, maxLocals+2);

    }