1 /* DWARF2 EH unwinding support for SH Linux.
2    Copyright (C) 2004, 2005 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
shmedia_fallback_frame_state(struct _Unwind_Context * context,_Unwind_FrameState * fs)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->cfa_how = CFA_REG_OFFSET;
98   fs->cfa_reg = 15;
99   fs->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   return _URC_NO_REASON;
141 }
142 
143 #else /* defined (__SH5__) */
144 
145 #define MD_FALLBACK_FRAME_STATE_FOR sh_fallback_frame_state
146 
147 static _Unwind_Reason_Code
sh_fallback_frame_state(struct _Unwind_Context * context,_Unwind_FrameState * fs)148 sh_fallback_frame_state (struct _Unwind_Context *context,
149 			 _Unwind_FrameState *fs)
150 {
151   unsigned char *pc = context->ra;
152   struct sigcontext *sc;
153   long new_cfa;
154   int i;
155 #if defined (__SH3E__) || defined (__SH4__)
156   int r;
157 #endif
158 
159   /* mov.w 1f,r3; trapa #0x10; 1: .short 0x77  (sigreturn)  */
160   /* mov.w 1f,r3; trapa #0x10; 1: .short 0xad  (rt_sigreturn)  */
161   /* Newer kernel uses pad instructions to avoid an SH-4 core bug.  */
162   /* mov.w 1f,r3; trapa #0x10; or r0,r0; or r0,r0; or r0,r0; or r0,r0;
163      or r0,r0; 1: .short 0x77  (sigreturn)  */
164   /* mov.w 1f,r3; trapa #0x10; or r0,r0; or r0,r0; or r0,r0; or r0,r0;
165      or r0,r0; 1: .short 0xad  (rt_sigreturn)  */
166   if (((*(unsigned short *) (pc+0)  == 0x9300)
167        && (*(unsigned short *) (pc+2)  == 0xc310)
168        && (*(unsigned short *) (pc+4)  == 0x0077))
169       || (((*(unsigned short *) (pc+0)  == 0x9305)
170 	   && (*(unsigned short *) (pc+2)  == 0xc310)
171 	   && (*(unsigned short *) (pc+14)  == 0x0077))))
172     sc = context->cfa;
173   else if (((*(unsigned short *) (pc+0) == 0x9300)
174 	    && (*(unsigned short *) (pc+2)  == 0xc310)
175 	    && (*(unsigned short *) (pc+4)  == 0x00ad))
176 	   || (((*(unsigned short *) (pc+0) == 0x9305)
177 		&& (*(unsigned short *) (pc+2)  == 0xc310)
178 		&& (*(unsigned short *) (pc+14)  == 0x00ad))))
179     {
180       struct rt_sigframe {
181 	struct siginfo info;
182 	struct ucontext uc;
183       } *rt_ = context->cfa;
184       /* The void * cast is necessary to avoid an aliasing warning.
185          The aliasing warning is correct, but should not be a problem
186          because it does not alias anything.  */
187       sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext;
188     }
189   else
190     return _URC_END_OF_STACK;
191 
192   new_cfa = sc->sc_regs[15];
193   fs->cfa_how = CFA_REG_OFFSET;
194   fs->cfa_reg = 15;
195   fs->cfa_offset = new_cfa - (long) context->cfa;
196 
197   for (i = 0; i < 15; i++)
198     {
199       fs->regs.reg[i].how = REG_SAVED_OFFSET;
200       fs->regs.reg[i].loc.offset
201 	= (long)&(sc->sc_regs[i]) - new_cfa;
202     }
203 
204   fs->regs.reg[SH_DWARF_FRAME_PR].how = REG_SAVED_OFFSET;
205   fs->regs.reg[SH_DWARF_FRAME_PR].loc.offset
206     = (long)&(sc->sc_pr) - new_cfa;
207   fs->regs.reg[SH_DWARF_FRAME_SR].how = REG_SAVED_OFFSET;
208   fs->regs.reg[SH_DWARF_FRAME_SR].loc.offset
209     = (long)&(sc->sc_sr) - new_cfa;
210   fs->regs.reg[SH_DWARF_FRAME_GBR].how = REG_SAVED_OFFSET;
211   fs->regs.reg[SH_DWARF_FRAME_GBR].loc.offset
212     = (long)&(sc->sc_gbr) - new_cfa;
213   fs->regs.reg[SH_DWARF_FRAME_MACH].how = REG_SAVED_OFFSET;
214   fs->regs.reg[SH_DWARF_FRAME_MACH].loc.offset
215     = (long)&(sc->sc_mach) - new_cfa;
216   fs->regs.reg[SH_DWARF_FRAME_MACL].how = REG_SAVED_OFFSET;
217   fs->regs.reg[SH_DWARF_FRAME_MACL].loc.offset
218     = (long)&(sc->sc_macl) - new_cfa;
219 
220 #if defined (__SH3E__) || defined (__SH4__)
221   r = SH_DWARF_FRAME_FP0;
222   for (i = 0; i < 16; i++)
223     {
224       fs->regs.reg[r+i].how = REG_SAVED_OFFSET;
225       fs->regs.reg[r+i].loc.offset
226 	= (long)&(sc->sc_fpregs[i]) - new_cfa;
227     }
228 
229   r = SH_DWARF_FRAME_XD0;
230   for (i = 0; i < 8; i++)
231     {
232       fs->regs.reg[i].how = REG_SAVED_OFFSET;
233       fs->regs.reg[i].loc.offset
234 	= (long)&(sc->sc_xfpregs[2*i]) - new_cfa;
235     }
236 
237   fs->regs.reg[SH_DWARF_FRAME_FPUL].how = REG_SAVED_OFFSET;
238   fs->regs.reg[SH_DWARF_FRAME_FPUL].loc.offset
239     = (long)&(sc->sc_fpul) - new_cfa;
240   fs->regs.reg[SH_DWARF_FRAME_FPSCR].how = REG_SAVED_OFFSET;
241   fs->regs.reg[SH_DWARF_FRAME_FPSCR].loc.offset
242     = (long)&(sc->sc_fpscr) - new_cfa;
243 #endif
244 
245   fs->regs.reg[SH_DWARF_FRAME_PC].how = REG_SAVED_OFFSET;
246   fs->regs.reg[SH_DWARF_FRAME_PC].loc.offset
247     = (long)&(sc->sc_pc) - new_cfa;
248   fs->retaddr_column = SH_DWARF_FRAME_PC;
249   return _URC_NO_REASON;
250 }
251 #endif /* defined (__SH5__) */
252