Search code examples
javajava-bytecode-asm

How can I find the line numbers of a method invocation in Java


I need to get the line numbers a specific method is invoked in a .class file.

I took a look at How can I find all the methods that call a given method in Java? It returns the methods that call a method but I need the line numbers in the caller methods, as well.


Solution

  • I solved it by manipulating the code on that link a little

    import java.io.InputStream;
    
    import org.objectweb.asm.*;
    import org.objectweb.asm.commons.*;
    
    public class App{
        public static void main( String[] args ) {
            try {
                Test test = new Test();
    
                    test.findCallers();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    
    
    class Test {
        private String targetClass;
        private Method targetMethod;
    
        private AppClassVisitor cv;
    
        class AppMethodVisitor extends MethodVisitor {
            boolean callsTarget;
            int line;
    
            public AppMethodVisitor() { 
                super(Opcodes.ASM5); 
            }
    
            public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
                if (owner.equals("Fibonacci") && name.equals("join") && desc.equals("()V")) {
                    callsTarget = true;
                    System.out.println("Function join called on " + this.line);
                }
                super.visitMethodInsn(opcode, owner, name, desc, itf);
            }
    
            public void visitCode() {
                callsTarget = false;
            }
    
            public void visitLineNumber(int line, Label start) {
                this.line = line;
            }
    
            public void visitEnd() {
                if (callsTarget){
                    System.out.println(cv.className + cv.methodName + cv.methodDesc  + line);
                }
            }
        }
    
        class AppClassVisitor extends ClassVisitor {
            private AppMethodVisitor mv = new AppMethodVisitor();
    
            public String className;
            public String methodName;
            public String methodDesc;
    
            public AppClassVisitor() { 
                super(Opcodes.ASM5); 
            }
    
            public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
                className = name;
            }
    
            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
                methodName = name;
                methodDesc = desc;
    
                return mv;
            }
        }
    
        public void findCallers() throws Exception {
            InputStream stream = App.class.getResourceAsStream("Fibonacci.class");
            ClassReader reader = new ClassReader(stream);
            cv = new AppClassVisitor();
    
            reader.accept(cv, 0);
    
            stream.close();
        }
    }
    

    Fibonacci.java content:

    public class Fibonacci extends Thread{
        int n;
        int result;
    
        public Fibonacci(int n){
            this.n = n;
        }
    
        public void run(){
            if((n == 0) || (n == 1)){
                result = 1;
            }else{
                Fibonacci f1 = new Fibonacci(n - 1);
                Fibonacci f2 = new Fibonacci(n - 2);
    
                f1.start();
                f2.start();
    
                try{
                    f1.join();
                    f2.join();
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
    
                result = f1.getResult() + f2.getResult();
            }
        }
    
        public int getResult(){
            return result;
        }
    
        public static void main(String[] args) {
            Fibonacci f1 = new Fibonacci(5);
            f1.start();
    
            try{
                f1.join();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
    
            System.out.println("Answer is " + f1.getResult());
        }
    }