I'm currently working on a Java agent whose job is to track (and let's say print) the current location of each thread in the program. As an example, if I have a Java program like so :
public class MyClass {
public static void a(String s) {
b(s);
}
public static void b(String s) {
System.out.println(s);
}
public static void main(String[] args) {
a("Hello")
}
}
I would like my instrumented program to output :
[+] Thread X : Entering MyClass.main([])
[+] Thread X : Entering MyClass.a(java.lang.String Hello)
[+] Thread X : Entering MyClass.b(java.lang.String Hello)
[+] Thread X : Entering java.io.PrintStream.println(java.lang.String Hello)
Hello
[-] Thread X : Leaving java.io.PrintStream.println(java.lang.String Hello)
[-] Thread X : Leaving MyClass.b(java.lang.String Hello)
[-] Thread X : Leaving MyClass.a(java.lang.String Hello)
[-] Thread X : Leaving MyClass.main([])
I cannot modify the original program, that is why I am creating an agent. I think the Advice API is the way to go, as it allows me to append code at the beginning and the end of each and every function with a very low computation overhead, but I'm running into two issues :
- My main question : Can the Advice API retrieve the signature (Class + method) of the method it has been called on ?
- The second issue concerns transforming every method of every class. Currently, my plan is to create a dozen of AgentBuilder, each targetting functions with zero, one, two, three, ... arguments. Is there a better way to go ? What about the types of the arguments ?
Currently, I have the following agent :
public static void agentmain(String agentArgs, Instrumentation inst) {
AgentBuilder mybuilder = new AgentBuilder.Default()
.disableClassFormatChanges()
.with(RedefinitionStrategy.RETRANSFORMATION)
.with(InitializationStrategy.NoOp.INSTANCE)
.with(TypeStrategy.Default.REDEFINE);
mybuilder.type(nameMatches(".*"))
.transform((builder, type, classLoader, module) -> {
try {
return builder
.visit(Advice.to(TraceAdvice.class).on(isMethod()));
} catch (SecurityException e) {
e.printStackTrace();
return null;
}
}).installOn(inst);
}
and my TraceAdvice class implements onEnter and onExit respectively with System.out.println("Entering")
and System.out.println("Exiting")
.
Thank you in advance