From d105b0c1435cb5a8cc31eadd8a92f774b440f507 Mon Sep 17 00:00:00 2001 From: cqwrteur <100043421+trcrsired@users.noreply.github.com> Date: Sat, 1 Jun 2024 02:55:50 -0400 Subject: [PATCH] [libunwind][libcxx][libcxxabi] Fix Exception Handling build for wasm The wasm unwind build appears to be dysfunctional, likely because the author has only supplied a customized LLVM build on request, rather than a fully functional patch. This patch fixes the build Apply formatting patch proposed by github bot use "" to prevent CMAKE_SYSTEM_PROCESSOR not defined [libunwind] logAPI functions should also be built [libcxxabi] Fix function signatures for wasm wasm does not define the function signatures correctly for cxxabi Fix them Fix formatting issues for libcxxabi's wasm eh change Merge remote-tracking branch 'parent/main' into wasmlibunwindfix remove unwanted changes in unwind-wasm.c Make Unwind-wasm.c compile correctly without workaround in CMakeLists.txt using __wasm__ macro to guard against all wasm eh build fix UnwindLevel.c's formatting issue ISO C requires a translation unit to contain at least one declaration [-Werror,-Wempty-translation-unit] compiler-rt does not define CMP_RESULT correct on wasm64 Fixed Merge code --- compiler-rt/lib/builtins/fp_compare_impl.inc | 2 +- libcxx/include/__exception/exception_ptr.h | 21 +- libcxxabi/include/cxxabi.h | 179 ++--- libcxxabi/src/cxa_exception.cpp | 712 ++++++++----------- libcxxabi/src/cxa_exception.h | 7 +- libunwind/include/libunwind.h | 2 + libunwind/src/Unwind-wasm.c | 13 +- libunwind/src/UnwindRegistersRestore.S | 3 +- libunwind/src/UnwindRegistersSave.S | 3 + libunwind/src/assembly.h | 2 + libunwind/src/cet_unwind.h | 3 + libunwind/src/config.h | 15 +- libunwind/src/libunwind.cpp | 2 + libunwind/src/libunwind_ext.h | 2 + 14 files changed, 423 insertions(+), 543 deletions(-) diff --git a/compiler-rt/lib/builtins/fp_compare_impl.inc b/compiler-rt/lib/builtins/fp_compare_impl.inc index a9a4f6fbf5dfe4..83bdea46a45da4 100644 --- a/compiler-rt/lib/builtins/fp_compare_impl.inc +++ b/compiler-rt/lib/builtins/fp_compare_impl.inc @@ -12,7 +12,7 @@ // functions. We need to ensure that the return value is sign-extended in the // same way as GCC expects (since otherwise GCC-generated __builtin_isinf // returns true for finite 128-bit floating-point numbers). -#ifdef __aarch64__ +#if defined(__aarch64__) || defined(__wasm__) // AArch64 GCC overrides libgcc_cmp_return to use int instead of long. typedef int CMP_RESULT; #elif __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 4 diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h index 0a8337fa39de39..01f340a587ec37 100644 --- a/libcxx/include/__exception/exception_ptr.h +++ b/libcxx/include/__exception/exception_ptr.h @@ -29,22 +29,21 @@ namespace __cxxabiv1 { +# if defined(__wasm__) +typedef void* (*__libcpp_exception_destructor_func)(void*); +# elif defined(_WIN32) +typedef void(__thiscall* __libcpp_exception_destructor_func)(void*); +# else +typedef void (*__libcpp_exception_destructor_func)(void*); +# endif + extern "C" { _LIBCPP_OVERRIDABLE_FUNC_VIS void* __cxa_allocate_exception(size_t) throw(); _LIBCPP_OVERRIDABLE_FUNC_VIS void __cxa_free_exception(void*) throw(); struct __cxa_exception; -_LIBCPP_OVERRIDABLE_FUNC_VIS __cxa_exception* __cxa_init_primary_exception( - void*, - std::type_info*, -# if defined(_WIN32) - void(__thiscall*)(void*)) throw(); -# elif defined(__wasm__) - // In Wasm, a destructor returns its argument - void* (*)(void*)) throw(); -# else - void (*)(void*)) throw(); -# endif +_LIBCPP_OVERRIDABLE_FUNC_VIS __cxa_exception* +__cxa_init_primary_exception(void*, std::type_info*, __libcpp_exception_destructor_func) throw(); } } // namespace __cxxabiv1 diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h index 0e3969084e04fd..4162fd7ec2ba77 100644 --- a/libcxxabi/include/cxxabi.h +++ b/libcxxabi/include/cxxabi.h @@ -20,62 +20,51 @@ #include <__cxxabi_config.h> #define _LIBCPPABI_VERSION 15000 -#define _LIBCXXABI_NORETURN __attribute__((noreturn)) +#define _LIBCXXABI_NORETURN __attribute__((noreturn)) #define _LIBCXXABI_ALWAYS_COLD __attribute__((cold)) #ifdef __cplusplus namespace std { -#if defined(_WIN32) +# if defined(_WIN32) class _LIBCXXABI_TYPE_VIS type_info; // forward declaration -#else +# else class type_info; // forward declaration -#endif -} - +# endif +} // namespace std // runtime routines use C calling conventions, but are in __cxxabiv1 namespace namespace __cxxabiv1 { struct __cxa_exception; +# if defined(__wasm__) +typedef void* (*__libcxxabi_exception_destructor_func)(void*); +# else +typedef void(_LIBCXXABI_DTOR_FUNC* __libcxxabi_exception_destructor_func)(void*); +# endif -extern "C" { +extern "C" { // 2.4.2 Allocating the Exception Object -extern _LIBCXXABI_FUNC_VIS void * -__cxa_allocate_exception(size_t thrown_size) throw(); -extern _LIBCXXABI_FUNC_VIS void -__cxa_free_exception(void *thrown_exception) throw(); +extern _LIBCXXABI_FUNC_VIS void* __cxa_allocate_exception(size_t thrown_size) throw(); +extern _LIBCXXABI_FUNC_VIS void __cxa_free_exception(void* thrown_exception) throw(); // This function is an LLVM extension, which mirrors the same extension in libsupc++ and libcxxrt -extern _LIBCXXABI_FUNC_VIS __cxa_exception* -#ifdef __wasm__ -// In Wasm, a destructor returns its argument -__cxa_init_primary_exception(void* object, std::type_info* tinfo, void*(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw(); -#else -__cxa_init_primary_exception(void* object, std::type_info* tinfo, void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw(); -#endif +extern _LIBCXXABI_FUNC_VIS __cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinfo, + __libcxxabi_exception_destructor_func) throw(); // 2.4.3 Throwing the Exception Object -extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void -__cxa_throw(void *thrown_exception, std::type_info *tinfo, -#ifdef __wasm__ - void *(_LIBCXXABI_DTOR_FUNC *dest)(void *)); -#else - void (_LIBCXXABI_DTOR_FUNC *dest)(void *)); -#endif +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_throw(void* thrown_exception, std::type_info* tinfo, + __libcxxabi_exception_destructor_func); // 2.5.3 Exception Handlers -extern _LIBCXXABI_FUNC_VIS void * -__cxa_get_exception_ptr(void *exceptionObject) throw(); -extern _LIBCXXABI_FUNC_VIS void * -__cxa_begin_catch(void *exceptionObject) throw(); +extern _LIBCXXABI_FUNC_VIS void* __cxa_get_exception_ptr(void* exceptionObject) throw(); +extern _LIBCXXABI_FUNC_VIS void* __cxa_begin_catch(void* exceptionObject) throw(); extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch(); -#if defined(_LIBCXXABI_ARM_EHABI) -extern _LIBCXXABI_FUNC_VIS bool -__cxa_begin_cleanup(void *exceptionObject) throw(); +# if defined(_LIBCXXABI_ARM_EHABI) +extern _LIBCXXABI_FUNC_VIS bool __cxa_begin_cleanup(void* exceptionObject) throw(); extern _LIBCXXABI_FUNC_VIS void __cxa_end_cleanup(); -#endif -extern _LIBCXXABI_FUNC_VIS std::type_info *__cxa_current_exception_type(); +# endif +extern _LIBCXXABI_FUNC_VIS std::type_info* __cxa_current_exception_type(); // 2.5.4 Rethrowing Exceptions extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_rethrow(); @@ -83,8 +72,7 @@ extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_rethrow(); // 2.6 Auxiliary Runtime APIs extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void); extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void); -extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void -__cxa_throw_bad_array_new_length(void); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_throw_bad_array_new_length(void); // 3.2.6 Pure Virtual Function API extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_pure_virtual(void); @@ -93,63 +81,49 @@ extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_pure_virtual(void); extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_deleted_virtual(void); // 3.3.2 One-time Construction API -#if defined(_LIBCXXABI_GUARD_ABI_ARM) -extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD int __cxa_guard_acquire(uint32_t *); -extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_release(uint32_t *); -extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_abort(uint32_t *); -#else -extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD int __cxa_guard_acquire(uint64_t *); -extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_release(uint64_t *); -extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_abort(uint64_t *); -#endif +# if defined(_LIBCXXABI_GUARD_ABI_ARM) +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD int __cxa_guard_acquire(uint32_t*); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_release(uint32_t*); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_abort(uint32_t*); +# else +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD int __cxa_guard_acquire(uint64_t*); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_release(uint64_t*); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_ALWAYS_COLD void __cxa_guard_abort(uint64_t*); +# endif // 3.3.3 Array Construction and Destruction API -extern _LIBCXXABI_FUNC_VIS void * -__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size, - void (*constructor)(void *), void (*destructor)(void *)); - -extern _LIBCXXABI_FUNC_VIS void * -__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size, - void (*constructor)(void *), void (*destructor)(void *), - void *(*alloc)(size_t), void (*dealloc)(void *)); - -extern _LIBCXXABI_FUNC_VIS void * -__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size, - void (*constructor)(void *), void (*destructor)(void *), - void *(*alloc)(size_t), void (*dealloc)(void *, size_t)); - -extern _LIBCXXABI_FUNC_VIS void -__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size, - void (*constructor)(void *), void (*destructor)(void *)); - -extern _LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address, - size_t element_count, - size_t element_size, - void (*destructor)(void *)); - -extern _LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address, - size_t element_count, - size_t element_size, - void (*destructor)(void *)); - -extern _LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address, - size_t element_size, - size_t padding_size, - void (*destructor)(void *)); - -extern _LIBCXXABI_FUNC_VIS void -__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size, - void (*destructor)(void *), void (*dealloc)(void *)); - -extern _LIBCXXABI_FUNC_VIS void -__cxa_vec_delete3(void *__array_address, size_t element_size, - size_t padding_size, void (*destructor)(void *), - void (*dealloc)(void *, size_t)); - -extern _LIBCXXABI_FUNC_VIS void -__cxa_vec_cctor(void *dest_array, void *src_array, size_t element_count, - size_t element_size, void (*constructor)(void *, void *), - void (*destructor)(void *)); +extern _LIBCXXABI_FUNC_VIS void* __cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size, + void (*constructor)(void*), void (*destructor)(void*)); + +extern _LIBCXXABI_FUNC_VIS void* __cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size, + void (*constructor)(void*), void (*destructor)(void*), + void* (*alloc)(size_t), void (*dealloc)(void*)); + +extern _LIBCXXABI_FUNC_VIS void* __cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size, + void (*constructor)(void*), void (*destructor)(void*), + void* (*alloc)(size_t), void (*dealloc)(void*, size_t)); + +extern _LIBCXXABI_FUNC_VIS void __cxa_vec_ctor(void* array_address, size_t element_count, size_t element_size, + void (*constructor)(void*), void (*destructor)(void*)); + +extern _LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void* array_address, size_t element_count, size_t element_size, + void (*destructor)(void*)); + +extern _LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void* array_address, size_t element_count, size_t element_size, + void (*destructor)(void*)); + +extern _LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void* array_address, size_t element_size, size_t padding_size, + void (*destructor)(void*)); + +extern _LIBCXXABI_FUNC_VIS void __cxa_vec_delete2(void* array_address, size_t element_size, size_t padding_size, + void (*destructor)(void*), void (*dealloc)(void*)); + +extern _LIBCXXABI_FUNC_VIS void __cxa_vec_delete3(void* __array_address, size_t element_size, size_t padding_size, + void (*destructor)(void*), void (*dealloc)(void*, size_t)); + +extern _LIBCXXABI_FUNC_VIS void __cxa_vec_cctor(void* dest_array, void* src_array, size_t element_count, + size_t element_size, void (*constructor)(void*, void*), + void (*destructor)(void*)); // 3.3.5.3 Runtime API // These functions are part of the C++ ABI, but they are not defined in libc++abi: @@ -157,30 +131,25 @@ __cxa_vec_cctor(void *dest_array, void *src_array, size_t element_count, // void __cxa_finalize(void *); // 3.4 Demangler API -extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name, - char *output_buffer, - size_t *length, int *status); +extern _LIBCXXABI_FUNC_VIS char* __cxa_demangle(const char* mangled_name, char* output_buffer, size_t* length, + int* status); // Apple additions to support C++ 0x exception_ptr class // These are primitives to wrap a smart pointer around an exception object -extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw(); -extern _LIBCXXABI_FUNC_VIS void -__cxa_rethrow_primary_exception(void *primary_exception); -extern _LIBCXXABI_FUNC_VIS void -__cxa_increment_exception_refcount(void *primary_exception) throw(); -extern _LIBCXXABI_FUNC_VIS void -__cxa_decrement_exception_refcount(void *primary_exception) throw(); +extern _LIBCXXABI_FUNC_VIS void* __cxa_current_primary_exception() throw(); +extern _LIBCXXABI_FUNC_VIS void __cxa_rethrow_primary_exception(void* primary_exception); +extern _LIBCXXABI_FUNC_VIS void __cxa_increment_exception_refcount(void* primary_exception) throw(); +extern _LIBCXXABI_FUNC_VIS void __cxa_decrement_exception_refcount(void* primary_exception) throw(); // Apple extension to support std::uncaught_exception() extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw(); extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw(); -#if defined(__linux__) || defined(__Fuchsia__) +# if defined(__linux__) || defined(__Fuchsia__) // Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI. // https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables -extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void *), void *, - void *) throw(); -#endif +extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void*), void*, void*) throw(); +# endif } // extern "C" } // namespace __cxxabiv1 diff --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp index ff69a4c65e465e..10d209fc5ceb41 100644 --- a/libcxxabi/src/cxa_exception.cpp +++ b/libcxxabi/src/cxa_exception.cpp @@ -12,15 +12,15 @@ #include "cxxabi.h" -#include // for std::terminate -#include // for memset +#include // for std::terminate +#include // for memset #include "cxa_exception.h" #include "cxa_handlers.h" #include "fallback_malloc.h" #include "include/atomic_support.h" // from libc++ #if __has_feature(address_sanitizer) -#include +# include #endif // +---------------------------+-----------------------------+---------------+ @@ -37,89 +37,67 @@ namespace __cxxabiv1 { // Utility routines -static -inline -__cxa_exception* -cxa_exception_from_thrown_object(void* thrown_object) -{ - return static_cast<__cxa_exception*>(thrown_object) - 1; +static inline __cxa_exception* cxa_exception_from_thrown_object(void* thrown_object) { + return static_cast<__cxa_exception*>(thrown_object) - 1; } // Note: This is never called when exception_header is masquerading as a // __cxa_dependent_exception. -static -inline -void* -thrown_object_from_cxa_exception(__cxa_exception* exception_header) -{ - return static_cast(exception_header + 1); +static inline void* thrown_object_from_cxa_exception(__cxa_exception* exception_header) { + return static_cast(exception_header + 1); } // Get the exception object from the unwind pointer. // Relies on the structure layout, where the unwind pointer is right in // front of the user's exception object -static -inline -__cxa_exception* -cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception) -{ - return cxa_exception_from_thrown_object(unwind_exception + 1 ); +static inline __cxa_exception* cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception) { + return cxa_exception_from_thrown_object(unwind_exception + 1); } // Round s up to next multiple of a. -static inline -size_t aligned_allocation_size(size_t s, size_t a) { - return (s + a - 1) & ~(a - 1); -} +static inline size_t aligned_allocation_size(size_t s, size_t a) { return (s + a - 1) & ~(a - 1); } -static inline -size_t cxa_exception_size_from_exception_thrown_size(size_t size) { - return aligned_allocation_size(size + sizeof (__cxa_exception), - alignof(__cxa_exception)); +static inline size_t cxa_exception_size_from_exception_thrown_size(size_t size) { + return aligned_allocation_size(size + sizeof(__cxa_exception), alignof(__cxa_exception)); } void __setExceptionClass(_Unwind_Exception* unwind_exception, uint64_t newValue) { - ::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue)); + ::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue)); } - static void setOurExceptionClass(_Unwind_Exception* unwind_exception) { - __setExceptionClass(unwind_exception, kOurExceptionClass); + __setExceptionClass(unwind_exception, kOurExceptionClass); } static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) { - __setExceptionClass(unwind_exception, kOurDependentExceptionClass); + __setExceptionClass(unwind_exception, kOurDependentExceptionClass); } // Is it one of ours? uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) { - // On x86 and some ARM unwinders, unwind_exception->exception_class is - // a uint64_t. On other ARM unwinders, it is a char[8]. - // See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf - // So we just copy it into a uint64_t to be sure. - uint64_t exClass; - ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass)); - return exClass; + // On x86 and some ARM unwinders, unwind_exception->exception_class is + // a uint64_t. On other ARM unwinders, it is a char[8]. + // See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf + // So we just copy it into a uint64_t to be sure. + uint64_t exClass; + ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass)); + return exClass; } bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) { - return (__getExceptionClass(unwind_exception) & get_vendor_and_language) == - (kOurExceptionClass & get_vendor_and_language); + return (__getExceptionClass(unwind_exception) & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); } static bool isDependentException(_Unwind_Exception* unwind_exception) { - return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01; + return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01; } // This does not need to be atomic -static inline int incrementHandlerCount(__cxa_exception *exception) { - return ++exception->handlerCount; -} +static inline int incrementHandlerCount(__cxa_exception* exception) { return ++exception->handlerCount; } // This does not need to be atomic -static inline int decrementHandlerCount(__cxa_exception *exception) { - return --exception->handlerCount; -} +static inline int decrementHandlerCount(__cxa_exception* exception) { return --exception->handlerCount; } /* If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler @@ -128,28 +106,25 @@ static inline int decrementHandlerCount(__cxa_exception *exception) { This is never called for a __cxa_dependent_exception. */ -static -void -exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) -{ - __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception); - if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) - std::__terminate(exception_header->terminateHandler); - // Just in case there exists a dependent exception that is pointing to this, - // check the reference count and only destroy this if that count goes to zero. - __cxa_decrement_exception_refcount(unwind_exception + 1); +static void exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) { + __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception); + if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) + std::__terminate(exception_header->terminateHandler); + // Just in case there exists a dependent exception that is pointing to this, + // check the reference count and only destroy this if that count goes to zero. + __cxa_decrement_exception_refcount(unwind_exception + 1); } static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) { -// Section 2.5.3 says: -// * For purposes of this ABI, several things are considered exception handlers: -// ** A terminate() call due to a throw. -// and -// * Upon entry, Following initialization of the catch parameter, -// a handler must call: -// * void *__cxa_begin_catch(void *exceptionObject ); - (void) __cxa_begin_catch(&exception_header->unwindHeader); - std::__terminate(exception_header->terminateHandler); + // Section 2.5.3 says: + // * For purposes of this ABI, several things are considered exception handlers: + // ** A terminate() call due to a throw. + // and + // * Upon entry, Following initialization of the catch parameter, + // a handler must call: + // * void *__cxa_begin_catch(void *exceptionObject ); + (void)__cxa_begin_catch(&exception_header->unwindHeader); + std::__terminate(exception_header->terminateHandler); } // Return the offset of the __cxa_exception header from the start of the @@ -165,8 +140,7 @@ static size_t get_cxa_exception_offset() { // Compute the maximum alignment for the target machine. constexpr size_t alignment = alignof(S); constexpr size_t excp_size = sizeof(__cxa_exception); - constexpr size_t aligned_size = - (excp_size + alignment - 1) / alignment * alignment; + constexpr size_t aligned_size = (excp_size + alignment - 1) / alignment * alignment; constexpr size_t offset = aligned_size - excp_size; static_assert((offset == 0 || alignof(_Unwind_Exception) < alignment), "offset is non-zero only if _Unwind_Exception isn't aligned"); @@ -180,39 +154,30 @@ extern "C" { // object. Zero-fill the object. If memory can't be allocated, call // std::terminate. Return a pointer to the memory to be used for the // user's exception object. -void *__cxa_allocate_exception(size_t thrown_size) throw() { - size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); - - // Allocate extra space before the __cxa_exception header to ensure the - // start of the thrown object is sufficiently aligned. - size_t header_offset = get_cxa_exception_offset(); - char *raw_buffer = - (char *)__aligned_malloc_with_fallback(header_offset + actual_size); - if (NULL == raw_buffer) - std::terminate(); - __cxa_exception *exception_header = - static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset)); - ::memset(exception_header, 0, actual_size); - return thrown_object_from_cxa_exception(exception_header); +void* __cxa_allocate_exception(size_t thrown_size) throw() { + size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); + + // Allocate extra space before the __cxa_exception header to ensure the + // start of the thrown object is sufficiently aligned. + size_t header_offset = get_cxa_exception_offset(); + char* raw_buffer = (char*)__aligned_malloc_with_fallback(header_offset + actual_size); + if (NULL == raw_buffer) + std::terminate(); + __cxa_exception* exception_header = static_cast<__cxa_exception*>((void*)(raw_buffer + header_offset)); + ::memset(exception_header, 0, actual_size); + return thrown_object_from_cxa_exception(exception_header); } - // Free a __cxa_exception object allocated with __cxa_allocate_exception. -void __cxa_free_exception(void *thrown_object) throw() { - // Compute the size of the padding before the header. - size_t header_offset = get_cxa_exception_offset(); - char *raw_buffer = - ((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset; - __aligned_free_with_fallback((void *)raw_buffer); +void __cxa_free_exception(void* thrown_object) throw() { + // Compute the size of the padding before the header. + size_t header_offset = get_cxa_exception_offset(); + char* raw_buffer = ((char*)cxa_exception_from_thrown_object(thrown_object)) - header_offset; + __aligned_free_with_fallback((void*)raw_buffer); } __cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinfo, -#ifdef __wasm__ -// In Wasm, a destructor returns its argument - void *(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() { -#else - void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() { -#endif + __libcxxabi_exception_destructor_func dest) throw() { __cxa_exception* exception_header = cxa_exception_from_thrown_object(object); exception_header->referenceCount = 0; exception_header->unexpectedHandler = std::get_unexpected(); @@ -228,22 +193,18 @@ __cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinf // This function shall allocate a __cxa_dependent_exception and // return a pointer to it. (Really to the object, not past its' end). // Otherwise, it will work like __cxa_allocate_exception. -void * __cxa_allocate_dependent_exception () { - size_t actual_size = sizeof(__cxa_dependent_exception); - void *ptr = __aligned_malloc_with_fallback(actual_size); - if (NULL == ptr) - std::terminate(); - ::memset(ptr, 0, actual_size); - return ptr; +void* __cxa_allocate_dependent_exception() { + size_t actual_size = sizeof(__cxa_dependent_exception); + void* ptr = __aligned_malloc_with_fallback(actual_size); + if (NULL == ptr) + std::terminate(); + ::memset(ptr, 0, actual_size); + return ptr; } - // This function shall free a dependent_exception. // It does not affect the reference count of the primary exception. -void __cxa_free_dependent_exception (void * dependent_exception) { - __aligned_free_with_fallback(dependent_exception); -} - +void __cxa_free_dependent_exception(void* dependent_exception) { __aligned_free_with_fallback(dependent_exception); } // 2.4.3 Throwing the Exception Object /* @@ -271,13 +232,7 @@ handler, _Unwind_RaiseException may return. In that case, __cxa_throw will call terminate, assuming that there was no handler for the exception. */ -void -#ifdef __wasm__ -// In Wasm, a destructor returns its argument -__cxa_throw(void *thrown_object, std::type_info *tinfo, void *(_LIBCXXABI_DTOR_FUNC *dest)(void *)) { -#else -__cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) { -#endif +void __cxa_throw(void* thrown_object, std::type_info* tinfo, __libcxxabi_exception_destructor_func dest) { __cxa_eh_globals* globals = __cxa_get_globals(); globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local @@ -290,16 +245,15 @@ __cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FU #endif #ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); + _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); #else - _Unwind_RaiseException(&exception_header->unwindHeader); + _Unwind_RaiseException(&exception_header->unwindHeader); #endif - // This only happens when there is no handler, or some unexpected unwinding - // error happens. - failed_throw(exception_header); + // This only happens when there is no handler, or some unexpected unwinding + // error happens. + failed_throw(exception_header); } - // 2.5.3 Exception Handlers /* The adjusted pointer is computed by the personality routine during phase 1 @@ -308,13 +262,11 @@ The adjusted pointer is computed by the personality routine during phase 1 Requires: exception is native */ -void *__cxa_get_exception_ptr(void *unwind_exception) throw() { +void* __cxa_get_exception_ptr(void* unwind_exception) throw() { #if defined(_LIBCXXABI_ARM_EHABI) - return reinterpret_cast( - static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); + return reinterpret_cast(static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); #else - return cxa_exception_from_exception_unwind_exception( - static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr; + return cxa_exception_from_exception_unwind_exception(static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr; #endif } @@ -323,30 +275,25 @@ void *__cxa_get_exception_ptr(void *unwind_exception) throw() { The routine to be called before the cleanup. This will save __cxa_exception in __cxa_eh_globals, so that __cxa_end_cleanup() can recover later. */ -bool __cxa_begin_cleanup(void *unwind_arg) throw() { - _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = - cxa_exception_from_exception_unwind_exception(unwind_exception); - - if (__isOurExceptionClass(unwind_exception)) - { - if (0 == exception_header->propagationCount) - { - exception_header->nextPropagatingException = globals->propagatingExceptions; - globals->propagatingExceptions = exception_header; - } - ++exception_header->propagationCount; - } - else - { - // If the propagatingExceptions stack is not empty, since we can't - // chain the foreign exception, terminate it. - if (NULL != globals->propagatingExceptions) - std::terminate(); - globals->propagatingExceptions = exception_header; +bool __cxa_begin_cleanup(void* unwind_arg) throw() { + _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); + __cxa_eh_globals* globals = __cxa_get_globals(); + __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception); + + if (__isOurExceptionClass(unwind_exception)) { + if (0 == exception_header->propagationCount) { + exception_header->nextPropagatingException = globals->propagatingExceptions; + globals->propagatingExceptions = exception_header; } - return true; + ++exception_header->propagationCount; + } else { + // If the propagatingExceptions stack is not empty, since we can't + // chain the foreign exception, terminate it. + if (NULL != globals->propagatingExceptions) + std::terminate(); + globals->propagatingExceptions = exception_header; + } + return true; } /* @@ -363,55 +310,48 @@ returns and we need to keep the original lr so just branch to it. When targeting bare metal, the function also clobbers ip/r12 to hold the address of _Unwind_Resume, which may be too far away for an ordinary branch. */ -__attribute__((used)) static _Unwind_Exception * -__cxa_end_cleanup_impl() -{ - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = globals->propagatingExceptions; - if (NULL == exception_header) - { - // It seems that __cxa_begin_cleanup() is not called properly. - // We have no choice but terminate the program now. - std::terminate(); - } +__attribute__((used)) static _Unwind_Exception* __cxa_end_cleanup_impl() { + __cxa_eh_globals* globals = __cxa_get_globals(); + __cxa_exception* exception_header = globals->propagatingExceptions; + if (NULL == exception_header) { + // It seems that __cxa_begin_cleanup() is not called properly. + // We have no choice but terminate the program now. + std::terminate(); + } - if (__isOurExceptionClass(&exception_header->unwindHeader)) - { - --exception_header->propagationCount; - if (0 == exception_header->propagationCount) - { - globals->propagatingExceptions = exception_header->nextPropagatingException; - exception_header->nextPropagatingException = NULL; - } - } - else - { - globals->propagatingExceptions = NULL; + if (__isOurExceptionClass(&exception_header->unwindHeader)) { + --exception_header->propagationCount; + if (0 == exception_header->propagationCount) { + globals->propagatingExceptions = exception_header->nextPropagatingException; + exception_header->nextPropagatingException = NULL; } - return &exception_header->unwindHeader; + } else { + globals->propagatingExceptions = NULL; + } + return &exception_header->unwindHeader; } asm(" .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n" " .globl __cxa_end_cleanup\n" " .type __cxa_end_cleanup,%function\n" "__cxa_end_cleanup:\n" -#if defined(__ARM_FEATURE_BTI_DEFAULT) +# if defined(__ARM_FEATURE_BTI_DEFAULT) " bti\n" -#endif +# endif " push {r1, r2, r3, r4}\n" " mov r4, lr\n" " bl __cxa_end_cleanup_impl\n" " mov lr, r4\n" -#if defined(LIBCXXABI_BAREMETAL) +# if defined(LIBCXXABI_BAREMETAL) " ldr r4, =_Unwind_Resume\n" " mov ip, r4\n" -#endif +# endif " pop {r1, r2, r3, r4}\n" -#if defined(LIBCXXABI_BAREMETAL) +# if defined(LIBCXXABI_BAREMETAL) " bx ip\n" -#else +# else " b _Unwind_Resume\n" -#endif +# endif " .popsection"); #endif // defined(_LIBCXXABI_ARM_EHABI) @@ -446,57 +386,49 @@ to terminate or unexpected during unwinding. * If we haven't terminated, assume the exception object is just past the _Unwind_Exception and return a pointer to that. */ -void* -__cxa_begin_catch(void* unwind_arg) throw() -{ - _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); - bool native_exception = __isOurExceptionClass(unwind_exception); - __cxa_eh_globals* globals = __cxa_get_globals(); - // exception_header is a hackish offset from a foreign exception, but it - // works as long as we're careful not to try to access any __cxa_exception - // parts. - __cxa_exception* exception_header = - cxa_exception_from_exception_unwind_exception - ( - static_cast<_Unwind_Exception*>(unwind_exception) - ); +void* __cxa_begin_catch(void* unwind_arg) throw() { + _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); + bool native_exception = __isOurExceptionClass(unwind_exception); + __cxa_eh_globals* globals = __cxa_get_globals(); + // exception_header is a hackish offset from a foreign exception, but it + // works as long as we're careful not to try to access any __cxa_exception + // parts. + __cxa_exception* exception_header = + cxa_exception_from_exception_unwind_exception(static_cast<_Unwind_Exception*>(unwind_exception)); #if defined(__MVS__) - // Remove the exception object from the linked list of exceptions that the z/OS unwinder - // maintains before adding it to the libc++abi list of caught exceptions. - // The libc++abi will manage the lifetime of the exception from this point forward. - _UnwindZOS_PopException(); + // Remove the exception object from the linked list of exceptions that the z/OS unwinder + // maintains before adding it to the libc++abi list of caught exceptions. + // The libc++abi will manage the lifetime of the exception from this point forward. + _UnwindZOS_PopException(); #endif - if (native_exception) - { - // Increment the handler count, removing the flag about being rethrown - exception_header->handlerCount = exception_header->handlerCount < 0 ? - -exception_header->handlerCount + 1 : exception_header->handlerCount + 1; - // place the exception on the top of the stack if it's not already - // there by a previous rethrow - if (exception_header != globals->caughtExceptions) - { - exception_header->nextException = globals->caughtExceptions; - globals->caughtExceptions = exception_header; - } - globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local + if (native_exception) { + // Increment the handler count, removing the flag about being rethrown + exception_header->handlerCount = + exception_header->handlerCount < 0 ? -exception_header->handlerCount + 1 : exception_header->handlerCount + 1; + // place the exception on the top of the stack if it's not already + // there by a previous rethrow + if (exception_header != globals->caughtExceptions) { + exception_header->nextException = globals->caughtExceptions; + globals->caughtExceptions = exception_header; + } + globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local #if defined(_LIBCXXABI_ARM_EHABI) - return reinterpret_cast(exception_header->unwindHeader.barrier_cache.bitpattern[0]); + return reinterpret_cast(exception_header->unwindHeader.barrier_cache.bitpattern[0]); #else - return exception_header->adjustedPtr; + return exception_header->adjustedPtr; #endif - } - // Else this is a foreign exception - // If the caughtExceptions stack is not empty, terminate - if (globals->caughtExceptions != 0) - std::terminate(); - // Push the foreign exception on to the stack - globals->caughtExceptions = exception_header; - return unwind_exception + 1; + } + // Else this is a foreign exception + // If the caughtExceptions stack is not empty, terminate + if (globals->caughtExceptions != 0) + std::terminate(); + // Push the foreign exception on to the stack + globals->caughtExceptions = exception_header; + return unwind_exception + 1; } - /* Upon exit for any reason, a handler must call: void __cxa_end_catch (); @@ -520,89 +452,77 @@ void __cxa_end_catch() { "sizeof(__cxa_exception) must be equal to " "sizeof(__cxa_dependent_exception)"); static_assert(__builtin_offsetof(__cxa_exception, referenceCount) == - __builtin_offsetof(__cxa_dependent_exception, - primaryException), + __builtin_offsetof(__cxa_dependent_exception, primaryException), "the layout of __cxa_exception must match the layout of " "__cxa_dependent_exception"); static_assert(__builtin_offsetof(__cxa_exception, handlerCount) == __builtin_offsetof(__cxa_dependent_exception, handlerCount), "the layout of __cxa_exception must match the layout of " "__cxa_dependent_exception"); - __cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch - __cxa_exception* exception_header = globals->caughtExceptions; - // If we've rethrown a foreign exception, then globals->caughtExceptions - // will have been made an empty stack by __cxa_rethrow() and there is - // nothing more to be done. Do nothing! - if (NULL != exception_header) - { - bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); - if (native_exception) - { - // This is a native exception - if (exception_header->handlerCount < 0) - { - // The exception has been rethrown by __cxa_rethrow, so don't delete it - if (0 == incrementHandlerCount(exception_header)) - { - // Remove from the chain of uncaught exceptions - globals->caughtExceptions = exception_header->nextException; - // but don't destroy - } - // Keep handlerCount negative in case there are nested catch's - // that need to be told that this exception is rethrown. Don't - // erase this rethrow flag until the exception is recaught. - } - else - { - // The native exception has not been rethrown - if (0 == decrementHandlerCount(exception_header)) - { - // Remove from the chain of uncaught exceptions - globals->caughtExceptions = exception_header->nextException; - // Destroy this exception, being careful to distinguish - // between dependent and primary exceptions - if (isDependentException(&exception_header->unwindHeader)) - { - // Reset exception_header to primaryException and deallocate the dependent exception - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(exception_header); - exception_header = - cxa_exception_from_thrown_object(dep_exception_header->primaryException); - __cxa_free_dependent_exception(dep_exception_header); - } - // Destroy the primary exception only if its referenceCount goes to 0 - // (this decrement must be atomic) - __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header)); - } - } + __cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch + __cxa_exception* exception_header = globals->caughtExceptions; + // If we've rethrown a foreign exception, then globals->caughtExceptions + // will have been made an empty stack by __cxa_rethrow() and there is + // nothing more to be done. Do nothing! + if (NULL != exception_header) { + bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); + if (native_exception) { + // This is a native exception + if (exception_header->handlerCount < 0) { + // The exception has been rethrown by __cxa_rethrow, so don't delete it + if (0 == incrementHandlerCount(exception_header)) { + // Remove from the chain of uncaught exceptions + globals->caughtExceptions = exception_header->nextException; + // but don't destroy } - else - { - // The foreign exception has not been rethrown. Pop the stack - // and delete it. If there are nested catch's and they try - // to touch a foreign exception in any way, that is undefined - // behavior. They likely can't since the only way to catch - // a foreign exception is with catch (...)! - _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader); - globals->caughtExceptions = 0; + // Keep handlerCount negative in case there are nested catch's + // that need to be told that this exception is rethrown. Don't + // erase this rethrow flag until the exception is recaught. + } else { + // The native exception has not been rethrown + if (0 == decrementHandlerCount(exception_header)) { + // Remove from the chain of uncaught exceptions + globals->caughtExceptions = exception_header->nextException; + // Destroy this exception, being careful to distinguish + // between dependent and primary exceptions + if (isDependentException(&exception_header->unwindHeader)) { + // Reset exception_header to primaryException and deallocate the dependent exception + __cxa_dependent_exception* dep_exception_header = + reinterpret_cast<__cxa_dependent_exception*>(exception_header); + exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException); + __cxa_free_dependent_exception(dep_exception_header); + } + // Destroy the primary exception only if its referenceCount goes to 0 + // (this decrement must be atomic) + __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header)); } + } + } else { + // The foreign exception has not been rethrown. Pop the stack + // and delete it. If there are nested catch's and they try + // to touch a foreign exception in any way, that is undefined + // behavior. They likely can't since the only way to catch + // a foreign exception is with catch (...)! + _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader); + globals->caughtExceptions = 0; } + } } // Note: exception_header may be masquerading as a __cxa_dependent_exception // and that's ok. exceptionType is there too. // However watch out for foreign exceptions. Return null for them. -std::type_info *__cxa_current_exception_type() { -// get the current exception - __cxa_eh_globals *globals = __cxa_get_globals_fast(); - if (NULL == globals) - return NULL; // If there have never been any exceptions, there are none now. - __cxa_exception *exception_header = globals->caughtExceptions; - if (NULL == exception_header) - return NULL; // No current exception - if (!__isOurExceptionClass(&exception_header->unwindHeader)) - return NULL; - return exception_header->exceptionType; +std::type_info* __cxa_current_exception_type() { + // get the current exception + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + if (NULL == globals) + return NULL; // If there have never been any exceptions, there are none now. + __cxa_exception* exception_header = globals->caughtExceptions; + if (NULL == exception_header) + return NULL; // No current exception + if (!__isOurExceptionClass(&exception_header->unwindHeader)) + return NULL; + return exception_header->exceptionType; } // 2.5.4 Rethrowing Exceptions @@ -618,41 +538,39 @@ If the exception is native: and that's ok. */ void __cxa_rethrow() { - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = globals->caughtExceptions; - if (NULL == exception_header) - std::terminate(); // throw; called outside of a exception handler - bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); - if (native_exception) - { - // Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch) - exception_header->handlerCount = -exception_header->handlerCount; - globals->uncaughtExceptions += 1; - // __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary - } - else // this is a foreign exception - { - // The only way to communicate to __cxa_end_catch that we've rethrown - // a foreign exception, so don't delete us, is to pop the stack here - // which must be empty afterwards. Then __cxa_end_catch will do - // nothing - globals->caughtExceptions = 0; - } + __cxa_eh_globals* globals = __cxa_get_globals(); + __cxa_exception* exception_header = globals->caughtExceptions; + if (NULL == exception_header) + std::terminate(); // throw; called outside of a exception handler + bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); + if (native_exception) { + // Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch) + exception_header->handlerCount = -exception_header->handlerCount; + globals->uncaughtExceptions += 1; + // __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary + } else // this is a foreign exception + { + // The only way to communicate to __cxa_end_catch that we've rethrown + // a foreign exception, so don't delete us, is to pop the stack here + // which must be empty afterwards. Then __cxa_end_catch will do + // nothing + globals->caughtExceptions = 0; + } #ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); + _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); #else - _Unwind_RaiseException(&exception_header->unwindHeader); + _Unwind_RaiseException(&exception_header->unwindHeader); #endif - // If we get here, some kind of unwinding error has occurred. - // There is some weird code generation bug happening with - // Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn) - // If we call failed_throw here. Turns up with -O2 or higher, and -Os. - __cxa_begin_catch(&exception_header->unwindHeader); - if (native_exception) - std::__terminate(exception_header->terminateHandler); - // Foreign exception: can't get exception_header->terminateHandler - std::terminate(); + // If we get here, some kind of unwinding error has occurred. + // There is some weird code generation bug happening with + // Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn) + // If we call failed_throw here. Turns up with -O2 or higher, and -Os. + __cxa_begin_catch(&exception_header->unwindHeader); + if (native_exception) + std::__terminate(exception_header->terminateHandler); + // Foreign exception: can't get exception_header->terminateHandler + std::terminate(); } /* @@ -662,13 +580,11 @@ void __cxa_rethrow() { Requires: If thrown_object is not NULL, it is a native exception. */ -void -__cxa_increment_exception_refcount(void *thrown_object) throw() { - if (thrown_object != NULL ) - { - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); - } +void __cxa_increment_exception_refcount(void* thrown_object) throw() { + if (thrown_object != NULL) { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); + } } /* @@ -680,17 +596,15 @@ __cxa_increment_exception_refcount(void *thrown_object) throw() { Requires: If thrown_object is not NULL, it is a native exception. */ _LIBCXXABI_NO_CFI -void __cxa_decrement_exception_refcount(void *thrown_object) throw() { - if (thrown_object != NULL ) - { - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0) - { - if (NULL != exception_header->exceptionDestructor) - exception_header->exceptionDestructor(thrown_object); - __cxa_free_exception(thrown_object); - } +void __cxa_decrement_exception_refcount(void* thrown_object) throw() { + if (thrown_object != NULL) { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0) { + if (NULL != exception_header->exceptionDestructor) + exception_header->exceptionDestructor(thrown_object); + __cxa_free_exception(thrown_object); } + } } /* @@ -703,24 +617,23 @@ void __cxa_decrement_exception_refcount(void *thrown_object) throw() { been no exceptions thrown, ever, on this thread, we can return NULL without the need to allocate the exception-handling globals. */ -void *__cxa_current_primary_exception() throw() { -// get the current exception - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (NULL == globals) - return NULL; // If there are no globals, there is no exception - __cxa_exception* exception_header = globals->caughtExceptions; - if (NULL == exception_header) - return NULL; // No current exception - if (!__isOurExceptionClass(&exception_header->unwindHeader)) - return NULL; // Can't capture a foreign exception (no way to refcount it) - if (isDependentException(&exception_header->unwindHeader)) { - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(exception_header); - exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException); - } - void* thrown_object = thrown_object_from_cxa_exception(exception_header); - __cxa_increment_exception_refcount(thrown_object); - return thrown_object; +void* __cxa_current_primary_exception() throw() { + // get the current exception + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + if (NULL == globals) + return NULL; // If there are no globals, there is no exception + __cxa_exception* exception_header = globals->caughtExceptions; + if (NULL == exception_header) + return NULL; // No current exception + if (!__isOurExceptionClass(&exception_header->unwindHeader)) + return NULL; // Can't capture a foreign exception (no way to refcount it) + if (isDependentException(&exception_header->unwindHeader)) { + __cxa_dependent_exception* dep_exception_header = reinterpret_cast<__cxa_dependent_exception*>(exception_header); + exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException); + } + void* thrown_object = thrown_object_from_cxa_exception(exception_header); + __cxa_increment_exception_refcount(thrown_object); + return thrown_object; } /* @@ -729,64 +642,55 @@ void *__cxa_current_primary_exception() throw() { primary exception is decremented, destroying the primary if necessary. Finally the dependent exception is destroyed. */ -static -void -dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) -{ - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1; - if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) - std::__terminate(dep_exception_header->terminateHandler); - __cxa_decrement_exception_refcount(dep_exception_header->primaryException); - __cxa_free_dependent_exception(dep_exception_header); +static void dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) { + __cxa_dependent_exception* dep_exception_header = + reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1; + if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) + std::__terminate(dep_exception_header->terminateHandler); + __cxa_decrement_exception_refcount(dep_exception_header->primaryException); + __cxa_free_dependent_exception(dep_exception_header); } /* If thrown_object is not null, allocate, initialize and throw a dependent exception. */ -void -__cxa_rethrow_primary_exception(void* thrown_object) -{ - if ( thrown_object != NULL ) - { - // thrown_object guaranteed to be native because - // __cxa_current_primary_exception returns NULL for foreign exceptions - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - __cxa_dependent_exception* dep_exception_header = - static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception()); - dep_exception_header->primaryException = thrown_object; - __cxa_increment_exception_refcount(thrown_object); - dep_exception_header->exceptionType = exception_header->exceptionType; - dep_exception_header->unexpectedHandler = std::get_unexpected(); - dep_exception_header->terminateHandler = std::get_terminate(); - setDependentExceptionClass(&dep_exception_header->unwindHeader); - __cxa_get_globals()->uncaughtExceptions += 1; - dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup; +void __cxa_rethrow_primary_exception(void* thrown_object) { + if (thrown_object != NULL) { + // thrown_object guaranteed to be native because + // __cxa_current_primary_exception returns NULL for foreign exceptions + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + __cxa_dependent_exception* dep_exception_header = + static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception()); + dep_exception_header->primaryException = thrown_object; + __cxa_increment_exception_refcount(thrown_object); + dep_exception_header->exceptionType = exception_header->exceptionType; + dep_exception_header->unexpectedHandler = std::get_unexpected(); + dep_exception_header->terminateHandler = std::get_terminate(); + setDependentExceptionClass(&dep_exception_header->unwindHeader); + __cxa_get_globals()->uncaughtExceptions += 1; + dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup; #ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader); + _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader); #else - _Unwind_RaiseException(&dep_exception_header->unwindHeader); + _Unwind_RaiseException(&dep_exception_header->unwindHeader); #endif - // Some sort of unwinding error. Note that terminate is a handler. - __cxa_begin_catch(&dep_exception_header->unwindHeader); - } - // If we return client will call terminate() + // Some sort of unwinding error. Note that terminate is a handler. + __cxa_begin_catch(&dep_exception_header->unwindHeader); + } + // If we return client will call terminate() } -bool -__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; } - -unsigned int -__cxa_uncaught_exceptions() throw() -{ - // This does not report foreign exceptions in flight - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (globals == 0) - return 0; - return globals->uncaughtExceptions; +bool __cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; } + +unsigned int __cxa_uncaught_exceptions() throw() { + // This does not report foreign exceptions in flight + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + if (globals == 0) + return 0; + return globals->uncaughtExceptions; } } // extern "C" -} // abi +} // namespace __cxxabiv1 diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h index aba08f2992103e..4476cec9738f35 100644 --- a/libcxxabi/src/cxa_exception.h +++ b/libcxxabi/src/cxa_exception.h @@ -43,12 +43,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception { // Manage the exception object itself. std::type_info *exceptionType; -#ifdef __wasm__ - // In Wasm, a destructor returns its argument - void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *); -#else - void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *); -#endif + __libcxxabi_exception_destructor_func exceptionDestructor; std::unexpected_handler unexpectedHandler; std::terminate_handler terminateHandler; diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h index b2dae8feed9a3b..63e147ae2423e2 100644 --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -15,6 +15,7 @@ #include <__libunwind_config.h> +#ifndef __wasm__ #include #include @@ -1299,5 +1300,6 @@ enum { UNW_LOONGARCH_F30 = 62, UNW_LOONGARCH_F31 = 63, }; +#endif #endif diff --git a/libunwind/src/Unwind-wasm.c b/libunwind/src/Unwind-wasm.c index b18b32c5d17847..808940c3a26d2e 100644 --- a/libunwind/src/Unwind-wasm.c +++ b/libunwind/src/Unwind-wasm.c @@ -10,15 +10,13 @@ // //===----------------------------------------------------------------------===// +// clang-format off #include - +// clang-format on #include "config.h" - -#ifdef __WASM_EXCEPTIONS__ - #include "unwind.h" -#include +#ifdef __wasm__ _Unwind_Reason_Code __gxx_personality_wasm0(int version, _Unwind_Action actions, uint64_t exceptionClass, _Unwind_Exception *unwind_exception, @@ -35,7 +33,7 @@ struct _Unwind_LandingPadContext { // Communication channel between compiler-generated user code and personality // function -thread_local struct _Unwind_LandingPadContext __wasm_lpad_context; +_Thread_local struct _Unwind_LandingPadContext __wasm_lpad_context; /// Calls to this function is in landing pads in compiler-generated user code. /// In other EH schemes, stack unwinding is done by libunwind library, which @@ -119,5 +117,4 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context) { return 0; } - -#endif // defined(__WASM_EXCEPTIONS__) +#endif diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S index 67d9e05711898d..955246db46cf7f 100644 --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#if !defined(__wasm__) #include "assembly.h" #define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 @@ -1235,4 +1236,4 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv) #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) */ NO_EXEC_STACK_DIRECTIVE - +#endif diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S index 5bf6055fe4147f..4397295e5929d9 100644 --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#ifndef __wasm__ #include "assembly.h" #define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 @@ -1180,3 +1181,5 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) */ NO_EXEC_STACK_DIRECTIVE + +#endif diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h index fb07d04071af3d..2c76e4b8a06b86 100644 --- a/libunwind/src/assembly.h +++ b/libunwind/src/assembly.h @@ -15,6 +15,7 @@ #ifndef UNWIND_ASSEMBLY_H #define UNWIND_ASSEMBLY_H +#ifndef __wasm__ #if defined(__linux__) && defined(__CET__) #include #define _LIBUNWIND_CET_ENDBR _CET_ENDBR @@ -284,5 +285,6 @@ aliasname: \ #if defined(__powerpc__) #define PPC_LEFT_SHIFT(index) << (index) #endif +#endif #endif /* UNWIND_ASSEMBLY_H */ diff --git a/libunwind/src/cet_unwind.h b/libunwind/src/cet_unwind.h index c364ed3e12feb3..7be3cc10a7fd71 100644 --- a/libunwind/src/cet_unwind.h +++ b/libunwind/src/cet_unwind.h @@ -10,6 +10,7 @@ #ifndef LIBUNWIND_CET_UNWIND_H #define LIBUNWIND_CET_UNWIND_H +#ifndef __wasm__ #include "libunwind.h" // Currently, CET is implemented on Linux x86 platforms. @@ -39,3 +40,5 @@ extern void *__libunwind_cet_get_registers(unw_cursor_t *); extern void *__libunwind_cet_get_jump_target(void); #endif + +#endif diff --git a/libunwind/src/config.h b/libunwind/src/config.h index deb5a4d4d73d46..2a57df41acca9f 100644 --- a/libunwind/src/config.h +++ b/libunwind/src/config.h @@ -66,13 +66,14 @@ #define _LIBUNWIND_EXPORT #define _LIBUNWIND_HIDDEN #else - #if !defined(__ELF__) && !defined(__MACH__) && !defined(_AIX) - #define _LIBUNWIND_EXPORT __declspec(dllexport) - #define _LIBUNWIND_HIDDEN - #else - #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) - #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) - #endif +#if !defined(__ELF__) && !defined(__MACH__) && !defined(_AIX) && \ + !defined(__wasm__) +#define _LIBUNWIND_EXPORT __declspec(dllexport) +#define _LIBUNWIND_HIDDEN +#else +#define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) +#define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) +#endif #endif #define STR(a) #a diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp index cf39ec5f7dbdf9..7d5855102a0e53 100644 --- a/libunwind/src/libunwind.cpp +++ b/libunwind/src/libunwind.cpp @@ -12,6 +12,7 @@ #include #include "config.h" +#ifndef __wasm__ #include "libunwind_ext.h" #include @@ -430,6 +431,7 @@ int __unw_remove_find_dynamic_unwind_sections( } #endif // __APPLE__ +#endif // Add logging hooks in Debug builds only #ifndef NDEBUG diff --git a/libunwind/src/libunwind_ext.h b/libunwind/src/libunwind_ext.h index 28db43a4f6eef2..3a7ca7c337e008 100644 --- a/libunwind/src/libunwind_ext.h +++ b/libunwind/src/libunwind_ext.h @@ -12,6 +12,7 @@ #ifndef __LIBUNWIND_EXT__ #define __LIBUNWIND_EXT__ +#ifndef __wasm__ #include "config.h" #include #include @@ -133,5 +134,6 @@ extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context, #ifdef __cplusplus } #endif +#endif #endif // __LIBUNWIND_EXT__