From 660a38843068d7c932142e75c5476f119f9531df Mon Sep 17 00:00:00 2001 From: TheRealMDoerr Date: Fri, 26 Sep 2025 18:00:10 +0200 Subject: [PATCH 1/5] 8368787: Error reporting: hs_err files should print instructions when referencing code in nemthods --- src/hotspot/share/code/codeBlob.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 18e7752013957..6511b4689ed44 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -910,6 +910,24 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const nm->print_nmethod(true); } else { nm->print_on(st); + if (nm->entry_point() <= addr && addr < nm->code_end()) { + // Pointing into an nmethod. Try to disassemble some instructions around addr. + address start = (addr < nm->verified_entry_point()) ? nm->entry_point() : nm->verified_entry_point(); + address end = nm->code_end(); + // Try using relocations to find known instruction start and end points. + // (Some platforms have variable length instructions and can only + // disassemble correctly at instruction start addresses.) + RelocIterator iter(nm, start); + while (iter.next() && iter.addr() < addr) { // find relocation before addr + start = iter.addr(); + } + if (iter.has_current()) { + if (iter.addr() == addr) iter.next(); // find relocation after addr + if (iter.has_current()) end = iter.addr(); + } + + Disassembler::decode(start, end, st); + } } return; } From 003680de6ac776bb8ca49aecb72512062db0dfca Mon Sep 17 00:00:00 2001 From: TheRealMDoerr Date: Tue, 7 Oct 2025 00:03:21 +0200 Subject: [PATCH 2/5] Always print hex dump. Plus disassembly when hsdis loaded. --- src/hotspot/share/code/codeBlob.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 6511b4689ed44..0571eb8f98542 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -926,7 +926,11 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const if (iter.has_current()) end = iter.addr(); } - Disassembler::decode(start, end, st); + // Always print hex. Disassembler may still have problems if start is not a correct instruction start. + os::print_hex_dump(st, start, end, 1, /* print_ascii=*/false); + if (!Disassembler::is_abstract()) { + Disassembler::decode(start, end, st); + } } } return; From 4a05d40fab88dcf24e01bad0e0a251bb7e6d8d3e Mon Sep 17 00:00:00 2001 From: TheRealMDoerr Date: Tue, 7 Oct 2025 12:22:33 +0200 Subject: [PATCH 3/5] Move printing code to nmethod.cpp. --- src/hotspot/share/code/codeBlob.cpp | 23 +---------------------- src/hotspot/share/code/nmethod.cpp | 25 +++++++++++++++++++++++++ src/hotspot/share/code/nmethod.hpp | 1 + 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 0571eb8f98542..e901d5606161c 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -910,28 +910,7 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const nm->print_nmethod(true); } else { nm->print_on(st); - if (nm->entry_point() <= addr && addr < nm->code_end()) { - // Pointing into an nmethod. Try to disassemble some instructions around addr. - address start = (addr < nm->verified_entry_point()) ? nm->entry_point() : nm->verified_entry_point(); - address end = nm->code_end(); - // Try using relocations to find known instruction start and end points. - // (Some platforms have variable length instructions and can only - // disassemble correctly at instruction start addresses.) - RelocIterator iter(nm, start); - while (iter.next() && iter.addr() < addr) { // find relocation before addr - start = iter.addr(); - } - if (iter.has_current()) { - if (iter.addr() == addr) iter.next(); // find relocation after addr - if (iter.has_current()) end = iter.addr(); - } - - // Always print hex. Disassembler may still have problems if start is not a correct instruction start. - os::print_hex_dump(st, start, end, 1, /* print_ascii=*/false); - if (!Disassembler::is_abstract()) { - Disassembler::decode(start, end, st); - } - } + nm->print_code_snippet(st, addr); } return; } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index c0091cd2f6590..ffc6cb404ef35 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -3995,6 +3995,31 @@ void nmethod::print_value_on_impl(outputStream* st) const { #endif } +void nmethod::print_code_snippet(outputStream* st, address addr) const { + if (entry_point() <= addr && addr < code_end()) { + // Pointing into the nmethod's code. Try to disassemble some instructions around addr. + address start = (addr < verified_entry_point()) ? entry_point() : verified_entry_point(); + address end = code_end(); + // Try using relocations to find known instruction start and end points. + // (Some platforms have variable length instructions and can only + // disassemble correctly at instruction start addresses.) + RelocIterator iter((nmethod*)this, start); + while (iter.next() && iter.addr() < addr) { // find relocation before addr + start = iter.addr(); + } + if (iter.has_current()) { + if (iter.addr() == addr) iter.next(); // find relocation after addr + if (iter.has_current()) end = iter.addr(); + } + + // Always print hex. Disassembler may still have problems when hitting an incorrect instruction start. + os::print_hex_dump(st, start, end, 1, /* print_ascii=*/false); + if (!Disassembler::is_abstract()) { + Disassembler::decode(start, end, st); + } + } +} + #ifndef PRODUCT void nmethod::print_calls(outputStream* st) { diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 020370c504b17..545b67ab300d8 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -996,6 +996,7 @@ class nmethod : public CodeBlob { void print_on_impl(outputStream* st) const; void print_code(); void print_value_on_impl(outputStream* st) const; + void print_code_snippet(outputStream* st, address addr) const; #if defined(SUPPORT_DATA_STRUCTS) // print output in opt build for disassembler library From 81dd1c8e86d0e33d546b5e9fe7773f0d0550a4fc Mon Sep 17 00:00:00 2001 From: TheRealMDoerr Date: Tue, 7 Oct 2025 19:09:24 +0200 Subject: [PATCH 4/5] Use frame_complete_offset for better start address computation. Improve comments. --- src/hotspot/share/code/nmethod.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index ffc6cb404ef35..7176a93b1a80f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -3998,13 +3998,25 @@ void nmethod::print_value_on_impl(outputStream* st) const { void nmethod::print_code_snippet(outputStream* st, address addr) const { if (entry_point() <= addr && addr < code_end()) { // Pointing into the nmethod's code. Try to disassemble some instructions around addr. - address start = (addr < verified_entry_point()) ? entry_point() : verified_entry_point(); + // Determine conservative start and end points. + address start; + if (frame_complete_offset() != CodeOffsets::frame_never_safe && + addr >= code_begin() + frame_complete_offset()) { + start = code_begin() + frame_complete_offset(); + } else { + start = (addr < verified_entry_point()) ? entry_point() : verified_entry_point(); + } address end = code_end(); - // Try using relocations to find known instruction start and end points. + + // Try using relocations to find closer instruction start and end points. // (Some platforms have variable length instructions and can only // disassemble correctly at instruction start addresses.) RelocIterator iter((nmethod*)this, start); while (iter.next() && iter.addr() < addr) { // find relocation before addr + // Note: There's a relocation which doesn't point to an instruction start: + // ZBarrierRelocationFormatStoreGoodAfterMov with ZGC on x86_64 + // We could detect and skip it, but hex dump is still usable when + // disassembler produces garbage in such a very rare case. start = iter.addr(); } if (iter.has_current()) { From db4c64a25fe4bd80ce0df9a058685900a2a3a727 Mon Sep 17 00:00:00 2001 From: TheRealMDoerr Date: Thu, 23 Oct 2025 12:02:48 +0200 Subject: [PATCH 5/5] Ensure to print at least 64 Bytes ahead in hex dump. --- src/hotspot/share/code/nmethod.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 7176a93b1a80f..c4adde49e500e 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -4006,6 +4006,7 @@ void nmethod::print_code_snippet(outputStream* st, address addr) const { } else { start = (addr < verified_entry_point()) ? entry_point() : verified_entry_point(); } + address start_for_hex_dump = start; // We can choose a different starting point for hex dump, below. address end = code_end(); // Try using relocations to find closer instruction start and end points. @@ -4018,6 +4019,8 @@ void nmethod::print_code_snippet(outputStream* st, address addr) const { // We could detect and skip it, but hex dump is still usable when // disassembler produces garbage in such a very rare case. start = iter.addr(); + // We want at least 64 Bytes ahead in hex dump. + if (iter.addr() <= (addr - 64)) start_for_hex_dump = iter.addr(); } if (iter.has_current()) { if (iter.addr() == addr) iter.next(); // find relocation after addr @@ -4025,7 +4028,7 @@ void nmethod::print_code_snippet(outputStream* st, address addr) const { } // Always print hex. Disassembler may still have problems when hitting an incorrect instruction start. - os::print_hex_dump(st, start, end, 1, /* print_ascii=*/false); + os::print_hex_dump(st, start_for_hex_dump, end, 1, /* print_ascii=*/false); if (!Disassembler::is_abstract()) { Disassembler::decode(start, end, st); }