0

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

Abel Garcia
  • 178
  • 1
  • 12

2 Answers2

2

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

You can't. The ClassVisitor receives a call like

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

and before you return the MethodVistor, you need to capture the information from the parameters you are interested in.

If the code was compiled with debugging information, you can obtain the parameter and local variable names with 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

The code in the method will have source information "instruction" in the form of a visitLabel

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

By the access modifier. Use Modifier.isStatic(access)

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Thanks @Peter, however, in point 1) what you are saying is that the only information about the arguments is what you can get from the `String desc` parameter that it is passed to the `visitMethod`? – Abel Garcia Feb 22 '16 at 12:50
  • 1
    @AbelGarcia yes, you should have all the information you need before the VisitMethod is used. – Peter Lawrey Feb 22 '16 at 12:51
  • I just tried to do as @Peter suggested but it didn't work. I found out that the only way to get the method formal parameters name is to visit the local variables. The first ones will be the ones corresponding to the arguments. – Abel Garcia Feb 22 '16 at 15:32
  • @AbelGarcia the formal names are only available in the debug information. If it exists you can use it. The only thing you can rely on is the method signature which is the type information. I found the ASMIfier useful to get a dump of all the callbacks you can expect and what data they contain. – Peter Lawrey Feb 22 '16 at 15:36
  • @Peter Lawrey: not entirely correct. Starting with Java 8, there is a [dedicated attribute](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24) that can describe parameters even when no other debug information (i.e. for local variables) is included. Still, it requires to be turned on via compile-time switch. – Holger Feb 22 '16 at 17:33
  • @Holger I think you mean the -parameters option available from Java 8 update 60. – Peter Lawrey Feb 22 '16 at 18:27
  • @Peter Lawrey: if you are using `javac`, you have to use the `-parameters` option (which doesn’t require update 60), if you are using a different compiler or an IDE like Eclipse, the method to reach the equivalent switch might differ. – Holger Feb 22 '16 at 18:32
  • @Holger and you are sure this was added in an earlier version? – Peter Lawrey Feb 22 '16 at 18:41
  • 1
    I just tried `jdk1.8.0_05`. Both, the `javac` option and the Reflection method [`getParameters`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Executable.html#getParameters--) are present and correctly working. Update: tried a pre-release and works as well. – Holger Feb 22 '16 at 18:42
  • @Holger That is good to know, an article I read suggested you needed update 60+ – Peter Lawrey Feb 22 '16 at 19:51
0

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.

Abel Garcia
  • 178
  • 1
  • 12