|  | // -*- C++ -*- The GNU C++ exception personality routine. | 
|  | // Copyright (C) 2001-2022 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 nake 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 (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 |