1  /* ARM EABI compliant unwinding routines
       2     Copyright (C) 2004-2023 Free Software Foundation, Inc.
       3     Contributed by Paul Brook
       4   
       5     This file is free software; you can redistribute it and/or modify it
       6     under the terms of the GNU General Public License as published by the
       7     Free Software Foundation; either version 3, or (at your option) any
       8     later version.
       9  
      10     This file is distributed in the hope that it will be useful, but
      11     WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     General Public License for more details.
      14  
      15     Under Section 7 of GPL version 3, you are granted additional
      16     permissions described in the GCC Runtime Library Exception, version
      17     3.1, as published by the Free Software Foundation.
      18  
      19     You should have received a copy of the GNU General Public License and
      20     a copy of the GCC Runtime Library Exception along with this program;
      21     see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      22     <http://www.gnu.org/licenses/>.  */
      23  
      24  #pragma GCC target ("general-regs-only")
      25  #include "unwind.h"
      26  
      27  /* We add a prototype for abort here to avoid creating a dependency on
      28     target headers.  */
      29  extern void abort (void);
      30  
      31  typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
      32  
      33  /* Misc constants.  */
      34  #define R_IP    12
      35  #define R_SP    13
      36  #define R_LR    14
      37  #define R_PC    15
      38  
      39  #define uint32_highbit (((_uw) 1) << 31)
      40  
      41  void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
      42  
      43  /* Unwind descriptors.  */
      44  
      45  typedef struct
      46  {
      47    _uw16 length;
      48    _uw16 offset;
      49  } EHT16;
      50  
      51  typedef struct
      52  {
      53    _uw length;
      54    _uw offset;
      55  } EHT32;
      56  
      57  /* Calculate the address encoded by a 31-bit self-relative offset at address
      58     P.  Copy of routine in unwind-arm.c.  */
      59  
      60  static inline _uw
      61  selfrel_offset31 (const _uw *p)
      62  {
      63    _uw offset;
      64  
      65    offset = *p;
      66    /* Sign extend to 32 bits.  */
      67    if (offset & (1 << 30))
      68      offset |= 1u << 31;
      69  
      70    return offset + (_uw) p;
      71  }
      72  
      73  
      74  /* Personality routine helper functions.  */
      75  
      76  #define CODE_FINISH (0xb0)
      77  
      78  /* Return the next byte of unwinding information, or CODE_FINISH if there is
      79     no data remaining.  */
      80  static inline _uw8
      81  next_unwind_byte (__gnu_unwind_state * uws)
      82  {
      83    _uw8 b;
      84  
      85    if (uws->bytes_left == 0)
      86      {
      87        /* Load another word */
      88        if (uws->words_left == 0)
      89  	return CODE_FINISH; /* Nothing left.  */
      90        uws->words_left--;
      91        uws->data = *(uws->next++);
      92        uws->bytes_left = 3;
      93      }
      94    else
      95      uws->bytes_left--;
      96  
      97    /* Extract the most significant byte.  */
      98    b = (uws->data >> 24) & 0xff;
      99    uws->data <<= 8;
     100    return b;
     101  }
     102  
     103  /* Execute the unwinding instructions described by UWS.  */
     104  _Unwind_Reason_Code
     105  __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
     106  {
     107    _uw op;
     108    int set_pc;
     109  #if defined(TARGET_HAVE_PACBTI)
     110    int set_pac = 0;
     111    int set_pac_sp = 0;
     112  #endif
     113    _uw reg;
     114    _uw sp;
     115  
     116    set_pc = 0;
     117    for (;;)
     118      {
     119        op = next_unwind_byte (uws);
     120        if (op == CODE_FINISH)
     121  	{
     122  	  /* When we reach end, we have to authenticate R12 we just popped
     123  	     earlier.
     124  
     125  	     Note: while the check provides additional security against a
     126  	     corrupted unwind chain, it isn't essential for correct unwinding
     127  	     of an uncorrupted chain.  */
     128  #if defined(TARGET_HAVE_PACBTI)
     129  	  if (set_pac)
     130  	    {
     131  	      _uw lr;
     132  	      _uw pac;
     133  	      if (!set_pac_sp)
     134  		_Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
     135  				 &sp);
     136  	      _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, &lr);
     137  	      _Unwind_VRS_Get (context, _UVRSC_PAC, R_IP,
     138  			       _UVRSD_UINT32, &pac);
     139  	      __asm__ __volatile__
     140  		("autg %0, %1, %2" : : "r"(pac), "r"(lr), "r"(sp) :);
     141  	    }
     142  #endif
     143  
     144  	  /* If we haven't already set pc then copy it from lr.  */
     145  	  if (!set_pc)
     146  	    {
     147  	      _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
     148  			       ®);
     149  	      _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
     150  			       ®);
     151  	      set_pc = 1;
     152  	    }
     153  	  /* Drop out of the loop.  */
     154  	  break;
     155  	}
     156        if ((op & 0x80) == 0)
     157  	{
     158  	  /* vsp = vsp +- (imm6 << 2 + 4).  */
     159  	  _uw offset;
     160  
     161  	  offset = ((op & 0x3f) << 2) + 4;
     162  	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®);
     163  	  if (op & 0x40)
     164  	    reg -= offset;
     165  	  else
     166  	    reg += offset;
     167  	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®);
     168  	  continue;
     169  	}
     170        
     171        if ((op & 0xf0) == 0x80)
     172  	{
     173  	  op = (op << 8) | next_unwind_byte (uws);
     174  	  if (op == 0x8000)
     175  	    {
     176  	      /* Refuse to unwind.  */
     177  	      return _URC_FAILURE;
     178  	    }
     179  	  /* Pop r4-r15 under mask.  */
     180  	  op = (op << 4) & 0xfff0;
     181  	  if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
     182  	      != _UVRSR_OK)
     183  	    return _URC_FAILURE;
     184  	  if (op & (1 << R_PC))
     185  	    set_pc = 1;
     186  	  continue;
     187  	}
     188        if ((op & 0xf0) == 0x90)
     189  	{
     190  	  op &= 0xf;
     191  	  if (op == 13 || op == 15)
     192  	    /* Reserved.  */
     193  	    return _URC_FAILURE;
     194  	  /* vsp = r[nnnn].  */
     195  	  _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, ®);
     196  	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®);
     197  	  continue;
     198  	}
     199        if ((op & 0xf0) == 0xa0)
     200  	{
     201  	  /* Pop r4-r[4+nnn], [lr].  */
     202  	  _uw mask;
     203  	  
     204  	  mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
     205  	  if (op & 8)
     206  	    mask |= (1 << R_LR);
     207  	  if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32)
     208  	      != _UVRSR_OK)
     209  	    return _URC_FAILURE;
     210  	  continue;
     211  	}
     212        if ((op & 0xf0) == 0xb0)
     213  	{
     214  	  /* op == 0xb0 already handled.  */
     215  	  if (op == 0xb1)
     216  	    {
     217  	      op = next_unwind_byte (uws);
     218  	      if (op == 0 || ((op & 0xf0) != 0))
     219  		/* Spare.  */
     220  		return _URC_FAILURE;
     221  	      /* Pop r0-r4 under mask.  */
     222  	      if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
     223  		  != _UVRSR_OK)
     224  		return _URC_FAILURE;
     225  	      continue;
     226  	    }
     227  	  if (op == 0xb2)
     228  	    {
     229  	      /* vsp = vsp + 0x204 + (uleb128 << 2).  */
     230  	      int shift;
     231  
     232  	      _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
     233  			       ®);
     234  	      op = next_unwind_byte (uws);
     235  	      shift = 2;
     236  	      while (op & 0x80)
     237  		{
     238  		  reg += ((op & 0x7f) << shift);
     239  		  shift += 7;
     240  		  op = next_unwind_byte (uws);
     241  		}
     242  	      reg += ((op & 0x7f) << shift) + 0x204;
     243  	      _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
     244  			       ®);
     245  	      continue;
     246  	    }
     247  	  if (op == 0xb3)
     248  	    {
     249  	      /* Pop VFP registers with fldmx.  */
     250  	      op = next_unwind_byte (uws);
     251  	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
     252  	      if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
     253  		  != _UVRSR_OK)
     254  		return _URC_FAILURE;
     255  	      continue;
     256  	    }
     257  	  /* Pop PAC off the stack into VRS pseudo.pac.  */
     258  	  if (op == 0xb4)
     259  	    {
     260  	      if (_Unwind_VRS_Pop (context, _UVRSC_PAC, 0, _UVRSD_UINT32)
     261  		  != _UVRSR_OK)
     262  		return _URC_FAILURE;
     263  #if defined(TARGET_HAVE_PACBTI)
     264  	      set_pac = 1;
     265  #endif
     266  	      continue;
     267  	    }
     268  
     269  	  /* Use current VSP as modifier in PAC validation.  */
     270  	  if (op == 0xb5)
     271  	    {
     272  	      _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &sp);
     273  #if defined(TARGET_HAVE_PACBTI)
     274  	      set_pac_sp = 1;
     275  #endif
     276  	      continue;
     277  	    }
     278  
     279  	  if ((op & 0xfc) == 0xb4)  /* Obsolete FPA.  */
     280  	    return _URC_FAILURE;
     281  
     282  	  /* op & 0xf8 == 0xb8.  */
     283  	  /* Pop VFP D[8]-D[8+nnn] with fldmx.  */
     284  	  op = 0x80000 | ((op & 7) + 1);
     285  	  if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
     286  	      != _UVRSR_OK)
     287  	    return _URC_FAILURE;
     288  	  continue;
     289  	}
     290        if ((op & 0xf0) == 0xc0)
     291  	{
     292  	  if (op == 0xc6)
     293  	    {
     294  	      /* Pop iWMMXt D registers.  */
     295  	      op = next_unwind_byte (uws);
     296  	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
     297  	      if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
     298  		  != _UVRSR_OK)
     299  		return _URC_FAILURE;
     300  	      continue;
     301  	    }
     302  	  if (op == 0xc7)
     303  	    {
     304  	      op = next_unwind_byte (uws);
     305  	      if (op == 0 || (op & 0xf0) != 0)
     306  		/* Spare.  */
     307  		return _URC_FAILURE;
     308  	      /* Pop iWMMXt wCGR{3,2,1,0} under mask.  */
     309  	      if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
     310  		  != _UVRSR_OK)
     311  		return _URC_FAILURE;
     312  	      continue;
     313  	    }
     314  	  if ((op & 0xf8) == 0xc0)
     315  	    {
     316  	      /* Pop iWMMXt wR[10]-wR[10+nnn].  */
     317  	      op = 0xa0000 | ((op & 0xf) + 1);
     318  	      if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
     319  		  != _UVRSR_OK)
     320  		return _URC_FAILURE;
     321  	      continue;
     322  	    }
     323  	  if (op == 0xc8)
     324  	    {
     325                /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm.  */
     326                op = next_unwind_byte (uws);
     327                op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
     328                if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
     329                    != _UVRSR_OK)
     330                  return _URC_FAILURE;
     331                continue;
     332  	    }
     333  	  if (op == 0xc9)
     334  	    {
     335  	      /* Pop VFP registers with fldmd.  */
     336  	      op = next_unwind_byte (uws);
     337  	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
     338  	      if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
     339  		  != _UVRSR_OK)
     340  		return _URC_FAILURE;
     341  	      continue;
     342  	    }
     343  	  /* Spare.  */
     344  	  return _URC_FAILURE;
     345  	}
     346        if ((op & 0xf8) == 0xd0)
     347  	{
     348  	  /* Pop VFP D[8]-D[8+nnn] with fldmd.  */
     349  	  op = 0x80000 | ((op & 7) + 1);
     350  	  if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
     351  	      != _UVRSR_OK)
     352  	    return _URC_FAILURE;
     353  	  continue;
     354  	}
     355        /* Spare.  */
     356        return _URC_FAILURE;
     357      }
     358    return _URC_OK;
     359  }
     360  
     361  
     362  /* Execute the unwinding instructions associated with a frame.  UCBP and
     363     CONTEXT are the current exception object and virtual CPU state
     364     respectively.  */
     365  
     366  _Unwind_Reason_Code
     367  __gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
     368  {
     369    _uw *ptr;
     370    __gnu_unwind_state uws;
     371  
     372    ptr = (_uw *) ucbp->pr_cache.ehtp;
     373    /* Skip over the personality routine address.  */
     374    ptr++;
     375    /* Setup the unwinder state.  */
     376    uws.data = (*ptr) << 8;
     377    uws.next = ptr + 1;
     378    uws.bytes_left = 3;
     379    uws.words_left = ((*ptr) >> 24) & 0xff;
     380  
     381    return __gnu_unwind_execute (context, &uws);
     382  }
     383  
     384  /* Get the _Unwind_Control_Block from an _Unwind_Context.  */
     385  
     386  static inline _Unwind_Control_Block *
     387  unwind_UCB_from_context (_Unwind_Context * context)
     388  {
     389    return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
     390  }
     391  
     392  /* Get the start address of the function being unwound.  */
     393  
     394  _Unwind_Ptr
     395  _Unwind_GetRegionStart (_Unwind_Context * context)
     396  {
     397    _Unwind_Control_Block *ucbp;
     398  
     399    ucbp = unwind_UCB_from_context (context);
     400    return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
     401  }
     402  
     403  /* Find the Language specific exception data.  */
     404  
     405  void *
     406  _Unwind_GetLanguageSpecificData (_Unwind_Context * context)
     407  {
     408    _Unwind_Control_Block *ucbp;
     409    _uw *ptr;
     410  
     411    /* Get a pointer to the exception table entry.  */
     412    ucbp = unwind_UCB_from_context (context);
     413    ptr = (_uw *) ucbp->pr_cache.ehtp;
     414    /* Skip the personality routine address.  */
     415    ptr++;
     416    /* Skip the unwind opcodes.  */
     417    ptr += (((*ptr) >> 24) & 0xff) + 1;
     418  
     419    return ptr;
     420  }
     421  
     422  
     423  /* These two should never be used.  */
     424  
     425  _Unwind_Ptr
     426  _Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused)))
     427  {
     428    abort ();
     429  }
     430  
     431  _Unwind_Ptr
     432  _Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
     433  {
     434    abort ();
     435  }