使用ASM进行字节码分析

Using ASM for bytecode analysis

我正在评估使用 ASM 作为实现某些字节码分析的框架的可能性。到目前为止,我一直在玩几个例子,但有几件事我需要解决: 1) 我看不出如何使用 MethodVisitor class(完整的参数类型名称和形式名称)检测方法的完整签名。

2) 如果正在分析的 .class 文件关联了 java 源代码,如何使用源代码中的行号 link 字节码指令

3) 如何区分ClassVisitor中的实例字段和静态字段

1) I don't see how I can detect a method fully signature with the MethodVisitor class (full argument type names and formal names).

你不能。 ClassVisitor 收到类似

的调用
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) 

在 return MethodVistor 之前,您需要从您感兴趣的参数中捕获信息。

如果代码编译时带有调试信息,可以通过visitLocalVariable

获取参数和局部变量名

2) In case the .class file being analysed has the java source associated, how to link bytecode instructions with the line numbers in the source

方法中的代码将以 visitLabel

的形式包含源信息 "instruction"

3) How to differentiate between instance fields and static fields in a ClassVisitor

access 修饰符。使用 Modifier.isStatic(access)

1) 实际上,我设法提取详细的方法签名(参数类型和名称以及 return 类型)作为 MethodVisitor 实现的一部分。 备注:这仅在 class 文件编译时包含调试信息时有效。

@Override
public MethodVisitor visitMethod(int access, String name,
        String desc, String signature, String[] exceptions) {



    try {
        final LinkedList<String> parameters;
        final boolean isStaticMethod;

        Type[] args = Type.getArgumentTypes(desc);
        Type ret = Type.getReturnType(desc);

        parameters = new LinkedList<String>();            
        isStaticMethod = Modifier.isStatic(access);

        return new MethodVisitor(Opcodes.ASM5) {
            // assume static method until we get a first parameter name
            public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
                if (isStaticMethod && parameters.size() < args.length) {
                    parameters.add(args[index].getClassName()+" " +name);
                } else if (index > 0 && parameters.size() < args.length) {
                    // for non-static the 0th arg is "this" so we need to offset by -1
                    parameters.add(args[index-1].getClassName() +" " +name);
                }
            }

            @Override
            public void visitEnd() {
                 System.out.println("Method: "+ret.getClassName()+" "+name+"("+String.join(", ", parameters)+")");
                super.visitEnd();
            }
        };
    } catch (Exception e) {
        throw e;
    }     

这将为标准 main 生成以下输出:

Method: void main(java.lang.String[] args)

2) 参数 Label startLabel end 包括有关相应源的信息,只要在编译发生时包含源。

3) 参见@Peter Lawrey 回复。