2013-03-05 2 views
2

자바 에이전트 개발을 위해 Java Instrumentation과 ASM ByteCode Library를 사용하고 있습니다. 메소드에 의해 던진 런타임 예외를 얻는 방법?ASM ByteCode - 예외의 stackTrace

코드 첨부. 여기에서 메서드가 정상적으로 종료되는지 여부를 확인하거나 을 예외로 설정합니다. 그러나 예외를 검색 할 수 없습니다. 예외를 검색하는 방법?

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 블록에서 예외가 throw되면 실행은 스택의 예외와 함께 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

방법과 거기에 뭔가를 추가 할 수 있습니다. 하지만 현재 메서드 또는이 메서드에서 호출 된 메서드에 의해 throw 된 모든 예외 스택 추적을 인쇄 할. 어떻게이 메서드에 의해 던져지고있는 예외 개체를 잡을 것인가? –

+0

그래서,/I는 시작의 핸들을 가지고 말을 어떤 말을 수 있습니다 – AKS

+0

예제 코드에서 'ASTORE, 1'이있는 행은 예외를 지역 변수 1에 저장합니다. 그런 다음 원하는만큼 여러 번 거기에서 검색 할 수 있습니다. 예제에서는'ALOAD, 1'을 로딩하고'printStackTrace'를 호출합니다. –