OSDN Git Service

gcc:
authorro <ro@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 14 Feb 2011 12:32:11 +0000 (12:32 +0000)
committerro <ro@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 14 Feb 2011 12:32:11 +0000 (12:32 +0000)
PR ada/41929
* config/sparc/sol2-unwind.h: Include <sys/frame.h>, <sys/stack.h>
(IS_SIGHANDLER): Define.
(sparc64_is_sighandler): New function, split off from
sparc64_fallback_frame_state.
(sparc_is_sighandler): New function, split off from
sparc_fallback_frame_state.
(sparc64_fallback_frame_state): Merge with ...
(sparc_fallback_frame_state): ... this into ...
(MD_FALLBACK_FRAME_STATE_FOR): ... this.
Change new_cfa to long.
Remove regs_off, fpu_save_off, fpu_save.
Define nframes, mctx.
Use IS_SIGHANDLER, handler_args, mctx, walk stack instead of
hardcoded offsets.

gcc/testsuite:
PR ada/41929
* gnat.dg/null_pointer_deref1.exp: Don't skip on
sparc*-sun-solaris2.11.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@170126 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/sparc/sol2-unwind.h
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/null_pointer_deref1.adb

index 6c3f6d4..aa604ee 100644 (file)
@@ -1,3 +1,21 @@
+2011-02-14  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
+
+       PR ada/41929
+       * config/sparc/sol2-unwind.h: Include <sys/frame.h>, <sys/stack.h>
+       (IS_SIGHANDLER): Define.
+       (sparc64_is_sighandler): New function, split off from
+       sparc64_fallback_frame_state.
+       (sparc_is_sighandler): New function, split off from
+       sparc_fallback_frame_state.
+       (sparc64_fallback_frame_state): Merge with ...
+       (sparc_fallback_frame_state): ... this into ...
+       (MD_FALLBACK_FRAME_STATE_FOR): ... this.
+       Change new_cfa to long.
+       Remove regs_off, fpu_save_off, fpu_save.
+       Define nframes, mctx.
+       Use IS_SIGHANDLER, handler_args, mctx, walk stack instead of
+       hardcoded offsets.
+
 2011-02-14  Ralf Wildenhues  <Ralf.Wildenhues@gmx.de>
 
        * go/gccgo.texi (Top, Import and Export): Fix a typo and a
index aa1358d..f8b9902 100644 (file)
@@ -1,5 +1,5 @@
 /* DWARF2 EH unwinding support for SPARC Solaris.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -26,224 +26,130 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    state data appropriately.  See unwind-dw2.c for the structs.  */
 
 #include <ucontext.h>
+#include <sys/frame.h>
+#include <sys/stack.h>
 
 #if defined(__arch64__)
 
-#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
+#define IS_SIGHANDLER sparc64_is_sighandler
 
