xref: /openbsd-src/gnu/llvm/libcxxabi/src/cxa_exception.cpp (revision 8f1d572453a8bab44a2fe956e25efc4124e87e82)
1*8f1d5724Srobert //===----------------------------------------------------------------------===//
279c2e3e6Spatrick //
379c2e3e6Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
479c2e3e6Spatrick // See https://llvm.org/LICENSE.txt for license information.
579c2e3e6Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
679c2e3e6Spatrick //
779c2e3e6Spatrick //
879c2e3e6Spatrick //  This file implements the "Exception Handling APIs"
979c2e3e6Spatrick //  https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
1079c2e3e6Spatrick //
1179c2e3e6Spatrick //===----------------------------------------------------------------------===//
1279c2e3e6Spatrick 
1379c2e3e6Spatrick #include "cxxabi.h"
1479c2e3e6Spatrick 
1579c2e3e6Spatrick #include <exception>        // for std::terminate
1679c2e3e6Spatrick #include <string.h>         // for memset
1779c2e3e6Spatrick #include "cxa_exception.h"
1879c2e3e6Spatrick #include "cxa_handlers.h"
1979c2e3e6Spatrick #include "fallback_malloc.h"
20*8f1d5724Srobert #include "include/atomic_support.h" // from libc++
2179c2e3e6Spatrick 
2279c2e3e6Spatrick #if __has_feature(address_sanitizer)
234e0cc08cSpatrick #include <sanitizer/asan_interface.h>
2479c2e3e6Spatrick #endif
2579c2e3e6Spatrick 
2679c2e3e6Spatrick // +---------------------------+-----------------------------+---------------+
2779c2e3e6Spatrick // | __cxa_exception           | _Unwind_Exception CLNGC++\0 | thrown object |
2879c2e3e6Spatrick // +---------------------------+-----------------------------+---------------+
2979c2e3e6Spatrick //                                                           ^
3079c2e3e6Spatrick //                                                           |
3179c2e3e6Spatrick //   +-------------------------------------------------------+
3279c2e3e6Spatrick //   |
3379c2e3e6Spatrick // +---------------------------+-----------------------------+
3479c2e3e6Spatrick // | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
3579c2e3e6Spatrick // +---------------------------+-----------------------------+
3679c2e3e6Spatrick 
3779c2e3e6Spatrick namespace __cxxabiv1 {
3879c2e3e6Spatrick 
3979c2e3e6Spatrick //  Utility routines
4079c2e3e6Spatrick static
4179c2e3e6Spatrick inline
4279c2e3e6Spatrick __cxa_exception*
cxa_exception_from_thrown_object(void * thrown_object)4379c2e3e6Spatrick cxa_exception_from_thrown_object(void* thrown_object)
4479c2e3e6Spatrick {
4579c2e3e6Spatrick     return static_cast<__cxa_exception*>(thrown_object) - 1;
4679c2e3e6Spatrick }
4779c2e3e6Spatrick 
4879c2e3e6Spatrick // Note:  This is never called when exception_header is masquerading as a
4979c2e3e6Spatrick //        __cxa_dependent_exception.
5079c2e3e6Spatrick static
5179c2e3e6Spatrick inline
5279c2e3e6Spatrick void*
thrown_object_from_cxa_exception(__cxa_exception * exception_header)5379c2e3e6Spatrick thrown_object_from_cxa_exception(__cxa_exception* exception_header)
5479c2e3e6Spatrick {
5579c2e3e6Spatrick     return static_cast<void*>(exception_header + 1);
5679c2e3e6Spatrick }
5779c2e3e6Spatrick 
5879c2e3e6Spatrick //  Get the exception object from the unwind pointer.
5979c2e3e6Spatrick //  Relies on the structure layout, where the unwind pointer is right in
6079c2e3e6Spatrick //  front of the user's exception object
6179c2e3e6Spatrick static
6279c2e3e6Spatrick inline
6379c2e3e6Spatrick __cxa_exception*
cxa_exception_from_exception_unwind_exception(_Unwind_Exception * unwind_exception)6479c2e3e6Spatrick cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception)
6579c2e3e6Spatrick {
6679c2e3e6Spatrick     return cxa_exception_from_thrown_object(unwind_exception + 1 );
6779c2e3e6Spatrick }
6879c2e3e6Spatrick 
6979c2e3e6Spatrick // Round s up to next multiple of a.
7079c2e3e6Spatrick static inline
aligned_allocation_size(size_t s,size_t a)7179c2e3e6Spatrick size_t aligned_allocation_size(size_t s, size_t a) {
7279c2e3e6Spatrick     return (s + a - 1) & ~(a - 1);
7379c2e3e6Spatrick }
7479c2e3e6Spatrick 
7579c2e3e6Spatrick static inline
cxa_exception_size_from_exception_thrown_size(size_t size)7679c2e3e6Spatrick size_t cxa_exception_size_from_exception_thrown_size(size_t size) {
7779c2e3e6Spatrick     return aligned_allocation_size(size + sizeof (__cxa_exception),
7879c2e3e6Spatrick                                    alignof(__cxa_exception));
7979c2e3e6Spatrick }
8079c2e3e6Spatrick 
__setExceptionClass(_Unwind_Exception * unwind_exception,uint64_t newValue)8179c2e3e6Spatrick void __setExceptionClass(_Unwind_Exception* unwind_exception, uint64_t newValue) {
8279c2e3e6Spatrick     ::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue));
8379c2e3e6Spatrick }
8479c2e3e6Spatrick 
8579c2e3e6Spatrick 
setOurExceptionClass(_Unwind_Exception * unwind_exception)8679c2e3e6Spatrick static void setOurExceptionClass(_Unwind_Exception* unwind_exception) {
8779c2e3e6Spatrick     __setExceptionClass(unwind_exception, kOurExceptionClass);
8879c2e3e6Spatrick }
8979c2e3e6Spatrick 
setDependentExceptionClass(_Unwind_Exception * unwind_exception)9079c2e3e6Spatrick static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) {
9179c2e3e6Spatrick     __setExceptionClass(unwind_exception, kOurDependentExceptionClass);
9279c2e3e6Spatrick }
9379c2e3e6Spatrick 
9479c2e3e6Spatrick //  Is it one of ours?
__getExceptionClass(const _Unwind_Exception * unwind_exception)9579c2e3e6Spatrick uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) {
9679c2e3e6Spatrick     // On x86 and some ARM unwinders, unwind_exception->exception_class is
9779c2e3e6Spatrick     // a uint64_t. On other ARM unwinders, it is a char[8].
9879c2e3e6Spatrick     // See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
9979c2e3e6Spatrick     // So we just copy it into a uint64_t to be sure.
10079c2e3e6Spatrick     uint64_t exClass;
10179c2e3e6Spatrick     ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass));
10279c2e3e6Spatrick     return exClass;
10379c2e3e6Spatrick }
10479c2e3e6Spatrick 
__isOurExceptionClass(const _Unwind_Exception * unwind_exception)10579c2e3e6Spatrick bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) {
10679c2e3e6Spatrick     return (__getExceptionClass(unwind_exception) & get_vendor_and_language) ==
10779c2e3e6Spatrick            (kOurExceptionClass                    & get_vendor_and_language);
10879c2e3e6Spatrick }
10979c2e3e6Spatrick 
isDependentException(_Unwind_Exception * unwind_exception)11079c2e3e6Spatrick static bool isDependentException(_Unwind_Exception* unwind_exception) {
11179c2e3e6Spatrick     return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01;
11279c2e3e6Spatrick }
11379c2e3e6Spatrick 
11479c2e3e6Spatrick //  This does not need to be atomic
incrementHandlerCount(__cxa_exception * exception)11579c2e3e6Spatrick static inline int incrementHandlerCount(__cxa_exception *exception) {
11679c2e3e6Spatrick     return ++exception->handlerCount;
11779c2e3e6Spatrick }
11879c2e3e6Spatrick 
11979c2e3e6Spatrick //  This does not need to be atomic
decrementHandlerCount(__cxa_exception * exception)12079c2e3e6Spatrick static inline  int decrementHandlerCount(__cxa_exception *exception) {
12179c2e3e6Spatrick     return --exception->handlerCount;
12279c2e3e6Spatrick }
12379c2e3e6Spatrick 
12479c2e3e6Spatrick /*
12579c2e3e6Spatrick     If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
12679c2e3e6Spatrick     stored in exc is called.  Otherwise the exceptionDestructor stored in
12779c2e3e6Spatrick     exc is called, and then the memory for the exception is deallocated.
12879c2e3e6Spatrick 
12979c2e3e6Spatrick     This is never called for a __cxa_dependent_exception.
13079c2e3e6Spatrick */
13179c2e3e6Spatrick static
13279c2e3e6Spatrick void
exception_cleanup_func(_Unwind_Reason_Code reason,_Unwind_Exception * unwind_exception)13379c2e3e6Spatrick exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
13479c2e3e6Spatrick {
13579c2e3e6Spatrick     __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception);
13679c2e3e6Spatrick     if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
13779c2e3e6Spatrick         std::__terminate(exception_header->terminateHandler);
13879c2e3e6Spatrick     // Just in case there exists a dependent exception that is pointing to this,
13979c2e3e6Spatrick     //    check the reference count and only destroy this if that count goes to zero.
14079c2e3e6Spatrick     __cxa_decrement_exception_refcount(unwind_exception + 1);
14179c2e3e6Spatrick }
14279c2e3e6Spatrick 
failed_throw(__cxa_exception * exception_header)14379c2e3e6Spatrick static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) {
14479c2e3e6Spatrick //  Section 2.5.3 says:
14579c2e3e6Spatrick //      * For purposes of this ABI, several things are considered exception handlers:
14679c2e3e6Spatrick //      ** A terminate() call due to a throw.
14779c2e3e6Spatrick //  and
14879c2e3e6Spatrick //      * Upon entry, Following initialization of the catch parameter,
14979c2e3e6Spatrick //          a handler must call:
15079c2e3e6Spatrick //      * void *__cxa_begin_catch(void *exceptionObject );
15179c2e3e6Spatrick     (void) __cxa_begin_catch(&exception_header->unwindHeader);
15279c2e3e6Spatrick     std::__terminate(exception_header->terminateHandler);
15379c2e3e6Spatrick }
15479c2e3e6Spatrick 
15579c2e3e6Spatrick // Return the offset of the __cxa_exception header from the start of the
15679c2e3e6Spatrick // allocated buffer. If __cxa_exception's alignment is smaller than the maximum
15779c2e3e6Spatrick // useful alignment for the target machine, padding has to be inserted before
15879c2e3e6Spatrick // the header to ensure the thrown object that follows the header is
15979c2e3e6Spatrick // sufficiently aligned. This happens if _Unwind_exception isn't double-word
16079c2e3e6Spatrick // aligned (on Darwin, for example).
get_cxa_exception_offset()16179c2e3e6Spatrick static size_t get_cxa_exception_offset() {
16279c2e3e6Spatrick   struct S {
16379c2e3e6Spatrick   } __attribute__((aligned));
16479c2e3e6Spatrick 
16579c2e3e6Spatrick   // Compute the maximum alignment for the target machine.
16679c2e3e6Spatrick   constexpr size_t alignment = alignof(S);
16779c2e3e6Spatrick   constexpr size_t excp_size = sizeof(__cxa_exception);
16879c2e3e6Spatrick   constexpr size_t aligned_size =
16979c2e3e6Spatrick       (excp_size + alignment - 1) / alignment * alignment;
17079c2e3e6Spatrick   constexpr size_t offset = aligned_size - excp_size;
17179c2e3e6Spatrick   static_assert((offset == 0 || alignof(_Unwind_Exception) < alignment),
17279c2e3e6Spatrick                 "offset is non-zero only if _Unwind_Exception isn't aligned");
17379c2e3e6Spatrick   return offset;
17479c2e3e6Spatrick }
17579c2e3e6Spatrick 
17679c2e3e6Spatrick extern "C" {
17779c2e3e6Spatrick 
17879c2e3e6Spatrick //  Allocate a __cxa_exception object, and zero-fill it.
17979c2e3e6Spatrick //  Reserve "thrown_size" bytes on the end for the user's exception
18079c2e3e6Spatrick //  object. Zero-fill the object. If memory can't be allocated, call
18179c2e3e6Spatrick //  std::terminate. Return a pointer to the memory to be used for the
18279c2e3e6Spatrick //  user's exception object.
__cxa_allocate_exception(size_t thrown_size)18379c2e3e6Spatrick void *__cxa_allocate_exception(size_t thrown_size) throw() {
18479c2e3e6Spatrick     size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
18579c2e3e6Spatrick 
18679c2e3e6Spatrick     // Allocate extra space before the __cxa_exception header to ensure the
18779c2e3e6Spatrick     // start of the thrown object is sufficiently aligned.
18879c2e3e6Spatrick     size_t header_offset = get_cxa_exception_offset();
18979c2e3e6Spatrick     char *raw_buffer =
19079c2e3e6Spatrick         (char *)__aligned_malloc_with_fallback(header_offset + actual_size);
19179c2e3e6Spatrick     if (NULL == raw_buffer)
19279c2e3e6Spatrick         std::terminate();
19379c2e3e6Spatrick     __cxa_exception *exception_header =
19479c2e3e6Spatrick         static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
19579c2e3e6Spatrick     ::memset(exception_header, 0, actual_size);
19679c2e3e6Spatrick     return thrown_object_from_cxa_exception(exception_header);
19779c2e3e6Spatrick }
19879c2e3e6Spatrick 
19979c2e3e6Spatrick 
20079c2e3e6Spatrick //  Free a __cxa_exception object allocated with __cxa_allocate_exception.
__cxa_free_exception(void * thrown_object)20179c2e3e6Spatrick void __cxa_free_exception(void *thrown_object) throw() {
20279c2e3e6Spatrick     // Compute the size of the padding before the header.
20379c2e3e6Spatrick     size_t header_offset = get_cxa_exception_offset();
20479c2e3e6Spatrick     char *raw_buffer =
20579c2e3e6Spatrick         ((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset;
20679c2e3e6Spatrick     __aligned_free_with_fallback((void *)raw_buffer);
20779c2e3e6Spatrick }
20879c2e3e6Spatrick 
20979c2e3e6Spatrick 
21079c2e3e6Spatrick //  This function shall allocate a __cxa_dependent_exception and
21179c2e3e6Spatrick //  return a pointer to it. (Really to the object, not past its' end).
21279c2e3e6Spatrick //  Otherwise, it will work like __cxa_allocate_exception.
__cxa_allocate_dependent_exception()21379c2e3e6Spatrick void * __cxa_allocate_dependent_exception () {
21479c2e3e6Spatrick     size_t actual_size = sizeof(__cxa_dependent_exception);
21579c2e3e6Spatrick     void *ptr = __aligned_malloc_with_fallback(actual_size);
21679c2e3e6Spatrick     if (NULL == ptr)
21779c2e3e6Spatrick         std::terminate();
21879c2e3e6Spatrick     ::memset(ptr, 0, actual_size);
21979c2e3e6Spatrick     return ptr;
22079c2e3e6Spatrick }
22179c2e3e6Spatrick 
22279c2e3e6Spatrick 
22379c2e3e6Spatrick //  This function shall free a dependent_exception.
22479c2e3e6Spatrick //  It does not affect the reference count of the primary exception.
__cxa_free_dependent_exception(void * dependent_exception)22579c2e3e6Spatrick void __cxa_free_dependent_exception (void * dependent_exception) {
22679c2e3e6Spatrick     __aligned_free_with_fallback(dependent_exception);
22779c2e3e6Spatrick }
22879c2e3e6Spatrick 
22979c2e3e6Spatrick 
23079c2e3e6Spatrick // 2.4.3 Throwing the Exception Object
23179c2e3e6Spatrick /*
23279c2e3e6Spatrick After constructing the exception object with the throw argument value,
23379c2e3e6Spatrick the generated code calls the __cxa_throw runtime library routine. This
23479c2e3e6Spatrick routine never returns.
23579c2e3e6Spatrick 
23679c2e3e6Spatrick The __cxa_throw routine will do the following:
23779c2e3e6Spatrick 
23879c2e3e6Spatrick * Obtain the __cxa_exception header from the thrown exception object address,
23979c2e3e6Spatrick which can be computed as follows:
24079c2e3e6Spatrick  __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);
24179c2e3e6Spatrick * Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
24279c2e3e6Spatrick * Save the tinfo and dest arguments in the __cxa_exception header.
24379c2e3e6Spatrick * Set the exception_class field in the unwind header. This is a 64-bit value
24479c2e3e6Spatrick representing the ASCII string "XXXXC++\0", where "XXXX" is a
24579c2e3e6Spatrick vendor-dependent string. That is, for implementations conforming to this
24679c2e3e6Spatrick ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
24779c2e3e6Spatrick * Increment the uncaught_exception flag.
24879c2e3e6Spatrick * Call _Unwind_RaiseException in the system unwind library, Its argument is the
24979c2e3e6Spatrick pointer to the thrown exception, which __cxa_throw itself received as an argument.
25079c2e3e6Spatrick __Unwind_RaiseException begins the process of stack unwinding, described
25179c2e3e6Spatrick in Section 2.5. In special cases, such as an inability to find a
25279c2e3e6Spatrick handler, _Unwind_RaiseException may return. In that case, __cxa_throw
25379c2e3e6Spatrick will call terminate, assuming that there was no handler for the
25479c2e3e6Spatrick exception.
25579c2e3e6Spatrick */
25679c2e3e6Spatrick void
__cxa_throw(void * thrown_object,std::type_info * tinfo,void (_LIBCXXABI_DTOR_FUNC * dest)(void *))257*8f1d5724Srobert __cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) {
25879c2e3e6Spatrick     __cxa_eh_globals *globals = __cxa_get_globals();
25979c2e3e6Spatrick     __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
26079c2e3e6Spatrick 
26179c2e3e6Spatrick     exception_header->unexpectedHandler = std::get_unexpected();
26279c2e3e6Spatrick     exception_header->terminateHandler  = std::get_terminate();
26379c2e3e6Spatrick     exception_header->exceptionType = tinfo;
26479c2e3e6Spatrick     exception_header->exceptionDestructor = dest;
26579c2e3e6Spatrick     setOurExceptionClass(&exception_header->unwindHeader);
26679c2e3e6Spatrick     exception_header->referenceCount = 1;  // This is a newly allocated exception, no need for thread safety.
26779c2e3e6Spatrick     globals->uncaughtExceptions += 1;   // Not atomically, since globals are thread-local
26879c2e3e6Spatrick 
26979c2e3e6Spatrick     exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
27079c2e3e6Spatrick 
27179c2e3e6Spatrick #if __has_feature(address_sanitizer)
27279c2e3e6Spatrick     // Inform the ASan runtime that now might be a good time to clean stuff up.
27379c2e3e6Spatrick     __asan_handle_no_return();
27479c2e3e6Spatrick #endif
27579c2e3e6Spatrick 
27679c2e3e6Spatrick #ifdef __USING_SJLJ_EXCEPTIONS__
27779c2e3e6Spatrick     _Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
27879c2e3e6Spatrick #else
27979c2e3e6Spatrick     _Unwind_RaiseException(&exception_header->unwindHeader);
28079c2e3e6Spatrick #endif
28179c2e3e6Spatrick     //  This only happens when there is no handler, or some unexpected unwinding
28279c2e3e6Spatrick     //     error happens.
28379c2e3e6Spatrick     failed_throw(exception_header);
28479c2e3e6Spatrick }
28579c2e3e6Spatrick 
28679c2e3e6Spatrick 
28779c2e3e6Spatrick // 2.5.3 Exception Handlers
28879c2e3e6Spatrick /*
28979c2e3e6Spatrick The adjusted pointer is computed by the personality routine during phase 1
29079c2e3e6Spatrick   and saved in the exception header (either __cxa_exception or
29179c2e3e6Spatrick   __cxa_dependent_exception).
29279c2e3e6Spatrick 
29379c2e3e6Spatrick   Requires:  exception is native
29479c2e3e6Spatrick */
__cxa_get_exception_ptr(void * unwind_exception)29579c2e3e6Spatrick void *__cxa_get_exception_ptr(void *unwind_exception) throw() {
29679c2e3e6Spatrick #if defined(_LIBCXXABI_ARM_EHABI)
29779c2e3e6Spatrick     return reinterpret_cast<void*>(
29879c2e3e6Spatrick         static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]);
29979c2e3e6Spatrick #else
30079c2e3e6Spatrick     return cxa_exception_from_exception_unwind_exception(
30179c2e3e6Spatrick         static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr;
30279c2e3e6Spatrick #endif
30379c2e3e6Spatrick }
30479c2e3e6Spatrick 
30579c2e3e6Spatrick #if defined(_LIBCXXABI_ARM_EHABI)
30679c2e3e6Spatrick /*
30779c2e3e6Spatrick The routine to be called before the cleanup.  This will save __cxa_exception in
30879c2e3e6Spatrick __cxa_eh_globals, so that __cxa_end_cleanup() can recover later.
30979c2e3e6Spatrick */
__cxa_begin_cleanup(void * unwind_arg)31079c2e3e6Spatrick bool __cxa_begin_cleanup(void *unwind_arg) throw() {
31179c2e3e6Spatrick     _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
31279c2e3e6Spatrick     __cxa_eh_globals* globals = __cxa_get_globals();
31379c2e3e6Spatrick     __cxa_exception* exception_header =
31479c2e3e6Spatrick         cxa_exception_from_exception_unwind_exception(unwind_exception);
31579c2e3e6Spatrick 
31679c2e3e6Spatrick     if (__isOurExceptionClass(unwind_exception))
31779c2e3e6Spatrick     {
31879c2e3e6Spatrick         if (0 == exception_header->propagationCount)
31979c2e3e6Spatrick         {
32079c2e3e6Spatrick             exception_header->nextPropagatingException = globals->propagatingExceptions;
32179c2e3e6Spatrick             globals->propagatingExceptions = exception_header;
32279c2e3e6Spatrick         }
32379c2e3e6Spatrick         ++exception_header->propagationCount;
32479c2e3e6Spatrick     }
32579c2e3e6Spatrick     else
32679c2e3e6Spatrick     {
32779c2e3e6Spatrick         // If the propagatingExceptions stack is not empty, since we can't
32879c2e3e6Spatrick         // chain the foreign exception, terminate it.
32979c2e3e6Spatrick         if (NULL != globals->propagatingExceptions)
33079c2e3e6Spatrick             std::terminate();
33179c2e3e6Spatrick         globals->propagatingExceptions = exception_header;
33279c2e3e6Spatrick     }
33379c2e3e6Spatrick     return true;
33479c2e3e6Spatrick }
33579c2e3e6Spatrick 
33679c2e3e6Spatrick /*
33779c2e3e6Spatrick The routine to be called after the cleanup has been performed.  It will get the
33879c2e3e6Spatrick propagating __cxa_exception from __cxa_eh_globals, and continue the stack
33979c2e3e6Spatrick unwinding with _Unwind_Resume.
34079c2e3e6Spatrick 
34179c2e3e6Spatrick According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any
34279c2e3e6Spatrick register, thus we have to write this function in assembly so that we can save
34379c2e3e6Spatrick {r1, r2, r3}.  We don't have to save r0 because it is the return value and the
344*8f1d5724Srobert first argument to _Unwind_Resume().  The function also saves/restores r4 to
345*8f1d5724Srobert keep the stack aligned and to provide a temp register.  _Unwind_Resume never
346*8f1d5724Srobert returns and we need to keep the original lr so just branch to it.  When
347*8f1d5724Srobert targeting bare metal, the function also clobbers ip/r12 to hold the address of
348*8f1d5724Srobert _Unwind_Resume, which may be too far away for an ordinary branch.
34979c2e3e6Spatrick */
35079c2e3e6Spatrick __attribute__((used)) static _Unwind_Exception *
__cxa_end_cleanup_impl()35179c2e3e6Spatrick __cxa_end_cleanup_impl()
35279c2e3e6Spatrick {
35379c2e3e6Spatrick     __cxa_eh_globals* globals = __cxa_get_globals();
35479c2e3e6Spatrick     __cxa_exception* exception_header = globals->propagatingExceptions;
35579c2e3e6Spatrick     if (NULL == exception_header)
35679c2e3e6Spatrick     {
35779c2e3e6Spatrick         // It seems that __cxa_begin_cleanup() is not called properly.
35879c2e3e6Spatrick         // We have no choice but terminate the program now.
35979c2e3e6Spatrick         std::terminate();
36079c2e3e6Spatrick     }
36179c2e3e6Spatrick 
36279c2e3e6Spatrick     if (__isOurExceptionClass(&exception_header->unwindHeader))
36379c2e3e6Spatrick     {
36479c2e3e6Spatrick         --exception_header->propagationCount;
36579c2e3e6Spatrick         if (0 == exception_header->propagationCount)
36679c2e3e6Spatrick         {
36779c2e3e6Spatrick             globals->propagatingExceptions = exception_header->nextPropagatingException;
36879c2e3e6Spatrick             exception_header->nextPropagatingException = NULL;
36979c2e3e6Spatrick         }
37079c2e3e6Spatrick     }
37179c2e3e6Spatrick     else
37279c2e3e6Spatrick     {
37379c2e3e6Spatrick         globals->propagatingExceptions = NULL;
37479c2e3e6Spatrick     }
37579c2e3e6Spatrick     return &exception_header->unwindHeader;
37679c2e3e6Spatrick }
37779c2e3e6Spatrick 
378*8f1d5724Srobert asm("	.pushsection	.text.__cxa_end_cleanup,\"ax\",%progbits\n"
37979c2e3e6Spatrick     "	.globl	__cxa_end_cleanup\n"
38079c2e3e6Spatrick     "	.type	__cxa_end_cleanup,%function\n"
38179c2e3e6Spatrick     "__cxa_end_cleanup:\n"
382*8f1d5724Srobert #if defined(__ARM_FEATURE_BTI_DEFAULT)
383*8f1d5724Srobert     "	bti\n"
384*8f1d5724Srobert #endif
38579c2e3e6Spatrick     "	push	{r1, r2, r3, r4}\n"
386*8f1d5724Srobert     "	mov	r4, lr\n"
38779c2e3e6Spatrick     "	bl	__cxa_end_cleanup_impl\n"
388*8f1d5724Srobert     "	mov	lr, r4\n"
389*8f1d5724Srobert #if defined(LIBCXXABI_BAREMETAL)
390*8f1d5724Srobert     "	ldr	r4,	=_Unwind_Resume\n"
391*8f1d5724Srobert     "	mov	ip,	r4\n"
392*8f1d5724Srobert #endif
39379c2e3e6Spatrick     "	pop	{r1, r2, r3, r4}\n"
394*8f1d5724Srobert #if defined(LIBCXXABI_BAREMETAL)
395*8f1d5724Srobert     "	bx	ip\n"
396*8f1d5724Srobert #else
397*8f1d5724Srobert     "	b	_Unwind_Resume\n"
398*8f1d5724Srobert #endif
399*8f1d5724Srobert     "	.popsection");
40079c2e3e6Spatrick #endif // defined(_LIBCXXABI_ARM_EHABI)
40179c2e3e6Spatrick 
40279c2e3e6Spatrick /*
40379c2e3e6Spatrick This routine can catch foreign or native exceptions.  If native, the exception
40479c2e3e6Spatrick can be a primary or dependent variety.  This routine may remain blissfully
40579c2e3e6Spatrick ignorant of whether the native exception is primary or dependent.
40679c2e3e6Spatrick 
40779c2e3e6Spatrick If the exception is native:
40879c2e3e6Spatrick * Increment's the exception's handler count.
40979c2e3e6Spatrick * Push the exception on the stack of currently-caught exceptions if it is not
41079c2e3e6Spatrick   already there (from a rethrow).
41179c2e3e6Spatrick * Decrements the uncaught_exception count.
41279c2e3e6Spatrick * Returns the adjusted pointer to the exception object, which is stored in
41379c2e3e6Spatrick   the __cxa_exception by the personality routine.
41479c2e3e6Spatrick 
41579c2e3e6Spatrick If the exception is foreign, this means it did not originate from one of throw
41679c2e3e6Spatrick routines.  The foreign exception does not necessarily have a __cxa_exception
41779c2e3e6Spatrick header.  However we can catch it here with a catch (...), or with a call
41879c2e3e6Spatrick to terminate or unexpected during unwinding.
41979c2e3e6Spatrick * Do not try to increment the exception's handler count, we don't know where
42079c2e3e6Spatrick   it is.
42179c2e3e6Spatrick * Push the exception on the stack of currently-caught exceptions only if the
42279c2e3e6Spatrick   stack is empty.  The foreign exception has no way to link to the current
42379c2e3e6Spatrick   top of stack.  If the stack is not empty, call terminate.  Even with an
42479c2e3e6Spatrick   empty stack, this is hacked in by pushing a pointer to an imaginary
42579c2e3e6Spatrick   __cxa_exception block in front of the foreign exception.  It would be better
42679c2e3e6Spatrick   if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it
42779c2e3e6Spatrick   doesn't.  It has a stack of __cxa_exception (which has a next* in it).
42879c2e3e6Spatrick * Do not decrement the uncaught_exception count because we didn't increment it
42979c2e3e6Spatrick   in __cxa_throw (or one of our rethrow functions).
43079c2e3e6Spatrick * If we haven't terminated, assume the exception object is just past the
43179c2e3e6Spatrick   _Unwind_Exception and return a pointer to that.
43279c2e3e6Spatrick */
43379c2e3e6Spatrick void*
__cxa_begin_catch(void * unwind_arg)43479c2e3e6Spatrick __cxa_begin_catch(void* unwind_arg) throw()
43579c2e3e6Spatrick {
43679c2e3e6Spatrick     _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
43779c2e3e6Spatrick     bool native_exception = __isOurExceptionClass(unwind_exception);
43879c2e3e6Spatrick     __cxa_eh_globals* globals = __cxa_get_globals();
43979c2e3e6Spatrick     // exception_header is a hackish offset from a foreign exception, but it
44079c2e3e6Spatrick     //   works as long as we're careful not to try to access any __cxa_exception
44179c2e3e6Spatrick     //   parts.
44279c2e3e6Spatrick     __cxa_exception* exception_header =
44379c2e3e6Spatrick             cxa_exception_from_exception_unwind_exception
44479c2e3e6Spatrick             (
44579c2e3e6Spatrick                 static_cast<_Unwind_Exception*>(unwind_exception)
44679c2e3e6Spatrick             );
447*8f1d5724Srobert 
448*8f1d5724Srobert #if defined(__MVS__)
449*8f1d5724Srobert     // Remove the exception object from the linked list of exceptions that the z/OS unwinder
450*8f1d5724Srobert     // maintains before adding it to the libc++abi list of caught exceptions.
451*8f1d5724Srobert     // The libc++abi will manage the lifetime of the exception from this point forward.
452*8f1d5724Srobert     _UnwindZOS_PopException();
453*8f1d5724Srobert #endif
454*8f1d5724Srobert 
45579c2e3e6Spatrick     if (native_exception)
45679c2e3e6Spatrick     {
45779c2e3e6Spatrick         // Increment the handler count, removing the flag about being rethrown
45879c2e3e6Spatrick         exception_header->handlerCount = exception_header->handlerCount < 0 ?
45979c2e3e6Spatrick             -exception_header->handlerCount + 1 : exception_header->handlerCount + 1;
46079c2e3e6Spatrick         //  place the exception on the top of the stack if it's not already
46179c2e3e6Spatrick         //    there by a previous rethrow
46279c2e3e6Spatrick         if (exception_header != globals->caughtExceptions)
46379c2e3e6Spatrick         {
46479c2e3e6Spatrick             exception_header->nextException = globals->caughtExceptions;
46579c2e3e6Spatrick             globals->caughtExceptions = exception_header;
46679c2e3e6Spatrick         }
46779c2e3e6Spatrick         globals->uncaughtExceptions -= 1;   // Not atomically, since globals are thread-local
46879c2e3e6Spatrick #if defined(_LIBCXXABI_ARM_EHABI)
46979c2e3e6Spatrick         return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]);
47079c2e3e6Spatrick #else
47179c2e3e6Spatrick         return exception_header->adjustedPtr;
47279c2e3e6Spatrick #endif
47379c2e3e6Spatrick     }
47479c2e3e6Spatrick     // Else this is a foreign exception
47579c2e3e6Spatrick     // If the caughtExceptions stack is not empty, terminate
47679c2e3e6Spatrick     if (globals->caughtExceptions != 0)
47779c2e3e6Spatrick         std::terminate();
47879c2e3e6Spatrick     // Push the foreign exception on to the stack
47979c2e3e6Spatrick     globals->caughtExceptions = exception_header;
48079c2e3e6Spatrick     return unwind_exception + 1;
48179c2e3e6Spatrick }
48279c2e3e6Spatrick 
48379c2e3e6Spatrick 
48479c2e3e6Spatrick /*
48579c2e3e6Spatrick Upon exit for any reason, a handler must call:
48679c2e3e6Spatrick     void __cxa_end_catch ();
48779c2e3e6Spatrick 
48879c2e3e6Spatrick This routine can be called for either a native or foreign exception.
48979c2e3e6Spatrick For a native exception:
49079c2e3e6Spatrick * Locates the most recently caught exception and decrements its handler count.
49179c2e3e6Spatrick * Removes the exception from the caught exception stack, if the handler count goes to zero.
49279c2e3e6Spatrick * If the handler count goes down to zero, and the exception was not re-thrown
49379c2e3e6Spatrick   by throw, it locates the primary exception (which may be the same as the one
49479c2e3e6Spatrick   it's handling) and decrements its reference count. If that reference count
49579c2e3e6Spatrick   goes to zero, the function destroys the exception. In any case, if the current
49679c2e3e6Spatrick   exception is a dependent exception, it destroys that.
49779c2e3e6Spatrick 
49879c2e3e6Spatrick For a foreign exception:
49979c2e3e6Spatrick * If it has been rethrown, there is nothing to do.
50079c2e3e6Spatrick * Otherwise delete the exception and pop the catch stack to empty.
50179c2e3e6Spatrick */
__cxa_end_catch()50279c2e3e6Spatrick void __cxa_end_catch() {
50379c2e3e6Spatrick   static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception),
50479c2e3e6Spatrick                 "sizeof(__cxa_exception) must be equal to "
50579c2e3e6Spatrick                 "sizeof(__cxa_dependent_exception)");
50679c2e3e6Spatrick   static_assert(__builtin_offsetof(__cxa_exception, referenceCount) ==
50779c2e3e6Spatrick                     __builtin_offsetof(__cxa_dependent_exception,
50879c2e3e6Spatrick                                        primaryException),
50979c2e3e6Spatrick                 "the layout of __cxa_exception must match the layout of "
51079c2e3e6Spatrick                 "__cxa_dependent_exception");
51179c2e3e6Spatrick   static_assert(__builtin_offsetof(__cxa_exception, handlerCount) ==
51279c2e3e6Spatrick                     __builtin_offsetof(__cxa_dependent_exception, handlerCount),
51379c2e3e6Spatrick                 "the layout of __cxa_exception must match the layout of "
51479c2e3e6Spatrick                 "__cxa_dependent_exception");
51579c2e3e6Spatrick     __cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch
51679c2e3e6Spatrick     __cxa_exception* exception_header = globals->caughtExceptions;
51779c2e3e6Spatrick     // If we've rethrown a foreign exception, then globals->caughtExceptions
51879c2e3e6Spatrick     //    will have been made an empty stack by __cxa_rethrow() and there is
51979c2e3e6Spatrick     //    nothing more to be done.  Do nothing!
52079c2e3e6Spatrick     if (NULL != exception_header)
52179c2e3e6Spatrick     {
52279c2e3e6Spatrick         bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader);
52379c2e3e6Spatrick         if (native_exception)
52479c2e3e6Spatrick         {
52579c2e3e6Spatrick             // This is a native exception
52679c2e3e6Spatrick             if (exception_header->handlerCount < 0)
52779c2e3e6Spatrick             {
52879c2e3e6Spatrick                 //  The exception has been rethrown by __cxa_rethrow, so don't delete it
52979c2e3e6Spatrick                 if (0 == incrementHandlerCount(exception_header))
53079c2e3e6Spatrick                 {
53179c2e3e6Spatrick                     //  Remove from the chain of uncaught exceptions
53279c2e3e6Spatrick                     globals->caughtExceptions = exception_header->nextException;
53379c2e3e6Spatrick                     // but don't destroy
53479c2e3e6Spatrick                 }
53579c2e3e6Spatrick                 // Keep handlerCount negative in case there are nested catch's
53679c2e3e6Spatrick                 //   that need to be told that this exception is rethrown.  Don't
53779c2e3e6Spatrick                 //   erase this rethrow flag until the exception is recaught.
53879c2e3e6Spatrick             }
53979c2e3e6Spatrick             else
54079c2e3e6Spatrick             {
54179c2e3e6Spatrick                 // The native exception has not been rethrown
54279c2e3e6Spatrick                 if (0 == decrementHandlerCount(exception_header))
54379c2e3e6Spatrick                 {
54479c2e3e6Spatrick                     //  Remove from the chain of uncaught exceptions
54579c2e3e6Spatrick                     globals->caughtExceptions = exception_header->nextException;
54679c2e3e6Spatrick                     // Destroy this exception, being careful to distinguish
54779c2e3e6Spatrick                     //    between dependent and primary exceptions
54879c2e3e6Spatrick                     if (isDependentException(&exception_header->unwindHeader))
54979c2e3e6Spatrick                     {
55079c2e3e6Spatrick                         // Reset exception_header to primaryException and deallocate the dependent exception
55179c2e3e6Spatrick                         __cxa_dependent_exception* dep_exception_header =
55279c2e3e6Spatrick                             reinterpret_cast<__cxa_dependent_exception*>(exception_header);
55379c2e3e6Spatrick                         exception_header =
55479c2e3e6Spatrick                             cxa_exception_from_thrown_object(dep_exception_header->primaryException);
55579c2e3e6Spatrick                         __cxa_free_dependent_exception(dep_exception_header);
55679c2e3e6Spatrick                     }
55779c2e3e6Spatrick                     // Destroy the primary exception only if its referenceCount goes to 0
55879c2e3e6Spatrick                     //    (this decrement must be atomic)
55979c2e3e6Spatrick                     __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header));
56079c2e3e6Spatrick                 }
56179c2e3e6Spatrick             }
56279c2e3e6Spatrick         }
56379c2e3e6Spatrick         else
56479c2e3e6Spatrick         {
56579c2e3e6Spatrick             // The foreign exception has not been rethrown.  Pop the stack
56679c2e3e6Spatrick             //    and delete it.  If there are nested catch's and they try
56779c2e3e6Spatrick             //    to touch a foreign exception in any way, that is undefined
56879c2e3e6Spatrick             //     behavior.  They likely can't since the only way to catch
56979c2e3e6Spatrick             //     a foreign exception is with catch (...)!
57079c2e3e6Spatrick             _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader);
57179c2e3e6Spatrick             globals->caughtExceptions = 0;
57279c2e3e6Spatrick         }
57379c2e3e6Spatrick     }
57479c2e3e6Spatrick }
57579c2e3e6Spatrick 
57679c2e3e6Spatrick // Note:  exception_header may be masquerading as a __cxa_dependent_exception
57779c2e3e6Spatrick //        and that's ok.  exceptionType is there too.
57879c2e3e6Spatrick //        However watch out for foreign exceptions.  Return null for them.
__cxa_current_exception_type()57979c2e3e6Spatrick std::type_info *__cxa_current_exception_type() {
58079c2e3e6Spatrick //  get the current exception
58179c2e3e6Spatrick     __cxa_eh_globals *globals = __cxa_get_globals_fast();
58279c2e3e6Spatrick     if (NULL == globals)
58379c2e3e6Spatrick         return NULL;     //  If there have never been any exceptions, there are none now.
58479c2e3e6Spatrick     __cxa_exception *exception_header = globals->caughtExceptions;
58579c2e3e6Spatrick     if (NULL == exception_header)
58679c2e3e6Spatrick         return NULL;        //  No current exception
58779c2e3e6Spatrick     if (!__isOurExceptionClass(&exception_header->unwindHeader))
58879c2e3e6Spatrick         return NULL;
58979c2e3e6Spatrick     return exception_header->exceptionType;
59079c2e3e6Spatrick }
59179c2e3e6Spatrick 
59279c2e3e6Spatrick // 2.5.4 Rethrowing Exceptions
59379c2e3e6Spatrick /*  This routine can rethrow native or foreign exceptions.
59479c2e3e6Spatrick If the exception is native:
59579c2e3e6Spatrick * marks the exception object on top of the caughtExceptions stack
59679c2e3e6Spatrick   (in an implementation-defined way) as being rethrown.
59779c2e3e6Spatrick * If the caughtExceptions stack is empty, it calls terminate()
59879c2e3e6Spatrick   (see [C++FDIS] [except.throw], 15.1.8).
59979c2e3e6Spatrick * It then calls _Unwind_RaiseException which should not return
60079c2e3e6Spatrick    (terminate if it does).
60179c2e3e6Spatrick   Note:  exception_header may be masquerading as a __cxa_dependent_exception
60279c2e3e6Spatrick          and that's ok.
60379c2e3e6Spatrick */
__cxa_rethrow()60479c2e3e6Spatrick void __cxa_rethrow() {
60579c2e3e6Spatrick     __cxa_eh_globals* globals = __cxa_get_globals();
60679c2e3e6Spatrick     __cxa_exception* exception_header = globals->caughtExceptions;
60779c2e3e6Spatrick     if (NULL == exception_header)
60879c2e3e6Spatrick         std::terminate();      // throw; called outside of a exception handler
60979c2e3e6Spatrick     bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader);
61079c2e3e6Spatrick     if (native_exception)
61179c2e3e6Spatrick     {
61279c2e3e6Spatrick         //  Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch)
61379c2e3e6Spatrick         exception_header->handlerCount = -exception_header->handlerCount;
61479c2e3e6Spatrick         globals->uncaughtExceptions += 1;
61579c2e3e6Spatrick         //  __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary
61679c2e3e6Spatrick     }
61779c2e3e6Spatrick     else  // this is a foreign exception
61879c2e3e6Spatrick     {
61979c2e3e6Spatrick         // The only way to communicate to __cxa_end_catch that we've rethrown
62079c2e3e6Spatrick         //   a foreign exception, so don't delete us, is to pop the stack here
62179c2e3e6Spatrick         //   which must be empty afterwards.  Then __cxa_end_catch will do
62279c2e3e6Spatrick         //   nothing
62379c2e3e6Spatrick         globals->caughtExceptions = 0;
62479c2e3e6Spatrick     }
62579c2e3e6Spatrick #ifdef __USING_SJLJ_EXCEPTIONS__
62679c2e3e6Spatrick     _Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
62779c2e3e6Spatrick #else
62879c2e3e6Spatrick     _Unwind_RaiseException(&exception_header->unwindHeader);
62979c2e3e6Spatrick #endif
63079c2e3e6Spatrick 
63179c2e3e6Spatrick     //  If we get here, some kind of unwinding error has occurred.
63279c2e3e6Spatrick     //  There is some weird code generation bug happening with
63379c2e3e6Spatrick     //     Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn)
63479c2e3e6Spatrick     //     If we call failed_throw here.  Turns up with -O2 or higher, and -Os.
63579c2e3e6Spatrick     __cxa_begin_catch(&exception_header->unwindHeader);
63679c2e3e6Spatrick     if (native_exception)
63779c2e3e6Spatrick         std::__terminate(exception_header->terminateHandler);
63879c2e3e6Spatrick     // Foreign exception: can't get exception_header->terminateHandler
63979c2e3e6Spatrick     std::terminate();
64079c2e3e6Spatrick }
64179c2e3e6Spatrick 
64279c2e3e6Spatrick /*
64379c2e3e6Spatrick     If thrown_object is not null, atomically increment the referenceCount field
64479c2e3e6Spatrick     of the __cxa_exception header associated with the thrown object referred to
64579c2e3e6Spatrick     by thrown_object.
64679c2e3e6Spatrick 
64779c2e3e6Spatrick     Requires:  If thrown_object is not NULL, it is a native exception.
64879c2e3e6Spatrick */
64979c2e3e6Spatrick void
__cxa_increment_exception_refcount(void * thrown_object)65079c2e3e6Spatrick __cxa_increment_exception_refcount(void *thrown_object) throw() {
65179c2e3e6Spatrick     if (thrown_object != NULL )
65279c2e3e6Spatrick     {
65379c2e3e6Spatrick         __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
65479c2e3e6Spatrick         std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1));
65579c2e3e6Spatrick     }
65679c2e3e6Spatrick }
65779c2e3e6Spatrick 
65879c2e3e6Spatrick /*
65979c2e3e6Spatrick     If thrown_object is not null, atomically decrement the referenceCount field
66079c2e3e6Spatrick     of the __cxa_exception header associated with the thrown object referred to
66179c2e3e6Spatrick     by thrown_object.  If the referenceCount drops to zero, destroy and
66279c2e3e6Spatrick     deallocate the exception.
66379c2e3e6Spatrick 
66479c2e3e6Spatrick     Requires:  If thrown_object is not NULL, it is a native exception.
66579c2e3e6Spatrick */
66679c2e3e6Spatrick _LIBCXXABI_NO_CFI
__cxa_decrement_exception_refcount(void * thrown_object)66779c2e3e6Spatrick void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
66879c2e3e6Spatrick     if (thrown_object != NULL )
66979c2e3e6Spatrick     {
67079c2e3e6Spatrick         __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
67179c2e3e6Spatrick         if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0)
67279c2e3e6Spatrick         {
67379c2e3e6Spatrick             if (NULL != exception_header->exceptionDestructor)
67479c2e3e6Spatrick                 exception_header->exceptionDestructor(thrown_object);
67579c2e3e6Spatrick             __cxa_free_exception(thrown_object);
67679c2e3e6Spatrick         }
67779c2e3e6Spatrick     }
67879c2e3e6Spatrick }
67979c2e3e6Spatrick 
68079c2e3e6Spatrick /*
68179c2e3e6Spatrick     Returns a pointer to the thrown object (if any) at the top of the
68279c2e3e6Spatrick     caughtExceptions stack.  Atomically increment the exception's referenceCount.
68379c2e3e6Spatrick     If there is no such thrown object or if the thrown object is foreign,
68479c2e3e6Spatrick     returns null.
68579c2e3e6Spatrick 
68679c2e3e6Spatrick     We can use __cxa_get_globals_fast here to get the globals because if there have
68779c2e3e6Spatrick     been no exceptions thrown, ever, on this thread, we can return NULL without
68879c2e3e6Spatrick     the need to allocate the exception-handling globals.
68979c2e3e6Spatrick */
__cxa_current_primary_exception()69079c2e3e6Spatrick void *__cxa_current_primary_exception() throw() {
69179c2e3e6Spatrick //  get the current exception
69279c2e3e6Spatrick     __cxa_eh_globals* globals = __cxa_get_globals_fast();
69379c2e3e6Spatrick     if (NULL == globals)
69479c2e3e6Spatrick         return NULL;        //  If there are no globals, there is no exception
69579c2e3e6Spatrick     __cxa_exception* exception_header = globals->caughtExceptions;
69679c2e3e6Spatrick     if (NULL == exception_header)
69779c2e3e6Spatrick         return NULL;        //  No current exception
69879c2e3e6Spatrick     if (!__isOurExceptionClass(&exception_header->unwindHeader))
69979c2e3e6Spatrick         return NULL;        // Can't capture a foreign exception (no way to refcount it)
70079c2e3e6Spatrick     if (isDependentException(&exception_header->unwindHeader)) {
70179c2e3e6Spatrick         __cxa_dependent_exception* dep_exception_header =
70279c2e3e6Spatrick             reinterpret_cast<__cxa_dependent_exception*>(exception_header);
70379c2e3e6Spatrick         exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException);
70479c2e3e6Spatrick     }
70579c2e3e6Spatrick     void* thrown_object = thrown_object_from_cxa_exception(exception_header);
70679c2e3e6Spatrick     __cxa_increment_exception_refcount(thrown_object);
70779c2e3e6Spatrick     return thrown_object;
70879c2e3e6Spatrick }
70979c2e3e6Spatrick 
71079c2e3e6Spatrick /*
71179c2e3e6Spatrick     If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
71279c2e3e6Spatrick     stored in exc is called.  Otherwise the referenceCount stored in the
71379c2e3e6Spatrick     primary exception is decremented, destroying the primary if necessary.
71479c2e3e6Spatrick     Finally the dependent exception is destroyed.
71579c2e3e6Spatrick */
71679c2e3e6Spatrick static
71779c2e3e6Spatrick void
dependent_exception_cleanup(_Unwind_Reason_Code reason,_Unwind_Exception * unwind_exception)71879c2e3e6Spatrick dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
71979c2e3e6Spatrick {
72079c2e3e6Spatrick     __cxa_dependent_exception* dep_exception_header =
72179c2e3e6Spatrick                       reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1;
72279c2e3e6Spatrick     if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
72379c2e3e6Spatrick         std::__terminate(dep_exception_header->terminateHandler);
72479c2e3e6Spatrick     __cxa_decrement_exception_refcount(dep_exception_header->primaryException);
72579c2e3e6Spatrick     __cxa_free_dependent_exception(dep_exception_header);
72679c2e3e6Spatrick }
72779c2e3e6Spatrick 
72879c2e3e6Spatrick /*
72979c2e3e6Spatrick     If thrown_object is not null, allocate, initialize and throw a dependent
73079c2e3e6Spatrick     exception.
73179c2e3e6Spatrick */
73279c2e3e6Spatrick void
__cxa_rethrow_primary_exception(void * thrown_object)73379c2e3e6Spatrick __cxa_rethrow_primary_exception(void* thrown_object)
73479c2e3e6Spatrick {
73579c2e3e6Spatrick     if ( thrown_object != NULL )
73679c2e3e6Spatrick     {
73779c2e3e6Spatrick         // thrown_object guaranteed to be native because
73879c2e3e6Spatrick         //   __cxa_current_primary_exception returns NULL for foreign exceptions
73979c2e3e6Spatrick         __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
74079c2e3e6Spatrick         __cxa_dependent_exception* dep_exception_header =
74179c2e3e6Spatrick             static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception());
74279c2e3e6Spatrick         dep_exception_header->primaryException = thrown_object;
74379c2e3e6Spatrick         __cxa_increment_exception_refcount(thrown_object);
74479c2e3e6Spatrick         dep_exception_header->exceptionType = exception_header->exceptionType;
74579c2e3e6Spatrick         dep_exception_header->unexpectedHandler = std::get_unexpected();
74679c2e3e6Spatrick         dep_exception_header->terminateHandler = std::get_terminate();
74779c2e3e6Spatrick         setDependentExceptionClass(&dep_exception_header->unwindHeader);
74879c2e3e6Spatrick         __cxa_get_globals()->uncaughtExceptions += 1;
74979c2e3e6Spatrick         dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup;
75079c2e3e6Spatrick #ifdef __USING_SJLJ_EXCEPTIONS__
75179c2e3e6Spatrick         _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader);
75279c2e3e6Spatrick #else
75379c2e3e6Spatrick         _Unwind_RaiseException(&dep_exception_header->unwindHeader);
75479c2e3e6Spatrick #endif
75579c2e3e6Spatrick         // Some sort of unwinding error.  Note that terminate is a handler.
75679c2e3e6Spatrick         __cxa_begin_catch(&dep_exception_header->unwindHeader);
75779c2e3e6Spatrick     }
75879c2e3e6Spatrick     // If we return client will call terminate()
75979c2e3e6Spatrick }
76079c2e3e6Spatrick 
76179c2e3e6Spatrick bool
__cxa_uncaught_exception()76279c2e3e6Spatrick __cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; }
76379c2e3e6Spatrick 
76479c2e3e6Spatrick unsigned int
__cxa_uncaught_exceptions()76579c2e3e6Spatrick __cxa_uncaught_exceptions() throw()
76679c2e3e6Spatrick {
76779c2e3e6Spatrick     // This does not report foreign exceptions in flight
76879c2e3e6Spatrick     __cxa_eh_globals* globals = __cxa_get_globals_fast();
76979c2e3e6Spatrick     if (globals == 0)
77079c2e3e6Spatrick         return 0;
77179c2e3e6Spatrick     return globals->uncaughtExceptions;
77279c2e3e6Spatrick }
77379c2e3e6Spatrick 
77479c2e3e6Spatrick }  // extern "C"
77579c2e3e6Spatrick 
77679c2e3e6Spatrick }  // abi
777