Patchwork Support Solaris 9, 11/x86 in MD_FALLBACK_FRAME_STATE_FOR

login
register
mail settings
Submitter Rainer Orth
Date July 12, 2010, 4:18 p.m.
Message ID <yddk4p0smgw.fsf@manam.CeBiTec.Uni-Bielefeld.DE>
Download mbox | patch
Permalink /patch/58633/
State New
Headers show

Comments

Rainer Orth - July 12, 2010, 4:18 p.m.
This is a considerably reworked version of my earlier patch

	PATCH: Fix Solaris 11/x86 MD_FALLBACK_FRAME_STATE_FOR
        http://gcc.gnu.org/ml/gcc-patches/2010-02/msg00994.html

The problem is that a couple of ACATS and libjava tests were failing on
Solaris 9 and 11 because MD_FALLBACK_FRAME_STATE_FOR returned
_URC_END_OF_STACK.  There were several problems:

* There were no 32-bit sigacthandler patterns for Solaris 9
  (single-threaded only, multi-threaded is identical to Solaris 10) nor
  __sighndlr patterns for Solaris 11.  Solaris 11 actually needs two
  different ones, as learned by inspection of the OpenSolaris libc
  sources

  http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libc/i386/threads/asm_subr.s#94

  The change occured in build 125, but I haven't yet tried that part of
  the code.

