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

标签 java java-bytecode-asm

我试图通过异常捕获运行时异常。我能够捕获通常的方法退出事件。 但是,控制永远不会到达 opcode==Opcodes.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");
                 }

运行时异常时,现有栈内容被清空,只剩下throwable对象。我可以通过 ASM 获取栈顶元素(基本上就是栈帧)吗?

提前致谢。

编辑:

这是我在添加 try - catch block 后修改的程序。

@Holger:感谢您的帮助。真的很感激。

所以,我试图在 ASM 的 MethodVisitor 中插入动态 try-catch block 。

这是我的代码:

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);

    }

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

最佳答案

RuntimeException 不需要抛出 athrow 指令。 idivirem 指令可以抛出 ArithmeticExceptiongetfieldputfieldinvoke... 指令可以抛出 NullPointerException,这里仅举几个例子。所以你在这些地方找不到 throw 指令。

拦截所有这些的唯一方法是注入(inject)一个异常处理程序来处理您的代码,并根据需要重新抛出异常。

关于java - 如何通过ASM捕获字节码中的运行时异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18916202/

相关文章:

java - 如何在jsp中将字节数据显示到img标签中?

java - 如何用 Jsoup 填写表格?

java - 决定线程池大小时如何看待超线程?

java - 从 Unsafe 创建的匿名类构建 ClassReader

java.lang.VerifyError : (class: Main, 方法:主签名:([Ljava/lang/String;)V) 堆栈大小太大

java - ListView 适配器的 null 异常

Java 字节/源代码分析 - 如何以编程方式找到使用另一个类的所有类/方法?

java - 使用 ASM 从方法体中删除异常

hadoop - 分析 Hadoop

java - Android View 布局组件相互叠加