(root)/
gcc-13.2.0/
libgcc/
config/
rs6000/
linux-unwind.h
       1  /* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
       2     Copyright (C) 2004-2023 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.how[2] = 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.how[i] = 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.how[R_CR2] = 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.how[R_CR3] = REG_SAVED_OFFSET;
     238    fs->regs.reg[R_CR3].loc.offset = cr_offset;
     239    fs->regs.how[R_CR4] = REG_SAVED_OFFSET;
     240    fs->regs.reg[R_CR4].loc.offset = cr_offset;
     241  #endif
     242  
     243    fs->regs.how[R_LR] = REG_SAVED_OFFSET;
     244    fs->regs.reg[R_LR].loc.offset = (long) &regs->link - new_cfa;
     245  
     246    fs->regs.how[ARG_POINTER_REGNUM] = 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.how[i + 32] = 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.how[i + R_VR0] = REG_SAVED_OFFSET;
     269  	  fs->regs.reg[i + R_VR0].loc.offset = (long) &vregs->vr[i] - new_cfa;
     270  	}
     271      }
     272  
     273    fs->regs.how[R_VRSAVE] = 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.how[i + FIRST_SPE_HIGH_REGNO - 4] = 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.how[2] == 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  }