Search code examples
javajava-bytecode-asmbytecode-manipulationjvm-bytecode

Using ASM for bytecode analysis


I am evaluating the possibility of using ASM as framework for implementing some bytecode analysis. So far I have been playing with a few examples but there are a couple of things that I need to sort out: 1) I don't see how I can detect a method fully signature with the MethodVisitor class (full argument type names and formal names).

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

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


Solution

  • 1) Actually I manage to extract detailed method signature (arguments types and names and return type) as part of a MethodVisitor implementation. Remark: this only works if the class file was compiled including debug info.

    @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;
        }     
    

    Which will produce the following output for an standard main:

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

    2) The arguments Label start and Label end include information about the corresponding source as long as there is a source included when the compilation took place.

    3) See @Peter Lawrey reply.