2 Replies Latest reply on Jan 7, 2016 3:54 AM by Panagiotis Sotiropoulos

    Can I use Byteman to add some code before every line of some method of some class? What would be the rule?

    Panagiotis Sotiropoulos Newbie

      Hello,

       

      I am developing some project which needs to add some code in front of every line of some method of some class dynamically. Can I use Byteman?

      What would be the rule?

       

      Thank you in advance,

      Panagiotis

        • 1. Re: Can I use Byteman to add some code before every line of some method of some class? What would be the rule?
          Andrew Dinn Master

          Hi Panagiotis,

           

          Byteman allows you to use a location clause to do this. Your rule (rules) should look like this

           

          RULE inject trace at line 55
          CLASS MyClass
          METHOD myMethod
          AT LINE 55
          IF TRUE
          DO traceln("trace injected at line 55");
          ENDRULE
          

           

          The traceln call is normally injected before any code on line 55 gets executed (although see below for some rather unintuitive counter-examples to that). Of course, this will only work if the method actually has code at line 55.  If it starts at line 56 then you will get an injection failure. Also, the target class (MyClass in the example)  must be  compiled using the -g flag to ensure that line numbers are included in the bytecode.

           

          If you to inject code before all lines in the method you will need a rule for each line.

           

          In general using AT LINE is not a very good idea. Line numbers can change even when the target method remains the same (because lines may get added or deleted in earlier methods)  so rules built around this type of location are much more fragile than rules which identify a trigger location based on the structure of the target method (e.g. AT ENTRY, AT CALL println etc). Can you tell me why you need to inject code at each line of the method? Maybe I can suggest a better way to do what you need.

           

          Here's the interesting counter-example. When expressions straddle multiple lines and include subexpressions then the line numbers injected into the bytecode may not fully represent the order of execution of expressions in the source code so injected coee may execute out of order wiht the source line numbers. Here's an example of that

           

          public class Test
          {
              public static void main(String[] args)
              {
                  new Test().test(args, 0, args.length);
              }
          
              public void test(String[] args, int start, int end)
              {
                  while (start < end) {
                      System.out.println("args[" +
                                         Integer.toString(start) +
                                         "] = " + args[start]);
                      start++;
                  }
              }
          }
          

           

           

          RULE inject at line 12
          CLASS Test
          METHOD test
          AT LINE 12
          IF true
          DO traceln("*** at line 12 start = " + $start)
          ENDRULE
          
          RULE inject at toString
          CLASS Test
          METHOD test
          AT CALL Integer.toString
          IF true
          DO traceln("*** at toString start = " + $start)
          ENDRULE
          

           

          Here is the output when this is run

           

          $ bmjava -l test.btm Test a b c d
          *** at toString start = 0
          args[0] = a
          *** at line 12 start = 0
          *** at toString start = 1
          args[1] = b
          *** at line 12 start = 1
          *** at toString start = 2
          args[2] = c
          *** at line 12 start = 2
          *** at toString start = 3
          args[3] = d
          *** at line 12 start = 3
          

           

          Firstly, note that the call to println starts on line 11 and finishes on line 13 and the call toString starts and ends on on line 12.

           

          In the bytecode the marker for line 12 is placed after the call to println because that call starts on line 11. So the call to println executes before the injected code for rule 'inject at line 12' which makes some sort of sense. However, println() must be passed the result of the call to Integer.toString(). So, even though that toString is called on line 12 in the source code it gets called before the call to println(). Which means rule 'inject at toString' is executed before rule 'inject at line 12'. A conundrum eh? :-)

           

          regards,

           

           

          Andrew Dinn

          • 2. Re: Can I use Byteman to add some code before every line of some method of some class? What would be the rule?
            Panagiotis Sotiropoulos Newbie

            Thank you Andrew.

             

            So, I think that a good solution for me, would be to call some empty method (doing nothing, eg void empty(){}) before every line and then using some rule, eg :

             

            RULE inject at empty 

            CLASS Test 

            METHOD test 

            AT ENTRY empty

            IF true 

            DO traceln("*** before empty() do something" ) 

            ENDRULE 

             

            so, that I can write fewer rules.

             

            Thank you very much,

            Panagiotis