* config/darwin.c, config/darwin.h, config/freebsd-spec.h,
[official-gcc.git] / gcc / config / rs6000 / darwin-fallback.c
bloba9ef4a7985e6b775dc40b89849d1ff453c703a59
1 /* Fallback frame-state unwinder for Darwin.
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 by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file into combinations with other programs,
14 and to distribute those combinations without any restriction coming
15 from the use of this file. (The General Public License restrictions
16 do apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into a combined
18 executable.)
20 GCC is distributed in the hope that it will be useful, but WITHOUT
21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
23 License for more details.
25 You should have received a copy of the GNU General Public License
26 along with GCC; see the file COPYING. If not, write to the Free
27 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
28 02111-1307, USA. */
30 #include "tconfig.h"
31 #include "tsystem.h"
32 #include "coretypes.h"
33 #include "tm.h"
34 #include "dwarf2.h"
35 #include "unwind.h"
36 #include "unwind-dw2.h"
37 #include <stdint.h>
38 #include <stdbool.h>
39 #include <signal.h>
40 #include <ucontext.h>
41 #include <mach/thread_status.h>
43 typedef unsigned long reg_unit;
45 /* Place in GPRS the parameters to the first 'sc' instruction that would
46 have been executed if we were returning from this CONTEXT, or
47 return false if an unexpected instruction is encountered. */
49 static bool
50 interpret_libc (reg_unit gprs[32], struct _Unwind_Context *context)
52 uint32_t *pc = (uint32_t *)_Unwind_GetIP (context);
53 uint32_t cr;
54 reg_unit lr = (reg_unit) pc;
55 reg_unit ctr = 0;
56 uint32_t *invalid_address = NULL;
58 int i;
60 for (i = 0; i < 13; i++)
61 gprs[i] = 1;
62 gprs[1] = _Unwind_GetCFA (context);
63 for (; i < 32; i++)
64 gprs[i] = _Unwind_GetGR (context, i);
65 cr = _Unwind_GetGR (context, CR2_REGNO);
67 /* For each supported Libc, we have to track the code flow
68 all the way back into the kernel.
70 This code is believed to support all released Libc/Libsystem builds since
71 Jaguar 6C115, including all the security updates. To be precise,
73 Libc Libsystem Build(s)
74 262~1 60~37 6C115
75 262~1 60.2~4 6D52
76 262~1 61~3 6F21-6F22
77 262~1 63~24 6G30-6G37
78 262~1 63~32 6I34-6I35
79 262~1 63~64 6L29-6L60
80 262.4.1~1 63~84 6L123-6R172
82 320~1 71~101 7B85-7D28
83 320~1 71~266 7F54-7F56
84 320~1 71~288 7F112
85 320~1 71~289 7F113
86 320.1.3~1 71.1.1~29 7H60-7H105
87 320.1.3~1 71.1.1~30 7H110-7H113
88 320.1.3~1 71.1.1~31 7H114
90 That's a big table! It would be insane to try to keep track of
91 every little detail, so we just read the code itself and do what
92 it would do.
95 for (;;)
97 uint32_t ins = *pc++;
99 if ((ins & 0xFC000003) == 0x48000000) /* b instruction */
101 pc += ((((int32_t) ins & 0x3FFFFFC) ^ 0x2000000) - 0x2000004) / 4;
102 continue;
104 if ((ins & 0xFC600000) == 0x2C000000) /* cmpwi */
106 int32_t val1 = (int16_t) ins;
107 int32_t val2 = gprs[ins >> 16 & 0x1F];
108 /* Only beq and bne instructions are supported, so we only
109 need to set the EQ bit. */
110 uint32_t mask = 0xF << ((ins >> 21 & 0x1C) ^ 0x1C);
111 if (val1 == val2)
112 cr |= mask;
113 else
114 cr &= ~mask;
115 continue;
117 if ((ins & 0xFEC38003) == 0x40820000) /* forwards beq/bne */
119 if ((cr >> ((ins >> 16 & 0x1F) ^ 0x1F) & 1) == (ins >> 24 & 1))
120 pc += (ins & 0x7FFC) / 4 - 1;
121 continue;
123 if ((ins & 0xFC0007FF) == 0x7C000378) /* or, including mr */
125 gprs [ins >> 16 & 0x1F] = (gprs [ins >> 11 & 0x1F]
126 | gprs [ins >> 21 & 0x1F]);
127 continue;
129 if (ins >> 26 == 0x0E) /* addi, including li */
131 reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
132 gprs [ins >> 21 & 0x1F] = src + (int16_t) ins;
133 continue;
135 if (ins >> 26 == 0x0F) /* addis, including lis */
137 reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
138 gprs [ins >> 21 & 0x1F] = src + ((int16_t) ins << 16);
139 continue;
141 if (ins >> 26 == 0x20) /* lwz */
143 reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
144 uint32_t *p = (uint32_t *)(src + (int16_t) ins);
145 if (p == invalid_address)
146 return false;
147 gprs [ins >> 21 & 0x1F] = *p;
148 continue;
150 if (ins >> 26 == 0x21) /* lwzu */
152 uint32_t *p = (uint32_t *)(gprs [ins >> 16 & 0x1F] += (int16_t) ins);
153 if (p == invalid_address)
154 return false;
155 gprs [ins >> 21 & 0x1F] = *p;
156 continue;
158 if (ins >> 26 == 0x24) /* stw */
159 /* What we hope this is doing is '--in_sigtramp'. We don't want
160 to actually store to memory, so just make a note of the
161 address and refuse to load from it. */
163 reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
164 uint32_t *p = (uint32_t *)(src + (int16_t) ins);
165 if (p == NULL || invalid_address != NULL)
166 return false;
167 invalid_address = p;
168 continue;
170 if (ins >> 26 == 0x2E) /* lmw */
172 reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
173 uint32_t *p = (uint32_t *)(src + (int16_t) ins);
174 int i;
176 for (i = (ins >> 21 & 0x1F); i < 32; i++)
178 if (p == invalid_address)
179 return false;
180 gprs[i] = *p++;
182 continue;
184 if ((ins & 0xFC1FFFFF) == 0x7c0803a6) /* mtlr */
186 lr = gprs [ins >> 21 & 0x1F];
187 continue;
189 if ((ins & 0xFC1FFFFF) == 0x7c0802a6) /* mflr */
191 gprs [ins >> 21 & 0x1F] = lr;
192 continue;
194 if ((ins & 0xFC1FFFFF) == 0x7c0903a6) /* mtctr */
196 ctr = gprs [ins >> 21 & 0x1F];
197 continue;
199 /* The PowerPC User's Manual says that bit 11 of the mtcrf
200 instruction is reserved and should be set to zero, but it
201 looks like the Darwin assembler doesn't do that... */
202 if ((ins & 0xFC000FFF) == 0x7c000120) /* mtcrf */
204 int i;
205 uint32_t mask = 0;
206 for (i = 0; i < 8; i++)
207 mask |= ((-(ins >> (12 + i) & 1)) & 0xF) << 4 * i;
208 cr = (cr & ~mask) | (gprs [ins >> 21 & 0x1F] & mask);
209 continue;
211 if (ins == 0x429f0005) /* bcl- 20,4*cr7+so,.+4, loads pc into LR */
213 lr = (reg_unit) pc;
214 continue;
216 if (ins == 0x4e800420) /* bctr */
218 pc = (uint32_t *) ctr;
219 continue;
221 if (ins == 0x44000002) /* sc */
222 return true;
224 return false;
228 /* These defines are from the kernel's bsd/dev/ppc/unix_signal.c. */
229 #define UC_TRAD 1
230 #define UC_TRAD_VEC 6
231 #define UC_TRAD64 20
232 #define UC_TRAD64_VEC 25
233 #define UC_FLAVOR 30
234 #define UC_FLAVOR_VEC 35
235 #define UC_FLAVOR64 40
236 #define UC_FLAVOR64_VEC 45
237 #define UC_DUAL 50
238 #define UC_DUAL_VEC 55
240 /* These are based on /usr/include/ppc/ucontext.h and
241 /usr/include/mach/ppc/thread_status.h, but rewritten to be more
242 convenient, to compile on Jaguar, and to work around Radar 3712064
243 on Panther, which is that the 'es' field of 'struct mcontext64' has
244 the wrong type (doh!). */
246 struct gcc_mcontext64 {
247 uint64_t dar;
248 uint32_t dsisr;
249 uint32_t exception;
250 uint32_t padding1[4];
251 uint64_t srr0;
252 uint64_t srr1;
253 uint32_t gpr[32][2];
254 uint32_t cr;
255 uint32_t xer[2]; /* These are arrays because the original structure has them misaligned. */
256 uint32_t lr[2];
257 uint32_t ctr[2];
258 uint32_t vrsave;
259 ppc_float_state_t fs;
260 ppc_vector_state_t vs;
263 #define UC_FLAVOR_SIZE \
264 (sizeof (struct mcontext) - sizeof (ppc_vector_state_t))
266 #define UC_FLAVOR_VEC_SIZE (sizeof (struct mcontext))
268 #define UC_FLAVOR64_SIZE \
269 (sizeof (struct gcc_mcontext64) - sizeof (ppc_vector_state_t))
271 #define UC_FLAVOR64_VEC_SIZE (sizeof (struct gcc_mcontext64))
273 /* Given GPRS as input to a 'sc' instruction, and OLD_CFA, update FS
274 to represent the execution of a signal return; or, if not a signal
275 return, return false. */
277 static bool
278 handle_syscall (_Unwind_FrameState *fs, const reg_unit gprs[32],
279 _Unwind_Ptr old_cfa)
281 ucontext_t *uctx;
282 bool is_64, is_vector;
283 ppc_float_state_t *float_state;
284 ppc_vector_state_t *vector_state;
285 _Unwind_Ptr new_cfa;
286 int i;
287 static _Unwind_Ptr return_addr;
289 /* Yay! We're in a Libc that we understand, and it's made a
290 system call. It'll be one of two kinds: either a Jaguar-style
291 SYS_sigreturn, or a Panther-style 'syscall' call with 184, which
292 is also SYS_sigreturn. */
294 if (gprs[0] == 0x67 /* SYS_SIGRETURN */)
296 uctx = (ucontext_t *) gprs[3];
297 is_vector = (uctx->uc_mcsize == UC_FLAVOR64_VEC_SIZE
298 || uctx->uc_mcsize == UC_FLAVOR_VEC_SIZE);
299 is_64 = (uctx->uc_mcsize == UC_FLAVOR64_VEC_SIZE
300 || uctx->uc_mcsize == UC_FLAVOR64_SIZE);
302 else if (gprs[0] == 0 && gprs[3] == 184)
304 int ctxstyle = gprs[5];
305 uctx = (ucontext_t *) gprs[4];
306 is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC
307 || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC);
308 is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC
309 || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64);
311 else
312 return false;
314 #define set_offset(r, addr) \
315 (fs->regs.reg[r].how = REG_SAVED_OFFSET, \
316 fs->regs.reg[r].loc.offset = (_Unwind_Ptr)(addr) - new_cfa)
318 /* Restore even the registers that are not call-saved, since they
319 might be being used in the prologue to save other registers,
320 for instance GPR0 is sometimes used to save LR. */
322 /* Handle the GPRs, and produce the information needed to do the rest. */
323 if (is_64)
325 /* The context is 64-bit, but it doesn't carry any extra information
326 for us because only the low 32 bits of the registers are
327 call-saved. */
328 struct gcc_mcontext64 *m64 = (struct gcc_mcontext64 *)uctx->uc_mcontext;
329 int i;
331 float_state = &m64->fs;
332 vector_state = &m64->vs;
334 new_cfa = m64->gpr[1][1];
336 set_offset (CR2_REGNO, &m64->cr);
337 for (i = 0; i < 32; i++)
338 set_offset (i, m64->gpr[i] + 1);
339 set_offset (XER_REGNO, m64->xer + 1);
340 set_offset (LINK_REGISTER_REGNUM, m64->lr + 1);
341 set_offset (COUNT_REGISTER_REGNUM, m64->ctr + 1);
342 if (is_vector)
343 set_offset (VRSAVE_REGNO, &m64->vrsave);
345 /* Sometimes, srr0 points to the instruction that caused the exception,
346 and sometimes to the next instruction to be executed; we want
347 the latter. */
348 if (m64->exception == 3 || m64->exception == 4
349 || m64->exception == 6
350 || (m64->exception == 7 && !(m64->srr1 & 0x10000)))
351 return_addr = m64->srr0 + 4;
352 else
353 return_addr = m64->srr0;
355 else
357 struct mcontext *m = uctx->uc_mcontext;
358 int i;
360 float_state = &m->fs;
361 vector_state = &m->vs;
363 new_cfa = m->ss.r1;
365 set_offset (CR2_REGNO, &m->ss.cr);
366 for (i = 0; i < 32; i++)
367 set_offset (i, &m->ss.r0 + i);
368 set_offset (XER_REGNO, &m->ss.xer);
369 set_offset (LINK_REGISTER_REGNUM, &m->ss.lr);
370 set_offset (COUNT_REGISTER_REGNUM, &m->ss.ctr);
372 if (is_vector)
373 set_offset (VRSAVE_REGNO, &m->ss.vrsave);
375 /* Sometimes, srr0 points to the instruction that caused the exception,
376 and sometimes to the next instruction to be executed; we want
377 the latter. */
378 if (m->es.exception == 3 || m->es.exception == 4
379 || m->es.exception == 6
380 || (m->es.exception == 7 && !(m->ss.srr1 & 0x10000)))
381 return_addr = m->ss.srr0 + 4;
382 else
383 return_addr = m->ss.srr0;
386 fs->cfa_how = CFA_REG_OFFSET;
387 fs->cfa_reg = STACK_POINTER_REGNUM;
388 fs->cfa_offset = new_cfa - old_cfa;;
390 /* The choice of column for the return address is somewhat tricky.
391 Fortunately, the actual choice is private to this file, and
392 the space it's reserved from is the GCC register space, not the
393 DWARF2 numbering. So any free element of the right size is an OK
394 choice. Thus: */
395 fs->retaddr_column = ARG_POINTER_REGNUM;
396 /* FIXME: this should really be done using a DWARF2 location expression,
397 not using a static variable. In fact, this entire file should
398 be implemented in DWARF2 expressions. */
399 set_offset (ARG_POINTER_REGNUM, &return_addr);
401 for (i = 0; i < 32; i++)
402 set_offset (32 + i, float_state->fpregs + i);
403 set_offset (SPEFSCR_REGNO, &float_state->fpscr);
405 if (is_vector)
407 for (i = 0; i < 32; i++)
408 set_offset (FIRST_ALTIVEC_REGNO + i, vector_state->save_vr + i);
409 set_offset (VSCR_REGNO, vector_state->save_vscr);
412 return true;
415 /* This is also prototyped in rs6000/darwin.h, inside the
416 MD_FALLBACK_FRAME_STATE_FOR macro. */
417 extern bool _Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
418 _Unwind_FrameState *fs);
420 /* Implement the MD_FALLBACK_FRAME_STATE_FOR macro,
421 returning true iff the frame was a sigreturn() frame that we
422 can understand. */
424 bool
425 _Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
426 _Unwind_FrameState *fs)
428 reg_unit gprs[32];
430 if (!interpret_libc (gprs, context))
431 return false;
432 return handle_syscall (fs, gprs, _Unwind_GetCFA (context));