From 6117cdf5a1dd76226a11dcbbf1660643ee2077f7 Mon Sep 17 00:00:00 2001 From: jbachorik Date: Mon, 17 Dec 2018 17:33:25 +0100 Subject: [PATCH 001/412] Bump version to 1.3.12-SNAPSHOT --- benchmark/pom.xml | 6 +++--- make/build.properties | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index c3143a790..26c41b034 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -53,17 +53,17 @@ questions. com.sun.tools.btrace btrace-client - 1.3.11.3 + 1.3.12-SNAPSHOT com.sun.tools.btrace btrace-agent - 1.3.11.3 + 1.3.12-SNAPSHOT com.sun.tools.btrace btrace-boot - 1.3.11.3 + 1.3.12-SNAPSHOT sun.jdk diff --git a/make/build.properties b/make/build.properties index d01b7050c..6b126282f 100644 --- a/make/build.properties +++ b/make/build.properties @@ -28,6 +28,6 @@ docs.dir=${project.dir}/docs samples.dir=${project.dir}/samples dist.dir=${project.dir}/dist junit.jar=${test.lib.dir}/junit-4.6.jar -release.version=1.3.11.3 +release.version=1.3.12-SNAPSHOT asm.version=5.2 maven.repo.local=../build/maven From 37a86a052c5f3d62f3d82cf0f5dd9485e9ef6c54 Mon Sep 17 00:00:00 2001 From: jbachorik Date: Mon, 17 Dec 2018 17:33:51 +0100 Subject: [PATCH 002/412] Bump version to 1.3.12-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e16086477..f89dd4b28 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ if (!currentJvm.toString().startsWith("1.7")) { } group 'com.sun.tools.btrace' -version = '1.3.11.3' +version = '1.3.12-SNAPSHOT' description = 'BTrace - a safe, dynamic tracing tool for the Java platform' sourceCompatibility = 7 From e12f1240b902d667d9d69ec93bade5e4fb898976 Mon Sep 17 00:00:00 2001 From: Feng Date: Tue, 18 Dec 2018 01:21:29 +0800 Subject: [PATCH 003/412] Fixes #307 - delay start agent scripts after class transformer installed (#373) --- .../classes/com/sun/btrace/agent/Main.java | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/share/classes/com/sun/btrace/agent/Main.java b/src/share/classes/com/sun/btrace/agent/Main.java index e40ad01dc..03c759a30 100644 --- a/src/share/classes/com/sun/btrace/agent/Main.java +++ b/src/share/classes/com/sun/btrace/agent/Main.java @@ -34,7 +34,8 @@ import java.lang.instrument.UnmodifiableClassException; import java.net.Socket; import java.net.ServerSocket; -import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; import java.util.Map; import java.util.StringTokenizer; import java.util.jar.JarFile; @@ -100,6 +101,8 @@ private static synchronized void main(final String args, final Instrumentation i Main.inst = inst; } + List scriptClients = new ArrayList<>(); + try { loadArgs(args); // set the debug level based on cmdline config @@ -109,7 +112,7 @@ private static synchronized void main(final String args, final Instrumentation i } parseArgs(); - int startedScripts = startScripts(); + int startedScripts = collectScriptClients(scriptClients); String tmp = argMap.get("noServer"); // noServer is defaulting to true if startup scripts are defined @@ -144,10 +147,25 @@ public void run() { } } finally { inst.addTransformer(transformer, true); + startClients(scriptClients); Main.debugPrint("Agent init took: " + (System.nanoTime() - ts) + "ns"); } } + private static void startClients(List scriptClients) { + for (Client client : scriptClients) { + try { + handleNewClient(client).get(); + } catch (ExecutionException e) { + if (isDebug()) { + debugPrint(e); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + private static boolean hasScripts() { return argMap.containsKey("script") || argMap.containsKey("scriptDir"); } @@ -223,7 +241,7 @@ private static void loadDefaultArguments(String config) { } } - private static int startScripts() { + private static int collectScriptClients(List scriptClients) { int scriptCount = 0; String p = argMap.get("stdout"); @@ -241,7 +259,7 @@ private static int startScripts() { debugPrint(((tokenizer.countTokens() == 1) ? "initial script is " : "initial scripts are ") + script); } while (tokenizer.hasMoreTokens()) { - if (loadBTraceScript(tokenizer.nextToken(), traceToStdOut)) { + if (loadBTraceScript(tokenizer.nextToken(), traceToStdOut, scriptClients)) { scriptCount++; } } @@ -255,7 +273,7 @@ private static int startScripts() { File[] files = dir.listFiles(); if (files != null) { for (File file : files) { - if (loadBTraceScript(file.getAbsolutePath(), traceToStdOut)) { + if (loadBTraceScript(file.getAbsolutePath(), traceToStdOut, scriptClients)) { scriptCount++; } } @@ -577,7 +595,7 @@ private static void appendToSysClassPath(Path libFolder) { } } - private static boolean loadBTraceScript(String filePath, boolean traceToStdOut) { + private static boolean loadBTraceScript(String filePath, boolean traceToStdOut, List scriptClients) { try { String scriptName = ""; String scriptParent = ""; @@ -614,19 +632,17 @@ private static boolean loadBTraceScript(String filePath, boolean traceToStdOut) ClientContext ctx = new ClientContext(inst, transformer, argMap, clientSettings); Client client = new FileClient(ctx, traceScript); if (client.isInitialized()) { - handleNewClient(client).get(); + scriptClients.add(client); return true; } } catch (NullPointerException e) { if (isDebug()) { debugPrint("script " + filePath + " does not exist!"); } - } catch (RuntimeException | IOException | ExecutionException re) { + } catch (RuntimeException | IOException re) { if (isDebug()) { debugPrint(re); } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); } return false; } From b1b1ef98ebc292d81fb47bf73b8198405f4a4df3 Mon Sep 17 00:00:00 2001 From: jbachorik Date: Mon, 8 Apr 2019 22:21:36 -0700 Subject: [PATCH 004/412] Remove pre-caching of all loaded classes Fixes #378 The pre-caching was done with the intent of re-using already loaded classes to be used in subtype checks but in retrospect it is obvious that the cost is much higher than if just the classes which needs to be checked in the class hierarchy are checked. --- src/share/classes/com/sun/btrace/agent/Client.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/share/classes/com/sun/btrace/agent/Client.java b/src/share/classes/com/sun/btrace/agent/Client.java index e91352bca..f0ca3370c 100644 --- a/src/share/classes/com/sun/btrace/agent/Client.java +++ b/src/share/classes/com/sun/btrace/agent/Client.java @@ -458,7 +458,6 @@ void retransformLoaded() throws UnmodifiableClassException { ClassCache cc = ClassCache.getInstance(); for (Class c : inst.getAllLoadedClasses()) { if (c != null) { - cc.get(c); if (inst.isModifiableClass(c) && isCandidate(c)) { debugPrint("candidate " + c + " added"); list.add(c); From ab115e7eebc75bd5c3c0fb76e3e9433c19e267dc Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Sun, 7 Jul 2019 13:04:42 +0200 Subject: [PATCH 005/412] Create BTraceTutorial.md --- docs/BTraceTutorial.md | 589 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 589 insertions(+) create mode 100644 docs/BTraceTutorial.md diff --git a/docs/BTraceTutorial.md b/docs/BTraceTutorial.md new file mode 100644 index 000000000..9669fbdb0 --- /dev/null +++ b/docs/BTraceTutorial.md @@ -0,0 +1,589 @@ +# BTrace Tutorial + +## 1. Hello World + +Accustoms the learner to 'btrace' command and the way it is used. +Demonstrates the BTrace ability to instrument a class. + +### Setup + +#### HelloWorld Class + +``` +package extra; + +abstract public class HelloWorld extends HelloWorldBase { + protected int field = 0; + + public static void main(String[] args) throws Exception { + System.out.println("ready when you are ..."); + System.in.read(); + + callA(); + } + + private static void callA() { + HelloWorld instance = new HelloWorldExt(); + long x = System.nanoTime(); + instance.callA("hello", 13); + System.out.println("dur = " + (System.nanoTime() - x)); + } + + private void callA(String a, int b) { + field++; + callB(callC(a, b)); + field--; + } + + private void callB(String s) { + field++; + System.out.println("You want " + s); + field--; + } + + abstract protected String callC(String a, int b); +} + +final class HelloWorldExt extends HelloWorld { + @Override + protected String callC(String a, int b) { + try { + field++; + String s = a + "-" + b; + for(int i=0;i<100;i++) { + s = callD(s); + } + return s; + } finally { + field--; + } + } +} + +abstract class HelloWorldBase { + final protected String callD(String s) { + return "# " + s; + } +} +``` + +### Steps + +1. Run the HelloWorld application +2. Get the HelloWorld application PID via `jps` command +3. Run `btrace ` +4. Proceed with the HelloWrold application +5. Watch messages being printed + +You will repeat these steps while gradually enhancing the used BTrace script + +### Lessons + +#### Lesson 1 - Launching BTrace + +##### Using `btrace` client to attach to a running JVM + +`btrace [opts] []` + +* **opts** BTrace specific options; use `btrace -h` to obtain the list of all supported options +* **pid** process id of the traced Java program +* **btrace-script** trace program. If it is a ".java", then it is compiled before submission. Or else, it is assumed to be pre-compiled [i.e., it has to be a .class] and submitted. +* **args** trace specific arguments + +Once you are attached to the target JVM you can press Ctrl-C in the terminal to show the BTrace console. From there you can either detach and exit or send an event (handled by the __@OnEvent__ annotated methods in the trace program). + +##### Starting a Java application with BTrace agent + +###### Directly + +`java -javaagent:btrace-agent.jar=[[,]*]? ` + +The agent takes a list of comma separated arguments. + +* **noServer** - don't start the socket server +* **bootClassPath** - boot classpath to be used +* **systemClassPath** - system classpath to be used +* **debug** - turns on verbose debug messages (true/false) +* **unsafe** - do not check for btrace restrictions violations (true/false) +* **dumpClasses** - dump the transformed bytecode to files (true/false) +* **dumpDir** - specifies the folder where the transformed classes will be dumped to +* **stdout** - redirect the btrace output to stdout instead of writing it to an arbitrary file (true/false) +* **probeDescPath** - the path to search for probe descriptor XMLs +* **startupRetransform** - enable retransform of all the loaded classes at attach (true/false) +* **scriptdir** - the path to a directory containing scripts to be run at the agent startup +* **scriptOutputFile** - the path to a file the btrace agent will store its output +* **script** - colon separated list of tracing scripts to be run at the agent startup + +The scripts to be run must have already been compiled to bytecode (a *.class* file) by __btracec__. + +###### Using `btracer' + +`btracer [opts] ` + +* **opts** BTrace specific options; use `btracer -h` to obtain the list of all supported options +* **pre-compiled-btrace.class** the trace script compiled to bytecode via __btracec__ +* **vm-args** the VM arguments; eg. `-cp app.jar Main.class` or `-jar app.jar` +* **application-args** the application specific arguments + +You can use __btracer__ to launch java application from jar (`btracer ... -jar app.jar `) or a main class (`btracer ... -cp
`) + +##### Compiling trace scripts + +This needs to be done in order to launch the Java application with BTrace agent. + +`btracec [-cp ] [-d ] ` + +* **classpath** is the classpath used for compiling BTrace program(s). Default is "." +* **directory** is the output directory where compiled .class files are stored. Default is ".". + +Rather than regular *javac* the BTrace compiler is used - causing the script to be validated at compile time and prevent reporting verify errors at runtime. + +#### Lesson 2 - Tracing methods + +This is the main purpose of BTrace - inject a custom code to custom locations to give the insights about the internal state and dynamics of the application. + +1. Getting just the information that any method is being executed +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="/.*/") + public static void onMethod() { + println("Hello from method"); + } +} +``` + +2. Get the method names +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld") + public static void onMethod(@ProbeMethodName String pmn) { + println("Hello from method " + pmn); + } +} +``` + +3. Intercept only a particular method +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="callA") + public static void onMethod(@ProbeMethodName String pmn) { + println("Hello from method " + pmn); + } +} +``` + +4. Intercept only a particular method with name matching the handler name +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="#") + public static void callA(@ProbeMethodName String pmn) { + println("Hello from method " + pmn); + } +} +``` + +5. Intercept methods with names matching certain patterns +__Note:__ you can use pattern matching for the class names, too + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="/call.*/") + public static void onMethod(@ProbeMethodName String pmn) { + println("Hello from method " + pmn); + } +} +``` + +6. Intercept methods with names matching certain patterns and inspect their parameters + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="/call.*/") + public static void onMethod(@ProbeMethodName String pmn, AnyType[] args) { + println("Hello from method " + pmn); + println("Received the following parameters:"); + printArray(args); + } +} +``` + +7. Intercept method with names matching certain patterns and discover their signatures +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="/call.*/") + public static void onMethod(@ProbeMethodName(fqn = true) String pmn) { + println("Hello from method " + pmn); + } +} +``` + +8. Intercept methods for all subclasses and implementations of a certain class/interface + +__Note:__ 'extra.HelloWorldBase.callD()' doesn't show up - it is defined in the superclass of 'extra.HelloWorld' and therefore not intercepted. + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="+extra.HelloWorld", method="/call.*/") + public static void onMethod(@ProbeMethodName(fqn = true) String pmn) { + println("Hello from method " + pmn); + } +} +``` + +9. Intercept method with a particular name and signature + capture the method arguments (you need to use the information learned in the previous step) + +__Note:__ The order of the un-annotated parameters must correspond to the order of the traced method parameters. Annotated parameters may be placed anywhere. + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorldExt", method="callC") + public static void onMethod(@ProbeMethodName String pmn, String param1, int param2) { + println("Hello from method " + pmn); + println("Arguments: param1 = " + str(param1) + ", param2 = " + str(param2)); + } +} +``` + +10. Intercpet method with a particular name and signature but don't capture the method arguments. Here you will need to decifer the VM method signature to get java like method signature. See the @OnMethod.type() javadoc for the java like signature format. + +Eg. having the VM method signature in form of (Ljava/lang/String;I)V will translate to "void (java.lang.String, int)" + +__Note:__ We are using overloaded method here and specifying the signature helps BTrace determine which method should be instrumented + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="callA", type="void (java.lang.String, int)") + public static void onMethod(@ProbeMethodName(fqn = true) String pmn) { + println("Hello from method " + pmn); + } +} +``` + +11. Intercept method with a particular name and capture its return value +`location=@Location(Kind.RETURN)` sets up the instrumentation to be inserted just before the method exits + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="callC", location=@Location(Kind.RETURN)) + public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @Return String ret) { + println("Hello from method " + pmn + "; returning " + ret); + } +} +``` + +12. Inspect the content of an instance variable in the method declaring class + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="/call.*/", location=@Location(Kind.RETURN)) + public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @Self Object thiz) { + println("Hello from method " + pmn); + println("field = " + str(getInt("field", thiz))); + } +} +``` + +Or retrieve the `java.lang.Field` instance first and perform a check before trying to retrieve the field value. + +``` +package helloworld; +import java.lang.Class; +import java.lang.reflect.Field; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="/call.*/", location=@Location(Kind.RETURN)) + public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @Self Object thiz) { + Class myClz = classOf(thiz); + Field fld = field(myClz, "field", false); + println("Hello from method " + pmn); + if (fld != null) { + println("field = " + str(getInt(fld, thiz))); + } + } +} +``` + +13. Get the method execution duration + +__Note:__ Need to use @Location(Kind.RETURN) to be able to capture the execution duration + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="/call.*/", location=@Location(Kind.RETURN)) + public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @Duration long dur) { + println("Hello from method " + pmn); + println("It took " + str(dur) + "ns to execute this method"); + } +} +``` + +14. Tracing methods invoked from inside a particular method + +__Note:__ 'class', 'method' etc. directly in the @OnMethod annotation will determine where we should look for the invocation of the methods defined by 'class', 'method' etc. parameters in the @Location annotation. +__Note:__ @ProbeMethodName and @ProbeClassName refer to the context method and class; @TargetMethodOrField refers to the traced method invocation +__Note:__ You can use the 'type' annotation parameter in @OnMethod annotation to restrict the context methods and in @Location to restrict the traced method invocations + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="callA", + location=@Location( + value = Kind.CALL, + clazz = "extra.HelloWorld", + method = "/call.*/", + where = Where.BEFORE) + ) + public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @TargetMethodOrField(fqn = true) String tpmn) { + println("Hello from method " + pmn); + println("Going to invoke method " + tpmn); + } +} +``` + +15. Measuring the duration of methods invoked from inside a particular method + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="callA", + location=@Location( + value = Kind.CALL, + clazz = "extra.HelloWorld", + method = "/call.*/", + where = Where.AFTER) + ) + public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @TargetMethodOrField(fqn = true) String tpmn, @Duration long dur) { + println("Hello from method " + pmn); + println("Executing " + tpmn + " took " + dur + "ns"); + } +} +``` + +16. Tracing methods invoked from inside a particular method and capturing their parameters + +__Note:__ The captured parameters pertain to the invoked method rather than the context method +__Note:__ The @Self annotated parameter captures the context instance and @TargetInstance annotated parameter captures the instance the method is invoked on + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnMethod(clazz="extra.HelloWorld", method="callA", + location=@Location( + value = Kind.CALL, + clazz = "extra.HelloWorld", + method = "/call.*/", + where = Where.BEFORE) + ) + public static void onMethod(@ProbeMethodName(fqn = true) String pmn, @TargetMethodOrField(fqn = true) String tpmn, + @Self Object thiz, @TargetInstance Object tgt, String a, int b) { + println("Hello from method " + pmn); + println("Going to invoke method " + tpmn); + println("context = " + str(classOf(thiz)) + ", target = " + str(classOf(tgt))); + println("a = " + a + ", b = " + str(b)); + } +} +``` + +#### Lesson 3 - Global callbacks + +Global callbacks are not directly related to the tracing code injection but they allow us to observe the global state and act correspondingly. + +#### __@OnExit__ + +Called when the traced application is about to exit. Allows to capture the exit code. + +__Note:__ The signature of the handler method __MUST__ be 'void (int)' + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnExit + public static void onexit(int code) { + println("Application exitting with " + code); + } +} +``` + +#### __@OnError__ + +Called whenever an exception is thrown from anywhere in the BTrace handlers. + +__Note:__ The signature of the handler method __MUST__ be 'void (java.lang.Throwable)' + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnError + public static void onerror(Throwable t) { + println("Encountered internal error " + str(t)); + } +} +``` + +#### __@OnTimer__ + +Allows to register a handler to be invoked periodically at defined intervals. + +__Note:__ The annotation parameter takes the interval value in milliseconds +__Note:__ The signature of the handler method __MUST__ be 'void ()' + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnTimer(1000) + public static void ontimer() { + println("tick ..."); + } +} +``` + +#### __@OnEvent__ + +Used to raise events from external clients (eg. the command line client). The annotation takes a String parameter which is the event name. When not provided the event is considered to be 'unnamed'. + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnEvent + public static void unnamed() { + println("Received unnamed event"); + } +} +``` +or + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + @OnEvent("myEvent") + public static void myevent() { + println("Received my event"); + } +} +``` + +#### Lesson 4 - Sampling + +Tracing many methods being executed frequently can bring a significant overhead to the traced application. And often we are not really interested in the high detail data - an aggregated view would do just fine. + +Therefore it is possible to employ statistical sampling to reduce the amount of collected data and related overhead while still providing relevant information about the application behaviour. + +The sampling implementation in BTrace guarantees that at least one invocation of a traced method will be recorded, no matter what the sampling settings are. + +1. Intercept only each 10th invocation on average + +__Note:__ Even though the 'callD' method is executed 100 times we will get only ~10 hits - as dictated by the 'mean' parameter. + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + private static int cntr = 1; + @Sampled(kind = Sampled.Sampler.Const, mean = 10) + @OnMethod(clazz="/extra\\.HelloWorld.*/", method="callD") + public static void onMethod(@ProbeMethodName(fqn = true) String pmn) { + println("Hello from method " + pmn + " : " + (cntr++)); + } +} +``` + +2. Let the sampler mean parameter be adjusted dynamically by keeping to the overhead target + +__Note:__ In this case the 'mean' parameter actually specify the lowest number of nanoseconds the average interval between interception should be. +__Note:__ Because the adaptive sampling needs to collect timestamps in order to maintain the overhead target the lowest value for the 'mean' parameter is 180 (cca. 60ns for gettint start/stop timestamp pair multiplied by the safety margin of 3) +__Note:__ The 'callD' method is very short and the number of iteration is rather limited - we will most probably get only one hit here + +``` +package helloworld; +import ...; + +@BTrace +public class HelloWorldTrace { + private static int cntr = 1; + @Sampled(kind = Sampled.Sampler.Adaptive, mean = 50) + @OnMethod(clazz="/extra\\.HelloWorld.*/", method="callD") + public static void onMethod(@ProbeMethodName(fqn = true) String pmn) { + println("Hello from method " + pmn + " : " + (cntr++)); + } +} +``` From 17c8613d6fca030d32bdb61ca104da71ffb8f90a Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Sun, 7 Jul 2019 13:06:33 +0200 Subject: [PATCH 006/412] Update BTraceTutorial.md --- docs/BTraceTutorial.md | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/BTraceTutorial.md b/docs/BTraceTutorial.md index 9669fbdb0..21d3d68ba 100644 --- a/docs/BTraceTutorial.md +++ b/docs/BTraceTutorial.md @@ -9,7 +9,7 @@ Demonstrates the BTrace ability to instrument a class. #### HelloWorld Class -``` +``` java package extra; abstract public class HelloWorld extends HelloWorldBase { @@ -143,7 +143,7 @@ Rather than regular *javac* the BTrace compiler is used - causing the script to This is the main purpose of BTrace - inject a custom code to custom locations to give the insights about the internal state and dynamics of the application. 1. Getting just the information that any method is being executed -``` +``` java package helloworld; import ...; @@ -157,7 +157,7 @@ public class HelloWorldTrace { ``` 2. Get the method names -``` +``` java package helloworld; import ...; @@ -171,7 +171,7 @@ public class HelloWorldTrace { ``` 3. Intercept only a particular method -``` +``` java package helloworld; import ...; @@ -185,7 +185,7 @@ public class HelloWorldTrace { ``` 4. Intercept only a particular method with name matching the handler name -``` +``` java package helloworld; import ...; @@ -201,7 +201,7 @@ public class HelloWorldTrace { 5. Intercept methods with names matching certain patterns __Note:__ you can use pattern matching for the class names, too -``` +``` java package helloworld; import ...; @@ -216,7 +216,7 @@ public class HelloWorldTrace { 6. Intercept methods with names matching certain patterns and inspect their parameters -``` +``` java package helloworld; import ...; @@ -232,7 +232,7 @@ public class HelloWorldTrace { ``` 7. Intercept method with names matching certain patterns and discover their signatures -``` +``` java package helloworld; import ...; @@ -249,7 +249,7 @@ public class HelloWorldTrace { __Note:__ 'extra.HelloWorldBase.callD()' doesn't show up - it is defined in the superclass of 'extra.HelloWorld' and therefore not intercepted. -``` +``` java package helloworld; import ...; @@ -266,7 +266,7 @@ public class HelloWorldTrace { __Note:__ The order of the un-annotated parameters must correspond to the order of the traced method parameters. Annotated parameters may be placed anywhere. -``` +``` java package helloworld; import ...; @@ -286,7 +286,7 @@ Eg. having the VM method signature in form of (Ljava/lang/String;I)V will transl __Note:__ We are using overloaded method here and specifying the signature helps BTrace determine which method should be instrumented -``` +``` java package helloworld; import ...; @@ -302,7 +302,7 @@ public class HelloWorldTrace { 11. Intercept method with a particular name and capture its return value `location=@Location(Kind.RETURN)` sets up the instrumentation to be inserted just before the method exits -``` +``` java package helloworld; import ...; @@ -317,7 +317,7 @@ public class HelloWorldTrace { 12. Inspect the content of an instance variable in the method declaring class -``` +``` java package helloworld; import ...; @@ -333,7 +333,7 @@ public class HelloWorldTrace { Or retrieve the `java.lang.Field` instance first and perform a check before trying to retrieve the field value. -``` +``` java package helloworld; import java.lang.Class; import java.lang.reflect.Field; @@ -357,7 +357,7 @@ public class HelloWorldTrace { __Note:__ Need to use @Location(Kind.RETURN) to be able to capture the execution duration -``` +``` java package helloworld; import ...; @@ -377,7 +377,7 @@ __Note:__ 'class', 'method' etc. directly in the @OnMethod annotation will deter __Note:__ @ProbeMethodName and @ProbeClassName refer to the context method and class; @TargetMethodOrField refers to the traced method invocation __Note:__ You can use the 'type' annotation parameter in @OnMethod annotation to restrict the context methods and in @Location to restrict the traced method invocations -``` +``` java package helloworld; import ...; @@ -399,7 +399,7 @@ public class HelloWorldTrace { 15. Measuring the duration of methods invoked from inside a particular method -``` +``` java package helloworld; import ...; @@ -424,7 +424,7 @@ public class HelloWorldTrace { __Note:__ The captured parameters pertain to the invoked method rather than the context method __Note:__ The @Self annotated parameter captures the context instance and @TargetInstance annotated parameter captures the instance the method is invoked on -``` +``` java package helloworld; import ...; @@ -457,7 +457,7 @@ Called when the traced application is about to exit. Allows to capture the exit __Note:__ The signature of the handler method __MUST__ be 'void (int)' -``` +``` java package helloworld; import ...; @@ -476,7 +476,7 @@ Called whenever an exception is thrown from anywhere in the BTrace handlers. __Note:__ The signature of the handler method __MUST__ be 'void (java.lang.Throwable)' -``` +``` java package helloworld; import ...; @@ -496,7 +496,7 @@ Allows to register a handler to be invoked periodically at defined intervals. __Note:__ The annotation parameter takes the interval value in milliseconds __Note:__ The signature of the handler method __MUST__ be 'void ()' -``` +``` java package helloworld; import ...; @@ -513,7 +513,7 @@ public class HelloWorldTrace { Used to raise events from external clients (eg. the command line client). The annotation takes a String parameter which is the event name. When not provided the event is considered to be 'unnamed'. -``` +``` java package helloworld; import ...; @@ -527,7 +527,7 @@ public class HelloWorldTrace { ``` or -``` +``` java package helloworld; import ...; @@ -552,7 +552,7 @@ The sampling implementation in BTrace guarantees that at least one invocation of __Note:__ Even though the 'callD' method is executed 100 times we will get only ~10 hits - as dictated by the 'mean' parameter. -``` +``` java package helloworld; import ...; @@ -573,7 +573,7 @@ __Note:__ In this case the 'mean' parameter actually specify the lowest number o __Note:__ Because the adaptive sampling needs to collect timestamps in order to maintain the overhead target the lowest value for the 'mean' parameter is 180 (cca. 60ns for gettint start/stop timestamp pair multiplied by the safety margin of 3) __Note:__ The 'callD' method is very short and the number of iteration is rather limited - we will most probably get only one hit here -``` +``` java package helloworld; import ...; From 7d984fc0e6a7166fb57ffa3e316fc4f7f77fff96 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Sun, 7 Jul 2019 13:07:18 +0200 Subject: [PATCH 007/412] Update BTraceTutorial.md --- docs/BTraceTutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/BTraceTutorial.md b/docs/BTraceTutorial.md index 21d3d68ba..cfd26ea1e 100644 --- a/docs/BTraceTutorial.md +++ b/docs/BTraceTutorial.md @@ -104,7 +104,7 @@ The agent takes a list of comma separated arguments. * **bootClassPath** - boot classpath to be used * **systemClassPath** - system classpath to be used * **debug** - turns on verbose debug messages (true/false) -* **unsafe** - do not check for btrace restrictions violations (true/false) +* **trusted** - do not check for btrace restrictions violations (true/false) * **dumpClasses** - dump the transformed bytecode to files (true/false) * **dumpDir** - specifies the folder where the transformed classes will be dumped to * **stdout** - redirect the btrace output to stdout instead of writing it to an arbitrary file (true/false) From 5d4e688eebf63b59fe7ef7c8b11ae23cbae65fc4 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Sun, 7 Jul 2019 13:08:56 +0200 Subject: [PATCH 008/412] Update BTraceTutorial.md --- docs/BTraceTutorial.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/BTraceTutorial.md b/docs/BTraceTutorial.md index cfd26ea1e..7f352d6e2 100644 --- a/docs/BTraceTutorial.md +++ b/docs/BTraceTutorial.md @@ -374,7 +374,9 @@ public class HelloWorldTrace { 14. Tracing methods invoked from inside a particular method __Note:__ 'class', 'method' etc. directly in the @OnMethod annotation will determine where we should look for the invocation of the methods defined by 'class', 'method' etc. parameters in the @Location annotation. + __Note:__ @ProbeMethodName and @ProbeClassName refer to the context method and class; @TargetMethodOrField refers to the traced method invocation + __Note:__ You can use the 'type' annotation parameter in @OnMethod annotation to restrict the context methods and in @Location to restrict the traced method invocations ``` java @@ -422,6 +424,7 @@ public class HelloWorldTrace { 16. Tracing methods invoked from inside a particular method and capturing their parameters __Note:__ The captured parameters pertain to the invoked method rather than the context method + __Note:__ The @Self annotated parameter captures the context instance and @TargetInstance annotated parameter captures the instance the method is invoked on ``` java @@ -494,6 +497,7 @@ public class HelloWorldTrace { Allows to register a handler to be invoked periodically at defined intervals. __Note:__ The annotation parameter takes the interval value in milliseconds + __Note:__ The signature of the handler method __MUST__ be 'void ()' ``` java @@ -569,8 +573,10 @@ public class HelloWorldTrace { 2. Let the sampler mean parameter be adjusted dynamically by keeping to the overhead target -__Note:__ In this case the 'mean' parameter actually specify the lowest number of nanoseconds the average interval between interception should be. -__Note:__ Because the adaptive sampling needs to collect timestamps in order to maintain the overhead target the lowest value for the 'mean' parameter is 180 (cca. 60ns for gettint start/stop timestamp pair multiplied by the safety margin of 3) +__Note:__ In this case the 'mean' parameter actually specify the lowest number of nanoseconds the average interval between interception should be + +__Note:__ Because the adaptive sampling needs to collect timestamps in order to maintain the overhead target the lowest value for the 'mean' parameter is 180 (cca. 60ns for getting start/stop timestamp pair multiplied by the safety margin of 3) + __Note:__ The 'callD' method is very short and the number of iteration is rather limited - we will most probably get only one hit here ``` java From 55ec059290acdffe4fcf4409915b58d0d468f5f2 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Fri, 25 Oct 2019 18:07:41 +0200 Subject: [PATCH 009/412] Update gradle.yml --- .github/workflows/gradle.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/gradle.yml diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 000000000..0e1231212 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,17 @@ +name: Java CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Build with Gradle + run: ./gradlew build From 12518d1efebee0222233207a77c944bb9af18494 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Wed, 6 Nov 2019 18:29:26 +0100 Subject: [PATCH 010/412] Update .travis.yml Fix TravisCI builds --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 7f1ae101b..c50c1ba6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ env: - secure: EIQ8VWbg8LRnX7n6PIP9HjXLg4nIKOsJk0xnMunbMZ475Z+pTd73awLu6VCbjO5DVAd9R7W36snIlGVv92j3dai6e0jOO+WtSTQ7gd1cEq+4swEXg7Qvc1oyqsXVL+FoO+j1InZxxUx93ObLRGvFZiUeBhnPNdqsM794EkUScN4= - secure: HLMEzx4NuU+oXU5yGViN8pAfFvhVeib5zvfH21nVbOC1Rg57HUKQTRCg5S/acr5C8At4BfHORt7p3MHztGB/GXylzm1kFRnKliJ50S9BkEW+/852f2gbGmnIEe7aMz4nFOheRpLgk7zcZrbYbztoRAFL+HREBiEaAZu8bti4gpU= sudo: false +dist: trusty cache: directories: - "$HOME/.gradle" From 3c1a9382fe813727f8aa2f3d5f00be416cd03bf3 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Wed, 6 Nov 2019 18:29:51 +0100 Subject: [PATCH 011/412] Update .travis.yml Fix TravisCI build --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 7f1ae101b..c50c1ba6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ env: - secure: EIQ8VWbg8LRnX7n6PIP9HjXLg4nIKOsJk0xnMunbMZ475Z+pTd73awLu6VCbjO5DVAd9R7W36snIlGVv92j3dai6e0jOO+WtSTQ7gd1cEq+4swEXg7Qvc1oyqsXVL+FoO+j1InZxxUx93ObLRGvFZiUeBhnPNdqsM794EkUScN4= - secure: HLMEzx4NuU+oXU5yGViN8pAfFvhVeib5zvfH21nVbOC1Rg57HUKQTRCg5S/acr5C8At4BfHORt7p3MHztGB/GXylzm1kFRnKliJ50S9BkEW+/852f2gbGmnIEe7aMz4nFOheRpLgk7zcZrbYbztoRAFL+HREBiEaAZu8bti4gpU= sudo: false +dist: trusty cache: directories: - "$HOME/.gradle" From a4195dbe0427ad16202d9d09d450280423baf08d Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Wed, 6 Nov 2019 18:30:31 +0100 Subject: [PATCH 012/412] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e266c203c..166071d35 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A safe, dynamic tracing tool for the Java platform ## Version -1.3.11.2 ([Release Page](https://github.com/btraceio/btrace/releases/latest)) +1.3.11.3 ([Release Page](https://github.com/btraceio/btrace/releases/latest)) _! NOTE: For the latest develop changes head to ['develop' branch](https://github.com/btraceio/btrace/tree/develop)_ From 0cc7edb880815422939d896411333d0ecadf4575 Mon Sep 17 00:00:00 2001 From: Zizon Qiu Date: Fri, 8 Nov 2019 02:34:39 +0800 Subject: [PATCH 013/412] fix class verify failure due to mismatch locals, of multi try-catch (#397) --- .../runtime/InstrumentingMethodVisitor.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/share/classes/com/sun/btrace/runtime/InstrumentingMethodVisitor.java b/src/share/classes/com/sun/btrace/runtime/InstrumentingMethodVisitor.java index a2a22ea41..1f48b889e 100644 --- a/src/share/classes/com/sun/btrace/runtime/InstrumentingMethodVisitor.java +++ b/src/share/classes/com/sun/btrace/runtime/InstrumentingMethodVisitor.java @@ -348,7 +348,7 @@ private static final class SavedState { private final LocalVarTypes localTypes = new LocalVarTypes(); private final Set frameOffsets = new HashSet<>(); private final Map jumpTargetStates = new HashMap<>(); - private final Map tryCatchHandlerMap = new HashMap<>(); + private final Map> tryCatchHandlerMap = new HashMap<>(); private int argsSize = 0; private int localsTailPtr = 0; @@ -1205,10 +1205,12 @@ public void visitLabel(Label label) { newLocals.clear(); newLocals.addAll(ss.newLocals); } - Label handler = tryCatchHandlerMap.get(label); - if (handler != null) { - if (!jumpTargetStates.containsKey(handler)) { - jumpTargetStates.put(handler, new SavedState(variableMapper, localTypes, stack, newLocals, SavedState.EXCEPTION)); + Set