On Fri, 1 May 2026 15:37:12 GMT, Kevin Walls <[email protected]> wrote:

> This implements "jcmd on core files" for Linux, and for MiniDumps on Windows 
> (MacOS is "future work").
> jcmd "revives" the VM memory and .so/.dll from the core/minidump, and runs 
> the existing native diagnostic command parser and command implementations.
> 
> ---------
> - [x] I confirm that I make this contribution in accordance with the [OpenJDK 
> Interim AI Policy](https://openjdk.org/legal/ai).

Summary:
-----
Revive memory from a core file, and load the JVM library, to create a duplicate 
of what was in memory when the core was created.
This will likely conflict with the running jcmd JVM process, so it is done in a 
new helper process.
The helper calls a new method in the JVM to reset some VM state, then jumps to 
the existing jcmd (diagnostic command) parser.
The native diagnostic commands run almost as if nothing has happened.  A few 
places in the VM check if we are revived.

The test test/hotspot/jtreg/serviceability/revival/JCmdRevival.java crashes in 
a few different ways, and runs the jcmds on the core/minidump ( make images 
test TEST=test/hotspot/jtreg/serviceability/revival ).
Tests could in time be more integrated with other jcmd testing, but for now 
this separate test is less disruptive.

More detail:
-----
jcmd: src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java
Uses attach API, and on a core file we call into: 
src/jdk.attach/share/classes/sun/tools/attach/VirtualMachineCoreDumpImpl.java
This launches the "revivalhelper" process: 
src/jdk.attach/share/native/revivalhelper/revivalhelper.cpp
...which calls revive_image() and revival_dcmd() defined in 
src/jdk.attach/share/native/revivalhelper/revival.cpp

revive_image() does some pre-work:
The JVM .so/.dll needs to be relocated (rebased) to load at the same address as 
that in the core file.
Linux does that relocation in elffile.cpp, on Windows it uses a Windows API 
(see pefile.cpp).
Relocation means changing the actual file, so a copy is made.

A directory core.revival is created for this copy, and serves as a cache to 
hold a few other files to speed up subsequent runs.
One file lists the memory mappings from the dump that will be mapped into the 
helper process.  Another file lists a few symbols.

That cache creation/analysis phase is somewhat separate to give some 
flexibility: if the analysis required more memory usage or libraries to load 
that cause more memory conflicts, it could be run in a separate process.  This 
does not appear necessary at the moment on these platforms.

There are platform-dependent native implementation parts in 
src/jdk.attach/linux/native/revivalhelper/revival_linux.cpp and 
src/jdk.attach/windows/native/revivalhelper/revival_windows.cpp

Mapping memory in revivalhelper can fail due to a conflict.  This is not 
generally very common, but the helper will exit and jcmd will retry.  Address 
space layout randomization both causes and fixes these clashes.

revivalhelper cooperates with the VM - you need to crash a VM with this change 
to use jcmd on a core file.  The cooperation in the VM is in the 
Thread::process_revival() method (open/src/hotspot/share/runtime/thread.cpp) 
wich resets some VM state and returns the one structure shared between VM and 
revivalhelper.

The core's JVM and that found for revival must be exactly the same.  Locally 
this is automatic, but if core is transported or the JVM at the path in the 
core has changed, run e.g. "jcmd -L /my/path core help" where you have either a 
JDK or just libjvm.so in /my/path (there is a version check also, based on 
finding string pointers to JVM version info which should be readable from both 
the binary and the core file).

-------------

PR Comment: https://git.openjdk.org/jdk/pull/31011#issuecomment-4360664113

Reply via email to