2011-11-02 22 views
5

Tôi đang cố gắng (không có thành công) để in chỉ nội dung của một phương thức nhất định. Các mã sau gần hiện các trick:Khá in một phương pháp trong ASM Bytecode

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

chạy nó với

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

dẫn đến

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


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

Những gì tôi muốn để có được chỉ là

SIPUSH 777 
    IRETURN 

không có chữ ký, ý kiến ​​và bất cứ điều gì. Làm cách nào tôi có thể thực hiện điều đó?

Trả lời

4

Câu trả lời là đã khá cũ và liên quan đến viết nhiều mã.

Tính đến asm v5 hướng dẫn phương pháp in ấn là đơn giản:

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

Trong thực hiện của bạn trong những ClassVisitor, chỉ cần ghi đè lên các phương pháp visitMethod. Dưới đây là một ví dụ:

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 sẽ nhận được các yêu cầu sự kiện để truy cập hướng dẫn phương pháp, vv bởi classVisitor. Mã sau đó sẽ được in bởi TraceMethodVisitor với sự trợ giúp của Máy in.

+3

Ngoài ra hãy xem trong hướng dẫn asm4 ở trang 59. –

0

Điều đơn giản nhất tôi có thể nghĩ là sử dụng regex hoặc một loại đối sánh chuỗi khác chỉ lọc ra các hướng dẫn.

Ví dụ: sử dụng một số OutputStreamWriter để viết cho số String thay thế. Giữ một mảng các giá trị chuỗi của all ASM opcode types, và sau đó nếu một dòng trong đó String chứa một chuỗi opcode thì dòng đó là một lệnh.

+0

Tôi muốn một giải pháp mà tôi muốn có được đầu ra sạch trực tiếp từ khách truy cập của ASM (hoặc bất kỳ tay phái sinh nào được chế tác bởi chính tôi) .. nhưng tôi sẽ sử dụng cách tiếp cận của bạn nếu tôi không tìm thấy gì tốt hơn! –

+0

Điều gì sẽ xảy ra nếu tên phương thức cũng là một mã opcode? – thejh

+0

Vâng, tôi nhận ra đây không phải là một giải pháp hoàn hảo, tuy nhiên nó sẽ làm việc nếu bạn phù hợp với trường hợp là tốt. Trong hầu hết các trường hợp, bạn sẽ không tìm thấy một phương thức gọi là BIPUSH hoặc ICONST_1 (với cách viết hoa đó). – jli

1

Trong ASM 4, có một trừu tượng mới được gọi là Máy in. bạn có thể chuyển trường hợp Máy in của riêng bạn (ví dụ: mở rộng hoặc sao chép triển khai Trình tạo văn bản) trong hàm tạo của TraceClassVisitor.

3

Điều này dường như làm các trick .. mặc dù tôi không hiểu làm thế nào:

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

và người ta có thể chạy nó bằng cách sử:

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

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

Về giải pháp này. Phiên bản ASM nào là bắt buộc? Tôi đang sử dụng org.ow2.asm asm v5.0.3 và các lớp dưới org.objectweb.asm.util.Printer không được tìm thấy – mangusbrother

Các vấn đề liên quan