-static _Unwind_Reason_Code
-sparc64_fallback_frame_state (struct _Unwind_Context *context,
-                             _Unwind_FrameState *fs)
+static int
+sparc64_is_sighandler (unsigned int *pc, unsigned int *savpc, int *nframes)
 {
-  void *pc = context->ra;
-  void *this_cfa = context->cfa;
-  void *new_cfa, *ra_location, *shifted_ra_location;
-  int regs_off;
-  int fpu_save_off;
-  unsigned char fpu_save;
-  int i;
-
-  /* This is the observed pattern for the sigacthandler in Solaris 8.  */
-  unsigned int sigacthandler_sol8_pattern []
-    = {0x9401400f, 0xca5aafa0, 0x913e2000, 0x892a3003,
-       0xe0590005, 0x9fc40000, 0x9410001a, 0x80a6e008};
-
-  /* This is the observed pattern for the sigacthandler in Solaris 9.  */ 
-  unsigned int sigacthandler_sol9_pattern []
-    = {0xa33e2000, 0x00000000, 0x892c7003, 0x90100011,
-       0xe0590005, 0x9fc40000, 0x9410001a, 0x80a46008};
-
-  /* This is the observed pattern for the __sighndlr.  */
-  unsigned int sighndlr_pattern []
-    = {0x9de3bf50, 0x90100018, 0x92100019, 0x9fc6c000,
-       0x9410001a, 0x81c7e008, 0x81e80000};
-
-  /* Deal with frame-less function from which a signal was raised.  */
-  if (_Unwind_IsSignalFrame (context))
+  if (/* Solaris 8 - single-threaded
+       ----------------------------
+       <sigacthandler+24>:  add  %g5, %o7, %o2
+       <sigacthandler+28>:  ldx  [ %o2 + 0xfa0 ], %g5
+       <sigacthandler+32>:  sra  %i0, 0, %o0
+       <sigacthandler+36>:  sllx  %o0, 3, %g4
+       <sigacthandler+40>:  ldx  [ %g4 + %g5 ], %l0
+       <sigacthandler+44>:  call  %l0
+       <sigacthandler+48>:  mov  %i2, %o2
+       <sigacthandler+52>:  cmp  %i3, 8        <--- PC  */
+      (   pc[-7] == 0x9401400f
+       && pc[-6] == 0xca5aafa0
+       && pc[-5] == 0x913e2000
+       && pc[-4] == 0x892a3003
+       && pc[-3] == 0xe0590005
+       && pc[-2] == 0x9fc40000
+       && pc[-1] == 0x9410001a
+       && pc[ 0] == 0x80a6e008)
+
+      || /* Solaris 9 - single-threaded
+          ----------------------------
+          The pattern changes slightly in different versions of the
+          operating system, so we skip the comparison against pc[-6] for
+          Solaris 9.
+
+          <sigacthandler+24>:  sra  %i0, 0, %l1
+
+          Solaris 9 5/02:
+          <sigacthandler+28>:  ldx  [ %o2 + 0xf68 ], %g5
+          Solaris 9 9/05:
+          <sigacthandler+28>:  ldx  [ %o2 + 0xe50 ], %g5
+
+          <sigacthandler+32>:  sllx  %l1, 3, %g4
+          <sigacthandler+36>:  mov  %l1, %o0
+          <sigacthandler+40>:  ldx  [ %g4 + %g5 ], %l0
+          <sigacthandler+44>:  call  %l0
+          <sigacthandler+48>:  mov  %i2, %o2
+          <sigacthandler+52>:  cmp  %l1, 8     <--- PC  */
+      (   pc[-7] == 0xa33e2000
+       /* skip pc[-6] */
+       && pc[-5] == 0x892c7003
+       && pc[-4] == 0x90100011
+       && pc[-3] == 0xe0590005
+       && pc[-2] == 0x9fc40000
+       && pc[-1] == 0x9410001a
+       && pc[ 0] == 0x80a46008))
     {
-      /* The CFA is by definition unmodified in this case.  */
-      fs->regs.cfa_how = CFA_REG_OFFSET;
-      fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
-      fs->regs.cfa_offset = 0;
-
-      /* This is the canonical RA column.  */
-      fs->retaddr_column = 15;
-
-      return _URC_NO_REASON;
+      /* We need to move up one frame:
+
+               <signal handler>        <-- context->cfa
+               sigacthandler
+               <kernel>
+      */
+      *nframes = 1;
+      return 1;
     }
 
-  /* Look for the sigacthandler pattern.  The pattern changes slightly
-     in different versions of the operating system, so we skip the
-     comparison against pc-(4*6) for Solaris 9.  */
-  if ((    *(unsigned int *)(pc-(4*7)) == sigacthandler_sol8_pattern[0]
-       && *(unsigned int *)(pc-(4*6)) == sigacthandler_sol8_pattern[1]
-       && *(unsigned int *)(pc-(4*5)) == sigacthandler_sol8_pattern[2]
-       && *(unsigned int *)(pc-(4*4)) == sigacthandler_sol8_pattern[3]
-       && *(unsigned int *)(pc-(4*3)) == sigacthandler_sol8_pattern[4]
-       && *(unsigned int *)(pc-(4*2)) == sigacthandler_sol8_pattern[5]
-       && *(unsigned int *)(pc-(4*1)) == sigacthandler_sol8_pattern[6]
-       && *(unsigned int *)(pc-(4*0)) == sigacthandler_sol8_pattern[7] ) ||
-      (    *(unsigned int *)(pc-(4*7)) == sigacthandler_sol9_pattern[0]
-       /* skip pc-(4*6) */
-       && *(unsigned int *)(pc-(4*5)) == sigacthandler_sol9_pattern[2]
-       && *(unsigned int *)(pc-(4*4)) == sigacthandler_sol9_pattern[3]
-       && *(unsigned int *)(pc-(4*3)) == sigacthandler_sol9_pattern[4]
-       && *(unsigned int *)(pc-(4*2)) == sigacthandler_sol9_pattern[5]
-       && *(unsigned int *)(pc-(4*1)) == sigacthandler_sol9_pattern[6]
-       && *(unsigned int *)(pc-(4*0)) == sigacthandler_sol9_pattern[7] ) )
-    /* We need to move up two frames (the kernel frame and the handler
-       frame).  Minimum stack frame size is 176 bytes (128 + 48): 128
-       bytes for spilling register window (16 extended words for in
-       and local registers), and 6 extended words to store at least
-       6 arguments to callees, The kernel frame and the sigacthandler
-       both have this minimal stack.  The ucontext_t structure is after
-       this offset.  */
-    regs_off = 176 + 176;
-
-  /* Look for the __sighndlr pattern.  */
-  else if (    *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0]
-           && *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1]
-           && *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2]
-           && *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3]
-           && *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4]
-           && *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5]
-           && *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] )
+  if (/* Solaris 8+ - multi-threaded
+       ----------------------------
+       <__sighndlr>:        save  %sp, -176, %sp
+       <__sighndlr+4>:      mov  %i0, %o0
+       <__sighndlr+8>:      mov  %i1, %o1
+       <__sighndlr+12>:     call  %i3
+       <__sighndlr+16>:     mov  %i2, %o2
+       <__sighndlr+20>:     ret                <--- PC
+       <__sighndlr+24>:     restore  */
+         pc[-5] == 0x9de3bf50
+      && pc[-4] == 0x90100018
+      && pc[-3] == 0x92100019
+      && pc[-2] == 0x9fc6c000
+      && pc[-1] == 0x9410001a
+      && pc[ 0] == 0x81c7e008
+      && pc[ 1] == 0x81e80000)
     {
-      /* We have observed different calling frames among different
-        versions of the operating system, so that we need to
-        discriminate using the upper frame.  We look for the return
-        address of the caller frame (there is an offset of 15 double
-        words between the frame address and the place where this return
-        address is stored) in order to do some more pattern matching.  */
-      unsigned int cuh_pattern
-       = *(unsigned int *)(*(unsigned long *)(this_cfa + 15*8) - 4);
-
-      if (cuh_pattern == 0xd25fa7ef)
+      if (/* Solaris 8 /usr/lib/sparcv9/libthread.so.1
+           ------------------------------------------
+           Before patch 108827-08:
+           <sigacthandler+1760>:     st  %g4, [ %i1 + 0x1c ]
+
+           Since patch 108827-08:
+           <sigacthandler+1816>:     st  %l0, [ %i4 + 0x10 ]  */
+               savpc[-1] == 0xc826601c
+            || savpc[-1] == 0xe0272010)
        {
-         /* This matches the call_user_handler pattern for Solaris 10.
-            There are 2 cases so we look for the return address of the
-            caller's caller frame in order to do more pattern matching.  */
-         unsigned int sah_pattern
-           = *(unsigned int *)(*(unsigned long *)(this_cfa + 176 + 15*8) - 4);
-
-          if (sah_pattern == 0x92100019)
-           /* This is the same setup as for Solaris 9, see below.  */
-           regs_off = 176 + 176 + 176 + 304;
-         else
-           /* We need to move up three frames (the kernel frame, the
-              call_user_handler frame, the __sighndlr frame).  Two of them
-              have the minimum stack frame size (kernel and __sighndlr
-              frames) of 176 bytes, and there is another with a stack frame
-              of 304 bytes (the call_user_handler frame).  The ucontext_t
-              structure is after this offset.  */
-           regs_off = 176 + 176 + 304;
+         /* We need to move up three frames:
+
+               <signal handler>        <-- context->cfa
+               __sighndlr
+               sigacthandler
+               <kernel>
+         */
+         *nframes = 2;
        }
-      else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x94100013)
-       /* This matches the call_user_handler pattern for Solaris 9 and
-          for Solaris 8 running inside Solaris Containers respectively.
-          We need to move up four frames (the kernel frame, the signal
-          frame, the call_user_handler frame, the __sighndlr frame).
-          Three of them have the minimum stack frame size (kernel,
-          signal, and __sighndlr frames) of 176 bytes, and there is
-          another with a stack frame of 304 bytes (the call_user_handler
-          frame).  The ucontext_t structure is after this offset.  */
-       regs_off = 176 + 176 + 176 + 304;
-      else
-       /* We need to move up three frames (the kernel frame, the
-          sigacthandler frame, and the __sighndlr frame).  The kernel
-          frame has a stack frame size of 176, the __sighndlr frames of
-          304 bytes, and there is a stack frame of 176 bytes for the
-          sigacthandler frame.  The ucontext_t structure is after this
-          offset.  */
-       regs_off = 176 + 304 + 176;
-    }
-
-  /* Exit if the pattern at the return address does not match the
-     previous three patterns.  */
-  else
-    return _URC_END_OF_STACK;
-
-  /* FPU information can be extracted from the ucontext_t structure 
-     that is the third argument for the signal handler, that is saved
-     in the stack.  There are 64 bytes between the beginning of the
-     ucontext_t argument of the signal handler and the uc_mcontext
-     field.  There are 176 bytes between the beginning of uc_mcontext
-     and the beginning of the fpregs field.  */
-  fpu_save_off = regs_off + (8*10) + 176;
-
-  /* The fpregs field contains 32 extended words at the beginning that
-     contain the FPU state.  Then there are 2 extended words and two
-     bytes.  */
-  fpu_save = *(unsigned char *)(this_cfa + fpu_save_off + (8*32) + (2*8) + 2);
-
-  /* We need to get the frame pointer for the kernel frame that
-     executes when the signal is raised.  This frame is just the
-     following to the application code that generated the signal, so
-     that the later's stack pointer is the former's frame pointer.
-     The stack pointer for the interrupted application code can be
-     calculated from the ucontext_t structure (third argument for the
-     signal handler) that is saved in the stack.  There are 10 words
-     between the beginning of the  ucontext_t argument  of the signal
-     handler and the uc_mcontext.gregs field that contains the
-     registers saved by the signal handler.  */
-  new_cfa = *(void **)(this_cfa + regs_off + (8*10) + (REG_SP*8));
-  /* The frame address is %sp + STACK_BIAS in 64-bit mode. */
-  new_cfa += 2047;
-  fs->regs.cfa_how = CFA_REG_OFFSET;
-  fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
-  fs->regs.cfa_offset = new_cfa - this_cfa;
-
-  /* Restore global and out registers (in this order) from the
-     ucontext_t structure, uc_mcontext.gregs field.  */
-  for (i = 1; i < 16; i++)
-    {
-      /* We never restore %sp as everything is purely CFA-based.  */
-      if ((unsigned int) i == __builtin_dwarf_sp_column ())
-       continue;
-
-      /* First the global registers and then the out registers.  */
-      fs->regs.reg[i].how = REG_SAVED_OFFSET;
-      fs->regs.reg[i].loc.offset
-       = this_cfa + regs_off + (8*10) + ((REG_Y+i)*8) - new_cfa;
-    }
-
-  /* Just above the stack pointer there are 16 extended words in which
-     the register window (in and local registers) was saved.  */
-  for (i = 0; i < 16; i++)
-    {
-      fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
-      fs->regs.reg[i + 16].loc.offset = i*8;
-    }
-
-  /* Check whether we need to restore FPU registers.  */
-  if (fpu_save)
-    {
-      for (i = 0; i < 64; i++)
+      else /* Solaris 8 /usr/lib/lwp/sparcv9/libthread.so.1, Solaris 9+
+            ----------------------------------------------------------  */
        {
-         if (i > 32 && (i & 1))
-           continue;
-
-         fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
-         fs->regs.reg[i + 32].loc.offset
-           = this_cfa + fpu_save_off + (i*4) - new_cfa;
+         /* We need to move up three frames:
+
+               <signal handler>        <-- context->cfa
+               __sighndlr
+               call_user_handler
+               sigacthandler
+               <kernel>
+         */
+         *nframes = 3;
        }
+      return 1;
     }
 
