]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/rs6000/linux-unwind.h
Update Copyright years for files modified in 2010.
[thirdparty/gcc.git] / gcc / config / rs6000 / linux-unwind.h
CommitLineData
8662eb14 1/* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
748086b7 2 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
8662eb14
AM
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published
748086b7 8 by the Free Software Foundation; either version 3, or (at your
8662eb14
AM
9 option) any later version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
15
748086b7
JJ
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.
8662eb14 19
748086b7
JJ
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/>. */
8662eb14 24
1de43f85
DE
25#define R_LR 65
26#define R_CR2 70
27#define R_VR0 77
28#define R_VRSAVE 109
29#define R_VSCR 110
30
a7a52913
AM
31struct gcc_vregs
32{
33 __attribute__ ((vector_size (16))) int vr[32];
34#ifdef __powerpc64__
35 unsigned int pad1[3];
36 unsigned int vscr;
37 unsigned int vsave;
38 unsigned int pad2[3];
39#else
40 unsigned int vsave;
41 unsigned int pad[2];
42 unsigned int vscr;
43#endif
44};
45
46struct gcc_regs
8662eb14
AM
47{
48 unsigned long gpr[32];
49 unsigned long nip;
50 unsigned long msr;
51 unsigned long orig_gpr3;
52 unsigned long ctr;
53 unsigned long link;
43e7c6a4
AM
54 unsigned long xer;
55 unsigned long ccr;
a7a52913
AM
56 unsigned long softe;
57 unsigned long trap;
58 unsigned long dar;
59 unsigned long dsisr;
60 unsigned long result;
61 unsigned long pad1[4];
62 double fpr[32];
63 unsigned int pad2;
64 unsigned int fpscr;
65#ifdef __powerpc64__
66 struct gcc_vregs *vp;
67#else
68 unsigned int pad3[2];
69#endif
70 struct gcc_vregs vregs;
8662eb14
AM
71};
72
73struct gcc_ucontext
74{
75#ifdef __powerpc64__
a7a52913 76 unsigned long pad[28];
8662eb14 77#else
a7a52913 78 unsigned long pad[12];
8662eb14 79#endif
a7a52913
AM
80 struct gcc_regs *regs;
81 struct gcc_regs rsave;
8662eb14
AM
82};
83
84#ifdef __powerpc64__
85
86enum { SIGNAL_FRAMESIZE = 128 };
87
8662eb14 88/* If PC is at a sigreturn trampoline, return a pointer to the
a7a52913 89 regs. Otherwise return NULL. */
8662eb14 90
a7a52913
AM
91static struct gcc_regs *
92get_regs (struct _Unwind_Context *context)
8662eb14 93{
9a461028 94 const unsigned int *pc = context->ra;
8662eb14
AM
95
96 /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */
97 /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */
9a461028 98 if (pc[0] != 0x38210000 + SIGNAL_FRAMESIZE || pc[2] != 0x44000002)
8662eb14 99 return NULL;
9a461028 100 if (pc[1] == 0x38000077)
8662eb14
AM
101 {
102 struct sigframe {
103 char gap[SIGNAL_FRAMESIZE];
a7a52913
AM
104 unsigned long pad[7];
105 struct gcc_regs *regs;
106 } *frame = (struct sigframe *) context->cfa;
107 return frame->regs;
8662eb14 108 }
9a461028 109 else if (pc[1] == 0x380000AC)
8662eb14 110 {
a7a52913
AM
111 /* This works for 2.4 kernels, but not for 2.6 kernels with vdso
112 because pc isn't pointing into the stack. Can be removed when
113 no one is running 2.4.19 or 2.4.20, the first two ppc64
114 kernels released. */
9a461028 115 const struct rt_sigframe_24 {
8662eb14
AM
116 int tramp[6];
117 void *pinfo;
118 struct gcc_ucontext *puc;
9a461028 119 } *frame24 = (const struct rt_sigframe_24 *) context->ra;
a7a52913
AM
120
121 /* Test for magic value in *puc of vdso. */
122 if ((long) frame24->puc != -21 * 8)
123 return frame24->puc->regs;
124 else
125 {
126 /* This works for 2.4.21 and later kernels. */
127 struct rt_sigframe {
128 char gap[SIGNAL_FRAMESIZE];
129 struct gcc_ucontext uc;
130 unsigned long pad[2];
131 int tramp[6];
132 void *pinfo;
133 struct gcc_ucontext *puc;
134 } *frame = (struct rt_sigframe *) context->cfa;
135 return frame->uc.regs;
136 }
8662eb14
AM
137 }
138 return NULL;
139}
140
141#else /* !__powerpc64__ */
142
143enum { SIGNAL_FRAMESIZE = 64 };
144
a7a52913
AM
145static struct gcc_regs *
146get_regs (struct _Unwind_Context *context)
8662eb14 147{
9a461028 148 const unsigned int *pc = context->ra;
8662eb14
AM
149
150 /* li r0, 0x7777; sc (sigreturn old) */
151 /* li r0, 0x0077; sc (sigreturn new) */
152 /* li r0, 0x6666; sc (rt_sigreturn old) */
153 /* li r0, 0x00AC; sc (rt_sigreturn new) */
9a461028 154 if (pc[1] != 0x44000002)
8662eb14 155 return NULL;
9a461028 156 if (pc[0] == 0x38007777 || pc[0] == 0x38000077)
8662eb14
AM
157 {
158 struct sigframe {
159 char gap[SIGNAL_FRAMESIZE];
a7a52913
AM
160 unsigned long pad[7];
161 struct gcc_regs *regs;
162 } *frame = (struct sigframe *) context->cfa;
163 return frame->regs;
8662eb14 164 }
9a461028 165 else if (pc[0] == 0x38006666 || pc[0] == 0x380000AC)
8662eb14
AM
166 {
167 struct rt_sigframe {
168 char gap[SIGNAL_FRAMESIZE + 16];
169 char siginfo[128];
170 struct gcc_ucontext uc;
a7a52913
AM
171 } *frame = (struct rt_sigframe *) context->cfa;
172 return frame->uc.regs;
8662eb14
AM
173 }
174 return NULL;
175}
176#endif
177
0388d40a 178/* Find an entry in the process auxiliary vector. The canonical way to
a7a52913
AM
179 test for VMX is to look at AT_HWCAP. */
180
181static long
182ppc_linux_aux_vector (long which)
183{
184 /* __libc_stack_end holds the original stack passed to a process. */
185 extern long *__libc_stack_end;
186 long argc;
187 char **argv;
188 char **envp;
189 struct auxv
190 {
191 long a_type;
192 long a_val;
193 } *auxp;
194
195 /* The Linux kernel puts argc first on the stack. */
196 argc = __libc_stack_end[0];
197 /* Followed by argv, NULL terminated. */
198 argv = (char **) __libc_stack_end + 1;
199 /* Followed by environment string pointers, NULL terminated. */
200 envp = argv + argc + 1;
201 while (*envp++)
202 continue;
203 /* Followed by the aux vector, zero terminated. */
204 for (auxp = (struct auxv *) envp; auxp->a_type != 0; ++auxp)
205 if (auxp->a_type == which)
206 return auxp->a_val;
207 return 0;
208}
209
8662eb14
AM
210/* Do code reading to identify a signal frame, and set the frame
211 state data appropriately. See unwind-dw2.c for the structs. */
212
213#define MD_FALLBACK_FRAME_STATE_FOR ppc_fallback_frame_state
214
215static _Unwind_Reason_Code
216ppc_fallback_frame_state (struct _Unwind_Context *context,
217 _Unwind_FrameState *fs)
218{
a7a52913
AM
219 static long hwcap = 0;
220 struct gcc_regs *regs = get_regs (context);
8662eb14
AM
221 long new_cfa;
222 int i;
223
a7a52913 224 if (regs == NULL)
8662eb14
AM
225 return _URC_END_OF_STACK;
226
a7a52913 227 new_cfa = regs->gpr[STACK_POINTER_REGNUM];
6673f90b
NF
228 fs->regs.cfa_how = CFA_REG_OFFSET;
229 fs->regs.cfa_reg = STACK_POINTER_REGNUM;
230 fs->regs.cfa_offset = new_cfa - (long) context->cfa;
8662eb14
AM
231
232 for (i = 0; i < 32; i++)
233 if (i != STACK_POINTER_REGNUM)
234 {
235 fs->regs.reg[i].how = REG_SAVED_OFFSET;
a7a52913 236 fs->regs.reg[i].loc.offset = (long) &regs->gpr[i] - new_cfa;
8662eb14
AM
237 }
238
1de43f85 239 fs->regs.reg[R_CR2].how = REG_SAVED_OFFSET;
be1d7465
JJ
240 /* CR? regs are always 32-bit and PPC is big-endian, so in 64-bit
241 libgcc loc.offset needs to point to the low 32 bits of regs->ccr. */
242 fs->regs.reg[R_CR2].loc.offset = (long) &regs->ccr - new_cfa
243 + sizeof (long) - 4;
43e7c6a4 244
1de43f85
DE
245 fs->regs.reg[R_LR].how = REG_SAVED_OFFSET;
246 fs->regs.reg[R_LR].loc.offset = (long) &regs->link - new_cfa;
8662eb14
AM
247
248 fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
a7a52913 249 fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) &regs->nip - new_cfa;
8662eb14 250 fs->retaddr_column = ARG_POINTER_REGNUM;
754e45a8 251 fs->signal_frame = 1;
a7a52913
AM
252
253 if (hwcap == 0)
254 {
255 hwcap = ppc_linux_aux_vector (16);
a4d05547 256 /* These will already be set if we found AT_HWCAP. A nonzero
a7a52913
AM
257 value stops us looking again if for some reason we couldn't
258 find AT_HWCAP. */
259#ifdef __powerpc64__
260 hwcap |= 0xc0000000;
261#else
262 hwcap |= 0x80000000;
263#endif
264 }
265
266 /* If we have a FPU... */
267 if (hwcap & 0x08000000)
268 for (i = 0; i < 32; i++)
269 {
270 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
271 fs->regs.reg[i + 32].loc.offset = (long) &regs->fpr[i] - new_cfa;
272 }
273
274 /* If we have a VMX unit... */
275 if (hwcap & 0x10000000)
276 {
277 struct gcc_vregs *vregs;
278#ifdef __powerpc64__
279 vregs = regs->vp;
280#else
281 vregs = &regs->vregs;
282#endif
283 if (regs->msr & (1 << 25))
284 {
285 for (i = 0; i < 32; i++)
286 {
1de43f85
DE
287 fs->regs.reg[i + R_VR0].how = REG_SAVED_OFFSET;
288 fs->regs.reg[i + R_VR0].loc.offset
f1a72222 289 = (long) &vregs->vr[i] - new_cfa;
a7a52913
AM
290 }
291
1de43f85
DE
292 fs->regs.reg[R_VSCR].how = REG_SAVED_OFFSET;
293 fs->regs.reg[R_VSCR].loc.offset = (long) &vregs->vscr - new_cfa;
a7a52913
AM
294 }
295
1de43f85
DE
296 fs->regs.reg[R_VRSAVE].how = REG_SAVED_OFFSET;
297 fs->regs.reg[R_VRSAVE].loc.offset = (long) &vregs->vsave - new_cfa;
a7a52913
AM
298 }
299
37ea0b7e
JM
300 /* If we have SPE register high-parts... we check at compile-time to
301 avoid expanding the code for all other PowerPC. */
302#ifdef __SPE__
303 for (i = 0; i < 32; i++)
304 {
305 fs->regs.reg[i + FIRST_PSEUDO_REGISTER - 1].how = REG_SAVED_OFFSET;
306 fs->regs.reg[i + FIRST_PSEUDO_REGISTER - 1].loc.offset
307 = (long) &regs->vregs - new_cfa + 4 * i;
308 }
309#endif
310
8662eb14
AM
311 return _URC_NO_REASON;
312}
754e45a8
JJ
313
314#define MD_FROB_UPDATE_CONTEXT frob_update_context
315
316static void
75334508 317frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATTRIBUTE_UNUSED)
754e45a8
JJ
318{
319 const unsigned int *pc = (const unsigned int *) context->ra;
320
321 /* Fix up for 2.6.12 - 2.6.16 Linux kernels that have vDSO, but don't
322 have S flag in it. */
323#ifdef __powerpc64__
324 /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */
325 /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */
326 if (pc[0] == 0x38210000 + SIGNAL_FRAMESIZE
327 && (pc[1] == 0x38000077 || pc[1] == 0x380000AC)
328 && pc[2] == 0x44000002)
f8e7718c 329 _Unwind_SetSignalFrame (context, 1);
754e45a8
JJ
330#else
331 /* li r0, 0x7777; sc (sigreturn old) */
332 /* li r0, 0x0077; sc (sigreturn new) */
333 /* li r0, 0x6666; sc (rt_sigreturn old) */
334 /* li r0, 0x00AC; sc (rt_sigreturn new) */
335 if ((pc[0] == 0x38007777 || pc[0] == 0x38000077
336 || pc[0] == 0x38006666 || pc[0] == 0x380000AC)
337 && pc[1] == 0x44000002)
f8e7718c 338 _Unwind_SetSignalFrame (context, 1);
754e45a8
JJ
339#endif
340
341#ifdef __powerpc64__
342 if (fs->regs.reg[2].how == REG_UNSAVED)
343 {
344 /* If the current unwind info (FS) does not contain explicit info
345 saving R2, then we have to do a minor amount of code reading to
346 figure out if it was saved. The big problem here is that the
347 code that does the save/restore is generated by the linker, so
348 we have no good way to determine at compile time what to do. */
349 unsigned int *insn
1de43f85 350 = (unsigned int *) _Unwind_GetGR (context, R_LR);
a4ab9629 351 if (insn && *insn == 0xE8410028)
754e45a8
JJ
352 _Unwind_SetGRPtr (context, 2, context->cfa + 40);
353 }
354#endif
355}