Java 允许轻松打印字节码指令*包括*参数的库
我正在寻找一个库,它可以轻松地让我看到一个方法的给定字节码。例如:Java 允许轻松打印字节码指令*包括*参数的库,java,reflection,bytecode,Java,Reflection,Bytecode,我正在寻找一个库,它可以轻松地让我看到一个方法的给定字节码。例如: ALOAD 0 INVOKEVIRTUAL ns/c.m ()I IRETURN 我两个都试过了: ASM:实际上,我可以让它打印指令和参数,但我很难理解它的整个访问者范式,也就是说,我所做的最好的工作就是漂亮地打印整个类 BCEL:可以让它打印指令,但没有参数 JavaAssist:可以让它打印指令,但没有参数 其中,ASM是唯一支持最新Java版本的。对于访客,您可能需要阅读。它是为旧版本的ASM API编写的,但是访问
ALOAD 0
INVOKEVIRTUAL ns/c.m ()I
IRETURN
我两个都试过了:
- ASM:实际上,我可以让它打印指令和参数,但我很难理解它的整个访问者范式,也就是说,我所做的最好的工作就是漂亮地打印整个类
- BCEL:可以让它打印指令,但没有参数
- JavaAssist:可以让它打印指令,但没有参数
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.TraceClassVisitor;
public class Main {
public static void main(String[] args) throws Exception {
if (1 > args.length) {
System.err.println("No arguments.");
return;
}
InputStream is = Main.class.getResourceAsStream(args[0]);
ClassReader cr = new ClassReader(is);
cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), 0);
}
}
哪些输出(当作为参数传递给Main.class时):
//类版本50.0(50)
//访问标志0x21
公共班机{
//编译自:Main.java
//访问标志0x1
公共()V
L0
线路号11 L0
阿洛德0
调用特定的java/lang/Object。()V
返回
MAXSTACK=1
最大局部数=1
//访问标志0x9
publicstaticmain([Ljava/lang/String;)V抛出java/lang/Exception
L0
线路号13 L0
ICONST_1
阿洛德0
排列长度
IF_ICMPLE L1
L2
行号14 L2
GETSTATIC java/lang/System.err:Ljava/io/PrintStream;
最不发达国家“没有理由”
INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V
L3
线路号15 L3
返回
L1
17号线L1
框架相同
LDC LMain;.class
阿洛德0
ICONST_0
AALOAD
InvokeVirtualJava/lang/Class.getResourceAsStream(Ljava/lang/String;)Ljava/io/InputStream;
阿斯托尔1号
L4
线路号18 L4
新建org/objectweb/asm/ClassReader
重复
阿洛德1号
调用特殊的org/objectweb/asm/ClassReader(Ljava/io/InputStream;)V
阿斯托尔2号
L5
线路号19 L5
阿洛德2号
新建org/objectweb/asm/util/TraceClassVisitor
重复
新的java/io/PrintWriter
重复
GETSTATIC java/lang/System.out:Ljava/io/PrintStream;
调用特殊的java/io/PrintWriter。(Ljava/io/OutputStream;)V
调用特殊的org/objectweb/asm/util/TraceClassVisitor。(Ljava/io/PrintWriter;)V
ICONST_0
INVOKEVIRTUAL org/objectweb/asm/ClassReader.accept(Lorg/objectweb/asm/ClassVisitor;I)V
L6
线路号28 L6
返回
MAXSTACK=6
最大局部变量=3
}
谢谢你的链接,但我已经读过了。它解释了ASM访问者工作原理背后的基本概念,而且它确实是生成新方法/执行基本指令所需的一切。另一方面,它不能帮助我理解如何按照我想要的方式实际操作一台像样的打印机。“字节码转换”部分有一个序列图也适用于您的案例。您使用的是TraceClassVisitor,而不是ClassWriter。其他一切都是一样的。访问者从以前的事件生成器(例如ClassReader或以前的访问者)接收事件序列并且可以改变事件的顺序。所以,如果跟踪访问者没有收到特定的事件类型,它将不会打印出来。你猜不到,但这不是闹着玩的!听起来你找到了解决方案。
// class version 50.0 (50)
// access flags 0x21
public class Main {
// compiled from: Main.java
// access flags 0x1
public <init>()V
L0
LINENUMBER 11 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x9
public static main([Ljava/lang/String;)V throws java/lang/Exception
L0
LINENUMBER 13 L0
ICONST_1
ALOAD 0
ARRAYLENGTH
IF_ICMPLE L1
L2
LINENUMBER 14 L2
GETSTATIC java/lang/System.err : Ljava/io/PrintStream;
LDC "No arguments."
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L3
LINENUMBER 15 L3
RETURN
L1
LINENUMBER 17 L1
FRAME SAME
LDC LMain;.class
ALOAD 0
ICONST_0
AALOAD
INVOKEVIRTUAL java/lang/Class.getResourceAsStream (Ljava/lang/String;)Ljava/io/InputStream;
ASTORE 1
L4
LINENUMBER 18 L4
NEW org/objectweb/asm/ClassReader
DUP
ALOAD 1
INVOKESPECIAL org/objectweb/asm/ClassReader.<init> (Ljava/io/InputStream;)V
ASTORE 2
L5
LINENUMBER 19 L5
ALOAD 2
NEW org/objectweb/asm/util/TraceClassVisitor
DUP
NEW java/io/PrintWriter
DUP
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
INVOKESPECIAL java/io/PrintWriter.<init> (Ljava/io/OutputStream;)V
INVOKESPECIAL org/objectweb/asm/util/TraceClassVisitor.<init> (Ljava/io/PrintWriter;)V
ICONST_0
INVOKEVIRTUAL org/objectweb/asm/ClassReader.accept (Lorg/objectweb/asm/ClassVisitor;I)V
L6
LINENUMBER 28 L6
RETURN
MAXSTACK = 6
MAXLOCALS = 3
}