-  /* State the rules to find the kernel's code "return address", which is
-     the address of the active instruction when the signal was caught.
-     On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
-     need to preventively subtract it from the purported return address.  */
-  ra_location = this_cfa + regs_off + (8*10) + (REG_PC*8);
-  shifted_ra_location = this_cfa + regs_off + (8*10) + (REG_Y*8);
-  *(void **)shifted_ra_location = *(void **)ra_location - 8;
-  fs->retaddr_column = 0;
-  fs->regs.reg[0].how = REG_SAVED_OFFSET;
-  fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
-  fs->signal_frame = 1;
-
-  return _URC_NO_REASON;
+  return 0;
 }
 
+#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
+
 #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
 
 static void
@@ -258,42 +164,150 @@ sparc64_frob_update_context (struct _Unwind_Context *context,
       && fs->regs.cfa_how == CFA_REG_OFFSET
       && fs->regs.cfa_offset != 0
       && !fs->signal_frame)
-    context->cfa -= 2047;
+    context->cfa -= STACK_BIAS;
 }
 
 #else
 
+#define IS_SIGHANDLER sparc_is_sighandler
+
+static int
+sparc_is_sighandler (unsigned int *pc, unsigned int * savpc, int *nframes)
+{
+  if (/* Solaris 8, 9 - single-threaded
+        -------------------------------
+       The pattern changes slightly in different versions of the operating
+       system, so we skip the comparison against pc[-6].
+
+       <sigacthandler+16>:  add  %o1, %o7, %o3
+       <sigacthandler+20>:  mov  %i1, %o1
+
+       <sigacthandler+24>:  ld  [ %o3 + <offset> ], %o2
+
+       <sigacthandler+28>:  sll  %i0, 2, %o0
+       <sigacthandler+32>:  ld  [ %o0 + %o2 ], %l0
+       <sigacthandler+36>:  mov  %i0, %o0
+       <sigacthandler+40>:  call  %l0
+       <sigacthandler+44>:  mov  %i2, %o2
+       <sigacthandler+48>:  cmp  %i0, 8        <--- PC  */
+         pc[-8] == 0x9602400f
+      && pc[-7] == 0x92100019
+      /* skip pc[-6] */
+      && pc[-5] == 0x912e2002
+      && pc[-4] == 0xe002000a
+      && pc[-3] == 0x90100018
+      && pc[-2] == 0x9fc40000
+      && pc[-1] == 0x9410001a
+      && pc[ 0] == 0x80a62008)
+    {
+      /* Need to move up one frame:
+
+               <signal handler>        <-- context->cfa
+               sigacthandler
+               <kernel>
+      */
+      *nframes = 1;
+      return 1;
+    }
+
+  if (/* Solaris 8 - multi-threaded
+       ---------------------------
+       <__libthread_segvhdlr+212>:  clr  %o2
+       <__libthread_segvhdlr+216>:  ld  [ %fp + -28 ], %l0
+       <__libthread_segvhdlr+220>:  mov  %i4, %o0
+       <__libthread_segvhdlr+224>:  mov  %i1, %o1
+       <__libthread_segvhdlr+228>:  call  %l0
+       <__libthread_segvhdlr+232>:  mov  %i2, %o2
+       <__libthread_segvhdlr+236>:  ret                <--- PC
+       <__libthread_segvhdlr+240>:  restore
+       <__libthread_segvhdlr+244>:  cmp  %o1, 0  */
+         pc[-6] == 0x94102000
+      && pc[-5] == 0xe007bfe4
+      && pc[-4] == 0x9010001c
+      && pc[-3] == 0x92100019
+      && pc[-2] == 0x9fc40000
+      && pc[-1] == 0x9410001a
+      && pc[ 0] == 0x81c7e008
+      && pc[ 1] == 0x81e80000
+      && pc[ 2] == 0x80a26000)
+    {
+      /* Need to move up one frame:
+
+               <signal handler>        <-- context->cfa
+               __libthread_segvhdlr
+               <kernel>
+      */
+      *nframes = 1;
+      return 1;
+    }
+
+  if(/* Solaris 8+ - multi-threaded
+       ----------------------------
+       <__sighndlr>:   save  %sp, -96, %sp
+       <__sighndlr+4>: mov  %i0, %o0
+       <__sighndlr+8>: mov  %i1, %o1
+       <__sighndlr+12>:        call  %i3
+       <__sighndlr+16>:        mov  %i2, %o2
+       <__sighndlr+20>:        ret             <--- PC
+       <__sighndlr+24>:        restore  */
+        pc[-5] == 0x9de3bfa0
+     && pc[-4] == 0x90100018
+     && pc[-3] == 0x92100019
+     && pc[-2] == 0x9fc6c000
+     && pc[-1] == 0x9410001a
+     && pc[ 0] == 0x81c7e008
+     && pc[ 1] == 0x81e80000)
+    {
+      if (/* Solaris 8 /usr/lib/libthread.so.1
+           ----------------------------------
+           <sigacthandler+1796>:     mov  %i0, %o0  */
+         savpc[-1] == 0x90100018)
+       {
+         /* We need to move up two frames:
+
+               <signal handler>        <-- context->cfa
+               __sighndlr
+               sigacthandler
+               <kernel>
+         */
+         *nframes = 2;
+       }
+      else /* Solaris 8 /usr/lib/lwp/libthread.so.1, Solaris 9+
+            --------------------------------------------------  */
+       {
+         /* We need to move up three frames:
+
+               <signal handler>        <-- context->cfa
+               __sighndlr
+               call_user_handler
+               sigacthandler
+               <kernel>
+         */
+         *nframes = 3;
+       }
+      return 1;
+    }
+
+  return 0;
+}
+
 #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
 
