2011-11-02 3 views
5

나는 주어진 방법의 내용을 인쇄하려고 (성공과 함께) 노력하고 있습니다. 다음 코드 거의 트릭을 수행합니다 단지꽤 방법을 ASM의 바이트 코드로 인쇄

SIPUSH 777 
    IRETURN 

ClassReader classReader = new ClassReader("something.Point"); 
PrintWriter printWriter = new PrintWriter(System.out); 
TraceClassVisitor traceClassVisitor = new TraceClassVisitor(printWriter); 
MyClassVisitor myClassVisitor = new MyClassVisitor(traceClassVisitor); 
classReader.accept(myClassVisitor, ClassReader.SKIP_DEBUG); 

내가 좀하고 싶습니다 무엇

// class version 50.0 (50) 
// access flags 0x21 
public class something/Point { 


    // access flags 0x1 
    public get777()I 
    SIPUSH 777 
    IRETURN 
} 

의 결과로 실행

class MyTraceMethodVisitor extends MethodVisitor { 
     public MyTraceMethodVisitor(MethodVisitor mv) { 
      super(Opcodes.ASM4, mv); 
     } 

     @Override 
     public void visitMaxs(int maxStack, int maxLocals) { 
     } 
    } 

    class MyClassVisitor extends ClassVisitor { 
     public MyClassVisitor(ClassVisitor cv) { 
      super(Opcodes.ASM4, cv); 
     } 

     @Override 
     public FieldVisitor visitField(int access, String name, String desc, 
       String signature, Object value) { 
      return null; 
     } 

     @Override 
     public MethodVisitor visitMethod(int access, String name, String desc, 
       String signature, String[] exceptions) { 

      if (name.equals("get777")) 
       return new MyTraceMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions)); 

      return null; 
     } 
    } 

이었다

서명, 의견 및 기타 사항은 없습니다. 어떻게해야합니까?

답변

4

대답은 이미 꽤 오래 쓰기를 포함 많은 코드. ASM의 V5 인쇄 방법 지침으로

는 간단하다 :

ClassVisitor의 구현에
// Setup for asm ClassReader, ClassWriter and your implementation of the ClassVisitor(e.g.: YourClassVisitor) 
final ClassReader reader = new ClassReader(classBytes); 
final ClassWriter writer = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS); 
final ClassVisitor visitor =new YourClassVisitor(Opcodes.ASM5, visitor); 

는 단순히 visitMethod 방법을 재정의합니다. 예 :

public class YourClassVisitor extends ClassVisitor { 
    public InstrumentationClassVisitor(int api, ClassVisitor cv) { 
     super(api, cv); 
    } 

    @Override 
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { 
     MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); 
     Printer p = new Textifier(Opcodes.ASM5) { 
      @Override 
      public void visitMethodEnd() { 
       print(new PrintWriter(System.out)); // print it after it has been visited 
      } 
     }; 
     return new TraceMethodVisitor(mv, p); 
    } 
} 

TraceMethodVisitor는 classVisitor에서 메소드 안내 등을 방문하는 이벤트 호출을 수신합니다. 코드는 프린터의 도움으로 TraceMethodVisitor에 의해 인쇄됩니다.

+3

59 페이지의 asm4 가이드를 살펴보십시오. –

0

제가 생각할 수있는 가장 쉬운 방법은 정규식이나 다른 유형의 문자열을 사용하여 지침을 필터링하는 것입니다.

예를 들어 String에 글을 쓰려면 OutputStreamWriter을 사용하십시오. all ASM opcode types의 문자열 값 배열을 유지 한 다음 해당 String에있는 라인에 opcode 문자열이 포함되어 있으면 해당 라인이 명령어입니다.

+0

나는 ASM의 방문객 (또는 직접 제작 한 파생물)에서 직접 깨끗한 결과물을 얻을 수있는 솔루션을 선호합니다.하지만 더 나은 것을 찾지 못하면 귀하의 접근 방식을 사용하게 될 것입니다! –

+0

메소드 이름도 opcode 정도라면? – thejh

+0

글쎄, 이것이 완벽한 해결책이 아니라는 것을 알았지 만, 당신이 대소 문자를 매치하더라도 작동 할 것이다. 대부분의 경우 BIPUSH 또는 ICONST_1 (대문자 사용)이라는 메소드를 찾을 수 없습니다. – jli

1

ASM 4에는 Printer라는 새로운 추상화가 있습니다. TraceClassVisitor의 생성자에서 자신의 Printer 인스턴스 (예 : Textifier 구현 확장 또는 복사)를 전달할 수 있습니다.

