|
| 1 | +--- |
| 2 | +layout: docs |
| 3 | +toc_group: debugging-and-diagnostics |
| 4 | +link_title: Java Debug Wire Protocol (JDWP) with Native Image |
| 5 | +permalink: /reference-manual/native-image/debugging-and-diagnostics/JDWP/ |
| 6 | +--- |
| 7 | + |
| 8 | +# Java Debug Wire Protocol (JDWP) with Native Image |
| 9 | + |
| 10 | +## Overview |
| 11 | + |
| 12 | +This document describes the Java Debug Wire Protocol (JDWP) debugging support for Native Image, a feature that enables debugging of native images using standard Java tooling. |
| 13 | + |
| 14 | +## Installation |
| 15 | + |
| 16 | +The JDWP feature is not included by default as part of Native Image. To use it, you need to [build GraalVM from source](https://github.com/oracle/graal/blob/master/vm/README.md) using the following [mx](https://github.com/graalvm/mx/) commands: |
| 17 | +```shell |
| 18 | +mx --dynamicimports /substratevm build |
| 19 | +export JAVA_HOME=$(mx --dynamicimports /substratevm graalvm-home) |
| 20 | +``` |
| 21 | + |
| 22 | +## Usage |
| 23 | + |
| 24 | +> Note: JDWP debugging for Native Image is currently under development. |
| 25 | +
|
| 26 | +To include JDWP support in a native image, add the `--macro:svmjdwp` option to your `native-image` command: |
| 27 | + |
| 28 | +```shell |
| 29 | +native-image --macro:svmjdwp ... -cp <class/path> YourApplication ... |
| 30 | +``` |
| 31 | + |
| 32 | +This command produces: |
| 33 | +1. The native executable |
| 34 | +2. An `<image-name>.metadata` file |
| 35 | +3. The `lib:svmjdwp` (`libsvmjdwp.so`, `libsvmjdwp.dylib` or `svmjdwp.dll`) shared library that will be necessary when debugging is also copied next to those files. |
| 36 | + |
| 37 | +### Launching in Debug Mode |
| 38 | + |
| 39 | +To launch the native image in debug mode, use the `-XX:JDWPOptions=` option, similar to HotSpot's `-agentlib:jdwp=`: |
| 40 | + |
| 41 | +```shell |
| 42 | +./your-application -XX:JDWPOptions=transport=dt_socket,server=y,address=8000 |
| 43 | +``` |
| 44 | + |
| 45 | +> Note: Debugging requires the _image-name.metadata_ file generated at build time and the `svmjdwp` shared library in the same directory as the native executable. |
| 46 | +
|
| 47 | +For a complete list of supported JDWP options on Native Image, run: |
| 48 | + |
| 49 | +```shell |
| 50 | +./your-application -XX:JDWPOptions=help |
| 51 | +``` |
| 52 | + |
| 53 | +### Additional JDWP Options |
| 54 | + |
| 55 | +Native Image supports additional non-standard JDWP options: |
| 56 | + |
| 57 | +- `mode=native:<path>`: Specifies the path to the `svmjdwp` library. This can be: |
| 58 | + - A direct path to `lib:svmjdwp` |
| 59 | + - A directory containing `lib:svmjdwp` |
| 60 | + - A GraalVM installation containing `lib:svmjdwp` in the `lib` or `bin` directory |
| 61 | + |
| 62 | + If no path is specified, `lib:svmjdwp` is searched for beside the native executable. |
| 63 | + |
| 64 | +Examples: |
| 65 | +- `-XX:JDWPOptions=...,mode=native:<path/to/lib:svmjdwp>` |
| 66 | +- `-XX:JDWPOptions=...,mode=native:<path/to/directory/containing/lib:svmjdwp>` |
| 67 | +- `-XX:JDWPOptions=...,mode=native:<path/to/java/home>`: Search `lib:svmjdwp` inside `JAVA_HOME`, for example `lib|bin/lib:svmjdwp`. |
| 68 | +- `-XX:JDWPOptions=...,mode=native`: Search `lib:svmjdwp` besides the native executable directory. |
| 69 | + |
| 70 | +- `-XX:JDWPOptions=...,vm.options=...`: VM options, separated by whitespaces, passed to the JDWP server isolate/JVM, should not include a `,` character. |
| 71 | +- `-XX:JDWPOptions=...,vm.options=@argfile`: Also supports [Java Command-Line Argument Files](https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html#java-command-line-argument-files). |
| 72 | + |
| 73 | +Note: If `lib:svmjdwp` cannot be found, the application will terminate with error code 1. |
| 74 | + |
| 75 | +### Build `lib:svmjdwp` |
| 76 | + |
| 77 | +Run `mx --native-images=lib:svmjdwp build` to build the library. |
| 78 | + |
| 79 | +### Build a Native Executable with JDWP Support |
| 80 | + |
| 81 | +Add the `--macro:svmjdwp` option to the `native-image` command: |
| 82 | +```shell |
| 83 | +mx native-image --macro:svmjdwp -cp <class/path> MainClass ... |
| 84 | +``` |
| 85 | + |
| 86 | +To build and include `lib:svmjdwp` as a build artifact, run: |
| 87 | +```shell |
| 88 | +mx --native-images=lib:svmjdwp native-image --macro:svmjdwp -cp <class/path> MainClass ... |
| 89 | +``` |
| 90 | + |
| 91 | +Both commands produce a binary, an `<image-name>.metadata` file. |
| 92 | + |
| 93 | +## Goals and Constraints |
| 94 | + |
| 95 | +The JDWP debugging support for Native Image aims to: |
| 96 | + |
| 97 | +1. Expose Native Image through JDWP as-is, maintaining its assumptions and constraints |
| 98 | +2. Incur minimal or no performance overhead when not in use |
| 99 | +3. Add minimal size overhead to the native binary |
| 100 | +4. Be available on all Graal-supported platforms, including Linux, macOS, and Windows, across x64 and AArch64 architectures |
| 101 | +5. Provide a debugging experience similar to HotSpot, without requiring additional steps (e.g., setting permissions, environment variables) |
| 102 | + |
| 103 | +## Architecture |
| 104 | + |
| 105 | +The JDWP debugging support is implemented using a Java bytecode interpreter, adapted from [Espresso](https://github.com/oracle/graal/tree/master/espresso) to work with Native Image. Key components include: |
| 106 | + |
| 107 | +1. **Interpreter**: Derived from Espresso and adapted for [SubstrateVM](https://github.com/oracle/graal/tree/master/substratevm/). It does not enable any dynamic features beyond what Native Image already supports. |
| 108 | + |
| 109 | +2. **PLT/GOT Feature**: Used to divert execution to the interpreter. This implementation detail may change for some platforms. |
| 110 | + |
| 111 | +3. **Metadata File**: An external _.metadata_ file produced at build time, containing information required for runtime method interpretation. |
| 112 | + |
| 113 | +4. **JDWP Server**: Implemented as a native library (`lib:svmjdwp`), handling network connections and implementing JDWP commands. |
| 114 | + |
| 115 | +5. **JDWP Resident**: A component within the application providing access to locals, fields, stack traces, and other runtime information. |
| 116 | + |
| 117 | +## Limitations |
| 118 | + |
| 119 | +The JDWP debugger for Native Image is designed to align with Native Image's architecture and principles. |
| 120 | +While many limitations are a natural consequence of Native Image's design, others may be due to the current implementation of the debugger itself. |
| 121 | +Here are the key limitations to be aware of: |
| 122 | + |
| 123 | +- The debugger follows Native Image closed-world assumptions: |
| 124 | + - Only classes, methods, and fields included in the image are accessible. |
| 125 | + - Some types may not be instantiable at runtime, even if there are instances in the image heap. |
| 126 | + - Some fields cannot be written to. |
| 127 | + - No support for dynamic class loading. |
| 128 | + - No class or method redefinition. |
| 129 | + - There's no runtime class-path `System.getProperty("java.class.path") == null` |
| 130 | +- No exception breakpoints. |
| 131 | +- No field watchpoints. |
| 132 | +- No early return or frame popping. |
| 133 | +- Some methods cannot be interpreted by the debugger (see below): |
| 134 | + - Methods that use "System Java". |
| 135 | + - Methods that contain a call to an intrinsic without compiled entry-point. |
| 136 | + - Breakpoints cannot be set in non-interpretable methods. |
| 137 | + - Stepping through non-interpretable methods is not possible, these are effectively treated as if they were Java "native" methods, with no guarantee to break/step on the next executed method, only on the next interpreted method. |
| 138 | +- Not all execution paths are executable/interpretable. |
| 139 | + - Interpreting "dead-code" may work, but only on a best-effort basis. |
| 140 | + - Violating compiled-code assumptions, for example, passing a null argument where a non-null was expected, is considered undefined behavior and prone to crashes. |
| 141 | +- Cannot write locals of compiled frames. |
| 142 | +- Cannot hit breakpoints or stepping events on actively executing compiled methods. |
| 143 | +- Step-out operations only work for interpreter frames, not compiled frames. |
| 144 | +- Can only debug the first isolate of a native image. |
| 145 | +- Step-into does not work for target methods of a `MethodHandle` object, for example, lambdas. |
| 146 | + |
| 147 | +These limitations reflect the current state of JDWP debugging support in Native Image. |
| 148 | +Some may be addressed in future iterations of the debugger, while others are fundamental to Native Image's design. |
| 149 | + |
| 150 | +### Further Reading |
| 151 | + |
| 152 | +- Instructions on how to run the JDWP server in HotSpot, so that the debugger can be debugged: [JDWP server](https://github.com/oracle/graal/tree/master/substratevm/src/com.oracle.svm.jdwp.server/README.md) |
| 153 | +- Implementation details about the interpreter and the transitions from and to compiled code: [SubstrateVM Interpreter](https://github.com/oracle/graal/tree/master/substratevm/src/com.oracle.svm.interpreter/README.md) |
0 commit comments