aoqi@0: aoqi@0: aoqi@0: aoqi@0: JavaScript interface to Hotspot Serviceability Agent aoqi@0: aoqi@0: aoqi@0: aoqi@0:

JavaScript interface to Hotspot Serviceability Agent

aoqi@0: aoqi@0:

aoqi@0: Serviceability Agent (SA) provides Java API and tools to diagnose HotSpot Virtual Machine and aoqi@0: Java apps running on it. SA is a snapshot debugger -- can be used to observe state of a frozen java process or java core dump. aoqi@0:

aoqi@0: aoqi@0:

Existing SA APIs

aoqi@0:

aoqi@0: There are two application programmer interfaces (APIs) for SA: aoqi@0:

aoqi@0:
1. Private java API aoqi@0:
aoqi@0:
aoqi@0: This tries to mimic hotspot VM's internal C++ classes and methods. Because VM data structures aoqi@0: are a moving target, this API can never be 'stable'! Besides, to use SA's private API knowledge of aoqi@0: HotSpot code base is essential. aoqi@0:
aoqi@0:
2. SA-JDI -- Java Debugger Interface read-only subset API aoqi@0:
aoqi@0:
aoqi@0: This is read-only subset of JDI (Java Debugger Interface) aoqi@0: This is a standardized interface to get java level state of a java process or java core dump. While this aoqi@0: interface is useful, this misses parts of java level state from target process or core such as aoqi@0: aoqi@0:
aoqi@0:
aoqi@0:

aoqi@0: aoqi@0:

SA Scripting interface

aoqi@0: aoqi@0:

aoqi@0: Traditionally, platform debuggers such as dbx, gdb and Solaris mdb (Module Debugger), provide a scripting aoqi@0: language interface. Scripting language interface provides easy-to-use, dynamically typed aoqi@0: interface to access data structures from debuggee. dbx and mdb even allow user to write aoqi@0: C/C++ modules to extend the scripting language commands. aoqi@0:

aoqi@0: aoqi@0:

aoqi@0: SA provides SOQL - Simple Object Query Language -- a SQL-like query language to access aoqi@0: Java heap as an object database. SA's main GUI (HSDB) also exposes scripting interface of underlying debugger such as dbx, windbg. aoqi@0: But to use this interface, user has to learn scripting interface of multiple debugger back-ends such as dbx, windbg. aoqi@0: And these scripting interfaces are 'raw' in the sense that no java state is exposed -- only C/C++ state of VM is exposed. aoqi@0: Higher level SA services are not available through scripting interface. aoqi@0:

aoqi@0: aoqi@0:

aoqi@0: jsdb -- JavaScript Debugger attempts to provide JavaScript interface to SA. aoqi@0: jsdb provides aoqi@0: aoqi@0:

aoqi@0:

aoqi@0: aoqi@0:

High level interface (Java State)

aoqi@0: aoqi@0: jsdb is a command line JavaScript shell based on aoqi@0: Mozilla's Rhino JavaScript Engine. aoqi@0: This command line utility attaches to Java process or core file or remote debug server and waits for user input. aoqi@0: This shell supports the following global functions and objects in addition to the standard JavaScript functions and aoqi@0: objects: aoqi@0: aoqi@0:

