xref: /netbsd-src/external/gpl3/gcc/dist/libgcc/config/rs6000/linux-unwind.h (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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 *
get_regs(struct _Unwind_Context * context)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 *
get_regs(struct _Unwind_Context * context)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
ppc_fallback_frame_state(struct _Unwind_Context * context,_Unwind_FrameState * fs)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
frob_update_context(struct _Unwind_Context * context,_Unwind_FrameState * fs ATTRIBUTE_UNUSED)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
ppc_backchain_fallback(struct _Unwind_Context * context,void * a)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 }
436