changeset 54283:e61065c08924

8220794: PPC64: Fix signal handler for SIGSEGV on branch to illegal address Reviewed-by: stuefe, goetz
author gromero
date Wed, 20 Mar 2019 16:59:35 -0400
parents 6ddb9e3f1654
children a2897fb258f1
files src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp
diffstat 1 files changed, 19 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- 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)) {