From e33dc13567a4f0d9a6c1ae63fa0424ca27d52584 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 6 Nov 2024 19:36:20 +0000 Subject: [PATCH] 8343343: Misc crash dump improvements on more platforms after JDK-8294160 Co-authored-by: Boris Ulasevich Reviewed-by: mbaesken, jkern, dlong --- src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp | 29 ++++----------- .../os_cpu/bsd_aarch64/os_bsd_aarch64.cpp | 23 ++++-------- src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp | 23 ++++-------- src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp | 4 --- .../os_cpu/linux_aarch64/os_linux_aarch64.cpp | 17 --------- src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp | 35 ++++++++++--------- src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp | 23 ++++-------- .../os_cpu/linux_riscv/os_linux_riscv.cpp | 17 --------- .../os_cpu/linux_s390/os_linux_s390.cpp | 23 ++++-------- src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp | 17 --------- .../os_cpu/linux_zero/os_linux_zero.cpp | 15 -------- .../windows_aarch64/os_windows_aarch64.cpp | 18 ---------- .../os_cpu/windows_x86/os_windows_x86.cpp | 17 --------- src/hotspot/share/runtime/os.cpp | 20 +++++++++++ 14 files changed, 68 insertions(+), 213 deletions(-) diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index f83aa603062..45d91c60ed4 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -123,13 +123,13 @@ frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; address epc = fetch_frame_from_context(ucVoid, &sp, &fp); - // Avoid crash during crash if pc broken. - if (epc) { - frame fr(sp, epc, frame::kind::unknown); - return fr; + if (epc == nullptr || !is_readable_pointer(epc)) { + // Try to recover from calling into bad memory + // Assume new frame has not been set up, the same as + // compiled frame stack bang + return fetch_compiled_frame_from_context(ucVoid); } - frame fr(sp); - return fr; + return frame(sp, epc, frame::kind::unknown); } frame os::fetch_compiled_frame_from_context(const void* ucVoid) { @@ -447,23 +447,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const ucontext_t* uc = (const ucontext_t*)context; - - address sp = (address)os::Aix::ucontext_get_sp(uc); - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = 32 /* r0-r32 */ + 3 /* pc, lr, sp */; int n = continuation; diff --git a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp index ba14cb2ac12..7702dbd17ad 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp @@ -159,6 +159,12 @@ frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; address epc = fetch_frame_from_context(ucVoid, &sp, &fp); + if (!is_readable_pointer(epc)) { + // Try to recover from calling into bad memory + // Assume new frame has not been set up, the same as + // compiled frame stack bang + return fetch_compiled_frame_from_context(ucVoid); + } return frame(sp, fp, epc); } @@ -442,23 +448,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const ucontext_t* uc = (const ucontext_t*)context; - - address sp = (address)os::Bsd::ucontext_get_sp(uc); - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = 29 /* x0-x28 */ + 3 /* fp, lr, sp */; int n = continuation; diff --git a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp index 437274a2cb1..153c5ad7e2b 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -333,6 +333,12 @@ frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; address epc = fetch_frame_from_context(ucVoid, &sp, &fp); + if (!is_readable_pointer(epc)) { + // Try to recover from calling into bad memory + // Assume new frame has not been set up, the same as + // compiled frame stack bang + return fetch_compiled_frame_from_context(ucVoid); + } return frame(sp, fp, epc); } @@ -836,23 +842,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const ucontext_t* uc = (const ucontext_t*)context; - - address sp = (address)os::Bsd::ucontext_get_sp(uc); - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = AMD64_ONLY(16) NOT_AMD64(8); int n = continuation; diff --git a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp index 0fc9484ce23..4ecdbe93ebf 100644 --- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp +++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp @@ -228,10 +228,6 @@ void os::print_context(outputStream* st, const void* context) { ShouldNotCallThis(); } -void os::print_tos_pc(outputStream *st, const void *context) { - ShouldNotCallThis(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { ShouldNotCallThis(); } diff --git a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp index 9f44fe3aa25..a7ec163f785 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -354,23 +354,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const ucontext_t* uc = (const ucontext_t*)context; - - address sp = (address)os::Linux::ucontext_get_sp(uc); - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::fetch_frame_from_context(uc).pc(); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = 32 /* r0-r31 */; int n = continuation; diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp index 807fa765897..861d0d20153 100644 --- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp @@ -188,9 +188,27 @@ frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; address epc = fetch_frame_from_context(ucVoid, &sp, &fp); + if (!is_readable_pointer(epc)) { + // Try to recover from calling into bad memory + // Assume new frame has not been set up, the same as + // compiled frame stack bang + return fetch_compiled_frame_from_context(ucVoid); + } return frame(sp, fp, epc); } +frame os::fetch_compiled_frame_from_context(const void* ucVoid) { + const ucontext_t* uc = (const ucontext_t*)ucVoid; + // In compiled code, the stack banging is performed before LR + // has been saved in the frame. LR is live, and SP and FP + // belong to the caller. + intptr_t* fp = os::Linux::ucontext_get_fp(uc); + intptr_t* sp = os::Linux::ucontext_get_sp(uc); + address pc = (address)(uc->uc_mcontext.arm_lr + - NativeInstruction::instruction_size); + return frame(sp, fp, pc); +} + frame os::get_sender_for_C_frame(frame* fr) { #ifdef __thumb__ // We can't reliably get anything from a thumb C frame. @@ -474,23 +492,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const ucontext_t* uc = (const ucontext_t*)context; - - address sp = (address)os::Linux::ucontext_get_sp(uc); - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = ARM_REGS_IN_CONTEXT; int n = continuation; diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp index 1857097bd52..f3f9a3a88df 100644 --- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp @@ -155,6 +155,12 @@ frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; address epc = fetch_frame_from_context(ucVoid, &sp, &fp); + if (!is_readable_pointer(epc)) { + // Try to recover from calling into bad memory + // Assume new frame has not been set up, the same as + // compiled frame stack bang + return fetch_compiled_frame_from_context(ucVoid); + } return frame(sp, epc, frame::kind::unknown); } @@ -461,23 +467,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const ucontext_t* uc = (const ucontext_t*)context; - - address sp = (address)os::Linux::ucontext_get_sp(uc); - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = 32 /* r0-r32 */ + 3 /* pc, lr, ctr */; int n = continuation; diff --git a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp index fcb0e170af1..a00659f37cb 100644 --- a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp @@ -352,23 +352,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const ucontext_t* uc = (const ucontext_t*)context; - - address sp = (address)os::Linux::ucontext_get_sp(uc); - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::fetch_frame_from_context(uc).pc(); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = 32; int n = continuation; diff --git a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp index 9ac1152a013..bc8e3d10431 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp @@ -140,6 +140,12 @@ frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; address epc = fetch_frame_from_context(ucVoid, &sp, &fp); + if (!is_readable_pointer(epc)) { + // Try to recover from calling into bad memory + // Assume new frame has not been set up, the same as + // compiled frame stack bang + return fetch_compiled_frame_from_context(ucVoid); + } return frame(sp, epc); } @@ -442,23 +448,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const ucontext_t* uc = (const ucontext_t*)context; - - address sp = (address)os::Linux::ucontext_get_sp(uc); - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = 16 /* r0-r15 */ + 1 /* pc */; int n = continuation; diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index 8fdcbe63c7e..e357747bfea 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -578,23 +578,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const ucontext_t* uc = (const ucontext_t*)context; - - address sp = (address)os::Linux::ucontext_get_sp(uc); - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::fetch_frame_from_context(uc).pc(); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = AMD64_ONLY(16) NOT_AMD64(8); int n = continuation; diff --git a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp index d593c46d15d..d8498f104c2 100644 --- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp +++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp @@ -376,21 +376,6 @@ void os::print_context(outputStream* st, const void* ucVoid) { st->print_cr("No context information."); } -void os::print_tos_pc(outputStream *st, const void* ucVoid) { - const ucontext_t* uc = (const ucontext_t*)ucVoid; - - address sp = (address)os::Linux::ucontext_get_sp(uc); - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::Posix::ucontext_get_pc(uc); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { st->print_cr("No register info."); } diff --git a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp index 722c3c8dd60..24410ed9203 100644 --- a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp +++ b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp @@ -205,24 +205,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const CONTEXT* uc = (const CONTEXT*)context; - - address sp = (address)uc->Sp; - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = (address)uc->Pc; - st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); - print_hex_dump(st, pc - 32, pc + 32, sizeof(char), /* print_ascii=*/false); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = 29 /* X0-X28 */; int n = continuation; diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp index de59a74cc24..f67e5df8e3e 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -464,23 +464,6 @@ void os::print_context(outputStream *st, const void *context) { st->cr(); } -void os::print_tos_pc(outputStream *st, const void *context) { - if (context == nullptr) return; - - const CONTEXT* uc = (const CONTEXT*)context; - - address sp = (address)uc->REG_SP; - print_tos(st, sp); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::fetch_frame_from_context(uc).pc(); - print_instructions(st, pc); - st->cr(); -} - void os::print_register_info(outputStream *st, const void *context, int& continuation) { const int register_count = AMD64_ONLY(16) NOT_AMD64(8); int n = continuation; diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 2395510f27f..31f671e742e 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1083,6 +1083,26 @@ void os::print_dhm(outputStream* st, const char* startStr, long sec) { st->print_cr("%s %ld days %ld:%02ld hours", startStr, days, hours, minutes); } +void os::print_tos_pc(outputStream* st, const void* context) { + if (context == nullptr) return; + + // First of all, carefully determine sp without inspecting memory near pc. + // See comment below. + intptr_t* sp = nullptr; + fetch_frame_from_context(context, &sp, nullptr); + print_tos(st, (address)sp); + st->cr(); + + // Note: it may be unsafe to inspect memory near pc. For example, pc may + // point to garbage if entry point in an nmethod is corrupted. Leave + // this at the end, and hope for the best. + // This version of fetch_frame_from_context finds the caller pc if the actual + // one is bad. + address pc = fetch_frame_from_context(context).pc(); + print_instructions(st, pc); + st->cr(); +} + void os::print_tos(outputStream* st, address sp) { st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", p2i(sp)); print_hex_dump(st, sp, sp + 512, sizeof(intptr_t));