Java 用ASM字节码打印一个方法

Java 用ASM字节码打印一个方法,java,bytecode,java-bytecode-asm,Java,Bytecode,Java Bytecode Asm,我正在尝试(没有成功)只打印给定方法的内容。下面的代码几乎可以做到这一点: class MyTraceMethodVisitor extends MethodVisitor { public MyTraceMethodVisitor(MethodVisitor mv) { super(Opcodes.ASM4, mv); } @Override public void visitMaxs(int m

我正在尝试(没有成功)只打印给定方法的内容。下面的代码几乎可以做到这一点:

    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
没有签名、评论或其他任何东西。
如何实现这一点?

我能想到的最简单的方法是使用正则表达式或其他类型的字符串匹配,只过滤掉指令


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

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

这似乎可以做到这一点。。虽然我不明白怎么做:

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) {
        }
    }
}
import java.io.IOException;
导入java.io.PrintWriter;
导入java.io.StringWriter;
导入java.util.List;
导入org.objectweb.asm.Attribute;
导入org.objectweb.asm.ClassReader;
导入org.objectweb.asm.ClassVisitor;
导入org.objectweb.asm.Handle;
导入org.objectweb.asm.Label;
导入org.objectweb.asm.MethodVisitor;
导入org.objectweb.asm.opcode;
导入org.objectweb.asm.util.Printer;
导入org.objectweb.asm.util.Textifier;
导入org.objectweb.asm.util.TraceClassVisitor;
公共类字节码预印字机{
/**
*获取给定方法的字节码方法体。
*@param className要搜索的类名。
*@param methodName方法名称。
*@param methodDescriptor方法的描述符。
*如果希望只获得第一个,则可以为null
*具有给定名称的方法。
*@抛出异常
*/
公共静态字符串[]getMethod(字符串类名称、字符串方法名称、字符串方法描述符)引发IOException{
ClassReader ClassReader=新的ClassReader(className);
StringWriter StringWriter=新StringWriter();
PrintWriter PrintWriter=新的PrintWriter(stringWriter);
TraceClassVisitor TraceClassVisitor=新的TraceClassVisitor(null,新的SourceCodeTextifier(),printWriter);
MethodSelectorVisitor MethodSelectorVisitor=新方法SelectorVisitor(traceClassVisitor、methodName、methodDescriptor);
accept(methodSelectorVisitor,classReader.SKIP_DEBUG);
返回toList(stringWriter.toString());
}
/**
*获取给定方法的字节码方法体。
*@param className要搜索的类名。
*@param methodName方法名称。
*@抛出异常
*/
公共静态字符串[]getMethod(字符串类名称,字符串方法名称)引发IOException{
返回getMethod(className,methodName,null);
}
私有静态字符串[]toList(字符串str){
//不会对所有操作系统都正常工作
String[]operations=str.split(“[”+“\n“+”]);
for(int i=0;i@Test
public void someTest() throws IOException {
    String[] ops = BytecodePrettyPrinter.getMethod("java.lang.String", "<init>", null);

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