How to print out all methods called during runtime in Java using instrumentation?

前端 未结 1 390
深忆病人
深忆病人 2021-01-16 14:29

I want to print out all methods that get called during runtime. They should be printed out in the order that they\'re called in and if they\'re called multiple times, they s

相关标签:
1条回答
  • 2021-01-16 15:19

    This can be done using Java Agents and an instrumentation library.

    Java agent - Separate code that can be made to run before the main part of the code.

    Instrumentation - Changing the source code during the load-time of a program.

    Code for making it work

    (taken from appcrawler and modified slightly):

    The agent.jar source code:

    SimpleTransformer.java:

    package test;
    
    import java.security.*;
    import java.lang.instrument.*;
    import java.util.*;
    import javassist.*;
     
    public class SimpleTransformer implements ClassFileTransformer {
     
      public SimpleTransformer() {
        super();
      }
     
      public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
        return transformClass(redefiningClass,bytes);
      }
     
      private byte[] transformClass(Class classToTransform, byte[] b) {
        ClassPool pool = ClassPool.getDefault();
        CtClass cl = null;
        try {
          cl = pool.makeClass(new java.io.ByteArrayInputStream(b));
          CtBehavior[] methods = cl.getDeclaredBehaviors();
          for (int i = 0; i < methods.length; i++) {
            if (methods[i].isEmpty() == false) {
              changeMethod(methods[i]);
            }
          }
          b = cl.toBytecode();
        }
        catch (Exception e) {
          e.printStackTrace();
        }
        catch (Throwable t) {
          t.printStackTrace();
        }
        finally {
          if (cl != null) {
            cl.detach();
          }
        }
        return b;
      }
     
      private void changeMethod(CtBehavior method) throws NotFoundException, CannotCompileException {
        /*if (method.getName().equals("doIt")) {
          method.insertBefore("System.out.println(\"started method at \" + new java.util.Date());");
          method.insertAfter("System.out.println(\"ended method at \" + new java.util.Date());");
        }*/
        
    
      
              //MY CODE
          //!Modifier.isAbstract(method.getModifiers()) -- abstract methods can't be modified. If you get exceptions, then add this to the if statement.
          //native methods can't be modified.
          if (!Modifier.isNative(method.getModifiers())) {
              String insertString = "System.out.println(\"started method " + method.getName() + "\");";
              method.insertBefore(insertString);
          }
      }
    

    SimpleMain.java:

    package test;
    
    import java.lang.instrument.Instrumentation;
    
    public class SimpleMain {
      public static void premain(String agentArguments, Instrumentation instrumentation) {  
        instrumentation.addTransformer(new SimpleTransformer());
      } 
    }
    

    MANIFEST.mf:

    Manifest-Version: 1.0
    Boot-Class-Path: javassist.jar
    Premain-Class: test.SimpleMain
    

    Take these files and package them into a jar file. Also make sure to include files from javassist.jar (downloadable from www.javassist.org) and tools.jar (found in Program Files/Java/jdk/lib/). Not sure if the second one is necessary, but the article says it is for some reason.

    Now you can use this jar file as a java agent.

    java -javaagent:agent.jar YourJavaProgram
    

    And voila. The java agent will instrument all methods and print out every method called during execution.

    0 讨论(0)
提交回复
热议问题