Documentation Contents

# Java Debug Wire Protocol Transport Interface (jdwpTransport)

A transport is implemented as a series of functions in a dynamic library (sometimes called a DLL, or shared library). The library exports an onload function that is invoked by the JDWP (or other) agent at startup-time.

Like JVMTI, jdwpTransport functions are accessed through an interface pointer called the environment pointer. An environment pointer is a pointer to an environment and has type `jdwpTransportEnv*`. The environment pointer is returned to the JDWP (or other) agent from the onload function.

A transport may support a single environment or it may support multiple environments. In other words, a transport may be used by only one, or multiple agents at the same time. If a transport supports multiple environments then each call to the onload function will return a new environment pointer. If a transport only supports a single environment then second, and subsequent calls to the onload function will return an error.

A transport is thread-safe and jdwpTransport functions can be used by multiple concurrent threads. For example, one thread may be blocked in the jdwpTransport `ReadPacket` function waiting for a packet while another thread invokes `WritePacket` function to write a packet.

In most cases jdwpTransport functions return a `jdwpTransportError` value indicating return status. Some functions return additional values through pointers provided by the calling function. In cases where the return values are allocated by a jdwpTransport function then the function will use the memory allocation routine specified by the agent. The memory allocation routines are specified to the transport, at start-up, via the onload function.

In the event of an error (that is, one of the jdwpTransport functions returns a value other than `JDWPTRANSPORT_ERROR_NONE`) then a string representing the error can be subsequently obtained through a call to the jdwpTransport function `GetLastError`. Errors are recorded on a per-thread basis. The `GetLastError` function will return a string represetning the last error that was encountered by the current thread only.

## Developing a Transport implementation

A transport library can be developed in any native language that supports C language calling conventions and C or C++ definitions.

The function, data type, and constant definitions needed for using the jdwpTransport interface are defined in the include file jdwpTransport.h. To use these definitions add the Java SE include directory to your include path :-

    #include "jdwpTransport.h"

## Transport Start-Up

The transport library must export an onload function with the following prototype :-

    JNIEXPORT jint JNICALL
    jdwpTransport_OnLoad(JavaVM *jvm,
                         jdwpTransportCallback *callback,
                         jint version,
                         jdwpTransportEnv** env);

This function will be called by the JDWP (or other agent) when the library is loaded.

The `jvm` argument is the JNI invocation interface obtained by agent by invoking JNI's `GetJavaVM` function.

The `callback` argument is a pointer to a function table of memory management routines that the transport must use to allocate the memory for return values that are allocated by the transport implementation :-

    typedef struct jdwpTransportCallback {
        void* (*alloc)(jint numBytes);
        void (*free)(void *buffer);
    } jdwpTransportCallback;

The lifespan of the `callback` argument is the onload function and therefore the transport must take a copy of the function table in the `jdwpTransport_OnLoad` function.

The function table has two entries. The `alloc` function allocates an area of memory. It has a single argument to specify the number of bytes to allocate. It returns a pointer to the begining of the allocated memory, or NULL if the memory request cannot be honored. If the number of bytes requested is zero then NULL is returned. The `free` function deallocates an area of memory that was previously allocated using the `alloc` function.

The memory management functions provided by the agent are thread safe and the transport implementation is not required to synchronize calls to the these functions. The implementation of the memory management functions are guaranteed not to call any jdwpTransport function.

`version` is the version of the transport interface that the agent expects. This must be specified as `JDWPTRANSPORT_VERSION_1_0`.

`env` is a pointer to the environment pointer returned by the function.

The `jdwpTransport_OnLoad` function returns `JNI_OK` if the transport initializes successfully. If initialization fails then one of the following errors is returned :

    JNI_ENOMEM
    JNI_EVERSION
    JNI_EEXIST

`JNI_ENOMEM` is returned if there is insufficient memory to complete initialization.

`JNI_EVERSION` is returned if the version in the `version` argument is not `JDWPTRANSPORT_VERSION_1_0`.

`JNI_EEXIST` is returned if the transport only supports a single environment, and the environment pointer was previously returned by the first call to the onload function.

## Functions

The jdwpTransport functions fall into these categories:

