198524Sfenner// -*- C++ -*- The GNU C++ exception personality routine. 298524Sfenner// Copyright (C) 2001, 2002, 2003, 2006, 2008 Free Software Foundation, Inc. 398524Sfenner// 498524Sfenner// This file is part of GCC. 598524Sfenner// 698524Sfenner// GCC is free software; you can redistribute it and/or modify 798524Sfenner// it under the terms of the GNU General Public License as published by 898524Sfenner// the Free Software Foundation; either version 2, or (at your option) 998524Sfenner// any later version. 1098524Sfenner// 1198524Sfenner// GCC is distributed in the hope that it will be useful, 1298524Sfenner// but WITHOUT ANY WARRANTY; without even the implied warranty of 1398524Sfenner// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1498524Sfenner// GNU General Public License for more details. 1598524Sfenner// 1698524Sfenner// You should have received a copy of the GNU General Public License 1798524Sfenner// along with GCC; see the file COPYING. If not, write to 1898524Sfenner// the Free Software Foundation, 51 Franklin Street, Fifth Floor, 1998524Sfenner// Boston, MA 02110-1301, USA. 2098524Sfenner 2198524Sfenner// As a special exception, you may use this file as part of a free software 2298524Sfenner// library without restriction. Specifically, if other files instantiate 2398524Sfenner// templates or use macros or inline functions from this file, or you compile 2498524Sfenner// this file and link it with other files to produce an executable, this 2598524Sfenner// file does not by itself cause the resulting executable to be covered by 26127668Sbms// the GNU General Public License. This exception does not however 27190207Srpaulo// invalidate any other reasons why the executable file might be covered by 2898524Sfenner// the GNU General Public License. 2998524Sfenner 3098524Sfenner#include <bits/c++config.h> 3198524Sfenner#include <cstdlib> 3298524Sfenner#include <exception_defines.h> 3398524Sfenner#include "unwind-cxx.h" 34127668Sbms 35127668Sbmsusing namespace __cxxabiv1; 3698524Sfenner 3798524Sfenner#ifdef __ARM_EABI_UNWINDER__ 3898524Sfenner#define NO_SIZE_OF_ENCODED_VALUE 39127668Sbms#endif 4098524Sfenner 4198524Sfenner#include "unwind-pe.h" 4298524Sfenner 4398524Sfenner 4498524Sfennerstruct lsda_header_info 4598524Sfenner{ 4698524Sfenner _Unwind_Ptr Start; 4798524Sfenner _Unwind_Ptr LPStart; 4898524Sfenner _Unwind_Ptr ttype_base; 49127668Sbms const unsigned char *TType; 5098524Sfenner const unsigned char *action_table; 5198524Sfenner unsigned char ttype_encoding; 5298524Sfenner unsigned char call_site_encoding; 5398524Sfenner}; 5498524Sfenner 5598524Sfennerstatic const unsigned char * 5698524Sfennerparse_lsda_header (_Unwind_Context *context, const unsigned char *p, 5798524Sfenner lsda_header_info *info) 5898524Sfenner{ 5998524Sfenner _Unwind_Word tmp; 6098524Sfenner unsigned char lpstart_encoding; 6198524Sfenner 6298524Sfenner info->Start = (context ? _Unwind_GetRegionStart (context) : 0); 6398524Sfenner 6498524Sfenner // Find @LPStart, the base to which landing pad offsets are relative. 6598524Sfenner lpstart_encoding = *p++; 6698524Sfenner if (lpstart_encoding != DW_EH_PE_omit) 6798524Sfenner p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); 6898524Sfenner else 69127668Sbms info->LPStart = info->Start; 7098524Sfenner 7198524Sfenner // Find @TType, the base of the handler and exception spec type data. 7298524Sfenner info->ttype_encoding = *p++; 7398524Sfenner if (info->ttype_encoding != DW_EH_PE_omit) 7498524Sfenner { 7598524Sfenner p = read_uleb128 (p, &tmp); 7698524Sfenner info->TType = p + tmp; 7798524Sfenner } 7898524Sfenner else 7998524Sfenner info->TType = 0; 8098524Sfenner 8198524Sfenner // The encoding and length of the call-site table; the action table 8298524Sfenner // immediately follows. 8398524Sfenner info->call_site_encoding = *p++; 8498524Sfenner p = read_uleb128 (p, &tmp); 8598524Sfenner info->action_table = p + tmp; 8698524Sfenner 8798524Sfenner return p; 8898524Sfenner} 8998524Sfenner 9098524Sfenner#ifdef __ARM_EABI_UNWINDER__ 9198524Sfenner 9298524Sfenner// Return an element from a type table. 9398524Sfenner 9498524Sfennerstatic const std::type_info* 9598524Sfennerget_ttype_entry(lsda_header_info* info, _Unwind_Word i) 9698524Sfenner{ 9798524Sfenner _Unwind_Ptr ptr; 9898524Sfenner 9998524Sfenner ptr = (_Unwind_Ptr) (info->TType - (i * 4)); 10098524Sfenner ptr = _Unwind_decode_target2(ptr); 10198524Sfenner 10298524Sfenner return reinterpret_cast<const std::type_info *>(ptr); 10398524Sfenner} 10498524Sfenner 10598524Sfenner// The ABI provides a routine for matching exception object types. 10698524Sfennertypedef _Unwind_Control_Block _throw_typet; 10798524Sfenner#define get_adjusted_ptr(catch_type, throw_type, thrown_ptr_p) \ 10898524Sfenner (__cxa_type_match (throw_type, catch_type, false, thrown_ptr_p) \ 10998524Sfenner != ctm_failed) 11098524Sfenner 11198524Sfenner// Return true if THROW_TYPE matches one if the filter types. 11298524Sfenner 11398524Sfennerstatic bool 11498524Sfennercheck_exception_spec(lsda_header_info* info, _throw_typet* throw_type, 11598524Sfenner void* thrown_ptr, _Unwind_Sword filter_value) 11698524Sfenner{ 11798524Sfenner const _Unwind_Word* e = ((const _Unwind_Word*) info->TType) 11898524Sfenner - filter_value - 1; 11998524Sfenner 12098524Sfenner while (1) 12198524Sfenner { 12298524Sfenner const std::type_info* catch_type; 12398524Sfenner _Unwind_Word tmp; 12498524Sfenner 12598524Sfenner tmp = *e; 12698524Sfenner 12798524Sfenner // Zero signals the end of the list. If we've not found 12898524Sfenner // a match by now, then we've failed the specification. 12998524Sfenner if (tmp == 0) 13098524Sfenner return false; 13198524Sfenner 13298524Sfenner tmp = _Unwind_decode_target2((_Unwind_Word) e); 13398524Sfenner 13498524Sfenner // Match a ttype entry. 13598524Sfenner catch_type = reinterpret_cast<const std::type_info*>(tmp); 13698524Sfenner 13798524Sfenner // ??? There is currently no way to ask the RTTI code about the 13898524Sfenner // relationship between two types without reference to a specific 13998524Sfenner // object. There should be; then we wouldn't need to mess with 14098524Sfenner // thrown_ptr here. 14198524Sfenner if (get_adjusted_ptr(catch_type, throw_type, &thrown_ptr)) 14298524Sfenner return true; 14398524Sfenner 14498524Sfenner // Advance to the next entry. 14598524Sfenner e++; 14698524Sfenner } 14798524Sfenner} 14898524Sfenner 14998524Sfenner 15098524Sfenner// Save stage1 handler information in the exception object 15198524Sfenner 15298524Sfennerstatic inline void 15398524Sfennersave_caught_exception(struct _Unwind_Exception* ue_header, 15498524Sfenner struct _Unwind_Context* context, 15598524Sfenner void* thrown_ptr, 15698524Sfenner int handler_switch_value, 15798524Sfenner const unsigned char* language_specific_data, 15898524Sfenner _Unwind_Ptr landing_pad, 15998524Sfenner const unsigned char* action_record 16098524Sfenner __attribute__((__unused__))) 16198524Sfenner{ 16298524Sfenner ue_header->barrier_cache.sp = _Unwind_GetGR(context, 13); 16398524Sfenner ue_header->barrier_cache.bitpattern[0] = (_uw) thrown_ptr; 16498524Sfenner ue_header->barrier_cache.bitpattern[1] 16598524Sfenner = (_uw) handler_switch_value; 16698524Sfenner ue_header->barrier_cache.bitpattern[2] 16798524Sfenner = (_uw) language_specific_data; 16898524Sfenner ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad; 16998524Sfenner} 17098524Sfenner 17198524Sfenner 17298524Sfenner// Restore the catch handler data saved during phase1. 17398524Sfenner 17498524Sfennerstatic inline void 17598524Sfennerrestore_caught_exception(struct _Unwind_Exception* ue_header, 17698524Sfenner int& handler_switch_value, 17798524Sfenner const unsigned char*& language_specific_data, 17898524Sfenner _Unwind_Ptr& landing_pad) 179127668Sbms{ 180127668Sbms handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1]; 18198524Sfenner language_specific_data = 18298524Sfenner (const unsigned char*) ue_header->barrier_cache.bitpattern[2]; 18398524Sfenner landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3]; 18498524Sfenner} 18598524Sfenner 18698524Sfenner#define CONTINUE_UNWINDING \ 18798524Sfenner do \ 18898524Sfenner { \ 18998524Sfenner if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \ 19098524Sfenner return _URC_FAILURE; \ 19198524Sfenner return _URC_CONTINUE_UNWIND; \ 19298524Sfenner } \ 19398524Sfenner while (0) 19498524Sfenner 19598524Sfenner#else 19698524Sfennertypedef const std::type_info _throw_typet; 19798524Sfenner 19898524Sfenner 19998524Sfenner// Return an element from a type table. 20098524Sfenner 20198524Sfennerstatic const std::type_info * 20298524Sfennerget_ttype_entry (lsda_header_info *info, _Unwind_Word i) 20398524Sfenner{ 20498524Sfenner _Unwind_Ptr ptr; 20598524Sfenner 20698524Sfenner i *= size_of_encoded_value (info->ttype_encoding); 20798524Sfenner read_encoded_value_with_base (info->ttype_encoding, info->ttype_base, 20898524Sfenner info->TType - i, &ptr); 20998524Sfenner 21098524Sfenner return reinterpret_cast<const std::type_info *>(ptr); 21198524Sfenner} 21298524Sfenner 21398524Sfenner// Given the thrown type THROW_TYPE, pointer to a variable containing a 21498524Sfenner// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to 21598524Sfenner// compare against, return whether or not there is a match and if so, 21698524Sfenner// update *THROWN_PTR_P. 21798524Sfenner 21898524Sfennerstatic bool 21998524Sfennerget_adjusted_ptr (const std::type_info *catch_type, 22098524Sfenner const std::type_info *throw_type, 22198524Sfenner void **thrown_ptr_p) 22298524Sfenner{ 22398524Sfenner void *thrown_ptr = *thrown_ptr_p; 22498524Sfenner 22598524Sfenner // Pointer types need to adjust the actual pointer, not 22698524Sfenner // the pointer to pointer that is the exception object. 22798524Sfenner // This also has the effect of passing pointer types 22898524Sfenner // "by value" through the __cxa_begin_catch return value. 22998524Sfenner if (throw_type->__is_pointer_p ()) 23098524Sfenner thrown_ptr = *(void **) thrown_ptr; 23198524Sfenner 23298524Sfenner if (catch_type->__do_catch (throw_type, &thrown_ptr, 1)) 23398524Sfenner { 23498524Sfenner *thrown_ptr_p = thrown_ptr; 23598524Sfenner return true; 23698524Sfenner } 23798524Sfenner 23898524Sfenner return false; 239127668Sbms} 24098524Sfenner 24198524Sfenner// Return true if THROW_TYPE matches one if the filter types. 24298524Sfenner 24398524Sfennerstatic bool 24498524Sfennercheck_exception_spec(lsda_header_info* info, _throw_typet* throw_type, 24598524Sfenner void* thrown_ptr, _Unwind_Sword filter_value) 24698524Sfenner{ 24798524Sfenner const unsigned char *e = info->TType - filter_value - 1; 24898524Sfenner 24998524Sfenner while (1) 25098524Sfenner { 25198524Sfenner const std::type_info *catch_type; 25298524Sfenner _Unwind_Word tmp; 25398524Sfenner 25498524Sfenner e = read_uleb128 (e, &tmp); 25598524Sfenner 25698524Sfenner // Zero signals the end of the list. If we've not found 25798524Sfenner // a match by now, then we've failed the specification. 25898524Sfenner if (tmp == 0) 25998524Sfenner return false; 26098524Sfenner 26198524Sfenner // Match a ttype entry. 26298524Sfenner catch_type = get_ttype_entry (info, tmp); 26398524Sfenner 26498524Sfenner // ??? There is currently no way to ask the RTTI code about the 26598524Sfenner // relationship between two types without reference to a specific 266127668Sbms // object. There should be; then we wouldn't need to mess with 26798524Sfenner // thrown_ptr here. 26898524Sfenner if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr)) 26998524Sfenner return true; 27098524Sfenner } 27198524Sfenner} 27298524Sfenner 27398524Sfenner 27498524Sfenner// Save stage1 handler information in the exception object 27598524Sfenner 27698524Sfennerstatic inline void 27798524Sfennersave_caught_exception(struct _Unwind_Exception* ue_header, 27898524Sfenner struct _Unwind_Context* context 27998524Sfenner __attribute__((__unused__)), 28098524Sfenner void* thrown_ptr, 28198524Sfenner int handler_switch_value, 282127668Sbms const unsigned char* language_specific_data, 28398524Sfenner _Unwind_Ptr landing_pad __attribute__((__unused__)), 28498524Sfenner const unsigned char* action_record) 285127668Sbms{ 28698524Sfenner __cxa_exception* xh = __get_exception_header_from_ue(ue_header); 28798524Sfenner 28898524Sfenner xh->handlerSwitchValue = handler_switch_value; 28998524Sfenner xh->actionRecord = action_record; 29098524Sfenner xh->languageSpecificData = language_specific_data; 29198524Sfenner xh->adjustedPtr = thrown_ptr; 29298524Sfenner 29398524Sfenner // ??? Completely unknown what this field is supposed to be for. 29498524Sfenner // ??? Need to cache TType encoding base for call_unexpected. 295127668Sbms xh->catchTemp = landing_pad; 29698524Sfenner} 29798524Sfenner 29898524Sfenner 29998524Sfenner// Restore the catch handler information saved during phase1. 30098524Sfenner 30198524Sfennerstatic inline void 302127668Sbmsrestore_caught_exception(struct _Unwind_Exception* ue_header, 30398524Sfenner int& handler_switch_value, 30498524Sfenner const unsigned char*& language_specific_data, 30598524Sfenner _Unwind_Ptr& landing_pad) 30698524Sfenner{ 30798524Sfenner __cxa_exception* xh = __get_exception_header_from_ue(ue_header); 30898524Sfenner handler_switch_value = xh->handlerSwitchValue; 30998524Sfenner language_specific_data = xh->languageSpecificData; 31098524Sfenner landing_pad = (_Unwind_Ptr) xh->catchTemp; 31198524Sfenner} 31298524Sfenner 31398524Sfenner#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND 31498524Sfenner 315127668Sbms#endif // !__ARM_EABI_UNWINDER__ 31698524Sfenner 31798524Sfenner// Return true if the filter spec is empty, ie throw(). 31898524Sfenner 31998524Sfennerstatic bool 32098524Sfennerempty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value) 321127668Sbms{ 32298524Sfenner const unsigned char *e = info->TType - filter_value - 1; 32398524Sfenner _Unwind_Word tmp; 32498524Sfenner 32598524Sfenner e = read_uleb128 (e, &tmp); 32698524Sfenner return tmp == 0; 327127668Sbms} 32898524Sfenner 32998524Sfennernamespace __cxxabiv1 33098524Sfenner{ 33198524Sfenner 33298524Sfenner// Using a different personality function name causes link failures 333127668Sbms// when trying to mix code using different exception handling models. 33498524Sfenner#ifdef _GLIBCXX_SJLJ_EXCEPTIONS 33598524Sfenner#define PERSONALITY_FUNCTION __gxx_personality_sj0 33698524Sfenner#define __builtin_eh_return_data_regno(x) x 33798524Sfenner#else 33898524Sfenner#define PERSONALITY_FUNCTION __gxx_personality_v0 33998524Sfenner#endif 34098524Sfenner 34198524Sfennerextern "C" _Unwind_Reason_Code 34298524Sfenner#ifdef __ARM_EABI_UNWINDER__ 34398524SfennerPERSONALITY_FUNCTION (_Unwind_State state, 34498524Sfenner struct _Unwind_Exception* ue_header, 34598524Sfenner struct _Unwind_Context* context) 34698524Sfenner#else 34798524SfennerPERSONALITY_FUNCTION (int version, 34898524Sfenner _Unwind_Action actions, 34998524Sfenner _Unwind_Exception_Class exception_class, 35098524Sfenner struct _Unwind_Exception *ue_header, 35198524Sfenner struct _Unwind_Context *context) 35298524Sfenner#endif 35398524Sfenner{ 35498524Sfenner enum found_handler_type 35598524Sfenner { 35698524Sfenner found_nothing, 35798524Sfenner found_terminate, 35898524Sfenner found_cleanup, 35998524Sfenner found_handler 36098524Sfenner } found_type; 36198524Sfenner 36298524Sfenner lsda_header_info info; 36398524Sfenner const unsigned char *language_specific_data; 36498524Sfenner const unsigned char *action_record; 36598524Sfenner const unsigned char *p; 36698524Sfenner _Unwind_Ptr landing_pad, ip; 36798524Sfenner int handler_switch_value; 36898524Sfenner void* thrown_ptr = ue_header + 1; 36998524Sfenner bool foreign_exception; 37098524Sfenner int ip_before_insn = 0; 37198524Sfenner 37298524Sfenner#ifdef __ARM_EABI_UNWINDER__ 37398524Sfenner _Unwind_Action actions; 374127668Sbms 37598524Sfenner switch (state & _US_ACTION_MASK) 37698524Sfenner { 37798524Sfenner case _US_VIRTUAL_UNWIND_FRAME: 37898524Sfenner actions = _UA_SEARCH_PHASE; 37998524Sfenner break; 38098524Sfenner 381127668Sbms case _US_UNWIND_FRAME_STARTING: 38298524Sfenner actions = _UA_CLEANUP_PHASE; 38398524Sfenner if (!(state & _US_FORCE_UNWIND) 384127668Sbms && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13)) 38598524Sfenner actions |= _UA_HANDLER_FRAME; 38698524Sfenner break; 38798524Sfenner 38898524Sfenner case _US_UNWIND_FRAME_RESUME: 38998524Sfenner CONTINUE_UNWINDING; 39098524Sfenner break; 39198524Sfenner 39298524Sfenner default: 39398524Sfenner std::abort(); 394127668Sbms } 39598524Sfenner actions |= state & _US_FORCE_UNWIND; 39698524Sfenner 39798524Sfenner // We don't know which runtime we're working with, so can't check this. 39898524Sfenner // However the ABI routines hide this from us, and we don't actually need 39998524Sfenner // to know. 40098524Sfenner foreign_exception = false; 40198524Sfenner 40298524Sfenner // The dwarf unwinder assumes the context structure holds things like the 40398524Sfenner // function and LSDA pointers. The ARM implementation caches these in 40498524Sfenner // the exception header (UCB). To avoid rewriting everything we make the 40598524Sfenner // virtual IP register point at the UCB. 40698524Sfenner ip = (_Unwind_Ptr) ue_header; 40798524Sfenner _Unwind_SetGR(context, 12, ip); 40898524Sfenner#else 40998524Sfenner __cxa_exception* xh = __get_exception_header_from_ue(ue_header); 41098524Sfenner 41198524Sfenner // Interface version check. 41298524Sfenner if (version != 1) 41398524Sfenner return _URC_FATAL_PHASE1_ERROR; 41498524Sfenner foreign_exception = !__is_gxx_exception_class(exception_class); 41598524Sfenner#endif 41698524Sfenner 41798524Sfenner // Shortcut for phase 2 found handler for domestic exception. 41898524Sfenner if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) 41998524Sfenner && !foreign_exception) 420127668Sbms { 42198524Sfenner restore_caught_exception(ue_header, handler_switch_value, 42298524Sfenner language_specific_data, landing_pad); 42398524Sfenner found_type = (landing_pad == 0 ? found_terminate : found_handler); 42498524Sfenner goto install_context; 42598524Sfenner } 426127668Sbms 42798524Sfenner language_specific_data = (const unsigned char *) 42898524Sfenner _Unwind_GetLanguageSpecificData (context); 42998524Sfenner 43098524Sfenner // If no LSDA, then there are no handlers or cleanups. 43198524Sfenner if (! language_specific_data) 432127668Sbms CONTINUE_UNWINDING; 43398524Sfenner 43498524Sfenner // Parse the LSDA header. 43598524Sfenner p = parse_lsda_header (context, language_specific_data, &info); 43698524Sfenner info.ttype_base = base_of_encoded_value (info.ttype_encoding, context); 43798524Sfenner#ifdef _GLIBCXX_HAVE_GETIPINFO 438127668Sbms ip = _Unwind_GetIPInfo (context, &ip_before_insn); 43998524Sfenner#else 44098524Sfenner ip = _Unwind_GetIP (context); 44198524Sfenner#endif 44298524Sfenner if (! ip_before_insn) 44398524Sfenner --ip; 444127668Sbms landing_pad = 0; 44598524Sfenner action_record = 0; 44698524Sfenner handler_switch_value = 0; 44798524Sfenner 44898524Sfenner#ifdef _GLIBCXX_SJLJ_EXCEPTIONS 44998524Sfenner // The given "IP" is an index into the call-site table, with two 45098524Sfenner // exceptions -- -1 means no-action, and 0 means terminate. But 451127668Sbms // since we're using uleb128 values, we've not got random access 452127668Sbms // to the array. 45398524Sfenner if ((int) ip < 0) 45498524Sfenner return _URC_CONTINUE_UNWIND; 45598524Sfenner else if (ip == 0) 45698524Sfenner { 45798524Sfenner // Fall through to set found_terminate. 458127668Sbms } 45998524Sfenner else 46098524Sfenner { 46198524Sfenner _Unwind_Word cs_lp, cs_action; 46298524Sfenner do 46398524Sfenner { 46498524Sfenner p = read_uleb128 (p, &cs_lp); 46598524Sfenner p = read_uleb128 (p, &cs_action); 46698524Sfenner } 46798524Sfenner while (--ip); 46898524Sfenner 46998524Sfenner // Can never have null landing pad for sjlj -- that would have 47098524Sfenner // been indicated by a -1 call site index. 47198524Sfenner landing_pad = cs_lp + 1; 47298524Sfenner if (cs_action) 47398524Sfenner action_record = info.action_table + cs_action - 1; 47498524Sfenner goto found_something; 47598524Sfenner } 47698524Sfenner#else 47798524Sfenner // Search the call-site table for the action associated with this IP. 47898524Sfenner while (p < info.action_table) 47998524Sfenner { 48098524Sfenner _Unwind_Ptr cs_start, cs_len, cs_lp; 48198524Sfenner _Unwind_Word cs_action; 48298524Sfenner 48398524Sfenner // Note that all call-site encodings are "absolute" displacements. 48498524Sfenner p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); 48598524Sfenner p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); 48698524Sfenner p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); 48798524Sfenner p = read_uleb128 (p, &cs_action); 48898524Sfenner 48998524Sfenner // The table is sorted, so if we've passed the ip, stop. 49098524Sfenner if (ip < info.Start + cs_start) 49198524Sfenner p = info.action_table; 49298524Sfenner else if (ip < info.Start + cs_start + cs_len) 49398524Sfenner { 49498524Sfenner if (cs_lp) 49598524Sfenner landing_pad = info.LPStart + cs_lp; 49698524Sfenner if (cs_action) 49798524Sfenner action_record = info.action_table + cs_action - 1; 49898524Sfenner goto found_something; 49998524Sfenner } 50098524Sfenner } 50198524Sfenner#endif // _GLIBCXX_SJLJ_EXCEPTIONS 50298524Sfenner 50398524Sfenner // If ip is not present in the table, call terminate. This is for 50498524Sfenner // a destructor inside a cleanup, or a library routine the compiler 50598524Sfenner // was not expecting to throw. 50698524Sfenner found_type = found_terminate; 50798524Sfenner goto do_something; 50898524Sfenner 50998524Sfenner found_something: 51098524Sfenner if (landing_pad == 0) 51198524Sfenner { 51298524Sfenner // If ip is present, and has a null landing pad, there are 51398524Sfenner // no cleanups or handlers to be run. 51498524Sfenner found_type = found_nothing; 51598524Sfenner } 51698524Sfenner else if (action_record == 0) 51798524Sfenner { 51898524Sfenner // If ip is present, has a non-null landing pad, and a null 51998524Sfenner // action table offset, then there are only cleanups present. 52098524Sfenner // Cleanups use a zero switch value, as set above. 52198524Sfenner found_type = found_cleanup; 52298524Sfenner } 52398524Sfenner else 52498524Sfenner { 52598524Sfenner // Otherwise we have a catch handler or exception specification. 52698524Sfenner 52798524Sfenner _Unwind_Sword ar_filter, ar_disp; 52898524Sfenner const std::type_info* catch_type; 52998524Sfenner _throw_typet* throw_type; 53098524Sfenner bool saw_cleanup = false; 53198524Sfenner bool saw_handler = false; 53298524Sfenner 53398524Sfenner // During forced unwinding, we only run cleanups. With a foreign 53498524Sfenner // exception class, there's no exception type. 53598524Sfenner // ??? What to do about GNU Java and GNU Ada exceptions. 53698524Sfenner 53798524Sfenner if ((actions & _UA_FORCE_UNWIND) 53898524Sfenner || foreign_exception) 53998524Sfenner throw_type = 0; 54098524Sfenner else 54198524Sfenner#ifdef __ARM_EABI_UNWINDER__ 54298524Sfenner throw_type = ue_header; 54398524Sfenner#else 54498524Sfenner throw_type = xh->exceptionType; 54598524Sfenner#endif 54698524Sfenner 54798524Sfenner while (1) 54898524Sfenner { 54998524Sfenner p = action_record; 55098524Sfenner p = read_sleb128 (p, &ar_filter); 55198524Sfenner read_sleb128 (p, &ar_disp); 55298524Sfenner 55398524Sfenner if (ar_filter == 0) 55498524Sfenner { 55598524Sfenner // Zero filter values are cleanups. 55698524Sfenner saw_cleanup = true; 55798524Sfenner } 55898524Sfenner else if (ar_filter > 0) 55998524Sfenner { 56098524Sfenner // Positive filter values are handlers. 56198524Sfenner catch_type = get_ttype_entry (&info, ar_filter); 56298524Sfenner 56398524Sfenner // Null catch type is a catch-all handler; we can catch foreign 56498524Sfenner // exceptions with this. Otherwise we must match types. 56598524Sfenner if (! catch_type 56698524Sfenner || (throw_type 56798524Sfenner && get_adjusted_ptr (catch_type, throw_type, 56898524Sfenner &thrown_ptr))) 56998524Sfenner { 57098524Sfenner saw_handler = true; 57198524Sfenner break; 57298524Sfenner } 57398524Sfenner } 57498524Sfenner else 57598524Sfenner { 57698524Sfenner // Negative filter values are exception specifications. 57798524Sfenner // ??? How do foreign exceptions fit in? As far as I can 57898524Sfenner // see we can't match because there's no __cxa_exception 57998524Sfenner // object to stuff bits in for __cxa_call_unexpected to use. 58098524Sfenner // Allow them iff the exception spec is non-empty. I.e. 58198524Sfenner // a throw() specification results in __unexpected. 58298524Sfenner if (throw_type 58398524Sfenner ? ! check_exception_spec (&info, throw_type, thrown_ptr, 58498524Sfenner ar_filter) 58598524Sfenner : empty_exception_spec (&info, ar_filter)) 58698524Sfenner { 58798524Sfenner saw_handler = true; 58898524Sfenner break; 58998524Sfenner } 59098524Sfenner } 59198524Sfenner 59298524Sfenner if (ar_disp == 0) 59398524Sfenner break; 59498524Sfenner action_record = p + ar_disp; 59598524Sfenner } 59698524Sfenner 59798524Sfenner if (saw_handler) 59898524Sfenner { 59998524Sfenner handler_switch_value = ar_filter; 60098524Sfenner found_type = found_handler; 60198524Sfenner } 60298524Sfenner else 60398524Sfenner found_type = (saw_cleanup ? found_cleanup : found_nothing); 60498524Sfenner } 60598524Sfenner 60698524Sfenner do_something: 60798524Sfenner if (found_type == found_nothing) 60898524Sfenner CONTINUE_UNWINDING; 60998524Sfenner 61098524Sfenner if (actions & _UA_SEARCH_PHASE) 61198524Sfenner { 61298524Sfenner if (found_type == found_cleanup) 61398524Sfenner CONTINUE_UNWINDING; 61498524Sfenner 61598524Sfenner // For domestic exceptions, we cache data from phase 1 for phase 2. 61698524Sfenner if (!foreign_exception) 61798524Sfenner { 61898524Sfenner save_caught_exception(ue_header, context, thrown_ptr, 61998524Sfenner handler_switch_value, language_specific_data, 62098524Sfenner landing_pad, action_record); 62198524Sfenner } 62298524Sfenner return _URC_HANDLER_FOUND; 62398524Sfenner } 62498524Sfenner 62598524Sfenner install_context: 62698524Sfenner 62798524Sfenner // We can't use any of the cxa routines with foreign exceptions, 62898524Sfenner // because they all expect ue_header to be a struct __cxa_exception. 62998524Sfenner // So in that case, call terminate or unexpected directly. 63098524Sfenner if ((actions & _UA_FORCE_UNWIND) 63198524Sfenner || foreign_exception) 63298524Sfenner { 63398524Sfenner if (found_type == found_terminate) 63498524Sfenner std::terminate (); 63598524Sfenner else if (handler_switch_value < 0) 63698524Sfenner { 63798524Sfenner try 63898524Sfenner { std::unexpected (); } 63998524Sfenner catch(...) 64098524Sfenner { std::terminate (); } 64198524Sfenner } 64298524Sfenner } 64398524Sfenner else 64498524Sfenner { 64598524Sfenner if (found_type == found_terminate) 64698524Sfenner __cxa_call_terminate(ue_header); 64798524Sfenner 64898524Sfenner // Cache the TType base value for __cxa_call_unexpected, as we won't 64998524Sfenner // have an _Unwind_Context then. 65098524Sfenner if (handler_switch_value < 0) 65198524Sfenner { 65298524Sfenner parse_lsda_header (context, language_specific_data, &info); 65398524Sfenner 65498524Sfenner#ifdef __ARM_EABI_UNWINDER__ 65598524Sfenner const _Unwind_Word* e; 65698524Sfenner _Unwind_Word n; 65798524Sfenner 65898524Sfenner e = ((const _Unwind_Word*) info.TType) - handler_switch_value - 1; 65998524Sfenner // Count the number of rtti objects. 66098524Sfenner n = 0; 66198524Sfenner while (e[n] != 0) 66298524Sfenner n++; 66398524Sfenner 66498524Sfenner // Count. 66598524Sfenner ue_header->barrier_cache.bitpattern[1] = n; 66698524Sfenner // Base (obsolete) 66798524Sfenner ue_header->barrier_cache.bitpattern[2] = 0; 66898524Sfenner // Stride. 66998524Sfenner ue_header->barrier_cache.bitpattern[3] = 4; 67098524Sfenner // List head. 67198524Sfenner ue_header->barrier_cache.bitpattern[4] = (_Unwind_Word) e; 67298524Sfenner#else 67398524Sfenner xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context); 67498524Sfenner#endif 67598524Sfenner } 67698524Sfenner } 67798524Sfenner 67898524Sfenner /* For targets with pointers smaller than the word size, we must extend the 67998524Sfenner pointer, and this extension is target dependent. */ 68098524Sfenner _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), 68198524Sfenner __builtin_extend_pointer (ue_header)); 68298524Sfenner _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 68398524Sfenner handler_switch_value); 68498524Sfenner _Unwind_SetIP (context, landing_pad); 68598524Sfenner#ifdef __ARM_EABI_UNWINDER__ 68698524Sfenner if (found_type == found_cleanup) 68798524Sfenner __cxa_begin_cleanup(ue_header); 68898524Sfenner#endif 68998524Sfenner return _URC_INSTALL_CONTEXT; 69098524Sfenner} 69198524Sfenner 69298524Sfenner/* The ARM EABI implementation of __cxa_call_unexpected is in a 69398524Sfenner different file so that the personality routine (PR) can be used 69498524Sfenner standalone. The generic routine shared datastructures with the PR 69598524Sfenner so it is most convenient to implement it here. */ 69698524Sfenner#ifndef __ARM_EABI_UNWINDER__ 69798524Sfennerextern "C" void 69898524Sfenner__cxa_call_unexpected (void *exc_obj_in) 69998524Sfenner{ 70098524Sfenner _Unwind_Exception *exc_obj 70198524Sfenner = reinterpret_cast <_Unwind_Exception *>(exc_obj_in); 702127668Sbms 70398524Sfenner __cxa_begin_catch (exc_obj); 70498524Sfenner 70598524Sfenner // This function is a handler for our exception argument. If we exit 70698524Sfenner // by throwing a different exception, we'll need the original cleaned up. 70798524Sfenner struct end_catch_protect 70898524Sfenner { 70998524Sfenner end_catch_protect() { } 71098524Sfenner ~end_catch_protect() { __cxa_end_catch(); } 71198524Sfenner } end_catch_protect_obj; 71298524Sfenner 71398524Sfenner lsda_header_info info; 71498524Sfenner __cxa_exception *xh = __get_exception_header_from_ue (exc_obj); 71598524Sfenner const unsigned char *xh_lsda; 71698524Sfenner _Unwind_Sword xh_switch_value; 71798524Sfenner std::terminate_handler xh_terminate_handler; 71898524Sfenner 71998524Sfenner // If the unexpectedHandler rethrows the exception (e.g. to categorize it), 72098524Sfenner // it will clobber data about the current handler. So copy the data out now. 721127668Sbms xh_lsda = xh->languageSpecificData; 72298524Sfenner xh_switch_value = xh->handlerSwitchValue; 72398524Sfenner xh_terminate_handler = xh->terminateHandler; 72498524Sfenner info.ttype_base = (_Unwind_Ptr) xh->catchTemp; 72598524Sfenner 72698524Sfenner try 72798524Sfenner { __unexpected (xh->unexpectedHandler); } 72898524Sfenner catch(...) 72998524Sfenner { 73098524Sfenner // Get the exception thrown from unexpected. 73198524Sfenner 73298524Sfenner __cxa_eh_globals *globals = __cxa_get_globals_fast (); 73398524Sfenner __cxa_exception *new_xh = globals->caughtExceptions; 73498524Sfenner void *new_ptr = new_xh + 1; 73598524Sfenner 73698524Sfenner // We don't quite have enough stuff cached; re-parse the LSDA. 73798524Sfenner parse_lsda_header (0, xh_lsda, &info); 738127668Sbms 73998524Sfenner // If this new exception meets the exception spec, allow it. 740127668Sbms if (check_exception_spec (&info, new_xh->exceptionType, 74198524Sfenner new_ptr, xh_switch_value)) 74298524Sfenner __throw_exception_again; 74398524Sfenner 74498524Sfenner // If the exception spec allows std::bad_exception, throw that. 74598524Sfenner // We don't have a thrown object to compare against, but since 74698524Sfenner // bad_exception doesn't have virtual bases, that's OK; just pass 0. 74798524Sfenner#ifdef __EXCEPTIONS 74898524Sfenner const std::type_info &bad_exc = typeid (std::bad_exception); 74998524Sfenner if (check_exception_spec (&info, &bad_exc, 0, xh_switch_value)) 750127668Sbms throw std::bad_exception(); 75198524Sfenner#endif 75298524Sfenner 75398524Sfenner // Otherwise, die. 75498524Sfenner __terminate (xh_terminate_handler); 75598524Sfenner } 75698524Sfenner} 75798524Sfenner#endif 75898524Sfenner 75998524Sfenner} // namespace __cxxabiv1 76098524Sfenner