Imported Upstream version 4.7.2
[platform/upstream/gcc48.git] / libgcc / config / mips / irix6-unwind.h
1 /* DWARF2 EH unwinding support for MIPS IRIX 6.
2    Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
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.
10
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.
15
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.
19
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/>.  */
24
25 /* Do code reading to identify a signal frame, and set the frame
26    state data appropriately.  See unwind-dw2.c for the structs.  */
27
28 /* This code was developed-for and only tested-in limited ABI
29    configurations.  Characterize that.  */
30
31 #if defined (_ABIN32) || defined (_ABI64)
32 #define SUPPORTED_ABI 1
33 #else
34 #define SUPPORTED_ABI 0
35 #endif
36
37 #include <signal.h>
38
39 #define MD_FALLBACK_FRAME_STATE_FOR mips_fallback_frame_state
40
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.  */
44
45 static sigcontext_t *
46 sigcontext_for (unsigned int *ra, void *cfa)
47 {
48   /* IRIX 6.5, mono-threaded application.  We're lucky enough to be able
49      to expect a short very sighandler specific sequence around.
50
51      <_sigtramp+124>:   li      v0,1088 (SYS_sigreturn)
52      <_sigtramp+128>:   syscall  */
53
54   if (   ra[6] == 0x24020440
55       && ra[7] == 0x0000000c)
56     return (sigcontext_t *)(cfa + 0x30);
57
58   /* IRIX 6.5 variants, multi-threaded application, pthreads.  Nothing really
59      sighandler specific handy, so match a fairly long constant sequence.  */
60
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)
85
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);
110
111   return 0;
112 }
113
114 #define SIGCTX_GREG_ADDR(REGNO,SIGCTX) \
115   ((void *) &(SIGCTX)->sc_regs[REGNO])
116
117 #define SIGCTX_FPREG_ADDR(REGNO,SIGCTX) \
118   ((void *) &(SIGCTX)->sc_fpregs[REGNO])
119
120 static _Unwind_Reason_Code
121 mips_fallback_frame_state (struct _Unwind_Context *context,
122                            _Unwind_FrameState *fs)
123 {
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;
128
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;
133
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;
138
139   if (! SUPPORTED_ABI)
140     return _URC_END_OF_STACK;
141     
142   sigctx = sigcontext_for (ctx_ra, ctx_cfa);
143
144   if (sigctx == 0)
145     return _URC_END_OF_STACK;
146
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);
150
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;
157
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 ++)
161     {
162       fs->regs.reg[i].how = REG_SAVED_OFFSET;
163       fs->regs.reg[i].loc.offset = SIGCTX_GREG_ADDR (i, sigctx) - k_cfa;
164     }
165
166   for (i = 0; i <= 31; i ++)
167     {
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;
170     }
171
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;
178
179   return _URC_NO_REASON;
180 }