- Connection Management
  - Attach
  - StartListening
  - StopListening
  - Accept
  - IsOpen
  - Close
- I/O Functions
  - ReadPacket
  - WritePacket
- Miscellaneous Functions
  - GetLastError
  - Get Capabilities

## Connection Management

The connection management functions are used to establish and close the connection to the debugger. A connection provides a reliable flow of JDWP packets to and from the debugger. Packets written to a connection are read, by the debugger, in exactly the order in which they were written. Similarly, any packets written to the connection by the debugger are read in the order in which they were written.

Connections are established either actively or passively. Establishing the connection actively means that the jdwpTransport's `Attach` function is called to initiate the connection the debugger. Establishing the connection passively means that the jdwpTransport's `StartListening` function is used to put the transport into listen mode so that it listens for a connection from a debugger. Once in listen mode the `Accept` function is used to accept the connection. Irrespective of how the connection is established the `Close` function is used to close the connection, and `IsOpen` is used to test if a connection is open to the debugger.

### Attach

    jdwpTransportError
    Attach(jdwpTransportEnv* env, const char* address,
           jlong attachTimeout, jlong handshakeTimeout)

Attaches to the debugger. Attaching to the debugger involves two steps. First, a connection is established to the specified `address`. Once a connection is established a handshake is performed to ensure that the connection is indeed established to a debugger. Handshaking involves the exchange of ASCII string JDWP-Handshake as specified in the Java Debug Wire Protocol specification.

The `address` argument is a pointer to a string representing the address of the debugger. The exact format is specific to the transport (In the case of a TCP/IP based transport the address may include the hostname and port number of the debugger. In the case of a transport that supports connections through a serial port it might be the device name of the serial port).

The `attachTimeout` argument specifies a timeout to use when attaching. If the transport supports an attach timeout (see GetCapabilities) and if the `attachTimeout` is positive then it specifies the timeout, in milliseconds (more or less), to use when attaching to the debugger. If the transport does not support an attach timeout, or if `attachTimeout` is specified as zero then a timeout is not used when attaching.

The `handshakeTimeout` argument specifies a timeout to use when handshaking with the debugger. If the transport supports a handshake timeout (see GetCapabilities) and if the `handshakeTimeout` is positive then it specifies the timeout, in milliseconds (more or less), to use when handshaking with the debugger. The exact usage of the handshake timeout is specific to the transport - for example one implementation may use the timeout as an inter-character timeout while waiting for the JDWP-Handshake message from the debugger. Another implementation may use the timeout to indicate the total duration allowed for the handshake exchange. In general the purpose of the handshake timeout is to allow for error handling in the event that the transport connects to something other than a valid debugger. If the transport does not support a handshake timeout, or if the `handshakeTimeout` is specified as zero then a timeout is not used when handshaking.

This function returns a universal error or one of the following errors:

    JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT
    JDWPTRANSPORT_ERROR_ILLEGAL_STATE
    JDWPTRANSPORT_ERROR_IO_ERROR
    JDWPTRANSPORT_ERROR_TIMEOUT

`JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT` is returned if `address` is invalid or `timeout` is negative.

`JDWPTRANSPORT_ERROR_ILLEGAL_STATE` is returned if the transport is currently in listen mode (see StartListening), or there is already an open connection to the debugger (see IsOpen).

`JDWPTRANSPORT_ERROR_IO_ERROR` is returned if there is an error (other than an attach timeout) attaching to the debugger. Note that errors during the start-up handshake (including a handshake timeout) are considered I/O errors. I/O errors are specific to the transport. GetLastError can be used to obtain a string representation of the error.

`JDWPTRANSPORT_ERROR_TIMEOUT` is returned if the transport supports an attach timeout, and if the `attachTimeout` value is positive, and if the connection to the debugger cannot be established within that attachTimeout period.

### StartListening

    jdwpTransportError
    StartListening(jdwpTransportEnv* env, const char* address, char** actualAddress);

Puts the transport into listen mode to listen for a connection from a debugger.

The `address` argument is a pointer to a string representing the local address that the transport should listen on. The exact format is specific to the transport (In the case of a TCP/IP based transport the address might a local TCP port number. In the case of a transport that supports connections through a serial port it might be the device name of a serial port). The `address` argument can be specified as `NULL` or as an empty string (first character is `\0`). In that case the transport listens on a default address that is specific to the transport.

