diff options
author | Olivier Hainque <hainque@adacore.com> | 2011-06-14 12:20:08 +0000 |
---|---|---|
committer | Rainer Orth <ro@gcc.gnu.org> | 2011-06-14 12:20:08 +0000 |
commit | ea9639996561c240b57a58ff9db4b407489f7ac3 (patch) | |
tree | 0c4b65cf7456f0c5d2cdcfc35ad20a3bf9561cb3 /libgcc | |
parent | 37e1a18f04e97714fa63d486bbce76e28e22baa3 (diff) | |
download | gcc-ea9639996561c240b57a58ff9db4b407489f7ac3.zip gcc-ea9639996561c240b57a58ff9db4b407489f7ac3.tar.gz gcc-ea9639996561c240b57a58ff9db4b407489f7ac3.tar.bz2 |
irix6-unwind.h: New file.
2011-06-14 Olivier Hainque <hainque@adacore.com>
Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* config/mips/irix6-unwind.h: New file.
* config.host (mips-sgi-irix6.5*): Set md_unwind_header.
Co-Authored-By: Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
From-SVN: r175013
Diffstat (limited to 'libgcc')
-rw-r--r-- | libgcc/ChangeLog | 6 | ||||
-rw-r--r-- | libgcc/config.host | 1 | ||||
-rw-r--r-- | libgcc/config/mips/irix6-unwind.h | 180 |
3 files changed, 187 insertions, 0 deletions
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 06c7613..1ce7387 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,9 @@ +2011-06-14 Olivier Hainque <hainque@adacore.com> + Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * config/mips/irix6-unwind.h: New file. + * config.host (mips-sgi-irix6.5*): Set md_unwind_header. + 2011-06-10 Eric Botcazou <ebotcazou@adacore.com> * config/sparc/linux-unwind.h (STACK_BIAS): Define. diff --git a/libgcc/config.host b/libgcc/config.host index c2b5dbc..6ea7490 100644 --- 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 index 0000000..e862560 --- /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; +} |