Merged with mainline at revision 128810.
[official-gcc.git] / gcc / config / rs6000 / linux-unwind.h
blobf3d76c0df144800102a1ccbc584cc7db2503ab44
1 /* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
2 Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
4 This file is part of GCC.
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
8 by the Free Software Foundation; either version 2, or (at your
9 option) any later version.
11 In addition to the permissions in the GNU General Public License,
12 the Free Software Foundation gives you unlimited permission to link
13 the compiled version of this file with other programs, and to
14 distribute those programs without any restriction coming from the
15 use of this file. (The General Public License restrictions do
16 apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into another program.)
19 GCC is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
22 License for more details.
24 You should have received a copy of the GNU General Public License
25 along with GCC; see the file COPYING. If not, write to the
26 Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
27 MA 02110-1301, USA. */
29 /* This file defines our own versions of various kernel and user
30 structs, so that system headers are not needed, which otherwise
31 can make bootstrapping a new toolchain difficult. Do not use
32 these structs elsewhere; Many fields are missing, particularly
33 from the end of the structures. */
35 #define R_LR 65
36 #define R_CR2 70
37 #define R_VR0 77
38 #define R_VRSAVE 109
39 #define R_VSCR 110
41 struct gcc_vregs
43 __attribute__ ((vector_size (16))) int vr[32];
44 #ifdef __powerpc64__
45 unsigned int pad1[3];
46 unsigned int vscr;
47 unsigned int vsave;
48 unsigned int pad2[3];
49 #else
50 unsigned int vsave;
51 unsigned int pad[2];
52 unsigned int vscr;
53 #endif
56 struct gcc_regs
58 unsigned long gpr[32];
59 unsigned long nip;
60 unsigned long msr;
61 unsigned long orig_gpr3;
62 unsigned long ctr;
63 unsigned long link;
64 unsigned long xer;
65 unsigned long ccr;
66 unsigned long softe;
67 unsigned long trap;
68 unsigned long dar;
69 unsigned long dsisr;
70 unsigned long result;
71 unsigned long pad1[4];
72 double fpr[32];
73 unsigned int pad2;
74 unsigned int fpscr;
75 #ifdef __powerpc64__
76 struct gcc_vregs *vp;
77 #else
78 unsigned int pad3[2];
79 #endif
80 struct gcc_vregs vregs;
83 struct gcc_ucontext
85 #ifdef __powerpc64__
86 unsigned long pad[28];
87 #else
88 unsigned long pad[12];
89 #endif
90 struct gcc_regs *regs;
91 struct gcc_regs rsave;
94 #ifdef __powerpc64__
96 enum { SIGNAL_FRAMESIZE = 128 };
98 /* If PC is at a sigreturn trampoline, return a pointer to the
99 regs. Otherwise return NULL. */
101 static struct gcc_regs *
102 get_regs (struct _Unwind_Context *context)
104 const unsigned char *pc = context->ra;
106 /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */
107 /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */
108 if (*(unsigned int *) (pc + 0) != 0x38210000 + SIGNAL_FRAMESIZE
109 || *(unsigned int *) (pc + 8) != 0x44000002)
110 return NULL;
111 if (*(unsigned int *) (pc + 4) == 0x38000077)
113 struct sigframe {
114 char gap[SIGNAL_FRAMESIZE];
115 unsigned long pad[7];
116 struct gcc_regs *regs;
117 } *frame = (struct sigframe *) context->cfa;
118 return frame->regs;
120 else if (*(unsigned int *) (pc + 4) == 0x380000AC)
122 /* This works for 2.4 kernels, but not for 2.6 kernels with vdso
123 because pc isn't pointing into the stack. Can be removed when
124 no one is running 2.4.19 or 2.4.20, the first two ppc64
125 kernels released. */
126 struct rt_sigframe_24 {
127 int tramp[6];
128 void *pinfo;
129 struct gcc_ucontext *puc;
130 } *frame24 = (struct rt_sigframe_24 *) pc;
132 /* Test for magic value in *puc of vdso. */
133 if ((long) frame24->puc != -21 * 8)
134 return frame24->puc->regs;
135 else
137 /* This works for 2.4.21 and later kernels. */
138 struct rt_sigframe {
139 char gap[SIGNAL_FRAMESIZE];
140 struct gcc_ucontext uc;
141 unsigned long pad[2];
142 int tramp[6];
143 void *pinfo;
144 struct gcc_ucontext *puc;
145 } *frame = (struct rt_sigframe *) context->cfa;
146 return frame->uc.regs;
149 return NULL;
152 #else /* !__powerpc64__ */
154 enum { SIGNAL_FRAMESIZE = 64 };
156 static struct gcc_regs *
157 get_regs (struct _Unwind_Context *context)
159 const unsigned char *pc = context->ra;
161 /* li r0, 0x7777; sc (sigreturn old) */
162 /* li r0, 0x0077; sc (sigreturn new) */
163 /* li r0, 0x6666; sc (rt_sigreturn old) */
164 /* li r0, 0x00AC; sc (rt_sigreturn new) */
165 if (*(unsigned int *) (pc + 4) != 0x44000002)
166 return NULL;
167 if (*(unsigned int *) (pc + 0) == 0x38007777
168 || *(unsigned int *) (pc + 0) == 0x38000077)
170 struct sigframe {
171 char gap[SIGNAL_FRAMESIZE];
172 unsigned long pad[7];
173 struct gcc_regs *regs;
174 } *frame = (struct sigframe *) context->cfa;
175 return frame->regs;
177 else if (*(unsigned int *) (pc + 0) == 0x38006666
178 || *(unsigned int *) (pc + 0) == 0x380000AC)
180 struct rt_sigframe {
181 char gap[SIGNAL_FRAMESIZE + 16];
182 char siginfo[128];
183 struct gcc_ucontext uc;
184 } *frame = (struct rt_sigframe *) context->cfa;
185 return frame->uc.regs;
187 return NULL;
189 #endif
191 /* Find an entry in the process auxiliary vector. The canonical way to
192 test for VMX is to look at AT_HWCAP. */
194 static long
195 ppc_linux_aux_vector (long which)
197 /* __libc_stack_end holds the original stack passed to a process. */
198 extern long *__libc_stack_end;
199 long argc;
200 char **argv;
201 char **envp;
202 struct auxv
204 long a_type;
205 long a_val;
206 } *auxp;
208 /* The Linux kernel puts argc first on the stack. */
209 argc = __libc_stack_end[0];
210 /* Followed by argv, NULL terminated. */
211 argv = (char **) __libc_stack_end + 1;
212 /* Followed by environment string pointers, NULL terminated. */
213 envp = argv + argc + 1;
214 while (*envp++)
215 continue;
216 /* Followed by the aux vector, zero terminated. */
217 for (auxp = (struct auxv *) envp; auxp->a_type != 0; ++auxp)
218 if (auxp->a_type == which)
219 return auxp->a_val;
220 return 0;
223 /* Do code reading to identify a signal frame, and set the frame
224 state data appropriately. See unwind-dw2.c for the structs. */
226 #define MD_FALLBACK_FRAME_STATE_FOR ppc_fallback_frame_state
228 static _Unwind_Reason_Code
229 ppc_fallback_frame_state (struct _Unwind_Context *context,
230 _Unwind_FrameState *fs)
232 static long hwcap = 0;
233 struct gcc_regs *regs = get_regs (context);
234 long new_cfa;
235 int i;
237 if (regs == NULL)
238 return _URC_END_OF_STACK;
240 new_cfa = regs->gpr[STACK_POINTER_REGNUM];
241 fs->regs.cfa_how = CFA_REG_OFFSET;
242 fs->regs.cfa_reg = STACK_POINTER_REGNUM;
243 fs->regs.cfa_offset = new_cfa - (long) context->cfa;
245 for (i = 0; i < 32; i++)
246 if (i != STACK_POINTER_REGNUM)
248 fs->regs.reg[i].how = REG_SAVED_OFFSET;
249 fs->regs.reg[i].loc.offset = (long) &regs->gpr[i] - new_cfa;
252 fs->regs.reg[R_CR2].how = REG_SAVED_OFFSET;
253 fs->regs.reg[R_CR2].loc.offset = (long) &regs->ccr - new_cfa;
255 fs->regs.reg[R_LR].how = REG_SAVED_OFFSET;
256 fs->regs.reg[R_LR].loc.offset = (long) &regs->link - new_cfa;
258 fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
259 fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) &regs->nip - new_cfa;
260 fs->retaddr_column = ARG_POINTER_REGNUM;
261 fs->signal_frame = 1;
263 if (hwcap == 0)
265 hwcap = ppc_linux_aux_vector (16);
266 /* These will already be set if we found AT_HWCAP. A nonzero
267 value stops us looking again if for some reason we couldn't
268 find AT_HWCAP. */
269 #ifdef __powerpc64__
270 hwcap |= 0xc0000000;
271 #else
272 hwcap |= 0x80000000;
273 #endif
276 /* If we have a FPU... */
277 if (hwcap & 0x08000000)
278 for (i = 0; i < 32; i++)
280 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
281 fs->regs.reg[i + 32].loc.offset = (long) &regs->fpr[i] - new_cfa;
284 /* If we have a VMX unit... */
285 if (hwcap & 0x10000000)
287 struct gcc_vregs *vregs;
288 #ifdef __powerpc64__
289 vregs = regs->vp;
290 #else
291 vregs = &regs->vregs;
292 #endif
293 if (regs->msr & (1 << 25))
295 for (i = 0; i < 32; i++)
297 fs->regs.reg[i + R_VR0].how = REG_SAVED_OFFSET;
298 fs->regs.reg[i + R_VR0].loc.offset
299 = (long) &vregs->vr[i] - new_cfa;
302 fs->regs.reg[R_VSCR].how = REG_SAVED_OFFSET;
303 fs->regs.reg[R_VSCR].loc.offset = (long) &vregs->vscr - new_cfa;
306 fs->regs.reg[R_VRSAVE].how = REG_SAVED_OFFSET;
307 fs->regs.reg[R_VRSAVE].loc.offset = (long) &vregs->vsave - new_cfa;
310 /* If we have SPE register high-parts... we check at compile-time to
311 avoid expanding the code for all other PowerPC. */
312 #ifdef __SPE__
313 for (i = 0; i < 32; i++)
315 fs->regs.reg[i + FIRST_PSEUDO_REGISTER - 1].how = REG_SAVED_OFFSET;
316 fs->regs.reg[i + FIRST_PSEUDO_REGISTER - 1].loc.offset
317 = (long) &regs->vregs - new_cfa + 4 * i;
319 #endif
321 return _URC_NO_REASON;
324 #define MD_FROB_UPDATE_CONTEXT frob_update_context
326 static void
327 frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATTRIBUTE_UNUSED)
329 const unsigned int *pc = (const unsigned int *) context->ra;
331 /* Fix up for 2.6.12 - 2.6.16 Linux kernels that have vDSO, but don't
332 have S flag in it. */
333 #ifdef __powerpc64__
334 /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */
335 /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */
336 if (pc[0] == 0x38210000 + SIGNAL_FRAMESIZE
337 && (pc[1] == 0x38000077 || pc[1] == 0x380000AC)
338 && pc[2] == 0x44000002)
339 _Unwind_SetSignalFrame (context, 1);
340 #else
341 /* li r0, 0x7777; sc (sigreturn old) */
342 /* li r0, 0x0077; sc (sigreturn new) */
343 /* li r0, 0x6666; sc (rt_sigreturn old) */
344 /* li r0, 0x00AC; sc (rt_sigreturn new) */
345 if ((pc[0] == 0x38007777 || pc[0] == 0x38000077
346 || pc[0] == 0x38006666 || pc[0] == 0x380000AC)
347 && pc[1] == 0x44000002)
348 _Unwind_SetSignalFrame (context, 1);
349 #endif
351 #ifdef __powerpc64__
352 if (fs->regs.reg[2].how == REG_UNSAVED)
354 /* If the current unwind info (FS) does not contain explicit info
355 saving R2, then we have to do a minor amount of code reading to
356 figure out if it was saved. The big problem here is that the
357 code that does the save/restore is generated by the linker, so
358 we have no good way to determine at compile time what to do. */
359 unsigned int *insn
360 = (unsigned int *) _Unwind_GetGR (context, R_LR);
361 if (*insn == 0xE8410028)
362 _Unwind_SetGRPtr (context, 2, context->cfa + 40);
364 #endif