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.
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"
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.
The jdwpTransport functions fall into these categories:
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.
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.
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.
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.
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.
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
.
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.
The I/O functions are used for reading and writing JDWP packets from and to the debugger.
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
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).
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.
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.
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, 2017, Oracle and/or its affiliates. All rights reserved.