1 /* Fallback frame-state unwinder for Darwin.
2 Copyright (C) 2004-2024 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 3, or (at your option)
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.
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.
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/>. */
29 #include "coretypes.h"
31 #include "libgcc_tm.h"
34 #include "unwind-dw2.h"
37 #include <sys/types.h>
49 typedef unsigned long reg_unit
;
51 /* Place in GPRS the parameters to the first 'sc' instruction that would
52 have been executed if we were returning from this CONTEXT, or
53 return false if an unexpected instruction is encountered. */
56 interpret_libc (reg_unit gprs
[32], struct _Unwind_Context
*context
)
58 uint32_t *pc
= (uint32_t *)_Unwind_GetIP (context
);
60 reg_unit lr
= (reg_unit
) pc
;
62 uint32_t *invalid_address
= NULL
;
66 for (i
= 0; i
< 13; i
++)
68 gprs
[1] = _Unwind_GetCFA (context
);
70 gprs
[i
] = _Unwind_GetGR (context
, i
);
71 cr
= _Unwind_GetGR (context
, R_CR2
);
73 /* For each supported Libc, we have to track the code flow
74 all the way back into the kernel.
76 This code is believed to support all released Libc/Libsystem builds since
77 Jaguar 6C115, including all the security updates. To be precise,
79 Libc Libsystem Build(s)
86 262.4.1~1 63~84 6L123-6R172
88 320~1 71~101 7B85-7D28
89 320~1 71~266 7F54-7F56
92 320.1.3~1 71.1.1~29 7H60-7H105
93 320.1.3~1 71.1.1~30 7H110-7H113
94 320.1.3~1 71.1.1~31 7H114
96 That's a big table! It would be insane to try to keep track of
97 every little detail, so we just read the code itself and do what
103 uint32_t ins
= *pc
++;
105 if ((ins
& 0xFC000003) == 0x48000000) /* b instruction */
107 pc
+= ((((int32_t) ins
& 0x3FFFFFC) ^ 0x2000000) - 0x2000004) / 4;
110 if ((ins
& 0xFC600000) == 0x2C000000) /* cmpwi */
112 int32_t val1
= (int16_t) ins
;
113 int32_t val2
= gprs
[ins
>> 16 & 0x1F];
114 /* Only beq and bne instructions are supported, so we only
115 need to set the EQ bit. */
116 uint32_t mask
= 0xF << ((ins
>> 21 & 0x1C) ^ 0x1C);
123 if ((ins
& 0xFEC38003) == 0x40820000) /* forwards beq/bne */
125 if ((cr
>> ((ins
>> 16 & 0x1F) ^ 0x1F) & 1) == (ins
>> 24 & 1))
126 pc
+= (ins
& 0x7FFC) / 4 - 1;
129 if ((ins
& 0xFC0007FF) == 0x7C000378) /* or, including mr */
131 gprs
[ins
>> 16 & 0x1F] = (gprs
[ins
>> 11 & 0x1F]
132 | gprs
[ins
>> 21 & 0x1F]);
135 if (ins
>> 26 == 0x0E) /* addi, including li */
137 reg_unit src
= (ins
>> 16 & 0x1F) == 0 ? 0 : gprs
[ins
>> 16 & 0x1F];
138 gprs
[ins
>> 21 & 0x1F] = src
+ (int16_t) ins
;
141 if (ins
>> 26 == 0x0F) /* addis, including lis */
143 reg_unit src
= (ins
>> 16 & 0x1F) == 0 ? 0 : gprs
[ins
>> 16 & 0x1F];
144 gprs
[ins
>> 21 & 0x1F] = src
+ ((int16_t) ins
<< 16);
147 if (ins
>> 26 == 0x20) /* lwz */
149 reg_unit src
= (ins
>> 16 & 0x1F) == 0 ? 0 : gprs
[ins
>> 16 & 0x1F];
150 uint32_t *p
= (uint32_t *)(src
+ (int16_t) ins
);
151 if (p
== invalid_address
)
153 gprs
[ins
>> 21 & 0x1F] = *p
;
156 if (ins
>> 26 == 0x21) /* lwzu */
158 uint32_t *p
= (uint32_t *)(gprs
[ins
>> 16 & 0x1F] += (int16_t) ins
);
159 if (p
== invalid_address
)
161 gprs
[ins
>> 21 & 0x1F] = *p
;
164 if (ins
>> 26 == 0x24) /* stw */
165 /* What we hope this is doing is '--in_sigtramp'. We don't want
166 to actually store to memory, so just make a note of the
167 address and refuse to load from it. */
169 reg_unit src
= (ins
>> 16 & 0x1F) == 0 ? 0 : gprs
[ins
>> 16 & 0x1F];
170 uint32_t *p
= (uint32_t *)(src
+ (int16_t) ins
);
171 if (p
== NULL
|| invalid_address
!= NULL
)
176 if (ins
>> 26 == 0x2E) /* lmw */
178 reg_unit src
= (ins
>> 16 & 0x1F) == 0 ? 0 : gprs
[ins
>> 16 & 0x1F];
179 uint32_t *p
= (uint32_t *)(src
+ (int16_t) ins
);
182 for (i
= (ins
>> 21 & 0x1F); i
< 32; i
++)
184 if (p
== invalid_address
)
190 if ((ins
& 0xFC1FFFFF) == 0x7c0803a6) /* mtlr */
192 lr
= gprs
[ins
>> 21 & 0x1F];
195 if ((ins
& 0xFC1FFFFF) == 0x7c0802a6) /* mflr */
197 gprs
[ins
>> 21 & 0x1F] = lr
;
200 if ((ins
& 0xFC1FFFFF) == 0x7c0903a6) /* mtctr */
202 ctr
= gprs
[ins
>> 21 & 0x1F];
205 /* The PowerPC User's Manual says that bit 11 of the mtcrf
206 instruction is reserved and should be set to zero, but it
207 looks like the Darwin assembler doesn't do that... */
208 if ((ins
& 0xFC000FFF) == 0x7c000120) /* mtcrf */
212 for (i
= 0; i
< 8; i
++)
213 mask
|= ((-(ins
>> (12 + i
) & 1)) & 0xF) << 4 * i
;
214 cr
= (cr
& ~mask
) | (gprs
[ins
>> 21 & 0x1F] & mask
);
217 if (ins
== 0x429f0005) /* bcl- 20,4*cr7+so,.+4, loads pc into LR */
222 if (ins
== 0x4e800420) /* bctr */
224 pc
= (uint32_t *) ctr
;
227 if (ins
== 0x44000002) /* sc */
234 /* We used to include <ucontext.h> and <mach/thread_status.h>,
235 but they change so much between different Darwin system versions
236 that it's much easier to just write the structures involved here
239 /* These defines are from the kernel's bsd/dev/ppc/unix_signal.c. */
241 #define UC_TRAD_VEC 6
243 #define UC_TRAD64_VEC 25
245 #define UC_FLAVOR_VEC 35
246 #define UC_FLAVOR64 40
247 #define UC_FLAVOR64_VEC 45
249 #define UC_DUAL_VEC 55
258 struct gcc_ucontext
*link
;
260 struct gcc_mcontext32
*mcontext
;
263 struct gcc_float_vector_state
268 uint32_t save_vr
[32][4];
269 uint32_t save_vscr
[4];
272 struct gcc_mcontext32
{
276 uint32_t padding1
[5];
286 struct gcc_float_vector_state fvs
;
289 /* These are based on /usr/include/ppc/ucontext.h and
290 /usr/include/mach/ppc/thread_status.h, but rewritten to be more
291 convenient, to compile on Jaguar, and to work around Radar 3712064
292 on Panther, which is that the 'es' field of 'struct mcontext64' has
293 the wrong type (doh!). */
295 struct gcc_mcontext64
{
299 uint32_t padding1
[4];
304 uint32_t xer
[2]; /* These are arrays because the original structure has them misaligned. */
308 struct gcc_float_vector_state fvs
;
311 #define UC_FLAVOR_SIZE \
312 (sizeof (struct gcc_mcontext32) - 33*16)
314 #define UC_FLAVOR_VEC_SIZE (sizeof (struct gcc_mcontext32))
316 #define UC_FLAVOR64_SIZE \
317 (sizeof (struct gcc_mcontext64) - 33*16)
319 #define UC_FLAVOR64_VEC_SIZE (sizeof (struct gcc_mcontext64))
321 /* Given GPRS as input to a 'sc' instruction, and OLD_CFA, update FS
322 to represent the execution of a signal return; or, if not a signal
323 return, return false. */
326 handle_syscall (_Unwind_FrameState
*fs
, const reg_unit gprs
[32],
329 struct gcc_ucontext
*uctx
;
330 bool is_64
, is_vector
;
331 struct gcc_float_vector_state
* float_vector_state
;
334 static _Unwind_Ptr return_addr
;
336 /* Yay! We're in a Libc that we understand, and it's made a
337 system call. In Jaguar, this is a direct system call with value 103;
338 in Panther and Tiger it is a SYS_syscall call for system call number 184,
339 and in Leopard it is a direct syscall with number 184. */
341 if (gprs
[0] == 0x67 /* SYS_SIGRETURN */)
343 uctx
= (struct gcc_ucontext
*) gprs
[3];
344 is_vector
= (uctx
->mcsize
== UC_FLAVOR64_VEC_SIZE
345 || uctx
->mcsize
== UC_FLAVOR_VEC_SIZE
);
346 is_64
= (uctx
->mcsize
== UC_FLAVOR64_VEC_SIZE
347 || uctx
->mcsize
== UC_FLAVOR64_SIZE
);
349 else if (gprs
[0] == 0 /* SYS_syscall */ && gprs
[3] == 184)
351 int ctxstyle
= gprs
[5];
352 uctx
= (struct gcc_ucontext
*) gprs
[4];
353 is_vector
= (ctxstyle
== UC_FLAVOR_VEC
|| ctxstyle
== UC_FLAVOR64_VEC
354 || ctxstyle
== UC_TRAD_VEC
|| ctxstyle
== UC_TRAD64_VEC
);
355 is_64
= (ctxstyle
== UC_FLAVOR64_VEC
|| ctxstyle
== UC_TRAD64_VEC
356 || ctxstyle
== UC_FLAVOR64
|| ctxstyle
== UC_TRAD64
);
358 else if (gprs
[0] == 184 /* SYS_sigreturn */)
360 int ctxstyle
= gprs
[4];
361 uctx
= (struct gcc_ucontext
*) gprs
[3];
362 is_vector
= (ctxstyle
== UC_FLAVOR_VEC
|| ctxstyle
== UC_FLAVOR64_VEC
363 || ctxstyle
== UC_TRAD_VEC
|| ctxstyle
== UC_TRAD64_VEC
);
364 is_64
= (ctxstyle
== UC_FLAVOR64_VEC
|| ctxstyle
== UC_TRAD64_VEC
365 || ctxstyle
== UC_FLAVOR64
|| ctxstyle
== UC_TRAD64
);
370 #define set_offset(r, addr) \
371 (fs->regs.how[r] = REG_SAVED_OFFSET, \
372 fs->regs.reg[r].loc.offset = (_Unwind_Ptr)(addr) - new_cfa)
374 /* Restore even the registers that are not call-saved, since they
375 might be being used in the prologue to save other registers,
376 for instance GPR0 is sometimes used to save LR. */
378 /* Handle the GPRs, and produce the information needed to do the rest. */
381 /* The context is 64-bit, but it doesn't carry any extra information
382 for us because only the low 32 bits of the registers are
384 struct gcc_mcontext64
*m64
= (struct gcc_mcontext64
*)uctx
->mcontext
;
387 float_vector_state
= &m64
->fvs
;
389 new_cfa
= m64
->gpr
[1][1];
391 set_offset (R_CR2
, &m64
->cr
);
392 for (i
= 0; i
< 32; i
++)
393 set_offset (i
, m64
->gpr
[i
] + 1);
394 set_offset (R_XER
, m64
->xer
+ 1);
395 set_offset (R_LR
, m64
->lr
+ 1);
396 set_offset (R_CTR
, m64
->ctr
+ 1);
398 set_offset (R_VRSAVE
, &m64
->vrsave
);
400 /* Sometimes, srr0 points to the instruction that caused the exception,
401 and sometimes to the next instruction to be executed; we want
403 if (m64
->exception
== 3 || m64
->exception
== 4
404 || m64
->exception
== 6
405 || (m64
->exception
== 7 && !(m64
->srr1
& 0x10000)))
406 return_addr
= m64
->srr0
+ 4;
408 return_addr
= m64
->srr0
;
412 struct gcc_mcontext32
*m
= uctx
->mcontext
;
415 float_vector_state
= &m
->fvs
;
419 set_offset (R_CR2
, &m
->cr
);
420 for (i
= 0; i
< 32; i
++)
421 set_offset (i
, m
->gpr
+ i
);
422 set_offset (R_XER
, &m
->xer
);
423 set_offset (R_LR
, &m
->lr
);
424 set_offset (R_CTR
, &m
->ctr
);
427 set_offset (R_VRSAVE
, &m
->vrsave
);
429 /* Sometimes, srr0 points to the instruction that caused the exception,
430 and sometimes to the next instruction to be executed; we want
432 if (m
->exception
== 3 || m
->exception
== 4
434 || (m
->exception
== 7 && !(m
->srr1
& 0x10000)))
435 return_addr
= m
->srr0
+ 4;
437 return_addr
= m
->srr0
;
440 fs
->regs
.cfa_how
= CFA_REG_OFFSET
;
441 fs
->regs
.cfa_reg
= __LIBGCC_STACK_POINTER_REGNUM__
;
442 fs
->regs
.cfa_offset
= new_cfa
- old_cfa
;;
444 /* The choice of column for the return address is somewhat tricky.
445 Fortunately, the actual choice is private to this file, and
446 the space it's reserved from is the GCC register space, not the
447 DWARF2 numbering. So any free element of the right size is an OK
449 fs
->retaddr_column
= ARG_POINTER_REGNUM
;
450 /* FIXME: this should really be done using a DWARF2 location expression,
451 not using a static variable. In fact, this entire file should
452 be implemented in DWARF2 expressions. */
453 set_offset (ARG_POINTER_REGNUM
, &return_addr
);
455 for (i
= 0; i
< 32; i
++)
456 set_offset (32 + i
, float_vector_state
->fpregs
+ i
);
457 set_offset (R_SPEFSCR
, &float_vector_state
->fpscr
);
461 for (i
= 0; i
< 32; i
++)
462 set_offset (R_VR0
+ i
, float_vector_state
->save_vr
+ i
);
463 set_offset (R_VSCR
, float_vector_state
->save_vscr
);
469 /* This is also prototyped in rs6000/darwin.h, inside the
470 MD_FALLBACK_FRAME_STATE_FOR macro. */
471 extern bool _Unwind_fallback_frame_state_for (struct _Unwind_Context
*context
,
472 _Unwind_FrameState
*fs
);
474 /* Implement the MD_FALLBACK_FRAME_STATE_FOR macro,
475 returning true iff the frame was a sigreturn() frame that we
479 _Unwind_fallback_frame_state_for (struct _Unwind_Context
*context
,
480 _Unwind_FrameState
*fs
)
484 if (!interpret_libc (gprs
, context
))
486 return handle_syscall (fs
, gprs
, _Unwind_GetCFA (context
));