jdsb globals

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
Function/VariableDescription
aoqi@0: address(jobject) aoqi@0: aoqi@0: function that returns the address of the Java object as a string aoqi@0:
aoqi@0: classof(jobject) aoqi@0: aoqi@0: function that returns the JavaScript object that represents class object of the Java object aoqi@0:
aoqi@0: dumpClass(jclass,[dir]) aoqi@0: aoqi@0: function that writes .class for the given Java Class. Optionally (second arg) accepts the directory where the aoqi@0: .class has to be written. aoqi@0:
aoqi@0: help() aoqi@0: aoqi@0: function that prints help message for global functions and objects aoqi@0:
aoqi@0: identityHash(jobject) aoqi@0: aoqi@0: function that returns the identity hashCode of the Java object aoqi@0:
aoqi@0: mirror(jobject) aoqi@0: aoqi@0: function that returns a local mirror of the Java object. aoqi@0:
aoqi@0: load([file1, file2,...]) aoqi@0: aoqi@0: function that loads zero or more JavaScript file(s). With no arguments, reads for aoqi@0: JavaScript code. aoqi@0:
aoqi@0: object(string) aoqi@0: aoqi@0: function that converts a string address into Java object aoqi@0:
aoqi@0: owner(jobject) aoqi@0: aoqi@0: function that returns the owner thread of this monitor or null aoqi@0:
aoqi@0: sizeof(jobject) aoqi@0: aoqi@0: function that returns the size of Java object in bytes aoqi@0:
aoqi@0: staticof(jclass, field) aoqi@0: aoqi@0: function that returns the value of given field of the given Java class aoqi@0:
aoqi@0: print(expr1, expr2,...) aoqi@0: aoqi@0: function that prints zero or more JavaScript expressions after converting those as strings aoqi@0:
aoqi@0: println(expr1, expr2..) aoqi@0: aoqi@0: function that same as print, but prints a newline at the end aoqi@0:
aoqi@0: read([prompt]) aoqi@0: aoqi@0: function that reads a single line from standard input aoqi@0:
aoqi@0: quit() aoqi@0: aoqi@0: function that quits the interactive load call as well as the shell aoqi@0:
aoqi@0: jvm aoqi@0: aoqi@0: variable -- a JavaScript object that represents the target jvm that is being debugged aoqi@0:
aoqi@0: aoqi@0:

jvm object

aoqi@0: aoqi@0:

aoqi@0: jvm object supports the following read-only properties. aoqi@0:

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
aoqi@0: Property name aoqi@0: aoqi@0: Description aoqi@0:
aoqi@0: threads aoqi@0: aoqi@0: array of Java threads from the debuggee aoqi@0:
aoqi@0: heap aoqi@0: aoqi@0: object representing the heap of the debuggee aoqi@0:
aoqi@0: type aoqi@0: aoqi@0: string value that is either "Server" or "Client" or "Core" -- the flavour of debuggee VM aoqi@0:
aoqi@0: bootClassPath aoqi@0: aoqi@0: string value of bootclasspath of the debuggee aoqi@0:
aoqi@0: cpu aoqi@0: aoqi@0: string value of cpu on which the debuggee runs/ran aoqi@0:
aoqi@0: sysProps aoqi@0: aoqi@0: name-value pairs (JavaScript associative array) of Java System properties of the debuggee aoqi@0:
aoqi@0: addressSize aoqi@0: aoqi@0: int value -- 32 for 32 bit debuggee, 64 for 64 bit debuggee aoqi@0:
aoqi@0: os aoqi@0: aoqi@0: string value of OS on which the debuggee runs/ran aoqi@0:
aoqi@0: buildInfo aoqi@0: aoqi@0: internal build info string from debuggee aoqi@0:
aoqi@0: flags aoqi@0: aoqi@0: name-value pairs (JavaScript associative array) of JVM command line flags of the debuggee aoqi@0:
aoqi@0: classPath aoqi@0: aoqi@0: string value of classpath of the debuggee aoqi@0:
aoqi@0: userDir aoqi@0: aoqi@0: string value of user.dir System property of the debuggee aoqi@0:
aoqi@0: aoqi@0:

heap object

aoqi@0: aoqi@0:

aoqi@0: heap object represents Java heap of the debuggee VM aoqi@0:

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
aoqi@0: Function or property name aoqi@0: aoqi@0: Description aoqi@0:
aoqi@0: capacity aoqi@0: aoqi@0: byte size of capacity of the heap aoqi@0:
aoqi@0: used aoqi@0: aoqi@0: byte size of used portion (of live objects) of the heap aoqi@0:
aoqi@0: forEachObject(func, [class], [include subtypes -- true|false]) aoqi@0: aoqi@0: This function accepts a callback function 'func' and optionally class name and boolean arguments. aoqi@0: This function calls the callback for each Java object in the debuggee's heap. The optional class aoqi@0: argument may be used to receive objects of given class only. The third arguments specifies whether aoqi@0: to include objects of subtype of given class [or interface] or not. The default value of class is "java.lang.Object" aoqi@0: and and that of the third argument is true. i.e., by default all objects are included. aoqi@0:
aoqi@0: forEachClass(func, [initiating loader -- true|false]) aoqi@0: aoqi@0: This function accepts a callback function 'func'. This function iterates through the classes of the debuggee and calls the aoqi@0: callback for each class. The second parameter tells whether to pass initiating loader to the iterator callback or not. aoqi@0:
aoqi@0: aoqi@0:

