-1

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

AntoineG
  • 93
  • 7
  • 1
    Welcome to SO. You are asking about the BB advice API, but omitting the advice class, showing us what you have achieved so far. That is a counter-productive way to ask a question. Please learn what an [MCVE](https://stackoverflow.com/help/mcve) is and how it helps you to get better answers. The good news is: All of what you asked about is easily possible with BB. – kriegaex Aug 05 '21 at 23:53
  • Thank you sir ! I am not sure that I fully understood your comment though : do you mean that the title is inapproriate as I am working with the Advice class and not the API ? To have a MCVE in my post, should I display here the complete implementation of the TraceAdvice class ? Would that be considered enough ? – AntoineG Aug 06 '21 at 11:40
  • Just follow the MCVE link and read the article. MCVE means, minimal but reproducible. In this concrete example, you were asking about the BB advice API, but omitted the advice you were asking about. Anyway, I am happy that my educated guess helped you to solve the problem. Sometimes, we do not get so lucky and speculation creates more confusion than it helps. – kriegaex Aug 06 '21 at 15:27

1 Answers1

0

Have you tried adding parameters like these to your before/after advice methods?

    @Origin Method method,
    @AllArguments(readOnly = false, typing = DYNAMIC) Object[] args

Printing the Method object already gives to the method signature in one easy step. You can also print Object[] args in any way you see fit, e.g. Arrays.toString(args) or even Arrays.deepToString(args).

I simply copied the snippet from one of my advices. If you do not wish to change any argument values, of course you do not need readOnly = false.

kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • Works perfectly, thank you very much ! Do you know where I can get the full list of decorators working with onEnter and onExit ? – AntoineG Aug 06 '21 at 11:35
  • Look for nested static interfaces in the [Advice](https://javadoc.io/doc/net.bytebuddy/byte-buddy/latest/net/bytebuddy/asm/Advice.html) class API. Just click through the Javadoc. Unfortunately, the tutorial is both outdated and incomplete. Sometimes it helps to read internal tests in the BB code. I have not used BB much and only in a burst for two months or so a while ago. I am not an expert either, but this is what I did. – kriegaex Aug 06 '21 at 15:23