+#endif
+
 static _Unwind_Reason_Code
-sparc_fallback_frame_state (struct _Unwind_Context *context,
-                           _Unwind_FrameState *fs)
+MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context *context,
+                            _Unwind_FrameState *fs)
 {
   void *pc = context->ra;
+  struct frame *fp = (struct frame *) context->cfa;
+  int nframes;
   void *this_cfa = context->cfa;
-  void *new_cfa, *ra_location, *shifted_ra_location;
-  int regs_off;
-  int fpu_save_off;
-  unsigned char fpu_save;
+  long new_cfa;
+  void *ra_location, *shifted_ra_location;
+  mcontext_t *mctx;
   int i;
 
-  /* This is the observed pattern for the sigacthandler.  */
-  unsigned int sigacthandler_pattern []
-    = {0x9602400f, 0x92100019, 0x00000000, 0x912e2002,
-       0xe002000a, 0x90100018, 0x9fc40000, 0x9410001a,
-       0x80a62008};
-
-  /* This is the observed pattern for the __libthread_segvhdlr.  */
-  unsigned int segvhdlr_pattern []
-    = {0x94102000, 0xe007bfe4, 0x9010001c, 0x92100019,
-       0x9fc40000, 0x9410001a, 0x81c7e008, 0x81e80000,
-       0x80a26000};
-
-  /* This is the observed pattern for the __sighndlr.  */
-  unsigned int sighndlr_pattern []
-    = {0x9de3bfa0, 0x90100018, 0x92100019, 0x9fc6c000,
-       0x9410001a, 0x81c7e008, 0x81e80000};
-
   /* Deal with frame-less function from which a signal was raised.  */
   if (_Unwind_IsSignalFrame (context))
     {
@@ -308,102 +322,27 @@ sparc_fallback_frame_state (struct _Unwind_Context *context,
       return _URC_NO_REASON;
     }
 
-  /* Look for the sigacthandler pattern.  The pattern changes slightly
-     in different versions of the operating system, so we skip the
-     comparison against pc-(4*6).  */
-  if (    *(unsigned int *)(pc-(4*8)) == sigacthandler_pattern[0]
-       && *(unsigned int *)(pc-(4*7)) == sigacthandler_pattern[1]
-       /* skip pc-(4*6) */
-       && *(unsigned int *)(pc-(4*5)) == sigacthandler_pattern[3]
-       && *(unsigned int *)(pc-(4*4)) == sigacthandler_pattern[4]
-       && *(unsigned int *)(pc-(4*3)) == sigacthandler_pattern[5]
-       && *(unsigned int *)(pc-(4*2)) == sigacthandler_pattern[6]
-       && *(unsigned int *)(pc-(4*1)) == sigacthandler_pattern[7]
-       && *(unsigned int *)(pc-(4*0)) == sigacthandler_pattern[8] )
-    /* We need to move up two frames (the kernel frame and the handler
-       frame).  Minimum stack frame size is 96 bytes (64 + 4 + 24): 64
-       bytes for spilling register window (16 words for in and local
-       registers), 4 bytes for a pointer to space for callees
-       returning structs, and 24 bytes to store at least six argument
-       to callees.  The ucontext_t structure is after this offset.  */
-    regs_off = 96 + 96;
-
-  /* Look for the __libthread_segvhdlr pattern.  */
-  else if (    *(unsigned int *)(pc-(4*6)) == segvhdlr_pattern[0]
-           && *(unsigned int *)(pc-(4*5)) == segvhdlr_pattern[1]
-           && *(unsigned int *)(pc-(4*4)) == segvhdlr_pattern[2]
-           && *(unsigned int *)(pc-(4*3)) == segvhdlr_pattern[3]
-           && *(unsigned int *)(pc-(4*2)) == segvhdlr_pattern[4]
-           && *(unsigned int *)(pc-(4*1)) == segvhdlr_pattern[5]
-           && *(unsigned int *)(pc-(4*0)) == segvhdlr_pattern[6]
-           && *(unsigned int *)(pc+(4*1)) == segvhdlr_pattern[7]
-           && *(unsigned int *)(pc+(4*2)) == segvhdlr_pattern[8] )
-    /* We need to move up four frames (the kernel frame, the
-       sigacthandler frame, the __sighndlr frame, and the
-       __libthread_segvhdlr).  Two of them have the minimum
-       stack frame size (kernel and __sighndlr frames) of 96 bytes,
-       other has a stack frame of 216 bytes (the sigacthandler frame),
-       and there is another with a stack frame of 128 bytes (the
-       __libthread_segvhdlr).  The ucontext_t structure is after this
-       offset.  */
-    regs_off = 96 + 96 + 128 + 216;
-
-  /* Look for the __sighndlr pattern.  */
-  else if (    *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0]
-           && *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1]
-           && *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2]
-           && *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3]
-           && *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4]
-           && *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5]
-           && *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] )
+  if (IS_SIGHANDLER (pc, (unsigned int *)fp->fr_savpc, &nframes))
     {
-      /* We have observed different calling frames among different
-        versions of the operating system, so that we need to
-        discriminate using the upper frame.  We look for the return
-        address of the caller frame (there is an offset of 15 words
-        between the frame address and the place where this return
-        address is stored) in order to do some more pattern matching.  */
-      unsigned int cuh_pattern
-       = *(unsigned int *)(*(unsigned int *)(this_cfa + 15*4) - 4);
-
-      if (cuh_pattern == 0xd407a04c)
-       {
-         /* This matches the call_user_handler pattern for Solaris 10.
-            There are 2 cases so we look for the return address of the
-            caller's caller frame in order to do more pattern matching.  */
-         unsigned int sah_pattern
-           = *(unsigned int *)(*(unsigned int *)(this_cfa + 96 + 15*4) - 4);
-
-          if (sah_pattern == 0x92100019)
-           /* This is the same setup as for Solaris 9, see below.  */
-           regs_off = 96 + 96 + 96 + 160;
-         else
-           /* We need to move up three frames (the kernel frame, the
-              call_user_handler frame, the __sighndlr frame).  Two of them
-              have the minimum stack frame size (kernel and __sighndlr
-              frames) of 96 bytes, and there is another with a stack frame
-              of 160 bytes (the call_user_handler frame).  The ucontext_t
-              structure is after this offset.  */
-           regs_off = 96 + 96 + 160;
-       }
-      else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b)
-       /* This matches the call_user_handler pattern for Solaris 9 and
-          for Solaris 8 running inside Solaris Containers respectively.
-          We need to move up four frames (the kernel frame, the signal
-          frame, the call_user_handler frame, the __sighndlr frame).
-          Three of them have the minimum stack frame size (kernel,
-          signal, and __sighndlr frames) of 96 bytes, and there is
-          another with a stack frame of 160 bytes (the call_user_handler
-          frame).  The ucontext_t structure is after this offset.  */
-       regs_off = 96 + 96 + 96 + 160;
-      else
-       /* We need to move up three frames (the kernel frame, the
-          sigacthandler frame, and the __sighndlr frame).  Two of them
-          have the minimum stack frame size (kernel and __sighndlr
-          frames) of 96 bytes, and there is another with a stack frame
-          of 216 bytes (the sigacthandler frame).  The ucontext_t 
-          structure is after this offset.  */
-       regs_off = 96 + 96 + 216;
+      struct handler_args {
+       struct frame frwin;
+       ucontext_t ucontext;
+      } *handler_args;
+      ucontext_t *ucp;
+
+      /* context->cfa points into the frame after the saved frame pointer and
+         saved pc (struct frame).
+
+         The ucontext_t structure is in the kernel frame after a struct
+         frame.  Since the frame sizes vary even within OS releases, we
+         need to walk the stack to get there.  */
+
+      for (i = 0; i < nframes; i++)
+       fp = (struct frame *) ((char *)fp->fr_savfp + STACK_BIAS);
+
+      handler_args = (struct handler_args *) fp;
+      ucp = &handler_args->ucontext;
+      mctx = &ucp->uc_mcontext;
     }
 
   /* Exit if the pattern at the return address does not match the
@@ -411,32 +350,13 @@ sparc_fallback_frame_state (struct _Unwind_Context *context,
   else
     return _URC_END_OF_STACK;
 
-  /* FPU information can be extracted from the ucontext_t structure
-     that is the third argument for the signal handler, that is saved
-     in the stack.  There are 10 words between the beginning of the
-     ucontext_t argument of the signal handler and the uc_mcontext
-     field.  There are 80 bytes between the beginning of uc_mcontext
-     and the beginning of the fpregs field.  */
-  fpu_save_off = regs_off + (4*10) + (4*20);
-
-  /* The fpregs field contains 32 words at the beginning that contain
-     the FPU state.  Then there are 2 words and two bytes.  */
-  fpu_save = *(unsigned char *)(this_cfa + fpu_save_off + (4*32) + (2*4) + 2);
-
-  /* We need to get the frame pointer for the kernel frame that
-     executes when the signal is raised.  This frame is just the
-     following to the application code that generated the signal, so
-     that the later's stack pointer is the former's frame pointer.
-     The stack pointer for the interrupted application code can be
-     calculated from the ucontext_t structure (third argument for the
-     signal handler) that is saved in the stack.  There are 10 words
-     between the beginning of the  ucontext_t argument  of the signal
-     handler and the uc_mcontext.gregs field that contains the
-     registers saved by the signal handler.  */
-  new_cfa = *(void **)(this_cfa + regs_off + (4*10) + (REG_SP*4));
+  new_cfa = mctx->gregs[REG_SP];
+  /* The frame address is %sp + STACK_BIAS in 64-bit mode.  */
+  new_cfa += STACK_BIAS;
+
   fs->regs.cfa_how = CFA_REG_OFFSET;
   fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