Accessing Java objects and arrays in script

aoqi@0: aoqi@0:

aoqi@0: From a given Java object, we can access all fields of the Java object by usual '.' operator. i.e., if you got a Java object aoqi@0: called 'o' of type java.lang.Thread from debuggee, you can access 'stackSize' field by o.stackSize syntax. Similarly, length of Java array aoqi@0: objects can be accessed by length property. And array indexing follows usual syntax. i.e., n'th element of array 'a' is aoqi@0: accessed by a[n]. aoqi@0:

aoqi@0: aoqi@0:

jvm.threads array

aoqi@0: aoqi@0:

aoqi@0: This is a JavaScript array of Java threads of the debuggee. As usual, 'length' property tells the number of threads and individual aoqi@0: threads may be accessed by index operator -- i.e, jvm.threads[0] returns the first thread. aoqi@0:

aoqi@0: aoqi@0:

thread object

aoqi@0: aoqi@0: aoqi@0:

aoqi@0: In addition to the fields of java.lang.Thread (or subclass) fields, thread objects have two additional properties. aoqi@0: aoqi@0:

aoqi@0: aoqi@0:

aoqi@0: aoqi@0:

stack frame object

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
aoqi@0: Property name aoqi@0: aoqi@0: Description aoqi@0:
aoqi@0: thisObject aoqi@0: aoqi@0: Object representing 'this' of the current frame [will be null for static methods] aoqi@0:
aoqi@0: locals aoqi@0: aoqi@0: name-value pairs of local variables [JavaScript associative array] aoqi@0:
aoqi@0: line aoqi@0: aoqi@0: Java source line number at which the frame is executing aoqi@0:
aoqi@0: bci aoqi@0: aoqi@0: byte code index of the bytecode that the frame is executing aoqi@0:
aoqi@0: thread aoqi@0: aoqi@0: thread to which this frame belongs aoqi@0:
aoqi@0: method aoqi@0: aoqi@0: Java method that the frame is executing aoqi@0:
aoqi@0: aoqi@0:

method object

aoqi@0: aoqi@0:

aoqi@0: method object represents a Java method of debuggee aoqi@0:

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
aoqi@0: Property name aoqi@0: aoqi@0: Description aoqi@0:
aoqi@0: isStatic aoqi@0: aoqi@0: boolean - true for static methods and false for non-static methods aoqi@0:
aoqi@0: isSynchronized aoqi@0: aoqi@0: boolean - true for synchronized methods and false for non-synchronized methods aoqi@0:
aoqi@0: isNative aoqi@0: aoqi@0: boolean - true for native methods and false for non-native methods aoqi@0:
aoqi@0: isProtected aoqi@0: aoqi@0: boolean - true for protected methods and false for non-protected methods aoqi@0:
aoqi@0: isPrivate aoqi@0: aoqi@0: boolean - true for private methods and false for non-private methods aoqi@0:
aoqi@0: isSynthetic aoqi@0: aoqi@0: boolean - true for Javac generated synthetic methods and false for non-synthetic methods aoqi@0:
aoqi@0: isPackagePrivate aoqi@0: aoqi@0: boolean - true for package-private methods and false for non-package-private methods aoqi@0:
aoqi@0: isPublic aoqi@0: aoqi@0: boolean - true for public methods and false for non-public methods aoqi@0:
aoqi@0: holder aoqi@0: aoqi@0: an object that represents Class that contains this method aoqi@0:
aoqi@0: signature aoqi@0: aoqi@0: string -- signature of this method aoqi@0:
aoqi@0: isObsolete aoqi@0: aoqi@0: boolean - true for obsolete (hotswapped) methods and false for non-obsolete methods aoqi@0:
aoqi@0: isStrict aoqi@0: aoqi@0: boolean - true for strictfp methods and false for non-strictfp methods aoqi@0:
aoqi@0: isFinal aoqi@0: aoqi@0: boolean - true for final methods and false for non-final methods aoqi@0:
aoqi@0: name aoqi@0: aoqi@0: string - name of this method aoqi@0:
aoqi@0: aoqi@0:

