我正在尝试(没有成功)打印仅给定方法的内容。以下代码几乎可以解决问题:
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
没有签名,评论和任何内容。 我怎么能做到这一点?
答案 0 :(得分: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接收访问方法指令等的事件调用。然后,TracemeethodVisitor将在打印机的帮助下打印代码。
答案 1 :(得分: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);
}
答案 2 :(得分:1)
在ASM 4中,有一个名为Printer的新抽象。您可以在TraceClassVisitor的构造函数中传递您自己的Printer实例(例如,扩展或复制Textifier实现)。
答案 3 :(得分:0)
我能想到的最简单的事情就是使用正则表达式或其他类型的字符串匹配来过滤掉指令。
例如,使用OutputStreamWriter
代替String
。保留一个字符串值数组all ASM opcode types,然后如果String
中的一行包含操作码字符串,则该行是一条指令。