(root)/
gcc-13.2.0/
libgcc/
config/
c6x/
pr-support.c
       1  /* C6X ABI compliant unwinding routines
       2     Copyright (C) 2011-2023 Free Software Foundation, Inc.
       3   
       4     This file is free software; you can redistribute it and/or modify it
       5     under the terms of the GNU General Public License as published by the
       6     Free Software Foundation; either version 3, or (at your option) any
       7     later version.
       8  
       9     This file is distributed in the hope that it will be useful, but
      10     WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     General Public License for more details.
      13  
      14     Under Section 7 of GPL version 3, you are granted additional
      15     permissions described in the GCC Runtime Library Exception, version
      16     3.1, as published by the Free Software Foundation.
      17  
      18     You should have received a copy of the GNU General Public License and
      19     a copy of the GCC Runtime Library Exception along with this program;
      20     see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      21     <http://www.gnu.org/licenses/>.  */
      22  
      23  #include "unwind.h"
      24  
      25  /* We add a prototype for abort here to avoid creating a dependency on
      26     target headers.  */
      27  extern void abort (void);
      28  
      29  typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
      30  
      31  /* Misc constants.  */
      32  #define R_A0 0
      33  #define R_A1 1
      34  #define R_A2 2
      35  #define R_A3 3
      36  #define R_A4 4
      37  #define R_A5 5
      38  #define R_A6 6
      39  #define R_A7 7
      40  #define R_A8 8
      41  #define R_A9 9
      42  #define R_A10 10
      43  #define R_A11 11
      44  #define R_A12 12
      45  #define R_A13 13
      46  #define R_A14 14
      47  #define R_A15 15
      48  #define R_B0 16
      49  #define R_B1 17
      50  #define R_B2 18
      51  #define R_B3 19
      52  #define R_B4 20
      53  #define R_B5 21
      54  #define R_B6 22
      55  #define R_B7 23
      56  #define R_B8 24
      57  #define R_B9 25
      58  #define R_B10 26
      59  #define R_B11 27
      60  #define R_B12 28
      61  #define R_B13 29
      62  #define R_B14 30
      63  #define R_B15 31
      64  
      65  #define R_SP R_B15
      66  #define R_PC 33
      67  
      68  #define uint32_highbit (((_uw) 1) << 31)
      69  
      70  void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
      71  
      72  /* Unwind descriptors.  */
      73  
      74  typedef struct
      75  {
      76    _uw16 length;
      77    _uw16 offset;
      78  } EHT16;
      79  
      80  typedef struct
      81  {
      82    _uw length;
      83    _uw offset;
      84  } EHT32;
      85  
      86  /* Calculate the address encoded by a 31-bit self-relative offset at address
      87     P.  Copy of routine in unwind-arm.c.  */
      88  
      89  static inline _uw
      90  selfrel_offset31 (const _uw *p)
      91  {
      92    _uw offset;
      93  
      94    offset = *p;
      95    /* Sign extend to 32 bits.  */
      96    if (offset & (1 << 30))
      97      offset |= 1u << 31;
      98  
      99    return offset + (_uw) p;
     100  }
     101  
     102  
     103  /* Personality routine helper functions.  */
     104  
     105  #define CODE_FINISH (0xe7)
     106  
     107  /* Return the next byte of unwinding information, or CODE_FINISH if there is
     108     no data remaining.  */
     109  static inline _uw8
     110  next_unwind_byte (__gnu_unwind_state * uws)
     111  {
     112    _uw8 b;
     113  
     114    if (uws->bytes_left == 0)
     115      {
     116        /* Load another word */
     117        if (uws->words_left == 0)
     118  	return CODE_FINISH; /* Nothing left.  */
     119        uws->words_left--;
     120        uws->data = *(uws->next++);
     121        uws->bytes_left = 3;
     122      }
     123    else
     124      uws->bytes_left--;
     125  
     126    /* Extract the most significant byte.  */
     127    b = (uws->data >> 24) & 0xff;
     128    uws->data <<= 8;
     129    return b;
     130  }
     131  
     132  static void
     133  unwind_restore_pair (_Unwind_Context * context, int reg, _uw *ptr)
     134  {
     135  #ifdef _BIG_ENDIAN
     136    _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32, ptr + 1);
     137    _Unwind_VRS_Set (context, _UVRSC_CORE, reg + 1, _UVRSD_UINT32, ptr);
     138  #else
     139    _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32, ptr);
     140    _Unwind_VRS_Set (context, _UVRSC_CORE, reg + 1, _UVRSD_UINT32, ptr + 1);
     141  #endif
     142  }
     143  
     144  static const int
     145  unwind_frame_regs[13] = 
     146  {
     147    R_A15, R_B15, R_B14, R_B13, R_B12, R_B11, R_B10, R_B3,
     148    R_A14, R_A13, R_A12, R_A11, R_A10
     149  };
     150  
     151  static void
     152  pop_compact_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
     153  {
     154    int size;
     155    _uw test;
     156    int i, regno, nregs;
     157  
     158    size = 0;
     159    nregs = __builtin_popcount (mask);
     160    for (i = 0; i < 13; i++)
     161      {
     162        test = 1 << i;
     163        if ((mask & test) == 0)
     164  	continue;
     165  
     166        regno = unwind_frame_regs[12 - i];
     167  
     168        if (i < 12 && nregs > 2
     169  	  && (mask & (test << 1)) != 0
     170  	  && unwind_frame_regs[11 - i] == regno + 1
     171  	  && (regno & 1) == 0)
     172  	{
     173  	  i++;
     174  	  nregs--;
     175  	}
     176  
     177        nregs--;
     178        size += 2;
     179      }
     180  
     181    if (!inc_sp)
     182      ptr -= size;
     183  
     184    /* SP points just past the end of the stack.  */
     185    ptr += 2;
     186    nregs = __builtin_popcount (mask);
     187    for (i = 0; i < 13; i++)
     188      {
     189        test = 1 << i;
     190        if ((mask & test) == 0)
     191  	continue;
     192  
     193        regno = unwind_frame_regs[12 - i];
     194  
     195        if (i < 12 && nregs > 2
     196  	  && (mask & (test << 1)) != 0
     197  	  && unwind_frame_regs[11 - i] == regno + 1
     198  	  && (regno & 1) == 0)
     199  	{
     200  	  /* Register pair.  */
     201  	  unwind_restore_pair (context, regno, ptr);
     202  	  i++;
     203  	  nregs--;
     204  	}
     205        else
     206  	{
     207  	  /* Single register with padding.  */
     208  	  _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, ptr);
     209  	}
     210  
     211        nregs--;
     212        ptr += 2;
     213      }
     214  
     215    ptr -= 2;
     216    if ((mask & (1 << 11)) == 0)
     217      _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
     218  }
     219  
     220  static void
     221  pop_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
     222  {
     223    int i;
     224    int regno;
     225    int nregs;
     226  
     227    nregs = __builtin_popcount (mask);
     228  
     229    if (!inc_sp)
     230      ptr -= nregs;
     231    else if (nregs & 1)
     232      ptr++;
     233  
     234    ptr++;
     235    for (i = 0; i < 13; i++)
     236      {
     237        if ((mask & (1 << i)) == 0)
     238  	continue;
     239        regno = unwind_frame_regs[12 - i];
     240        if (i < 12 && unwind_frame_regs[11 - i] == (regno + 1)
     241  	  && (mask & (1 << (i + 1))) != 0
     242  	  && (((_uw)ptr) & 4) == 0
     243  	  && (regno & 1) == 0)
     244  	{
     245  	  unwind_restore_pair (context, regno, ptr);
     246  	  i++;
     247  	  ptr += 2;
     248  	}
     249        else
     250  	{
     251  	  _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32,
     252  			   ptr);
     253  	  ptr++;
     254  	}
     255      }
     256  
     257    ptr--;
     258    if ((mask & (1 << 11)) == 0)
     259      _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
     260  }
     261  
     262  /* Unwind a 24-bit encoded frame.  */
     263  _Unwind_Reason_Code
     264  __gnu_unwind_24bit (_Unwind_Context * context, _uw data, int compact)
     265  {
     266    _uw offset;
     267    _uw mask;
     268    _uw *ptr;
     269    _uw tmp;
     270    int ret_reg = unwind_frame_regs[data & 0xf];
     271  
     272    if (ret_reg != R_B3)
     273      {
     274        _Unwind_VRS_Get (context, _UVRSC_CORE, unwind_frame_regs[data & 0xf],
     275  		       _UVRSD_UINT32, &tmp);
     276        _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &tmp);
     277      }
     278  
     279    mask = (data >> 4) & 0x1fff;
     280  
     281    offset = (data >> 17) & 0x7f;
     282    if (offset == 0x7f)
     283      _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &ptr);
     284    else
     285      {
     286        _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
     287        ptr += offset * 2;
     288      }
     289  
     290  
     291    if (compact)
     292      pop_compact_frame (context, mask, ptr, offset != 0x7f);
     293    else
     294      pop_frame (context, mask, ptr, offset != 0x7f);
     295  
     296    _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &tmp);
     297    _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &tmp);
     298  
     299    return _URC_OK;
     300  }
     301  
     302  static void
     303  unwind_pop_rts (_Unwind_Context * context)
     304  {
     305    _uw *ptr;
     306  
     307    _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
     308  #ifdef _BIG_ENDIAN
     309    _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ptr + 1);
     310  #else
     311    _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ptr + 2);
     312  #endif
     313    ptr += 3;
     314    unwind_restore_pair (context, R_A10, ptr);
     315    ptr += 2;
     316    unwind_restore_pair (context, R_B10, ptr);
     317    ptr += 2;
     318    unwind_restore_pair (context, R_A12, ptr);
     319    ptr += 2;
     320    unwind_restore_pair (context, R_B12, ptr);
     321    ptr += 2;
     322    unwind_restore_pair (context, R_A14, ptr);
     323    ptr += 2;
     324    _Unwind_VRS_Set (context, _UVRSC_CORE, R_B14, _UVRSD_UINT32, ptr);
     325    _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
     326    /* PC will be set by implicit RETURN opcode.  */
     327  }
     328  
     329  /* Execute the unwinding instructions described by UWS.  */
     330  _Unwind_Reason_Code
     331  __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
     332  {
     333    _uw op;
     334    int inc_sp;
     335    _uw reg;
     336    _uw *ptr;
     337  
     338    inc_sp = 1;
     339    for (;;)
     340      {
     341        op = next_unwind_byte (uws);
     342        if (op == CODE_FINISH)
     343  	{
     344  	  /* Drop out of the loop.  */
     345  	  break;
     346  	}
     347        if ((op & 0xc0) == 0)
     348  	{
     349  	  /* sp += (imm6 << 3) + 8.  */
     350  	  _uw offset;
     351  
     352  	  offset = ((op & 0x3f) << 3) + 8;
     353  	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
     354  	  reg += offset;
     355  	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
     356  	  continue;
     357  	}
     358  
     359        if (op == 0xd2)
     360  	{
     361  	  /* vsp = vsp + 0x204 + (uleb128 << 2).  */
     362  	  int shift;
     363  
     364  	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
     365  	  op = next_unwind_byte (uws);
     366  	  shift = 3;
     367  	  while (op & 0x80)
     368  	    {
     369  	      reg += ((op & 0x7f) << shift);
     370  	      shift += 7;
     371  	      op = next_unwind_byte (uws);
     372  	    }
     373  	  reg += ((op & 0x7f) << shift) + 0x408;
     374  	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
     375  	  continue;
     376  	}
     377  
     378        if ((op & 0xe0) == 0x80)
     379  	{
     380  	  /* POP bitmask */
     381  	  _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
     382  
     383  	  if (mask == 0)
     384  	    {
     385  	      /* CANTUNWIND */
     386  	      return _URC_FAILURE;
     387  	    }
     388  
     389  	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
     390  	  pop_frame (context, mask, ptr, inc_sp);
     391  	  continue;
     392  	}
     393  
     394        if ((op & 0xe0) == 0xa0)
     395  	{
     396  	  /* POP bitmask (compact) */
     397  	  _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
     398  
     399  	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
     400  	  pop_compact_frame (context, mask, ptr, inc_sp);
     401  	  continue;
     402  	}
     403  
     404        if ((op & 0xf0) == 0xc0)
     405  	{
     406  	  /* POP registers */
     407  	  int nregs = op & 0xf;
     408  
     409  	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
     410  	  while (nregs > 0)
     411  	    {
     412  	      op = next_unwind_byte (uws);
     413  	      if ((op >> 4) != 0xf)
     414  		{
     415  		  reg = unwind_frame_regs[op >> 4];
     416  		  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
     417  				   ptr);
     418  		  nregs--;
     419  		}
     420  	      ptr--;
     421  	      if ((op & 0xf) != 0xf)
     422  		{
     423  		  reg = unwind_frame_regs[op & 0xf];
     424  		  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
     425  				   ptr);
     426  		  nregs--;
     427  		}
     428  	      ptr--;
     429  	    }
     430  
     431  	  continue;
     432  	}
     433  
     434        if (op == 0xd0)
     435  	{
     436  	  /* MV FP, SP */
     437  	  inc_sp = 0;
     438  	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &reg);
     439  	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
     440  	  continue;
     441  	}
     442  
     443        if (op == 0xd1)
     444  	{
     445  	  /* __cx6abi_pop_rts */
     446  	  unwind_pop_rts (context);
     447  	  break;
     448  	}
     449  
     450        if ((op & 0xf0) == 0xe0)
     451  	{
     452  	  /* B3 = reg.  RETURN case already handled above.  */
     453  	  int regno = unwind_frame_regs[op & 0xf];
     454  
     455  	  _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &reg);
     456  	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &reg);
     457  	  continue;
     458  	}
     459        
     460        /* Reserved.  */
     461        return _URC_FAILURE;
     462      }
     463  
     464    /* Implicit RETURN.  */
     465    _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &reg);
     466    _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &reg);
     467    return _URC_OK;
     468  }
     469  
     470  
     471  /* Execute the unwinding instructions associated with a frame.  UCBP and
     472     CONTEXT are the current exception object and virtual CPU state
     473     respectively.  */
     474  
     475  _Unwind_Reason_Code
     476  __gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
     477  {
     478    _uw *ptr;
     479    __gnu_unwind_state uws;
     480  
     481    ptr = (_uw *) ucbp->pr_cache.ehtp;
     482    /* Skip over the personality routine address.  */
     483    ptr++;
     484    /* Setup the unwinder state.  */
     485    uws.data = (*ptr) << 8;
     486    uws.next = ptr + 1;
     487    uws.bytes_left = 3;
     488    uws.words_left = ((*ptr) >> 24) & 0xff;
     489  
     490    return __gnu_unwind_execute (context, &uws);
     491  }
     492  
     493  /* Data segment base pointer corresponding to the function catching
     494     the exception.  */
     495  
     496  _Unwind_Ptr
     497  _Unwind_GetDataRelBase (_Unwind_Context *context)
     498  {
     499    return _Unwind_GetGR (context, R_B14);
     500  }
     501  
     502  /* This should never be used.  */
     503  
     504  _Unwind_Ptr
     505  _Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
     506  {
     507    abort ();
     508  }
     509  
     510  /* Only used by gcc personality routines, so can rely on a value they hid
     511     there earlier.  */
     512  _Unwind_Ptr
     513  _Unwind_GetRegionStart (_Unwind_Context *context)
     514  {
     515    _Unwind_Control_Block *ucbp;
     516   
     517    ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
     518    return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
     519  }
     520  
     521  void *
     522  _Unwind_GetLanguageSpecificData (_Unwind_Context *context)
     523  {
     524    _Unwind_Control_Block *ucbp;
     525    _uw *ptr;
     526   
     527    ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
     528    ptr = (_uw *) ucbp->pr_cache.ehtp;
     529    /* Skip the personality routine address.  */
     530    ptr++;
     531    /* Skip the unwind opcodes.  */
     532    ptr += (((*ptr) >> 24) & 0xff) + 1;
     533  
     534    return ptr;
     535  }