The Java 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). JDWP is optional; it might not be available in some implementations of the JDK. The existence of JDWP can allow the same debugger to work
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 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.
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.
JDWP is one layer within the Java Platform Debugger Architecture (JPDA). This architecture also contains the higher-level Java Debug Interface (JDI). The JDWP is designed to facilitate efficient use by the JDI; many of its abilities are tailored to that end. The JDI is more appropriate than JDWP for many debugger tools, particularly those written in the Java programming language. For more information on the Java Platform Debugger Architecture, see the Java Platform Debugger Architecture documentation for this release.
After the transport connection is established and before any packets are sent, a handshake occurs between the two sides of the connection:
The handshake process has the following steps:
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 fieldID must uniquely identify the field 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.
If a debuggee receives a Command Packet with a non-implemented or non-recognized command set or command then it returns a Reply Packet with the error code field set to NOT_IMPLEMENTED (see Error Constants).