JavaTM Debug Wire Protocol |
The JavaTM Debug Wire Protocol (JDWP) is the protocol used for communication between a debugger and the Java virtual machine (VM) which it debugs (hereafter called the target VM). The existence of JDWP can allow the same debugger to work
Future versions of JDWP may allow in-process debugging.
The JDWP differs from many protocol specifications in that it only details format and layout, not transport. A JDWP implementation can be designed to accept different transport mechanisms through a simple API. A particular transport does not necessarily support each of the three debugger/target VM combinations listed above.
The JDWP is designed to be simple enough for easy implementation, yet it is flexible enough for future growth.
The JDWP is primarily designed to facilitate efficient use by the JDI API; many of its abilities are tailored to that end.
A JDWP implementation spans the debugger and the target VM. Typically, the debugger side is written in Java and the target side is written in native code. The target side should be written in native code to avoid the deadlocks and intrusiveness that would be unavoidable in a Java Language implementation.
Currently, the JDWP does not specify any mechanism for transport rendezvous or any directory services. This may be changed in the future, but it may be addressed in a separate document.
The JDWP is packet based and is not stateful. There are two basic packet types: command packets and reply packets.
Command packets may be sent by either the debugger or the target VM. They are used by the debugger to request information from the target VM, or to control program execution. Command packets are sent by the target VM to notify the debugger of some event in the target VM such as a breakpoint or exception.
A reply packet is sent only in response to a command packet and always provides information success or failure of the command. Reply packets may also carry data requested in the command (for example, the value of a field or variable). Currently, events sent from the target VM do not require a response packet from the debugger.
The JDWP is asynchronous; multiple command packets may be sent before the first reply packet is received.
Command and reply packet headers are equal in size; this is to make transports easier to implement and abstract. The layout of each packet looks like this:
All fields and data sent via JDWP should be in big-endian format. (See the Java Virtual Machine Specification for the definition of big-endian.) The first three fields are identical in both packet types.
A simple monotonic counter should be adequate for most implementations. It will allow 2^32 unique outstanding packets and is the simplest implementation alternative.
0x80
The reply bit, when set, indicates that this packet is a reply.
The command set space is roughly divided as follows:
0 - 63
64 - 127
128 - 256
In general, the data field of a command or reply packet is an abstraction of a group of multiple fields that define the command or reply data. Each subfield of a data field is encoded in big endian (Java) format. The detailed composition of data fields for each command and its reply are described in this section.
There is a small set of common data types that are common to many of the different JDWP commands and replies. They are described below.
Name | Size | Description |
---|---|---|
byte
| 1 byte | A byte value. |
boolean
| 1 byte | A boolean value, encoded as 0 for false and non-zero for true. |
int
| 4 bytes | An four-byte integer value. The integer is signed unless explicitly stated to be unsigned. |
long
| 8 bytes | An eight-byte integer value. The value is signed unless explicitly stated to be unsigned. |
objectID
| Target VM-specific, up to 8 bytes (see below) | Uniquely identifies an object in the target VM. A particular
object will be identified by exactly one objectID in JDWP commands and
replies throughout its lifetime (or until the objectID is explicitly
disposed). An ObjectID is not reused to
identify a different object unless it has been explicitly
disposed,
regardless of whether the referenced object has been
garbage collected. An objectID of 0 represents a null object.
Note that the existence of an object ID does not prevent the garbage collection of the object. Any attempt to access a a garbage collected object with its object ID will result in the INVALID_OBJECT error code. Garbage collection can be disabled with the DisableCollection command, but it is not usually necessary to do so. |
tagged-objectID
| size of objectID plus one byte | The first byte is a signature byte which is used to identify the object's type. See JDWP.Tag for the possible values of this byte (note that only object tags, not primitive tags, may be used). It is followed immediately by the objectID itself. |
threadID
| same as objectID | Uniquely identifies an object in the target VM that is known to be a thread |
threadGroupID
| same as objectID | Uniquely identifies an object in the target VM that is known to be a thread group |
stringID
| same as objectID | Uniquely identifies an object in the target VM that is known to be a string object. Note: this is very different from string, which is a value. |
classLoaderID
| same as objectID | Uniquely identifies an object in the target VM that is known to be a class loader object |
classObjectID
| same as objectID | Uniquely identifies an object in the target VM that is known to be a class object. |
arrayID
| same as objectID | Uniquely identifies an object in the target VM that is known to be an array. |
referenceTypeID
| same as objectID | Uniquely identifies a reference type in the target VM.
It should not be assumed that for a particular class,
the classObjectID and the
referenceTypeID are the same.
A particular
reference type will be identified by exactly one ID in JDWP commands and
replies throughout its lifetime A referenceTypeID is not reused to
identify a different reference type,
regardless of whether the referenced class has been
unloaded.
|
classID
| same as referenceTypeID | Uniquely identifies a reference type in the target VM that is known to be a class type. |
interfaceID
| same as referenceTypeID | Uniquely identifies a reference type in the target VM that is known to be an interface type. |
arrayTypeID
| same as referenceTypeID | Uniquely identifies a reference type in the target VM that is known to be an array type. |
methodID
| Target VM-specific, up to 8 bytes (see below) | Uniquely identifies a method in some class in the target VM. The methodID must uniquely identify the method within its class/interface or any of its subclasses/subinterfaces/implementors. A methodID is not necessarily unique on its own; it is always paired with a referenceTypeID to uniquely identify one method. The referenceTypeID can identify either the declaring type of the method or a subtype. |
fieldID
| Target VM-specific, up to 8 bytes (see below) | Uniquely identifies a field in some class in the target VM. The methodID must uniquely identify the method within its class/interface or any of its subclasses/subinterfaces/implementors. A fieldID is not necessarily unique on its own; it is always paired with a referenceTypeID to uniquely identify one field. The referenceTypeID can identify either the declaring type of the field or a subtype. |
frameID
| Target VM-specific, up to 8 bytes (see below) | Uniquely identifies a frame in the target VM. The frameID must uniquely identify the frame within the entire VM (not only within a given thread). The frameID need only be valid during the time its thread is suspended. |
location
| Target VM specific | An executable location. The location is identified by
one byte
type tag followed by a
a classID followed by a methodID
followed by an unsigned eight-byte index,
which identifies the location within
the method.
Index values are restricted as follows:
The type tag is necessary to identify whether location's classID identifies a class or an interface. Almost all locations are within classes, but it is possible to have executable code in the static initializer of an interface. |
string
| Variable | A UTF-8 encoded string, not zero terminated, preceded by a four-byte integer length. |
value
| Variable | A value retrieved from the target VM. The first byte is a signature byte which is used to identify the type. See JDWP.Tag for the possible values of this byte. It is followed immediately by the value itself. This value can be an objectID (see Get ID Sizes) or a primitive value (1 to 8 bytes). More details about each value type can be found in the next table. |
untagged-value
| Variable | A value as described above without the signature byte. This form is
used when the signature information can be determined from
context.
|
arrayregion
| Variable | A compact representation of values used with some array operations.
The first byte is a signature byte which is used to identify
the type. See JDWP.Tag for the
possible values of this byte.
Next is a four-byte integer indicating the number of
values in the sequence. This is followed by the values themselves:
Primitive values are encoded as a sequence of
untagged-values ; Object values are encoded
as a sequence of values .
|
Object ids, reference type ids, field ids, method ids, and frame ids may be sized differently in different target VM implementations. Typically, their sizes correspond to size of the native identifiers used for these items in JNI and JVMDI calls. The maximum size of any of these types is 8 bytes. The "idSizes" command in the VirtualMachine command set is used by the debugger to determine the size of each of these types.
Copyright © 1999 Sun
Microsystems, Inc. All Rights Reserved.
Please send comments to: java-debugger@java.sun.com |