Patchwork unwinding fallback for mips-irix6 n32

login
register
mail settings
Submitter Rainer Orth
Date June 10, 2011, 11:03 a.m.
Message ID <yddaadqaqxs.fsf@manam.CeBiTec.Uni-Bielefeld.DE>
Download mbox | patch
Permalink /patch/99883/
State New
Headers show

Comments

Rainer Orth - June 10, 2011, 11:03 a.m.
Hello Olivier,

> We have been using an unwinding fallback on mips-irix6/n32 for a while
> (number of years) across different versions of GCC (3.4, 4.1, 4.3, and
> 4.5 lately).
>
> We haven't submitted this for inclusion so far because of the pretty
> limited range of supported configurations (irix 6, n32 abi only).
>
> Exchanges offlist suggested that it could be of interest nevertheless,
> so here it is.
>
> Our latest port was to gcc 4.5. The attached patch is a minor
> adaptation of that to mainline. I tested that a non bootstrap build
> proceeds fine and that a basic test involving SEGV in Ada works as
> expected.
>
> Rainer kindly offered to perform more thorough testing, to validate
> that this indeed reduces the amount of failures he has been observing.

I've finally gotten around to this.  Apart from some comment and code
cleanups along the lines of the sol2-unwind.h files, I had to minimally
adapt the N32 multithreaded code sequence for IRIX 6.5.30 that I'm
running here.  While I was at it, I added N64 support which proved to be
almost trivial.  You'll probably have to adapt this for the version of
IRIX 6.5 you're running, or we could simply skip the single varying
insn.

With this patch, a couple of gnat.dg tests are fixed:

* N32:

-FAIL: gnat.dg/null_pointer_deref1.adb execution test
-FAIL: gnat.dg/null_pointer_deref2.adb execution test
-FAIL: gnat.dg/stack_check1.adb execution test
-FAIL: gnat.dg/stack_check2.adb execution test

* N64:

-FAIL: gnat.dg/null_pointer_deref1.adb execution test
-FAIL: gnat.dg/null_pointer_deref2.adb execution test
-FAIL: gnat.dg/stack_check1.adb execution test

64-bit stack_check2.adb remains broken, though.  It SEGVs in memcpy, but
the stack is corrupted, so I cannot say yet what's going on.

I'll run a full bootstrap over the weekend.  It seems that the remaining
libjava failures are unrelated.

I may backport this to the 4.6 branch after some time (trivial apart
from the gcc -> libgcc move).  I will only try 4.5 if I manage to add
O32 support.  This might be a non-trivial excercise since the libc
implementation is quite different.

Thanks for providing the patch.  

	Rainer


2011-05-29  Olivier Hainque  <hainque@adacore.com>
	    Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	libgcc:
	* config/mips/irix6-unwind.h: New file.
	* config.host (mips-sgi-irix6.5*): Set md_unwind_header.
Olivier Hainque - June 16, 2011, 12:55 p.m.
Hi Rainer,

Rainer Orth wrote:
> I've finally gotten around to this.  Apart from some comment and code
> cleanups along the lines of the sol2-unwind.h files, I had to minimally
> adapt the N32 multithreaded code sequence for IRIX 6.5.30 that I'm
> running here.  While I was at it, I added N64 support which proved to be
> almost trivial.  You'll probably have to adapt this for the version of
> IRIX 6.5 you're running, or we could simply skip the single varying
> insn.
 
 Either way is fine with me. There's a micro stronger confidence
 in exact matches, but this could lead to spurious propagation failures
 on other variants of the OS where a third version of that insn
 could show up while still part of a valid context.

> With this patch, a couple of gnat.dg tests are fixed:

 Nice :)

> 64-bit stack_check2.adb remains broken, though.  It SEGVs in memcpy, but
> the stack is corrupted, so I cannot say yet what's going on.
> 
> I'll run a full bootstrap over the weekend.  It seems that the remaining
> libjava failures are unrelated.

 OK ...
 
> I may backport this to the 4.6 branch after some time (trivial apart
> from the gcc -> libgcc move).  I will only try 4.5 if I manage to add
> O32 support.  This might be a non-trivial excercise since the libc
> implementation is quite different.

 Understood;

> Thanks for providing the patch.  

 My pleasure. Thanks a lot for your work over it and feedback, much
 appreciated.

 Cheers,

 Olivier
Rainer Orth - June 17, 2011, 1:16 p.m.
Hi Olivier,

