xref: /netbsd-src/external/gpl3/gcc/dist/libgcc/unwind-c.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
148fb7bfaSmrg /* Supporting functions for C exception handling.
2*b1e83836Smrg    Copyright (C) 2002-2022 Free Software Foundation, Inc.
348fb7bfaSmrg    Contributed by Aldy Hernandez <aldy@quesejoda.com>.
448fb7bfaSmrg    Shamelessly stolen from the Java front end.
548fb7bfaSmrg 
648fb7bfaSmrg This file is part of GCC.
748fb7bfaSmrg 
848fb7bfaSmrg GCC is free software; you can redistribute it and/or modify it under
948fb7bfaSmrg the terms of the GNU General Public License as published by the Free
1048fb7bfaSmrg Software Foundation; either version 3, or (at your option) any later
1148fb7bfaSmrg version.
1248fb7bfaSmrg 
1348fb7bfaSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1448fb7bfaSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1548fb7bfaSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1648fb7bfaSmrg for more details.
1748fb7bfaSmrg 
1848fb7bfaSmrg Under Section 7 of GPL version 3, you are granted additional
1948fb7bfaSmrg permissions described in the GCC Runtime Library Exception, version
2048fb7bfaSmrg 3.1, as published by the Free Software Foundation.
2148fb7bfaSmrg 
2248fb7bfaSmrg You should have received a copy of the GNU General Public License and
2348fb7bfaSmrg a copy of the GCC Runtime Library Exception along with this program;
2448fb7bfaSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2548fb7bfaSmrg <http://www.gnu.org/licenses/>.  */
2648fb7bfaSmrg 
2748fb7bfaSmrg #include "tconfig.h"
2848fb7bfaSmrg #include "tsystem.h"
293f4ceed9Smrg #include "auto-target.h"
3048fb7bfaSmrg #include "unwind.h"
3148fb7bfaSmrg #define NO_SIZE_OF_ENCODED_VALUE
3248fb7bfaSmrg #include "unwind-pe.h"
3348fb7bfaSmrg 
3448fb7bfaSmrg typedef struct
3548fb7bfaSmrg {
3648fb7bfaSmrg   _Unwind_Ptr Start;
3748fb7bfaSmrg   _Unwind_Ptr LPStart;
3848fb7bfaSmrg   _Unwind_Ptr ttype_base;
3948fb7bfaSmrg   const unsigned char *TType;
4048fb7bfaSmrg   const unsigned char *action_table;
4148fb7bfaSmrg   unsigned char ttype_encoding;
4248fb7bfaSmrg   unsigned char call_site_encoding;
4348fb7bfaSmrg } lsda_header_info;
4448fb7bfaSmrg 
4548fb7bfaSmrg static const unsigned char *
parse_lsda_header(struct _Unwind_Context * context,const unsigned char * p,lsda_header_info * info)4648fb7bfaSmrg parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
4748fb7bfaSmrg 		   lsda_header_info *info)
4848fb7bfaSmrg {
4948fb7bfaSmrg   _uleb128_t tmp;
5048fb7bfaSmrg   unsigned char lpstart_encoding;
5148fb7bfaSmrg 
5248fb7bfaSmrg   info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
5348fb7bfaSmrg 
5448fb7bfaSmrg   /* Find @LPStart, the base to which landing pad offsets are relative.  */
5548fb7bfaSmrg   lpstart_encoding = *p++;
5648fb7bfaSmrg   if (lpstart_encoding != DW_EH_PE_omit)
5748fb7bfaSmrg     p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
5848fb7bfaSmrg   else
5948fb7bfaSmrg     info->LPStart = info->Start;
6048fb7bfaSmrg 
6148fb7bfaSmrg   /* Find @TType, the base of the handler and exception spec type data.  */
6248fb7bfaSmrg   info->ttype_encoding = *p++;
6348fb7bfaSmrg   if (info->ttype_encoding != DW_EH_PE_omit)
6448fb7bfaSmrg     {
6548fb7bfaSmrg       p = read_uleb128 (p, &tmp);
6648fb7bfaSmrg       info->TType = p + tmp;
6748fb7bfaSmrg     }
6848fb7bfaSmrg   else
6948fb7bfaSmrg     info->TType = 0;
7048fb7bfaSmrg 
7148fb7bfaSmrg   /* The encoding and length of the call-site table; the action table
7248fb7bfaSmrg      immediately follows.  */
7348fb7bfaSmrg   info->call_site_encoding = *p++;
7448fb7bfaSmrg   p = read_uleb128 (p, &tmp);
7548fb7bfaSmrg   info->action_table = p + tmp;
7648fb7bfaSmrg 
7748fb7bfaSmrg   return p;
7848fb7bfaSmrg }
7948fb7bfaSmrg 
8048fb7bfaSmrg #ifdef __ARM_EABI_UNWINDER__
8148fb7bfaSmrg /* ARM EABI personality routines must also unwind the stack.  */
8248fb7bfaSmrg #define CONTINUE_UNWINDING \
8348fb7bfaSmrg   do								\
8448fb7bfaSmrg     {								\
8548fb7bfaSmrg       if (__gnu_unwind_frame (ue_header, context) != _URC_OK)	\
8648fb7bfaSmrg 	return _URC_FAILURE;					\
8748fb7bfaSmrg       return _URC_CONTINUE_UNWIND;				\
8848fb7bfaSmrg     }								\
8948fb7bfaSmrg   while (0)
9048fb7bfaSmrg #else
9148fb7bfaSmrg #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
9248fb7bfaSmrg #endif
9348fb7bfaSmrg 
9448fb7bfaSmrg #ifdef __USING_SJLJ_EXCEPTIONS__
9548fb7bfaSmrg #define PERSONALITY_FUNCTION    __gcc_personality_sj0
9648fb7bfaSmrg #define __builtin_eh_return_data_regno(x) x
9748fb7bfaSmrg #elif defined(__SEH__)
9848fb7bfaSmrg #define PERSONALITY_FUNCTION	__gcc_personality_imp
9948fb7bfaSmrg #else
10048fb7bfaSmrg #define PERSONALITY_FUNCTION    __gcc_personality_v0
10148fb7bfaSmrg #endif
10248fb7bfaSmrg 
10348fb7bfaSmrg #ifdef __ARM_EABI_UNWINDER__
10448fb7bfaSmrg _Unwind_Reason_Code
10548fb7bfaSmrg PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
10648fb7bfaSmrg 		      struct _Unwind_Context *);
10748fb7bfaSmrg 
10848fb7bfaSmrg _Unwind_Reason_Code
109181254a7Smrg __attribute__((target ("general-regs-only")))
PERSONALITY_FUNCTION(_Unwind_State state,struct _Unwind_Exception * ue_header,struct _Unwind_Context * context)11048fb7bfaSmrg PERSONALITY_FUNCTION (_Unwind_State state,
11148fb7bfaSmrg 		      struct _Unwind_Exception * ue_header,
11248fb7bfaSmrg 		      struct _Unwind_Context * context)
11348fb7bfaSmrg #else
11448fb7bfaSmrg #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__)
11548fb7bfaSmrg static
11648fb7bfaSmrg #endif
11748fb7bfaSmrg _Unwind_Reason_Code
11848fb7bfaSmrg PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
11948fb7bfaSmrg 		      struct _Unwind_Exception *, struct _Unwind_Context *);
12048fb7bfaSmrg 
12148fb7bfaSmrg _Unwind_Reason_Code
12248fb7bfaSmrg PERSONALITY_FUNCTION (int version,
12348fb7bfaSmrg 		      _Unwind_Action actions,
12448fb7bfaSmrg 		      _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
12548fb7bfaSmrg 		      struct _Unwind_Exception *ue_header,
12648fb7bfaSmrg 		      struct _Unwind_Context *context)
12748fb7bfaSmrg #endif
12848fb7bfaSmrg {
12948fb7bfaSmrg   lsda_header_info info;
13048fb7bfaSmrg   const unsigned char *language_specific_data, *p;
13148fb7bfaSmrg   _Unwind_Ptr landing_pad, ip;
13248fb7bfaSmrg   int ip_before_insn = 0;
13348fb7bfaSmrg 
13448fb7bfaSmrg #ifdef __ARM_EABI_UNWINDER__
13548fb7bfaSmrg   if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
13648fb7bfaSmrg     CONTINUE_UNWINDING;
13748fb7bfaSmrg 
13848fb7bfaSmrg   /* The dwarf unwinder assumes the context structure holds things like the
13948fb7bfaSmrg      function and LSDA pointers.  The ARM implementation caches these in
14048fb7bfaSmrg      the exception header (UCB).  To avoid rewriting everything we make a
14148fb7bfaSmrg      virtual scratch register point at the UCB.  */
14248fb7bfaSmrg   ip = (_Unwind_Ptr) ue_header;
14348fb7bfaSmrg   _Unwind_SetGR (context, UNWIND_POINTER_REG, ip);
14448fb7bfaSmrg #else
14548fb7bfaSmrg   if (version != 1)
14648fb7bfaSmrg     return _URC_FATAL_PHASE1_ERROR;
14748fb7bfaSmrg 
14848fb7bfaSmrg   /* Currently we only support cleanups for C.  */
14948fb7bfaSmrg   if ((actions & _UA_CLEANUP_PHASE) == 0)
15048fb7bfaSmrg     CONTINUE_UNWINDING;
15148fb7bfaSmrg #endif
15248fb7bfaSmrg 
15348fb7bfaSmrg   language_specific_data = (const unsigned char *)
15448fb7bfaSmrg     _Unwind_GetLanguageSpecificData (context);
15548fb7bfaSmrg 
15648fb7bfaSmrg   /* If no LSDA, then there are no handlers or cleanups.  */
15748fb7bfaSmrg   if (! language_specific_data)
15848fb7bfaSmrg     CONTINUE_UNWINDING;
15948fb7bfaSmrg 
16048fb7bfaSmrg   /* Parse the LSDA header.  */
16148fb7bfaSmrg   p = parse_lsda_header (context, language_specific_data, &info);
16248fb7bfaSmrg #ifdef HAVE_GETIPINFO
16348fb7bfaSmrg   ip = _Unwind_GetIPInfo (context, &ip_before_insn);
16448fb7bfaSmrg #else
16548fb7bfaSmrg   ip = _Unwind_GetIP (context);
16648fb7bfaSmrg #endif
16748fb7bfaSmrg   if (! ip_before_insn)
16848fb7bfaSmrg     --ip;
16948fb7bfaSmrg   landing_pad = 0;
17048fb7bfaSmrg 
17148fb7bfaSmrg #ifdef __USING_SJLJ_EXCEPTIONS__
17248fb7bfaSmrg   /* The given "IP" is an index into the call-site table, with two
17348fb7bfaSmrg      exceptions -- -1 means no-action, and 0 means terminate.  But
17448fb7bfaSmrg      since we're using uleb128 values, we've not got random access
17548fb7bfaSmrg      to the array.  */
17648fb7bfaSmrg   if ((int) ip <= 0)
17748fb7bfaSmrg     return _URC_CONTINUE_UNWIND;
17848fb7bfaSmrg   else
17948fb7bfaSmrg     {
18048fb7bfaSmrg       _uleb128_t cs_lp, cs_action;
18148fb7bfaSmrg       do
18248fb7bfaSmrg 	{
18348fb7bfaSmrg 	  p = read_uleb128 (p, &cs_lp);
18448fb7bfaSmrg 	  p = read_uleb128 (p, &cs_action);
18548fb7bfaSmrg 	}
18648fb7bfaSmrg       while (--ip);
18748fb7bfaSmrg 
18848fb7bfaSmrg       /* Can never have null landing pad for sjlj -- that would have
18948fb7bfaSmrg 	 been indicated by a -1 call site index.  */
19048fb7bfaSmrg       landing_pad = (_Unwind_Ptr)cs_lp + 1;
19148fb7bfaSmrg       goto found_something;
19248fb7bfaSmrg     }
19348fb7bfaSmrg #else
19448fb7bfaSmrg   /* Search the call-site table for the action associated with this IP.  */
19548fb7bfaSmrg   while (p < info.action_table)
19648fb7bfaSmrg     {
19748fb7bfaSmrg       _Unwind_Ptr cs_start, cs_len, cs_lp;
19848fb7bfaSmrg       _uleb128_t cs_action;
19948fb7bfaSmrg 
20048fb7bfaSmrg       /* Note that all call-site encodings are "absolute" displacements.  */
20148fb7bfaSmrg       p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
20248fb7bfaSmrg       p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
20348fb7bfaSmrg       p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
20448fb7bfaSmrg       p = read_uleb128 (p, &cs_action);
20548fb7bfaSmrg 
20648fb7bfaSmrg       /* The table is sorted, so if we've passed the ip, stop.  */
20748fb7bfaSmrg       if (ip < info.Start + cs_start)
20848fb7bfaSmrg 	p = info.action_table;
20948fb7bfaSmrg       else if (ip < info.Start + cs_start + cs_len)
21048fb7bfaSmrg 	{
21148fb7bfaSmrg 	  if (cs_lp)
21248fb7bfaSmrg 	    landing_pad = info.LPStart + cs_lp;
21348fb7bfaSmrg 	  goto found_something;
21448fb7bfaSmrg 	}
21548fb7bfaSmrg     }
21648fb7bfaSmrg #endif
21748fb7bfaSmrg 
21848fb7bfaSmrg   /* IP is not in table.  No associated cleanups.  */
21948fb7bfaSmrg   /* ??? This is where C++ calls std::terminate to catch throw
22048fb7bfaSmrg      from a destructor.  */
22148fb7bfaSmrg   CONTINUE_UNWINDING;
22248fb7bfaSmrg 
22348fb7bfaSmrg  found_something:
22448fb7bfaSmrg   if (landing_pad == 0)
22548fb7bfaSmrg     {
22648fb7bfaSmrg       /* IP is present, but has a null landing pad.
22748fb7bfaSmrg 	 No handler to be run.  */
22848fb7bfaSmrg       CONTINUE_UNWINDING;
22948fb7bfaSmrg     }
23048fb7bfaSmrg 
23148fb7bfaSmrg   _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
23248fb7bfaSmrg 		 (_Unwind_Ptr) ue_header);
23348fb7bfaSmrg   _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
23448fb7bfaSmrg   _Unwind_SetIP (context, landing_pad);
23548fb7bfaSmrg   return _URC_INSTALL_CONTEXT;
23648fb7bfaSmrg }
23748fb7bfaSmrg 
23848fb7bfaSmrg #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__)
23948fb7bfaSmrg EXCEPTION_DISPOSITION
__gcc_personality_seh0(PEXCEPTION_RECORD ms_exc,void * this_frame,PCONTEXT ms_orig_context,PDISPATCHER_CONTEXT ms_disp)24048fb7bfaSmrg __gcc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
24148fb7bfaSmrg 			PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
24248fb7bfaSmrg {
24348fb7bfaSmrg   return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
24448fb7bfaSmrg 				ms_disp, __gcc_personality_imp);
24548fb7bfaSmrg }
24648fb7bfaSmrg #endif /* SEH */
247