If `actualAddress` is not `NULL` then it is set to the address of a string returned by the `StartListening` function. The returned string will contain the string representation of the address that the transport is listening on. This may, or may not, differ from the address provided in the `address` argument. The string is allocated using the allocation callback provided to the transport when the `jdwpTransport_OnLoad` function was called. The caller is responsible for freeing the returned string.

This function returns a universal error or one of the following errors:

    JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT
    JDWPTRANSPORT_ERROR_ILLEGAL_STATE
    JDWPTRANSPORT_ERROR_IO_ERROR

`JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT` is returned if `address` is invalid.

`JDWPTRANSPORT_ERROR_ILLEGAL_STATE` is returned if there is already an open connection to a debugger (see IsOpen), or the transport is already in listen mode.

`JDWPTRANSPORT_ERROR_IO_ERROR` is returned if there is an error putting the transport into listen mode. The nature of the error is specific to the transport. GetLastError can be used to obtain a string representing the error.

### StopListening

    jdwpTransportError
    StopListening(jdwpTransportEnv* env)

Takes the transport out of listen mode so that it's no longer listening for connections from a debugger.

If the transport is in listen mode then it will be taken out of this mode. If there is an open (see IsOpen) connection to a debugger then it is unaffected by this function. In other words, `StopListening` does not close a connection to the debugger. If the transport is not in listen mode then this function does nothing and no error is returned.

This function returns a universal error or one of the following errors:

    JDWPTRANSPORT_ERROR_IO_ERROR

`JDWPTRANSPORT_ERROR_IO_ERROR` is returned if there is an error taking the transport out of listen mode. The nature of the error is specific to the transport. GetLastError can be used to obtain a string representing the error.

### Accept

    jdwpTransportError
    Accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout)

Accepts a connection from a debugger. Accepting a connection from a debugger involves two steps. Firstly, a connection is established by the debugger. Once a connection is established a handshake is performed to ensure that the connection was indeed established by a debugger. Handshaking involves the exchange of ASCII string JDWP-Handshake as specified in the Java Debug Wire Protocol specification.

The `acceptTimeout` argument specifies the timeout to use while waiting for the debugger to connect. If the transport supports an accept timeout (see GetCapabilities) and if the `acceptTimeout` is positive then it specifies the timeout, in milliseconds (more or less), to use when waiting for a connection from a debugger. If the transport does not support an accept timeout, or if `timeout` is specified as zero then block indefinitely waiting for a connection.

The `handshakeTimeout` argument specifies a timeout to use when handshaking with the debugger. If the transport supports a handshake timeout (see GetCapabilities) and if the `handshakeTimeout` is positive then it specifies the timeout, in milliseconds (more or less), to use when handshaking with the debugger. The exact usage of the handshake timeout is specific to the transport - for example one implementation may use the timeout as an inter-character timeout while waiting for the JDWP-Handshake message from the debugger. Another implementation may use the timeout to indicate the total duration allowed for the handshake exchange. In general the purpose of the handshake timeout is to allow for error handling in the event that something other than a debugger establishes a connection to the debuggee. If the transport does not support a handshake timeout, or if the `handshakeTimeout` is specified as zero then a timeout is not used when handshaking.

This function returns a universal error or one of the following errors:

    JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT
    JDWPTRANSPORT_ERROR_ILLEGAL_STATE
    JDWPTRANSPORT_ERROR_IO_ERROR
    JDWPTRANSPORT_ERROR_TIMEOUT

`JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT` is returned if `attachTimeout` or `handshakeTimeout` is negative.

`JDWPTRANSPORT_ERROR_ILLEGAL_STATE` is returned if there is already an open connection to a debugger (see IsOpen), or if the transport is not in listen mode (see StartListening).

`JDWPTRANSPORT_ERROR_IO_ERROR` is returned if there is an error (other than an accept timeout) while accepting a connection from a debugger. Note that errors during the start-up handshake (including a handshake timeout) are considered I/O errors. The nature of the error is specific to the transport. GetLastError can be used to obtain a string representing the error.