> Rainer Orth wrote:
>> I've finally gotten around to this.  Apart from some comment and code
>> cleanups along the lines of the sol2-unwind.h files, I had to minimally
>> adapt the N32 multithreaded code sequence for IRIX 6.5.30 that I'm
>> running here.  While I was at it, I added N64 support which proved to be
>> almost trivial.  You'll probably have to adapt this for the version of
>> IRIX 6.5 you're running, or we could simply skip the single varying
>> insn.
>  
>  Either way is fine with me. There's a micro stronger confidence
>  in exact matches, but this could lead to spurious propagation failures
>  on other variants of the OS where a third version of that insn
>  could show up while still part of a valid context.

agreed: if the number variations we observe remain in the 3-5 range, we
can continue with matching all of them.  I've installed the patch in the
meantime, so feel free to update it with the N64 variants you see on
IRIX != 6.5.30 (might even vary in patches, though).

>> 64-bit stack_check2.adb remains broken, though.  It SEGVs in memcpy, but
>> the stack is corrupted, so I cannot say yet what's going on.

Still can't, but am currently looking into the remaining libjava failures.

>> I'll run a full bootstrap over the weekend.  It seems that the remaining
>> libjava failures are unrelated.
>
>  OK ...

They were, but libjava on both IRIX and Tru64 UNIX didn't make use of
MD_FALLBACK_FRAME_STATE_FOR yet.  I've just fixed that, which allowed me
to get rid of another testsuite failure there.

Thanks.
        Rainer

Patch

diff --git a/libgcc/config.host b/libgcc/config.host
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -456,6 +456,7 @@  microblaze*-*-*)
 mips-sgi-irix6.5*)
 	tmake_file="mips/t-irix6 t-crtfm t-slibgcc mips/t-slibgcc-irix"
 	extra_parts="crtbegin.o crtend.o crtfastmath.o irix-crti.o irix-crtn.o"
+	md_unwind_header=mips/irix6-unwind.h
 	;;
 mips*-*-netbsd*)			# NetBSD/mips, either endian.
 	;;
