]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgcc/config/rs6000/linux-unwind.h
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / rs6000 / linux-unwind.h
1 /* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
2 Copyright (C) 2004-2022 Free Software Foundation, Inc.
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
8 by the Free Software Foundation; either version 3, or (at your
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
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/>. */
24
25 #define R_LR 65
26 #define R_CR2 70
27 #define R_CR3 71
28 #define R_CR4 72
29 #define R_VR0 77
30 #define R_VRSAVE 109
31
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
40 struct 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
55 struct gcc_regs
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;
63 unsigned long xer;
64 unsigned long ccr;
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;
80 };
81
82 struct gcc_ucontext
83 {
84 #ifdef __powerpc64__
85 unsigned long pad[28];
86 #else
87 unsigned long pad[12];
88 #endif
89 struct gcc_regs *regs;
90 struct gcc_regs rsave;
91 };
92
93 #ifdef __powerpc64__
94
95 enum { SIGNAL_FRAMESIZE = 128 };
96
97 struct 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
106 /* If PC is at a sigreturn trampoline, return a pointer to the
107 regs. Otherwise return NULL. */
108
109 static struct gcc_regs *
110 get_regs (struct _Unwind_Context *context)
111 {
112 const unsigned int *pc = context->ra;
113
114 /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */
115 /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */
116 if (pc[0] != 0x38210000 + SIGNAL_FRAMESIZE || pc[2] != 0x44000002)
117 return NULL;
118 if (pc[1] == 0x38000077)
119 {
120 struct sigframe {
121 char gap[SIGNAL_FRAMESIZE];
122 unsigned long pad[7];
123 struct gcc_regs *regs;
124 } *frame = (struct sigframe *) context->cfa;
125 return frame->regs;
126 }
127 else if (pc[1] == 0x380000AC)
128 {
129 #if _CALL_ELF != 2
130 /* These old kernel versions never supported ELFv2. */
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. */
135 const struct rt_sigframe_24 {
136 int tramp[6];
137 void *pinfo;
138 struct gcc_ucontext *puc;
139 } *frame24 = (const struct rt_sigframe_24 *) context->ra;
140
141 /* Test for magic value in *puc of vdso. */
142 if ((long) frame24->puc != -21 * 8)
143 return frame24->puc->regs;
144 else
145 #endif
146 {
147 /* This works for 2.4.21 and later kernels. */
148 struct rt_sigframe *frame = (struct rt_sigframe *) context->cfa;
149 return frame->uc.regs;
150 }
151 }
152 return NULL;
153 }
154
155 #else /* !__powerpc64__ */
156
157 enum { SIGNAL_FRAMESIZE = 64 };
158
159 struct rt_sigframe {
160 char gap[SIGNAL_FRAMESIZE + 16];
161 char siginfo[128];
162 struct gcc_ucontext uc;
163 };
164
165 static struct gcc_regs *
166 get_regs (struct _Unwind_Context *context)
167 {
168 const unsigned int *pc = context->ra;
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) */
174 if (pc[1] != 0x44000002)
175 return NULL;
176 if (pc[0] == 0x38007777 || pc[0] == 0x38000077)
177 {
178 struct sigframe {
179 char gap[SIGNAL_FRAMESIZE];
180 unsigned long pad[7];
181 struct gcc_regs *regs;
182 } *frame = (struct sigframe *) context->cfa;
183 return frame->regs;
184 }
185 else if (pc[0] == 0x38006666 || pc[0] == 0x380000AC)
186 {
187 struct rt_sigframe *frame = (struct rt_sigframe *) context->cfa;
188 return frame->uc.regs;
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
199 static _Unwind_Reason_Code
200 ppc_fallback_frame_state (struct _Unwind_Context *context,
201 _Unwind_FrameState *fs)
202 {
203 struct gcc_regs *regs = get_regs (context);
204 struct gcc_vregs *vregs;
205 long cr_offset;
206 long new_cfa;
207 int i;
208
209 if (regs == NULL)
210 return _URC_NORMAL_STOP;
211
212 new_cfa = regs->gpr[__LIBGCC_STACK_POINTER_REGNUM__];
213 fs->regs.cfa_how = CFA_REG_OFFSET;
214 fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__;
215 fs->regs.cfa_offset = new_cfa - (long) context->cfa;
216
217 #ifdef __powerpc64__
218 fs->regs.reg[2].how = REG_SAVED_OFFSET;
219 fs->regs.reg[2].loc.offset = (long) &regs->gpr[2] - new_cfa;
220 #endif
221 for (i = 14; i < 32; i++)
222 {
223 fs->regs.reg[i].how = REG_SAVED_OFFSET;
224 fs->regs.reg[i].loc.offset = (long) &regs->gpr[i] - new_cfa;
225 }
226
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
232 /* In the ELFv1 ABI, CR2 stands in for the whole CR. */
233 fs->regs.reg[R_CR2].how = REG_SAVED_OFFSET;
234 fs->regs.reg[R_CR2].loc.offset = cr_offset;
235 #if _CALL_ELF == 2
236 /* In the ELFv2 ABI, every CR field has a separate CFI entry. */
237 fs->regs.reg[R_CR3].how = REG_SAVED_OFFSET;
238 fs->regs.reg[R_CR3].loc.offset = cr_offset;
239 fs->regs.reg[R_CR4].how = REG_SAVED_OFFSET;
240 fs->regs.reg[R_CR4].loc.offset = cr_offset;
241 #endif
242
243 fs->regs.reg[R_LR].how = REG_SAVED_OFFSET;
244 fs->regs.reg[R_LR].loc.offset = (long) &regs->link - new_cfa;
245
246 fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
247 fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) &regs->nip - new_cfa;
248 fs->retaddr_column = ARG_POINTER_REGNUM;
249 fs->signal_frame = 1;
250
251 /* If we have a FPU... */
252 for (i = 14; i < 32; i++)
253 {
254 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
255 fs->regs.reg[i + 32].loc.offset = (long) &regs->fpr[i] - new_cfa;
256 }
257
258 /* If we have a VMX unit... */
259 #ifdef __powerpc64__
260 vregs = regs->vp;
261 #else
262 vregs = &regs->vregs;
263 #endif
264 if (regs->msr & (1 << 25))
265 {
266 for (i = 20; i < 32; i++)
267 {
268 fs->regs.reg[i + R_VR0].how = REG_SAVED_OFFSET;
269 fs->regs.reg[i + R_VR0].loc.offset = (long) &vregs->vr[i] - new_cfa;
270 }
271 }
272
273 fs->regs.reg[R_VRSAVE].how = REG_SAVED_OFFSET;
274 fs->regs.reg[R_VRSAVE].loc.offset = (long) &vregs->vsave - new_cfa;
275
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__
279 for (i = 14; i < 32; i++)
280 {
281 fs->regs.reg[i + FIRST_SPE_HIGH_REGNO - 4].how = REG_SAVED_OFFSET;
282 fs->regs.reg[i + FIRST_SPE_HIGH_REGNO - 4].loc.offset
283 = (long) &regs->vregs - new_cfa + 4 * i;
284 }
285 #endif
286
287 return _URC_NO_REASON;
288 }
289
290 #define MD_FROB_UPDATE_CONTEXT frob_update_context
291
292 static void
293 frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATTRIBUTE_UNUSED)
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)
305 _Unwind_SetSignalFrame (context, 1);
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)
314 _Unwind_SetSignalFrame (context, 1);
315 #endif
316
317 #ifdef __powerpc64__
318 if (fs->regs.reg[2].how == REG_UNSAVED)
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. */
325 if (pc[0] == 0xF8410000 + TOC_SAVE_SLOT
326 #if _CALL_ELF != 2
327 /* The ELFv2 linker never generates the old PLT stub form. */
328 || ((pc[0] & 0xFFFF0000) == 0x3D820000
329 && pc[1] == 0xF8410000 + TOC_SAVE_SLOT)
330 #endif
331 )
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 }
336 else
337 {
338 unsigned int *insn
339 = (unsigned int *) _Unwind_GetGR (context, R_LR);
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. */
344 else if (pc[0] == 0x4E800421
345 && pc[1] == 0xE8410000 + TOC_SAVE_SLOT)
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);
352 _Unwind_SetGRPtr (context, 2, (void *)(sp + TOC_SAVE_SLOT));
353 }
354 #endif
355 }
356 }
357 #endif
358 }
359
360 #define MD_BACKCHAIN_FALLBACK ppc_backchain_fallback
361
362 struct 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 */
388 struct 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
398 static void
399 ppc_backchain_fallback (struct _Unwind_Context *context, void *a)
400 {
401 struct frame_layout *current;
402 struct trace_arg *arg = a;
403 int count;
404
405 /* Get the last address computed. */
406 current = context->cfa;
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. */
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 }