【问题标题】:Using ASM for bytecode analysis使用 ASM 进行字节码分析
【发布时间】:2016-06-03 21:06:42
【问题描述】:

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

2) 如果正在分析的.class文件关联了java源,如何将字节码指令与源中的行号链接起来

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

【问题讨论】:

    标签: java java-bytecode-asm bytecode-manipulation jvm-bytecode


    【解决方案1】:

    1) 我看不到如何使用 MethodVisitor 类检测方法的完全签名(完整的参数类型名称和正式名称)。

    你不能。 ClassVisitor 收到类似的调用

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

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

    如果代码是带调试信息编译的,可以用visitLocalVariable获取参数和局部变量名

    2) 如果正在分析的.class文件关联了java源,如何将字节码指令与源中的行号链接起来

    方法中的代码会有visitLabel形式的源信息“指令”

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

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

    【讨论】:

    • 谢谢@Peter,但是,在第 1 点)您所说的是,关于参数的唯一信息是您可以从传递给 visitMethodString desc 参数中获得的信息?
    • @AbelGarcia 是的,在使用 VisitMethod 之前,您应该拥有所需的所有信息。
    • 我只是尝试按照@Peter 的建议进行操作,但没有成功。我发现获取方法形式参数名称的唯一方法是访问局部变量。第一个将是与参数相对应的那些。
    • @AbelGarcia 正式名称仅在调试信息中可用。如果存在,您可以使用它。您唯一可以依赖的是方法签名,它是类型信息。我发现 ASMIfier 可用于转储您可以预期的所有回调以及它们包含的数据。
    • 我刚试过jdk1.8.0_05javac 选项和反射方法 getParameters 都存在并且正常工作。更新:尝试了预发布并且也可以正常工作。
    【解决方案2】:

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

    @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 生成以下输出:

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

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

    3) 请参阅@Peter Lawrey 回复。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多