]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/rs6000/darwin-fallback.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / rs6000 / darwin-fallback.c
CommitLineData
f8a57be8 1/* Fallback frame-state unwinder for Darwin.
83ffe9cd 2 Copyright (C) 2004-2023 Free Software Foundation, Inc.
f8a57be8
GK
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 by
748086b7 8 the Free Software Foundation; either version 3, or (at your option)
f8a57be8
GK
9 any later version.
10
f8a57be8
GK
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.
15
748086b7
JJ
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.
19
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/>. */
f8a57be8 24
49522de2
GK
25#ifdef __ppc__
26
f8a57be8
GK
27#include "tconfig.h"
28#include "tsystem.h"
29#include "coretypes.h"
30#include "tm.h"
852b75ed 31#include "libgcc_tm.h"
a80b0574 32#include "dwarf2.h"
f8a57be8
GK
33#include "unwind.h"
34#include "unwind-dw2.h"
35#include <stdint.h>
36#include <stdbool.h>
7880e30b 37#include <sys/types.h>
f8a57be8 38#include <signal.h>
f8a57be8 39
1de43f85
DE
40#define R_LR 65
41#define R_CTR 66
42#define R_CR2 70
43#define R_XER 76
44#define R_VR0 77
45#define R_VRSAVE 109
46#define R_VSCR 110
47#define R_SPEFSCR 112
48
f8a57be8
GK
49typedef unsigned long reg_unit;
50
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. */
54
55static bool
56interpret_libc (reg_unit gprs[32], struct _Unwind_Context *context)
57{
58 uint32_t *pc = (uint32_t *)_Unwind_GetIP (context);
59 uint32_t cr;
60 reg_unit lr = (reg_unit) pc;
61 reg_unit ctr = 0;
62 uint32_t *invalid_address = NULL;
63
64 int i;
65
66 for (i = 0; i < 13; i++)
67 gprs[i] = 1;
68 gprs[1] = _Unwind_GetCFA (context);
69 for (; i < 32; i++)
70 gprs[i] = _Unwind_GetGR (context, i);
fb0671a8 71 cr = _Unwind_GetGR (context, R_CR2);
f8a57be8
GK
72
73 /* For each supported Libc, we have to track the code flow
74 all the way back into the kernel.
75
76 This code is believed to support all released Libc/Libsystem builds since
77 Jaguar 6C115, including all the security updates. To be precise,
78
79 Libc Libsystem Build(s)
80 262~1 60~37 6C115
81 262~1 60.2~4 6D52
82 262~1 61~3 6F21-6F22
83 262~1 63~24 6G30-6G37
84 262~1 63~32 6I34-6I35
85 262~1 63~64 6L29-6L60
86 262.4.1~1 63~84 6L123-6R172
87
88 320~1 71~101 7B85-7D28
89 320~1 71~266 7F54-7F56
90 320~1 71~288 7F112
91 320~1 71~289 7F113
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
95
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
98 it would do.
99 */
100
101 for (;;)
102 {
103 uint32_t ins = *pc++;
104
105 if ((ins & 0xFC000003) == 0x48000000) /* b instruction */
106 {
107 pc += ((((int32_t) ins & 0x3FFFFFC) ^ 0x2000000) - 0x2000004) / 4;
108 continue;
109 }
110 if ((ins & 0xFC600000) == 0x2C000000) /* cmpwi */
111 {
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);
117 if (val1 == val2)
118 cr |= mask;
119 else
120 cr &= ~mask;
121 continue;
122 }
123 if ((ins & 0xFEC38003) == 0x40820000) /* forwards beq/bne */
124 {
125 if ((cr >> ((ins >> 16 & 0x1F) ^ 0x1F) & 1) == (ins >> 24 & 1))
126 pc += (ins & 0x7FFC) / 4 - 1;
127 continue;
128 }
129 if ((ins & 0xFC0007FF) == 0x7C000378) /* or, including mr */
130 {
131 gprs [ins >> 16 & 0x1F] = (gprs [ins >> 11 & 0x1F]
132 | gprs [ins >> 21 & 0x1F]);
133 continue;
134 }
135 if (ins >> 26 == 0x0E) /* addi, including li */
136 {
137 reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
138 gprs [ins >> 21 & 0x1F] = src + (int16_t) ins;
139 continue;
140 }
141 if (ins >> 26 == 0x0F) /* addis, including lis */
142 {
143 reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
144 gprs [ins >> 21 & 0x1F] = src + ((int16_t) ins << 16);
145 continue;
146 }
147 if (ins >> 26 == 0x20) /* lwz */
148 {
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)
152 return false;
153 gprs [ins >> 21 & 0x1F] = *p;
154 continue;
155 }
156 if (ins >> 26 == 0x21) /* lwzu */
157 {
158 uint32_t *p = (uint32_t *)(gprs [ins >> 16 & 0x1F] += (int16_t) ins);
159 if (p == invalid_address)
160 return false;
161 gprs [ins >> 21 & 0x1F] = *p;
162 continue;
163 }
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. */
168 {
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)
172 return false;
173 invalid_address = p;
174 continue;
175 }
176 if (ins >> 26 == 0x2E) /* lmw */
177 {
178 reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
179 uint32_t *p = (uint32_t *)(src + (int16_t) ins);
180 int i;
181
182 for (i = (ins >> 21 & 0x1F); i < 32; i++)
183 {
184 if (p == invalid_address)
185 return false;
186 gprs[i] = *p++;
187 }
188 continue;
189 }
190 if ((ins & 0xFC1FFFFF) == 0x7c0803a6) /* mtlr */
191 {
192 lr = gprs [ins >> 21 & 0x1F];
193 continue;
194 }
195 if ((ins & 0xFC1FFFFF) == 0x7c0802a6) /* mflr */
196 {
197 gprs [ins >> 21 & 0x1F] = lr;
198 continue;
199 }
200 if ((ins & 0xFC1FFFFF) == 0x7c0903a6) /* mtctr */
201 {
202 ctr = gprs [ins >> 21 & 0x1F];
203 continue;
204 }
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 */
209 {
210 int i;
211 uint32_t mask = 0;
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);
215 continue;
216 }
217 if (ins == 0x429f0005) /* bcl- 20,4*cr7+so,.+4, loads pc into LR */
218 {
219 lr = (reg_unit) pc;
220 continue;
221 }
222 if (ins == 0x4e800420) /* bctr */
223 {
224 pc = (uint32_t *) ctr;
225 continue;
226 }
227 if (ins == 0x44000002) /* sc */
228 return true;
229
230 return false;
231 }
232}
233
7880e30b
GK
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
237 directly. */
238
f8a57be8
GK
239/* These defines are from the kernel's bsd/dev/ppc/unix_signal.c. */
240#define UC_TRAD 1
241#define UC_TRAD_VEC 6
242#define UC_TRAD64 20
243#define UC_TRAD64_VEC 25
244#define UC_FLAVOR 30
245#define UC_FLAVOR_VEC 35
246#define UC_FLAVOR64 40
247#define UC_FLAVOR64_VEC 45
248#define UC_DUAL 50
249#define UC_DUAL_VEC 55
250
7880e30b
GK
251struct gcc_ucontext
252{
253 int onstack;
254 sigset_t sigmask;
255 void * stack_sp;
256 size_t stack_sz;
257 int stack_flags;
258 struct gcc_ucontext *link;
259 size_t mcsize;
260 struct gcc_mcontext32 *mcontext;
261};
262
263struct gcc_float_vector_state
264{
265 double fpregs[32];
266 uint32_t fpscr_pad;
267 uint32_t fpscr;
268 uint32_t save_vr[32][4];
269 uint32_t save_vscr[4];
270};
271
272struct gcc_mcontext32 {
273 uint32_t dar;
274 uint32_t dsisr;
275 uint32_t exception;
276 uint32_t padding1[5];
277 uint32_t srr0;
278 uint32_t srr1;
279 uint32_t gpr[32];
280 uint32_t cr;
281 uint32_t xer;
282 uint32_t lr;
283 uint32_t ctr;
284 uint32_t mq;
285 uint32_t vrsave;
286 struct gcc_float_vector_state fvs;
287};
288
f8a57be8
GK
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!). */
294
295struct gcc_mcontext64 {
296 uint64_t dar;
297 uint32_t dsisr;
298 uint32_t exception;
299 uint32_t padding1[4];
300 uint64_t srr0;
301 uint64_t srr1;
302 uint32_t gpr[32][2];
303 uint32_t cr;
304 uint32_t xer[2]; /* These are arrays because the original structure has them misaligned. */
305 uint32_t lr[2];
306 uint32_t ctr[2];
307 uint32_t vrsave;
7880e30b 308 struct gcc_float_vector_state fvs;
f8a57be8
GK
309};
310
311#define UC_FLAVOR_SIZE \
7880e30b 312 (sizeof (struct gcc_mcontext32) - 33*16)
f8a57be8 313
7880e30b 314#define UC_FLAVOR_VEC_SIZE (sizeof (struct gcc_mcontext32))
f8a57be8
GK
315
316#define UC_FLAVOR64_SIZE \
7880e30b 317 (sizeof (struct gcc_mcontext64) - 33*16)
f8a57be8
GK
318
319#define UC_FLAVOR64_VEC_SIZE (sizeof (struct gcc_mcontext64))
320
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. */
324
325static bool
326handle_syscall (_Unwind_FrameState *fs, const reg_unit gprs[32],
327 _Unwind_Ptr old_cfa)
328{
7880e30b 329 struct gcc_ucontext *uctx;
f8a57be8 330 bool is_64, is_vector;
7880e30b 331 struct gcc_float_vector_state * float_vector_state;
f8a57be8
GK
332 _Unwind_Ptr new_cfa;
333 int i;
334 static _Unwind_Ptr return_addr;
335
336 /* Yay! We're in a Libc that we understand, and it's made a
49522de2
GK
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. */
f8a57be8
GK
340
341 if (gprs[0] == 0x67 /* SYS_SIGRETURN */)
342 {
7880e30b
GK
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);
f8a57be8 348 }
49522de2 349 else if (gprs[0] == 0 /* SYS_syscall */ && gprs[3] == 184)
f8a57be8
GK
350 {
351 int ctxstyle = gprs[5];
7880e30b 352 uctx = (struct gcc_ucontext *) gprs[4];
f8a57be8
GK
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);
357 }
49522de2
GK
358 else if (gprs[0] == 184 /* SYS_sigreturn */)
359 {
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);
366 }
f8a57be8
GK
367 else
368 return false;
369
370#define set_offset(r, addr) \
146e4591 371 (fs->regs.how[r] = REG_SAVED_OFFSET, \
f8a57be8
GK
372 fs->regs.reg[r].loc.offset = (_Unwind_Ptr)(addr) - new_cfa)
373
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. */
377
378 /* Handle the GPRs, and produce the information needed to do the rest. */
379 if (is_64)
380 {
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
383 call-saved. */
7880e30b 384 struct gcc_mcontext64 *m64 = (struct gcc_mcontext64 *)uctx->mcontext;
f8a57be8
GK
385 int i;
386
7880e30b 387 float_vector_state = &m64->fvs;
f8a57be8
GK
388
389 new_cfa = m64->gpr[1][1];
390
1de43f85 391 set_offset (R_CR2, &m64->cr);
f8a57be8
GK
392 for (i = 0; i < 32; i++)
393 set_offset (i, m64->gpr[i] + 1);
1de43f85
DE
394 set_offset (R_XER, m64->xer + 1);
395 set_offset (R_LR, m64->lr + 1);
396 set_offset (R_CTR, m64->ctr + 1);
f8a57be8 397 if (is_vector)
1de43f85 398 set_offset (R_VRSAVE, &m64->vrsave);
f8a57be8
GK
399
400 /* Sometimes, srr0 points to the instruction that caused the exception,
401 and sometimes to the next instruction to be executed; we want
402 the latter. */
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;
407 else
408 return_addr = m64->srr0;
409 }
410 else
411 {
7880e30b 412 struct gcc_mcontext32 *m = uctx->mcontext;
f8a57be8
GK
413 int i;
414
7880e30b 415 float_vector_state = &m->fvs;
f8a57be8 416
7880e30b 417 new_cfa = m->gpr[1];
f8a57be8 418
1de43f85 419 set_offset (R_CR2, &m->cr);
f8a57be8 420 for (i = 0; i < 32; i++)
7880e30b 421 set_offset (i, m->gpr + i);
1de43f85
DE
422 set_offset (R_XER, &m->xer);
423 set_offset (R_LR, &m->lr);
424 set_offset (R_CTR, &m->ctr);
f8a57be8
GK
425
426 if (is_vector)
1de43f85 427 set_offset (R_VRSAVE, &m->vrsave);
f8a57be8
GK
428
429 /* Sometimes, srr0 points to the instruction that caused the exception,
430 and sometimes to the next instruction to be executed; we want
431 the latter. */
7880e30b
GK
432 if (m->exception == 3 || m->exception == 4
433 || m->exception == 6
434 || (m->exception == 7 && !(m->srr1 & 0x10000)))
435 return_addr = m->srr0 + 4;
f8a57be8 436 else
7880e30b 437 return_addr = m->srr0;
f8a57be8
GK
438 }
439
6673f90b 440 fs->regs.cfa_how = CFA_REG_OFFSET;
53d68b9f 441 fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__;
6673f90b 442 fs->regs.cfa_offset = new_cfa - old_cfa;;
f8a57be8
GK
443
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
448 choice. Thus: */
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);
454
455 for (i = 0; i < 32; i++)
7880e30b 456 set_offset (32 + i, float_vector_state->fpregs + i);
1de43f85 457 set_offset (R_SPEFSCR, &float_vector_state->fpscr);
f8a57be8
GK
458
459 if (is_vector)
460 {
461 for (i = 0; i < 32; i++)
1de43f85
DE
462 set_offset (R_VR0 + i, float_vector_state->save_vr + i);
463 set_offset (R_VSCR, float_vector_state->save_vscr);
f8a57be8
GK
464 }
465
466 return true;
467}
468
469/* This is also prototyped in rs6000/darwin.h, inside the
470 MD_FALLBACK_FRAME_STATE_FOR macro. */
471extern bool _Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
472 _Unwind_FrameState *fs);
473
474/* Implement the MD_FALLBACK_FRAME_STATE_FOR macro,
475 returning true iff the frame was a sigreturn() frame that we
476 can understand. */
477
478bool
479_Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
480 _Unwind_FrameState *fs)
481{
482 reg_unit gprs[32];
483
484 if (!interpret_libc (gprs, context))
485 return false;
486 return handle_syscall (fs, gprs, _Unwind_GetCFA (context));
487}
49522de2 488#endif