* The 64-bit case is more involved.  While my original patch worked on
  Solaris 11, it caused Solaris 10 to regress.  I started several
  attempts to work out the offset from the signal handler frame to the
  ucontext_t structure in the kernel frame, but unfortunately the
  offsets vary even between different Solaris 10 updates and the whole
  procedure is incredibly fragile.  Finally, I gave up and decided to
  walk the stack instead.

  The layout of the kernel frame can be confirmed from the OpenSolaris
  sources:

  http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/intel/ia32/os/sendsig.c#105

  I'd have liked to use the unwinder routines for the stack walking
  (e.g. some new _Unwind_BacktraceFrom function that takes a context to
  start from (i.e. the context argument to MD_FALLBACK_FRAME_STATE_FOR
  instead of the current context), but couldn't get this to work, so I'm
  doing the walking myself.

The patch was tested on Solaris 8 to 11 and fixed all EH problems found
there.  One problem is that the 64-bit stack unwinding relies on the
frame pointer now, which doesn't work with libjava out of the box since
that is built with -fomit-frame-pointer by default.  I'll post an
updated patch for that soon.

Will soon commit to mainline and backport to the 4.4 and 4.5 branches.

	Rainer


2010-02-17  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	* config/i386/sol2-unwind.h (x86_64_fallback_frame_state): Correct
	explanation.
	Find ucontext_t * on Solaris 11.
	(x86_fallback_frame_state): Handle Solaris 9 multi-threaded pattern.
	Handle new Solaris 11 __sighndlr patterns.

Patch

diff -r 927eaa7fb82d gcc/config/i386/sol2-unwind.h
--- a/gcc/config/i386/sol2-unwind.h	Fri Jul 09 22:53:24 2010 +0200
+++ b/gcc/config/i386/sol2-unwind.h	Mon Jul 12 09:29:23 2010 +0200
@@ -1,5 +1,5 @@ 
 /* DWARF2 EH unwinding support for AMD x86-64 and x86.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -26,6 +26,7 @@ 
    state data appropriately.  See unwind-dw2.c for the structs.  */
 
 #include <ucontext.h>
+#include <sys/frame.h>
 
 #ifdef __x86_64__
 
@@ -39,7 +40,7 @@ 
   mcontext_t *mctx;
   long new_cfa;
 
-  if (/* Solaris 2.10
+  if (/* Solaris 10+
 	------------
 	<__sighndlr+0>:      push   %rbp
 	<__sighndlr+1>:      mov    %rsp,%rbp
@@ -47,15 +48,41 @@ 
 	<__sighndlr+6>:      leaveq           <--- PC
 	<__sighndlr+7>:      retq  */
       *(unsigned long *)(pc - 6) == 0xc3c9d1ffe5894855)
-    /* We need to move up four frames (the kernel frame, the signal frame,
-       the call_user_handler frame and the __sighndlr frame).  Two of them
-       have the minimum stack frame size (kernel and __sighndlr frames),
-       the signal frame has a stack frame size of 32 and there is another
-       with a stack frame size of 112 bytes (the call_user_handler frame).
-       The ucontext_t structure is after this offset.  */
+
+    /* We need to move up three frames:
+
+		<signal handler>	<-- context->cfa
+		__sighndlr
+		call_user_handler
+		sigacthandler
+		<kernel>
+
+       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 the signal
+       number and a siginfo_t *.  Since the frame sizes vary even within
+       Solaris 10 updates, we need to walk the stack to get there.  */
     {
-      int off = 16 + 16 + 32 + 112;
-      mctx = &((ucontext_t *) (context->cfa + off))->uc_mcontext;
+      struct frame *fp = (struct frame *) context->cfa - 1;
+      struct handler_args {
+	int signo;
+	siginfo_t *sip;
+	ucontext_t ucontext;
+      } *handler_args;
+      ucontext_t *ucp;
+
+      /* Next frame: __sighndlr frame pointer.  */
+      fp = (struct frame *) fp->fr_savfp;
+      /* call_user_handler frame pointer.  */
+      fp = (struct frame *) fp->fr_savfp;
+      /* sigacthandler frame pointer.  */
+      fp = (struct frame *) fp->fr_savfp;
+
+      /* The argument area precedes the struct frame.  */
+      handler_args = (struct handler_args *) (fp + 1);
+      ucp = &handler_args->ucontext;
+      mctx = &ucp->uc_mcontext;
     }
   else
     return _URC_END_OF_STACK;
@@ -117,8 +144,8 @@ 
   mcontext_t *mctx;
   long new_cfa;
 
-  if (/* Solaris 2.8 - single thread
-	-------------------------
+  if (/* Solaris 8 - single-threaded
+	----------------------------
 	<sigacthandler+17>:  mov    0x10(%ebp),%esi
 	<sigacthandler+20>:  push   %esi
 	<sigacthandler+21>:  pushl  0xc(%ebp)
@@ -135,7 +162,7 @@ 
        && *(unsigned long *)(pc - 4)  == 0x8814ff00
        && *(unsigned long *)(pc - 0)  == 0x560cc483)
 
-      || /* Solaris 2.8 - multi thread
+      || /* Solaris 8 - multi-threaded
 	   ---------------------------
 	   <__sighndlr+0>:      push   %ebp
 	   <__sighndlr+1>:      mov    %esp,%ebp
@@ -149,8 +176,26 @@ 
 	  && *(unsigned long *)(pc - 7)  == 0x0875ff0c
 	  && *(unsigned long *)(pc - 3)  == 0xc91455ff)
 
-      || /* Solaris 2.10
-	   ------------
+      || /* Solaris 9 - single-threaded
+	   ----------------------------
+           <sigacthandler+16>:    mov    0x244(%ebx),%ecx
+	   <sigacthandler+22>:    mov    0x8(%ebp),%eax
+	   <sigacthandler+25>:    mov    (%ecx,%eax,4),%ecx
+	   <sigacthandler+28>:    pushl  0x10(%ebp)
+	   <sigacthandler+31>:    pushl  0xc(%ebp)
+	   <sigacthandler+34>:    push   %eax
+	   <sigacthandler+35>:    call   *%ecx
+	   <sigacthandler+37>:    add    $0xc,%esp	<--- PC
+	   <sigacthandler+40>:    pushl  0x10(%ebp) */
+         (*(unsigned long *)(pc - 21) == 0x2448b8b
+	  && *(unsigned long *)(pc - 17) == 0x458b0000
+	  && *(unsigned long *)(pc - 13) == 0x810c8b08
+	  && *(unsigned long *)(pc - 9)  == 0xff1075ff
+	  && *(unsigned long *)(pc - 5)  == 0xff500c75
+	  && *(unsigned long *)(pc - 1)  == 0xcc483d1)
+
+      || /* Solaris 9 - multi-threaded, Solaris 10
+	   ---------------------------------------
 	   <__sighndlr+0>:      push   %ebp
 	   <__sighndlr+1>:      mov    %esp,%ebp
 	   <__sighndlr+3>:      pushl  0x10(%ebp)
@@ -164,7 +209,43 @@ 
 	  && *(unsigned long *)(pc - 11) == 0x75ff1075
 	  && *(unsigned long *)(pc - 7)  == 0x0875ff0c
 	  && *(unsigned long *)(pc - 3)  == 0x831455ff
-	  && *(unsigned long *)(pc + 1)  == 0xc3c90cc4))
+	  && *(unsigned long *)(pc + 1)  == 0xc3c90cc4)
+
+      || /* Solaris 11 before snv_125
+	   --------------------------
+	  <__sighndlr+0>       	push   %ebp
+	  <__sighndlr+1>       	mov    %esp,%ebp
+	  <__sighndlr+4>      	pushl  0x10(%ebp)
+	  <__sighndlr+6>      	pushl  0xc(%ebp)
+	  <__sighndlr+9>      	pushl  0x8(%ebp)
+	  <__sighndlr+12>      	call   *0x14(%ebp)
+	  <__sighndlr+15>	add    $0xc,%esp
+	  <__sighndlr+18>      	leave                <--- PC
+	  <__sighndlr+19>      	ret  */
+	 (*(unsigned long *)(pc - 18) == 0xffec8b55
+	  && *(unsigned long *)(pc - 14) == 0x7fff107f
+	  && *(unsigned long *)(pc - 10)  == 0x0875ff0c
+	  && *(unsigned long *)(pc - 6)  == 0x83145fff
+	  && *(unsigned long *)(pc - 1)  == 0xc3c90cc4)
+
+      || /* Solaris 11 since snv_125
+	   -------------------------
+	  <__sighndlr+0>       	push   %ebp
+	  <__sighndlr+1>       	mov    %esp,%ebp
+	  <__sighndlr+3>       	and    $0xfffffff0,%esp
+	  <__sighndlr+6>       	sub    $0x4,%esp
+	  <__sighndlr+9>      	pushl  0x10(%ebp)
+	  <__sighndlr+12>      	pushl  0xc(%ebp)
+	  <__sighndlr+15>      	pushl  0x8(%ebp)
+	  <__sighndlr+18>      	call   *0x14(%ebp)
+	  <__sighndlr+21>      	leave                <--- PC
+	  <__sighndlr+22>      	ret  */
+	 (*(unsigned long *)(pc - 21) == 0x83ec8b55
+	  && *(unsigned long *)(pc - 17) == 0xec83f0e4
+	  && *(unsigned long *)(pc - 13)  == 0x1075ff04
+	  && *(unsigned long *)(pc - 9)  == 0xff0c75ff
+	  && *(unsigned long *)(pc - 5)  == 0x55ff0875
+	  && (*(unsigned long *)(pc - 1) & 0x00ffffff) == 0x00c3c914))
     {
       struct handler_args {
 	int signo;