-
1. Re: Javagent Bytemap .btm file not working
adinn Sep 21, 2016 11:53 AM (in response to gaurav6281)Hi Guarav,
What java release are you using to run the java program?
-
2. Re: Javagent Bytemap .btm file not working
gaurav6281 Sep 21, 2016 12:15 PM (in response to adinn)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
adinn Sep 21, 2016 12:40 PM (in response to gaurav6281)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
gaurav6281 Sep 21, 2016 1:14 PM (in response to adinn)(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
....
-
bytemap.jpg 4.2 MB
-
-
5. Re: Javagent Bytemap .btm file not working
adinn Sep 22, 2016 4:46 AM (in response to gaurav6281)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
gaurav6281 Sep 22, 2016 5:39 AM (in response to adinn)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")
ENDRULERULE trace thread stack
CLASS ThreadInteraction
METHOD workingConsumer
AFTER READ Thread.currentThread().getName()
IF true
DO traceln(formatStack())
ENDRULERULE trace main exit
CLASS ThreadInteraction
METHOD main
AT EXIT
IF true
DO traceln("exiting main")
ENDRULEMy 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
adinn Sep 22, 2016 9:17 AM (in response to gaurav6281)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())
ENDRULEor
Variant 2:
RULE trace thread stack
CLASS ThreadInteraction
METHOD workingConsumer
AFTER WRITE $threadName
IF true
DO traceln(formatStack())
ENDRULEIn 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()
ENDRULENotice 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()
ENDRULEThis 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()
ENDRULENotice 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