ASM: вывод Java-байт-кода и кода операции
Я пытаюсь написать программу, которая принимает файл.class и собирает все методы файла.class, а также содержимое каждого метода. Вот мой код
public class ClassReaderTest1 {
public static void main(String[] args) throws Exception{
InputStream in = new FileInputStream("*.class");
ClassReader reader = new ClassReader(in);
ClassNode classNode = new ClassNode();
reader.accept(classNode,0);
@SuppressWarnings("unchecked")
final List<MethodNode> methods = classNode.methods;
for(MethodNode m: methods){
InsnList inList = m.instructions;
System.out.println(m.name);
for(int i = 0; i< inList.size(); i++){
System.out.println(" " + Integer.toHexString(inList.get(i).getOpcode()));
}
}
}
}
и вот мой вывод
init>
ffffffff
ffffffff
19
b7
b1
ffffffff
main
ffffffff
ffffffff
b2
12
b6
ffffffff
ffffffff
3
36
ffffffff
ffffffff
b1
ffffffff
В конечном итоге я не хочу печатать эти значения, я просто хочу иметь возможность ссылаться на них в моей программе (я пытаюсь проверить, что я получаю правильные значения). Я получаю методы, как и ожидалось, но содержание методов не имеет смысла для меня. На мой взгляд, это не коды операций; в частности, "fffffff" не является кодом операции Java. То, что я хотел бы сделать, это распечатать все методы, как я делал выше, а затем, где у меня сейчас есть коды операций, распечатать байт-код Java, затем несколько пробелов и затем код операции. Например
main
bytecode **
.
.
Файл, который я загружаю в эту программу, состоит только из основного метода, одного оператора println и инициализации переменной int.
У меня вопрос: я делаю что-то не так или просто неправильно интерпретирую свои результаты? Кроме того, как я могу получить байт-код? Я не смог найти способ получить это. Я вижу это, когда использую подключаемый модуль java bytecode для затмения, но мне нужно иметь возможность ссылаться на него в моей программе.
заранее спасибо
1 ответ
Я смог понять это самостоятельно. Я публикую свое решение на тот случай, если у кого-то возникнет такая же проблема. Обратите внимание, что в моей реализации я не распечатываю коды операций (для этого нужно добавить только один оператор println).
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.List;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.*;
import org.objectweb.asm.util.*;
public class ClassReaderTest1 {
public static void main(String[] args) throws Exception{
InputStream in = new FileInputStream("*afile*");
ClassReader reader = new ClassReader(in);
ClassNode classNode = new ClassNode();
reader.accept(classNode,0);
@SuppressWarnings("unchecked")
final List<MethodNode> methods = classNode.methods;
for(MethodNode m: methods){
InsnList inList = m.instructions;
System.out.println(m.name);
for(int i = 0; i< inList.size(); i++){
System.out.print(insnToString(inList.get(i)));
}
}
}
public static String insnToString(AbstractInsnNode insn){
insn.accept(mp);
StringWriter sw = new StringWriter();
printer.print(new PrintWriter(sw));
printer.getText().clear();
return sw.toString();
}
private static Printer printer = new Textifier();
private static TraceMethodVisitor mp = new TraceMethodVisitor(printer);
}
и вот вывод, который производится
<init>
L0
LINENUMBER 1 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
main
L2
LINENUMBER 3 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "Hello World!!!"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L3
LINENUMBER 4 L3
ICONST_0
ISTORE 1
L4
LINENUMBER 5 L4
RETURN
L5