-  fs->regs.cfa_offset = new_cfa - this_cfa;
+  fs->regs.cfa_offset = new_cfa - (long) this_cfa;
 
   /* Restore global and out registers (in this order) from the
      ucontext_t structure, uc_mcontext.gregs field.  */
@@ -446,44 +366,54 @@ sparc_fallback_frame_state (struct _Unwind_Context *context,
       if ((unsigned int) i == __builtin_dwarf_sp_column ())
        continue;
 
-      /* First the global registers and then the out registers */
+      /* First the global registers and then the out registers */
       fs->regs.reg[i].how = REG_SAVED_OFFSET;
-      fs->regs.reg[i].loc.offset
-       = this_cfa + regs_off + (4*10) + ((REG_Y+i)*4) - new_cfa;
+      fs->regs.reg[i].loc.offset = (long)&mctx->gregs[REG_Y + i] - new_cfa;
     }
 
-  /* Just above the stack pointer there are 16 words in which the
-     register window (in and local registers) was saved.  */
+  /* Just above the stack pointer there are 16 extended words in which
+     the register window (in and local registers) was saved.  */
   for (i = 0; i < 16; i++)
     {
       fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
-      fs->regs.reg[i + 16].loc.offset = i*4;
+      fs->regs.reg[i + 16].loc.offset = i*sizeof(long);
     }
 
   /* Check whether we need to restore FPU registers.  */
