2011-11-02 50 views
5

我想(没有成功)打印只有给定的方法的内容。下面的代码几乎的伎俩:在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; 
     } 
    } 

运行它与

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 
} 

我想什么让刚刚

SIPUSH 777 
    IRETURN 

没有签名,评论和任何。 我该怎么做到这一点?

回答

4

,答案已经很老了,涉及到写作许多代码。

由于ASM V5印刷方法的指令很简单:

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

在你执行ClassVisitor,只需重写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

我能想到的最简单的事情是使用正则表达式或其他类型的匹配字符串来过滤掉指令。

例如,使用OutputStreamWriter代替写入String。保留一组all ASM opcode types的字符串值,然后如果该String中的一行包含操作码字符串,则该行是一条指令。

+0

我更喜欢一个解决方案,我可以直接从ASM的访问者那里获得干净的输出(或者我自己制作的任何派生手)。但是如果我找不到更好的东西,我会用你的方法! –

+0

如果一个方法名也是一个操作码呢? – 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