Path: blob/master/libs/c++abi/src/cxa_personality.cpp
12346 views
//===------------------------- cxa_exception.cpp --------------------------===//1//2// The LLVM Compiler Infrastructure3//4// This file is dual licensed under the MIT and the University of Illinois Open5// Source Licenses. See LICENSE.TXT for details.6//7//8// This file implements the "Exception Handling APIs"9// http://mentorembedded.github.io/cxx-abi/abi-eh.html10// http://www.intel.com/design/itanium/downloads/245358.htm11//12//===----------------------------------------------------------------------===//1314#include <assert.h>15#include <stdlib.h>16#include <string.h>17#include <typeinfo>1819#include "__cxxabi_config.h"20#include "cxa_exception.hpp"21#include "cxa_handlers.hpp"22#include "private_typeinfo.h"23#include "unwind.h"2425/*26Exception Header Layout:2728+---------------------------+-----------------------------+---------------+29| __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |30+---------------------------+-----------------------------+---------------+31^32|33+-------------------------------------------------------+34|35+---------------------------+-----------------------------+36| __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |37+---------------------------+-----------------------------+3839Exception Handling Table Layout:4041+-----------------+--------+42| lpStartEncoding | (char) |43+---------+-------+--------+---------------+-----------------------+44| lpStart | (encoded with lpStartEncoding) | defaults to funcStart |45+---------+-----+--------+-----------------+---------------+-------+46| ttypeEncoding | (char) | Encoding of the type_info table |47+---------------+-+------+----+----------------------------+----------------+48| classInfoOffset | (ULEB128) | Offset to type_info table, defaults to null |49+-----------------++--------+-+----------------------------+----------------+50| callSiteEncoding | (char) | Encoding for Call Site Table |51+------------------+--+-----+-----+------------------------+--------------------------+52| callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table |53+---------------------+-----------+---------------------------------------------------+54#ifndef __USING_SJLJ_EXCEPTIONS__55+---------------------+-----------+------------------------------------------------+56| Beginning of Call Site Table The current ip lies within the |57| ... (start, length) range of one of these |58| call sites. There may be action needed. |59| +-------------+---------------------------------+------------------------------+ |60| | start | (encoded with callSiteEncoding) | offset relative to funcStart | |61| | length | (encoded with callSiteEncoding) | length of code fragment | |62| | landingPad | (encoded with callSiteEncoding) | offset relative to lpStart | |63| | actionEntry | (ULEB128) | Action Table Index 1-based | |64| | | | actionEntry == 0 -> cleanup | |65| +-------------+---------------------------------+------------------------------+ |66| ... |67+----------------------------------------------------------------------------------+68#else // __USING_SJLJ_EXCEPTIONS__69+---------------------+-----------+------------------------------------------------+70| Beginning of Call Site Table The current ip is a 1-based index into |71| ... this table. Or it is -1 meaning no |72| action is needed. Or it is 0 meaning |73| terminate. |74| +-------------+---------------------------------+------------------------------+ |75| | landingPad | (ULEB128) | offset relative to lpStart | |76| | actionEntry | (ULEB128) | Action Table Index 1-based | |77| | | | actionEntry == 0 -> cleanup | |78| +-------------+---------------------------------+------------------------------+ |79| ... |80+----------------------------------------------------------------------------------+81#endif // __USING_SJLJ_EXCEPTIONS__82+---------------------------------------------------------------------+83| Beginning of Action Table ttypeIndex == 0 : cleanup |84| ... ttypeIndex > 0 : catch |85| ttypeIndex < 0 : exception spec |86| +--------------+-----------+--------------------------------------+ |87| | ttypeIndex | (SLEB128) | Index into type_info Table (1-based) | |88| | actionOffset | (SLEB128) | Offset into next Action Table entry | |89| +--------------+-----------+--------------------------------------+ |90| ... |91+---------------------------------------------------------------------+-----------------+92| type_info Table, but classInfoOffset does *not* point here! |93| +----------------+------------------------------------------------+-----------------+ |94| | Nth type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == N | |95| +----------------+------------------------------------------------+-----------------+ |96| ... |97| +----------------+------------------------------------------------+-----------------+ |98| | 1st type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == 1 | |99| +----------------+------------------------------------------------+-----------------+ |100| +---------------------------------------+-----------+------------------------------+ |101| | 1st ttypeIndex for 1st exception spec | (ULEB128) | classInfoOffset points here! | |102| | ... | (ULEB128) | | |103| | Mth ttypeIndex for 1st exception spec | (ULEB128) | | |104| | 0 | (ULEB128) | | |105| +---------------------------------------+------------------------------------------+ |106| ... |107| +---------------------------------------+------------------------------------------+ |108| | 0 | (ULEB128) | throw() | |109| +---------------------------------------+------------------------------------------+ |110| ... |111| +---------------------------------------+------------------------------------------+ |112| | 1st ttypeIndex for Nth exception spec | (ULEB128) | | |113| | ... | (ULEB128) | | |114| | Mth ttypeIndex for Nth exception spec | (ULEB128) | | |115| | 0 | (ULEB128) | | |116| +---------------------------------------+------------------------------------------+ |117+---------------------------------------------------------------------------------------+118119Notes:120121* ttypeIndex in the Action Table, and in the exception spec table, is an index,122not a byte count, if positive. It is a negative index offset of123classInfoOffset and the sizeof entry depends on ttypeEncoding.124But if ttypeIndex is negative, it is a positive 1-based byte offset into the125type_info Table.126And if ttypeIndex is zero, it refers to a catch (...).127128* landingPad can be 0, this implies there is nothing to be done.129130* landingPad != 0 and actionEntry == 0 implies a cleanup needs to be done131@landingPad.132133* A cleanup can also be found under landingPad != 0 and actionEntry != 0 in134the Action Table with ttypeIndex == 0.135*/136137namespace __cxxabiv1138{139140namespace141{142143template <class AsType>144uintptr_t readPointerHelper(const uint8_t*& p) {145AsType value;146memcpy(&value, p, sizeof(AsType));147p += sizeof(AsType);148return static_cast<uintptr_t>(value);149}150151} // end namespace152153extern "C"154{155156// private API157158// Heavily borrowed from llvm/examples/ExceptionDemo/ExceptionDemo.cpp159160// DWARF Constants161enum162{163DW_EH_PE_absptr = 0x00,164DW_EH_PE_uleb128 = 0x01,165DW_EH_PE_udata2 = 0x02,166DW_EH_PE_udata4 = 0x03,167DW_EH_PE_udata8 = 0x04,168DW_EH_PE_sleb128 = 0x09,169DW_EH_PE_sdata2 = 0x0A,170DW_EH_PE_sdata4 = 0x0B,171DW_EH_PE_sdata8 = 0x0C,172DW_EH_PE_pcrel = 0x10,173DW_EH_PE_textrel = 0x20,174DW_EH_PE_datarel = 0x30,175DW_EH_PE_funcrel = 0x40,176DW_EH_PE_aligned = 0x50,177DW_EH_PE_indirect = 0x80,178DW_EH_PE_omit = 0xFF179};180181/// Read a uleb128 encoded value and advance pointer182/// See Variable Length Data Appendix C in:183/// @link http://dwarfstd.org/Dwarf4.pdf @unlink184/// @param data reference variable holding memory pointer to decode from185/// @returns decoded value186static187uintptr_t188readULEB128(const uint8_t** data)189{190uintptr_t result = 0;191uintptr_t shift = 0;192unsigned char byte;193const uint8_t *p = *data;194do195{196byte = *p++;197result |= static_cast<uintptr_t>(byte & 0x7F) << shift;198shift += 7;199} while (byte & 0x80);200*data = p;201return result;202}203204/// Read a sleb128 encoded value and advance pointer205/// See Variable Length Data Appendix C in:206/// @link http://dwarfstd.org/Dwarf4.pdf @unlink207/// @param data reference variable holding memory pointer to decode from208/// @returns decoded value209static210intptr_t211readSLEB128(const uint8_t** data)212{213uintptr_t result = 0;214uintptr_t shift = 0;215unsigned char byte;216const uint8_t *p = *data;217do218{219byte = *p++;220result |= static_cast<uintptr_t>(byte & 0x7F) << shift;221shift += 7;222} while (byte & 0x80);223*data = p;224if ((byte & 0x40) && (shift < (sizeof(result) << 3)))225result |= static_cast<uintptr_t>(~0) << shift;226return static_cast<intptr_t>(result);227}228229/// Read a pointer encoded value and advance pointer230/// See Variable Length Data in:231/// @link http://dwarfstd.org/Dwarf3.pdf @unlink232/// @param data reference variable holding memory pointer to decode from233/// @param encoding dwarf encoding type234/// @returns decoded value235static236uintptr_t237readEncodedPointer(const uint8_t** data, uint8_t encoding)238{239uintptr_t result = 0;240if (encoding == DW_EH_PE_omit)241return result;242const uint8_t* p = *data;243// first get value244switch (encoding & 0x0F)245{246case DW_EH_PE_absptr:247result = readPointerHelper<uintptr_t>(p);248break;249case DW_EH_PE_uleb128:250result = readULEB128(&p);251break;252case DW_EH_PE_sleb128:253result = static_cast<uintptr_t>(readSLEB128(&p));254break;255case DW_EH_PE_udata2:256result = readPointerHelper<uint16_t>(p);257break;258case DW_EH_PE_udata4:259result = readPointerHelper<uint32_t>(p);260break;261case DW_EH_PE_udata8:262result = readPointerHelper<uint64_t>(p);263break;264case DW_EH_PE_sdata2:265result = readPointerHelper<int16_t>(p);266break;267case DW_EH_PE_sdata4:268result = readPointerHelper<int32_t>(p);269break;270case DW_EH_PE_sdata8:271result = readPointerHelper<int64_t>(p);272break;273default:274// not supported275abort();276break;277}278// then add relative offset279switch (encoding & 0x70)280{281case DW_EH_PE_absptr:282// do nothing283break;284case DW_EH_PE_pcrel:285if (result)286result += (uintptr_t)(*data);287break;288case DW_EH_PE_textrel:289case DW_EH_PE_datarel:290case DW_EH_PE_funcrel:291case DW_EH_PE_aligned:292default:293// not supported294abort();295break;296}297// then apply indirection298if (result && (encoding & DW_EH_PE_indirect))299result = *((uintptr_t*)result);300*data = p;301return result;302}303304static305void306call_terminate(bool native_exception, _Unwind_Exception* unwind_exception)307{308__cxa_begin_catch(unwind_exception);309if (native_exception)310{311// Use the stored terminate_handler if possible312__cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;313std::__terminate(exception_header->terminateHandler);314}315std::terminate();316}317318#if defined(_LIBCXXABI_ARM_EHABI)319static const void* read_target2_value(const void* ptr)320{321uintptr_t offset = *reinterpret_cast<const uintptr_t*>(ptr);322if (!offset)323return 0;324// "ARM EABI provides a TARGET2 relocation to describe these typeinfo325// pointers. The reason being it allows their precise semantics to be326// deferred to the linker. For bare-metal they turn into absolute327// relocations. For linux they turn into GOT-REL relocations."328// https://gcc.gnu.org/ml/gcc-patches/2009-08/msg00264.html329#if defined(LIBCXXABI_BAREMETAL)330return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(ptr) +331offset);332#else333return *reinterpret_cast<const void **>(reinterpret_cast<uintptr_t>(ptr) +334offset);335#endif336}337338static const __shim_type_info*339get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,340uint8_t ttypeEncoding, bool native_exception,341_Unwind_Exception* unwind_exception)342{343if (classInfo == 0)344{345// this should not happen. Indicates corrupted eh_table.346call_terminate(native_exception, unwind_exception);347}348349assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6350(ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal351(ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux352"Unexpected TTypeEncoding");353(void)ttypeEncoding;354355const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t);356return reinterpret_cast<const __shim_type_info *>(357read_target2_value(ttypePtr));358}359#else // !defined(_LIBCXXABI_ARM_EHABI)360static361const __shim_type_info*362get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,363uint8_t ttypeEncoding, bool native_exception,364_Unwind_Exception* unwind_exception)365{366if (classInfo == 0)367{368// this should not happen. Indicates corrupted eh_table.369call_terminate(native_exception, unwind_exception);370}371switch (ttypeEncoding & 0x0F)372{373case DW_EH_PE_absptr:374ttypeIndex *= sizeof(void*);375break;376case DW_EH_PE_udata2:377case DW_EH_PE_sdata2:378ttypeIndex *= 2;379break;380case DW_EH_PE_udata4:381case DW_EH_PE_sdata4:382ttypeIndex *= 4;383break;384case DW_EH_PE_udata8:385case DW_EH_PE_sdata8:386ttypeIndex *= 8;387break;388default:389// this should not happen. Indicates corrupted eh_table.390call_terminate(native_exception, unwind_exception);391}392classInfo -= ttypeIndex;393return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding);394}395#endif // !defined(_LIBCXXABI_ARM_EHABI)396397/*398This is checking a thrown exception type, excpType, against a possibly empty399list of catchType's which make up an exception spec.400401An exception spec acts like a catch handler, but in reverse. This "catch402handler" will catch an excpType if and only if none of the catchType's in403the list will catch a excpType. If any catchType in the list can catch an404excpType, then this exception spec does not catch the excpType.405*/406#if defined(_LIBCXXABI_ARM_EHABI)407static408bool409exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo,410uint8_t ttypeEncoding, const __shim_type_info* excpType,411void* adjustedPtr, _Unwind_Exception* unwind_exception)412{413if (classInfo == 0)414{415// this should not happen. Indicates corrupted eh_table.416call_terminate(false, unwind_exception);417}418419assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6420(ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal421(ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux422"Unexpected TTypeEncoding");423(void)ttypeEncoding;424425// specIndex is negative of 1-based byte offset into classInfo;426specIndex = -specIndex;427--specIndex;428const void** temp = reinterpret_cast<const void**>(429reinterpret_cast<uintptr_t>(classInfo) +430static_cast<uintptr_t>(specIndex) * sizeof(uintptr_t));431// If any type in the spec list can catch excpType, return false, else return true432// adjustments to adjustedPtr are ignored.433while (true)434{435// ARM EHABI exception specification table (filter table) consists of436// several pointers which will directly point to the type info object437// (instead of ttypeIndex). The table will be terminated with 0.438const void** ttypePtr = temp++;439if (*ttypePtr == 0)440break;441// We can get the __shim_type_info simply by performing a442// R_ARM_TARGET2 relocation, and cast the result to __shim_type_info.443const __shim_type_info* catchType =444static_cast<const __shim_type_info*>(read_target2_value(ttypePtr));445void* tempPtr = adjustedPtr;446if (catchType->can_catch(excpType, tempPtr))447return false;448}449return true;450}451#else452static453bool454exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo,455uint8_t ttypeEncoding, const __shim_type_info* excpType,456void* adjustedPtr, _Unwind_Exception* unwind_exception)457{458if (classInfo == 0)459{460// this should not happen. Indicates corrupted eh_table.461call_terminate(false, unwind_exception);462}463// specIndex is negative of 1-based byte offset into classInfo;464specIndex = -specIndex;465--specIndex;466const uint8_t* temp = classInfo + specIndex;467// If any type in the spec list can catch excpType, return false, else return true468// adjustments to adjustedPtr are ignored.469while (true)470{471uint64_t ttypeIndex = readULEB128(&temp);472if (ttypeIndex == 0)473break;474const __shim_type_info* catchType = get_shim_type_info(ttypeIndex,475classInfo,476ttypeEncoding,477true,478unwind_exception);479void* tempPtr = adjustedPtr;480if (catchType->can_catch(excpType, tempPtr))481return false;482}483return true;484}485#endif486487static488void*489get_thrown_object_ptr(_Unwind_Exception* unwind_exception)490{491// Even for foreign exceptions, the exception object is *probably* at unwind_exception + 1492// Regardless, this library is prohibited from touching a foreign exception493void* adjustedPtr = unwind_exception + 1;494if (__getExceptionClass(unwind_exception) == kOurDependentExceptionClass)495adjustedPtr = ((__cxa_dependent_exception*)adjustedPtr - 1)->primaryException;496return adjustedPtr;497}498499namespace500{501502struct scan_results503{504int64_t ttypeIndex; // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup505const uint8_t* actionRecord; // Currently unused. Retained to ease future maintenance.506const uint8_t* languageSpecificData; // Needed only for __cxa_call_unexpected507uintptr_t landingPad; // null -> nothing found, else something found508void* adjustedPtr; // Used in cxa_exception.cpp509_Unwind_Reason_Code reason; // One of _URC_FATAL_PHASE1_ERROR,510// _URC_FATAL_PHASE2_ERROR,511// _URC_CONTINUE_UNWIND,512// _URC_HANDLER_FOUND513};514515} // unnamed namespace516517static518void519set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,520const scan_results& results)521{522#if defined(__USING_SJLJ_EXCEPTIONS__)523#define __builtin_eh_return_data_regno(regno) regno524#endif525_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),526reinterpret_cast<uintptr_t>(unwind_exception));527_Unwind_SetGR(context, __builtin_eh_return_data_regno(1),528static_cast<uintptr_t>(results.ttypeIndex));529_Unwind_SetIP(context, results.landingPad);530}531532/*533There are 3 types of scans needed:5345351. Scan for handler with native or foreign exception. If handler found,536save state and return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND.537May also report an error on invalid input.538May terminate for invalid exception table.539_UA_SEARCH_PHASE5405412. Scan for handler with foreign exception. Must return _URC_HANDLER_FOUND,542or call terminate.543_UA_CLEANUP_PHASE && _UA_HANDLER_FRAME && !native_exception5445453. Scan for cleanups. If a handler is found and this isn't forced unwind,546then terminate, otherwise ignore the handler and keep looking for cleanup.547If a cleanup is found, return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND.548May also report an error on invalid input.549May terminate for invalid exception table.550_UA_CLEANUP_PHASE && !_UA_HANDLER_FRAME551*/552553static void scan_eh_tab(scan_results &results, _Unwind_Action actions,554bool native_exception,555_Unwind_Exception *unwind_exception,556_Unwind_Context *context) {557// Initialize results to found nothing but an error558results.ttypeIndex = 0;559results.actionRecord = 0;560results.languageSpecificData = 0;561results.landingPad = 0;562results.adjustedPtr = 0;563results.reason = _URC_FATAL_PHASE1_ERROR;564// Check for consistent actions565if (actions & _UA_SEARCH_PHASE)566{567// Do Phase 1568if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND))569{570// None of these flags should be set during Phase 1571// Client error572results.reason = _URC_FATAL_PHASE1_ERROR;573return;574}575}576else if (actions & _UA_CLEANUP_PHASE)577{578if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND))579{580// _UA_HANDLER_FRAME should only be set if phase 1 found a handler.581// If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened.582// Client error583results.reason = _URC_FATAL_PHASE2_ERROR;584return;585}586}587else // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set588{589// One of these should be set.590// Client error591results.reason = _URC_FATAL_PHASE1_ERROR;592return;593}594// Start scan by getting exception table address595const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context);596if (lsda == 0)597{598// There is no exception table599results.reason = _URC_CONTINUE_UNWIND;600return;601}602results.languageSpecificData = lsda;603// Get the current instruction pointer and offset it before next604// instruction in the current frame which threw the exception.605uintptr_t ip = _Unwind_GetIP(context) - 1;606// Get beginning current frame's code (as defined by the607// emitted dwarf code)608uintptr_t funcStart = _Unwind_GetRegionStart(context);609#ifdef __USING_SJLJ_EXCEPTIONS__610if (ip == uintptr_t(-1))611{612// no action613results.reason = _URC_CONTINUE_UNWIND;614return;615}616else if (ip == 0)617call_terminate(native_exception, unwind_exception);618// ip is 1-based index into call site table619#else // !__USING_SJLJ_EXCEPTIONS__620uintptr_t ipOffset = ip - funcStart;621#endif // !defined(_USING_SLJL_EXCEPTIONS__)622const uint8_t* classInfo = NULL;623// Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding624// dwarf emission625// Parse LSDA header.626uint8_t lpStartEncoding = *lsda++;627const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);628if (lpStart == 0)629lpStart = (const uint8_t*)funcStart;630uint8_t ttypeEncoding = *lsda++;631if (ttypeEncoding != DW_EH_PE_omit)632{633// Calculate type info locations in emitted dwarf code which634// were flagged by type info arguments to llvm.eh.selector635// intrinsic636uintptr_t classInfoOffset = readULEB128(&lsda);637classInfo = lsda + classInfoOffset;638}639// Walk call-site table looking for range that640// includes current PC.641uint8_t callSiteEncoding = *lsda++;642#ifdef __USING_SJLJ_EXCEPTIONS__643(void)callSiteEncoding; // When using SjLj exceptions, callSiteEncoding is never used644#endif645uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda));646const uint8_t* callSiteTableStart = lsda;647const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;648const uint8_t* actionTableStart = callSiteTableEnd;649const uint8_t* callSitePtr = callSiteTableStart;650while (callSitePtr < callSiteTableEnd)651{652// There is one entry per call site.653#ifndef __USING_SJLJ_EXCEPTIONS__654// The call sites are non-overlapping in [start, start+length)655// The call sites are ordered in increasing value of start656uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);657uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);658uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);659uintptr_t actionEntry = readULEB128(&callSitePtr);660if ((start <= ipOffset) && (ipOffset < (start + length)))661#else // __USING_SJLJ_EXCEPTIONS__662// ip is 1-based index into this table663uintptr_t landingPad = readULEB128(&callSitePtr);664uintptr_t actionEntry = readULEB128(&callSitePtr);665if (--ip == 0)666#endif // __USING_SJLJ_EXCEPTIONS__667{668// Found the call site containing ip.669#ifndef __USING_SJLJ_EXCEPTIONS__670if (landingPad == 0)671{672// No handler here673results.reason = _URC_CONTINUE_UNWIND;674return;675}676landingPad = (uintptr_t)lpStart + landingPad;677#else // __USING_SJLJ_EXCEPTIONS__678++landingPad;679#endif // __USING_SJLJ_EXCEPTIONS__680if (actionEntry == 0)681{682// Found a cleanup683// If this is a type 1 or type 2 search, there are no handlers684// If this is a type 3 search, you want to install the cleanup.685if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME))686{687results.ttypeIndex = 0; // Redundant but clarifying688results.landingPad = landingPad;689results.reason = _URC_HANDLER_FOUND;690return;691}692// No handler here693results.reason = _URC_CONTINUE_UNWIND;694return;695}696// Convert 1-based byte offset into697const uint8_t* action = actionTableStart + (actionEntry - 1);698// Scan action entries until you find a matching handler, cleanup, or the end of action list699while (true)700{701const uint8_t* actionRecord = action;702int64_t ttypeIndex = readSLEB128(&action);703if (ttypeIndex > 0)704{705// Found a catch, does it actually catch?706// First check for catch (...)707const __shim_type_info* catchType =708get_shim_type_info(static_cast<uint64_t>(ttypeIndex),709classInfo, ttypeEncoding,710native_exception, unwind_exception);711if (catchType == 0)712{713// Found catch (...) catches everything, including foreign exceptions714// If this is a type 1 search save state and return _URC_HANDLER_FOUND715// If this is a type 2 search save state and return _URC_HANDLER_FOUND716// If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!717// If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan718if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))719{720// Save state and return _URC_HANDLER_FOUND721results.ttypeIndex = ttypeIndex;722results.actionRecord = actionRecord;723results.landingPad = landingPad;724results.adjustedPtr = get_thrown_object_ptr(unwind_exception);725results.reason = _URC_HANDLER_FOUND;726return;727}728else if (!(actions & _UA_FORCE_UNWIND))729{730// It looks like the exception table has changed731// on us. Likely stack corruption!732call_terminate(native_exception, unwind_exception);733}734}735// Else this is a catch (T) clause and will never736// catch a foreign exception737else if (native_exception)738{739__cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;740void* adjustedPtr = get_thrown_object_ptr(unwind_exception);741const __shim_type_info* excpType =742static_cast<const __shim_type_info*>(exception_header->exceptionType);743if (adjustedPtr == 0 || excpType == 0)744{745// Something very bad happened746call_terminate(native_exception, unwind_exception);747}748if (catchType->can_catch(excpType, adjustedPtr))749{750// Found a matching handler751// If this is a type 1 search save state and return _URC_HANDLER_FOUND752// If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1!753// If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan754if (actions & _UA_SEARCH_PHASE)755{756// Save state and return _URC_HANDLER_FOUND757results.ttypeIndex = ttypeIndex;758results.actionRecord = actionRecord;759results.landingPad = landingPad;760results.adjustedPtr = adjustedPtr;761results.reason = _URC_HANDLER_FOUND;762return;763}764else if (!(actions & _UA_FORCE_UNWIND))765{766// It looks like the exception table has changed767// on us. Likely stack corruption!768call_terminate(native_exception, unwind_exception);769}770}771}772// Scan next action ...773}774else if (ttypeIndex < 0)775{776// Found an exception spec. If this is a foreign exception,777// it is always caught.778if (native_exception)779{780// Does the exception spec catch this native exception?781__cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;782void* adjustedPtr = get_thrown_object_ptr(unwind_exception);783const __shim_type_info* excpType =784static_cast<const __shim_type_info*>(exception_header->exceptionType);785if (adjustedPtr == 0 || excpType == 0)786{787// Something very bad happened788call_terminate(native_exception, unwind_exception);789}790if (exception_spec_can_catch(ttypeIndex, classInfo,791ttypeEncoding, excpType,792adjustedPtr, unwind_exception))793{794// native exception caught by exception spec795// If this is a type 1 search, save state and return _URC_HANDLER_FOUND796// If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!797// If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan798if (actions & _UA_SEARCH_PHASE)799{800// Save state and return _URC_HANDLER_FOUND801results.ttypeIndex = ttypeIndex;802results.actionRecord = actionRecord;803results.landingPad = landingPad;804results.adjustedPtr = adjustedPtr;805results.reason = _URC_HANDLER_FOUND;806return;807}808else if (!(actions & _UA_FORCE_UNWIND))809{810// It looks like the exception table has changed811// on us. Likely stack corruption!812call_terminate(native_exception, unwind_exception);813}814}815}816else817{818// foreign exception caught by exception spec819// If this is a type 1 search, save state and return _URC_HANDLER_FOUND820// If this is a type 2 search, save state and return _URC_HANDLER_FOUND821// If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!822// If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan823if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))824{825// Save state and return _URC_HANDLER_FOUND826results.ttypeIndex = ttypeIndex;827results.actionRecord = actionRecord;828results.landingPad = landingPad;829results.adjustedPtr = get_thrown_object_ptr(unwind_exception);830results.reason = _URC_HANDLER_FOUND;831return;832}833else if (!(actions & _UA_FORCE_UNWIND))834{835// It looks like the exception table has changed836// on us. Likely stack corruption!837call_terminate(native_exception, unwind_exception);838}839}840// Scan next action ...841}842else // ttypeIndex == 0843{844// Found a cleanup845// If this is a type 1 search, ignore it and continue scan846// If this is a type 2 search, ignore it and continue scan847// If this is a type 3 search, save state and return _URC_HANDLER_FOUND848if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME))849{850// Save state and return _URC_HANDLER_FOUND851results.ttypeIndex = ttypeIndex;852results.actionRecord = actionRecord;853results.landingPad = landingPad;854results.adjustedPtr = get_thrown_object_ptr(unwind_exception);855results.reason = _URC_HANDLER_FOUND;856return;857}858}859const uint8_t* temp = action;860int64_t actionOffset = readSLEB128(&temp);861if (actionOffset == 0)862{863// End of action list, no matching handler or cleanup found864results.reason = _URC_CONTINUE_UNWIND;865return;866}867// Go to next action868action += actionOffset;869} // there is no break out of this loop, only return870}871#ifndef __USING_SJLJ_EXCEPTIONS__872else if (ipOffset < start)873{874// There is no call site for this ip875// Something bad has happened. We should never get here.876// Possible stack corruption.877call_terminate(native_exception, unwind_exception);878}879#endif // !__USING_SJLJ_EXCEPTIONS__880} // there might be some tricky cases which break out of this loop881882// It is possible that no eh table entry specify how to handle883// this exception. By spec, terminate it immediately.884call_terminate(native_exception, unwind_exception);885}886887// public API888889/*890The personality function branches on actions like so:891892_UA_SEARCH_PHASE893894If _UA_CLEANUP_PHASE or _UA_HANDLER_FRAME or _UA_FORCE_UNWIND there's895an error from above, return _URC_FATAL_PHASE1_ERROR.896897Scan for anything that could stop unwinding:8988991. A catch clause that will catch this exception900(will never catch foreign).9012. A catch (...) (will always catch foreign).9023. An exception spec that will catch this exception903(will always catch foreign).904If a handler is found905If not foreign906Save state in header907return _URC_HANDLER_FOUND908Else a handler not found909return _URC_CONTINUE_UNWIND910911_UA_CLEANUP_PHASE912913If _UA_HANDLER_FRAME914If _UA_FORCE_UNWIND915How did this happen? return _URC_FATAL_PHASE2_ERROR916If foreign917Do _UA_SEARCH_PHASE to recover state918else919Recover state from header920Transfer control to landing pad. return _URC_INSTALL_CONTEXT921922Else923924This branch handles both normal C++ non-catching handlers (cleanups)925and forced unwinding.926Scan for anything that can not stop unwinding:9279281. A cleanup.929930If a cleanup is found931transfer control to it. return _URC_INSTALL_CONTEXT932Else a cleanup is not found: return _URC_CONTINUE_UNWIND933*/934935#if !defined(_LIBCXXABI_ARM_EHABI)936#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)937static _Unwind_Reason_Code __gxx_personality_imp938#else939_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code940#ifdef __USING_SJLJ_EXCEPTIONS__941__gxx_personality_sj0942#else943__gxx_personality_v0944#endif945#endif946(int version, _Unwind_Action actions, uint64_t exceptionClass,947_Unwind_Exception* unwind_exception, _Unwind_Context* context)948{949if (version != 1 || unwind_exception == 0 || context == 0)950return _URC_FATAL_PHASE1_ERROR;951952bool native_exception = (exceptionClass & get_vendor_and_language) ==953(kOurExceptionClass & get_vendor_and_language);954scan_results results;955if (actions & _UA_SEARCH_PHASE)956{957// Phase 1 search: All we're looking for in phase 1 is a handler that958// halts unwinding959scan_eh_tab(results, actions, native_exception, unwind_exception, context);960if (results.reason == _URC_HANDLER_FOUND)961{962// Found one. Can we cache the results somewhere to optimize phase 2?963if (native_exception)964{965__cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;966exception_header->handlerSwitchValue = static_cast<int>(results.ttypeIndex);967exception_header->actionRecord = results.actionRecord;968exception_header->languageSpecificData = results.languageSpecificData;969exception_header->catchTemp = reinterpret_cast<void*>(results.landingPad);970exception_header->adjustedPtr = results.adjustedPtr;971}972return _URC_HANDLER_FOUND;973}974// Did not find a catching-handler. Return the results of the scan975// (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE1_ERROR976// if we were called improperly).977return results.reason;978}979if (actions & _UA_CLEANUP_PHASE)980{981// Phase 2 search:982// Did we find a catching handler in phase 1?983if (actions & _UA_HANDLER_FRAME)984{985// Yes, phase 1 said we have a catching handler here.986// Did we cache the results of the scan?987if (native_exception)988{989// Yes, reload the results from the cache.990__cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;991results.ttypeIndex = exception_header->handlerSwitchValue;992results.actionRecord = exception_header->actionRecord;993results.languageSpecificData = exception_header->languageSpecificData;994results.landingPad = reinterpret_cast<uintptr_t>(exception_header->catchTemp);995results.adjustedPtr = exception_header->adjustedPtr;996}997else998{999// No, do the scan again to reload the results.1000scan_eh_tab(results, actions, native_exception, unwind_exception, context);1001// Phase 1 told us we would find a handler. Now in Phase 2 we1002// didn't find a handler. The eh table should not be changing!1003if (results.reason != _URC_HANDLER_FOUND)1004call_terminate(native_exception, unwind_exception);1005}1006// Jump to the handler1007set_registers(unwind_exception, context, results);1008return _URC_INSTALL_CONTEXT;1009}1010// Either we didn't do a phase 1 search (due to forced unwinding), or1011// phase 1 reported no catching-handlers.1012// Search for a (non-catching) cleanup1013scan_eh_tab(results, actions, native_exception, unwind_exception, context);1014if (results.reason == _URC_HANDLER_FOUND)1015{1016// Found a non-catching handler. Jump to it:1017set_registers(unwind_exception, context, results);1018return _URC_INSTALL_CONTEXT;1019}1020// Did not find a cleanup. Return the results of the scan1021// (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR1022// if we were called improperly).1023return results.reason;1024}1025// We were called improperly: neither a phase 1 or phase 2 search1026return _URC_FATAL_PHASE1_ERROR;1027}10281029#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)1030extern "C" _LIBCXXABI_FUNC_VIS EXCEPTION_DISPOSITION1031__gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame,1032PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)1033{1034return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp,1035__gxx_personality_imp);1036}1037#endif10381039#else10401041extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*,1042_Unwind_Context*);10431044// Helper function to unwind one frame.1045// ARM EHABI 7.3 and 7.4: If the personality function returns _URC_CONTINUE_UNWIND, the1046// personality routine should update the virtual register set (VRS) according to the1047// corresponding frame unwinding instructions (ARM EHABI 9.3.)1048static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception,1049_Unwind_Context* context)1050{1051if (__gnu_unwind_frame(unwind_exception, context) != _URC_OK)1052return _URC_FAILURE;1053return _URC_CONTINUE_UNWIND;1054}10551056// ARM register names1057#if !defined(LIBCXXABI_USE_LLVM_UNWINDER)1058static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block1059#endif1060static const uint32_t REG_SP = 13;10611062static void save_results_to_barrier_cache(_Unwind_Exception* unwind_exception,1063const scan_results& results)1064{1065unwind_exception->barrier_cache.bitpattern[0] = (uint32_t)results.adjustedPtr;1066unwind_exception->barrier_cache.bitpattern[1] = (uint32_t)results.actionRecord;1067unwind_exception->barrier_cache.bitpattern[2] = (uint32_t)results.languageSpecificData;1068unwind_exception->barrier_cache.bitpattern[3] = (uint32_t)results.landingPad;1069unwind_exception->barrier_cache.bitpattern[4] = (uint32_t)results.ttypeIndex;1070}10711072static void load_results_from_barrier_cache(scan_results& results,1073const _Unwind_Exception* unwind_exception)1074{1075results.adjustedPtr = (void*)unwind_exception->barrier_cache.bitpattern[0];1076results.actionRecord = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[1];1077results.languageSpecificData = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2];1078results.landingPad = (uintptr_t)unwind_exception->barrier_cache.bitpattern[3];1079results.ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4];1080}10811082extern "C" _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code1083__gxx_personality_v0(_Unwind_State state,1084_Unwind_Exception* unwind_exception,1085_Unwind_Context* context)1086{1087if (unwind_exception == 0 || context == 0)1088return _URC_FATAL_PHASE1_ERROR;10891090bool native_exception = __isOurExceptionClass(unwind_exception);10911092#if !defined(LIBCXXABI_USE_LLVM_UNWINDER)1093// Copy the address of _Unwind_Control_Block to r12 so that1094// _Unwind_GetLanguageSpecificData() and _Unwind_GetRegionStart() can1095// return correct address.1096_Unwind_SetGR(context, REG_UCB, reinterpret_cast<uint32_t>(unwind_exception));1097#endif10981099// Check the undocumented force unwinding behavior1100bool is_force_unwinding = state & _US_FORCE_UNWIND;1101state &= ~_US_FORCE_UNWIND;11021103scan_results results;1104switch (state) {1105case _US_VIRTUAL_UNWIND_FRAME:1106if (is_force_unwinding)1107return continue_unwind(unwind_exception, context);11081109// Phase 1 search: All we're looking for in phase 1 is a handler that halts unwinding1110scan_eh_tab(results, _UA_SEARCH_PHASE, native_exception, unwind_exception, context);1111if (results.reason == _URC_HANDLER_FOUND)1112{1113unwind_exception->barrier_cache.sp = _Unwind_GetGR(context, REG_SP);1114if (native_exception)1115save_results_to_barrier_cache(unwind_exception, results);1116return _URC_HANDLER_FOUND;1117}1118// Did not find the catch handler1119if (results.reason == _URC_CONTINUE_UNWIND)1120return continue_unwind(unwind_exception, context);1121return results.reason;11221123case _US_UNWIND_FRAME_STARTING:1124// TODO: Support force unwinding in the phase 2 search.1125// NOTE: In order to call the cleanup functions, _Unwind_ForcedUnwind()1126// will call this personality function with (_US_FORCE_UNWIND |1127// _US_UNWIND_FRAME_STARTING).11281129// Phase 2 search1130if (unwind_exception->barrier_cache.sp == _Unwind_GetGR(context, REG_SP))1131{1132// Found a catching handler in phase 11133if (native_exception)1134{1135// Load the result from the native exception barrier cache.1136load_results_from_barrier_cache(results, unwind_exception);1137results.reason = _URC_HANDLER_FOUND;1138}1139else1140{1141// Search for the catching handler again for the foreign exception.1142scan_eh_tab(results, static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME),1143native_exception, unwind_exception, context);1144if (results.reason != _URC_HANDLER_FOUND) // phase1 search should guarantee to find one1145call_terminate(native_exception, unwind_exception);1146}11471148// Install the context for the catching handler1149set_registers(unwind_exception, context, results);1150return _URC_INSTALL_CONTEXT;1151}11521153// Either we didn't do a phase 1 search (due to forced unwinding), or1154// phase 1 reported no catching-handlers.1155// Search for a (non-catching) cleanup1156scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, context);1157if (results.reason == _URC_HANDLER_FOUND)1158{1159// Found a non-catching handler11601161// ARM EHABI 8.4.2: Before we can jump to the cleanup handler, we have to setup some1162// internal data structures, so that __cxa_end_cleanup() can get unwind_exception from1163// __cxa_get_globals().1164__cxa_begin_cleanup(unwind_exception);11651166// Install the context for the cleanup handler1167set_registers(unwind_exception, context, results);1168return _URC_INSTALL_CONTEXT;1169}11701171// Did not find any handler1172if (results.reason == _URC_CONTINUE_UNWIND)1173return continue_unwind(unwind_exception, context);1174return results.reason;11751176case _US_UNWIND_FRAME_RESUME:1177return continue_unwind(unwind_exception, context);1178}11791180// We were called improperly: neither a phase 1 or phase 2 search1181return _URC_FATAL_PHASE1_ERROR;1182}1183#endif118411851186__attribute__((noreturn))1187_LIBCXXABI_FUNC_VIS void1188__cxa_call_unexpected(void* arg)1189{1190_Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);1191if (unwind_exception == 0)1192call_terminate(false, unwind_exception);1193__cxa_begin_catch(unwind_exception);1194bool native_old_exception = __isOurExceptionClass(unwind_exception);1195std::unexpected_handler u_handler;1196std::terminate_handler t_handler;1197__cxa_exception* old_exception_header = 0;1198int64_t ttypeIndex;1199const uint8_t* lsda;1200if (native_old_exception)1201{1202old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1;1203t_handler = old_exception_header->terminateHandler;1204u_handler = old_exception_header->unexpectedHandler;1205// If std::__unexpected(u_handler) rethrows the same exception,1206// these values get overwritten by the rethrow. So save them now:1207#if defined(_LIBCXXABI_ARM_EHABI)1208ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4];1209lsda = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2];1210#else1211ttypeIndex = old_exception_header->handlerSwitchValue;1212lsda = old_exception_header->languageSpecificData;1213#endif1214}1215else1216{1217t_handler = std::get_terminate();1218u_handler = std::get_unexpected();1219}1220try1221{1222std::__unexpected(u_handler);1223}1224catch (...)1225{1226// If the old exception is foreign, then all we can do is terminate.1227// We have no way to recover the needed old exception spec. There's1228// no way to pass that information here. And the personality routine1229// can't call us directly and do anything but terminate() if we throw1230// from here.1231if (native_old_exception)1232{1233// Have:1234// old_exception_header->languageSpecificData1235// old_exception_header->actionRecord1236// Need1237// const uint8_t* classInfo1238// uint8_t ttypeEncoding1239uint8_t lpStartEncoding = *lsda++;1240const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);1241(void)lpStart; // purposefully unused. Just needed to increment lsda.1242uint8_t ttypeEncoding = *lsda++;1243if (ttypeEncoding == DW_EH_PE_omit)1244std::__terminate(t_handler);1245uintptr_t classInfoOffset = readULEB128(&lsda);1246const uint8_t* classInfo = lsda + classInfoOffset;1247// Is this new exception catchable by the exception spec at ttypeIndex?1248// The answer is obviously yes if the new and old exceptions are the same exception1249// If no1250// throw;1251__cxa_eh_globals* globals = __cxa_get_globals_fast();1252__cxa_exception* new_exception_header = globals->caughtExceptions;1253if (new_exception_header == 0)1254// This shouldn't be able to happen!1255std::__terminate(t_handler);1256bool native_new_exception = __isOurExceptionClass(&new_exception_header->unwindHeader);1257void* adjustedPtr;1258if (native_new_exception && (new_exception_header != old_exception_header))1259{1260const __shim_type_info* excpType =1261static_cast<const __shim_type_info*>(new_exception_header->exceptionType);1262adjustedPtr =1263__getExceptionClass(&new_exception_header->unwindHeader) == kOurDependentExceptionClass ?1264((__cxa_dependent_exception*)new_exception_header)->primaryException :1265new_exception_header + 1;1266if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding,1267excpType, adjustedPtr, unwind_exception))1268{1269// We need to __cxa_end_catch, but for the old exception,1270// not the new one. This is a little tricky ...1271// Disguise new_exception_header as a rethrown exception, but1272// don't actually rethrow it. This means you can temporarily1273// end the catch clause enclosing new_exception_header without1274// __cxa_end_catch destroying new_exception_header.1275new_exception_header->handlerCount = -new_exception_header->handlerCount;1276globals->uncaughtExceptions += 1;1277// Call __cxa_end_catch for new_exception_header1278__cxa_end_catch();1279// Call __cxa_end_catch for old_exception_header1280__cxa_end_catch();1281// Renter this catch clause with new_exception_header1282__cxa_begin_catch(&new_exception_header->unwindHeader);1283// Rethrow new_exception_header1284throw;1285}1286}1287// Will a std::bad_exception be catchable by the exception spec at1288// ttypeIndex?1289// If no1290// throw std::bad_exception();1291const __shim_type_info* excpType =1292static_cast<const __shim_type_info*>(&typeid(std::bad_exception));1293std::bad_exception be;1294adjustedPtr = &be;1295if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding,1296excpType, adjustedPtr, unwind_exception))1297{1298// We need to __cxa_end_catch for both the old exception and the1299// new exception. Technically we should do it in that order.1300// But it is expedient to do it in the opposite order:1301// Call __cxa_end_catch for new_exception_header1302__cxa_end_catch();1303// Throw std::bad_exception will __cxa_end_catch for1304// old_exception_header1305throw be;1306}1307}1308}1309std::__terminate(t_handler);1310}13111312} // extern "C"13131314} // __cxxabiv1131513161317