8220794: PPC64: Fix signal handler for SIGSEGV on branch to illegal address
Reviewed-by: stuefe, goetz
--- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp Tue Mar 26 14:49:54 2019 +0100
+++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp Wed Mar 20 16:59:35 2019 -0400
@@ -132,6 +132,10 @@
return NULL;
}
+static unsigned long ucontext_get_trap(const ucontext_t * uc) {
+ return uc->uc_mcontext.regs->trap;
+}
+
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
intptr_t** ret_sp, intptr_t** ret_fp) {
@@ -304,9 +308,22 @@
// Handle ALL stack overflow variations here
if (sig == SIGSEGV) {
- // Si_addr may not be valid due to a bug in the linux-ppc64 kernel (see
+ // si_addr may not be valid due to a bug in the linux-ppc64 kernel (see
// comment below). Use get_stack_bang_address instead of si_addr.
- address addr = ((NativeInstruction*)pc)->get_stack_bang_address(uc);
+ // If SIGSEGV is caused due to a branch to an invalid address an
+ // "Instruction Storage" interruption is generated and 'pc' (NIP) already
+ // contains the invalid address. Otherwise, the SIGSEGV is caused due to
+ // load/store instruction trying to load/store from/to an invalid address
+ // and causing a "Data Storage" interruption, so we inspect the intruction
+ // in order to extract the faulty data addresss.
+ address addr;
+ if ((ucontext_get_trap(uc) & 0x0F00 /* no IRQ reply bits */) == 0x0400) {
+ // Instruction interruption
+ addr = pc;
+ } else {
+ // Data interruption (0x0300): extract faulty data address
+ addr = ((NativeInstruction*)pc)->get_stack_bang_address(uc);
+ }
// Check if fault address is within thread stack.
if (thread->on_local_stack(addr)) {