class object

aoqi@0: aoqi@0:

aoqi@0: A class object represents loaded Java class in debuggee VM. This represents java.lang.Class instance in the debuggee. aoqi@0: This is type of return value of classof global function. Also, method.holder property and field.holder are aoqi@0: of this type. aoqi@0:

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
aoqi@0: Property name aoqi@0: aoqi@0: Description aoqi@0:
aoqi@0: name aoqi@0: aoqi@0: name of this class aoqi@0:
aoqi@0: superClass aoqi@0: aoqi@0: class object representing super class of this class aoqi@0:
aoqi@0: isArrayClass aoqi@0: aoqi@0: boolean -- is the current class an array class? aoqi@0:
aoqi@0: isStatic aoqi@0: aoqi@0: boolean -- is the current class static or not aoqi@0:
aoqi@0: isInterface aoqi@0: aoqi@0: boolean -- is the current class an interface aoqi@0:
aoqi@0: isAbstract aoqi@0: aoqi@0: boolean -- is the current class abstract or not aoqi@0:
aoqi@0: isProtected aoqi@0: aoqi@0: boolean -- is the current class protected or not aoqi@0:
aoqi@0: isPrivate aoqi@0: aoqi@0: boolean -- is the current class private or not aoqi@0:
aoqi@0: isPackagePrivate aoqi@0: aoqi@0: boolean -- is the current class package private or not aoqi@0:
aoqi@0: isSynthetic aoqi@0: aoqi@0: boolean -- is the current class synthetic or not aoqi@0:
aoqi@0: classLoader aoqi@0: aoqi@0: object that represents ClassLoader object that loaded the current class aoqi@0:
aoqi@0: fields aoqi@0: aoqi@0: array of static and instance fields of the current class aoqi@0:
aoqi@0: protectionDomain aoqi@0: aoqi@0: protection domain to which current class belongs aoqi@0:
aoqi@0: isPublic aoqi@0: aoqi@0: boolean -- is the current class public or not aoqi@0:
aoqi@0: signers aoqi@0: aoqi@0: array of signers for current class aoqi@0:
aoqi@0: sourceFile aoqi@0: aoqi@0: string -- name of the source file for current class aoqi@0:
aoqi@0: interfaces aoqi@0: aoqi@0: array -- interfaces implemented by current class aoqi@0:
aoqi@0: isStrict aoqi@0: aoqi@0: boolean -- is the current class strictfp or not aoqi@0:
aoqi@0: methods aoqi@0: aoqi@0: array of methods (static and instance) of the current class aoqi@0:
aoqi@0: isFinal aoqi@0: aoqi@0: boolean -- is the current class final or not aoqi@0:
aoqi@0: statics aoqi@0: aoqi@0: name-value pairs (JavaScript associate array) of static fields of the current class aoqi@0:
aoqi@0: aoqi@0:

field object

aoqi@0:

aoqi@0: field represents a static or instance field of some class in debuggee aoqi@0:

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
aoqi@0: Property name aoqi@0: aoqi@0: Description aoqi@0:
aoqi@0: isStatic aoqi@0: aoqi@0: boolean -- is this field a static field? aoqi@0:
aoqi@0: holder aoqi@0: aoqi@0: class that owns this field aoqi@0:
aoqi@0: signature aoqi@0: aoqi@0: string signature of this field aoqi@0:
aoqi@0: isProtected aoqi@0: aoqi@0: boolean - is this field a protected field or not? aoqi@0:
aoqi@0: isPrivate aoqi@0: aoqi@0: boolean - is this field a private field or not? aoqi@0:
aoqi@0: isSynthetic aoqi@0: aoqi@0: boolean - is this javac generated synthetic field or not? aoqi@0:
aoqi@0: isPackagePrivate aoqi@0: aoqi@0: boolean - is this field a package private field or not? aoqi@0:
aoqi@0: isTransient aoqi@0: aoqi@0: boolean - is this field a transient field or not? aoqi@0:
aoqi@0: isFinal aoqi@0: aoqi@0: boolean - is this field final or not? aoqi@0:
aoqi@0: name aoqi@0: aoqi@0: string - name of this field aoqi@0:
aoqi@0: isPublic aoqi@0: aoqi@0: boolean - is this field public or not? aoqi@0:
aoqi@0: aoqi@0:

Initialization Script

aoqi@0:

aoqi@0: jsdb engine looks for initialization script file named jsdb.js in user's home directory. If found, it loads just after attaching to debuggee but before printing prompt for user's input. User can assume that s/he can access debuggee VM aoqi@0: state during initialization script. aoqi@0:

aoqi@0: aoqi@0:

Sample scripts

aoqi@0: aoqi@0: Semantics and knowledge of application classes (for eg. AppServer's classes) would be needed to create app specific aoqi@0: scripts. The following script samples are app-independent and provide a flavour of kind of scripts that can be written. aoqi@0: aoqi@0:

Script to print system properties of JVM

aoqi@0: aoqi@0:
aoqi@0: 
aoqi@0: jvm.sysProps.toString()
aoqi@0: 
aoqi@0: 
aoqi@0: aoqi@0:

Script to print JVM command line flags

aoqi@0:
aoqi@0: 
aoqi@0: jvm.flags.toString()
aoqi@0: 
aoqi@0: 
aoqi@0: aoqi@0: aoqi@0:

Script to print class-wise histogram of objects

aoqi@0: aoqi@0:
aoqi@0: 
aoqi@0: 
aoqi@0: // associate array to hold histogram
aoqi@0: var histo;
aoqi@0: function func(obj) {
aoqi@0:     var classname = classof(obj).name;
aoqi@0:     if (histo[classname] == undefined) {
aoqi@0:        // first time we are visiting this class type
aoqi@0:        histo[classname] = 1;
aoqi@0:     } else {
aoqi@0:        histo[classname]++; 
aoqi@0:     }
aoqi@0: }
aoqi@0: 
aoqi@0: // iterate through java heap calling 'func' for each object
aoqi@0: jvm.heap.forEachObject(func);
aoqi@0: 
aoqi@0: // print the histogram
aoqi@0: for (i in histo) {
aoqi@0:    println('number of instances of ', i, ' = ', histo[i]);
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0: 
aoqi@0: aoqi@0:

Script to print stack trace of all Java threads

aoqi@0: aoqi@0:
aoqi@0: 
aoqi@0: 
aoqi@0: function printStackTrace(t) {
aoqi@0:     println(t.name);
aoqi@0:     println('');
aoqi@0:     for (i in t.frames) {
aoqi@0:        println(t.frames[i]);
aoqi@0:     }
aoqi@0:     println('');
aoqi@0: }
aoqi@0: 
aoqi@0: // walk through the list of threads and call printStackTrace
aoqi@0: // for each thread
aoqi@0: for (o in jvm.threads) {
aoqi@0:     printStackTrace(jvm.threads[o]);
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0: 
aoqi@0: 
aoqi@0: aoqi@0: aoqi@0:

Script to re-construct .class files for all non-bootstrap classes

aoqi@0: aoqi@0:
aoqi@0: 
aoqi@0: 
aoqi@0: function dump(cl) {
aoqi@0:    if (!cl.isArrayClass  && cl.classLoader != null) { 
aoqi@0:       // not an array class and a non-bootstrap class
aoqi@0:       // create .class files in e:\tmp dir
aoqi@0:       dumpClass(cl, "e:\\tmp); 
aoqi@0:    } else {
aoqi@0:       println("skipping bootstrap class ", cl.name);
aoqi@0:    }
aoqi@0: }
aoqi@0: 
aoqi@0: // walk thru heap and call callback for each java.lang.Class instance
aoqi@0: jvm.heap.forEachObject(dump, "java.lang.Class");
aoqi@0: 
aoqi@0: 
aoqi@0: aoqi@0:

Script to print paths of all java.io.File's currently accessed

aoqi@0: aoqi@0:
aoqi@0: 
aoqi@0: 
aoqi@0: function printFile(f) {
aoqi@0:    // construct a mirror java.io.File here and
aoqi@0:    // print absolute path here
aoqi@0:    println(mirror(f).getAbsolutePath());
aoqi@0: }
aoqi@0: 
aoqi@0: jvm.heap.forEachObject(printFile, "java.io.File");
aoqi@0: 
aoqi@0: 
aoqi@0: 
aoqi@0: aoqi@0:

Script to print static fields of java.lang.Thread class

aoqi@0:
aoqi@0: 
aoqi@0: 
aoqi@0: var threadClass = classof("java.lang.Thread");
aoqi@0: for (i in threadClass.statics) {
aoqi@0:   println(i, '=', threadClass.statics[i]);
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0: 
aoqi@0: aoqi@0:

Low level interface (VM State)

aoqi@0: aoqi@0:

aoqi@0: Low level jsdb interface works by JavaScript-to-Java (previously known as "LiveConnect") aoqi@0: interface provided by Rhino JavaScript engine. aoqi@0:

aoqi@0: aoqi@0:

sapkg object

aoqi@0:

aoqi@0: This object provides short names for SA package names. For eg. instead of writing aoqi@0: Packages.sun.jvm.hotspot.memory, we can write sapkg.memory. aoqi@0:

aoqi@0: aoqi@0:

sa object

aoqi@0:

aoqi@0: This object contains all SA singleton objects such as VM, Universe, SymbolTable, aoqi@0: SystemDictionary, ObjectHeap, CollectedHeap, Debugger, CDebugger (if available), aoqi@0: Interpreter, TypeDataBase and Threads. For eg. to access SymbolTable of Java debuggee, aoqi@0: we can use sa.symbolTable. User can execute the following code to get fields of this object. aoqi@0:

aoqi@0:
aoqi@0: 
aoqi@0: for (i in sa) {
aoqi@0:   println(i);
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0: aoqi@0:

Heap Iterators

aoqi@0:
aoqi@0:
forEachOop(callback)
aoqi@0:
calls a callback function for each Oop in Java heap
aoqi@0:
forEachOopOfKlass(callback, klass, [includeSubtypes])
aoqi@0:
calls a callback function for each Oop of a give Klass type aoqi@0: Optinally, third argument can specify whether to include subtype Oops aoqi@0: or not. aoqi@0:
aoqi@0:
aoqi@0: aoqi@0:

System Dictionary Access

aoqi@0:
aoqi@0:
forEachKlass(callback)
aoqi@0:
calls a callback function for each Klass in Java heap
aoqi@0:
forEachKlassAndLoader(callback)
aoqi@0:
aoqi@0: calls callback with Klass and initiating loader (Oop) for System dictionary aoqi@0: entry. aoqi@0:
aoqi@0:
forEachPrimArrayKlass(callback)
aoqi@0:
aoqi@0: calls callback with Klass and initiating loader (Oop) for each aoqi@0: primitive array Klass in the system. aoqi@0:
aoqi@0:
findInstanceKlass(name)
aoqi@0:
aoqi@0: finds the first instance klass with given name from System dictionary aoqi@0:
aoqi@0:
aoqi@0: aoqi@0:

Thread, Frame Iterators

aoqi@0:
aoqi@0:
forEachJavaThread(callback)
aoqi@0:
calls callback for each Java Thread
aoqi@0:
forEachFrame(javaThread, callback)
aoqi@0:
calls callback for each Frame of a given JavaThread
aoqi@0:
forEachVFrame(javaThread, callback)
aoqi@0:
calls callback for each JavaVFrame of a given JavaThread
aoqi@0:
forEachThread(callback)
aoqi@0:
calls callback for each (native) ThreadProxy (obtained by CDebugger.getThreadList) aoqi@0:
aoqi@0:
forEachCFrame(threadProxy, callback)
aoqi@0:
aoqi@0: calls callback for each CFrame of a given ThreadProxy object aoqi@0:
aoqi@0:
aoqi@0: aoqi@0:

Code blobs, Interpreter codelets

aoqi@0:
aoqi@0:
forEachCodeBlob(callback)
aoqi@0:
aoqi@0: calls callback with each code blob in code cache aoqi@0:
aoqi@0:
findCodeBlob(address)
aoqi@0:
aoqi@0: finds the code blob, if any, that contains the given address. aoqi@0: Returns null, on failure. aoqi@0:
aoqi@0:
findNMethod(address)
aoqi@0:
aoqi@0: finds the NMethod that contains given address. aoqi@0:
aoqi@0:
pcDescAt(addr)
aoqi@0:
aoqi@0: returns PCDesc at given address or null. aoqi@0:
aoqi@0:
forEachInterpCodelet(callbacl)
aoqi@0:
aoqi@0: calls callback with each Interpreter codelet aoqi@0:
aoqi@0:
aoqi@0: aoqi@0:

VM structs, constants

aoqi@0:
aoqi@0:
forEachType(callback)
aoqi@0:
aoqi@0: calls callback for each Type in VM's type database aoqi@0:
aoqi@0:
forEachVMIntConst(callback)
aoqi@0:
aoqi@0: calls callback for each named integer constant. passes name aoqi@0: as argument. aoqi@0:
aoqi@0:
forEachVMLongConst(callback)
aoqi@0:
aoqi@0: calls callback for each named long constant. passes name aoqi@0: as argument. aoqi@0:
aoqi@0:
findVMType(name)
aoqi@0:
aoqi@0: finds a VM type by name. returns null if no known Type of given name aoqi@0: exists in type database. aoqi@0:
aoqi@0:
findVMIntConst(name)
aoqi@0:
aoqi@0: finds an integer constant in type data base by name. aoqi@0:
aoqi@0:
findVMLongConst(name)
aoqi@0:
aoqi@0: finds an long constant in type data base by name. aoqi@0:
aoqi@0:
vmTypeof(addr)
aoqi@0:
aoqi@0: returns VM type of object at 'addr' if any. Else, returns null. aoqi@0:
aoqi@0:
isOfVMType(addr, type)
aoqi@0:
aoqi@0: returns whether object at 'addr' is of VM type 'type' or not. aoqi@0:
aoqi@0:
printVMType(type, addr)
aoqi@0:
aoqi@0: prints 'addr' as VM object of type 'type' aoqi@0:
aoqi@0:
printXXX(addr)
aoqi@0:
aoqi@0: For each VM type, these functions are defined. For eg. there is printUniverse, aoqi@0: printSystemDictionary etc. are available. Without 'addr' being passed static fields are printed. With 'addr' param being passed, instance fields are printed. aoqi@0:
aoqi@0:
aoqi@0: aoqi@0:

Low level debugger facilities

aoqi@0:
aoqi@0:
num2addr(number)
aoqi@0:
aoqi@0: converts a (long) number to SA Address instance aoqi@0:
aoqi@0:
str2addr(string)
aoqi@0:
aoqi@0: converts a given hex string to SA Address instance aoqi@0:
aoqi@0:
any2addr(any)
aoqi@0:
aoqi@0: Takes a number or a string or an Address and returns aoqi@0: an Address instance. For other types, returns 'undefined' aoqi@0:
aoqi@0:
addr2str(addr)
aoqi@0:
aoqi@0: converts a given Address instance to a hex string aoqi@0:
aoqi@0:
addr2num(addr)
aoqi@0:
aoqi@0: converts a given Address instance to a (long) number aoqi@0:
aoqi@0:
sym2addr(library, symbol)
aoqi@0:
aoqi@0: returns Address of a given symbol in a given library (shared object or DLL) aoqi@0: Example: sym2addr('jvm.dll', 'JNI_CreateJavaVM') aoqi@0:
addr2sym(addr)
aoqi@0:
aoqi@0: Returns nearest symbol to a given address (if any). If no such symbol is found, aoqi@0: returns the given address as a string. aoqi@0:
aoqi@0:
readBytesAt(addr, num)
aoqi@0:
aoqi@0: returns 'num' bytes at 'addr' as a Java byte[] aoqi@0:
aoqi@0:
readWordsAt(addr, num)
aoqi@0:
aoqi@0: returns 'num' words at 'addr' as a Java long[] aoqi@0:
aoqi@0:
readCStrAt(addr)
aoqi@0:
aoqi@0: returns 'C' String at given address aoqi@0:
aoqi@0:
readCStrLen(addr)
aoqi@0:
aoqi@0: returns the length of the 'C' String at given address aoqi@0:
aoqi@0:
readRegs(threadProxy)
aoqi@0:
aoqi@0: returns register set (of Thread Context) of a given thread specified aoqi@0: by threadProxy. return value is an associate array having name-value pairs aoqi@0: of registers. aoqi@0:
aoqi@0:
regs(threadProxy)
aoqi@0:
aoqi@0: prints register set of a given thread. aoqi@0:
aoqi@0:
mem(addr, [num])
aoqi@0:
aoqi@0: prints 'num' words (address size) at 'addr'. Prints nearest symbol for address, if found. aoqi@0:
aoqi@0:
dis(addr, [num])
aoqi@0:
prints native code disassembly of 'num' bytes at given address 'addr'. aoqi@0: Default value of 'num' is 4. This automatically detects whether the given address aoqi@0: inside a nmethod. If so, it prints safepoint info, entry points , method signature etc. aoqi@0: of the nmethod. aoqi@0:
aoqi@0:
jdis(method [or addr])
aoqi@0:
aoqi@0: prints Java bytecode disassembly for given method Oop or address of a method Oop. aoqi@0:
aoqi@0:
nmethoddis(nmethod)
aoqi@0:
aoqi@0: prints disassembly of given nmethod object. Note that you don't have to call this directly aoqi@0: instead use 'dis'. aoqi@0:
aoqi@0:
where
aoqi@0:
aoqi@0: prints Java stack trace for all Java threads aoqi@0:
aoqi@0:
aoqi@0: aoqi@0:

Miscellaneous

aoqi@0:
aoqi@0:
addr2oop(addr)
aoqi@0:
aoqi@0: converts a given address to a Oop object aoqi@0:
aoqi@0:
oop2addr(oop)
aoqi@0:
aoqi@0: returns address of a given Oop object aoqi@0:
aoqi@0:
isOfVMType(addr, type)
aoqi@0:
aoqi@0: returns whether the given 'addr' points to a (C++) VM object of specified aoqi@0: type. type may be specified by SA Type object or string name of the type. aoqi@0:
aoqi@0:
newVMObject(addr)
aoqi@0:
aoqi@0: returns instance of SA object for a given address (similar to SA VirtualConstructor aoqi@0: interface). aoqi@0:
aoqi@0:
vmobj2addr(vmobject)
aoqi@0:
aoqi@0: returns Address represented by a given SA VMObject aoqi@0:
aoqi@0:
addr2vmobj(addr)
aoqi@0:
same as newVMObject(addr)
aoqi@0:
whatis(addr)
aoqi@0:
aoqi@0: returns string description of given address (using SA FindPointer and guess type API). aoqi@0:
isOop(addr)
aoqi@0:
aoqi@0: returns whether a given address is a valid Oop address or not aoqi@0:
aoqi@0:
aoqi@0: aoqi@0:

Moving b/w jsdb low level and high level interfaces

aoqi@0: aoqi@0:

aoqi@0: Java objects of debuggee are represented by different script wrappers in high level aoqi@0: interface. In the low-level interface these are instances of SA Oop class or its' aoqi@0: subclass. To move b/w low-level and high-level interfaces the following functions may aoqi@0: be used aoqi@0:

aoqi@0:
aoqi@0:
oop2obj(oop)
aoqi@0:
aoqi@0: converts a given Oop object to a high-level wrapper object aoqi@0:
aoqi@0:
obj2oop(obj)
aoqi@0:
aoqi@0: converts a jsdb high level wrapper to underlying Oop instance aoqi@0:
aoqi@0:
aoqi@0: aoqi@0:

JavaScript tips

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: