diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp --- a/libcxxabi/src/cxa_personality.cpp +++ b/libcxxabi/src/cxa_personality.cpp @@ -88,7 +88,7 @@ | +-------------+---------------------------------+------------------------------+ | | ... | +----------------------------------------------------------------------------------+ -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // __USING_SJLJ_EXCEPTIONS__ +---------------------------------------------------------------------+ | Beginning of Action Table ttypeIndex == 0 : cleanup | | ... ttypeIndex > 0 : catch | @@ -241,74 +241,75 @@ /// @link http://dwarfstd.org/Dwarf3.pdf @unlink /// @param data reference variable holding memory pointer to decode from /// @param encoding dwarf encoding type +/// @param base for adding relative offset, default to 0 /// @returns decoded value -static -uintptr_t -readEncodedPointer(const uint8_t** data, uint8_t encoding) -{ - uintptr_t result = 0; - if (encoding == DW_EH_PE_omit) - return result; - const uint8_t* p = *data; - // first get value - switch (encoding & 0x0F) - { - case DW_EH_PE_absptr: - result = readPointerHelper(p); - break; - case DW_EH_PE_uleb128: - result = readULEB128(&p); - break; - case DW_EH_PE_sleb128: - result = static_cast(readSLEB128(&p)); - break; - case DW_EH_PE_udata2: - result = readPointerHelper(p); - break; - case DW_EH_PE_udata4: - result = readPointerHelper(p); - break; - case DW_EH_PE_udata8: - result = readPointerHelper(p); - break; - case DW_EH_PE_sdata2: - result = readPointerHelper(p); - break; - case DW_EH_PE_sdata4: - result = readPointerHelper(p); - break; - case DW_EH_PE_sdata8: - result = readPointerHelper(p); - break; - default: - // not supported - abort(); - break; - } - // then add relative offset - switch (encoding & 0x70) - { - case DW_EH_PE_absptr: - // do nothing - break; - case DW_EH_PE_pcrel: - if (result) - result += (uintptr_t)(*data); - break; - case DW_EH_PE_textrel: - case DW_EH_PE_datarel: - case DW_EH_PE_funcrel: - case DW_EH_PE_aligned: - default: - // not supported - abort(); - break; - } - // then apply indirection - if (result && (encoding & DW_EH_PE_indirect)) - result = *((uintptr_t*)result); - *data = p; +static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding, + uintptr_t base = 0) { + uintptr_t result = 0; + if (encoding == DW_EH_PE_omit) return result; + const uint8_t* p = *data; + // first get value + switch (encoding & 0x0F) { + case DW_EH_PE_absptr: + result = readPointerHelper(p); + break; + case DW_EH_PE_uleb128: + result = readULEB128(&p); + break; + case DW_EH_PE_sleb128: + result = static_cast(readSLEB128(&p)); + break; + case DW_EH_PE_udata2: + result = readPointerHelper(p); + break; + case DW_EH_PE_udata4: + result = readPointerHelper(p); + break; + case DW_EH_PE_udata8: + result = readPointerHelper(p); + break; + case DW_EH_PE_sdata2: + result = readPointerHelper(p); + break; + case DW_EH_PE_sdata4: + result = readPointerHelper(p); + break; + case DW_EH_PE_sdata8: + result = readPointerHelper(p); + break; + default: + // not supported + abort(); + break; + } + // then add relative offset + switch (encoding & 0x70) { + case DW_EH_PE_absptr: + // do nothing + break; + case DW_EH_PE_pcrel: + if (result) + result += (uintptr_t)(*data); + break; + case DW_EH_PE_datarel: + assert((base != 0) && "DW_EH_PE_datarel is invalid with a base of 0"); + if (result) + result += base; + break; + case DW_EH_PE_textrel: + case DW_EH_PE_funcrel: + case DW_EH_PE_aligned: + default: + // not supported + abort(); + break; + } + // then apply indirection + if (result && (encoding & DW_EH_PE_indirect)) + result = *((uintptr_t*)result); + *data = p; + return result; } static @@ -348,59 +349,55 @@ static const __shim_type_info* get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, uint8_t ttypeEncoding, bool native_exception, - _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(native_exception, unwind_exception); - } - - assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 - (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal - (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux - "Unexpected TTypeEncoding"); - (void)ttypeEncoding; - - const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t); - return reinterpret_cast( - read_target2_value(ttypePtr)); + _Unwind_Exception* unwind_exception, uintptr_t base = 0) { + if (classInfo == 0) { + // this should not happen. Indicates corrupted eh_table. + call_terminate(native_exception, unwind_exception); + } + + assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 + (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal + (ttypeEncoding == + (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux + "Unexpected TTypeEncoding"); + (void)ttypeEncoding; + + const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t); + return reinterpret_cast( + read_target2_value(ttypePtr)); } #else // !defined(_LIBCXXABI_ARM_EHABI) -static -const __shim_type_info* +static const __shim_type_info* get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, uint8_t ttypeEncoding, bool native_exception, - _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(native_exception, unwind_exception); - } - switch (ttypeEncoding & 0x0F) - { - case DW_EH_PE_absptr: - ttypeIndex *= sizeof(void*); - break; - case DW_EH_PE_udata2: - case DW_EH_PE_sdata2: - ttypeIndex *= 2; - break; - case DW_EH_PE_udata4: - case DW_EH_PE_sdata4: - ttypeIndex *= 4; - break; - case DW_EH_PE_udata8: - case DW_EH_PE_sdata8: - ttypeIndex *= 8; - break; - default: - // this should not happen. Indicates corrupted eh_table. - call_terminate(native_exception, unwind_exception); - } - classInfo -= ttypeIndex; - return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding); + _Unwind_Exception* unwind_exception, uintptr_t base = 0) { + if (classInfo == 0) { + // this should not happen. Indicates corrupted eh_table. + call_terminate(native_exception, unwind_exception); + } + switch (ttypeEncoding & 0x0F) { + case DW_EH_PE_absptr: + ttypeIndex *= sizeof(void*); + break; + case DW_EH_PE_udata2: + case DW_EH_PE_sdata2: + ttypeIndex *= 2; + break; + case DW_EH_PE_udata4: + case DW_EH_PE_sdata4: + ttypeIndex *= 4; + break; + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: + ttypeIndex *= 8; + break; + default: + // this should not happen. Indicates corrupted eh_table. + call_terminate(native_exception, unwind_exception); + } + classInfo -= ttypeIndex; + return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding, + base); } #endif // !defined(_LIBCXXABI_ARM_EHABI) @@ -414,83 +411,73 @@ excpType, then this exception spec does not catch the excpType. */ #if defined(_LIBCXXABI_ARM_EHABI) -static -bool -exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, - uint8_t ttypeEncoding, const __shim_type_info* excpType, - void* adjustedPtr, _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(false, unwind_exception); - } - - assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 - (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal - (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux - "Unexpected TTypeEncoding"); - (void)ttypeEncoding; - - // specIndex is negative of 1-based byte offset into classInfo; - specIndex = -specIndex; - --specIndex; - const void** temp = reinterpret_cast( - reinterpret_cast(classInfo) + - static_cast(specIndex) * sizeof(uintptr_t)); - // If any type in the spec list can catch excpType, return false, else return true - // adjustments to adjustedPtr are ignored. - while (true) - { - // ARM EHABI exception specification table (filter table) consists of - // several pointers which will directly point to the type info object - // (instead of ttypeIndex). The table will be terminated with 0. - const void** ttypePtr = temp++; - if (*ttypePtr == 0) - break; - // We can get the __shim_type_info simply by performing a - // R_ARM_TARGET2 relocation, and cast the result to __shim_type_info. - const __shim_type_info* catchType = - static_cast(read_target2_value(ttypePtr)); - void* tempPtr = adjustedPtr; - if (catchType->can_catch(excpType, tempPtr)) - return false; - } - return true; +static bool exception_spec_can_catch( + int64_t specIndex, const uint8_t* classInfo, uint8_t ttypeEncoding, + const __shim_type_info* excpType, void* adjustedPtr, + _Unwind_Exception* unwind_exception, uintptr_t base = 0) { + if (classInfo == 0) { + // this should not happen. Indicates corrupted eh_table. + call_terminate(false, unwind_exception); + } + + assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 + (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal + (ttypeEncoding == + (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux + "Unexpected TTypeEncoding"); + (void)ttypeEncoding; + + // specIndex is negative of 1-based byte offset into classInfo; + specIndex = -specIndex; + --specIndex; + const void** temp = reinterpret_cast( + reinterpret_cast(classInfo) + + static_cast(specIndex) * sizeof(uintptr_t)); + // If any type in the spec list can catch excpType, return false, else return true + // adjustments to adjustedPtr are ignored. + while (true) { + // ARM EHABI exception specification table (filter table) consists of + // several pointers which will directly point to the type info object + // (instead of ttypeIndex). The table will be terminated with 0. + const void** ttypePtr = temp++; + if (*ttypePtr == 0) + break; + // We can get the __shim_type_info simply by performing a + // R_ARM_TARGET2 relocation, and cast the result to __shim_type_info. + const __shim_type_info* catchType = + static_cast(read_target2_value(ttypePtr)); + void* tempPtr = adjustedPtr; + if (catchType->can_catch(excpType, tempPtr)) + return false; + } + return true; } #else -static -bool -exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, - uint8_t ttypeEncoding, const __shim_type_info* excpType, - void* adjustedPtr, _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(false, unwind_exception); - } - // specIndex is negative of 1-based byte offset into classInfo; - specIndex = -specIndex; - --specIndex; - const uint8_t* temp = classInfo + specIndex; - // If any type in the spec list can catch excpType, return false, else return true - // adjustments to adjustedPtr are ignored. - while (true) - { - uint64_t ttypeIndex = readULEB128(&temp); - if (ttypeIndex == 0) - break; - const __shim_type_info* catchType = get_shim_type_info(ttypeIndex, - classInfo, - ttypeEncoding, - true, - unwind_exception); - void* tempPtr = adjustedPtr; - if (catchType->can_catch(excpType, tempPtr)) - return false; - } - return true; +static bool exception_spec_can_catch( + int64_t specIndex, const uint8_t* classInfo, uint8_t ttypeEncoding, + const __shim_type_info* excpType, void* adjustedPtr, + _Unwind_Exception* unwind_exception, uintptr_t base = 0) { + if (classInfo == 0) { + // this should not happen. Indicates corrupted eh_table. + call_terminate(false, unwind_exception); + } + // specIndex is negative of 1-based byte offset into classInfo; + specIndex = -specIndex; + --specIndex; + const uint8_t* temp = classInfo + specIndex; + // If any type in the spec list can catch excpType, return false, else return true + // adjustments to adjustedPtr are ignored. + while (true) { + uint64_t ttypeIndex = readULEB128(&temp); + if (ttypeIndex == 0) + break; + const __shim_type_info* catchType = get_shim_type_info( + ttypeIndex, classInfo, ttypeEncoding, true, unwind_exception, base); + void* tempPtr = adjustedPtr; + if (catchType->can_catch(excpType, tempPtr)) + return false; + } + return true; } #endif @@ -531,6 +518,9 @@ { #if defined(__USING_SJLJ_EXCEPTIONS__) #define __builtin_eh_return_data_regno(regno) regno +#elif defined(__ibmxl__) +// IBM xlclang++ compiler does not support __builtin_eh_return_data_regno. +#define __builtin_eh_return_data_regno(regno) regno + 3 #endif _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), reinterpret_cast(unwind_exception)); @@ -610,6 +600,11 @@ return; } results.languageSpecificData = lsda; +#if defined(_AIX) + uintptr_t base = _Unwind_GetDataRelBase(context); +#else + uintptr_t base = 0; +#endif // Get the current instruction pointer and offset it before next // instruction in the current frame which threw the exception. uintptr_t ip = _Unwind_GetIP(context) - 1; @@ -675,7 +670,7 @@ if (--ip == 0) #endif // __USING_SJLJ_EXCEPTIONS__ { - // Found the call site containing ip. + // Found the call site containing ip. #ifndef __USING_SJLJ_EXCEPTIONS__ if (landingPad == 0) { @@ -708,10 +703,10 @@ { // Found a catch, does it actually catch? // First check for catch (...) - const __shim_type_info* catchType = - get_shim_type_info(static_cast(ttypeIndex), - classInfo, ttypeEncoding, - native_exception, unwind_exception); + const __shim_type_info* catchType = get_shim_type_info( + static_cast(ttypeIndex), classInfo, + ttypeEncoding, native_exception, unwind_exception, + base); if (catchType == 0) { // Found catch (...) catches everything, including @@ -770,18 +765,17 @@ // Something very bad happened call_terminate(native_exception, unwind_exception); } - if (exception_spec_can_catch(ttypeIndex, classInfo, - ttypeEncoding, excpType, - adjustedPtr, unwind_exception)) - { - // Native exception caught by exception - // specification. - assert(actions & _UA_SEARCH_PHASE); - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.adjustedPtr = adjustedPtr; - results.reason = _URC_HANDLER_FOUND; - return; + if (exception_spec_can_catch( + ttypeIndex, classInfo, ttypeEncoding, excpType, + adjustedPtr, unwind_exception, base)) { + // Native exception caught by exception + // specification. + assert(actions & _UA_SEARCH_PHASE); + results.ttypeIndex = ttypeIndex; + results.actionRecord = actionRecord; + results.adjustedPtr = adjustedPtr; + results.reason = _URC_HANDLER_FOUND; + return; } } else { // foreign exception caught by exception spec @@ -813,8 +807,7 @@ } // there is no break out of this loop, only return } #ifndef __USING_SJLJ_EXCEPTIONS__ - else if (ipOffset < start) - { + else if (ipOffset < start) { // There is no call site for this ip // Something bad has happened. We should never get here. // Possible stack corruption. @@ -911,6 +904,12 @@ // Jump to the handler. set_registers(unwind_exception, context, results); +#if defined(_AIX) + // Cache ttype base for __cxa_call_unexpected. + if (results.ttypeIndex < 0) { + exception_header->catchTemp = (void*)_Unwind_GetDataRelBase(context); + } +#endif return _URC_INSTALL_CONTEXT; } @@ -940,6 +939,14 @@ assert(actions & _UA_CLEANUP_PHASE); assert(results.reason == _URC_HANDLER_FOUND); set_registers(unwind_exception, context, results); +#if defined(_AIX) + // Cache ttype base for __cxa_call_unexpected. + if (results.ttypeIndex < 0) { + __cxa_exception* exception_header = + (__cxa_exception*)(unwind_exception + 1) - 1; + exception_header->catchTemp = (void*)_Unwind_GetDataRelBase(context); + } +#endif return _URC_INSTALL_CONTEXT; } @@ -1114,6 +1121,8 @@ __cxa_exception* old_exception_header = 0; int64_t ttypeIndex; const uint8_t* lsda; + uintptr_t base = 0; + if (native_old_exception) { old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1; @@ -1127,6 +1136,7 @@ #else ttypeIndex = old_exception_header->handlerSwitchValue; lsda = old_exception_header->languageSpecificData; + base = (uintptr_t)old_exception_header->catchTemp; #endif } else @@ -1147,60 +1157,67 @@ // from here. if (native_old_exception) { - // Have: - // old_exception_header->languageSpecificData - // old_exception_header->actionRecord - // Need - // const uint8_t* classInfo - // uint8_t ttypeEncoding - uint8_t lpStartEncoding = *lsda++; - const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); - (void)lpStart; // purposefully unused. Just needed to increment lsda. - uint8_t ttypeEncoding = *lsda++; - if (ttypeEncoding == DW_EH_PE_omit) - std::__terminate(t_handler); - uintptr_t classInfoOffset = readULEB128(&lsda); - const uint8_t* classInfo = lsda + classInfoOffset; - // Is this new exception catchable by the exception spec at ttypeIndex? - // The answer is obviously yes if the new and old exceptions are the same exception - // If no - // throw; - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - __cxa_exception* new_exception_header = globals->caughtExceptions; - if (new_exception_header == 0) - // This shouldn't be able to happen! - std::__terminate(t_handler); - bool native_new_exception = __isOurExceptionClass(&new_exception_header->unwindHeader); - void* adjustedPtr; - if (native_new_exception && (new_exception_header != old_exception_header)) - { - const __shim_type_info* excpType = - static_cast(new_exception_header->exceptionType); - adjustedPtr = - __getExceptionClass(&new_exception_header->unwindHeader) == kOurDependentExceptionClass ? - ((__cxa_dependent_exception*)new_exception_header)->primaryException : - new_exception_header + 1; - if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, - excpType, adjustedPtr, unwind_exception)) - { - // We need to __cxa_end_catch, but for the old exception, - // not the new one. This is a little tricky ... - // Disguise new_exception_header as a rethrown exception, but - // don't actually rethrow it. This means you can temporarily - // end the catch clause enclosing new_exception_header without - // __cxa_end_catch destroying new_exception_header. - new_exception_header->handlerCount = -new_exception_header->handlerCount; - globals->uncaughtExceptions += 1; - // Call __cxa_end_catch for new_exception_header - __cxa_end_catch(); - // Call __cxa_end_catch for old_exception_header - __cxa_end_catch(); - // Renter this catch clause with new_exception_header - __cxa_begin_catch(&new_exception_header->unwindHeader); - // Rethrow new_exception_header - throw; - } + // Have: + // old_exception_header->languageSpecificData + // old_exception_header->actionRecord + // old_exception_header->catchTemp, i.e., ttype_base + // Need + // const uint8_t* classInfo + // uint8_t ttypeEncoding + uint8_t lpStartEncoding = *lsda++; + const uint8_t* lpStart = + (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); + (void)lpStart; // purposefully unused. Just needed to increment lsda. + uint8_t ttypeEncoding = *lsda++; + if (ttypeEncoding == DW_EH_PE_omit) + std::__terminate(t_handler); + uintptr_t classInfoOffset = readULEB128(&lsda); + const uint8_t* classInfo = lsda + classInfoOffset; + // Is this new exception catchable by the exception spec at ttypeIndex? + // The answer is obviously yes if the new and old exceptions are the same exception + // If no + // throw; + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + __cxa_exception* new_exception_header = globals->caughtExceptions; + if (new_exception_header == 0) + // This shouldn't be able to happen! + std::__terminate(t_handler); + bool native_new_exception = + __isOurExceptionClass(&new_exception_header->unwindHeader); + void* adjustedPtr; + if (native_new_exception && + (new_exception_header != old_exception_header)) { + const __shim_type_info* excpType = + static_cast( + new_exception_header->exceptionType); + adjustedPtr = + __getExceptionClass(&new_exception_header->unwindHeader) == + kOurDependentExceptionClass + ? ((__cxa_dependent_exception*)new_exception_header) + ->primaryException + : new_exception_header + 1; + if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, + excpType, adjustedPtr, + unwind_exception, base)) { + // We need to __cxa_end_catch, but for the old exception, + // not the new one. This is a little tricky ... + // Disguise new_exception_header as a rethrown exception, but + // don't actually rethrow it. This means you can temporarily + // end the catch clause enclosing new_exception_header without + // __cxa_end_catch destroying new_exception_header. + new_exception_header->handlerCount = + -new_exception_header->handlerCount; + globals->uncaughtExceptions += 1; + // Call __cxa_end_catch for new_exception_header + __cxa_end_catch(); + // Call __cxa_end_catch for old_exception_header + __cxa_end_catch(); + // Renter this catch clause with new_exception_header + __cxa_begin_catch(&new_exception_header->unwindHeader); + // Rethrow new_exception_header + throw; } + } // Will a std::bad_exception be catchable by the exception spec at // ttypeIndex? // If no @@ -1210,16 +1227,16 @@ std::bad_exception be; adjustedPtr = &be; if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, - excpType, adjustedPtr, unwind_exception)) - { - // We need to __cxa_end_catch for both the old exception and the - // new exception. Technically we should do it in that order. - // But it is expedient to do it in the opposite order: - // Call __cxa_end_catch for new_exception_header - __cxa_end_catch(); - // Throw std::bad_exception will __cxa_end_catch for - // old_exception_header - throw be; + excpType, adjustedPtr, + unwind_exception, base)) { + // We need to __cxa_end_catch for both the old exception and the + // new exception. Technically we should do it in that order. + // But it is expedient to do it in the opposite order: + // Call __cxa_end_catch for new_exception_header + __cxa_end_catch(); + // Throw std::bad_exception will __cxa_end_catch for + // old_exception_header + throw be; } } }