在ASM字节码中打印方法很漂亮

我正在尝试(没有成功) 打印给定方法的内容。 以下代码几乎可以解决问题:

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 

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

答案已经很老了,需要编写很多代码。

截至asm v5打印方法说明很简单:

 // Setup for asm ClassReader, ClassWriter and your implementation of the ClassVisitor(eg: 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将在打印机的帮助下打印代码。

这似乎可以解决问题..虽然我不明白如何:

 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", "", null); for (String op : ops) System.out.println(op); } 

在ASM 4中,有一个名为Printer的新抽象。 您可以在TraceClassVisitor的构造函数中传递您自己的Printer实例(例如,扩展或复制Textifier实现)。

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

例如,使用OutputStreamWriter来写入String 。 保留所有ASM操作码类型的字符串值数组,然后如果该String中的一行包含操作码字符串,则该行是一条指令。