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 <hain...@adacore.com> Rainer Orth <r...@cebitec.uni-bielefeld.de> libgcc: * config/mips/irix6-unwind.h: New file. * config.host (mips-sgi-irix6.5*): Set md_unwind_header. 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; +} -- ----------------------------------------------------------------------------- Rainer Orth, Center for Biotechnology, Bielefeld University