7 Replies Latest reply on Sep 22, 2016 9:17 AM by Andrew Dinn

    Javagent Bytemap .btm file not working

    GAURAV BHATNAGAR Newbie

      Hi,

      I am using IntelliJ and have written one simple class with blank main method. I have written one .btm file having below contents:-

       

      RULE trace main entry

      CLASS ThreadInteraction

      METHOD main

      AT ENTRY

      IF true

      DO traceln("entering main")

      ENDRULE

       

      RULE trace main exit

      CLASS ThreadInteraction

      METHOD main

      AT EXIT

      IF true

      DO traceln("exiting main")

      ENDRULE

       

      Problem is :- When I am running the java class by passing VM options as below, entering main and exiting main statements(in above .btm file) are not printed in the console implying bytemap not working. Can anyone please suggest what is missing ?

       

      -javaagent:C:\Users\gaurav\byteman-download-2.1.2-bin\byteman-download-2.1.2\lib\byteman.jar=script:C:\Users\gaurav\threadInteraction.btm

        • 1. Re: Javagent Bytemap .btm file not working
          Andrew Dinn Master

          Hi Guarav,

           

          What java release are you using to run the java program?

          • 2. Re: Javagent Bytemap .btm file not working
            GAURAV BHATNAGAR Newbie

            Andrew, System was not allowing me to post until 30 mins. and hence the delay in my response.

             

            (1) Java 8

             

            (2) Andrew, does / or \ matters ?

             

            (3) Also, my java class is :- C:\Users\gaurav\IdeaProjects\icb-tbe\ios-tbe-demo\src\main\java\com\jpm\ib\ios\tbe\ThreadInteraction.java

             

            and my .class file is :-  C:\Users\gaurav\IdeaProjects\icb-tbe\ios-tbe-demo\target\classes\com\jpm\ib\ios\tbe\ThreadInteraction.class

             

            and my .btm file is :- C:\Users\gaurav  and I have specified CLASS name as just  ThreadInteraction  (without any of the above 2 full paths) . Is it fine ?

            • 3. Re: Javagent Bytemap .btm file not working
              Andrew Dinn Master

              Hi Gaurav,

               

              GAURAV BHATNAGAR wrote:

               

              (1) Java 8

               

              I am afraid I need a more precise answer than that. Where did you obtain the Java program from? Is it a full SDK that you downloaded?

               

              GAURAV BHATNAGAR wrote:

               

              (2) Andrew, does / or \ matters ?

               

              No, you should be able to specify the path using either / or \.

               

              GAURAV BHATNAGAR wrote:

               

              (3) Also, my java class is :- C:\Users\gaurav\IdeaProjects\icb-tbe\ios-tbe-demo\src\main\java\com\jpm\ib\ios\tbe\ThreadInteraction.java

               

              and my .class file is :- C:\Users\gaurav\IdeaProjects\icb-tbe\ios-tbe-demo\target\classes\com\jpm\ib\ios\tbe\ThreadInteraction.class

               

              It doesn't really matter what the source file is only the bytecode file. There should not be a problem using that path.

               

              GAURAV BHATNAGAR wrote:

               

              and my .btm file is :- C:\Users\gaurav and I have specified CLASS name as just ThreadInteraction (without any of the above 2 full paths) . Is it fine ?

               

              Yes it is fine. In the rule's CLASS clause you can simply specify the class name without a package name or you can specify it with full package name i.e. CLASS jpm.ib.ios.tbe.ThreadInteraction. Similarly, you can specify the method name with or without a signature i.e. METHOD main or METHOD main(String[]).

               

              One thing you could do in order to see if the agent is being loaded or your rules are being processed is to add an extra java command line argument

               

                -Dorg.jboss.byteman.verbose

               

              This should print a variety of trace when (if) the Byteman agent runs. If so then please post details of all output and I will try to diagnose it form there.

               

              regards,

               

               

              Andrew Dinn

              • 4. Re: Javagent Bytemap .btm file not working
                GAURAV BHATNAGAR Newbie

                (1) I am using Full JDK 8

                (2) My whole intention to see how ByteMap works is to interrupt running thread and introduce some behaviour. To begin with I have written below simple class having 2 threads. The .btm fil ewhich I added should have output

                entering main  and then Submitting Task1 etc... but when I run java program from IntelliJ , it just shows Submitting Task1.

                 

                import java.io.BufferedReader;

                import java.io.InputStream;

                import java.io.InputStreamReader;

                import java.util.concurrent.*;

                 

                class ThreadInteraction {

                 

                  static BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>();

                 

                  public static void main(String[] args) throws Exception {

                  ExecutorService executorService = Executors.newFixedThreadPool(2);

                  final Future<Object> submit = executorService.submit(() -> {

                  String threadName = Thread.currentThread().getName();

                  System.out.println("Submitting Task1..." + threadName);

                  int i = 0;

                  while (true) {

                  blockingQueue.put(i++);

                  System.out.println("Thread " + threadName + " inserting " + i + " into the blocking Queue");

                  Thread.sleep(1000);

                  }

                  });

                  final Future<Object> submit1 = executorService.submit(() -> {

                  String threadName = Thread.currentThread().getName();

                  System.out.println("Submitting Task2..." + threadName);

                  while (true) {

                  System.out.println("Thread " + threadName + " taking out " + blockingQueue.take() + " from the blocking Queue");

                  }

                  });

                  }

                }

                 

                (3) Andrew as you suggested I tried putting VM option to see any debug information but nothing works. Output comes as below:- (i.e. no debug information, just as per written program). Please see attached image of my VM arguments.

                Submitting Task1...pool-1-thread-1

                Thread pool-1-thread-1 inserting 1 into the blocking Queue

                Submitting Task2...pool-1-thread-2

                Thread pool-1-thread-2 taking out 0 from the blocking Queue

                Thread pool-1-thread-2 taking out 1 from the blocking Queue

                ....

                • 5. Re: Javagent Bytemap .btm file not working
                  Andrew Dinn Master

                  Hi Gaurav,

                   

                  This is very odd behaviour. It doesn't look to me like the agent is being loaded although it may possibly be that the script is not being loaded. However, I would have expected to see some exceptions being thrown in both those cases.

                   

                  In order to understand what is going wrong here it is probably best to simplify things to see if a very basic base works. Could you please compile the following basic Hello world program and try to run it from a command shell using one very simple rule:

                   

                  Contents of file Hello.java:

                  public class Hello

                  {

                      public static void main(String[] args)

                      {

                          System.out.println("Hello world!");

                      }

                  }

                   

                  Contents of file hello.btm:

                  RULE Test rule at entry

                  CLASS Hello

                  METHOD main

                  IF true

                  DO traceln("entering main")

                  ENDRULE

                   

                  Create both of these files placing them into your working directory (let's assume you use C:\Users\gaurav\hello)

                  Open a command shell and change to that directory

                   

                  > cd C:\Users\gaurav\hello

                   

                  The first thing I need is to see what output the java command prints. So, execute this

                   

                  > java-version

                   

                  n.b. you will need to ensure that the java program is in your PATH. Alternatively you can provide the full path to java as part of the command -- something like this:

                   

                  > C:\Users\gaurav\downloads\java-1.8.0\bin\java -version

                   

                  Now compile the java code

                   

                  > javac Hello.java

                   

                  once again you need to ensure that the javac program is in your path or else provide a full path. Also, after this command finishes check that there is a file called Hello.class in your working directory.

                   

                  If it compiles ok then run the program with Byteman from the command line

                   

                  > java -Dorg.jboss.byteman.verbose -javaagent:C:\Users\gaurav\byteman-download-2.1.2-bin\byteman-download-2.1.2\lib\byteman.jar=script:hello.btm Hello

                   

                  If you can post the output from each of these commands I may be able to identify what is going wrong.

                   

                  regards,

                   

                   

                  Andrew Dinn

                  • 6. Re: Javagent Bytemap .btm file not working
                    GAURAV BHATNAGAR Newbie

                    Many Thanks Andrew for the response. I tried changing bytemap version to latest i.e. 3.0.6 and surprisingly it worked. Earlier I was suing 2.1.2. May be 2.1.2 doesn't work in IntelliJ ??? Not sure

                     

                    Not I am trying to print stack trace of the one of the thread execution. my .btm file looks like :-

                     

                    RULE trace main entry
                    CLASS ThreadInteraction
                    METHOD main
                    AT ENTRY
                    IF true
                    DO traceln("entering main")
                    ENDRULE

                     

                    RULE trace thread stack
                    CLASS ThreadInteraction
                    METHOD workingConsumer
                    AFTER READ Thread.currentThread().getName()
                    IF true
                    DO traceln(formatStack())
                    ENDRULE

                     

                    RULE trace main exit
                    CLASS ThreadInteraction
                    METHOD main
                    AT EXIT
                    IF true
                    DO traceln("exiting main")
                    ENDRULE

                     

                     

                    My Java Class look slike below(I have created 2 private methods and want to print stack trace of the thread running from 1st line of one of the private method. But above 2nd rule is not running.

                    Kindly let me know

                    (1) How to call private method?

                    (2) How to inject rule say from in between the method after 3rd or 4th line say after some System.out ..line or some variable assignment etc. I mean can we directly put exact same line of code in .btm file as DO ?

                    (3) Can I have multiple IFs or multiple DOs ..say If 1 condition is satisfied then print something and pause all running threads in the JVM , do some logic and then resume all running threads ..

                     

                    My java class is asbelow:-

                     

                    import java.io.BufferedReader;

                    import java.io.InputStream;

                    import java.io.InputStreamReader;

                    import java.util.concurrent.*;

                     

                    class ThreadInteraction {

                     

                       static BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>();

                     

                       public static void main(String[] args) throws Exception {

                      ExecutorService executorService = Executors.newFixedThreadPool(2);

                       final Future<Object> submit = executorService.submit(() -> {

                       return workingProducer();

                      });

                       final Future<Object> submit1 = executorService.submit(() -> {

                       return workingConsumer();

                      });

                      }

                     

                       private static Object workingConsumer() throws InterruptedException {

                      String threadName = Thread.currentThread().getName();

                      System.out.println("Submitting Task2..." + threadName);

                       while (true) {

                      System.out.println("Thread " + threadName + " taking out " + blockingQueue.take() + " from the blocking Queue");

                      }

                      }

                     

                       private static Object workingProducer() throws InterruptedException {

                      String threadName = Thread.currentThread().getName();

                      System.out.println("Submitting Task1..." + threadName);

                       int i = 0;

                       while (true) {

                       blockingQueue.put(i++);

                      System.out.println("Thread " + threadName + " inserting " + i + " into the blocking Queue");

                      Thread.sleep(1000);

                      }

                      }

                    }

                    • 7. Re: Javagent Bytemap .btm file not working
                      Andrew Dinn Master

                      Hi Gaurav,

                       

                      I'm glad to hear that Byteman is now working (although I don't know of any reason why 2.1.2 should not have worked).

                       

                      Let's deal with the failure of your 2nd rule. I am afraid it your AT clause is not using a valid syntax. Here are two different location specifiers which will work:

                       

                      Variant 1:

                       

                      RULE trace thread stack
                      CLASS ThreadInteraction
                      METHOD workingConsumer
                      AFTER CALL Thread.getName()
                      IF true
                      DO traceln(formatStack())
                      ENDRULE

                       

                      or

                       

                      Variant 2:

                       

                      RULE trace thread stack
                      CLASS ThreadInteraction
                      METHOD workingConsumer
                      AFTER WRITE $threadName
                      IF true
                      DO traceln(formatStack())
                      ENDRULE

                       

                      In variant 1 the AFTER CALL location identifies the point where the first call to method Thread.getName() has occurred. In this case the method call to be matched has been specified with class name, method name and signature but the package name has been omitted. You can provide the full name if you want. You can also omit the class name and/or signature which means Byteman will ignore those elements when searching for matching calls. n.b. if your code contained more than one call then you can include a count such as AT CALL Thread.getName() 2 to specify that you are interested in the second call.

                       

                      In variant 2 the location specifies the point where a local variable of the target method is written, in this case the first write to variable threadName. Notice that when you mention a method variable you have to prefix the name with  a $ sign. This distinguishes the reference from variables introduced in a rule's BIND clause which don't use a $ prefix. Once again this location refers to the first assignment i.e. the point where the variable is initialised but you can supply a count after the local variable name to refer to later point in the code where the variable gets assigned.

                       

                      N.B. variant 2 will only work if you compile your class using javac -g -- that ensures that the compiled class bytecode contains details of local variable names like threadName. If you compile without this flag then Byteman will not find a variable called threadName so it will assume that the rule does not apply.

                       

                      Finally, I'll suggest one more improvement. Your rule uses traceln(formatStack()) which is ok. However, there is a builtin called traceStack() which is identical to calling traceln(formatStack()).

                       

                      Now let's move on to your other questions.

                       

                      1) How do you call a private method? Well, just write a call to it. For example, let's assume your class ThreadInteraction has a private method

                       

                      private void dump()

                      {

                        System.out.println("Thread interaction " + this " +

                                           " executing in thread " + Thread.currentThread().getName());

                      }

                       

                      Your rule could execute the method like this

                       

                      RULE trace thread stack
                      CLASS ThreadInteraction
                      METHOD workingConsumer
                      AFTER WRITE $threadName
                      IF true
                      DO traceStack();

                         $this.dump()
                      ENDRULE

                       

                      Notice that method dump is an instance method. So, you need to call the method with some object of class ThreadInteraction as the target for the method call. $this refers to the local variable this in the call to method workingConsumer i.e. it is an instance of class ThreadInteraction. If you have not compiled with javac -g then $this will not work (same reason as above) but you can use $0 instead. Similarly, if workingConsumer had parameters you could refer to them by name if you compile using -g or by number ($1, $2 etc) if you did not compile with -g.

                       

                      2) How to inject before/after the call to System.out.traceln

                       

                      This rule will inject just before the while loop

                       

                      RULE trace thread stack
                      CLASS ThreadInteraction
                      METHOD workingConsumer
                      AFTER CALL println
                      IF true
                      DO traceStack();

                         $this.dump()
                      ENDRULE

                       

                      This rule will inject inside the while loop just before the 2nd call to System.out.traceln

                       

                       

                      RULE trace thread stack
                      CLASS ThreadInteraction
                      METHOD workingConsumer
                      AT CALL println 2
                      IF true
                      DO traceStack();

                         $this.dump()
                      ENDRULE

                       

                      Notice that for this second rule the call to traceln happens after the call to blocikngQueue.take() so the code injected by Byteman gets called after the take() call immediately before the traceln call.

                       

                      3) Can I have multiple IFs or multiple DOs ..say If 1 condition is satisfied then print something and pause all running threads in the JVM , do some logic and then resume all running threads

                       

                      You can only have one IF and one DO in a rule. But you can inject more than one rule at the same location. The rules mostly get run in the order they are injected. The exception is rules with location AFTER XXX which get run in reverse order (this means the nesting of pairs of AT rules and AFTER rules is maintained). I can't tell you how to do what you are asking for as the JDK doesn't provide a way for user code to pause or resume all running threads. What I suggest is that you read the Byteman Programmer's Guide and try to  how to use the builtin rendezvous methods to suspend threads and then resume them again. If you are not sure how to use them after you have looked at the explanation of how they work then I suggest you work through the first 3 Byteman tutorials. The last one explains how to use injected code to start and stop threads. You can find pointers to the Programmer's Guide and tutorials on the Byteman documentation page.

                       

                      regards,

                       

                      Andrew Dinn