-
1. Re: Can I use Byteman to add some code before every line of some method of some class? What would be the rule?
adinn Jan 6, 2016 6:16 AM (in response to takis)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?
takis Jan 7, 2016 3:54 AM (in response to takis)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