Committing forgotten headers from r185218.
[official-gcc.git] / libgcc / config / mips / irix6-unwind.h
blobe862560fe341a9fbacfcb0718bf6e9506999c8ee
1 /* DWARF2 EH unwinding support for MIPS IRIX 6.
2 Copyright (C) 2011 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 /* Do code reading to identify a signal frame, and set the frame
26 state data appropriately. See unwind-dw2.c for the structs. */
28 /* This code was developed-for and only tested-in limited ABI
29 configurations. Characterize that. */
31 #if defined (_ABIN32) || defined (_ABI64)
32 #define SUPPORTED_ABI 1
33 #else
34 #define SUPPORTED_ABI 0
35 #endif
37 #include <signal.h>
39 #define MD_FALLBACK_FRAME_STATE_FOR mips_fallback_frame_state
41 /* Look at the code around RA to see if it matches a sighandler caller with a
42 sigcontext_t * argument (SA_SIGINFO cleared). Return that pointer argument
43 if it does match, or 0 otherwise. */
45 static sigcontext_t *
46 sigcontext_for (unsigned int *ra, void *cfa)
48 /* IRIX 6.5, mono-threaded application. We're lucky enough to be able
49 to expect a short very sighandler specific sequence around.
51 <_sigtramp+124>: li v0,1088 (SYS_sigreturn)
52 <_sigtramp+128>: syscall */
54 if ( ra[6] == 0x24020440
55 && ra[7] == 0x0000000c)
56 return (sigcontext_t *)(cfa + 0x30);
58 /* IRIX 6.5 variants, multi-threaded application, pthreads. Nothing really
59 sighandler specific handy, so match a fairly long constant sequence. */
61 #if _MIPS_SIM == _ABIN32
62 /*
63 <sig_fixup_mask+40>: sd s0,0(sp)
64 <sig_fixup_mask+44>: sll ra,a0,0x2
65 <sig_fixup_mask+48>: addiu t9,t9,-28584/-28456/-28448
66 <sig_fixup_mask+52>: lw s0,3804(at)
67 <sig_fixup_mask+56>: addu t9,t9,ra
68 <sig_fixup_mask+60>: lw t9,0(t9)
69 <sig_fixup_mask+64>: ld at,3696(at)
70 <sig_fixup_mask+68>: ld s2,88(s0)
71 <sig_fixup_mask+72>: jalr t9
72 <sig_fixup_mask+76>: sd at,88(s0) */
73 if ( ra[-10] == 0xffb00000
74 && ra[ -9] == 0x0004f880
75 && (ra[-8] == 0x27399058
76 || ra[-8] == 0x273990d8
77 || ra[-8] == 0x273990e0)
78 && ra[ -7] == 0x8c300edc
79 && ra[ -6] == 0x033fc821
80 && ra[ -5] == 0x8f390000
81 && ra[ -4] == 0xdc210e70
82 && ra[ -3] == 0xde120058
83 && ra[ -2] == 0x0320f809
84 && ra[ -1] == 0xfe010058)
86 #elif _MIPS_SIM == _ABI64
87 /*
88 <sig_fixup_mask+44>: sd s0,0(sp)
89 <sig_fixup_mask+48>: daddu t9,t9,ra
90 <sig_fixup_mask+52>: dsll ra,a0,0x3
91 <sig_fixup_mask+56>: ld s0,3880(at)
92 <sig_fixup_mask+60>: daddu t9,t9,ra
93 <sig_fixup_mask+64>: ld t9,0(t9)
94 <sig_fixup_mask+68>: ld at,3696(at)
95 <sig_fixup_mask+72>: ld s2,152(s0)
96 <sig_fixup_mask+76>: jalr t9
97 <sig_fixup_mask+80>: sd at,152(s0) */
98 if ( ra[-10] == 0xffb00000
99 && ra[ -9] == 0x033fc82d
100 && ra[ -8] == 0x0004f8f8
101 && ra[ -7] == 0xdc300f28
102 && ra[ -6] == 0x033fc82d
103 && ra[ -5] == 0xdf390000
104 && ra[ -4] == 0xdc210e70
105 && ra[ -3] == 0xde120098
106 && ra[ -2] == 0x0320f809
107 && ra[ -1] == 0xfe010098)
108 #endif
109 return (sigcontext_t *)(cfa + 0x60);
111 return 0;
114 #define SIGCTX_GREG_ADDR(REGNO,SIGCTX) \
115 ((void *) &(SIGCTX)->sc_regs[REGNO])
117 #define SIGCTX_FPREG_ADDR(REGNO,SIGCTX) \
118 ((void *) &(SIGCTX)->sc_fpregs[REGNO])
120 static _Unwind_Reason_Code
121 mips_fallback_frame_state (struct _Unwind_Context *context,
122 _Unwind_FrameState *fs)
124 /* Return address and CFA of the frame we're attempting to unwind through,
125 possibly a signal handler. */
126 void *ctx_ra = (void *)context->ra;
127 void *ctx_cfa = (void *)context->cfa;
129 /* CFA of the intermediate abstract kernel frame between the interrupted
130 code and the signal handler, if we're indeed unwinding through a signal
131 handler. */
132 void *k_cfa;
134 /* Pointer to the sigcontext_t structure pushed by the kernel when we're
135 unwinding through a signal handler setup with SA_SIGINFO cleared. */
136 sigcontext_t *sigctx;
137 int i;
139 if (! SUPPORTED_ABI)
140 return _URC_END_OF_STACK;
142 sigctx = sigcontext_for (ctx_ra, ctx_cfa);
144 if (sigctx == 0)
145 return _URC_END_OF_STACK;
147 /* The abstract kernel frame's CFA is extactly the stack pointer
148 value at the interruption point. */
149 k_cfa = *(void **)SIGCTX_GREG_ADDR (CTX_SP, sigctx);
151 /* State the rules to compute the CFA we have the value of: use the
152 previous CFA and offset by the difference between the two. See
153 uw_update_context_1 for the supporting details. */
154 fs->regs.cfa_how = CFA_REG_OFFSET;
155 fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
156 fs->regs.cfa_offset = k_cfa - ctx_cfa;
158 /* Fill the internal frame_state structure with information stating where
159 each register of interest can be found from the CFA. */
160 for (i = 0; i <= 31; i ++)
162 fs->regs.reg[i].how = REG_SAVED_OFFSET;
163 fs->regs.reg[i].loc.offset = SIGCTX_GREG_ADDR (i, sigctx) - k_cfa;
166 for (i = 0; i <= 31; i ++)
168 fs->regs.reg[32+i].how = REG_SAVED_OFFSET;
169 fs->regs.reg[32+i].loc.offset = SIGCTX_FPREG_ADDR (i, sigctx) - k_cfa;
172 /* State the rules to find the kernel's code "return address", which is the
173 address of the active instruction when the signal was caught. */
174 fs->retaddr_column = DWARF_FRAME_RETURN_COLUMN;
175 fs->regs.reg[fs->retaddr_column].how = REG_SAVED_OFFSET;
176 fs->regs.reg[fs->retaddr_column].loc.offset = (void *)&sigctx->sc_pc - k_cfa;
177 fs->signal_frame = 1;
179 return _URC_NO_REASON;