`JDWPTRANSPORT_ERROR_TIMEOUT` is returned if the transport supports an accept timeout, and if the `acceptTimeout` value is positive, and if the connection to the debugger cannot be established within that timeout period.

Note: A thread that is blocked in `Accept` waiting for a connection from a debugger can be interrupted by another thread calling `StopListening`. In that case the thread that called `Accept` will return `JDWPTRANSPORT_ERROR_IO_ERROR` indicating an I/O error has occurred. If a thread blocked in `Accept` has accepted a connection and is in the process of handshaking with the debugger then `StopListening` will not interrupt the connection.

### IsOpen

    jboolean
    isOpen(jdwpTransportEnv* env)

Tells whether or not there is a connection open to a debugger.

Returns `JNI_TRUE` if, and only if, there is an open connection to a debugger. Otherwise it returns `JNI_FALSE`.

### Close

    jdwpTransportError
    Close(jdwpTransportEnv* env)

Closes an open connection to a debugger.

If there isn't an open connection to a debugger (see IsOpen) then this function does nothing and no error is returned.

If there are threads blocked in any I/O functions (namely, ReadPacket and WritePacket), then these I/O functions will be interrupted by the close and will return an `JDWPTRANSPORT_ERROR_IO_ERROR` indicating an I/O error has occurred.

This function returns a universal error or one of the following errors:

    JDWPTRANSPORT_ERROR_IO_ERROR

`JDWPTRANSPORT_ERROR_IO_ERROR` is returned if there is an error closing the connection. The nature of the error is specific to the transport. GetLastError can be used to obtain a string representing the error.

## I/O Functions

The I/O functions are used for reading and writing JDWP packets from and to the debugger.

### ReadPacket

    typedef struct {
        jint len;
        jint id;
        jbyte flags;
        jbyte cmdSet;
        jbyte cmd;
        jbyte *data;
    } jdwpCmdPacket;

    typedef struct {
        jint len;
        jint id;
        jbyte flags;
        jshort errorCode;
        jbyte *data;
    } jdwpReplyPacket;

    typedef struct jdwpPacket {
        union {
            jdwpCmdPacket cmd;
            jdwpReplyPacket reply;
        } type;
    } jdwpPacket;

    jdwpTransportError
    ReadPacket(jdwpTransportEnv* env, jdwpPacket* packet)

Reads a JDWP packet from an open connection to a debugger.

This function does a blocking read on an open connection. It blocks indefinitely until a complete JDWP packet can be returned, or in the case of a transport based on a stream-oriented protocol, end-of-stream is encountered.

The `packet` argument is the address of a `jdwpPacket` structure that is populated by this function. The `packet.type.cmd.len` or `packet.type.reply.len` field (depending on if the packet is a command or reply packet) is populated with the length of the packet. If end of stream is encountered the length field will be set to `0` and all other fields in the packet will be undefined. If end of stream is encountered after reading some, but not all, bytes of a packet it is considered an I/O error and `JDWPTRANSPORT_ERROR_IO_ERROR` will be returned. In that case the length field will not be populated. When an entire packet is read then all fields in the packet are populated with values in host order. This may, or may not, differ from the big endian order require when transmitting JDWP packets.

The `packet.type.cmd.data` or `packet.type.reply.data` field (depending on if the packet is a command or reply packet) will be populated with `NULL` or a pointer to the packet data allocated by this function. Packet data is allocated using the allocation callback provided to the transport when the `jdwpTransport_OnLoad` function was called. The caller is responsible to free it. The layout of the packet data (that is the data following the header, if any) is returned to the caller in the byte ordering in which it was received.

The `ReadPacket` function does not do any integrity checking on the returned packet except checking that the length of the packet (as indicated by the first 4 bytes) is `>=` 11 bytes. If the `length` field is less than 11 bytes then `JDWPTRANSPORT_ERROR_IO_ERROR` is returned.

This function returns a universal error or one of the following errors:

    JDWPTRANSPORT_ERROR_IO_ERROR
    JDWPTRANSPORT_ERROR_ILLEGAL_STATE
    JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT

`JDWPTRANSPORT_ERROR_IO_ERROR` is returned if an I/O error occurs when reading, the connection is closed asynchronously by another thread calling the Close function, or a badly formed packet (`length` field less than 11 bytes) is received. I/O errors are specific to the transport. GetLastError can be used to obtain a string representing the error.

