OSDN Git Service

86392f4181ed5376371a29e021a1086945ae3932
[pf3gnuchains/pf3gnuchains3x.git] / gcc / config / rs6000 / linux-unwind.h
1 /* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
2    Copyright (C) 2004, 2005, 2006, 2007 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 2, or (at your
9    option) any later version.
10
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.)
18
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.
23
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.  */
28
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.  */
34
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
40
41 struct gcc_vregs
42 {
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
54 };
55
56 struct gcc_regs
57 {
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;
81 };
82
83 struct gcc_ucontext
84 {
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;
92 };
93
94 #ifdef __powerpc64__
95
96 enum { SIGNAL_FRAMESIZE = 128 };
97
98 /* If PC is at a sigreturn trampoline, return a pointer to the
99    regs.  Otherwise return NULL.  */
100
101 static struct gcc_regs *
102 get_regs (struct _Unwind_Context *context)
103 {
104   const unsigned char *pc = context->ra;
105
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)
112     {
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;
119     }
120   else if (*(unsigned int *) (pc + 4) == 0x380000AC)
121     {
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;
131
132       /* Test for magic value in *puc of vdso.  */
133       if ((long) frame24->puc != -21 * 8)
134         return frame24->puc->regs;
135       else
136         {
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;
147         }
148     }
149   return NULL;
150 }
151
152 #else  /* !__powerpc64__ */
153
154 enum { SIGNAL_FRAMESIZE = 64 };
155
156 static struct gcc_regs *
157 get_regs (struct _Unwind_Context *context)
158 {
159   const unsigned char *pc = context->ra;
160
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)
169     {
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;
176     }
177   else if (*(unsigned int *) (pc + 0) == 0x38006666
178            || *(unsigned int *) (pc + 0) == 0x380000AC)
179     {
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;
186     }
187   return NULL;
188 }
189 #endif
190
191 /* Find an entry in the process auxiliary vector.  The canonical way to
192    test for VMX is to look at AT_HWCAP.  */
193
194 static long
195 ppc_linux_aux_vector (long which)
196 {
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
203   {
204     long a_type;
205     long a_val;
206   } *auxp;
207
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;
221 }
222
223 /* Do code reading to identify a signal frame, and set the frame
224    state data appropriately.  See unwind-dw2.c for the structs.  */
225
226 #define MD_FALLBACK_FRAME_STATE_FOR ppc_fallback_frame_state
227
228 static _Unwind_Reason_Code
229 ppc_fallback_frame_state (struct _Unwind_Context *context,
230                           _Unwind_FrameState *fs)
231 {
232   static long hwcap = 0;
233   struct gcc_regs *regs = get_regs (context);
234   long new_cfa;
235   int i;
236
237   if (regs == NULL)
238     return _URC_END_OF_STACK;
239
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;
244
245   for (i = 0; i < 32; i++)
246     if (i != STACK_POINTER_REGNUM)
247       {
248         fs->regs.reg[i].how = REG_SAVED_OFFSET;
249         fs->regs.reg[i].loc.offset = (long) &regs->gpr[i] - new_cfa;
250       }
251
252   fs->regs.reg[R_CR2].how = REG_SAVED_OFFSET;
253   /* CR? regs are always 32-bit and PPC is big-endian, so in 64-bit
254      libgcc loc.offset needs to point to the low 32 bits of regs->ccr.  */
255   fs->regs.reg[R_CR2].loc.offset = (long) &regs->ccr - new_cfa
256                                    + sizeof (long) - 4;
257
258   fs->regs.reg[R_LR].how = REG_SAVED_OFFSET;
259   fs->regs.reg[R_LR].loc.offset = (long) &regs->link - new_cfa;
260
261   fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
262   fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) &regs->nip - new_cfa;
263   fs->retaddr_column = ARG_POINTER_REGNUM;
264   fs->signal_frame = 1;
265
266   if (hwcap == 0)
267     {
268       hwcap = ppc_linux_aux_vector (16);
269       /* These will already be set if we found AT_HWCAP.  A nonzero
270          value stops us looking again if for some reason we couldn't
271          find AT_HWCAP.  */
272 #ifdef __powerpc64__
273       hwcap |= 0xc0000000;
274 #else
275       hwcap |= 0x80000000;
276 #endif
277     }
278
279   /* If we have a FPU...  */
280   if (hwcap & 0x08000000)
281     for (i = 0; i < 32; i++)
282       {
283         fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
284         fs->regs.reg[i + 32].loc.offset = (long) &regs->fpr[i] - new_cfa;
285       }
286
287   /* If we have a VMX unit...  */
288   if (hwcap & 0x10000000)
289     {
290       struct gcc_vregs *vregs;
291 #ifdef __powerpc64__
292       vregs = regs->vp;
293 #else
294       vregs = &regs->vregs;
295 #endif
296       if (regs->msr & (1 << 25))
297         {
298           for (i = 0; i < 32; i++)
299             {
300               fs->regs.reg[i + R_VR0].how = REG_SAVED_OFFSET;
301               fs->regs.reg[i + R_VR0].loc.offset
302                 = (long) &vregs->vr[i] - new_cfa;
303             }
304
305           fs->regs.reg[R_VSCR].how = REG_SAVED_OFFSET;
306           fs->regs.reg[R_VSCR].loc.offset = (long) &vregs->vscr - new_cfa;
307         }
308
309       fs->regs.reg[R_VRSAVE].how = REG_SAVED_OFFSET;
310       fs->regs.reg[R_VRSAVE].loc.offset = (long) &vregs->vsave - new_cfa;
311     }
312
313   /* If we have SPE register high-parts... we check at compile-time to
314      avoid expanding the code for all other PowerPC.  */
315 #ifdef __SPE__
316   for (i = 0; i < 32; i++)
317     {
318       fs->regs.reg[i + FIRST_PSEUDO_REGISTER - 1].how = REG_SAVED_OFFSET;
319       fs->regs.reg[i + FIRST_PSEUDO_REGISTER - 1].loc.offset
320         = (long) &regs->vregs - new_cfa + 4 * i;
321     }
322 #endif
323
324   return _URC_NO_REASON;
325 }
326
327 #define MD_FROB_UPDATE_CONTEXT frob_update_context
328
329 static void
330 frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATTRIBUTE_UNUSED)
331 {
332   const unsigned int *pc = (const unsigned int *) context->ra;
333
334   /* Fix up for 2.6.12 - 2.6.16 Linux kernels that have vDSO, but don't
335      have S flag in it.  */
336 #ifdef __powerpc64__
337   /* addi r1, r1, 128; li r0, 0x0077; sc  (sigreturn) */
338   /* addi r1, r1, 128; li r0, 0x00AC; sc  (rt_sigreturn) */
339   if (pc[0] == 0x38210000 + SIGNAL_FRAMESIZE
340       && (pc[1] == 0x38000077 || pc[1] == 0x380000AC)
341       && pc[2] == 0x44000002)
342     _Unwind_SetSignalFrame (context, 1);
343 #else
344   /* li r0, 0x7777; sc  (sigreturn old)  */
345   /* li r0, 0x0077; sc  (sigreturn new)  */
346   /* li r0, 0x6666; sc  (rt_sigreturn old)  */
347   /* li r0, 0x00AC; sc  (rt_sigreturn new)  */
348   if ((pc[0] == 0x38007777 || pc[0] == 0x38000077
349        || pc[0] == 0x38006666 || pc[0] == 0x380000AC)
350       && pc[1] == 0x44000002)
351     _Unwind_SetSignalFrame (context, 1);
352 #endif
353
354 #ifdef __powerpc64__
355   if (fs->regs.reg[2].how == REG_UNSAVED)
356     {
357       /* If the current unwind info (FS) does not contain explicit info
358          saving R2, then we have to do a minor amount of code reading to
359          figure out if it was saved.  The big problem here is that the
360          code that does the save/restore is generated by the linker, so
361          we have no good way to determine at compile time what to do.  */
362       unsigned int *insn
363         = (unsigned int *) _Unwind_GetGR (context, R_LR);
364       if (insn && *insn == 0xE8410028)
365         _Unwind_SetGRPtr (context, 2, context->cfa + 40);
366     }
367 #endif
368 }