java - ASM ByteCode - 异常的 stackTrace

标签 java assembly java-bytecode-asm

我正在使用 java Instrumentation 和 ASM ByteCode Library 来开发 Javaagent。 如何获取方法抛出的运行时异常?

附上代码。这里获取该方法是否正常终止或抛出 一个异常(exception)。但无法检索异常。如何检索异常?

 package com.abc.agent.servlet;

 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;

 import com.abc.agent.matcher.HttpServletMethodMatcher;

public class AbcServletMethodVisitorAdapter extends MethodVisitor {
    private String methodName;
    private String className;
    private String description;
    private boolean doMethodMatch;
    private int opcode = -1;

public AbcServletMethodVisitorAdapter(MethodVisitor mv , String  methodName , String description , String className) {
    super(Opcodes.ASM4, mv);
    this.methodName = methodName;
    this.className = className;
    this.description = description;
    this.doMethodMatch = false;
}

public void visitCode() {
    super.visitCode();
    if(methodName.equals("<clinit>") || methodName.equals("<init>"))
        return;
    HttpServletMethodMatcher httpServletMethodMatcher = new HttpServletMethodMatcher(className , methodName , description);
    this.doMethodMatch =  httpServletMethodMatcher.isHttpServletMatch();
    if(this.doMethodMatch){
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitVarInsn(Opcodes.ALOAD, 1);
        mv.visitLdcInsn(this.className);
        mv.visitLdcInsn(this.methodName);
        mv.visitLdcInsn(this.description);
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/abc/agent/trace/RootTracer", "httpServletDoMethodBegin", "(Ljava/lang/Object;Ljavax/servlet/http/HttpServletRequest;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
        mv.visitCode();
    }
    else // Other Methods defined in the HttpServlet...
    {
        mv.visitLdcInsn(this.className);
        mv.visitLdcInsn(this.methodName);
        mv.visitLdcInsn(this.description);
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/abc/agent/trace/RootTracer", "httpServletOtherMethodBegin", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
        mv.visitCode();
    }
}

public void visitMaxs(int maxStack, int maxLocals) {
    super.visitMaxs(maxStack + 4, maxLocals);
    }

public void visitInsn(int opcode) {
    if(methodName.equals("<clinit>") || methodName.equals("<init>")){
        // Do nothing....
    }
    else{
        if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
            this.opcode = opcode;
            mv.visitLdcInsn(this.className);
            mv.visitLdcInsn(this.methodName);
            mv.visitLdcInsn(this.description);
            mv.visitLdcInsn(this.opcode);
            if(this.doMethodMatch) {
                mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/abc/agent/trace/RootTracer", "httpServletDoMethodEnd", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V");
            }
            else{
                mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/abc/agent/trace/RootTracer", "httpServletOtherMethodEnd", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V");
            }
        }
    }
    mv.visitInsn(opcode);
}
}

最佳答案

这是一个简单的例子。首先,我们为代码中需要引用的各个点创建一堆标签。然后我们在方法执行周围设置一个 try-catch block 。然后我们调用“try” block 中的代码,如果try block 中抛出异常,执行将跳转到异常在堆栈上的lCatchBlockStart标签处。示例 catch block 调用 e.printStackTrace()。

在本例中我使用了局部变量 1,因为它恰好可用。您可能必须选择其他一些变量 - 当然,您没有将异常存储在变量中,但这样做很常见。

除非您在构建 ClassWriter 时使用 COMPUTE_FRAMES 标志,否则您还必须插入访问Frame() 调用。

Label lTryBlockStart = new Label();
Label lTryBlockEnd = new Label();
Label lCatchBlockStart = new Label();
Label lCatchBlockEnd = new Label();
// set up try-catch block for RuntimeException
mv.visitTryCatchBlock(lTryBlockStart, lTryBlockEnd, lCatchBlockStart, "java/lang/RuntimeException");
mv.visitLabel(lTryBlockStart);
// code to call the method goes here
mv.visitLabel(lTryBlockEnd);
mv.visitJumpInsn(GOTO, lCatchBlockEnd); // when here, no exception was thrown, so skip exception handler

// exception handler starts here, with RuntimeException stored on the stack
mv.visitLabel(lCatchBlockStart);
mv.visitVarInsn(ASTORE, 1); // store the RuntimeException in local variable 1
// here we could for example do e.printStackTrace()
mv.visitVarInsn(ALOAD, 1); // load it
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/RuntimeException", "printStackTrace", "()V");

// exception handler ends here:
mv.visitLabel(lCatchBlockEnd);

关于java - ASM ByteCode - 异常的 stackTrace,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15222911/

相关文章:

c++ - 帮助理解生成的部分汇编代码

Eclipse:错误(字节码大纲)源文件[在项目中]不在其项目的构建路径上

java.lang.UnsupportedOperationException : This feature requires ASM8_EXPERIMENTAL 异常

java - 在我的框架中使用 GroupLayout

c 文件中内联汇编代码的编译错误,可能与分支有关

java - 以字节形式读取文件,无需换行符或回车符

assembly - 为什么eax包含向量参数的数量?

java - IDE 想要将我的 Int 转换为 boolean 值?我的方法之一说它不能应用

java - Java 是 "pass-by-reference"还是 "pass-by-value"?

java - Spring 异常处理程序 - 使用带注释和 xml 定义