(root)/
gcc-13.2.0/
libgcc/
unwind-c.c
       1  /* Supporting functions for C exception handling.
       2     Copyright (C) 2002-2023 Free Software Foundation, Inc.
       3     Contributed by Aldy Hernandez <aldy@quesejoda.com>.
       4     Shamelessly stolen from the Java front end.
       5  
       6  This file is part of GCC.
       7  
       8  GCC is free software; you can redistribute it and/or modify it under
       9  the terms of the GNU General Public License as published by the Free
      10  Software Foundation; either version 3, or (at your option) any later
      11  version.
      12  
      13  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      14  WARRANTY; without even the implied warranty of MERCHANTABILITY or
      15  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      16  for more details.
      17  
      18  Under Section 7 of GPL version 3, you are granted additional
      19  permissions described in the GCC Runtime Library Exception, version
      20  3.1, as published by the Free Software Foundation.
      21  
      22  You should have received a copy of the GNU General Public License and
      23  a copy of the GCC Runtime Library Exception along with this program;
      24  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      25  <http://www.gnu.org/licenses/>.  */
      26  
      27  #include "tconfig.h"
      28  #include "tsystem.h"
      29  #include "auto-target.h"
      30  #include "unwind.h"
      31  #define NO_SIZE_OF_ENCODED_VALUE
      32  #include "unwind-pe.h"
      33  
      34  typedef struct
      35  {
      36    _Unwind_Ptr Start;
      37    _Unwind_Ptr LPStart;
      38    _Unwind_Ptr ttype_base;
      39    const unsigned char *TType;
      40    const unsigned char *action_table;
      41    unsigned char ttype_encoding;
      42    unsigned char call_site_encoding;
      43  } lsda_header_info;
      44  
      45  static const unsigned char *
      46  parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
      47  		   lsda_header_info *info)
      48  {
      49    _uleb128_t tmp;
      50    unsigned char lpstart_encoding;
      51  
      52    info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
      53  
      54    /* Find @LPStart, the base to which landing pad offsets are relative.  */
      55    lpstart_encoding = *p++;
      56    if (lpstart_encoding != DW_EH_PE_omit)
      57      p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
      58    else
      59      info->LPStart = info->Start;
      60  
      61    /* Find @TType, the base of the handler and exception spec type data.  */
      62    info->ttype_encoding = *p++;
      63    if (info->ttype_encoding != DW_EH_PE_omit)
      64      {
      65        p = read_uleb128 (p, &tmp);
      66        info->TType = p + tmp;
      67      }
      68    else
      69      info->TType = 0;
      70  
      71    /* The encoding and length of the call-site table; the action table
      72       immediately follows.  */
      73    info->call_site_encoding = *p++;
      74    p = read_uleb128 (p, &tmp);
      75    info->action_table = p + tmp;
      76  
      77    return p;
      78  }
      79  
      80  #ifdef __ARM_EABI_UNWINDER__
      81  /* ARM EABI personality routines must also unwind the stack.  */
      82  #define CONTINUE_UNWINDING \
      83    do								\
      84      {								\
      85        if (__gnu_unwind_frame (ue_header, context) != _URC_OK)	\
      86  	return _URC_FAILURE;					\
      87        return _URC_CONTINUE_UNWIND;				\
      88      }								\
      89    while (0)
      90  #else
      91  #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
      92  #endif
      93  
      94  #ifdef __USING_SJLJ_EXCEPTIONS__
      95  #define PERSONALITY_FUNCTION    __gcc_personality_sj0
      96  #define __builtin_eh_return_data_regno(x) x
      97  #elif defined(__SEH__)
      98  #define PERSONALITY_FUNCTION	__gcc_personality_imp
      99  #else
     100  #define PERSONALITY_FUNCTION    __gcc_personality_v0
     101  #endif
     102  
     103  #ifdef __ARM_EABI_UNWINDER__
     104  _Unwind_Reason_Code
     105  PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
     106  		      struct _Unwind_Context *);
     107  
     108  _Unwind_Reason_Code
     109  __attribute__((target ("general-regs-only")))
     110  PERSONALITY_FUNCTION (_Unwind_State state,
     111  		      struct _Unwind_Exception * ue_header,
     112  		      struct _Unwind_Context * context)
     113  #else
     114  #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__)
     115  static
     116  #endif
     117  _Unwind_Reason_Code
     118  PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
     119  		      struct _Unwind_Exception *, struct _Unwind_Context *);
     120  
     121  _Unwind_Reason_Code
     122  PERSONALITY_FUNCTION (int version,
     123  		      _Unwind_Action actions,
     124  		      _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
     125  		      struct _Unwind_Exception *ue_header,
     126  		      struct _Unwind_Context *context)
     127  #endif
     128  {
     129    lsda_header_info info;
     130    const unsigned char *language_specific_data, *p;
     131    _Unwind_Ptr landing_pad, ip;
     132    int ip_before_insn = 0;
     133  
     134  #ifdef __ARM_EABI_UNWINDER__
     135    if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
     136      CONTINUE_UNWINDING;
     137  
     138    /* The dwarf unwinder assumes the context structure holds things like the
     139       function and LSDA pointers.  The ARM implementation caches these in
     140       the exception header (UCB).  To avoid rewriting everything we make a
     141       virtual scratch register point at the UCB.  */
     142    ip = (_Unwind_Ptr) ue_header;
     143    _Unwind_SetGR (context, UNWIND_POINTER_REG, ip);
     144  #else
     145    if (version != 1)
     146      return _URC_FATAL_PHASE1_ERROR;
     147  
     148    /* Currently we only support cleanups for C.  */
     149    if ((actions & _UA_CLEANUP_PHASE) == 0)
     150      CONTINUE_UNWINDING;
     151  #endif
     152  
     153    language_specific_data = (const unsigned char *)
     154      _Unwind_GetLanguageSpecificData (context);
     155  
     156    /* If no LSDA, then there are no handlers or cleanups.  */
     157    if (! language_specific_data)
     158      CONTINUE_UNWINDING;
     159  
     160    /* Parse the LSDA header.  */
     161    p = parse_lsda_header (context, language_specific_data, &info);
     162  #ifdef HAVE_GETIPINFO
     163    ip = _Unwind_GetIPInfo (context, &ip_before_insn);
     164  #else
     165    ip = _Unwind_GetIP (context);
     166  #endif
     167    if (! ip_before_insn)
     168      --ip;
     169    landing_pad = 0;
     170  
     171  #ifdef __USING_SJLJ_EXCEPTIONS__
     172    /* The given "IP" is an index into the call-site table, with two
     173       exceptions -- -1 means no-action, and 0 means terminate.  But
     174       since we're using uleb128 values, we've not got random access
     175       to the array.  */
     176    if ((int) ip <= 0)
     177      return _URC_CONTINUE_UNWIND;
     178    else
     179      {
     180        _uleb128_t cs_lp, cs_action;
     181        do
     182  	{
     183  	  p = read_uleb128 (p, &cs_lp);
     184  	  p = read_uleb128 (p, &cs_action);
     185  	}
     186        while (--ip);
     187  
     188        /* Can never have null landing pad for sjlj -- that would have
     189  	 been indicated by a -1 call site index.  */
     190        landing_pad = (_Unwind_Ptr)cs_lp + 1;
     191        goto found_something;
     192      }
     193  #else
     194    /* Search the call-site table for the action associated with this IP.  */
     195    while (p < info.action_table)
     196      {
     197        _Unwind_Ptr cs_start, cs_len, cs_lp;
     198        _uleb128_t cs_action;
     199  
     200        /* Note that all call-site encodings are "absolute" displacements.  */
     201        p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
     202        p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
     203        p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
     204        p = read_uleb128 (p, &cs_action);
     205  
     206        /* The table is sorted, so if we've passed the ip, stop.  */
     207        if (ip < info.Start + cs_start)
     208  	p = info.action_table;
     209        else if (ip < info.Start + cs_start + cs_len)
     210  	{
     211  	  if (cs_lp)
     212  	    landing_pad = info.LPStart + cs_lp;
     213  	  goto found_something;
     214  	}
     215      }
     216  #endif
     217  
     218    /* IP is not in table.  No associated cleanups.  */
     219    /* ??? This is where C++ calls std::terminate to catch throw
     220       from a destructor.  */
     221    CONTINUE_UNWINDING;
     222  
     223   found_something:
     224    if (landing_pad == 0)
     225      {
     226        /* IP is present, but has a null landing pad.
     227  	 No handler to be run.  */
     228        CONTINUE_UNWINDING;
     229      }
     230  
     231    _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
     232  		 (_Unwind_Ptr) ue_header);
     233    _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
     234    _Unwind_SetIP (context, landing_pad);
     235    return _URC_INSTALL_CONTEXT;
     236  }
     237  
     238  #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__)
     239  EXCEPTION_DISPOSITION
     240  __gcc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
     241  			PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
     242  {
     243    return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
     244  				ms_disp, __gcc_personality_imp);
     245  }
     246  #endif /* SEH */