3

이것은 내가 방법을 이해하지는 않지만 .. 트릭을 할 것 같다 :

import java.io.IOException; 
import java.io.PrintWriter; 
import java.io.StringWriter; 
import java.util.List; 

import org.objectweb.asm.Attribute; 
import org.objectweb.asm.ClassReader; 
import org.objectweb.asm.ClassVisitor; 
import org.objectweb.asm.Handle; 
import org.objectweb.asm.Label; 
import org.objectweb.asm.MethodVisitor; 
import org.objectweb.asm.Opcodes; 
import org.objectweb.asm.util.Printer; 
import org.objectweb.asm.util.Textifier; 
import org.objectweb.asm.util.TraceClassVisitor; 


public class BytecodePrettyPrinter { 
    /** 
    * Gets us the bytecode method body of a given method. 
    * @param className The class name to search for. 
    * @param methodName The method name. 
    * @param methodDescriptor The method's descriptor. 
    *       Can be null if one wishes to just get the first 
    *       method with the given name. 
    * @throws IOException 
    */ 
    public static String[] getMethod(String className, String methodName, String methodDescriptor) throws IOException { 
     ClassReader classReader = new ClassReader(className); 
     StringWriter stringWriter = new StringWriter(); 
     PrintWriter printWriter = new PrintWriter(stringWriter); 
     TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, new SourceCodeTextifier(), printWriter); 
     MethodSelectorVisitor methodSelectorVisitor = new MethodSelectorVisitor(traceClassVisitor, methodName, methodDescriptor); 
     classReader.accept(methodSelectorVisitor, ClassReader.SKIP_DEBUG); 

