197403Sobrien// -*- C++ -*- The GNU C++ exception personality routine. 2229551Spfg// Copyright (C) 2001, 2002, 2003, 2006, 2008 Free Software Foundation, Inc. 397403Sobrien// 4132720Skan// This file is part of GCC. 597403Sobrien// 6132720Skan// GCC is free software; you can redistribute it and/or modify 797403Sobrien// it under the terms of the GNU General Public License as published by 897403Sobrien// the Free Software Foundation; either version 2, or (at your option) 997403Sobrien// any later version. 1097403Sobrien// 11132720Skan// GCC is distributed in the hope that it will be useful, 1297403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of 1397403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1497403Sobrien// GNU General Public License for more details. 1597403Sobrien// 1697403Sobrien// You should have received a copy of the GNU General Public License 17132720Skan// along with GCC; see the file COPYING. If not, write to 18169691Skan// the Free Software Foundation, 51 Franklin Street, Fifth Floor, 19169691Skan// Boston, MA 02110-1301, USA. 2097403Sobrien 2197403Sobrien// As a special exception, you may use this file as part of a free software 2297403Sobrien// library without restriction. Specifically, if other files instantiate 2397403Sobrien// templates or use macros or inline functions from this file, or you compile 2497403Sobrien// this file and link it with other files to produce an executable, this 2597403Sobrien// file does not by itself cause the resulting executable to be covered by 2697403Sobrien// the GNU General Public License. This exception does not however 2797403Sobrien// invalidate any other reasons why the executable file might be covered by 2897403Sobrien// the GNU General Public License. 2997403Sobrien 3097403Sobrien#include <bits/c++config.h> 3197403Sobrien#include <cstdlib> 3297403Sobrien#include <exception_defines.h> 3397403Sobrien#include "unwind-cxx.h" 3497403Sobrien 3597403Sobrienusing namespace __cxxabiv1; 3697403Sobrien 37169691Skan#ifdef __ARM_EABI_UNWINDER__ 38169691Skan#define NO_SIZE_OF_ENCODED_VALUE 39169691Skan#endif 40169691Skan 4197403Sobrien#include "unwind-pe.h" 4297403Sobrien 4397403Sobrien 4497403Sobrienstruct lsda_header_info 4597403Sobrien{ 4697403Sobrien _Unwind_Ptr Start; 4797403Sobrien _Unwind_Ptr LPStart; 4897403Sobrien _Unwind_Ptr ttype_base; 4997403Sobrien const unsigned char *TType; 5097403Sobrien const unsigned char *action_table; 5197403Sobrien unsigned char ttype_encoding; 5297403Sobrien unsigned char call_site_encoding; 5397403Sobrien}; 5497403Sobrien 5597403Sobrienstatic const unsigned char * 5697403Sobrienparse_lsda_header (_Unwind_Context *context, const unsigned char *p, 5797403Sobrien lsda_header_info *info) 5897403Sobrien{ 5997403Sobrien _Unwind_Word tmp; 6097403Sobrien unsigned char lpstart_encoding; 6197403Sobrien 6297403Sobrien info->Start = (context ? _Unwind_GetRegionStart (context) : 0); 6397403Sobrien 6497403Sobrien // Find @LPStart, the base to which landing pad offsets are relative. 6597403Sobrien lpstart_encoding = *p++; 6697403Sobrien if (lpstart_encoding != DW_EH_PE_omit) 6797403Sobrien p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); 6897403Sobrien else 6997403Sobrien info->LPStart = info->Start; 7097403Sobrien 7197403Sobrien // Find @TType, the base of the handler and exception spec type data. 7297403Sobrien info->ttype_encoding = *p++; 7397403Sobrien if (info->ttype_encoding != DW_EH_PE_omit) 7497403Sobrien { 7597403Sobrien p = read_uleb128 (p, &tmp); 7697403Sobrien info->TType = p + tmp; 7797403Sobrien } 7897403Sobrien else 7997403Sobrien info->TType = 0; 8097403Sobrien 8197403Sobrien // The encoding and length of the call-site table; the action table 8297403Sobrien // immediately follows. 8397403Sobrien info->call_site_encoding = *p++; 8497403Sobrien p = read_uleb128 (p, &tmp); 8597403Sobrien info->action_table = p + tmp; 8697403Sobrien 8797403Sobrien return p; 8897403Sobrien} 8997403Sobrien 90169691Skan#ifdef __ARM_EABI_UNWINDER__ 91169691Skan 92169691Skan// Return an element from a type table. 93169691Skan 94169691Skanstatic const std::type_info* 95169691Skanget_ttype_entry(lsda_header_info* info, _Unwind_Word i) 96169691Skan{ 97169691Skan _Unwind_Ptr ptr; 98169691Skan 99169691Skan ptr = (_Unwind_Ptr) (info->TType - (i * 4)); 100169691Skan ptr = _Unwind_decode_target2(ptr); 101169691Skan 102169691Skan return reinterpret_cast<const std::type_info *>(ptr); 103169691Skan} 104169691Skan 105169691Skan// The ABI provides a routine for matching exception object types. 106169691Skantypedef _Unwind_Control_Block _throw_typet; 107169691Skan#define get_adjusted_ptr(catch_type, throw_type, thrown_ptr_p) \ 108169691Skan (__cxa_type_match (throw_type, catch_type, false, thrown_ptr_p) \ 109169691Skan != ctm_failed) 110169691Skan 111169691Skan// Return true if THROW_TYPE matches one if the filter types. 112169691Skan 113169691Skanstatic bool 114169691Skancheck_exception_spec(lsda_header_info* info, _throw_typet* throw_type, 115169691Skan void* thrown_ptr, _Unwind_Sword filter_value) 116169691Skan{ 117169691Skan const _Unwind_Word* e = ((const _Unwind_Word*) info->TType) 118169691Skan - filter_value - 1; 119169691Skan 120169691Skan while (1) 121169691Skan { 122169691Skan const std::type_info* catch_type; 123169691Skan _Unwind_Word tmp; 124169691Skan 125169691Skan tmp = *e; 126169691Skan 127169691Skan // Zero signals the end of the list. If we've not found 128169691Skan // a match by now, then we've failed the specification. 129169691Skan if (tmp == 0) 130169691Skan return false; 131169691Skan 132169691Skan tmp = _Unwind_decode_target2((_Unwind_Word) e); 133169691Skan 134169691Skan // Match a ttype entry. 135169691Skan catch_type = reinterpret_cast<const std::type_info*>(tmp); 136169691Skan 137169691Skan // ??? There is currently no way to ask the RTTI code about the 138169691Skan // relationship between two types without reference to a specific 139169691Skan // object. There should be; then we wouldn't need to mess with 140169691Skan // thrown_ptr here. 141169691Skan if (get_adjusted_ptr(catch_type, throw_type, &thrown_ptr)) 142169691Skan return true; 143169691Skan 144169691Skan // Advance to the next entry. 145169691Skan e++; 146169691Skan } 147169691Skan} 148169691Skan 149169691Skan 150169691Skan// Save stage1 handler information in the exception object 151169691Skan 152169691Skanstatic inline void 153169691Skansave_caught_exception(struct _Unwind_Exception* ue_header, 154169691Skan struct _Unwind_Context* context, 155169691Skan void* thrown_ptr, 156169691Skan int handler_switch_value, 157169691Skan const unsigned char* language_specific_data, 158169691Skan _Unwind_Ptr landing_pad, 159169691Skan const unsigned char* action_record 160169691Skan __attribute__((__unused__))) 161169691Skan{ 162169691Skan ue_header->barrier_cache.sp = _Unwind_GetGR(context, 13); 163169691Skan ue_header->barrier_cache.bitpattern[0] = (_uw) thrown_ptr; 164169691Skan ue_header->barrier_cache.bitpattern[1] 165169691Skan = (_uw) handler_switch_value; 166169691Skan ue_header->barrier_cache.bitpattern[2] 167169691Skan = (_uw) language_specific_data; 168169691Skan ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad; 169169691Skan} 170169691Skan 171169691Skan 172169691Skan// Restore the catch handler data saved during phase1. 173169691Skan 174169691Skanstatic inline void 175169691Skanrestore_caught_exception(struct _Unwind_Exception* ue_header, 176169691Skan int& handler_switch_value, 177169691Skan const unsigned char*& language_specific_data, 178169691Skan _Unwind_Ptr& landing_pad) 179169691Skan{ 180169691Skan handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1]; 181169691Skan language_specific_data = 182169691Skan (const unsigned char*) ue_header->barrier_cache.bitpattern[2]; 183169691Skan landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3]; 184169691Skan} 185169691Skan 186169691Skan#define CONTINUE_UNWINDING \ 187169691Skan do \ 188169691Skan { \ 189169691Skan if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \ 190169691Skan return _URC_FAILURE; \ 191169691Skan return _URC_CONTINUE_UNWIND; \ 192169691Skan } \ 193169691Skan while (0) 194169691Skan 195169691Skan#else 196169691Skantypedef const std::type_info _throw_typet; 197169691Skan 198169691Skan 199169691Skan// Return an element from a type table. 200169691Skan 20197403Sobrienstatic const std::type_info * 20297403Sobrienget_ttype_entry (lsda_header_info *info, _Unwind_Word i) 20397403Sobrien{ 20497403Sobrien _Unwind_Ptr ptr; 20597403Sobrien 20697403Sobrien i *= size_of_encoded_value (info->ttype_encoding); 20797403Sobrien read_encoded_value_with_base (info->ttype_encoding, info->ttype_base, 20897403Sobrien info->TType - i, &ptr); 20997403Sobrien 21097403Sobrien return reinterpret_cast<const std::type_info *>(ptr); 21197403Sobrien} 21297403Sobrien 21397403Sobrien// Given the thrown type THROW_TYPE, pointer to a variable containing a 21497403Sobrien// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to 21597403Sobrien// compare against, return whether or not there is a match and if so, 21697403Sobrien// update *THROWN_PTR_P. 21797403Sobrien 21897403Sobrienstatic bool 21997403Sobrienget_adjusted_ptr (const std::type_info *catch_type, 22097403Sobrien const std::type_info *throw_type, 22197403Sobrien void **thrown_ptr_p) 22297403Sobrien{ 22397403Sobrien void *thrown_ptr = *thrown_ptr_p; 22497403Sobrien 22597403Sobrien // Pointer types need to adjust the actual pointer, not 22697403Sobrien // the pointer to pointer that is the exception object. 22797403Sobrien // This also has the effect of passing pointer types 22897403Sobrien // "by value" through the __cxa_begin_catch return value. 22997403Sobrien if (throw_type->__is_pointer_p ()) 23097403Sobrien thrown_ptr = *(void **) thrown_ptr; 23197403Sobrien 23297403Sobrien if (catch_type->__do_catch (throw_type, &thrown_ptr, 1)) 23397403Sobrien { 23497403Sobrien *thrown_ptr_p = thrown_ptr; 23597403Sobrien return true; 23697403Sobrien } 23797403Sobrien 23897403Sobrien return false; 23997403Sobrien} 24097403Sobrien 241117397Skan// Return true if THROW_TYPE matches one if the filter types. 242117397Skan 24397403Sobrienstatic bool 244169691Skancheck_exception_spec(lsda_header_info* info, _throw_typet* throw_type, 245169691Skan void* thrown_ptr, _Unwind_Sword filter_value) 24697403Sobrien{ 24797403Sobrien const unsigned char *e = info->TType - filter_value - 1; 24897403Sobrien 24997403Sobrien while (1) 25097403Sobrien { 25197403Sobrien const std::type_info *catch_type; 25297403Sobrien _Unwind_Word tmp; 25397403Sobrien 25497403Sobrien e = read_uleb128 (e, &tmp); 25597403Sobrien 25697403Sobrien // Zero signals the end of the list. If we've not found 25797403Sobrien // a match by now, then we've failed the specification. 25897403Sobrien if (tmp == 0) 25997403Sobrien return false; 26097403Sobrien 26197403Sobrien // Match a ttype entry. 26297403Sobrien catch_type = get_ttype_entry (info, tmp); 26397403Sobrien 26497403Sobrien // ??? There is currently no way to ask the RTTI code about the 26597403Sobrien // relationship between two types without reference to a specific 26697403Sobrien // object. There should be; then we wouldn't need to mess with 26797403Sobrien // thrown_ptr here. 26897403Sobrien if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr)) 26997403Sobrien return true; 27097403Sobrien } 27197403Sobrien} 27297403Sobrien 273169691Skan 274169691Skan// Save stage1 handler information in the exception object 275169691Skan 276169691Skanstatic inline void 277169691Skansave_caught_exception(struct _Unwind_Exception* ue_header, 278169691Skan struct _Unwind_Context* context 279169691Skan __attribute__((__unused__)), 280169691Skan void* thrown_ptr, 281169691Skan int handler_switch_value, 282169691Skan const unsigned char* language_specific_data, 283169691Skan _Unwind_Ptr landing_pad __attribute__((__unused__)), 284169691Skan const unsigned char* action_record) 285169691Skan{ 286169691Skan __cxa_exception* xh = __get_exception_header_from_ue(ue_header); 287169691Skan 288169691Skan xh->handlerSwitchValue = handler_switch_value; 289169691Skan xh->actionRecord = action_record; 290169691Skan xh->languageSpecificData = language_specific_data; 291169691Skan xh->adjustedPtr = thrown_ptr; 292169691Skan 293169691Skan // ??? Completely unknown what this field is supposed to be for. 294169691Skan // ??? Need to cache TType encoding base for call_unexpected. 295169691Skan xh->catchTemp = landing_pad; 296169691Skan} 297169691Skan 298169691Skan 299169691Skan// Restore the catch handler information saved during phase1. 300169691Skan 301169691Skanstatic inline void 302169691Skanrestore_caught_exception(struct _Unwind_Exception* ue_header, 303169691Skan int& handler_switch_value, 304169691Skan const unsigned char*& language_specific_data, 305169691Skan _Unwind_Ptr& landing_pad) 306169691Skan{ 307169691Skan __cxa_exception* xh = __get_exception_header_from_ue(ue_header); 308169691Skan handler_switch_value = xh->handlerSwitchValue; 309169691Skan language_specific_data = xh->languageSpecificData; 310169691Skan landing_pad = (_Unwind_Ptr) xh->catchTemp; 311169691Skan} 312169691Skan 313169691Skan#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND 314169691Skan 315169691Skan#endif // !__ARM_EABI_UNWINDER__ 316169691Skan 317117397Skan// Return true if the filter spec is empty, ie throw(). 318117397Skan 319117397Skanstatic bool 320117397Skanempty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value) 321117397Skan{ 322117397Skan const unsigned char *e = info->TType - filter_value - 1; 323117397Skan _Unwind_Word tmp; 324117397Skan 325117397Skan e = read_uleb128 (e, &tmp); 326117397Skan return tmp == 0; 327117397Skan} 328117397Skan 329169691Skannamespace __cxxabiv1 330169691Skan{ 331169691Skan 33297403Sobrien// Using a different personality function name causes link failures 33397403Sobrien// when trying to mix code using different exception handling models. 334132720Skan#ifdef _GLIBCXX_SJLJ_EXCEPTIONS 33597403Sobrien#define PERSONALITY_FUNCTION __gxx_personality_sj0 33697403Sobrien#define __builtin_eh_return_data_regno(x) x 33797403Sobrien#else 33897403Sobrien#define PERSONALITY_FUNCTION __gxx_personality_v0 33997403Sobrien#endif 34097403Sobrien 34197403Sobrienextern "C" _Unwind_Reason_Code 342169691Skan#ifdef __ARM_EABI_UNWINDER__ 343169691SkanPERSONALITY_FUNCTION (_Unwind_State state, 344169691Skan struct _Unwind_Exception* ue_header, 345169691Skan struct _Unwind_Context* context) 346169691Skan#else 34797403SobrienPERSONALITY_FUNCTION (int version, 34897403Sobrien _Unwind_Action actions, 34997403Sobrien _Unwind_Exception_Class exception_class, 35097403Sobrien struct _Unwind_Exception *ue_header, 35197403Sobrien struct _Unwind_Context *context) 352169691Skan#endif 35397403Sobrien{ 35497403Sobrien enum found_handler_type 35597403Sobrien { 35697403Sobrien found_nothing, 35797403Sobrien found_terminate, 35897403Sobrien found_cleanup, 35997403Sobrien found_handler 36097403Sobrien } found_type; 36197403Sobrien 36297403Sobrien lsda_header_info info; 36397403Sobrien const unsigned char *language_specific_data; 36497403Sobrien const unsigned char *action_record; 36597403Sobrien const unsigned char *p; 36697403Sobrien _Unwind_Ptr landing_pad, ip; 36797403Sobrien int handler_switch_value; 368169691Skan void* thrown_ptr = ue_header + 1; 369169691Skan bool foreign_exception; 370169691Skan int ip_before_insn = 0; 37197403Sobrien 372169691Skan#ifdef __ARM_EABI_UNWINDER__ 373169691Skan _Unwind_Action actions; 374169691Skan 375169691Skan switch (state & _US_ACTION_MASK) 376169691Skan { 377169691Skan case _US_VIRTUAL_UNWIND_FRAME: 378169691Skan actions = _UA_SEARCH_PHASE; 379169691Skan break; 380169691Skan 381169691Skan case _US_UNWIND_FRAME_STARTING: 382169691Skan actions = _UA_CLEANUP_PHASE; 383169691Skan if (!(state & _US_FORCE_UNWIND) 384169691Skan && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13)) 385169691Skan actions |= _UA_HANDLER_FRAME; 386169691Skan break; 387169691Skan 388169691Skan case _US_UNWIND_FRAME_RESUME: 389169691Skan CONTINUE_UNWINDING; 390169691Skan break; 391169691Skan 392169691Skan default: 393169691Skan std::abort(); 394169691Skan } 395169691Skan actions |= state & _US_FORCE_UNWIND; 396169691Skan 397169691Skan // We don't know which runtime we're working with, so can't check this. 398169691Skan // However the ABI routines hide this from us, and we don't actually need 399169691Skan // to know. 400169691Skan foreign_exception = false; 401169691Skan 402169691Skan // The dwarf unwinder assumes the context structure holds things like the 403169691Skan // function and LSDA pointers. The ARM implementation caches these in 404169691Skan // the exception header (UCB). To avoid rewriting everything we make the 405169691Skan // virtual IP register point at the UCB. 406169691Skan ip = (_Unwind_Ptr) ue_header; 407169691Skan _Unwind_SetGR(context, 12, ip); 408169691Skan#else 409169691Skan __cxa_exception* xh = __get_exception_header_from_ue(ue_header); 410169691Skan 41197403Sobrien // Interface version check. 41297403Sobrien if (version != 1) 41397403Sobrien return _URC_FATAL_PHASE1_ERROR; 414169691Skan foreign_exception = !__is_gxx_exception_class(exception_class); 415169691Skan#endif 41697403Sobrien 41797403Sobrien // Shortcut for phase 2 found handler for domestic exception. 41897403Sobrien if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) 419169691Skan && !foreign_exception) 42097403Sobrien { 421169691Skan restore_caught_exception(ue_header, handler_switch_value, 422169691Skan language_specific_data, landing_pad); 42397403Sobrien found_type = (landing_pad == 0 ? found_terminate : found_handler); 42497403Sobrien goto install_context; 42597403Sobrien } 42697403Sobrien 42797403Sobrien language_specific_data = (const unsigned char *) 42897403Sobrien _Unwind_GetLanguageSpecificData (context); 42997403Sobrien 43097403Sobrien // If no LSDA, then there are no handlers or cleanups. 43197403Sobrien if (! language_specific_data) 432169691Skan CONTINUE_UNWINDING; 43397403Sobrien 43497403Sobrien // Parse the LSDA header. 43597403Sobrien p = parse_lsda_header (context, language_specific_data, &info); 43697403Sobrien info.ttype_base = base_of_encoded_value (info.ttype_encoding, context); 437229551Spfg#ifdef _GLIBCXX_HAVE_GETIPINFO 438169691Skan ip = _Unwind_GetIPInfo (context, &ip_before_insn); 439169691Skan#else 440169691Skan ip = _Unwind_GetIP (context); 441169691Skan#endif 442169691Skan if (! ip_before_insn) 443169691Skan --ip; 44497403Sobrien landing_pad = 0; 44597403Sobrien action_record = 0; 44697403Sobrien handler_switch_value = 0; 44797403Sobrien 448132720Skan#ifdef _GLIBCXX_SJLJ_EXCEPTIONS 44997403Sobrien // The given "IP" is an index into the call-site table, with two 45097403Sobrien // exceptions -- -1 means no-action, and 0 means terminate. But 45197403Sobrien // since we're using uleb128 values, we've not got random access 45297403Sobrien // to the array. 45397403Sobrien if ((int) ip < 0) 45497403Sobrien return _URC_CONTINUE_UNWIND; 45597403Sobrien else if (ip == 0) 45697403Sobrien { 45797403Sobrien // Fall through to set found_terminate. 45897403Sobrien } 45997403Sobrien else 46097403Sobrien { 46197403Sobrien _Unwind_Word cs_lp, cs_action; 46297403Sobrien do 46397403Sobrien { 46497403Sobrien p = read_uleb128 (p, &cs_lp); 46597403Sobrien p = read_uleb128 (p, &cs_action); 46697403Sobrien } 46797403Sobrien while (--ip); 46897403Sobrien 46997403Sobrien // Can never have null landing pad for sjlj -- that would have 47097403Sobrien // been indicated by a -1 call site index. 47197403Sobrien landing_pad = cs_lp + 1; 47297403Sobrien if (cs_action) 47397403Sobrien action_record = info.action_table + cs_action - 1; 47497403Sobrien goto found_something; 47597403Sobrien } 47697403Sobrien#else 47797403Sobrien // Search the call-site table for the action associated with this IP. 47897403Sobrien while (p < info.action_table) 47997403Sobrien { 48097403Sobrien _Unwind_Ptr cs_start, cs_len, cs_lp; 48197403Sobrien _Unwind_Word cs_action; 48297403Sobrien 48397403Sobrien // Note that all call-site encodings are "absolute" displacements. 48497403Sobrien p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); 48597403Sobrien p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); 48697403Sobrien p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); 48797403Sobrien p = read_uleb128 (p, &cs_action); 48897403Sobrien 48997403Sobrien // The table is sorted, so if we've passed the ip, stop. 49097403Sobrien if (ip < info.Start + cs_start) 49197403Sobrien p = info.action_table; 49297403Sobrien else if (ip < info.Start + cs_start + cs_len) 49397403Sobrien { 49497403Sobrien if (cs_lp) 49597403Sobrien landing_pad = info.LPStart + cs_lp; 49697403Sobrien if (cs_action) 49797403Sobrien action_record = info.action_table + cs_action - 1; 49897403Sobrien goto found_something; 49997403Sobrien } 50097403Sobrien } 501132720Skan#endif // _GLIBCXX_SJLJ_EXCEPTIONS 50297403Sobrien 50397403Sobrien // If ip is not present in the table, call terminate. This is for 50497403Sobrien // a destructor inside a cleanup, or a library routine the compiler 50597403Sobrien // was not expecting to throw. 506117397Skan found_type = found_terminate; 50797403Sobrien goto do_something; 50897403Sobrien 50997403Sobrien found_something: 51097403Sobrien if (landing_pad == 0) 51197403Sobrien { 51297403Sobrien // If ip is present, and has a null landing pad, there are 51397403Sobrien // no cleanups or handlers to be run. 51497403Sobrien found_type = found_nothing; 51597403Sobrien } 51697403Sobrien else if (action_record == 0) 51797403Sobrien { 51897403Sobrien // If ip is present, has a non-null landing pad, and a null 51997403Sobrien // action table offset, then there are only cleanups present. 52097403Sobrien // Cleanups use a zero switch value, as set above. 52197403Sobrien found_type = found_cleanup; 52297403Sobrien } 52397403Sobrien else 52497403Sobrien { 52597403Sobrien // Otherwise we have a catch handler or exception specification. 52697403Sobrien 52797403Sobrien _Unwind_Sword ar_filter, ar_disp; 528169691Skan const std::type_info* catch_type; 529169691Skan _throw_typet* throw_type; 53097403Sobrien bool saw_cleanup = false; 53197403Sobrien bool saw_handler = false; 53297403Sobrien 53397403Sobrien // During forced unwinding, we only run cleanups. With a foreign 53497403Sobrien // exception class, there's no exception type. 53597403Sobrien // ??? What to do about GNU Java and GNU Ada exceptions. 53697403Sobrien 53797403Sobrien if ((actions & _UA_FORCE_UNWIND) 538169691Skan || foreign_exception) 53997403Sobrien throw_type = 0; 54097403Sobrien else 541169691Skan#ifdef __ARM_EABI_UNWINDER__ 542169691Skan throw_type = ue_header; 543169691Skan#else 54497403Sobrien throw_type = xh->exceptionType; 545169691Skan#endif 54697403Sobrien 54797403Sobrien while (1) 54897403Sobrien { 54997403Sobrien p = action_record; 55097403Sobrien p = read_sleb128 (p, &ar_filter); 55197403Sobrien read_sleb128 (p, &ar_disp); 55297403Sobrien 55397403Sobrien if (ar_filter == 0) 55497403Sobrien { 55597403Sobrien // Zero filter values are cleanups. 55697403Sobrien saw_cleanup = true; 55797403Sobrien } 55897403Sobrien else if (ar_filter > 0) 55997403Sobrien { 56097403Sobrien // Positive filter values are handlers. 56197403Sobrien catch_type = get_ttype_entry (&info, ar_filter); 56297403Sobrien 563117397Skan // Null catch type is a catch-all handler; we can catch foreign 564117397Skan // exceptions with this. Otherwise we must match types. 565117397Skan if (! catch_type 566117397Skan || (throw_type 567117397Skan && get_adjusted_ptr (catch_type, throw_type, 568117397Skan &thrown_ptr))) 56997403Sobrien { 570117397Skan saw_handler = true; 571117397Skan break; 57297403Sobrien } 57397403Sobrien } 57497403Sobrien else 57597403Sobrien { 57697403Sobrien // Negative filter values are exception specifications. 57797403Sobrien // ??? How do foreign exceptions fit in? As far as I can 57897403Sobrien // see we can't match because there's no __cxa_exception 57997403Sobrien // object to stuff bits in for __cxa_call_unexpected to use. 580117397Skan // Allow them iff the exception spec is non-empty. I.e. 581117397Skan // a throw() specification results in __unexpected. 58297403Sobrien if (throw_type 583117397Skan ? ! check_exception_spec (&info, throw_type, thrown_ptr, 584117397Skan ar_filter) 585117397Skan : empty_exception_spec (&info, ar_filter)) 58697403Sobrien { 58797403Sobrien saw_handler = true; 58897403Sobrien break; 58997403Sobrien } 59097403Sobrien } 59197403Sobrien 59297403Sobrien if (ar_disp == 0) 59397403Sobrien break; 59497403Sobrien action_record = p + ar_disp; 59597403Sobrien } 59697403Sobrien 59797403Sobrien if (saw_handler) 59897403Sobrien { 59997403Sobrien handler_switch_value = ar_filter; 60097403Sobrien found_type = found_handler; 60197403Sobrien } 60297403Sobrien else 60397403Sobrien found_type = (saw_cleanup ? found_cleanup : found_nothing); 60497403Sobrien } 60597403Sobrien 60697403Sobrien do_something: 60797403Sobrien if (found_type == found_nothing) 608169691Skan CONTINUE_UNWINDING; 60997403Sobrien 61097403Sobrien if (actions & _UA_SEARCH_PHASE) 61197403Sobrien { 61297403Sobrien if (found_type == found_cleanup) 613169691Skan CONTINUE_UNWINDING; 61497403Sobrien 61597403Sobrien // For domestic exceptions, we cache data from phase 1 for phase 2. 616169691Skan if (!foreign_exception) 61797403Sobrien { 618169691Skan save_caught_exception(ue_header, context, thrown_ptr, 619169691Skan handler_switch_value, language_specific_data, 620169691Skan landing_pad, action_record); 62197403Sobrien } 62297403Sobrien return _URC_HANDLER_FOUND; 62397403Sobrien } 62497403Sobrien 62597403Sobrien install_context: 626169691Skan 627117397Skan // We can't use any of the cxa routines with foreign exceptions, 628117397Skan // because they all expect ue_header to be a struct __cxa_exception. 629117397Skan // So in that case, call terminate or unexpected directly. 630117397Skan if ((actions & _UA_FORCE_UNWIND) 631169691Skan || foreign_exception) 63297403Sobrien { 633117397Skan if (found_type == found_terminate) 634117397Skan std::terminate (); 635117397Skan else if (handler_switch_value < 0) 636117397Skan { 637117397Skan try 638117397Skan { std::unexpected (); } 639117397Skan catch(...) 640117397Skan { std::terminate (); } 641117397Skan } 64297403Sobrien } 643117397Skan else 644117397Skan { 645117397Skan if (found_type == found_terminate) 646169691Skan __cxa_call_terminate(ue_header); 64797403Sobrien 648117397Skan // Cache the TType base value for __cxa_call_unexpected, as we won't 649117397Skan // have an _Unwind_Context then. 650117397Skan if (handler_switch_value < 0) 651117397Skan { 652117397Skan parse_lsda_header (context, language_specific_data, &info); 653169691Skan 654169691Skan#ifdef __ARM_EABI_UNWINDER__ 655169691Skan const _Unwind_Word* e; 656169691Skan _Unwind_Word n; 657169691Skan 658169691Skan e = ((const _Unwind_Word*) info.TType) - handler_switch_value - 1; 659169691Skan // Count the number of rtti objects. 660169691Skan n = 0; 661169691Skan while (e[n] != 0) 662169691Skan n++; 663169691Skan 664169691Skan // Count. 665169691Skan ue_header->barrier_cache.bitpattern[1] = n; 666169691Skan // Base (obsolete) 667169691Skan ue_header->barrier_cache.bitpattern[2] = 0; 668169691Skan // Stride. 669169691Skan ue_header->barrier_cache.bitpattern[3] = 4; 670169691Skan // List head. 671169691Skan ue_header->barrier_cache.bitpattern[4] = (_Unwind_Word) e; 672169691Skan#else 673117397Skan xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context); 674169691Skan#endif 675117397Skan } 67697403Sobrien } 67797403Sobrien 678132720Skan /* For targets with pointers smaller than the word size, we must extend the 679132720Skan pointer, and this extension is target dependent. */ 68097403Sobrien _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), 681169691Skan __builtin_extend_pointer (ue_header)); 68297403Sobrien _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 68397403Sobrien handler_switch_value); 68497403Sobrien _Unwind_SetIP (context, landing_pad); 685169691Skan#ifdef __ARM_EABI_UNWINDER__ 686169691Skan if (found_type == found_cleanup) 687169691Skan __cxa_begin_cleanup(ue_header); 688169691Skan#endif 68997403Sobrien return _URC_INSTALL_CONTEXT; 69097403Sobrien} 69197403Sobrien 692169691Skan/* The ARM EABI implementation of __cxa_call_unexpected is in a 693169691Skan different file so that the personality routine (PR) can be used 694169691Skan standalone. The generic routine shared datastructures with the PR 695169691Skan so it is most convenient to implement it here. */ 696169691Skan#ifndef __ARM_EABI_UNWINDER__ 69797403Sobrienextern "C" void 69897403Sobrien__cxa_call_unexpected (void *exc_obj_in) 69997403Sobrien{ 70097403Sobrien _Unwind_Exception *exc_obj 70197403Sobrien = reinterpret_cast <_Unwind_Exception *>(exc_obj_in); 70297403Sobrien 70397403Sobrien __cxa_begin_catch (exc_obj); 70497403Sobrien 70597403Sobrien // This function is a handler for our exception argument. If we exit 70697403Sobrien // by throwing a different exception, we'll need the original cleaned up. 70797403Sobrien struct end_catch_protect 70897403Sobrien { 70997403Sobrien end_catch_protect() { } 71097403Sobrien ~end_catch_protect() { __cxa_end_catch(); } 71197403Sobrien } end_catch_protect_obj; 71297403Sobrien 71397403Sobrien lsda_header_info info; 71497403Sobrien __cxa_exception *xh = __get_exception_header_from_ue (exc_obj); 71597403Sobrien const unsigned char *xh_lsda; 71697403Sobrien _Unwind_Sword xh_switch_value; 71797403Sobrien std::terminate_handler xh_terminate_handler; 71897403Sobrien 71997403Sobrien // If the unexpectedHandler rethrows the exception (e.g. to categorize it), 72097403Sobrien // it will clobber data about the current handler. So copy the data out now. 72197403Sobrien xh_lsda = xh->languageSpecificData; 72297403Sobrien xh_switch_value = xh->handlerSwitchValue; 72397403Sobrien xh_terminate_handler = xh->terminateHandler; 72497403Sobrien info.ttype_base = (_Unwind_Ptr) xh->catchTemp; 72597403Sobrien 72697403Sobrien try 72797403Sobrien { __unexpected (xh->unexpectedHandler); } 72897403Sobrien catch(...) 72997403Sobrien { 73097403Sobrien // Get the exception thrown from unexpected. 731117397Skan 73297403Sobrien __cxa_eh_globals *globals = __cxa_get_globals_fast (); 73397403Sobrien __cxa_exception *new_xh = globals->caughtExceptions; 73497403Sobrien void *new_ptr = new_xh + 1; 735117397Skan 73697403Sobrien // We don't quite have enough stuff cached; re-parse the LSDA. 73797403Sobrien parse_lsda_header (0, xh_lsda, &info); 738117397Skan 73997403Sobrien // If this new exception meets the exception spec, allow it. 74097403Sobrien if (check_exception_spec (&info, new_xh->exceptionType, 74197403Sobrien new_ptr, xh_switch_value)) 74297403Sobrien __throw_exception_again; 743117397Skan 74497403Sobrien // If the exception spec allows std::bad_exception, throw that. 74597403Sobrien // We don't have a thrown object to compare against, but since 74697403Sobrien // bad_exception doesn't have virtual bases, that's OK; just pass 0. 74797403Sobrien#ifdef __EXCEPTIONS 74897403Sobrien const std::type_info &bad_exc = typeid (std::bad_exception); 74997403Sobrien if (check_exception_spec (&info, &bad_exc, 0, xh_switch_value)) 75097403Sobrien throw std::bad_exception(); 75197403Sobrien#endif 752117397Skan 75397403Sobrien // Otherwise, die. 75497403Sobrien __terminate (xh_terminate_handler); 75597403Sobrien } 75697403Sobrien} 757169691Skan#endif 758169691Skan 759169691Skan} // namespace __cxxabiv1 760