| // -*- C++ -*- The GNU C++ exception personality routine. | 
 | // Copyright (C) 2001-2025 Free Software Foundation, Inc. | 
 | // | 
 | // This file is part of GCC. | 
 | // | 
 | // GCC is free software; you can redistribute it and/or modify | 
 | // it under the terms of the GNU General Public License as published by | 
 | // the Free Software Foundation; either version 3, or (at your option) | 
 | // any later version. | 
 | // | 
 | // GCC is distributed in the hope that it will be useful, | 
 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | // GNU General Public License for more details. | 
 | // | 
 | // Under Section 7 of GPL version 3, you are granted additional | 
 | // permissions described in the GCC Runtime Library Exception, version | 
 | // 3.1, as published by the Free Software Foundation. | 
 |  | 
 | // You should have received a copy of the GNU General Public License and | 
 | // a copy of the GCC Runtime Library Exception along with this program; | 
 | // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see | 
 | // <http://www.gnu.org/licenses/>. | 
 |  | 
 | #include <bits/c++config.h> | 
 | #include <cstdlib> | 
 | #include <bits/exception_defines.h> | 
 | #include <cxxabi.h> | 
 | #include "unwind-cxx.h" | 
 |  | 
 |  | 
 | using namespace __cxxabiv1; | 
 |  | 
 | #include "unwind-pe.h" | 
 |  | 
 |  | 
 | struct lsda_header_info | 
 | { | 
 |   _Unwind_Ptr Start; | 
 |   _Unwind_Ptr LPStart; | 
 |   _Unwind_Ptr ttype_base; | 
 |   const unsigned char *TType; | 
 |   const unsigned char *action_table; | 
 |   unsigned char ttype_encoding; | 
 |   unsigned char call_site_encoding; | 
 | }; | 
 |  | 
 | static const unsigned char * | 
 | parse_lsda_header (_Unwind_Context *context, const unsigned char *p, | 
 | 		   lsda_header_info *info) | 
 | { | 
 |   _uleb128_t tmp; | 
 |   unsigned char lpstart_encoding; | 
 |  | 
 |   info->Start = (context ? _Unwind_GetRegionStart (context) : 0); | 
 |  | 
 |   // Find @LPStart, the base to which landing pad offsets are relative. | 
 |   lpstart_encoding = *p++; | 
 |   if (lpstart_encoding != DW_EH_PE_omit) | 
 |     p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); | 
 |   else | 
 |     info->LPStart = info->Start; | 
 |  | 
 |   // Find @TType, the base of the handler and exception spec type data. | 
 |   info->ttype_encoding = *p++; | 
 |   if (info->ttype_encoding != DW_EH_PE_omit) | 
 |     { | 
 | #if _GLIBCXX_OVERRIDE_TTYPE_ENCODING | 
 |       /* Older ARM EABI toolchains set this value incorrectly, so use a | 
 | 	 hardcoded OS-specific format.  */ | 
 |       info->ttype_encoding = _GLIBCXX_OVERRIDE_TTYPE_ENCODING; | 
 | #endif | 
 |       p = read_uleb128 (p, &tmp); | 
 |       info->TType = p + tmp; | 
 |     } | 
 |   else | 
 |     info->TType = 0; | 
 |  | 
 |   // The encoding and length of the call-site table; the action table | 
 |   // immediately follows. | 
 |   info->call_site_encoding = *p++; | 
 |   p = read_uleb128 (p, &tmp); | 
 |   info->action_table = p + tmp; | 
 |  | 
 |   return p; | 
 | } | 
 |  | 
 | // Return an element from a type table. | 
 |  | 
 | static const std::type_info * | 
 | get_ttype_entry (lsda_header_info *info, _uleb128_t i) | 
 | { | 
 |   _Unwind_Ptr ptr; | 
 |  | 
 |   i *= size_of_encoded_value (info->ttype_encoding); | 
 |   read_encoded_value_with_base ( | 
 | #if __FDPIC__ | 
 | 				/* Force these flags to make sure to | 
 | 				   take the GOT into account.  */ | 
 | 				(DW_EH_PE_pcrel | DW_EH_PE_indirect), | 
 | #else | 
 | 				info->ttype_encoding, | 
 | #endif | 
 | 				info->ttype_base, | 
 | 				info->TType - i, &ptr); | 
 |  | 
 |   return reinterpret_cast<const std::type_info *>(ptr); | 
 | } | 
 |  | 
 | #ifdef __ARM_EABI_UNWINDER__ | 
 |  | 
 | // The ABI provides a routine for matching exception object types. | 
 | typedef _Unwind_Control_Block _throw_typet; | 
 | #define get_adjusted_ptr(catch_type, throw_type, thrown_ptr_p) \ | 
 |   (__cxa_type_match (throw_type, catch_type, false, thrown_ptr_p) \ | 
 |    != ctm_failed) | 
 |  | 
 | // Return true if THROW_TYPE matches one if the filter types. | 
 |  | 
 | static bool | 
 | check_exception_spec(lsda_header_info* info, _throw_typet* throw_type, | 
 | 		     void* thrown_ptr, _sleb128_t filter_value) | 
 | { | 
 |   const _uleb128_t* e = ((const _uleb128_t*) info->TType) | 
 | 			  - filter_value - 1; | 
 |  | 
 |   while (1) | 
 |     { | 
 |       const std::type_info* catch_type; | 
 |       _uleb128_t tmp; | 
 |  | 
 |       tmp = *e; | 
 |  | 
 |       // Zero signals the end of the list.  If we've not found | 
 |       // a match by now, then we've failed the specification. | 
 |       if (tmp == 0) | 
 |         return false; | 
 |  | 
 |       tmp = _Unwind_decode_typeinfo_ptr(info->ttype_base, (_Unwind_Word) e); | 
 |  | 
 |       // Match a ttype entry. | 
 |       catch_type = reinterpret_cast<const std::type_info*>(tmp); | 
 |  | 
 |       // ??? There is currently no way to ask the RTTI code about the | 
 |       // relationship between two types without reference to a specific | 
 |       // object.  There should be; then we wouldn't need to mess with | 
 |       // thrown_ptr here. | 
 |       if (get_adjusted_ptr(catch_type, throw_type, &thrown_ptr)) | 
 | 	return true; | 
 |  | 
 |       // Advance to the next entry. | 
 |       e++; | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | // Save stage1 handler information in the exception object | 
 |  | 
 | static inline void | 
 | save_caught_exception(struct _Unwind_Exception* ue_header, | 
 | 		      struct _Unwind_Context* context, | 
 | 		      void* thrown_ptr, | 
 | 		      int handler_switch_value, | 
 | 		      const unsigned char* language_specific_data, | 
 | 		      _Unwind_Ptr landing_pad, | 
 | 		      const unsigned char* action_record | 
 | 			__attribute__((__unused__))) | 
 | { | 
 |     ue_header->barrier_cache.sp = _Unwind_GetGR(context, UNWIND_STACK_REG); | 
 |     ue_header->barrier_cache.bitpattern[0] = (_uw) thrown_ptr; | 
 |     ue_header->barrier_cache.bitpattern[1] | 
 |       = (_uw) handler_switch_value; | 
 |     ue_header->barrier_cache.bitpattern[2] | 
 |       = (_uw) language_specific_data; | 
 |     ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad; | 
 | } | 
 |  | 
 |  | 
 | // Restore the catch handler data saved during phase1. | 
 |  | 
 | static inline void | 
 | restore_caught_exception(struct _Unwind_Exception* ue_header, | 
 | 			 int& handler_switch_value, | 
 | 			 const unsigned char*& language_specific_data, | 
 | 			 _Unwind_Ptr& landing_pad) | 
 | { | 
 |   handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1]; | 
 |   language_specific_data = | 
 |     (const unsigned char*) ue_header->barrier_cache.bitpattern[2]; | 
 |   landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3]; | 
 | } | 
 |  | 
 | #define CONTINUE_UNWINDING \ | 
 |   do								\ | 
 |     {								\ | 
 |       if (__gnu_unwind_frame(ue_header, context) != _URC_OK)	\ | 
 | 	return _URC_FAILURE;					\ | 
 |       return _URC_CONTINUE_UNWIND;				\ | 
 |     }								\ | 
 |   while (0) | 
 |  | 
 | // Return true if the filter spec is empty, ie throw(). | 
 |  | 
 | static bool | 
 | empty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value) | 
 | { | 
 |   const _Unwind_Word* e = ((const _Unwind_Word*) info->TType) | 
 | 			  - filter_value - 1; | 
 |  | 
 |   return *e == 0; | 
 | } | 
 |  | 
 | #else | 
 | typedef const std::type_info _throw_typet; | 
 |  | 
 |  | 
 | // Given the thrown type THROW_TYPE, pointer to a variable containing a | 
 | // pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to | 
 | // compare against, return whether or not there is a match and if so, | 
 | // update *THROWN_PTR_P. | 
 |  | 
 | static bool | 
 | get_adjusted_ptr (const std::type_info *catch_type, | 
 | 		  const std::type_info *throw_type, | 
 | 		  void **thrown_ptr_p) | 
 | { | 
 |   void *thrown_ptr = *thrown_ptr_p; | 
 |  | 
 |   // Pointer types need to adjust the actual pointer, not | 
 |   // the pointer to pointer that is the exception object. | 
 |   // This also has the effect of passing pointer types | 
 |   // "by value" through the __cxa_begin_catch return value. | 
 |   if (throw_type->__is_pointer_p ()) | 
 |     thrown_ptr = *(void **) thrown_ptr; | 
 |  | 
 |   if (catch_type->__do_catch (throw_type, &thrown_ptr, 1)) | 
 |     { | 
 |       *thrown_ptr_p = thrown_ptr; | 
 |       return true; | 
 |     } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | // Return true if THROW_TYPE matches one if the filter types. | 
 |  | 
 | static bool | 
 | check_exception_spec(lsda_header_info* info, _throw_typet* throw_type, | 
 | 		      void* thrown_ptr, _sleb128_t filter_value) | 
 | { | 
 |   const unsigned char *e = info->TType - filter_value - 1; | 
 |  | 
 |   while (1) | 
 |     { | 
 |       const std::type_info *catch_type; | 
 |       _uleb128_t tmp; | 
 |  | 
 |       e = read_uleb128 (e, &tmp); | 
 |  | 
 |       // Zero signals the end of the list.  If we've not found | 
 |       // a match by now, then we've failed the specification. | 
 |       if (tmp == 0) | 
 |         return false; | 
 |  | 
 |       // Match a ttype entry. | 
 |       catch_type = get_ttype_entry (info, tmp); | 
 |  | 
 |       // ??? There is currently no way to ask the RTTI code about the | 
 |       // relationship between two types without reference to a specific | 
 |       // object.  There should be; then we wouldn't need to mess with | 
 |       // thrown_ptr here. | 
 |       if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr)) | 
 | 	return true; | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | // Save stage1 handler information in the exception object | 
 |  | 
 | static inline void | 
 | save_caught_exception(struct _Unwind_Exception* ue_header, | 
 | 		      struct _Unwind_Context* context | 
 | 			__attribute__((__unused__)), | 
 | 		      void* thrown_ptr, | 
 | 		      int handler_switch_value, | 
 | 		      const unsigned char* language_specific_data, | 
 | 		      _Unwind_Ptr landing_pad __attribute__((__unused__)), | 
 | 		      const unsigned char* action_record) | 
 | { | 
 |   __cxa_exception* xh = __get_exception_header_from_ue(ue_header); | 
 |  | 
 |   xh->handlerSwitchValue = handler_switch_value; | 
 |   xh->actionRecord = action_record; | 
 |   xh->languageSpecificData = language_specific_data; | 
 |   xh->adjustedPtr = thrown_ptr; | 
 |  | 
 |   // ??? Completely unknown what this field is supposed to be for. | 
 |   // ??? Need to cache TType encoding base for call_unexpected. | 
 |   xh->catchTemp = landing_pad; | 
 | } | 
 |  | 
 |  | 
 | // Restore the catch handler information saved during phase1. | 
 |  | 
 | static inline void | 
 | restore_caught_exception(struct _Unwind_Exception* ue_header, | 
 | 			 int& handler_switch_value, | 
 | 			 const unsigned char*& language_specific_data, | 
 | 			 _Unwind_Ptr& landing_pad) | 
 | { | 
 |   __cxa_exception* xh = __get_exception_header_from_ue(ue_header); | 
 |   handler_switch_value = xh->handlerSwitchValue; | 
 |   language_specific_data = xh->languageSpecificData; | 
 |   landing_pad = (_Unwind_Ptr) xh->catchTemp; | 
 | } | 
 |  | 
 | #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND | 
 |  | 
 | // Return true if the filter spec is empty, ie throw(). | 
 |  | 
 | static bool | 
 | empty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value) | 
 | { | 
 |   const unsigned char *e = info->TType - filter_value - 1; | 
 |   _uleb128_t tmp; | 
 |  | 
 |   e = read_uleb128 (e, &tmp); | 
 |   return tmp == 0; | 
 | } | 
 |  | 
 | #endif // !__ARM_EABI_UNWINDER__ | 
 |  | 
 | namespace __cxxabiv1 | 
 | { | 
 |  | 
 | // Using a different personality function name causes link failures | 
 | // when trying to mix code using different exception handling models. | 
 | #ifdef __USING_SJLJ_EXCEPTIONS__ | 
 | #define PERSONALITY_FUNCTION	__gxx_personality_sj0 | 
 | #define __builtin_eh_return_data_regno(x) x | 
 | #elif defined(__SEH__) | 
 | #define PERSONALITY_FUNCTION	__gxx_personality_imp | 
 | #else | 
 | #define PERSONALITY_FUNCTION	__gxx_personality_v0 | 
 | #endif | 
 |  | 
 | #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__) | 
 | static | 
 | #else | 
 | extern "C" | 
 | #endif | 
 | _Unwind_Reason_Code | 
 | #ifdef __ARM_EABI_UNWINDER__ | 
 | __attribute__((target ("general-regs-only"))) | 
 | PERSONALITY_FUNCTION (_Unwind_State state, | 
 | 		      struct _Unwind_Exception* ue_header, | 
 | 		      struct _Unwind_Context* context) | 
 | #else | 
 | PERSONALITY_FUNCTION (int version, | 
 | 		      _Unwind_Action actions, | 
 | 		      _Unwind_Exception_Class exception_class, | 
 | 		      struct _Unwind_Exception *ue_header, | 
 | 		      struct _Unwind_Context *context) | 
 | #endif | 
 | { | 
 |   enum found_handler_type | 
 |   { | 
 |     found_nothing, | 
 |     found_terminate, | 
 |     found_cleanup, | 
 |     found_handler | 
 |   } found_type; | 
 |  | 
 |   lsda_header_info info; | 
 |   const unsigned char *language_specific_data; | 
 |   const unsigned char *action_record; | 
 |   const unsigned char *p; | 
 |   _Unwind_Ptr landing_pad, ip; | 
 |   int handler_switch_value; | 
 |   void* thrown_ptr = 0; | 
 |   bool foreign_exception; | 
 |   int ip_before_insn = 0; | 
 |  | 
 | #ifdef __ARM_EABI_UNWINDER__ | 
 |   _Unwind_Action actions; | 
 |  | 
 |   switch (state & _US_ACTION_MASK) | 
 |     { | 
 |     case _US_VIRTUAL_UNWIND_FRAME: | 
 |       // If the unwind state pattern is | 
 |       // _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND | 
 |       // then we don't need to search for any handler as it is not a real | 
 |       // exception. Just unwind the stack. | 
 |       if (state & _US_FORCE_UNWIND) | 
 | 	CONTINUE_UNWINDING; | 
 |       actions = _UA_SEARCH_PHASE; | 
 |       break; | 
 |  | 
 |     case _US_UNWIND_FRAME_STARTING: | 
 |       actions = _UA_CLEANUP_PHASE; | 
 |       if (!(state & _US_FORCE_UNWIND) | 
 | 	  && ue_header->barrier_cache.sp == _Unwind_GetGR(context, | 
 | 							  UNWIND_STACK_REG)) | 
 | 	actions |= _UA_HANDLER_FRAME; | 
 |       break; | 
 |  | 
 |     case _US_UNWIND_FRAME_RESUME: | 
 |       CONTINUE_UNWINDING; | 
 |       break; | 
 |  | 
 |     default: | 
 |       std::abort(); | 
 |     } | 
 |   actions |= state & _US_FORCE_UNWIND; | 
 |  | 
 |   // We don't know which runtime we're working with, so can't check this. | 
 |   // However the ABI routines hide this from us, and we don't actually need | 
 |   // to know. | 
 |   foreign_exception = false; | 
 |  | 
 |   // The dwarf unwinder assumes the context structure holds things like the | 
 |   // function and LSDA pointers.  The ARM implementation caches these in | 
 |   // the exception header (UCB).  To avoid rewriting everything we make a | 
 |   // virtual scratch register point at the UCB. | 
 |   ip = (_Unwind_Ptr) ue_header; | 
 |   _Unwind_SetGR(context, UNWIND_POINTER_REG, ip); | 
 | #else | 
 |   __cxa_exception* xh = __get_exception_header_from_ue(ue_header); | 
 |  | 
 |   // Interface version check. | 
 |   if (version != 1) | 
 |     return _URC_FATAL_PHASE1_ERROR; | 
 |   foreign_exception = !__is_gxx_exception_class(exception_class); | 
 | #endif | 
 |  | 
 |   // Shortcut for phase 2 found handler for domestic exception. | 
 |   if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) | 
 |       && !foreign_exception) | 
 |     { | 
 |       restore_caught_exception(ue_header, handler_switch_value, | 
 | 			       language_specific_data, landing_pad); | 
 |       found_type = (landing_pad == 0 ? found_terminate : found_handler); | 
 |       goto install_context; | 
 |     } | 
 |  | 
 |   language_specific_data = (const unsigned char *) | 
 |     _Unwind_GetLanguageSpecificData (context); | 
 |  | 
 |   // If no LSDA, then there are no handlers or cleanups. | 
 |   if (! language_specific_data) | 
 |     CONTINUE_UNWINDING; | 
 |  | 
 |   // Parse the LSDA header. | 
 |   p = parse_lsda_header (context, language_specific_data, &info); | 
 |   info.ttype_base = base_of_encoded_value (info.ttype_encoding, context); | 
 | #ifdef _GLIBCXX_HAVE_GETIPINFO | 
 |   ip = _Unwind_GetIPInfo (context, &ip_before_insn); | 
 | #else | 
 |   ip = _Unwind_GetIP (context); | 
 | #endif | 
 |   if (! ip_before_insn) | 
 |     --ip; | 
 |   landing_pad = 0; | 
 |   action_record = 0; | 
 |   handler_switch_value = 0; | 
 |  | 
 | #ifdef __USING_SJLJ_EXCEPTIONS__ | 
 |   // The given "IP" is an index into the call-site table, with two | 
 |   // exceptions -- -1 means no-action, and 0 means terminate.  But | 
 |   // since we're using uleb128 values, we've not got random access | 
 |   // to the array. | 
 |   if ((int) ip < 0) | 
 |     return _URC_CONTINUE_UNWIND; | 
 |   else if (ip == 0) | 
 |     { | 
 |       // Fall through to set found_terminate. | 
 |     } | 
 |   else | 
 |     { | 
 |       _uleb128_t cs_lp, cs_action; | 
 |       do | 
 | 	{ | 
 | 	  p = read_uleb128 (p, &cs_lp); | 
 | 	  p = read_uleb128 (p, &cs_action); | 
 | 	} | 
 |       while (--ip); | 
 |  | 
 |       // Can never have null landing pad for sjlj -- that would have | 
 |       // been indicated by a -1 call site index. | 
 |       landing_pad = cs_lp + 1; | 
 |       if (cs_action) | 
 | 	action_record = info.action_table + cs_action - 1; | 
 |       goto found_something; | 
 |     } | 
 | #else | 
 |   // Search the call-site table for the action associated with this IP. | 
 |   while (p < info.action_table) | 
 |     { | 
 |       _Unwind_Ptr cs_start, cs_len, cs_lp; | 
 |       _uleb128_t cs_action; | 
 |  | 
 |       // Note that all call-site encodings are "absolute" displacements. | 
 |       p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); | 
 |       p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); | 
 |       p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); | 
 |       p = read_uleb128 (p, &cs_action); | 
 |  | 
 |       // The table is sorted, so if we've passed the ip, stop. | 
 |       if (ip < info.Start + cs_start) | 
 | 	p = info.action_table; | 
 |       else if (ip < info.Start + cs_start + cs_len) | 
 | 	{ | 
 | 	  if (cs_lp) | 
 | 	    landing_pad = info.LPStart + cs_lp; | 
 | 	  if (cs_action) | 
 | 	    action_record = info.action_table + cs_action - 1; | 
 | 	  goto found_something; | 
 | 	} | 
 |     } | 
 | #endif // __USING_SJLJ_EXCEPTIONS__ | 
 |  | 
 |   // If ip is not present in the table, call terminate.  This is for | 
 |   // a destructor inside a cleanup, or a library routine the compiler | 
 |   // was not expecting to throw. | 
 |   found_type = found_terminate; | 
 |   goto do_something; | 
 |  | 
 |  found_something: | 
 |   if (landing_pad == 0) | 
 |     { | 
 |       // If ip is present, and has a null landing pad, there are | 
 |       // no cleanups or handlers to be run. | 
 |       found_type = found_nothing; | 
 |     } | 
 |   else if (action_record == 0) | 
 |     { | 
 |       // If ip is present, has a non-null landing pad, and a null | 
 |       // action table offset, then there are only cleanups present. | 
 |       // Cleanups use a zero switch value, as set above. | 
 |       found_type = found_cleanup; | 
 |     } | 
 |   else | 
 |     { | 
 |       // Otherwise we have a catch handler or exception specification. | 
 |  | 
 |       _sleb128_t ar_filter, ar_disp; | 
 |       const std::type_info* catch_type; | 
 |       _throw_typet* throw_type; | 
 |       bool saw_cleanup = false; | 
 |       bool saw_handler = false; | 
 |  | 
 | #ifdef __ARM_EABI_UNWINDER__ | 
 |       // ??? How does this work - more importantly, how does it interact with | 
 |       // dependent exceptions? | 
 |       throw_type = ue_header; | 
 |       if (actions & _UA_FORCE_UNWIND) | 
 | 	{ | 
 | 	  __GXX_INIT_FORCED_UNWIND_CLASS(ue_header->exception_class); | 
 | 	} | 
 |       else if (!foreign_exception) | 
 | 	thrown_ptr = __get_object_from_ue (ue_header); | 
 | #else | 
 | #if __cpp_rtti | 
 |       // During forced unwinding, match a magic exception type. | 
 |       if (actions & _UA_FORCE_UNWIND) | 
 | 	{ | 
 | 	  throw_type = &typeid(abi::__forced_unwind); | 
 | 	} | 
 |       // With a foreign exception class, there's no exception type. | 
 |       // ??? What to do about GNU Java and GNU Ada exceptions? | 
 |       else if (foreign_exception) | 
 | 	{ | 
 | 	  throw_type = &typeid(abi::__foreign_exception); | 
 | 	} | 
 |       else | 
 | #endif | 
 |         { | 
 |           thrown_ptr = __get_object_from_ue (ue_header); | 
 |           throw_type = __get_exception_header_from_obj | 
 |             (thrown_ptr)->exceptionType; | 
 |         } | 
 | #endif | 
 |  | 
 |       while (1) | 
 | 	{ | 
 | 	  p = action_record; | 
 | 	  p = read_sleb128 (p, &ar_filter); | 
 | 	  read_sleb128 (p, &ar_disp); | 
 |  | 
 | 	  if (ar_filter == 0) | 
 | 	    { | 
 | 	      // Zero filter values are cleanups. | 
 | 	      saw_cleanup = true; | 
 | 	    } | 
 | 	  else if (actions == _UA_CLEANUP_PHASE) | 
 | 	    // We checked the handlers in the search phase; if one of them | 
 | 	    // matched, actions would also have _UA_HANDLER_FRAME set. | 
 | 	    ; | 
 | 	  else if (ar_filter > 0) | 
 | 	    { | 
 | 	      // Positive filter values are handlers. | 
 | 	      catch_type = get_ttype_entry (&info, ar_filter); | 
 |  | 
 | 	      // Null catch type is a catch-all handler; we can catch foreign | 
 | 	      // exceptions with this.  Otherwise we must match types. | 
 | 	      if (! catch_type | 
 | 		  || (throw_type | 
 | 		      && get_adjusted_ptr (catch_type, throw_type, | 
 | 					   &thrown_ptr))) | 
 | 		{ | 
 | 		  saw_handler = true; | 
 | 		  break; | 
 | 		} | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      // Negative filter values are exception specifications. | 
 | 	      // ??? How do foreign exceptions fit in?  As far as I can | 
 | 	      // see we can't match because there's no __cxa_exception | 
 | 	      // object to stuff bits in for __cxa_call_unexpected to use. | 
 | 	      // Allow them iff the exception spec is non-empty.  I.e. | 
 | 	      // a throw() specification results in __unexpected. | 
 | 	      if ((throw_type | 
 | 		   && !(actions & _UA_FORCE_UNWIND) | 
 | 		   && !foreign_exception) | 
 | 		  ? ! check_exception_spec (&info, throw_type, thrown_ptr, | 
 | 					    ar_filter) | 
 | 		  : empty_exception_spec (&info, ar_filter)) | 
 | 		{ | 
 | 		  saw_handler = true; | 
 | 		  break; | 
 | 		} | 
 | 	    } | 
 |  | 
 | 	  if (ar_disp == 0) | 
 | 	    break; | 
 | 	  action_record = p + ar_disp; | 
 | 	} | 
 |  | 
 |       if (saw_handler) | 
 | 	{ | 
 | 	  handler_switch_value = ar_filter; | 
 | 	  found_type = found_handler; | 
 | 	} | 
 |       else | 
 | 	found_type = (saw_cleanup ? found_cleanup : found_nothing); | 
 |     } | 
 |  | 
 |  do_something: | 
 |    if (found_type == found_nothing) | 
 |      CONTINUE_UNWINDING; | 
 |  | 
 |   if (actions & _UA_SEARCH_PHASE) | 
 |     { | 
 |       if (found_type == found_cleanup) | 
 | 	CONTINUE_UNWINDING; | 
 |  | 
 |       // For domestic exceptions, we cache data from phase 1 for phase 2. | 
 |       if (!foreign_exception) | 
 |         { | 
 | 	  save_caught_exception(ue_header, context, thrown_ptr, | 
 | 				handler_switch_value, language_specific_data, | 
 | 				landing_pad, action_record); | 
 | 	} | 
 |       return _URC_HANDLER_FOUND; | 
 |     } | 
 |  | 
 |  install_context: | 
 |  | 
 |   // We can't use any of the cxa routines with foreign exceptions, | 
 |   // because they all expect ue_header to be a struct __cxa_exception. | 
 |   // So in that case, call terminate or unexpected directly. | 
 |   if ((actions & _UA_FORCE_UNWIND) | 
 |       || foreign_exception) | 
 |     { | 
 |       if (found_type == found_terminate) | 
 | 	std::terminate (); | 
 |       else if (handler_switch_value < 0) | 
 | 	{ | 
 | #pragma GCC diagnostic push | 
 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | 
 | 	  __try | 
 | 	    { std::unexpected (); } | 
 | 	  __catch(...) | 
 | 	    { std::terminate (); } | 
 | #pragma GCC diagnostic pop | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       if (found_type == found_terminate) | 
 | 	__cxa_call_terminate(ue_header); | 
 |  | 
 |       // Cache the TType base value for __cxa_call_unexpected, as we won't | 
 |       // have an _Unwind_Context then. | 
 |       if (handler_switch_value < 0) | 
 | 	{ | 
 | 	  parse_lsda_header (context, language_specific_data, &info); | 
 | 	  info.ttype_base = base_of_encoded_value (info.ttype_encoding, | 
 | 						   context); | 
 |  | 
 | #ifdef __ARM_EABI_UNWINDER__ | 
 | 	  const _Unwind_Word* e; | 
 | 	  _Unwind_Word n; | 
 |  | 
 | 	  e = ((const _Unwind_Word*) info.TType) - handler_switch_value - 1; | 
 | 	  // Count the number of rtti objects. | 
 | 	  n = 0; | 
 | 	  while (e[n] != 0) | 
 | 	    n++; | 
 |  | 
 | 	  // Count. | 
 | 	  ue_header->barrier_cache.bitpattern[1] = n; | 
 | 	  // Base | 
 | 	  ue_header->barrier_cache.bitpattern[2] = info.ttype_base; | 
 | 	  // Stride. | 
 | 	  ue_header->barrier_cache.bitpattern[3] = 4; | 
 | 	  // List head. | 
 | 	  ue_header->barrier_cache.bitpattern[4] = (_Unwind_Word) e; | 
 | #else | 
 | 	  xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context); | 
 | #endif | 
 | 	} | 
 |     } | 
 |  | 
 |   /* For targets with pointers smaller than the word size, we must extend the | 
 |      pointer, and this extension is target dependent.  */ | 
 |   _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), | 
 | 		 __builtin_extend_pointer (ue_header)); | 
 |   _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), | 
 | 		 handler_switch_value); | 
 |   _Unwind_SetIP (context, landing_pad); | 
 | #ifdef __ARM_EABI_UNWINDER__ | 
 |   if (found_type == found_cleanup) | 
 |     __cxa_begin_cleanup(ue_header); | 
 | #endif | 
 |   return _URC_INSTALL_CONTEXT; | 
 | } | 
 |  | 
 | /* The ARM EABI implementation of __cxa_call_unexpected is in a | 
 |    different file so that the personality routine (PR) can be used | 
 |    standalone.  The generic routine shared datastructures with the PR | 
 |    so it is most convenient to implement it here.  */ | 
 | #ifndef __ARM_EABI_UNWINDER__ | 
 | extern "C" void | 
 | __cxa_call_unexpected (void *exc_obj_in) | 
 | { | 
 |   _Unwind_Exception *exc_obj | 
 |     = reinterpret_cast <_Unwind_Exception *>(exc_obj_in); | 
 |  | 
 |   __cxa_begin_catch (exc_obj); | 
 |  | 
 |   // This function is a handler for our exception argument.  If we exit | 
 |   // by throwing a different exception, we'll need the original cleaned up. | 
 |   struct end_catch_protect | 
 |   { | 
 |     end_catch_protect() { } | 
 |     ~end_catch_protect() { __cxa_end_catch(); } | 
 |   } end_catch_protect_obj; | 
 |  | 
 |   lsda_header_info info; | 
 |   __cxa_exception *xh = __get_exception_header_from_ue (exc_obj); | 
 |   const unsigned char *xh_lsda; | 
 |   _Unwind_Sword xh_switch_value; | 
 |   std::terminate_handler xh_terminate_handler; | 
 |  | 
 |   // If the unexpectedHandler rethrows the exception (e.g. to categorize it), | 
 |   // it will clobber data about the current handler.  So copy the data out now. | 
 |   xh_lsda = xh->languageSpecificData; | 
 |   xh_switch_value = xh->handlerSwitchValue; | 
 |   xh_terminate_handler = xh->terminateHandler; | 
 |   info.ttype_base = (_Unwind_Ptr) xh->catchTemp; | 
 |  | 
 |   __try | 
 |     { __unexpected (xh->unexpectedHandler); } | 
 |   __catch(...) | 
 |     { | 
 |       // Get the exception thrown from unexpected. | 
 |  | 
 |       __cxa_eh_globals *globals = __cxa_get_globals_fast (); | 
 |       __cxa_exception *new_xh = globals->caughtExceptions; | 
 |       void *new_ptr = __get_object_from_ambiguous_exception (new_xh); | 
 |  | 
 |       // We don't quite have enough stuff cached; re-parse the LSDA. | 
 |       parse_lsda_header (0, xh_lsda, &info); | 
 |  | 
 |       // If this new exception meets the exception spec, allow it. | 
 |       if (check_exception_spec (&info, __get_exception_header_from_obj | 
 |                                   (new_ptr)->exceptionType, | 
 | 				new_ptr, xh_switch_value)) | 
 | 	{ __throw_exception_again; } | 
 |  | 
 |       // If the exception spec allows std::bad_exception, throw that. | 
 |       // We don't have a thrown object to compare against, but since | 
 |       // bad_exception doesn't have virtual bases, that's OK; just pass 0. | 
 | #if __cpp_exceptions && __cpp_rtti | 
 |       const std::type_info &bad_exc = typeid (std::bad_exception); | 
 |       if (check_exception_spec (&info, &bad_exc, 0, xh_switch_value)) | 
 | 	throw std::bad_exception(); | 
 | #endif | 
 |  | 
 |       // Otherwise, die. | 
 |       __terminate (xh_terminate_handler); | 
 |     } | 
 | } | 
 | #endif | 
 |  | 
 | #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__) | 
 | extern "C" | 
 | EXCEPTION_DISPOSITION | 
 | __gxx_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame, | 
 | 			PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) | 
 | { | 
 |   return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context, | 
 | 				ms_disp, __gxx_personality_imp); | 
 | } | 
 | #endif /* SEH */ | 
 |  | 
 | } // namespace __cxxabiv1 |