Как распечатать все методы, вызываемые во время выполнения в Java, с помощью инструментовки?

Я хочу распечатать все методы, которые вызываются во время выполнения. Они должны быть напечатаны в том порядке, в котором они вызываются, и если они вызываются несколько раз, они должны быть напечатаны несколько раз.

Это можно использовать для обратного проектирования — посмотреть, какие функции вызываются, когда вы нажимаете кнопку или выполняете определенное действие.

Я хочу использовать для этого агенты и инструменты Java.


person Nopslide    schedule 26.03.2017    source источник
comment
Возможный дубликат Получить текущую трассировку стека в Java   -  person Ravi    schedule 26.03.2017
comment
Для этого и нужен отладчик. Вы можете отслеживать каждый метод по мере его вызова. Вы можете использовать API-интерфейс отладчика, чтобы сделать это программно, но пошаговое выполнение кода, вероятно, будет проще, поскольку вы также можете видеть используемые значения.   -  person Peter Lawrey    schedule 26.03.2017
comment
Уточнил, что я хочу, чтобы это было сделано с помощью java-агента.   -  person Nopslide    schedule 26.03.2017


Ответы (1)


Это можно сделать с помощью агентов Java и инструментальной библиотеки.

Агент Java — отдельный код, который можно запустить перед основной частью кода.

Инструментарий — изменение исходного кода во время загрузки программы.

Код для работы

(взято из appcrawler и немного изменен):

Исходный код agent.jar:

Простой трансформер.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());
  } 
}

МАНИФЕСТ.mf:

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

Возьмите эти файлы и упакуйте их в файл jar. Также не забудьте включить файлы из javassist.jar (можно загрузить с www.javassist.org) и tools.jar. (находится в Program Files/Java/jdk/lib/). Не уверен, что второй нужен, но в статье написано, что он почему-то нужен.

Теперь вы можете использовать этот jar-файл в качестве java-агента.

java -javaagent:agent.jar YourJavaProgram

И вуаля. Агент Java будет обрабатывать все методы и распечатывать каждый метод, вызванный во время выполнения.

person Nopslide    schedule 26.03.2017
comment
Примечание. Этот код работает для простых программ, но может не работать с более сложными, как это было с моим проектом. - person Nopslide; 27.03.2017