`JDWPTRANSPORT_ERROR_ILLEGAL_STATE` is returned if there isn't an open connection to a debugger (see IsOpen).

`JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT` is returned if `packet` is `NULL`

### WritePacket

    jdwpTransportError
    WritePacket(jdwpTransportEnv* env, const jdwpPacket* packet)

Writes a JDWP packet to an open connection.

The `packet` argument is a pointer to a `jdwpPacket` structure. All fields in the packet header must be stored in host order. The packet data field (`packet.type.cmd.data` or `packet.type.reply.data`) must be `NULL`, or a pointer to a location containing packet data that immediately follows the header. The packet data is must be in network order (big endian) ready for transmission.

This function returns a universal error or one of the following errors:

    JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT
    JDWPTRANSPORT_ERROR_IO_ERROR
    JDWPTRANSPORT_ERROR_ILLEGAL_STATE

`JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT` if `packet` is `NULL`, or if the packet length field (`packet.type.cmd.len` or `packet.type.reply.len`) is less than 11, or it is greater than 11 but the packet data field (`packet.type.cmd.data` or `packet.type.reply.data`) is `NULL`.

`JDWPTRANSPORT_ERROR_IO_ERROR` is returned if an I/O error occurs when writing, or the connection is closed asynchronously by another thread calling the Close function. I/O errors are specific to the transport. GetLastError can be used to obtain a string representing the error.

`JDWPTRANSPORT_ERROR_ILLEGAL_STATE` is returned if there isn't an open connection to a debugger (see IsOpen).

## Miscellaneous Functions

### GetLastError

    jdwpTransportError
    GetLastError(jdwpTransportEnv* env, char** msg);

Returns the string representation of the last error.

When an error occurs it is recorded on a per-thread basis. A subsequent call to `GetLastError` returns the string representation of the last I/O error.

The `msg` argument is a pointer to a null-terminated string returned by this function. The string is allocated using the allocation callback provided to the transport when the `jdwpTransport_OnLoad` function was called. The caller is responsible to free the returned string.

This function returns a universal error or one of the following errors:

    JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE

`JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE` is returned if this thread has not encountered an I/O error or there isn't a string representation of the last error available.

### GetCapabilities

    typedef struct {
        unsigned int can_timeout_attach     :1;
        unsigned int can_timeout_accept     :1;
        unsigned int can_timeout_handshake  :1;
        unsigned int reserved3              :1;
        unsigned int reserved4              :1;
        unsigned int reserved5              :1;
        unsigned int reserved6              :1;
        unsigned int reserved7              :1;
        unsigned int reserved8              :1;
        unsigned int reserved9              :1;
        unsigned int reserved10             :1;
        unsigned int reserved11             :1;
        unsigned int reserved12             :1;
        unsigned int reserved13             :1;
        unsigned int reserved14             :1;
        unsigned int reserved15             :1;
    } JDWPTransportCapabilities;

    jdwpTransportError
    GetCapabilities(jdwpTransportEnv* env, JDWPTransportCapabilities* capabilitiesPtr)

Returns via `capabilitiesPtr` the optional jdwpTransport features supported by this transport. The capabilities structure contains a number of boolean flags indicating whether the named feature is supported. The current set of flags is:

Boolean Flag | Meaning
--- | ---
`can_timeout_attach` | Indicates if the transport supports attaching with a timeout
`can_timeout_accept` | Indicates if the transport supports an accept timeout
`can_timeout_handshake` | Indicates if the transport supports a timeout when performing the initial handshake with the debugger when the connection is established

This function does not return any errors.

### Universal Errors

Error | Meaning
--- | ---
`JDWPTRANSPORT_ERROR_NONE` | No error has occurred. This is the error code that is returned on successful completion of the function.
`JDWPTRANSPORT_ERROR_OUT_OF_MEMORY` | The function needed to allocate memory and no more memory was available for allocation.
`JDWPTRANSPORT_ERROR_INTERNAL` | An unexpected internal error has occurred.

Copyright © 1993, 2015, Oracle and/or its affiliates. All rights reserved.
Contact Us