DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Five Java Developer Must-Haves for Ultra-Fast Startup Solutions
  • Java Module Benefits With Example
  • JVM Memory Architecture and GC Algorithm Basics
  • How to Configure, Customize, and Use Ballerina Logs

Trending

  • A Guide to Container Runtimes
  • Contextual AI Integration for Agile Product Teams
  • How to Format Articles for DZone
  • Unlocking Data with Language: Real-World Applications of Text-to-SQL Interfaces
  1. DZone
  2. Coding
  3. Java
  4. Remote Debugging Java Applications With JDWP

Remote Debugging Java Applications With JDWP

Take a look at this simple breakdown of how to use the JDWP to debug Java applications.

By 
Mahmoud Anouti user avatar
Mahmoud Anouti
·
Jul. 16, 19 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
29.8K Views

Join the DZone community and get the full member experience.

Join For Free

Most Java developers have had to debug their applications, usually to find and fix an issue there. In many cases, the application to debug (known as the “debuggee”) is launched from within the IDE used by the developer, while the debugger is also integrated into the IDE, allowing easy inspection of the program state in a step-by-step manner. Sometimes, however, the debuggee JVM is launched from a separate command line, or by executing it on a separate host. In such scenarios, debugging necessitates launching the JVM with some options suitable for debugging, while your IDE debugger would have to connect to it. This is where JDWP (Java Debug Wire Protocol) comes into play.

What is JDWP?

In order to debug remotely executed JVMs (where the debuggee is separately launched locally or on another machine), the Java platform defines a protocol for communication between the JVM and the debugger. JDWP dictates the format of the commands sent by the debugger (e.g. to evaluate a local variable), and replies by the JVM. The exact way of transporting the packets is not specified and is up to the implementation to define transport mechanisms. What JDWP specifies is the format and layout of packets containing commands and those containing replies. Therefore it is conceptually very simple.

JDWP is only one part of the debugging infrastructure in the Java platform. The endpoints (debugger and debuggee) communicating over JDWP implement other specifications to provide the actual debugging functionality. The JVM implements the JVM Tool Interface (JVMTI) to provide debugging functionality for it, for example, to control executions using breakpoints or inspecting the current object. JVMTI is the low-level layer implemented natively in the JVM. The debugger implements another interface called the Java Debug Interface (JDI) that provides a high-level way to carry debugging requests from the debugger process. JDI is a pure Java interface. Together, JVMTI, JDWP, and JDI form the main layers of the Java Platform Debugger Architecture. Links to official references about all these specifications are provided at the end.

In the Oracle Java implementation, there are two transport mechanisms provided: the socket transport, and the shared memory transport for Windows only. The socket transport (dt_socket) relies on TCP sockets bound to listen on a port for connections, and using that connection to transfer the debug session packets. Shared memory transport (dt_shmem) uses shared memory to send and receive packets. The main difference is that socket transport allows debugging a target JVM application running on a remote machine, while shared memory allows only debugging locally running applications. For the examples that follow, we’ll focus only on socket transport.

Debugging Remotely Using JDWP

The way a debugger connects to a target JVM is by having one act as the server listening for an incoming connection, and the other attaching to the server. The server endpoint could be either the JVM or the debugger. This applies to both socket transport and shared memory transport. Therefore, there are two steps to perform in order to remotely debug a target app:

  1. Launch either the JVM or the debugger in server mode, so that it listens at a certain address, namely an assigned IP address and port number.
  2. Attach the other part to the listening server on that address.

For example, to launch the JVM with debug options to listen on an address, we use the following option with the Java executable:

java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000  ... MainClass


The -agentlib:jdwp with the comma-separated key-value suboptions instruct the JVM to load the JDWP agent and wait for a socket connection on port 8000. Here’s what each suboption does:

  • transport=dt_socket tells the JDWP agent to use socket transport.
  • server=y means that the JVM will listen for a debugger to attach to it.
  • suspend=y means the JVM will wait for the debugger to attach before executing the main class. This is also the default value. If set to n, the JVM will immediately execute the main class, while listening for the debugger connection.
  • address=8000 specifies the address at which the debug socket will listen. In this case, the JVM will listen at port 8000 for incoming connections only from the local host (starting JDK 9).

The second step is to attach the debugger at that address. All popular IDEs provide a way to easily do this. In Eclipse, for example, it can be configured by going to Run -> Debug Configuration and creating a Remote Java Application configuration:

2019-07-07_17_22_26-Eclipse_remote_debug_attach

Notice that the host and port must match the address of the JDWP agent on JVM side.

[JDK 9+] Binding the Listening Socket to All Addresses

In the previous example, the address was set to 8000 (port number) without any hostname or IP address. Before JDK 9, this would mean the JVM would listen on all available IP addresses, making the socket accessible by debuggers on remote machines. Starting with JDK 9, this was changed to only allow local connections for better security. In other words, -agentlib:jdwp=transport=dt_socket,server=y,address=8000 is now equivalent to -agentlib:jdwp=transport=dt_socket,server=y,address=localhost:8000.

To bind the socket to addresses allowing remote connections, either prefix the port with the host name, IP address, or an asterisk (*) to bind to all available IP addresses:

-agentlib:jdwp=transport=dt_socket,server=y,address=host1:8000

or

-agentlib:jdwp=transport=dt_socket,server=y,address=*:8000

More Examples

Adding a Timeout

We can add a timeout for the JDWP agent listening for the debugger. To make the JVM exit after 10 seconds without any debugger attaching:

-agentlib:jdwp=transport=dt_socket,server=y,address=*:8000,timeout=10000

Listening at A Dynamic Port

If server=y (i.e. JVM is listening for connection), we can skip the address option, which will make it use a dynamically assigned port. Since no address was specified, this allows only local connections. The chosen port will be displayed at stdout of the JVM, e.g.:

Listening for transport dt_socket at address: 12345

The Other Way Around: Attaching to A Debugger

We can set server=n on the JVM command line option (or just remove the server option as it defaults to n), and tell it to attach to a debugger at a certain address. We would first run the debugger in listening mode:

2019-07-07_17_22_26-Eclipse_remote_debug_listen


Let’s say the debugger was started on host2. We would then run the JVM with the option:

-agentlib:jdwp=transport=dt_socket,address=host2:8000

Delaying JDWP Connection Establishment until A Specific Exception Is Thrown

A useful option to the JDWP agent is to start the JVM as normal and wait until a specific exception is thrown. For example, say you want to debug a failing application with a MyCustomException but don’t want to initiate the debugger connection until it is thrown. This can be done with the onthrow option:

-agentlib:jdwp=transport=dt_socket,server=y,address=*:8000,onthrow=com.example.MyCustomException,launch=notify_script

This would start the application normally without listening on the address. When the exception is thrown, the agent will listen on port 8000 and a debugger can be attached to it. Thelaunch option is a mandatory option along with onthrow used to start a certain process when the exception is thrown. The process will be given the transport and port number as arguments. It can be used, for example, to automatically launch the debugger to attach to the listening VM upon the exception being thrown.

References

  • Java Platform Debugger Architecture

  • JDWP spec

  • JPDA Connection and Invocation Details

  • [JDK 9 Release Notes] JDWP socket connector accept only local connections by default


Java (programming language) application Java virtual machine remote Shared memory Connection (dance) Debug (command)

Published at DZone with permission of Mahmoud Anouti, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Five Java Developer Must-Haves for Ultra-Fast Startup Solutions
  • Java Module Benefits With Example
  • JVM Memory Architecture and GC Algorithm Basics
  • How to Configure, Customize, and Use Ballerina Logs

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!