diff gcc/config/sparc/sol2-unwind.h @ 67:f6334be47118

update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
author nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
date Tue, 22 Mar 2011 17:18:12 +0900
parents 77e2b8dfacca
children
line wrap: on
line diff
--- a/gcc/config/sparc/sol2-unwind.h	Tue May 25 18:58:51 2010 +0900
+++ b/gcc/config/sparc/sol2-unwind.h	Tue Mar 22 17:18:12 2011 +0900
@@ -1,5 +1,5 @@
 /* DWARF2 EH unwinding support for SPARC Solaris.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -26,203 +26,129 @@
    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;
+  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)
 
-  /* This is the observed pattern for the sigacthandler in Solaris 8.  */
-  unsigned int sigacthandler_sol8_pattern []
-    = {0x9401400f, 0xca5aafa0, 0x913e2000, 0x892a3003,
-       0xe0590005, 0x9fc40000, 0x9410001a, 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.
 
-  /* This is the observed pattern for the sigacthandler in Solaris 9.  */ 
-  unsigned int sigacthandler_sol9_pattern []
-    = {0xa33e2000, 0x00000000, 0x892c7003, 0x90100011,
-       0xe0590005, 0x9fc40000, 0x9410001a, 0x80a46008};
+	   <sigacthandler+24>:  sra  %i0, 0, %l1
 
-  /* This is the observed pattern for the __sighndlr.  */
-  unsigned int sighndlr_pattern []
-    = {0x9de3bf50, 0x90100018, 0x92100019, 0x9fc6c000,
-       0x9410001a, 0x81c7e008, 0x81e80000};
+	   Solaris 9 5/02:
+	   <sigacthandler+28>:  ldx  [ %o2 + 0xf68 ], %g5
+	   Solaris 9 9/05:
+	   <sigacthandler+28>:  ldx  [ %o2 + 0xe50 ], %g5
 
-  /* Deal with frame-less function from which a signal was raised.  */
-  if (_Unwind_IsSignalFrame (context))
+	   <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;
+      /* We need to move up one frame:
 
-      /* This is the canonical RA column.  */
-      fs->retaddr_column = 15;
-
-      return _URC_NO_REASON;
+		<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;
+  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)
+    {
+      if (/* Solaris 8 /usr/lib/sparcv9/libthread.so.1
+	    ------------------------------------------
+	    Before patch 108827-08:
+	    <sigacthandler+1760>:     st  %g4, [ %i1 + 0x1c ]
 
-  /* 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] )
-    {
-      /* 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);
+	    Since patch 108827-08:
+	    <sigacthandler+1816>:     st  %l0, [ %i4 + 0x10 ]  */
+	        savpc[-1] == 0xc826601c
+	     || savpc[-1] == 0xe0272010)
+	{
+	  /* We need to move up three frames:
 
-      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;
+		<signal handler>	<-- context->cfa
+		__sighndlr
+		sigacthandler
+		<kernel>
+	  */
+	  *nframes = 2;
+	}
+      else /* Solaris 8 /usr/lib/lwp/sparcv9/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;
     }
 
-  /* 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;
+  return 0;
+}
 
-      /* 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++)
-	{
-	  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;
-	}
-    }
-
-  /* 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;
-}
+#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
 
 #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
 
@@ -238,42 +164,150 @@
       && 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))
     {
@@ -288,91 +322,27 @@
       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;
+  if (IS_SIGHANDLER (pc, (unsigned int *)fp->fr_savpc, &nframes))
+    {
+      struct handler_args {
+	struct frame frwin;
+	ucontext_t ucontext;
+      } *handler_args;
+      ucontext_t *ucp;
 
-  /* 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;
+      /* context->cfa points into the frame after the saved frame pointer and
+         saved pc (struct frame).
 
-  /* 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] )
-    {
-      /* 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);
+         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.  */
 
-      if (cuh_pattern == 0xd407a04c)
-	/* This matches the call_user_handler pattern for Solaris 10.
-	   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;
+      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
@@ -380,32 +350,13 @@
   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);
+  new_cfa = mctx->gregs[REG_SP];
+  /* The frame address is %sp + STACK_BIAS in 64-bit mode.  */
+  new_cfa += STACK_BIAS;
 
-  /* 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));
   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.  */
@@ -415,44 +366,54 @@
       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)
+  /* Check whether we need to restore FPU registers.  */
+  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
+}