Java Platform Debugger Architecture
Java SE 1.5 Enhancements
The version 5.0 family of the JDK includes the following JPDA enhancements:
- Addition of JVMTI
- JPDA now supports generics
- JPDA now supports enums
- JPDA now supports varargs
- JPDA pluggable connections and transports
- JDWP Allow machine to be specified on address param for server
- Read-only subset of JDI
- Tool to generate/analyze core files from a crashed JVM
- Need a way to timeout or test for connection with LinsteningConnector.accept()
Addition of JVMTI
The Java Virtual Machine Tool Interface (JVMTI) is a new native programming interface for use by development and monitoring tools, which replaces JVMPI and JVMDI. It provides both a way to inspect the state and to control the execution of applications running in the Java virtual machine (VM). JVMTI is intended to provide a VM interface for the full breadth of tools that need access to VM state, including but not limited to: profiling, debugging, monitoring, thread analysis, and coverage analysis tools.
Note: JVMPI and JVMDI will be removed in the next major release of Java SE.
JPDA Now Supports Generics
Generics is a new feature in the Java programming langauge, and the JPDA interfaces now allow debuggers to access generic information. This change adds interface elements to the JDWP and JDI components of JPDA. These elements allow generic information to be accessed by JDI clients as Strings containing the actual contents of the Signature attributes from .class files.
JDWP changes
The following are new commands to JDWP. These are the similar to the previously-existing commands, but return generic signatures if they exist, in addition to the JNI signatures.
- AllClassesWithGeneric: Similar to AllClasses but also returns the generic signature for each class
- SignatureWithGeneric: Similar to the ReferenceType.Signature command but also returns the generic signature.
- FieldsWithGeneric: Similar to the Fields command but also returns the generic signature for each field.
- MethodsWithGeneric: Similar to the Methods command but also returns the generic signature for each method.
- VariableTableWithGeneric: Similar to the VariableTable command but also includes a new generic signature value for each variable.
JDI changes
New methods:
- LocalVariable.genericSignature()
- ReferenceType.genericSignature()
- TypeComponent.genericSignature()
- Method.isBridge()
JPDA Now Supports Enums
Enumeration types are a new feature in the Java programming langauge, and the JPDA interfaces now allow debuggers to access information about enumeration types.
New methods:
- com.sun.jdi.ClassType.isEnum()
- com.sun.jdi.Field.isEnumConstant()
JPDA Now Supports Varargs
The ability to declare a method as accepting a variable number of agruments is a new feature in the Java programming langauge. The JDI now allows a debugger to query whether or not a method accepts a variable number of arguments. This change also modifies the three JDI methods that allow a method to be called to accept varargs.
New method in com.sun.jdi.Method:
- boolean isVarargs();
Specification update for the following methods:
- com.sun.jdi.Method.argumentTypes()
- com.sun.jdi.Method.arguments()
- com.sun.jdi.ClassType.invokeMethod
- com.sun.jdi.ClassType.newInstance
- com.sun.jdi.ObjectReference.invokeMethod
JPDA Pluggable Connections and Transports
The Java Debug Interface (JDI) previously lacked a provider interface to allow tool vendors to develop and deploy their own Connectors. A Connector is the means by which a Java debugger connects to a target virtual machine.
The JDK ships with 6 Connectors. Two of these are LaunchingConnectors, which are used to launch and establish a debugging session with a target VM. The other four Connectors encapsulate transports for remote debugging. The creation of these 6 Connectors was previously hardcoded into the Oracle JDI implementation of VirtualMachineManager and there was no means for tool vendors to develop or deploy additional Connectors.
Related to the above is that the Java Platform Debugger Architecture (JPDA) previously lacked a means for tool vendors to plug-in their own transport implementations. There was no supported way to debug over non-Oracle provided transports. The JDK ships with 2 transports - a TCP transport (for Solaris, Linux, and Windows) and a shared memory transport (Windows only).
There are two components to this enhancement:
- Extend the Java Debug Interface (JDI) with specification and a provider interface to allow 3rd party Connectors and Transport Services be developed and deployed
- Develop a VM/debuggee-side native interface to allow 3rd party transport libraries to be located and loaded by the debugging agent running in the VM
Specification updates for 5 existing classes/interfaces :
- com.sun.jdi.Bootstrap
- com.sun.jdi.VirtualMachineManager
- com.sun.jdi.connect.AttachingConnector
- com.sun.jdi.connect.ListeningConnector
- com.sun.jdi.connect.Transport
Two new methods added com.sun.jdi.VirtualMachineManager:
- VirtualMachine createVirtualMachine(Connection connection, Process process) throws IOException
- VirtualMachine createVirtualMachine(Connection connection) throws IOException;
Four new classes :
- com.sun.jdi.connect.spi.TransportService
- com.sun.jdi.connect.spi.TransportService.Capabilities (inner class)
- com.sun.jdi.connect.spi.TransportService.ListenKey (inner class)
- com.sun.jdi.connect.spi.Connection
Two new exceptions :
- com.sun.jdi.connect.TransportTimeoutException
- com.sun.jdi.connect.spi.ClosedConnectionException
Native transport interface (defined by jdwpTransport.h)
New Connector arguments have been added as follows :
A "timeout" Connector argument has been added to the following Connectors (note that these are Connector names and not class names) :
- com.sun.jdi.SocketAttach
- com.sun.jdi.SocketListen
- com.sun.jdi.SharedMemoryAttach
- com.sun.jdi.SharedMemoryListen
The timeout argument is optional and specifies the attach or accept timeout (in milliseconds) to use when establishing a connection to the debuggee.
A "localAddress" Connector argument has been added to com.sun.jdi.SocketListen. This Connector argument specifies the local address to bind to when waiting to accept a connection from the debuggee.
Also, the options string to the JDWP agent has been amended to include a timeout option. The timeout argument specifies the timeout (in milliseconds) when establishing the connection to the debugger :
-agentlib:jdwp=...,...,timeout=<timeout>
In addition the address string for the dt_socket transport has been amended to take a local address when running in server mode. For example:
-agentlib:jdwp=transport=dt_socket,address=127.0.0.1:4000,server=y
indicates that the debugee bind to loopback address, port 4000 and wait for the debugger to connect.
JDWP Allow machine to be specified on address param for server
One of the JPDA options is the "address=" parameter, which has the format of:
JPDA Server: address=port
JPDA Client: address=machine:port
This change allows the server to accept a machine name, for cases where the JPDA server is running on a computer with more than one network card and address. The SunCommandLineLauncher, which is the default LaunchingConnector returned by Bootstrap.virtualMachineManager().defaultConnector(), now has a localAddress connector argument so that the local address can be specified. Also, the JDWP options string on the debugee-side can now accept a local address in addition to a port.
Read-only subset of JDI
When using JDI to debug a 'debuggee' that is unmodifiable (such as when the debuggee is represented by a corefile), the JDI client needs to know which JDI methods it can call and which it cannot. This change adds a method to the VirtualMachine interface that allows the JDI client to determine if that VM is read-only. It also defines various JDI methods as throwing a new exception if called on a read-only VM.
New method in com.sun.jdi.VirtualMachine.
- boolean canBeModified()
New exception class:
- com.sun.jdi.VMCannotBeModified.
The clause: @throws VMCannotBeModifiedException if the VirtualMachine is read-only - see {@link VirtualMachine#canBeModified()}. has been added to the specification of the following methods:
com.sun.jdi.ArrayReference
- void setValue(int index, Value value)
- void setValues(List values)
- void setValues(int index, List values, int srcIndex, int length)
com.sun.jdi.ArrayType
- ArrayReference newInstance(int length);
com.sun.jdi.ClassType
- void setValue(Field field, Value value)
- Value invokeMethod(ThreadReference thread, Method method, List arguments, int options)
- ObjectReference newInstance(ThreadReference thread, Method method, List arguments, int options)
com.sun.jdi.ObjectReference
- ArrayReference newInstance(int length);
com.sun.jdi.ClassType
- void setValue(Field field, Value value)
- Value invokeMethod(ThreadReference thread, Method method, List arguments, int options)
- ObjectReference newInstance(ThreadReference thread, Method method, List arguments, int options)
com.sun.jdi.ObjectReference
- void setValue(Field field, Value value)
- Value invokeMethod(ThreadReference thread, Method method,
- List arguments, int options)
com.sun.jdi.StackFrame
- void setValue(LocalVariable variable, Value value)
com.sun.jdi.ThreadGroupReference
- void suspend();
- void resume();
com.sun.jdi.ThreadReference
- void suspend();
- void resume();
- void stop(ObjectReference throwable);
- void interrupt();
- void popFrames(StackFrame frame)
com.sun.jdi.VirtualMachine
- void redefineClasses(Map classToBytes);
- void suspend();
- void resume();
- EventQueue eventQueue();
- EventRequestManager eventRequestManager();
- void exit(int exitCode);
Tool to generate/analyze core files from a crashed JVM
When a JVM crashes, developers want to be able to look at a core file and understand what their code was doing when the crash occured. JDI, the Java Debug Interface, defines interfaces for 'connectors'. A connector is an implementation of one of these interfaces. Connectors are used to establish a connection between a debugger process and a debuggee. Java SE ships with several connectors that allow a debugger process to launch a debuggee, attach to an already running debuggee, or listen for incoming connections from a debuggee which has not yet run. These connectors are not part of the JDI specification but are part of the implementation of JDI on a platform. Other vendors are free to include whatever connectors they choose. In addition, users themselves can create their own connectors.
This feature adds three new connectors to the Oracle implementation. Each connector has a set of arguments that the JDI user can/must set in order to use the connector.
The interface summary below lists the class names of these three new connectors. This solution uses a Solaris private interface in libproc.h.
This will add three new attaching connectors to our release of Java SE:
- sun.jvm.hotspot.jdi.SACoreAttachingConnector
- sun.jvm.hotspot.jdi.SAPIDAttachingConnector
- sun.jvm.hotspot.jdi.SADebugServerAttachingConnector
These connectors will be contained in the list of connectors returned to a JDI client by the JDI methods:
- VirtualMachineManager.allConnectors()
- VirtualMachineManager.attachingConnectors()
These connectors are used by a JDI client in the same way that the other JDI attaching connectors are used.
The JDI VirtualMachine objects returned by these connectors' attach() methods are 'read-only'. This means that VirtualMachine.canBeModified() will return false. This in turn means that the methods defined in JDI as throwing VMCannotBeModifiedException if the VirtualMachine is read-only should not be called by the JDI client. These connectors can only be used to debug processes and corefiles that use the Oracle Hotspot Virtual Machine. These connectors are not available on Windows nor on Linux Itanium.
Need a way to timeout or test for connection with ListeningConnector.accept()
The method com.sun.jdi.connect.ListeningConnector.attach() previously waited indefinitely for a connection, with no way to set a timeout or interrupt the wait. This made it fairly dangerous to use in an integrated debugger. This change makes it possible to set a timeout, instantly test for a connection, or interrupt another thread.