aoqi@0: 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:aoqi@0: There are two application programmer interfaces (APIs) for SA: 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:
Function/Variable | aoqi@0:Description | aoqi@0:
---|---|
aoqi@0: address(jobject) aoqi@0: | aoqi@0:aoqi@0: function that returns the address of the Java object as a string aoqi@0: | aoqi@0:aoqi@0: classof(jobject) aoqi@0: | aoqi@0:aoqi@0: function that returns the JavaScript object that represents class object of the Java object aoqi@0: | aoqi@0: aoqi@0:aoqi@0: dumpClass(jclass,[dir]) aoqi@0: | 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: aoqi@0:aoqi@0: help() aoqi@0: | aoqi@0:aoqi@0: function that prints help message for global functions and objects aoqi@0: | aoqi@0: aoqi@0:
aoqi@0: identityHash(jobject) aoqi@0: | aoqi@0:aoqi@0: function that returns the identity hashCode of the Java object aoqi@0: | aoqi@0:
aoqi@0: mirror(jobject) aoqi@0: | aoqi@0:aoqi@0: function that returns a local mirror of the Java object. aoqi@0: | aoqi@0:
aoqi@0: load([file1, file2,...]) aoqi@0: | aoqi@0:
aoqi@0: function that loads zero or more JavaScript file(s). With no arguments, reads |
aoqi@0:
aoqi@0: object(string) aoqi@0: | aoqi@0:aoqi@0: function that converts a string address into Java object aoqi@0: | aoqi@0:
aoqi@0: owner(jobject) aoqi@0: | aoqi@0:aoqi@0: function that returns the owner thread of this monitor or null aoqi@0: | aoqi@0:
aoqi@0: sizeof(jobject) aoqi@0: | aoqi@0:aoqi@0: function that returns the size of Java object in bytes aoqi@0: | aoqi@0:
aoqi@0: staticof(jclass, field) aoqi@0: | aoqi@0:aoqi@0: function that returns the value of given field of the given Java class aoqi@0: | aoqi@0:
aoqi@0: print(expr1, expr2,...) aoqi@0: | aoqi@0:aoqi@0: function that prints zero or more JavaScript expressions after converting those as strings aoqi@0: | aoqi@0:
aoqi@0: println(expr1, expr2..) aoqi@0: | aoqi@0:aoqi@0: function that same as print, but prints a newline at the end aoqi@0: | aoqi@0:
aoqi@0: read([prompt]) aoqi@0: | aoqi@0:aoqi@0: function that reads a single line from standard input aoqi@0: | aoqi@0:
aoqi@0: quit() aoqi@0: | aoqi@0:aoqi@0: function that quits the interactive load call as well as the shell aoqi@0: | aoqi@0:
aoqi@0: jvm aoqi@0: | 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 supports the following read-only properties. aoqi@0:
aoqi@0: aoqi@0:aoqi@0: Property name aoqi@0: | aoqi@0:aoqi@0: Description aoqi@0: | aoqi@0:
---|---|
aoqi@0: threads aoqi@0: | aoqi@0:aoqi@0: array of Java threads from the debuggee aoqi@0: | aoqi@0:
aoqi@0: heap aoqi@0: | aoqi@0:aoqi@0: object representing the heap of the debuggee aoqi@0: | aoqi@0:
aoqi@0: type aoqi@0: | aoqi@0:aoqi@0: string value that is either "Server" or "Client" or "Core" -- the flavour of debuggee VM aoqi@0: | aoqi@0:
aoqi@0: bootClassPath aoqi@0: | aoqi@0:aoqi@0: string value of bootclasspath of the debuggee aoqi@0: | aoqi@0:
aoqi@0: cpu aoqi@0: | aoqi@0:aoqi@0: string value of cpu on which the debuggee runs/ran aoqi@0: | aoqi@0:
aoqi@0: sysProps aoqi@0: | aoqi@0:aoqi@0: name-value pairs (JavaScript associative array) of Java System properties of the debuggee aoqi@0: | aoqi@0:
aoqi@0: addressSize aoqi@0: | aoqi@0:aoqi@0: int value -- 32 for 32 bit debuggee, 64 for 64 bit debuggee aoqi@0: | aoqi@0:
aoqi@0: os aoqi@0: | aoqi@0:aoqi@0: string value of OS on which the debuggee runs/ran aoqi@0: | aoqi@0:
aoqi@0: buildInfo aoqi@0: | aoqi@0:aoqi@0: internal build info string from debuggee aoqi@0: | aoqi@0:
aoqi@0: flags aoqi@0: | aoqi@0:aoqi@0: name-value pairs (JavaScript associative array) of JVM command line flags of the debuggee aoqi@0: | aoqi@0:
aoqi@0: classPath aoqi@0: | aoqi@0:aoqi@0: string value of classpath of the debuggee aoqi@0: | aoqi@0:
aoqi@0: userDir aoqi@0: | aoqi@0:aoqi@0: string value of user.dir System property of the debuggee aoqi@0: | aoqi@0:
aoqi@0: heap object represents Java heap of the debuggee VM aoqi@0:
aoqi@0:aoqi@0: Function or property name aoqi@0: | aoqi@0:aoqi@0: Description aoqi@0: | aoqi@0:
---|---|
aoqi@0: capacity aoqi@0: | aoqi@0:aoqi@0: byte size of capacity of the heap aoqi@0: | aoqi@0:
aoqi@0: used aoqi@0: | aoqi@0:aoqi@0: byte size of used portion (of live objects) of the heap aoqi@0: | aoqi@0:
aoqi@0: forEachObject(func, [class], [include subtypes -- true|false]) aoqi@0: | 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:
aoqi@0: forEachClass(func, [initiating loader -- true|false]) aoqi@0: | 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: 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: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: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: Property name aoqi@0: | aoqi@0:aoqi@0: Description aoqi@0: | aoqi@0:aoqi@0: thisObject aoqi@0: | aoqi@0:aoqi@0: Object representing 'this' of the current frame [will be null for static methods] aoqi@0: | aoqi@0: aoqi@0:
---|---|
aoqi@0: locals aoqi@0: | aoqi@0:aoqi@0: name-value pairs of local variables [JavaScript associative array] aoqi@0: | aoqi@0:
aoqi@0: line aoqi@0: | aoqi@0:aoqi@0: Java source line number at which the frame is executing aoqi@0: | aoqi@0:
aoqi@0: bci aoqi@0: | aoqi@0:aoqi@0: byte code index of the bytecode that the frame is executing aoqi@0: | aoqi@0:
aoqi@0: thread aoqi@0: | aoqi@0:aoqi@0: thread to which this frame belongs aoqi@0: | aoqi@0:
aoqi@0: method aoqi@0: | aoqi@0:aoqi@0: Java method that the frame is executing aoqi@0: | aoqi@0:
aoqi@0: method object represents a Java method of debuggee aoqi@0:
aoqi@0: aoqi@0:aoqi@0: Property name aoqi@0: | aoqi@0:aoqi@0: Description aoqi@0: | aoqi@0:
---|---|
aoqi@0: isStatic aoqi@0: | aoqi@0:aoqi@0: boolean - true for static methods and false for non-static methods aoqi@0: | aoqi@0:
aoqi@0: isSynchronized aoqi@0: | aoqi@0:aoqi@0: boolean - true for synchronized methods and false for non-synchronized methods aoqi@0: | aoqi@0:
aoqi@0: isNative aoqi@0: | aoqi@0:aoqi@0: boolean - true for native methods and false for non-native methods aoqi@0: | aoqi@0:
aoqi@0: isProtected aoqi@0: | aoqi@0:aoqi@0: boolean - true for protected methods and false for non-protected methods aoqi@0: | aoqi@0:
aoqi@0: isPrivate aoqi@0: | aoqi@0:aoqi@0: boolean - true for private methods and false for non-private methods aoqi@0: | aoqi@0:
aoqi@0: isSynthetic aoqi@0: | aoqi@0:aoqi@0: boolean - true for Javac generated synthetic methods and false for non-synthetic methods aoqi@0: | aoqi@0:
aoqi@0: isPackagePrivate aoqi@0: | aoqi@0:aoqi@0: boolean - true for package-private methods and false for non-package-private methods aoqi@0: | aoqi@0:
aoqi@0: isPublic aoqi@0: | aoqi@0:aoqi@0: boolean - true for public methods and false for non-public methods aoqi@0: | aoqi@0:
aoqi@0: holder aoqi@0: | aoqi@0:aoqi@0: an object that represents Class that contains this method aoqi@0: | aoqi@0:
aoqi@0: signature aoqi@0: | aoqi@0:aoqi@0: string -- signature of this method aoqi@0: | aoqi@0:
aoqi@0: isObsolete aoqi@0: | aoqi@0:aoqi@0: boolean - true for obsolete (hotswapped) methods and false for non-obsolete methods aoqi@0: | aoqi@0:
aoqi@0: isStrict aoqi@0: | aoqi@0:aoqi@0: boolean - true for strictfp methods and false for non-strictfp methods aoqi@0: | aoqi@0:
aoqi@0: isFinal aoqi@0: | aoqi@0:aoqi@0: boolean - true for final methods and false for non-final methods aoqi@0: | aoqi@0:
aoqi@0: name aoqi@0: | aoqi@0:aoqi@0: string - name of this method 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: Property name aoqi@0: | aoqi@0:aoqi@0: Description aoqi@0: | aoqi@0:
---|---|
aoqi@0: name aoqi@0: | aoqi@0:aoqi@0: name of this class aoqi@0: | aoqi@0:
aoqi@0: superClass aoqi@0: | aoqi@0:aoqi@0: class object representing super class of this class aoqi@0: | aoqi@0:
aoqi@0: isArrayClass aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class an array class? aoqi@0: | aoqi@0:
aoqi@0: isStatic aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class static or not aoqi@0: | aoqi@0:
aoqi@0: isInterface aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class an interface aoqi@0: | aoqi@0:
aoqi@0: isAbstract aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class abstract or not aoqi@0: | aoqi@0:
aoqi@0: isProtected aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class protected or not aoqi@0: | aoqi@0:
aoqi@0: isPrivate aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class private or not aoqi@0: | aoqi@0:
aoqi@0: isPackagePrivate aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class package private or not aoqi@0: | aoqi@0:
aoqi@0: isSynthetic aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class synthetic or not aoqi@0: | aoqi@0:
aoqi@0: classLoader aoqi@0: | aoqi@0:aoqi@0: object that represents ClassLoader object that loaded the current class aoqi@0: | aoqi@0:
aoqi@0: fields aoqi@0: | aoqi@0:aoqi@0: array of static and instance fields of the current class aoqi@0: | aoqi@0:
aoqi@0: protectionDomain aoqi@0: | aoqi@0:aoqi@0: protection domain to which current class belongs aoqi@0: | aoqi@0:
aoqi@0: isPublic aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class public or not aoqi@0: | aoqi@0:
aoqi@0: signers aoqi@0: | aoqi@0:aoqi@0: array of signers for current class aoqi@0: | aoqi@0:
aoqi@0: sourceFile aoqi@0: | aoqi@0:aoqi@0: string -- name of the source file for current class aoqi@0: | aoqi@0:
aoqi@0: interfaces aoqi@0: | aoqi@0:aoqi@0: array -- interfaces implemented by current class aoqi@0: | aoqi@0:
aoqi@0: isStrict aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class strictfp or not aoqi@0: | aoqi@0:
aoqi@0: methods aoqi@0: | aoqi@0:aoqi@0: array of methods (static and instance) of the current class aoqi@0: | aoqi@0:
aoqi@0: isFinal aoqi@0: | aoqi@0:aoqi@0: boolean -- is the current class final or not aoqi@0: | aoqi@0:
aoqi@0: statics aoqi@0: | aoqi@0:aoqi@0: name-value pairs (JavaScript associate array) of static fields of the current class aoqi@0: | aoqi@0:
aoqi@0: field represents a static or instance field of some class in debuggee aoqi@0:
aoqi@0: aoqi@0:aoqi@0: Property name aoqi@0: | aoqi@0:aoqi@0: Description aoqi@0: | aoqi@0:
---|---|
aoqi@0: isStatic aoqi@0: | aoqi@0:aoqi@0: boolean -- is this field a static field? aoqi@0: | aoqi@0:
aoqi@0: holder aoqi@0: | aoqi@0:aoqi@0: class that owns this field aoqi@0: | aoqi@0:
aoqi@0: signature aoqi@0: | aoqi@0:aoqi@0: string signature of this field aoqi@0: | aoqi@0:
aoqi@0: isProtected aoqi@0: | aoqi@0:aoqi@0: boolean - is this field a protected field or not? aoqi@0: | aoqi@0:
aoqi@0: isPrivate aoqi@0: | aoqi@0:aoqi@0: boolean - is this field a private field or not? aoqi@0: | aoqi@0:
aoqi@0: isSynthetic aoqi@0: | aoqi@0:aoqi@0: boolean - is this javac generated synthetic field or not? aoqi@0: | aoqi@0:
aoqi@0: isPackagePrivate aoqi@0: | aoqi@0:aoqi@0: boolean - is this field a package private field or not? aoqi@0: | aoqi@0:
aoqi@0: isTransient aoqi@0: | aoqi@0:aoqi@0: boolean - is this field a transient field or not? aoqi@0: | aoqi@0:
aoqi@0: isFinal aoqi@0: | aoqi@0:aoqi@0: boolean - is this field final or not? aoqi@0: | aoqi@0:
aoqi@0: name aoqi@0: | aoqi@0:aoqi@0: string - name of this field aoqi@0: | aoqi@0:
aoqi@0: isPublic aoqi@0: | aoqi@0:aoqi@0: boolean - is this field public or not? aoqi@0: | 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:
aoqi@0:
aoqi@0: jvm.sysProps.toString()
aoqi@0:
aoqi@0:
aoqi@0:
aoqi@0:
aoqi@0:
aoqi@0: jvm.flags.toString()
aoqi@0:
aoqi@0:
aoqi@0:
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:
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:
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:
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:
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: 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: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: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: 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:aoqi@0:aoqi@0: for(i in object) { println(i); } aoqi@0: aoqi@0:
aoqi@0:
aoqi@0: for(i in this) { println(i); }
aoqi@0:
aoqi@0:
aoqi@0: