1 /* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
2 Copyright (C) 2004, 2005 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, 59 Temple Place - Suite 330, Boston,
27 MA 02111-1307, 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. */
37 __attribute__ ((vector_size (16))) int vr[32];
52 unsigned long gpr[32];
55 unsigned long orig_gpr3;
65 unsigned long pad1[4];
74 struct gcc_vregs vregs;
80 unsigned long pad[28];
82 unsigned long pad[12];
84 struct gcc_regs *regs;
85 struct gcc_regs rsave;
90 enum { SIGNAL_FRAMESIZE = 128 };
92 /* If the current unwind info (FS) does not contain explicit info
93 saving R2, then we have to do a minor amount of code reading to
94 figure out if it was saved. The big problem here is that the
95 code that does the save/restore is generated by the linker, so
96 we have no good way to determine at compile time what to do. */
98 #define MD_FROB_UPDATE_CONTEXT(CTX, FS) \
100 if ((FS)->regs.reg[2].how == REG_UNSAVED) \
104 _Unwind_GetGR ((CTX), LINK_REGISTER_REGNUM); \
105 if (*insn == 0xE8410028) \
106 _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40); \
110 /* If PC is at a sigreturn trampoline, return a pointer to the
111 regs. Otherwise return NULL. */
113 #define PPC_LINUX_GET_REGS(CONTEXT) \
115 const unsigned char *pc = (CONTEXT)->ra; \
116 struct gcc_regs *regs = NULL; \
118 /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */ \
119 /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */ \
120 if (*(unsigned int *) (pc + 0) != 0x38210000 + SIGNAL_FRAMESIZE \
121 || *(unsigned int *) (pc + 8) != 0x44000002) \
123 else if (*(unsigned int *) (pc + 4) == 0x38000077) \
126 char gap[SIGNAL_FRAMESIZE]; \
127 unsigned long pad[7]; \
128 struct gcc_regs *regs; \
129 } *frame = (struct sigframe *) (CONTEXT)->cfa; \
130 regs = frame->regs; \
132 else if (*(unsigned int *) (pc + 4) == 0x380000AC) \
134 /* This works for 2.4 kernels, but not for 2.6 kernels with vdso \
135 because pc isn't pointing into the stack. Can be removed when \
136 no one is running 2.4.19 or 2.4.20, the first two ppc64 \
137 kernels released. */ \
138 struct rt_sigframe_24 { \
141 struct gcc_ucontext *puc; \
142 } *frame24 = (struct rt_sigframe_24 *) pc; \
144 /* Test for magic value in *puc of vdso. */ \
145 if ((long) frame24->puc != -21 * 8) \
146 regs = frame24->puc->regs; \
149 /* This works for 2.4.21 and later kernels. */ \
150 struct rt_sigframe { \
151 char gap[SIGNAL_FRAMESIZE]; \
152 struct gcc_ucontext uc; \
153 unsigned long pad[2]; \
156 struct gcc_ucontext *puc; \
157 } *frame = (struct rt_sigframe *) (CONTEXT)->cfa; \
158 regs = frame->uc.regs; \
164 #define LINUX_HWCAP_DEFAULT 0xc0000000
166 #define PPC_LINUX_VREGS(REGS) (REGS)->vp
168 #else /* !__powerpc64__ */
170 enum { SIGNAL_FRAMESIZE = 64 };
172 #define PPC_LINUX_GET_REGS(CONTEXT) \
174 const unsigned char *pc = (CONTEXT)->ra; \
175 struct gcc_regs *regs = NULL; \
177 /* li r0, 0x7777; sc (sigreturn old) */ \
178 /* li r0, 0x0077; sc (sigreturn new) */ \
179 /* li r0, 0x6666; sc (rt_sigreturn old) */ \
180 /* li r0, 0x00AC; sc (rt_sigreturn new) */ \
181 if (*(unsigned int *) (pc + 4) != 0x44000002) \
183 else if (*(unsigned int *) (pc + 0) == 0x38007777 \
184 || *(unsigned int *) (pc + 0) == 0x38000077) \
187 char gap[SIGNAL_FRAMESIZE]; \
188 unsigned long pad[7]; \
189 struct gcc_regs *regs; \
190 } *frame = (struct sigframe *) (CONTEXT)->cfa; \
191 regs = frame->regs; \
193 else if (*(unsigned int *) (pc + 0) == 0x38006666 \
194 || *(unsigned int *) (pc + 0) == 0x380000AC) \
196 struct rt_sigframe { \
197 char gap[SIGNAL_FRAMESIZE + 16]; \
199 struct gcc_ucontext uc; \
200 } *frame = (struct rt_sigframe *) (CONTEXT)->cfa; \
201 regs = frame->uc.regs; \
206 #define LINUX_HWCAP_DEFAULT 0x80000000
208 #define PPC_LINUX_VREGS(REGS) &(REGS)->vregs
212 /* Do code reading to identify a signal frame, and set the frame
213 state data appropriately. See unwind-dw2.c for the structs. */
215 #define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
217 static long hwcap = 0; \
218 struct gcc_regs *regs = PPC_LINUX_GET_REGS (CONTEXT); \
225 new_cfa = regs->gpr[STACK_POINTER_REGNUM]; \
226 (FS)->cfa_how = CFA_REG_OFFSET; \
227 (FS)->cfa_reg = STACK_POINTER_REGNUM; \
228 (FS)->cfa_offset = new_cfa - (long) (CONTEXT)->cfa; \
230 for (i = 0; i < 32; i++) \
231 if (i != STACK_POINTER_REGNUM) \
233 (FS)->regs.reg[i].how = REG_SAVED_OFFSET; \
234 (FS)->regs.reg[i].loc.offset \
235 = (long) ®s->gpr[i] - new_cfa; \
238 (FS)->regs.reg[CR2_REGNO].how = REG_SAVED_OFFSET; \
239 (FS)->regs.reg[CR2_REGNO].loc.offset \
240 = (long) ®s->ccr - new_cfa; \
242 (FS)->regs.reg[LINK_REGISTER_REGNUM].how = REG_SAVED_OFFSET; \
243 (FS)->regs.reg[LINK_REGISTER_REGNUM].loc.offset \
244 = (long) ®s->link - new_cfa; \
246 (FS)->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET; \
247 (FS)->regs.reg[ARG_POINTER_REGNUM].loc.offset \
248 = (long) ®s->nip - new_cfa; \
249 (FS)->retaddr_column = ARG_POINTER_REGNUM; \
253 /* __libc_stack_end holds the original stack passed to a \
255 extern long *__libc_stack_end; \
265 /* The Linux kernel puts argc first on the stack. */ \
266 argc = __libc_stack_end[0]; \
267 /* Followed by argv, NULL terminated. */ \
268 argv = (char **) __libc_stack_end + 1; \
269 /* Followed by environment string pointers, NULL terminated. */ \
270 envp = argv + argc + 1; \
273 /* Followed by the aux vector, zero terminated. */ \
274 for (auxp = (struct auxv *) envp; auxp->a_type != 0; ++auxp) \
275 if (auxp->a_type == 16) \
277 hwcap = auxp->a_val; \
281 /* These will already be set if we found AT_HWCAP. A non-zero \
282 value stops us looking again if for some reason we couldn't \
284 hwcap |= LINUX_HWCAP_DEFAULT; \
287 /* If we have a FPU... */ \
288 if (hwcap & 0x08000000) \
289 for (i = 0; i < 32; i++) \
291 (FS)->regs.reg[i + 32].how = REG_SAVED_OFFSET; \
292 (FS)->regs.reg[i + 32].loc.offset \
293 = (long) ®s->fpr[i] - new_cfa; \
296 /* If we have a VMX unit... */ \
297 if (hwcap & 0x10000000) \
299 struct gcc_vregs *vregs; \
300 vregs = PPC_LINUX_VREGS (regs); \
301 if (regs->msr & (1 << 25)) \
303 for (i = 0; i < 32; i++) \
305 (FS)->regs.reg[i + FIRST_ALTIVEC_REGNO].how \
306 = REG_SAVED_OFFSET; \
307 (FS)->regs.reg[i + FIRST_ALTIVEC_REGNO].loc.offset \
308 = (long) &vregs[i] - new_cfa; \
311 (FS)->regs.reg[VSCR_REGNO].how = REG_SAVED_OFFSET; \
312 (FS)->regs.reg[VSCR_REGNO].loc.offset \
313 = (long) &vregs->vscr - new_cfa; \
316 (FS)->regs.reg[VRSAVE_REGNO].how = REG_SAVED_OFFSET; \
317 (FS)->regs.reg[VRSAVE_REGNO].loc.offset \
318 = (long) &vregs->vsave - new_cfa; \