2013-03-05 141 views
2

我正在使用Java Instrumentation和ASM ByteCode庫來開發Javaagent。 如何獲得由方法拋出的運行時異常?ASM ByteCode - 異常的堆棧跟蹤

附代碼。這裏得到方法是否正常終止或拋出 例外。但無法檢索異常。如何檢索異常?

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

回答

2

這是一個簡單的例子。首先,我們爲需要參考的代碼中的變量點創建一堆標籤。然後我們圍繞方法執行建立一個try-catch塊。然後我們調用「try」塊中的代碼,並且如果在try塊中引發異常,則執行將跳轉到lCatchBlockStart標籤,但堆棧中的例外。示例catch塊調用e.printStackTrace()。

我在本例中使用了局部變量編號1,因爲它碰巧可用。您可能需要選擇一些其他的變量 - 當然你不存儲在一個變量的例外,但它是相當普遍這樣做。

除非在構建ClassWriter時使用COMPUTE_FRAMES標誌,否則還必須插入visitFrame()調用。

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

嗨,你的幫助..我已附上代碼,在此代碼,其中插入你所指定的行感謝... – 2013-03-06 05:03:41

+0

因此,可以說,我有啓動手柄/任何結束方法,我可以添加一些東西。但是我想打印由當前方法或方法調用的當前方法拋出的任何異常的堆棧跟蹤。我將如何獲得這個方法拋出的異常對象? – AKS 2016-02-02 12:52:04

+0

在我的示例代碼中,使用'ASTORE,1'的行將異常存儲在局部變量1中。然後,您可以根據需要多次檢索該異常。在我的例子中,我加載了'ALOAD,1'並且在其上調用'printStackTrace'。 – 2016-02-02 16:14:03