(root)/
gcc-13.2.0/
libgcc/
config/
xtensa/
unwind-dw2-xtensa.c
       1  /* DWARF2 exception handling and frame unwinding for Xtensa.
       2     Copyright (C) 1997-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 by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     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  #include "tconfig.h"
      26  #include "tsystem.h"
      27  #include "coretypes.h"
      28  #include "tm.h"
      29  #include "libgcc_tm.h"
      30  #include "dwarf2.h"
      31  #include "unwind.h"
      32  #ifdef __USING_SJLJ_EXCEPTIONS__
      33  # define NO_SIZE_OF_ENCODED_VALUE
      34  #endif
      35  #include "unwind-pe.h"
      36  #include "unwind-dw2-fde.h"
      37  #include "unwind-dw2-xtensa.h"
      38  
      39  #ifndef __USING_SJLJ_EXCEPTIONS__
      40  
      41  /* The standard CIE and FDE structures work fine for Xtensa but the
      42     variable-size register window save areas are not a good fit for the rest
      43     of the standard DWARF unwinding mechanism.  Nor is that mechanism
      44     necessary, since the register save areas are always in fixed locations
      45     in each stack frame.  This file is a stripped down and customized version
      46     of the standard DWARF unwinding code.  It needs to be customized to have
      47     builtin logic for finding the save areas and also to track the stack
      48     pointer value (besides the CFA) while unwinding since the primary save
      49     area is located below the stack pointer.  It is stripped down to reduce
      50     code size and ease the maintenance burden of tracking changes in the
      51     standard version of the code.  */
      52  
      53  #ifndef DWARF_REG_TO_UNWIND_COLUMN
      54  #define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
      55  #endif
      56  
      57  #define XTENSA_RA_FIELD_MASK 0x3FFFFFFF
      58  
      59  /* This is the register and unwind state for a particular frame.  This
      60     provides the information necessary to unwind up past a frame and return
      61     to its caller.  */
      62  struct _Unwind_Context
      63  {
      64    /* Track register window save areas of 4 registers each, instead of
      65       keeping separate addresses for the individual registers.  */
      66    _Unwind_Word *reg[4];
      67  
      68    void *cfa;
      69    void *sp;
      70    void *ra;
      71  
      72    /* Cache the 2 high bits to replace the window size in return addresses.  */
      73    _Unwind_Word ra_high_bits;
      74  
      75    void *lsda;
      76    struct dwarf_eh_bases bases;
      77    /* Signal frame context.  */
      78  #define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
      79    _Unwind_Word flags;
      80    /* 0 for now, can be increased when further fields are added to
      81       struct _Unwind_Context.  */
      82    _Unwind_Word version;
      83  };
      84  
      85  
      86  /* Read unaligned data from the instruction buffer.  */
      87  
      88  union unaligned
      89  {
      90    void *p;
      91  } __attribute__ ((packed));
      92  
      93  static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *);
      94  static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *,
      95  					       _Unwind_FrameState *);
      96  
      97  static inline void *
      98  read_pointer (const void *p) { const union unaligned *up = p; return up->p; }
      99  
     100  static inline _Unwind_Word
     101  _Unwind_IsSignalFrame (struct _Unwind_Context *context)
     102  {
     103    return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0;
     104  }
     105  
     106  static inline void
     107  _Unwind_SetSignalFrame (struct _Unwind_Context *context, int val)
     108  {
     109    if (val)
     110      context->flags |= SIGNAL_FRAME_BIT;
     111    else
     112      context->flags &= ~SIGNAL_FRAME_BIT;
     113  }
     114  
     115  /* Get the value of register INDEX as saved in CONTEXT.  */
     116  
     117  inline _Unwind_Word
     118  _Unwind_GetGR (struct _Unwind_Context *context, int index)
     119  {
     120    _Unwind_Word *ptr;
     121  
     122    index = DWARF_REG_TO_UNWIND_COLUMN (index);
     123    ptr = context->reg[index >> 2] + (index & 3);
     124  
     125    return *ptr;
     126  }
     127  
     128  /* Get the value of the CFA as saved in CONTEXT.  */
     129  
     130  _Unwind_Word
     131  _Unwind_GetCFA (struct _Unwind_Context *context)
     132  {
     133    return (_Unwind_Ptr) context->sp;
     134  }
     135  
     136  /* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
     137  
     138  inline void
     139  _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
     140  {
     141    _Unwind_Word *ptr;
     142  
     143    index = DWARF_REG_TO_UNWIND_COLUMN (index);
     144    ptr = context->reg[index >> 2] + (index & 3);
     145  
     146    *ptr = val;
     147  }
     148  
     149  /* Retrieve the return address for CONTEXT.  */
     150  
     151  inline _Unwind_Ptr
     152  _Unwind_GetIP (struct _Unwind_Context *context)
     153  {
     154    return (_Unwind_Ptr) context->ra;
     155  }
     156  
     157  /* Retrieve the return address and flag whether that IP is before
     158     or after first not yet fully executed instruction.  */
     159  
     160  inline _Unwind_Ptr
     161  _Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
     162  {
     163    *ip_before_insn = _Unwind_IsSignalFrame (context);
     164    return (_Unwind_Ptr) context->ra;
     165  }
     166  
     167  /* Overwrite the return address for CONTEXT with VAL.  */
     168  
     169  inline void
     170  _Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
     171  {
     172    context->ra = (void *) val;
     173  }
     174  
     175  void *
     176  _Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
     177  {
     178    return context->lsda;
     179  }
     180  
     181  _Unwind_Ptr
     182  _Unwind_GetRegionStart (struct _Unwind_Context *context)
     183  {
     184    return (_Unwind_Ptr) context->bases.func;
     185  }
     186  
     187  void *
     188  _Unwind_FindEnclosingFunction (void *pc)
     189  {
     190    struct dwarf_eh_bases bases;
     191    const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases);
     192    if (fde)
     193      return bases.func;
     194    else
     195      return NULL;
     196  }
     197  
     198  _Unwind_Ptr
     199  _Unwind_GetDataRelBase (struct _Unwind_Context *context)
     200  {
     201    return (_Unwind_Ptr) context->bases.dbase;
     202  }
     203  
     204  _Unwind_Ptr
     205  _Unwind_GetTextRelBase (struct _Unwind_Context *context)
     206  {
     207    return (_Unwind_Ptr) context->bases.tbase;
     208  }
     209  
     210  #include "md-unwind-support.h"
     211  
     212  /* Extract any interesting information from the CIE for the translation
     213     unit F belongs to.  Return a pointer to the byte after the augmentation,
     214     or NULL if we encountered an undecipherable augmentation.  */
     215  
     216  static const unsigned char *
     217  extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
     218  		  _Unwind_FrameState *fs)
     219  {
     220    const unsigned char *aug = cie->augmentation;
     221    const unsigned char *p = aug + strlen ((const char *)aug) + 1;
     222    const unsigned char *ret = NULL;
     223    _uleb128_t utmp;
     224    _sleb128_t stmp;
     225  
     226    /* g++ v2 "eh" has pointer immediately following augmentation string,
     227       so it must be handled first.  */
     228    if (aug[0] == 'e' && aug[1] == 'h')
     229      {
     230        fs->eh_ptr = read_pointer (p);
     231        p += sizeof (void *);
     232        aug += 2;
     233      }
     234  
     235    /* Immediately following the augmentation are the code and
     236       data alignment and return address column.  */
     237    p = read_uleb128 (p, &utmp);
     238    p = read_sleb128 (p, &stmp);
     239    if (cie->version == 1)
     240      fs->retaddr_column = *p++;
     241    else
     242      {
     243        p = read_uleb128 (p, &utmp);
     244        fs->retaddr_column = (_Unwind_Word)utmp;
     245      }
     246    fs->lsda_encoding = DW_EH_PE_omit;
     247  
     248    /* If the augmentation starts with 'z', then a uleb128 immediately
     249       follows containing the length of the augmentation field following
     250       the size.  */
     251    if (*aug == 'z')
     252      {
     253        p = read_uleb128 (p, &utmp);
     254        ret = p + utmp;
     255  
     256        fs->saw_z = 1;
     257        ++aug;
     258      }
     259  
     260    /* Iterate over recognized augmentation subsequences.  */
     261    while (*aug != '\0')
     262      {
     263        /* "L" indicates a byte showing how the LSDA pointer is encoded.  */
     264        if (aug[0] == 'L')
     265  	{
     266  	  fs->lsda_encoding = *p++;
     267  	  aug += 1;
     268  	}
     269  
     270        /* "R" indicates a byte indicating how FDE addresses are encoded.  */
     271        else if (aug[0] == 'R')
     272  	{
     273  	  fs->fde_encoding = *p++;
     274  	  aug += 1;
     275  	}
     276  
     277        /* "P" indicates a personality routine in the CIE augmentation.  */
     278        else if (aug[0] == 'P')
     279  	{
     280  	  _Unwind_Ptr personality;
     281  	  
     282  	  p = read_encoded_value (context, *p, p + 1, &personality);
     283  	  fs->personality = (_Unwind_Personality_Fn) personality;
     284  	  aug += 1;
     285  	}
     286  
     287        /* "S" indicates a signal frame.  */
     288        else if (aug[0] == 'S')
     289  	{
     290  	  fs->signal_frame = 1;
     291  	  aug += 1;
     292  	}
     293  
     294        /* Otherwise we have an unknown augmentation string.
     295  	 Bail unless we saw a 'z' prefix.  */
     296        else
     297  	return ret;
     298      }
     299  
     300    return ret ? ret : p;
     301  }
     302  
     303  /* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for
     304     its caller and decode it into FS.  This function also sets the
     305     lsda member of CONTEXT, as it is really information
     306     about the caller's frame.  */
     307  
     308  static _Unwind_Reason_Code
     309  uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     310  {
     311    const struct dwarf_fde *fde;
     312    const struct dwarf_cie *cie;
     313    const unsigned char *aug;
     314    int window_size;
     315    _Unwind_Word *ra_ptr;
     316  
     317    memset (fs, 0, sizeof (*fs));
     318    context->lsda = 0;
     319  
     320    fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1,
     321  			  &context->bases);
     322    if (fde == NULL)
     323      {
     324  #ifdef MD_FALLBACK_FRAME_STATE_FOR
     325        _Unwind_Reason_Code reason;
     326        /* Couldn't find frame unwind info for this function.  Try a
     327  	 target-specific fallback mechanism.  This will necessarily
     328  	 not provide a personality routine or LSDA.  */
     329        reason = MD_FALLBACK_FRAME_STATE_FOR (context, fs);
     330        if (reason != _URC_END_OF_STACK)
     331  	return reason;
     332  #endif
     333        /* The frame was not recognized and handled by the fallback function,
     334  	 but it is not really the end of the stack.  Fall through here and
     335  	 unwind it anyway.  */
     336      }
     337    else
     338      {
     339        cie = get_cie (fde);
     340        if (extract_cie_info (cie, context, fs) == NULL)
     341  	/* CIE contained unknown augmentation.  */
     342  	return _URC_FATAL_PHASE1_ERROR;
     343  
     344        /* Locate augmentation for the fde.  */
     345        aug = (const unsigned char *) fde + sizeof (*fde);
     346        aug += 2 * size_of_encoded_value (fs->fde_encoding);
     347        if (fs->saw_z)
     348  	{
     349  	  _uleb128_t i;
     350  	  aug = read_uleb128 (aug, &i);
     351  	}
     352        if (fs->lsda_encoding != DW_EH_PE_omit)
     353  	{
     354  	  _Unwind_Ptr lsda;
     355  
     356  	  aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda);
     357  	  context->lsda = (void *) lsda;
     358  	}
     359      }
     360  
     361    /* Check for the end of the stack.  This needs to be checked after
     362       the MD_FALLBACK_FRAME_STATE_FOR check for signal frames because
     363       the contents of context->reg[0] are undefined at a signal frame,
     364       and register a0 may appear to be zero.  (The return address in
     365       context->ra comes from register a4 or a8).  */
     366    ra_ptr = context->reg[0];
     367    if (ra_ptr && *ra_ptr == 0)
     368      return _URC_END_OF_STACK;
     369  
     370    /* Find the window size from the high bits of the return address.  */
     371    if (ra_ptr)
     372      window_size = (*ra_ptr >> 30) * 4;
     373    else
     374      window_size = 8;
     375  
     376    fs->retaddr_column = window_size;
     377  
     378    return _URC_NO_REASON;
     379  }
     380  
     381  static void
     382  uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     383  {
     384    struct _Unwind_Context orig_context = *context;
     385    _Unwind_Word *sp, *cfa, *next_cfa;
     386    int i;
     387  
     388    if (fs->signal_regs)
     389      {
     390        cfa = (_Unwind_Word *) fs->signal_regs[1];
     391        next_cfa = (_Unwind_Word *) cfa[-3];
     392  
     393        for (i = 0; i < 4; i++)
     394  	context->reg[i] = fs->signal_regs + (i << 2);
     395      }
     396    else
     397      {
     398        int window_size = fs->retaddr_column >> 2;
     399  
     400        sp = (_Unwind_Word *) orig_context.sp;
     401        cfa = (_Unwind_Word *) orig_context.cfa;
     402        next_cfa = (_Unwind_Word *) cfa[-3];
     403  
     404        /* Registers a0-a3 are in the save area below sp.  */
     405        context->reg[0] = sp - 4;
     406  
     407        /* Find the extra save area below next_cfa.  */
     408        for (i = 1; i < window_size; i++)
     409  	context->reg[i] = next_cfa - 4 * (1 + window_size - i);
     410  
     411        /* Remaining registers rotate from previous save areas.  */
     412        for (i = window_size; i < 4; i++)
     413  	context->reg[i] = orig_context.reg[i - window_size];
     414      }
     415  
     416    context->sp = cfa;
     417    context->cfa = next_cfa;
     418  
     419    _Unwind_SetSignalFrame (context, fs->signal_frame);
     420  }
     421  
     422  /* CONTEXT describes the unwind state for a frame, and FS describes the FDE
     423     of its caller.  Update CONTEXT to refer to the caller as well.  Note
     424     that the lsda member is not updated here, but later in
     425     uw_frame_state_for.  */
     426  
     427  static void
     428  uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     429  {
     430    uw_update_context_1 (context, fs);
     431  
     432    /* Compute the return address now, since the return address column
     433       can change from frame to frame.  */
     434    if (fs->signal_ra != 0)
     435      context->ra = (void *) fs->signal_ra;
     436    else
     437      context->ra = (void *) ((_Unwind_GetGR (context, fs->retaddr_column)
     438  			     & XTENSA_RA_FIELD_MASK) | context->ra_high_bits);
     439  }
     440  
     441  static void
     442  uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     443  {
     444    uw_update_context (context, fs);
     445  }
     446  
     447  /* Fill in CONTEXT for top-of-stack.  The only valid registers at this
     448     level will be the return address and the CFA.  */
     449  
     450  #define uw_init_context(CONTEXT)					   \
     451    do									   \
     452      {									   \
     453        __builtin_unwind_init ();						   \
     454        uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (),		   \
     455  			 __builtin_return_address (0));			   \
     456      }									   \
     457    while (0)
     458  
     459  static void __attribute__((noinline))
     460  uw_init_context_1 (struct _Unwind_Context *context, void *outer_cfa,
     461  		   void *outer_ra)
     462  {
     463    void *ra = __builtin_return_address (0);
     464    void *cfa = __builtin_dwarf_cfa ();
     465    _Unwind_FrameState fs;
     466  
     467    memset (context, 0, sizeof (struct _Unwind_Context));
     468    context->ra = ra;
     469  
     470    memset (&fs, 0, sizeof (fs));
     471    fs.retaddr_column = 8;
     472    context->sp = cfa;
     473    context->cfa = outer_cfa;
     474    context->ra_high_bits =
     475      ((_Unwind_Word) uw_init_context_1) & ~XTENSA_RA_FIELD_MASK;
     476    uw_update_context_1 (context, &fs);
     477  
     478    context->ra = outer_ra;
     479  }
     480  
     481  
     482  /* Install TARGET into CURRENT so that we can return to it.  This is a
     483     macro because __builtin_eh_return must be invoked in the context of
     484     our caller, and also because spilling registers of the caller before
     485     the context installation may result in reload of wrong register values
     486     after the context installation due to the change of the stack pointer
     487     in the base save area.  This spilling may be caused by an interrupt
     488     handler on baremetal host.  */
     489  
     490  #define uw_install_context(CURRENT, TARGET, FRAMES)			 \
     491    do									 \
     492      {									 \
     493        void *handler = __builtin_frob_return_addr ((TARGET)->ra);	 \
     494        long i;								 \
     495  									 \
     496        /* The eh_return insn assumes a window size of 8, so don't bother	 \
     497  	 copying the save areas for registers a8-a15 since they won't be \
     498  	 reloaded.  */							 \
     499        for (i = 0; i < 2; ++i)						 \
     500  	{								 \
     501  	  _Unwind_Word *c = (CURRENT)->reg[i];				 \
     502  	  _Unwind_Word *t = (TARGET)->reg[i];				 \
     503  	  int j;							 \
     504  									 \
     505  	  if (t && c && t != c)						 \
     506  	    for (j = 0; j < 4; ++j)					 \
     507  	      *c++ = *t++;						 \
     508  	}								 \
     509        __builtin_eh_return (0, handler);					 \
     510      }									 \
     511    while (0)
     512  
     513  static inline _Unwind_Ptr
     514  uw_identify_context (struct _Unwind_Context *context)
     515  {
     516    return _Unwind_GetCFA (context);
     517  }
     518  
     519  
     520  #include "unwind.inc"
     521  
     522  #if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
     523  alias (_Unwind_Backtrace);
     524  alias (_Unwind_DeleteException);
     525  alias (_Unwind_FindEnclosingFunction);
     526  alias (_Unwind_ForcedUnwind);
     527  alias (_Unwind_GetDataRelBase);
     528  alias (_Unwind_GetTextRelBase);
     529  alias (_Unwind_GetCFA);
     530  alias (_Unwind_GetGR);
     531  alias (_Unwind_GetIP);
     532  alias (_Unwind_GetLanguageSpecificData);
     533  alias (_Unwind_GetRegionStart);
     534  alias (_Unwind_RaiseException);
     535  alias (_Unwind_Resume);
     536  alias (_Unwind_Resume_or_Rethrow);
     537  alias (_Unwind_SetGR);
     538  alias (_Unwind_SetIP);
     539  #endif
     540  
     541  #endif /* !USING_SJLJ_EXCEPTIONS */