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)
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
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
32 #include "coretypes.h"
36 #include "unwind-dw2.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. */
50 interpret_libc (reg_unit gprs
[32], struct _Unwind_Context
*context
)
52 uint32_t *pc
= (uint32_t *)_Unwind_GetIP (context
);
54 reg_unit lr
= (reg_unit
) pc
;
56 uint32_t *invalid_address
= NULL
;
60 for (i
= 0; i
< 13; i
++)
62 gprs
[1] = _Unwind_GetCFA (context
);
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)
80 262.4.1~1 63~84 6L123-6R172
82 320~1 71~101 7B85-7D28
83 320~1 71~266 7F54-7F56
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
99 if ((ins
& 0xFC000003) == 0x48000000) /* b instruction */
101 pc
+= ((((int32_t) ins
& 0x3FFFFFC) ^ 0x2000000) - 0x2000004) / 4;
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);
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;
123 if ((ins
& 0xFC0007FF) == 0x7C000378) /* or, including mr */
125 gprs
[ins
>> 16 & 0x1F] = (gprs
[ins
>> 11 & 0x1F]
126 | gprs
[ins
>> 21 & 0x1F]);
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
;
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);
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
)
147 gprs
[ins
>> 21 & 0x1F] = *p
;
150 if (ins
>> 26 == 0x21) /* lwzu */
152 uint32_t *p
= (uint32_t *)(gprs
[ins
>> 16 & 0x1F] += (int16_t) ins
);
153 if (p
== invalid_address
)
155 gprs
[ins
>> 21 & 0x1F] = *p
;
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
)
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
);
176 for (i
= (ins
>> 21 & 0x1F); i
< 32; i
++)
178 if (p
== invalid_address
)
184 if ((ins
& 0xFC1FFFFF) == 0x7c0803a6) /* mtlr */
186 lr
= gprs
[ins
>> 21 & 0x1F];
189 if ((ins
& 0xFC1FFFFF) == 0x7c0802a6) /* mflr */
191 gprs
[ins
>> 21 & 0x1F] = lr
;
194 if ((ins
& 0xFC1FFFFF) == 0x7c0903a6) /* mtctr */
196 ctr
= gprs
[ins
>> 21 & 0x1F];
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 */
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
);
211 if (ins
== 0x429f0005) /* bcl- 20,4*cr7+so,.+4, loads pc into LR */
216 if (ins
== 0x4e800420) /* bctr */
218 pc
= (uint32_t *) ctr
;
221 if (ins
== 0x44000002) /* sc */
228 /* These defines are from the kernel's bsd/dev/ppc/unix_signal.c. */
230 #define UC_TRAD_VEC 6
232 #define UC_TRAD64_VEC 25
234 #define UC_FLAVOR_VEC 35
235 #define UC_FLAVOR64 40
236 #define UC_FLAVOR64_VEC 45
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
{
250 uint32_t padding1
[4];
255 uint32_t xer
[2]; /* These are arrays because the original structure has them misaligned. */
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. */
278 handle_syscall (_Unwind_FrameState
*fs
, const reg_unit gprs
[32],
282 bool is_64
, is_vector
;
283 ppc_float_state_t
*float_state
;
284 ppc_vector_state_t
*vector_state
;
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
);
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. */
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
328 struct gcc_mcontext64
*m64
= (struct gcc_mcontext64
*)uctx
->uc_mcontext
;
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);
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
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;
353 return_addr
= m64
->srr0
;
357 struct mcontext
*m
= uctx
->uc_mcontext
;
360 float_state
= &m
->fs
;
361 vector_state
= &m
->vs
;
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
);
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
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;
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
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
);
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
);
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
425 _Unwind_fallback_frame_state_for (struct _Unwind_Context
*context
,
426 _Unwind_FrameState
*fs
)
430 if (!interpret_libc (gprs
, context
))
432 return handle_syscall (fs
, gprs
, _Unwind_GetCFA (context
));