-  if (fpu_save)
+  if (mctx->fpregs.fpu_qcnt)
     {
       for (i = 0; i < 32; i++)
        {
          fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
          fs->regs.reg[i + 32].loc.offset
-           = this_cfa + fpu_save_off + (i*4) - new_cfa;
+           = (long)&mctx->fpregs.fpu_fr.fpu_regs[i] - new_cfa;
+       }
+
+#ifdef __arch64__
+      /* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles.  */
+      for (i = 32; i < 64; i++)
+       {
+         if (i > 32 && (i & 1))
+           continue;
+
+         fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
+         fs->regs.reg[i + 32].loc.offset
+           = (long)&mctx->fpregs.fpu_fr.fpu_dregs[i/2] - new_cfa;
        }
+#endif
     }
 
   /* State the rules to find the kernel's code "return address", which is
      the address of the active instruction when the signal was caught.
      On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
      need to preventively subtract it from the purported return address.  */
-  ra_location = this_cfa + regs_off + (4*10) + (REG_PC*4);
-  shifted_ra_location = this_cfa + regs_off + (4*10) + (REG_Y*4);
+  ra_location = &mctx->gregs[REG_PC];
+  shifted_ra_location = &mctx->gregs[REG_Y];
   *(void **)shifted_ra_location = *(void **)ra_location - 8;
   fs->retaddr_column = 0;
   fs->regs.reg[0].how = REG_SAVED_OFFSET;
-  fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
+  fs->regs.reg[0].loc.offset = (long)shifted_ra_location - new_cfa;
   fs->signal_frame = 1;
 
   return _URC_NO_REASON;
-};
-
-#endif
+}
index 1952af9..63318f1 100644 (file)
@@ -1,3 +1,9 @@
+2011-02-14  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
+
+       PR ada/41929
+       * gnat.dg/null_pointer_deref1.exp: Don't skip on
+       sparc*-sun-solaris2.11.
+
 2011-02-14  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/47349
index f845064..6e7bf14 100644 (file)
@@ -1,4 +1,4 @@
--- { dg-do run { target { ! "sparc*-sun-solaris2.11" } } }
+-- { dg-do run }
 -- { dg-options "-gnatp" }
 
 -- This test requires architecture- and OS-specific support code for unwinding