comparison gcc/config/rs6000/linux-unwind.h @ 0:a06113de4d67

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