xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/unwind-c.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* Supporting functions for C exception handling.
2*8feb0f0bSmrg    Copyright (C) 2002-2020 Free Software Foundation, Inc.
31debfc3dSmrg    Contributed by Aldy Hernandez <aldy@quesejoda.com>.
41debfc3dSmrg    Shamelessly stolen from the Java front end.
51debfc3dSmrg 
61debfc3dSmrg This file is part of GCC.
71debfc3dSmrg 
81debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
91debfc3dSmrg the terms of the GNU General Public License as published by the Free
101debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
111debfc3dSmrg version.
121debfc3dSmrg 
131debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
141debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
151debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
161debfc3dSmrg for more details.
171debfc3dSmrg 
181debfc3dSmrg Under Section 7 of GPL version 3, you are granted additional
191debfc3dSmrg permissions described in the GCC Runtime Library Exception, version
201debfc3dSmrg 3.1, as published by the Free Software Foundation.
211debfc3dSmrg 
221debfc3dSmrg You should have received a copy of the GNU General Public License and
231debfc3dSmrg a copy of the GCC Runtime Library Exception along with this program;
241debfc3dSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
251debfc3dSmrg <http://www.gnu.org/licenses/>.  */
261debfc3dSmrg 
271debfc3dSmrg #include "tconfig.h"
281debfc3dSmrg #include "tsystem.h"
291debfc3dSmrg #include "auto-target.h"
301debfc3dSmrg #include "unwind.h"
311debfc3dSmrg #define NO_SIZE_OF_ENCODED_VALUE
321debfc3dSmrg #include "unwind-pe.h"
331debfc3dSmrg 
341debfc3dSmrg typedef struct
351debfc3dSmrg {
361debfc3dSmrg   _Unwind_Ptr Start;
371debfc3dSmrg   _Unwind_Ptr LPStart;
381debfc3dSmrg   _Unwind_Ptr ttype_base;
391debfc3dSmrg   const unsigned char *TType;
401debfc3dSmrg   const unsigned char *action_table;
411debfc3dSmrg   unsigned char ttype_encoding;
421debfc3dSmrg   unsigned char call_site_encoding;
431debfc3dSmrg } lsda_header_info;
441debfc3dSmrg 
451debfc3dSmrg static const unsigned char *
parse_lsda_header(struct _Unwind_Context * context,const unsigned char * p,lsda_header_info * info)461debfc3dSmrg parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
471debfc3dSmrg 		   lsda_header_info *info)
481debfc3dSmrg {
491debfc3dSmrg   _uleb128_t tmp;
501debfc3dSmrg   unsigned char lpstart_encoding;
511debfc3dSmrg 
521debfc3dSmrg   info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
531debfc3dSmrg 
541debfc3dSmrg   /* Find @LPStart, the base to which landing pad offsets are relative.  */
551debfc3dSmrg   lpstart_encoding = *p++;
561debfc3dSmrg   if (lpstart_encoding != DW_EH_PE_omit)
571debfc3dSmrg     p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
581debfc3dSmrg   else
591debfc3dSmrg     info->LPStart = info->Start;
601debfc3dSmrg 
611debfc3dSmrg   /* Find @TType, the base of the handler and exception spec type data.  */
621debfc3dSmrg   info->ttype_encoding = *p++;
631debfc3dSmrg   if (info->ttype_encoding != DW_EH_PE_omit)
641debfc3dSmrg     {
651debfc3dSmrg       p = read_uleb128 (p, &tmp);
661debfc3dSmrg       info->TType = p + tmp;
671debfc3dSmrg     }
681debfc3dSmrg   else
691debfc3dSmrg     info->TType = 0;
701debfc3dSmrg 
711debfc3dSmrg   /* The encoding and length of the call-site table; the action table
721debfc3dSmrg      immediately follows.  */
731debfc3dSmrg   info->call_site_encoding = *p++;
741debfc3dSmrg   p = read_uleb128 (p, &tmp);
751debfc3dSmrg   info->action_table = p + tmp;
761debfc3dSmrg 
771debfc3dSmrg   return p;
781debfc3dSmrg }
791debfc3dSmrg 
801debfc3dSmrg #ifdef __ARM_EABI_UNWINDER__
811debfc3dSmrg /* ARM EABI personality routines must also unwind the stack.  */
821debfc3dSmrg #define CONTINUE_UNWINDING \
831debfc3dSmrg   do								\
841debfc3dSmrg     {								\
851debfc3dSmrg       if (__gnu_unwind_frame (ue_header, context) != _URC_OK)	\
861debfc3dSmrg 	return _URC_FAILURE;					\
871debfc3dSmrg       return _URC_CONTINUE_UNWIND;				\
881debfc3dSmrg     }								\
891debfc3dSmrg   while (0)
901debfc3dSmrg #else
911debfc3dSmrg #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
921debfc3dSmrg #endif
931debfc3dSmrg 
941debfc3dSmrg #ifdef __USING_SJLJ_EXCEPTIONS__
951debfc3dSmrg #define PERSONALITY_FUNCTION    __gcc_personality_sj0
961debfc3dSmrg #define __builtin_eh_return_data_regno(x) x
971debfc3dSmrg #elif defined(__SEH__)
981debfc3dSmrg #define PERSONALITY_FUNCTION	__gcc_personality_imp
991debfc3dSmrg #else
1001debfc3dSmrg #define PERSONALITY_FUNCTION    __gcc_personality_v0
1011debfc3dSmrg #endif
1021debfc3dSmrg 
1031debfc3dSmrg #ifdef __ARM_EABI_UNWINDER__
1041debfc3dSmrg _Unwind_Reason_Code
1051debfc3dSmrg PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
1061debfc3dSmrg 		      struct _Unwind_Context *);
1071debfc3dSmrg 
1081debfc3dSmrg _Unwind_Reason_Code
109c0a68be4Smrg __attribute__((target ("general-regs-only")))
PERSONALITY_FUNCTION(_Unwind_State state,struct _Unwind_Exception * ue_header,struct _Unwind_Context * context)1101debfc3dSmrg PERSONALITY_FUNCTION (_Unwind_State state,
1111debfc3dSmrg 		      struct _Unwind_Exception * ue_header,
1121debfc3dSmrg 		      struct _Unwind_Context * context)
1131debfc3dSmrg #else
1141debfc3dSmrg #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__)
1151debfc3dSmrg static
1161debfc3dSmrg #endif
1171debfc3dSmrg _Unwind_Reason_Code
1181debfc3dSmrg PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
1191debfc3dSmrg 		      struct _Unwind_Exception *, struct _Unwind_Context *);
1201debfc3dSmrg 
1211debfc3dSmrg _Unwind_Reason_Code
1221debfc3dSmrg PERSONALITY_FUNCTION (int version,
1231debfc3dSmrg 		      _Unwind_Action actions,
1241debfc3dSmrg 		      _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
1251debfc3dSmrg 		      struct _Unwind_Exception *ue_header,
1261debfc3dSmrg 		      struct _Unwind_Context *context)
1271debfc3dSmrg #endif
1281debfc3dSmrg {
1291debfc3dSmrg   lsda_header_info info;
1301debfc3dSmrg   const unsigned char *language_specific_data, *p;
1311debfc3dSmrg   _Unwind_Ptr landing_pad, ip;
1321debfc3dSmrg   int ip_before_insn = 0;
1331debfc3dSmrg 
1341debfc3dSmrg #ifdef __ARM_EABI_UNWINDER__
1351debfc3dSmrg   if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
1361debfc3dSmrg     CONTINUE_UNWINDING;
1371debfc3dSmrg 
1381debfc3dSmrg   /* The dwarf unwinder assumes the context structure holds things like the
1391debfc3dSmrg      function and LSDA pointers.  The ARM implementation caches these in
1401debfc3dSmrg      the exception header (UCB).  To avoid rewriting everything we make a
1411debfc3dSmrg      virtual scratch register point at the UCB.  */
1421debfc3dSmrg   ip = (_Unwind_Ptr) ue_header;
1431debfc3dSmrg   _Unwind_SetGR (context, UNWIND_POINTER_REG, ip);
1441debfc3dSmrg #else
1451debfc3dSmrg   if (version != 1)
1461debfc3dSmrg     return _URC_FATAL_PHASE1_ERROR;
1471debfc3dSmrg 
1481debfc3dSmrg   /* Currently we only support cleanups for C.  */
1491debfc3dSmrg   if ((actions & _UA_CLEANUP_PHASE) == 0)
1501debfc3dSmrg     CONTINUE_UNWINDING;
1511debfc3dSmrg #endif
1521debfc3dSmrg 
1531debfc3dSmrg   language_specific_data = (const unsigned char *)
1541debfc3dSmrg     _Unwind_GetLanguageSpecificData (context);
1551debfc3dSmrg 
1561debfc3dSmrg   /* If no LSDA, then there are no handlers or cleanups.  */
1571debfc3dSmrg   if (! language_specific_data)
1581debfc3dSmrg     CONTINUE_UNWINDING;
1591debfc3dSmrg 
1601debfc3dSmrg   /* Parse the LSDA header.  */
1611debfc3dSmrg   p = parse_lsda_header (context, language_specific_data, &info);
1621debfc3dSmrg #ifdef HAVE_GETIPINFO
1631debfc3dSmrg   ip = _Unwind_GetIPInfo (context, &ip_before_insn);
1641debfc3dSmrg #else
1651debfc3dSmrg   ip = _Unwind_GetIP (context);
1661debfc3dSmrg #endif
1671debfc3dSmrg   if (! ip_before_insn)
1681debfc3dSmrg     --ip;
1691debfc3dSmrg   landing_pad = 0;
1701debfc3dSmrg 
1711debfc3dSmrg #ifdef __USING_SJLJ_EXCEPTIONS__
1721debfc3dSmrg   /* The given "IP" is an index into the call-site table, with two
1731debfc3dSmrg      exceptions -- -1 means no-action, and 0 means terminate.  But
1741debfc3dSmrg      since we're using uleb128 values, we've not got random access
1751debfc3dSmrg      to the array.  */
1761debfc3dSmrg   if ((int) ip <= 0)
1771debfc3dSmrg     return _URC_CONTINUE_UNWIND;
1781debfc3dSmrg   else
1791debfc3dSmrg     {
1801debfc3dSmrg       _uleb128_t cs_lp, cs_action;
1811debfc3dSmrg       do
1821debfc3dSmrg 	{
1831debfc3dSmrg 	  p = read_uleb128 (p, &cs_lp);
1841debfc3dSmrg 	  p = read_uleb128 (p, &cs_action);
1851debfc3dSmrg 	}
1861debfc3dSmrg       while (--ip);
1871debfc3dSmrg 
1881debfc3dSmrg       /* Can never have null landing pad for sjlj -- that would have
1891debfc3dSmrg 	 been indicated by a -1 call site index.  */
1901debfc3dSmrg       landing_pad = (_Unwind_Ptr)cs_lp + 1;
1911debfc3dSmrg       goto found_something;
1921debfc3dSmrg     }
1931debfc3dSmrg #else
1941debfc3dSmrg   /* Search the call-site table for the action associated with this IP.  */
1951debfc3dSmrg   while (p < info.action_table)
1961debfc3dSmrg     {
1971debfc3dSmrg       _Unwind_Ptr cs_start, cs_len, cs_lp;
1981debfc3dSmrg       _uleb128_t cs_action;
1991debfc3dSmrg 
2001debfc3dSmrg       /* Note that all call-site encodings are "absolute" displacements.  */
2011debfc3dSmrg       p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
2021debfc3dSmrg       p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
2031debfc3dSmrg       p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
2041debfc3dSmrg       p = read_uleb128 (p, &cs_action);
2051debfc3dSmrg 
2061debfc3dSmrg       /* The table is sorted, so if we've passed the ip, stop.  */
2071debfc3dSmrg       if (ip < info.Start + cs_start)
2081debfc3dSmrg 	p = info.action_table;
2091debfc3dSmrg       else if (ip < info.Start + cs_start + cs_len)
2101debfc3dSmrg 	{
2111debfc3dSmrg 	  if (cs_lp)
2121debfc3dSmrg 	    landing_pad = info.LPStart + cs_lp;
2131debfc3dSmrg 	  goto found_something;
2141debfc3dSmrg 	}
2151debfc3dSmrg     }
2161debfc3dSmrg #endif
2171debfc3dSmrg 
2181debfc3dSmrg   /* IP is not in table.  No associated cleanups.  */
2191debfc3dSmrg   /* ??? This is where C++ calls std::terminate to catch throw
2201debfc3dSmrg      from a destructor.  */
2211debfc3dSmrg   CONTINUE_UNWINDING;
2221debfc3dSmrg 
2231debfc3dSmrg  found_something:
2241debfc3dSmrg   if (landing_pad == 0)
2251debfc3dSmrg     {
2261debfc3dSmrg       /* IP is present, but has a null landing pad.
2271debfc3dSmrg 	 No handler to be run.  */
2281debfc3dSmrg       CONTINUE_UNWINDING;
2291debfc3dSmrg     }
2301debfc3dSmrg 
2311debfc3dSmrg   _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
2321debfc3dSmrg 		 (_Unwind_Ptr) ue_header);
2331debfc3dSmrg   _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
2341debfc3dSmrg   _Unwind_SetIP (context, landing_pad);
2351debfc3dSmrg   return _URC_INSTALL_CONTEXT;
2361debfc3dSmrg }
2371debfc3dSmrg 
2381debfc3dSmrg #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__)
2391debfc3dSmrg EXCEPTION_DISPOSITION
__gcc_personality_seh0(PEXCEPTION_RECORD ms_exc,void * this_frame,PCONTEXT ms_orig_context,PDISPATCHER_CONTEXT ms_disp)2401debfc3dSmrg __gcc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
2411debfc3dSmrg 			PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
2421debfc3dSmrg {
2431debfc3dSmrg   return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
2441debfc3dSmrg 				ms_disp, __gcc_personality_imp);
2451debfc3dSmrg }
2461debfc3dSmrg #endif /* SEH */
247