     return toList(stringWriter.toString()); 
    } 

    /** 
    * Gets us the bytecode method body of a given method. 
    * @param className The class name to search for. 
    * @param methodName The method name. 
    * @throws IOException 
    */ 
    public static String[] getMethod(String className, String methodName) throws IOException { 
     return getMethod(className, methodName, null); 
    } 

    private static String[] toList(String str) { 
     //won't work correctly for all OSs 
     String[] operations = str.split("[" + "\n" + "]"); 

     for (int i = 0; i < operations.length; ++i) { 
      operations[i] = operations[i].trim(); 
     } 

     return operations; 
    } 

    private static class MethodSelectorVisitor extends ClassVisitor { 
     private final String methodName; 
     private final String methodDescriptor; 

     public MethodSelectorVisitor(ClassVisitor cv, String methodName, String methodDescriptor) { 
      super(Opcodes.ASM4, cv); 
      this.methodName = methodName; 
      this.methodDescriptor = methodDescriptor; 
     } 

     @Override 
     public MethodVisitor visitMethod(int access, String name, String desc, 
       String signature, String[] exceptions) { 

      if (methodName.equals(name)) { 
       if (methodDescriptor == null) 
        return new MaxVisitFilterMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions)); 

       if (methodDescriptor.equals(desc)) 
        return new MaxVisitFilterMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions)); 
      } 

      return null; 
     } 
    } 

    private static class MaxVisitFilterMethodVisitor extends MethodVisitor { 
     public MaxVisitFilterMethodVisitor(MethodVisitor mv) { 
      super(Opcodes.ASM4, mv); 
     } 

     @Override 
     public void visitMaxs(int maxStack, int maxLocals) { 
     } 
    } 


    private static class SourceCodeTextifier extends Printer { 
     public SourceCodeTextifier() { 
      this(Opcodes.ASM4); 
     } 

     protected SourceCodeTextifier(final int api) { 
      super(api); 
     } 

     @Override 
     public void visit(
      final int version, 
      final int access, 
      final String name, 
      final String signature, 
      final String superName, 
      final String[] interfaces) 
     { 
     } 

     @Override 
     public void visitSource(final String file, final String debug) { 
     } 

     @Override 
     public void visitOuterClass(
      final String owner, 
      final String name, 
      final String desc) 
     { 
     } 

     @Override 
     public Textifier visitClassAnnotation(
      final String desc, 
      final boolean visible) 
     { 
      return new Textifier(); 
     } 

     @Override 
     public void visitClassAttribute(final Attribute attr) { 
     } 

     @Override 
     public void visitInnerClass(
      final String name, 
      final String outerName, 
      final String innerName, 
      final int access) 
     { 
     } 

     @Override 
     public Textifier visitField(
      final int access, 
      final String name, 
      final String desc, 
      final String signature, 
      final Object value) 
     { 
      return new Textifier(); 
     } 

     @Override 
     public Textifier visitMethod(
      final int access, 
      final String name, 
      final String desc, 
      final String signature, 
      final String[] exceptions) 
     { 
      Textifier t = new Textifier(); 
      text.add(t.getText()); 
      return t; 
     } 

     @Override 
     public void visitClassEnd() { 
     } 

     @Override 
     public void visit(final String name, final Object value) { 
     } 


     @Override 
     public void visitEnum(
      final String name, 
      final String desc, 
      final String value) 
     { 
     } 

     @Override 
     public Textifier visitAnnotation(
      final String name, 
      final String desc) 
     { 
      return new Textifier(); 
     } 

     @Override 
     public Textifier visitArray(
      final String name) 
     { 
      return new Textifier(); 
     } 

     @Override 
     public void visitAnnotationEnd() { 
     } 

     @Override 
     public Textifier visitFieldAnnotation(
      final String desc, 
      final boolean visible) 
     { 
      return new Textifier(); 
     } 

     @Override 
     public void visitFieldAttribute(final Attribute attr) { 
      visitAttribute(attr); 
     } 

     @Override 
     public void visitFieldEnd() { 
     } 

     @Override 
     public Textifier visitAnnotationDefault() { 
      return new Textifier(); 
     } 

     @Override 
     public Textifier visitMethodAnnotation(
      final String desc, 
      final boolean visible) 
     { 
      return new Textifier(); 
     } 

     @Override 
     public Textifier visitParameterAnnotation(
      final int parameter, 
      final String desc, 
      final boolean visible) 
     { 
      return new Textifier(); 
     } 

     @Override 
     public void visitMethodAttribute(final Attribute attr) { 
     } 

     @Override 
     public void visitCode() { 
     } 

     @Override 
     public void visitFrame(
      final int type, 
      final int nLocal, 
      final Object[] local, 
      final int nStack, 
      final Object[] stack) 
     { 
     } 

     @Override 
     public void visitInsn(final int opcode) { 
     } 

     @Override 
     public void visitIntInsn(final int opcode, final int operand) { 
     } 

     @Override 
     public void visitVarInsn(final int opcode, final int var) { 
     } 

     @Override 
     public void visitTypeInsn(final int opcode, final String type) { 
     } 

     @Override 
     public void visitFieldInsn(
      final int opcode, 
      final String owner, 
      final String name, 
      final String desc) 
     { 
     } 

     @Override 
     public void visitMethodInsn(
      final int opcode, 
      final String owner, 
      final String name, 
      final String desc) 
     { 
     } 

     @Override 
     public void visitInvokeDynamicInsn(
      String name, 
      String desc, 
      Handle bsm, 
      Object... bsmArgs) 
     { 
     } 

     @Override 
     public void visitJumpInsn(final int opcode, final Label label) { 
     } 

     @Override 
     public void visitLabel(final Label label) { 
     } 

     @Override 
     public void visitLdcInsn(final Object cst) { 
     } 

     @Override 
     public void visitIincInsn(final int var, final int increment) { 
     } 

     @Override 
     public void visitTableSwitchInsn(
      final int min, 
      final int max, 
      final Label dflt, 
      final Label... labels) 
     { 
     } 

     @Override 
     public void visitLookupSwitchInsn(
      final Label dflt, 
      final int[] keys, 
      final Label[] labels) 
     { 
     } 

     @Override 
     public void visitMultiANewArrayInsn(final String desc, final int dims) { 
     } 

     @Override 
     public void visitTryCatchBlock(
      final Label start, 
      final Label end, 
      final Label handler, 
      final String type) 
     { 
     } 

     @Override 
     public void visitLocalVariable(
      final String name, 
      final String desc, 
      final String signature, 
      final Label start, 
      final Label end, 
      final int index) 
     { 
     } 

     @Override 
     public void visitLineNumber(final int line, final Label start) { 
     } 

     @Override 
     public void visitMaxs(final int maxStack, final int maxLocals) { 
     } 

     @Override 
     public void visitMethodEnd() { 
     } 

     public void visitAttribute(final Attribute attr) { 
     } 
    } 
} 

을 하나는 사용하여 실행할 수 있습니다

@Test 
public void someTest() throws IOException { 
    String[] ops = BytecodePrettyPrinter.getMethod("java.lang.String", "<init>", null); 

    for (String op : ops) 
     System.out.println(op); 
} 
+0

이 솔루션에 관한. ASM의 어떤 버전이 필요합니까? org.ow2.asm asm v5.0.3을 사용 중이며 org.objectweb.asm.util.Printer 아래의 클래스가 없습니다. – mangusbrother