]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/rs6000/linux-unwind.h
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / rs6000 / linux-unwind.h
CommitLineData
8662eb14 1/* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
83ffe9cd 2 Copyright (C) 2004-2023 Free Software Foundation, Inc.
8662eb14
AM
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
748086b7 8 by the Free Software Foundation; either version 3, or (at your
8662eb14
AM
9 option) any later version.
10
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.
8662eb14 19
748086b7
JJ
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/>. */
8662eb14 24
1de43f85
DE
25#define R_LR 65
26#define R_CR2 70
b54214fe
UW
27#define R_CR3 71
28#define R_CR4 72
1de43f85
DE
29#define R_VR0 77
30#define R_VRSAVE 109
1de43f85 31
b54214fe
UW
32#ifdef __powerpc64__
33#if _CALL_ELF == 2
34#define TOC_SAVE_SLOT 24
35#else
36#define TOC_SAVE_SLOT 40
37#endif
38#endif
39
a7a52913
AM
40struct gcc_vregs
41{
42 __attribute__ ((vector_size (16))) int vr[32];
43#ifdef __powerpc64__
44 unsigned int pad1[3];
45 unsigned int vscr;
46 unsigned int vsave;
47 unsigned int pad2[3];
48#else
49 unsigned int vsave;
50 unsigned int pad[2];
51 unsigned int vscr;
52#endif
53};
54
55struct gcc_regs
8662eb14
AM
56{
57 unsigned long gpr[32];
58 unsigned long nip;
59 unsigned long msr;
60 unsigned long orig_gpr3;
61 unsigned long ctr;
62 unsigned long link;
43e7c6a4
AM
63 unsigned long xer;
64 unsigned long ccr;
a7a52913
AM
65 unsigned long softe;
66 unsigned long trap;
67 unsigned long dar;
68 unsigned long dsisr;
69 unsigned long result;
70 unsigned long pad1[4];
71 double fpr[32];
72 unsigned int pad2;
73 unsigned int fpscr;
74#ifdef __powerpc64__
75 struct gcc_vregs *vp;
76#else
77 unsigned int pad3[2];
78#endif
79 struct gcc_vregs vregs;
8662eb14
AM
80};
81
82struct gcc_ucontext
83{
84#ifdef __powerpc64__
a7a52913 85 unsigned long pad[28];
8662eb14 86#else
a7a52913 87 unsigned long pad[12];
8662eb14 88#endif
a7a52913
AM
89 struct gcc_regs *regs;
90 struct gcc_regs rsave;
8662eb14
AM
91};
92
93#ifdef __powerpc64__
94
95enum { SIGNAL_FRAMESIZE = 128 };
96
b7561b5d
RMZ
97struct rt_sigframe {
98 char gap[SIGNAL_FRAMESIZE];
99 struct gcc_ucontext uc;
100 unsigned long pad[2];
101 int tramp[6];
102 void *pinfo;
103 struct gcc_ucontext *puc;
104};
105
8662eb14 106/* If PC is at a sigreturn trampoline, return a pointer to the
a7a52913 107 regs. Otherwise return NULL. */
8662eb14 108
a7a52913
AM
109static struct gcc_regs *
110get_regs (struct _Unwind_Context *context)
8662eb14 111{
9a461028 112 const unsigned int *pc = context->ra;
8662eb14
AM
113
114 /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */
115 /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */
9a461028 116 if (pc[0] != 0x38210000 + SIGNAL_FRAMESIZE || pc[2] != 0x44000002)
8662eb14 117 return NULL;
9a461028 118 if (pc[1] == 0x38000077)
8662eb14
AM
119 {
120 struct sigframe {
121 char gap[SIGNAL_FRAMESIZE];
a7a52913
AM
122 unsigned long pad[7];
123 struct gcc_regs *regs;
124 } *frame = (struct sigframe *) context->cfa;
125 return frame->regs;
8662eb14 126 }
9a461028 127 else if (pc[1] == 0x380000AC)
8662eb14 128 {
b54214fe
UW
129#if _CALL_ELF != 2
130 /* These old kernel versions never supported ELFv2. */
a7a52913
AM
131 /* This works for 2.4 kernels, but not for 2.6 kernels with vdso
132 because pc isn't pointing into the stack. Can be removed when
133 no one is running 2.4.19 or 2.4.20, the first two ppc64
134 kernels released. */
9a461028 135 const struct rt_sigframe_24 {
8662eb14
AM
136 int tramp[6];
137 void *pinfo;
138 struct gcc_ucontext *puc;
9a461028 139 } *frame24 = (const struct rt_sigframe_24 *) context->ra;
a7a52913
AM
140
141 /* Test for magic value in *puc of vdso. */
142 if ((long) frame24->puc != -21 * 8)
143 return frame24->puc->regs;
144 else
b54214fe 145#endif
a7a52913
AM
146 {
147 /* This works for 2.4.21 and later kernels. */
b7561b5d 148 struct rt_sigframe *frame = (struct rt_sigframe *) context->cfa;
a7a52913
AM
149 return frame->uc.regs;
150 }
8662eb14
AM
151 }
152 return NULL;
153}
154
155#else /* !__powerpc64__ */
156
157enum { SIGNAL_FRAMESIZE = 64 };
158
b7561b5d
RMZ
159struct rt_sigframe {
160 char gap[SIGNAL_FRAMESIZE + 16];
161 char siginfo[128];
162 struct gcc_ucontext uc;
163};
164
a7a52913
AM
165static struct gcc_regs *
166get_regs (struct _Unwind_Context *context)
8662eb14 167{
9a461028 168 const unsigned int *pc = context->ra;
8662eb14
AM
169
170 /* li r0, 0x7777; sc (sigreturn old) */
171 /* li r0, 0x0077; sc (sigreturn new) */
172 /* li r0, 0x6666; sc (rt_sigreturn old) */
173 /* li r0, 0x00AC; sc (rt_sigreturn new) */
9a461028 174 if (pc[1] != 0x44000002)
8662eb14 175 return NULL;
9a461028 176 if (pc[0] == 0x38007777 || pc[0] == 0x38000077)
8662eb14
AM
177 {
178 struct sigframe {
179 char gap[SIGNAL_FRAMESIZE];
a7a52913
AM
180 unsigned long pad[7];
181 struct gcc_regs *regs;
182 } *frame = (struct sigframe *) context->cfa;
183 return frame->regs;
8662eb14 184 }
9a461028 185 else if (pc[0] == 0x38006666 || pc[0] == 0x380000AC)
8662eb14 186 {
b7561b5d 187 struct rt_sigframe *frame = (struct rt_sigframe *) context->cfa;
a7a52913 188 return frame->uc.regs;
8662eb14
AM
189 }
190 return NULL;
191}
192#endif
193
194/* Do code reading to identify a signal frame, and set the frame
195 state data appropriately. See unwind-dw2.c for the structs. */
196
197#define MD_FALLBACK_FRAME_STATE_FOR ppc_fallback_frame_state
198
199static _Unwind_Reason_Code
200ppc_fallback_frame_state (struct _Unwind_Context *context,
201 _Unwind_FrameState *fs)
202{
a7a52913 203 struct gcc_regs *regs = get_regs (context);
110207ad 204 struct gcc_vregs *vregs;
13e0981a 205 long cr_offset;
8662eb14
AM
206 long new_cfa;
207 int i;
208
a7a52913 209 if (regs == NULL)
b7561b5d 210 return _URC_NORMAL_STOP;
8662eb14 211
53d68b9f 212 new_cfa = regs->gpr[__LIBGCC_STACK_POINTER_REGNUM__];
6673f90b 213 fs->regs.cfa_how = CFA_REG_OFFSET;
53d68b9f 214 fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__;
6673f90b 215 fs->regs.cfa_offset = new_cfa - (long) context->cfa;
8662eb14 216
110207ad 217#ifdef __powerpc64__
146e4591 218 fs->regs.how[2] = REG_SAVED_OFFSET;
110207ad
AM
219 fs->regs.reg[2].loc.offset = (long) &regs->gpr[2] - new_cfa;
220#endif
221 for (i = 14; i < 32; i++)
222 {
146e4591 223 fs->regs.how[i] = REG_SAVED_OFFSET;
110207ad
AM
224 fs->regs.reg[i].loc.offset = (long) &regs->gpr[i] - new_cfa;
225 }
8662eb14 226
13e0981a
UW
227 /* The CR is saved in the low 32 bits of regs->ccr. */
228 cr_offset = (long) &regs->ccr - new_cfa;
229#ifndef __LITTLE_ENDIAN__
230 cr_offset += sizeof (long) - 4;
231#endif
b54214fe 232 /* In the ELFv1 ABI, CR2 stands in for the whole CR. */
146e4591 233 fs->regs.how[R_CR2] = REG_SAVED_OFFSET;
13e0981a 234 fs->regs.reg[R_CR2].loc.offset = cr_offset;
b54214fe
UW
235#if _CALL_ELF == 2
236 /* In the ELFv2 ABI, every CR field has a separate CFI entry. */
146e4591 237 fs->regs.how[R_CR3] = REG_SAVED_OFFSET;
b54214fe 238 fs->regs.reg[R_CR3].loc.offset = cr_offset;
146e4591 239 fs->regs.how[R_CR4] = REG_SAVED_OFFSET;
b54214fe
UW
240 fs->regs.reg[R_CR4].loc.offset = cr_offset;
241#endif
43e7c6a4 242
146e4591 243 fs->regs.how[R_LR] = REG_SAVED_OFFSET;
1de43f85 244 fs->regs.reg[R_LR].loc.offset = (long) &regs->link - new_cfa;
8662eb14 245
146e4591 246 fs->regs.how[ARG_POINTER_REGNUM] = REG_SAVED_OFFSET;
a7a52913 247 fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) &regs->nip - new_cfa;
8662eb14 248 fs->retaddr_column = ARG_POINTER_REGNUM;
754e45a8 249 fs->signal_frame = 1;
a7a52913 250
110207ad
AM
251 /* If we have a FPU... */
252 for (i = 14; i < 32; i++)
a7a52913 253 {
146e4591 254 fs->regs.how[i + 32] = REG_SAVED_OFFSET;
110207ad 255 fs->regs.reg[i + 32].loc.offset = (long) &regs->fpr[i] - new_cfa;
a7a52913
AM
256 }
257
a7a52913 258 /* If we have a VMX unit... */
a7a52913 259#ifdef __powerpc64__
110207ad 260 vregs = regs->vp;
a7a52913 261#else
110207ad 262 vregs = &regs->vregs;
a7a52913 263#endif
110207ad
AM
264 if (regs->msr & (1 << 25))
265 {
266 for (i = 20; i < 32; i++)
a7a52913 267 {
146e4591 268 fs->regs.how[i + R_VR0] = REG_SAVED_OFFSET;
110207ad 269 fs->regs.reg[i + R_VR0].loc.offset = (long) &vregs->vr[i] - new_cfa;
a7a52913 270 }
a7a52913
AM
271 }
272
146e4591 273 fs->regs.how[R_VRSAVE] = REG_SAVED_OFFSET;
110207ad
AM
274 fs->regs.reg[R_VRSAVE].loc.offset = (long) &vregs->vsave - new_cfa;
275
37ea0b7e
JM
276 /* If we have SPE register high-parts... we check at compile-time to
277 avoid expanding the code for all other PowerPC. */
278#ifdef __SPE__
110207ad 279 for (i = 14; i < 32; i++)
37ea0b7e 280 {
146e4591 281 fs->regs.how[i + FIRST_SPE_HIGH_REGNO - 4] = REG_SAVED_OFFSET;
23742a9e 282 fs->regs.reg[i + FIRST_SPE_HIGH_REGNO - 4].loc.offset
37ea0b7e
JM
283 = (long) &regs->vregs - new_cfa + 4 * i;
284 }
285#endif
286
8662eb14
AM
287 return _URC_NO_REASON;
288}
754e45a8
JJ
289
290#define MD_FROB_UPDATE_CONTEXT frob_update_context
291
292static void
75334508 293frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATTRIBUTE_UNUSED)
754e45a8
JJ
294{
295 const unsigned int *pc = (const unsigned int *) context->ra;
296
297 /* Fix up for 2.6.12 - 2.6.16 Linux kernels that have vDSO, but don't
298 have S flag in it. */
299#ifdef __powerpc64__
300 /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */
301 /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */
302 if (pc[0] == 0x38210000 + SIGNAL_FRAMESIZE
303 && (pc[1] == 0x38000077 || pc[1] == 0x380000AC)
304 && pc[2] == 0x44000002)
f8e7718c 305 _Unwind_SetSignalFrame (context, 1);
754e45a8
JJ
306#else
307 /* li r0, 0x7777; sc (sigreturn old) */
308 /* li r0, 0x0077; sc (sigreturn new) */
309 /* li r0, 0x6666; sc (rt_sigreturn old) */
310 /* li r0, 0x00AC; sc (rt_sigreturn new) */
311 if ((pc[0] == 0x38007777 || pc[0] == 0x38000077
312 || pc[0] == 0x38006666 || pc[0] == 0x380000AC)
313 && pc[1] == 0x44000002)
f8e7718c 314 _Unwind_SetSignalFrame (context, 1);
754e45a8
JJ
315#endif
316
317#ifdef __powerpc64__
146e4591 318 if (fs->regs.how[2] == REG_UNSAVED)
754e45a8
JJ
319 {
320 /* If the current unwind info (FS) does not contain explicit info
321 saving R2, then we have to do a minor amount of code reading to
322 figure out if it was saved. The big problem here is that the
323 code that does the save/restore is generated by the linker, so
324 we have no good way to determine at compile time what to do. */
b54214fe
UW
325 if (pc[0] == 0xF8410000 + TOC_SAVE_SLOT
326#if _CALL_ELF != 2
327 /* The ELFv2 linker never generates the old PLT stub form. */
2374a88a 328 || ((pc[0] & 0xFFFF0000) == 0x3D820000
b54214fe
UW
329 && pc[1] == 0xF8410000 + TOC_SAVE_SLOT)
330#endif
331 )
2374a88a
AM
332 {
333 /* We are in a plt call stub or r2 adjusting long branch stub,
334 before r2 has been saved. Keep REG_UNSAVED. */
335 }
2374a88a
AM
336 else
337 {
338 unsigned int *insn
339 = (unsigned int *) _Unwind_GetGR (context, R_LR);
b54214fe
UW
340 if (insn && *insn == 0xE8410000 + TOC_SAVE_SLOT)
341 _Unwind_SetGRPtr (context, 2, context->cfa + TOC_SAVE_SLOT);
342#if _CALL_ELF != 2
343 /* ELFv2 does not use this function pointer call sequence. */
bd15e32c 344 else if (pc[0] == 0x4E800421
b54214fe 345 && pc[1] == 0xE8410000 + TOC_SAVE_SLOT)
bd15e32c
AM
346 {
347 /* We are at the bctrl instruction in a call via function
348 pointer. gcc always emits the load of the new R2 just
349 before the bctrl so this is the first and only place
350 we need to use the stored R2. */
351 _Unwind_Word sp = _Unwind_GetGR (context, 1);
b54214fe 352 _Unwind_SetGRPtr (context, 2, (void *)(sp + TOC_SAVE_SLOT));
bd15e32c 353 }
b54214fe 354#endif
2374a88a 355 }
754e45a8
JJ
356 }
357#endif
358}
b7561b5d
RMZ
359
360#define MD_BACKCHAIN_FALLBACK ppc_backchain_fallback
361
362struct trace_arg
363{
364 /* Stores the list of addresses. */
365 void **array;
366 struct unwind_link *unwind_link;
367 _Unwind_Word cfa;
368 /* Number of addresses currently stored. */
369 int count;
370 /* Maximum number of addresses. */
371 int size;
372};
373
374/* This is the stack layout we see with every stack frame.
375 Note that every routine is required by the ABI to lay out the stack
376 like this.
377
378 +----------------+ +-----------------+
379 %r1 -> | previous frame--------> | previous frame--->... --> NULL
380 | | | |
381 | cr save | | cr save |
382 | | | |
383 | (unused) | | lr save |
384 +----------------+ +-----------------+
385
386 The CR save is only present on 64-bit ABIs.
387*/
388struct frame_layout
389{
390 struct frame_layout *backchain;
391#ifdef __powerpc64__
392 long int cr_save;
393#endif
394 void *lr_save;
395};
396
397
75ef0353
JJ
398static void
399ppc_backchain_fallback (struct _Unwind_Context *context, void *a)
b7561b5d
RMZ
400{
401 struct frame_layout *current;
402 struct trace_arg *arg = a;
403 int count;
404
8d71d3a3 405 /* Get the last address computed. */
b7561b5d 406 current = context->cfa;
8d71d3a3
RMZ
407
408 /* If the trace CFA is not the context CFA the backtrace is done. */
409 if (arg == NULL || arg->cfa != current)
410 return;
411
412 /* Start with next address. */
b7561b5d
RMZ
413 current = current->backchain;
414
415 for (count = arg->count; current != NULL; current = current->backchain)
416 {
417 arg->array[count] = current->lr_save;
418
419 /* Check if the symbol is the signal trampoline and get the interrupted
420 symbol address from the trampoline saved area. */
421 context->ra = current->lr_save;
422 if (current->lr_save && get_regs (context))
423 {
424 struct rt_sigframe *sigframe = (struct rt_sigframe *) current;
425 if (count + 1 == arg->size)
426 break;
427 arg->array[++count] = (void *) sigframe->uc.rsave.nip;
428 current = (void *) sigframe->uc.rsave.gpr[1];
429 }
430 if (count++ >= arg->size)
431 break;
432 }
433
434 arg->count = count-1;
435}