OSDN Git Service

5374f8a61f9b4cc3c204631b3719440911aa0906
[pf3gnuchains/gcc-fork.git] / gcc / config / sh / linux-unwind.h
1 /* DWARF2 EH unwinding support for SH Linux.
2    Copyright (C) 2004, 2005, 2006 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 2, or (at your option)
9 any later version.
10
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file with other programs, and to distribute
14 those programs without any restriction coming from the use of this
15 file.  (The General Public License restrictions do apply in other
16 respects; for example, they cover modification of the file, and
17 distribution when not linked into another program.)
18
19 GCC is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING.  If not, write to
26 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
27 Boston, MA 02110-1301, USA.  */
28
29 /* Do code reading to identify a signal frame, and set the frame
30    state data appropriately.  See unwind-dw2.c for the structs.  */
31
32 #include <signal.h>
33 #include <sys/ucontext.h>
34 #include "insn-constants.h"
35
36 # if defined (__SH5__)
37 #define SH_DWARF_FRAME_GP0      0
38 #define SH_DWARF_FRAME_FP0      77
39 #define SH_DWARF_FRAME_BT0      68
40 #define SH_DWARF_FRAME_PR_MEDIA 18
41 #define SH_DWARF_FRAME_SR       65
42 #define SH_DWARF_FRAME_FPSCR    76
43 #else
44 #define SH_DWARF_FRAME_GP0      0
45 #define SH_DWARF_FRAME_FP0      25
46 #define SH_DWARF_FRAME_XD0      87
47 #define SH_DWARF_FRAME_PR       17
48 #define SH_DWARF_FRAME_GBR      19
49 #define SH_DWARF_FRAME_MACH     20
50 #define SH_DWARF_FRAME_MACL     21
51 #define SH_DWARF_FRAME_PC       16
52 #define SH_DWARF_FRAME_SR       22
53 #define SH_DWARF_FRAME_FPUL     23
54 #define SH_DWARF_FRAME_FPSCR    24
55 #endif /* defined (__SH5__) */
56
57 #if defined (__SH5__)
58
59 #define MD_FALLBACK_FRAME_STATE_FOR shmedia_fallback_frame_state
60
61 static _Unwind_Reason_Code
62 shmedia_fallback_frame_state (struct _Unwind_Context *context,
63                               _Unwind_FrameState *fs)
64 {
65   unsigned char *pc = context->ra;
66   struct sigcontext *sc;
67   long new_cfa;
68   int i, r;
69
70   /* movi 0x10,r9; shori 0x77,r9; trapa r9; nop (sigreturn)  */
71   /* movi 0x10,r9; shori 0xad,r9; trapa r9; nop (rt_sigreturn)  */
72   if ((*(unsigned long *) (pc-1)  == 0xcc004090)
73       && (*(unsigned long *) (pc+3)  == 0xc801dc90)
74       && (*(unsigned long *) (pc+7)  == 0x6c91fff0)
75       && (*(unsigned long *) (pc+11)  == 0x6ff0fff0))
76     sc = context->cfa;
77   else if ((*(unsigned long *) (pc-1)  == 0xcc004090)
78            && (*(unsigned long *) (pc+3)  == 0xc802b490)
79            && (*(unsigned long *) (pc+7)  == 0x6c91fff0)
80            && (*(unsigned long *) (pc+11)  == 0x6ff0fff0))
81     {
82       struct rt_sigframe {
83         struct siginfo *pinfo;
84         void *puc;
85         struct siginfo info;
86         struct ucontext uc;
87       } *rt_ = context->cfa;
88       /* The void * cast is necessary to avoid an aliasing warning.
89          The aliasing warning is correct, but should not be a problem
90          because it does not alias anything.  */
91       sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext;
92     }
93   else
94     return _URC_END_OF_STACK;
95
96   new_cfa = sc->sc_regs[15];
97   fs->regs.cfa_how = CFA_REG_OFFSET;
98   fs->regs.cfa_reg = 15;
99   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
100
101   for (i = 0; i < 63; i++)
102     {
103       if (i == 15)
104         continue;
105
106       fs->regs.reg[i].how = REG_SAVED_OFFSET;
107       fs->regs.reg[i].loc.offset
108         = (long)&(sc->sc_regs[i]) - new_cfa;
109     }
110
111   fs->regs.reg[SH_DWARF_FRAME_SR].how = REG_SAVED_OFFSET;
112   fs->regs.reg[SH_DWARF_FRAME_SR].loc.offset
113     = (long)&(sc->sc_sr) - new_cfa;
114
115   r = SH_DWARF_FRAME_BT0;
116   for (i = 0; i < 8; i++)
117     {
118       fs->regs.reg[r+i].how = REG_SAVED_OFFSET;
119       fs->regs.reg[r+i].loc.offset
120         = (long)&(sc->sc_tregs[i]) - new_cfa;
121     }
122
123   r = SH_DWARF_FRAME_FP0;
124   for (i = 0; i < 32; i++)
125     {
126       fs->regs.reg[r+i].how = REG_SAVED_OFFSET;
127       fs->regs.reg[r+i].loc.offset
128         = (long)&(sc->sc_fpregs[i]) - new_cfa;
129     }
130
131   fs->regs.reg[SH_DWARF_FRAME_FPSCR].how = REG_SAVED_OFFSET;
132   fs->regs.reg[SH_DWARF_FRAME_FPSCR].loc.offset
133     = (long)&(sc->sc_fpscr) - new_cfa;
134
135   /* We use the slot for the zero register to save return address.  */
136   fs->regs.reg[63].how = REG_SAVED_OFFSET;
137   fs->regs.reg[63].loc.offset
138     = (long)&(sc->sc_pc) - new_cfa;
139   fs->retaddr_column = 63;
140   fs->signal_frame = 1;
141   return _URC_NO_REASON;
142 }
143
144 #else /* defined (__SH5__) */
145
146 #define MD_FALLBACK_FRAME_STATE_FOR sh_fallback_frame_state
147
148 static _Unwind_Reason_Code
149 sh_fallback_frame_state (struct _Unwind_Context *context,
150                          _Unwind_FrameState *fs)
151 {
152   unsigned char *pc = context->ra;
153   struct sigcontext *sc;
154   long new_cfa;
155   int i;
156 #if defined (__SH3E__) || defined (__SH4__)
157   int r;
158 #endif
159
160   /* mov.w 1f,r3; trapa #0x10; 1: .short 0x77  (sigreturn)  */
161   /* mov.w 1f,r3; trapa #0x10; 1: .short 0xad  (rt_sigreturn)  */
162   /* Newer kernel uses pad instructions to avoid an SH-4 core bug.  */
163   /* mov.w 1f,r3; trapa #0x10; or r0,r0; or r0,r0; or r0,r0; or r0,r0;
164      or r0,r0; 1: .short 0x77  (sigreturn)  */
165   /* mov.w 1f,r3; trapa #0x10; or r0,r0; or r0,r0; or r0,r0; or r0,r0;
166      or r0,r0; 1: .short 0xad  (rt_sigreturn)  */
167   if (((*(unsigned short *) (pc+0)  == 0x9300)
168        && (*(unsigned short *) (pc+2)  == 0xc310)
169        && (*(unsigned short *) (pc+4)  == 0x0077))
170       || (((*(unsigned short *) (pc+0)  == 0x9305)
171            && (*(unsigned short *) (pc+2)  == 0xc310)
172            && (*(unsigned short *) (pc+14)  == 0x0077))))
173     sc = context->cfa;
174   else if (((*(unsigned short *) (pc+0) == 0x9300)
175             && (*(unsigned short *) (pc+2)  == 0xc310)
176             && (*(unsigned short *) (pc+4)  == 0x00ad))
177            || (((*(unsigned short *) (pc+0) == 0x9305)
178                 && (*(unsigned short *) (pc+2)  == 0xc310)
179                 && (*(unsigned short *) (pc+14)  == 0x00ad))))
180     {
181       struct rt_sigframe {
182         struct siginfo info;
183         struct ucontext uc;
184       } *rt_ = context->cfa;
185       /* The void * cast is necessary to avoid an aliasing warning.
186          The aliasing warning is correct, but should not be a problem
187          because it does not alias anything.  */
188       sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext;
189     }
190   else
191     return _URC_END_OF_STACK;
192
193   new_cfa = sc->sc_regs[15];
194   fs->regs.cfa_how = CFA_REG_OFFSET;
195   fs->regs.cfa_reg = 15;
196   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
197
198   for (i = 0; i < 15; i++)
199     {
200       fs->regs.reg[i].how = REG_SAVED_OFFSET;
201       fs->regs.reg[i].loc.offset
202         = (long)&(sc->sc_regs[i]) - new_cfa;
203     }
204
205   fs->regs.reg[SH_DWARF_FRAME_PR].how = REG_SAVED_OFFSET;
206   fs->regs.reg[SH_DWARF_FRAME_PR].loc.offset
207     = (long)&(sc->sc_pr) - new_cfa;
208   fs->regs.reg[SH_DWARF_FRAME_SR].how = REG_SAVED_OFFSET;
209   fs->regs.reg[SH_DWARF_FRAME_SR].loc.offset
210     = (long)&(sc->sc_sr) - new_cfa;
211   fs->regs.reg[SH_DWARF_FRAME_GBR].how = REG_SAVED_OFFSET;
212   fs->regs.reg[SH_DWARF_FRAME_GBR].loc.offset
213     = (long)&(sc->sc_gbr) - new_cfa;
214   fs->regs.reg[SH_DWARF_FRAME_MACH].how = REG_SAVED_OFFSET;
215   fs->regs.reg[SH_DWARF_FRAME_MACH].loc.offset
216     = (long)&(sc->sc_mach) - new_cfa;
217   fs->regs.reg[SH_DWARF_FRAME_MACL].how = REG_SAVED_OFFSET;
218   fs->regs.reg[SH_DWARF_FRAME_MACL].loc.offset
219     = (long)&(sc->sc_macl) - new_cfa;
220
221 #if defined (__SH3E__) || defined (__SH4__)
222   r = SH_DWARF_FRAME_FP0;
223   for (i = 0; i < 16; i++)
224     {
225       fs->regs.reg[r+i].how = REG_SAVED_OFFSET;
226       fs->regs.reg[r+i].loc.offset
227         = (long)&(sc->sc_fpregs[i]) - new_cfa;
228     }
229
230   r = SH_DWARF_FRAME_XD0;
231   for (i = 0; i < 8; i++)
232     {
233       fs->regs.reg[i].how = REG_SAVED_OFFSET;
234       fs->regs.reg[i].loc.offset
235         = (long)&(sc->sc_xfpregs[2*i]) - new_cfa;
236     }
237
238   fs->regs.reg[SH_DWARF_FRAME_FPUL].how = REG_SAVED_OFFSET;
239   fs->regs.reg[SH_DWARF_FRAME_FPUL].loc.offset
240     = (long)&(sc->sc_fpul) - new_cfa;
241   fs->regs.reg[SH_DWARF_FRAME_FPSCR].how = REG_SAVED_OFFSET;
242   fs->regs.reg[SH_DWARF_FRAME_FPSCR].loc.offset
243     = (long)&(sc->sc_fpscr) - new_cfa;
244 #endif
245
246   fs->regs.reg[SH_DWARF_FRAME_PC].how = REG_SAVED_OFFSET;
247   fs->regs.reg[SH_DWARF_FRAME_PC].loc.offset
248     = (long)&(sc->sc_pc) - new_cfa;
249   fs->retaddr_column = SH_DWARF_FRAME_PC;
250   fs->signal_frame = 1;
251   return _URC_NO_REASON;
252 }
253 #endif /* defined (__SH5__) */