diff --git a/libgcc/config/mips/irix6-unwind.h b/libgcc/config/mips/irix6-unwind.h
new file mode 100644
--- /dev/null
+++ b/libgcc/config/mips/irix6-unwind.h
@@ -0,0 +1,180 @@ 
+/* DWARF2 EH unwinding support for MIPS IRIX 6.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/* Do code reading to identify a signal frame, and set the frame
+   state data appropriately.  See unwind-dw2.c for the structs.  */
+
+/* This code was developed-for and only tested-in limited ABI
+   configurations.  Characterize that.  */
+
+#if defined (_ABIN32) || defined (_ABI64)
+#define SUPPORTED_ABI 1
+#else
+#define SUPPORTED_ABI 0
+#endif
+
+#include <signal.h>
+
+#define MD_FALLBACK_FRAME_STATE_FOR mips_fallback_frame_state
+
+/* Look at the code around RA to see if it matches a sighandler caller with a
+   sigcontext_t * argument (SA_SIGINFO cleared).  Return that pointer argument
+   if it does match, or 0 otherwise.  */
+
+static sigcontext_t *
+sigcontext_for (unsigned int *ra, void *cfa)
+{
+  /* IRIX 6.5, mono-threaded application.  We're lucky enough to be able
+     to expect a short very sighandler specific sequence around.
+
+     <_sigtramp+124>:	li	v0,1088 (SYS_sigreturn)
+     <_sigtramp+128>:	syscall  */
+
+  if (   ra[6] == 0x24020440
+      && ra[7] == 0x0000000c)
+    return (sigcontext_t *)(cfa + 0x30);
+
+  /* IRIX 6.5 variants, multi-threaded application, pthreads.  Nothing really
+     sighandler specific handy, so match a fairly long constant sequence.  */
+
+#if _MIPS_SIM == _ABIN32
+  /* 
+     <sig_fixup_mask+40>:	sd	s0,0(sp)
+     <sig_fixup_mask+44>:	sll	ra,a0,0x2
+     <sig_fixup_mask+48>:	addiu	t9,t9,-28584/-28456/-28448
+     <sig_fixup_mask+52>:	lw	s0,3804(at)
+     <sig_fixup_mask+56>:	addu	t9,t9,ra
+     <sig_fixup_mask+60>:	lw	t9,0(t9)
+     <sig_fixup_mask+64>:	ld	at,3696(at)
+     <sig_fixup_mask+68>:	ld	s2,88(s0)
+     <sig_fixup_mask+72>:	jalr	t9
+     <sig_fixup_mask+76>:	sd	at,88(s0)  */
+   if (   ra[-10] == 0xffb00000
+      && ra[ -9] == 0x0004f880
+      && (ra[-8] == 0x27399058
+	  || ra[-8] == 0x273990d8
+	  || ra[-8] == 0x273990e0)
+      && ra[ -7] == 0x8c300edc
+      && ra[ -6] == 0x033fc821
+      && ra[ -5] == 0x8f390000
+      && ra[ -4] == 0xdc210e70
+      && ra[ -3] == 0xde120058
+      && ra[ -2] == 0x0320f809
+      && ra[ -1] == 0xfe010058)
+
+#elif _MIPS_SIM == _ABI64
+  /* 
+     <sig_fixup_mask+44>:	sd	s0,0(sp)
+     <sig_fixup_mask+48>:	daddu	t9,t9,ra
+     <sig_fixup_mask+52>:	dsll	ra,a0,0x3
+     <sig_fixup_mask+56>:	ld	s0,3880(at)
+     <sig_fixup_mask+60>:	daddu	t9,t9,ra
+     <sig_fixup_mask+64>:	ld	t9,0(t9)
+     <sig_fixup_mask+68>:	ld	at,3696(at)
+     <sig_fixup_mask+72>:	ld	s2,152(s0)
+     <sig_fixup_mask+76>:	jalr	t9
+     <sig_fixup_mask+80>:	sd	at,152(s0)  */
+  if (   ra[-10] == 0xffb00000
+      && ra[ -9] == 0x033fc82d
+      && ra[ -8] == 0x0004f8f8
+      && ra[ -7] == 0xdc300f28
+      && ra[ -6] == 0x033fc82d
+      && ra[ -5] == 0xdf390000
+      && ra[ -4] == 0xdc210e70
+      && ra[ -3] == 0xde120098
+      && ra[ -2] == 0x0320f809
+      && ra[ -1] == 0xfe010098)
+#endif
+    return (sigcontext_t *)(cfa + 0x60);
+
+  return 0;
+}
+
+#define SIGCTX_GREG_ADDR(REGNO,SIGCTX) \
+  ((void *) &(SIGCTX)->sc_regs[REGNO])
+
+#define SIGCTX_FPREG_ADDR(REGNO,SIGCTX) \
+  ((void *) &(SIGCTX)->sc_fpregs[REGNO])
+
+static _Unwind_Reason_Code
+mips_fallback_frame_state (struct _Unwind_Context *context,
+			   _Unwind_FrameState *fs)
+{
+  /* Return address and CFA of the frame we're attempting to unwind through,
+     possibly a signal handler.  */
+  void *ctx_ra  = (void *)context->ra;
+  void *ctx_cfa = (void *)context->cfa;
+
+  /* CFA of the intermediate abstract kernel frame between the interrupted
+     code and the signal handler, if we're indeed unwinding through a signal
+     handler.  */
+  void *k_cfa;
+
+  /* Pointer to the sigcontext_t structure pushed by the kernel when we're
+     unwinding through a signal handler setup with SA_SIGINFO cleared.  */
+  sigcontext_t *sigctx;
+  int i;
+
+  if (! SUPPORTED_ABI)
+    return _URC_END_OF_STACK;
+    
+  sigctx = sigcontext_for (ctx_ra, ctx_cfa);
+
+  if (sigctx == 0)
+    return _URC_END_OF_STACK;
+
+  /* The abstract kernel frame's CFA is extactly the stack pointer
+     value at the interruption point.  */
+  k_cfa = *(void **)SIGCTX_GREG_ADDR (CTX_SP, sigctx);
+
+  /* State the rules to compute the CFA we have the value of: use the
+     previous CFA and offset by the difference between the two.  See
+     uw_update_context_1 for the supporting details.  */
+  fs->regs.cfa_how = CFA_REG_OFFSET;
+  fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
+  fs->regs.cfa_offset = k_cfa - ctx_cfa;
+
+  /* Fill the internal frame_state structure with information stating where
+     each register of interest can be found from the CFA.  */
+  for (i = 0; i <= 31; i ++)
+    {
+      fs->regs.reg[i].how = REG_SAVED_OFFSET;
+      fs->regs.reg[i].loc.offset = SIGCTX_GREG_ADDR (i, sigctx) - k_cfa;
+    }
+
+  for (i = 0; i <= 31; i ++)
+    {
+      fs->regs.reg[32+i].how = REG_SAVED_OFFSET;
+      fs->regs.reg[32+i].loc.offset = SIGCTX_FPREG_ADDR (i, sigctx) - k_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.  */
+  fs->retaddr_column = DWARF_FRAME_RETURN_COLUMN;
+  fs->regs.reg[fs->retaddr_column].how = REG_SAVED_OFFSET;
+  fs->regs.reg[fs->retaddr_column].loc.offset = (void *)&sigctx->sc_pc - k_cfa;
+  fs->signal_frame = 1;
+
+  return _URC_NO_REASON;
+}