14684ddb6SLionel Sambuc /*
24684ddb6SLionel Sambuc * Copyright 2010-2011 PathScale, Inc. All rights reserved.
34684ddb6SLionel Sambuc *
44684ddb6SLionel Sambuc * Redistribution and use in source and binary forms, with or without
54684ddb6SLionel Sambuc * modification, are permitted provided that the following conditions are met:
64684ddb6SLionel Sambuc *
74684ddb6SLionel Sambuc * 1. Redistributions of source code must retain the above copyright notice,
84684ddb6SLionel Sambuc * this list of conditions and the following disclaimer.
94684ddb6SLionel Sambuc *
104684ddb6SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright notice,
114684ddb6SLionel Sambuc * this list of conditions and the following disclaimer in the documentation
124684ddb6SLionel Sambuc * and/or other materials provided with the distribution.
134684ddb6SLionel Sambuc *
144684ddb6SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
154684ddb6SLionel Sambuc * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
164684ddb6SLionel Sambuc * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
174684ddb6SLionel Sambuc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
184684ddb6SLionel Sambuc * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
194684ddb6SLionel Sambuc * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
204684ddb6SLionel Sambuc * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
214684ddb6SLionel Sambuc * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
224684ddb6SLionel Sambuc * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
234684ddb6SLionel Sambuc * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
244684ddb6SLionel Sambuc * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
254684ddb6SLionel Sambuc */
264684ddb6SLionel Sambuc
274684ddb6SLionel Sambuc #include <stdlib.h>
284684ddb6SLionel Sambuc #include <dlfcn.h>
294684ddb6SLionel Sambuc #include <stdio.h>
304684ddb6SLionel Sambuc #include <string.h>
314684ddb6SLionel Sambuc #include <stdint.h>
324684ddb6SLionel Sambuc
334684ddb6SLionel Sambuc #if !defined(__minix)
344684ddb6SLionel Sambuc #include <pthread.h>
354684ddb6SLionel Sambuc #else
364684ddb6SLionel Sambuc #define _MTHREADIFY_PTHREADS 1
374684ddb6SLionel Sambuc #include <minix/mthread.h>
38*0a6a1f1dSLionel Sambuc #define LIBCXXRT_WEAK_LOCKS 1
394684ddb6SLionel Sambuc #endif /* !defined(__minix) */
404684ddb6SLionel Sambuc
414684ddb6SLionel Sambuc #include "typeinfo.h"
424684ddb6SLionel Sambuc #include "dwarf_eh.h"
434684ddb6SLionel Sambuc #include "atomic.h"
444684ddb6SLionel Sambuc #include "cxxabi.h"
454684ddb6SLionel Sambuc
464684ddb6SLionel Sambuc #pragma weak pthread_key_create
474684ddb6SLionel Sambuc #pragma weak pthread_setspecific
484684ddb6SLionel Sambuc #pragma weak pthread_getspecific
494684ddb6SLionel Sambuc #pragma weak pthread_once
504684ddb6SLionel Sambuc #ifdef LIBCXXRT_WEAK_LOCKS
514684ddb6SLionel Sambuc #pragma weak pthread_mutex_lock
524684ddb6SLionel Sambuc #define pthread_mutex_lock(mtx) do {\
534684ddb6SLionel Sambuc if (pthread_mutex_lock) pthread_mutex_lock(mtx);\
544684ddb6SLionel Sambuc } while(0)
554684ddb6SLionel Sambuc #pragma weak pthread_mutex_unlock
564684ddb6SLionel Sambuc #define pthread_mutex_unlock(mtx) do {\
574684ddb6SLionel Sambuc if (pthread_mutex_unlock) pthread_mutex_unlock(mtx);\
584684ddb6SLionel Sambuc } while(0)
594684ddb6SLionel Sambuc #pragma weak pthread_cond_signal
604684ddb6SLionel Sambuc #define pthread_cond_signal(cv) do {\
614684ddb6SLionel Sambuc if (pthread_cond_signal) pthread_cond_signal(cv);\
624684ddb6SLionel Sambuc } while(0)
634684ddb6SLionel Sambuc #pragma weak pthread_cond_wait
644684ddb6SLionel Sambuc #define pthread_cond_wait(cv, mtx) do {\
654684ddb6SLionel Sambuc if (pthread_cond_wait) pthread_cond_wait(cv, mtx);\
664684ddb6SLionel Sambuc } while(0)
674684ddb6SLionel Sambuc #endif
684684ddb6SLionel Sambuc
694684ddb6SLionel Sambuc using namespace ABI_NAMESPACE;
704684ddb6SLionel Sambuc
714684ddb6SLionel Sambuc /**
724684ddb6SLionel Sambuc * Saves the result of the landing pad that we have found. For ARM, this is
734684ddb6SLionel Sambuc * stored in the generic unwind structure, while on other platforms it is
744684ddb6SLionel Sambuc * stored in the C++ exception.
754684ddb6SLionel Sambuc */
saveLandingPad(struct _Unwind_Context * context,struct _Unwind_Exception * ucb,struct __cxa_exception * ex,int selector,dw_eh_ptr_t landingPad)764684ddb6SLionel Sambuc static void saveLandingPad(struct _Unwind_Context *context,
774684ddb6SLionel Sambuc struct _Unwind_Exception *ucb,
784684ddb6SLionel Sambuc struct __cxa_exception *ex,
794684ddb6SLionel Sambuc int selector,
804684ddb6SLionel Sambuc dw_eh_ptr_t landingPad)
814684ddb6SLionel Sambuc {
82*0a6a1f1dSLionel Sambuc #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
834684ddb6SLionel Sambuc // On ARM, we store the saved exception in the generic part of the structure
844684ddb6SLionel Sambuc ucb->barrier_cache.sp = _Unwind_GetGR(context, 13);
85*0a6a1f1dSLionel Sambuc ucb->barrier_cache.bitpattern[1] = static_cast<uint32_t>(selector);
86*0a6a1f1dSLionel Sambuc ucb->barrier_cache.bitpattern[3] = reinterpret_cast<uint32_t>(landingPad);
874684ddb6SLionel Sambuc #endif
884684ddb6SLionel Sambuc // Cache the results for the phase 2 unwind, if we found a handler
894684ddb6SLionel Sambuc // and this is not a foreign exception.
904684ddb6SLionel Sambuc if (ex)
914684ddb6SLionel Sambuc {
924684ddb6SLionel Sambuc ex->handlerSwitchValue = selector;
934684ddb6SLionel Sambuc ex->catchTemp = landingPad;
944684ddb6SLionel Sambuc }
954684ddb6SLionel Sambuc }
964684ddb6SLionel Sambuc
974684ddb6SLionel Sambuc /**
984684ddb6SLionel Sambuc * Loads the saved landing pad. Returns 1 on success, 0 on failure.
994684ddb6SLionel Sambuc */
loadLandingPad(struct _Unwind_Context * context,struct _Unwind_Exception * ucb,struct __cxa_exception * ex,unsigned long * selector,dw_eh_ptr_t * landingPad)1004684ddb6SLionel Sambuc static int loadLandingPad(struct _Unwind_Context *context,
1014684ddb6SLionel Sambuc struct _Unwind_Exception *ucb,
1024684ddb6SLionel Sambuc struct __cxa_exception *ex,
1034684ddb6SLionel Sambuc unsigned long *selector,
1044684ddb6SLionel Sambuc dw_eh_ptr_t *landingPad)
1054684ddb6SLionel Sambuc {
106*0a6a1f1dSLionel Sambuc #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
1074684ddb6SLionel Sambuc *selector = ucb->barrier_cache.bitpattern[1];
108*0a6a1f1dSLionel Sambuc *landingPad = reinterpret_cast<dw_eh_ptr_t>(ucb->barrier_cache.bitpattern[3]);
1094684ddb6SLionel Sambuc return 1;
1104684ddb6SLionel Sambuc #else
1114684ddb6SLionel Sambuc if (ex)
1124684ddb6SLionel Sambuc {
1134684ddb6SLionel Sambuc *selector = ex->handlerSwitchValue;
114*0a6a1f1dSLionel Sambuc *landingPad = reinterpret_cast<dw_eh_ptr_t>(ex->catchTemp);
1154684ddb6SLionel Sambuc return 0;
1164684ddb6SLionel Sambuc }
1174684ddb6SLionel Sambuc return 0;
1184684ddb6SLionel Sambuc #endif
1194684ddb6SLionel Sambuc }
1204684ddb6SLionel Sambuc
continueUnwinding(struct _Unwind_Exception * ex,struct _Unwind_Context * context)1214684ddb6SLionel Sambuc static inline _Unwind_Reason_Code continueUnwinding(struct _Unwind_Exception *ex,
1224684ddb6SLionel Sambuc struct _Unwind_Context *context)
1234684ddb6SLionel Sambuc {
124*0a6a1f1dSLionel Sambuc #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
1254684ddb6SLionel Sambuc if (__gnu_unwind_frame(ex, context) != _URC_OK) { return _URC_FAILURE; }
1264684ddb6SLionel Sambuc #endif
1274684ddb6SLionel Sambuc return _URC_CONTINUE_UNWIND;
1284684ddb6SLionel Sambuc }
1294684ddb6SLionel Sambuc
1304684ddb6SLionel Sambuc
1314684ddb6SLionel Sambuc extern "C" void __cxa_free_exception(void *thrown_exception);
1324684ddb6SLionel Sambuc extern "C" void __cxa_free_dependent_exception(void *thrown_exception);
1334684ddb6SLionel Sambuc extern "C" void* __dynamic_cast(const void *sub,
1344684ddb6SLionel Sambuc const __class_type_info *src,
1354684ddb6SLionel Sambuc const __class_type_info *dst,
1364684ddb6SLionel Sambuc ptrdiff_t src2dst_offset);
1374684ddb6SLionel Sambuc
1384684ddb6SLionel Sambuc /**
1394684ddb6SLionel Sambuc * The type of a handler that has been found.
1404684ddb6SLionel Sambuc */
1414684ddb6SLionel Sambuc typedef enum
1424684ddb6SLionel Sambuc {
1434684ddb6SLionel Sambuc /** No handler. */
1444684ddb6SLionel Sambuc handler_none,
1454684ddb6SLionel Sambuc /**
1464684ddb6SLionel Sambuc * A cleanup - the exception will propagate through this frame, but code
1474684ddb6SLionel Sambuc * must be run when this happens.
1484684ddb6SLionel Sambuc */
1494684ddb6SLionel Sambuc handler_cleanup,
1504684ddb6SLionel Sambuc /**
1514684ddb6SLionel Sambuc * A catch statement. The exception will not propagate past this frame
1524684ddb6SLionel Sambuc * (without an explicit rethrow).
1534684ddb6SLionel Sambuc */
1544684ddb6SLionel Sambuc handler_catch
1554684ddb6SLionel Sambuc } handler_type;
1564684ddb6SLionel Sambuc
1574684ddb6SLionel Sambuc /**
1584684ddb6SLionel Sambuc * Per-thread info required by the runtime. We store a single structure
1594684ddb6SLionel Sambuc * pointer in thread-local storage, because this tends to be a scarce resource
1604684ddb6SLionel Sambuc * and it's impolite to steal all of it and not leave any for the rest of the
1614684ddb6SLionel Sambuc * program.
1624684ddb6SLionel Sambuc *
1634684ddb6SLionel Sambuc * Instances of this structure are allocated lazily - at most one per thread -
1644684ddb6SLionel Sambuc * and are destroyed on thread termination.
1654684ddb6SLionel Sambuc */
1664684ddb6SLionel Sambuc struct __cxa_thread_info
1674684ddb6SLionel Sambuc {
1684684ddb6SLionel Sambuc /** The termination handler for this thread. */
1694684ddb6SLionel Sambuc terminate_handler terminateHandler;
1704684ddb6SLionel Sambuc /** The unexpected exception handler for this thread. */
1714684ddb6SLionel Sambuc unexpected_handler unexpectedHandler;
1724684ddb6SLionel Sambuc /**
1734684ddb6SLionel Sambuc * The number of emergency buffers held by this thread. This is 0 in
1744684ddb6SLionel Sambuc * normal operation - the emergency buffers are only used when malloc()
1754684ddb6SLionel Sambuc * fails to return memory for allocating an exception. Threads are not
1764684ddb6SLionel Sambuc * permitted to hold more than 4 emergency buffers (as per recommendation
1774684ddb6SLionel Sambuc * in ABI spec [3.3.1]).
1784684ddb6SLionel Sambuc */
1794684ddb6SLionel Sambuc int emergencyBuffersHeld;
1804684ddb6SLionel Sambuc /**
1814684ddb6SLionel Sambuc * The exception currently running in a cleanup.
1824684ddb6SLionel Sambuc */
1834684ddb6SLionel Sambuc _Unwind_Exception *currentCleanup;
1844684ddb6SLionel Sambuc /**
1854684ddb6SLionel Sambuc * Our state with respect to foreign exceptions. Usually none, set to
1864684ddb6SLionel Sambuc * caught if we have just caught an exception and rethrown if we are
1874684ddb6SLionel Sambuc * rethrowing it.
1884684ddb6SLionel Sambuc */
1894684ddb6SLionel Sambuc enum
1904684ddb6SLionel Sambuc {
1914684ddb6SLionel Sambuc none,
1924684ddb6SLionel Sambuc caught,
1934684ddb6SLionel Sambuc rethrown
1944684ddb6SLionel Sambuc } foreign_exception_state;
1954684ddb6SLionel Sambuc /**
1964684ddb6SLionel Sambuc * The public part of this structure, accessible from outside of this
1974684ddb6SLionel Sambuc * module.
1984684ddb6SLionel Sambuc */
1994684ddb6SLionel Sambuc __cxa_eh_globals globals;
2004684ddb6SLionel Sambuc };
2014684ddb6SLionel Sambuc /**
2024684ddb6SLionel Sambuc * Dependent exception. This
2034684ddb6SLionel Sambuc */
2044684ddb6SLionel Sambuc struct __cxa_dependent_exception
2054684ddb6SLionel Sambuc {
2064684ddb6SLionel Sambuc #if __LP64__
2074684ddb6SLionel Sambuc void *primaryException;
2084684ddb6SLionel Sambuc #endif
2094684ddb6SLionel Sambuc std::type_info *exceptionType;
2104684ddb6SLionel Sambuc void (*exceptionDestructor) (void *);
2114684ddb6SLionel Sambuc unexpected_handler unexpectedHandler;
2124684ddb6SLionel Sambuc terminate_handler terminateHandler;
2134684ddb6SLionel Sambuc __cxa_exception *nextException;
2144684ddb6SLionel Sambuc int handlerCount;
215*0a6a1f1dSLionel Sambuc #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
2164684ddb6SLionel Sambuc _Unwind_Exception *nextCleanup;
2174684ddb6SLionel Sambuc int cleanupCount;
2184684ddb6SLionel Sambuc #endif
2194684ddb6SLionel Sambuc int handlerSwitchValue;
2204684ddb6SLionel Sambuc const char *actionRecord;
2214684ddb6SLionel Sambuc const char *languageSpecificData;
2224684ddb6SLionel Sambuc void *catchTemp;
2234684ddb6SLionel Sambuc void *adjustedPtr;
2244684ddb6SLionel Sambuc #if !__LP64__
2254684ddb6SLionel Sambuc void *primaryException;
2264684ddb6SLionel Sambuc #endif
2274684ddb6SLionel Sambuc _Unwind_Exception unwindHeader;
2284684ddb6SLionel Sambuc };
2294684ddb6SLionel Sambuc
2304684ddb6SLionel Sambuc
2314684ddb6SLionel Sambuc namespace std
2324684ddb6SLionel Sambuc {
2334684ddb6SLionel Sambuc void unexpected();
2344684ddb6SLionel Sambuc class exception
2354684ddb6SLionel Sambuc {
2364684ddb6SLionel Sambuc public:
2374684ddb6SLionel Sambuc virtual ~exception() throw();
2384684ddb6SLionel Sambuc virtual const char* what() const throw();
2394684ddb6SLionel Sambuc };
2404684ddb6SLionel Sambuc
2414684ddb6SLionel Sambuc }
2424684ddb6SLionel Sambuc
2434684ddb6SLionel Sambuc /**
2444684ddb6SLionel Sambuc * Class of exceptions to distinguish between this and other exception types.
2454684ddb6SLionel Sambuc *
2464684ddb6SLionel Sambuc * The first four characters are the vendor ID. Currently, we use GNUC,
2474684ddb6SLionel Sambuc * because we aim for ABI-compatibility with the GNU implementation, and
2484684ddb6SLionel Sambuc * various checks may test for equality of the class, which is incorrect.
2494684ddb6SLionel Sambuc */
2504684ddb6SLionel Sambuc static const uint64_t exception_class =
2514684ddb6SLionel Sambuc EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\0');
2524684ddb6SLionel Sambuc /**
2534684ddb6SLionel Sambuc * Class used for dependent exceptions.
2544684ddb6SLionel Sambuc */
2554684ddb6SLionel Sambuc static const uint64_t dependent_exception_class =
2564684ddb6SLionel Sambuc EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\x01');
2574684ddb6SLionel Sambuc /**
2584684ddb6SLionel Sambuc * The low four bytes of the exception class, indicating that we conform to the
2594684ddb6SLionel Sambuc * Itanium C++ ABI. This is currently unused, but should be used in the future
2604684ddb6SLionel Sambuc * if we change our exception class, to allow this library and libsupc++ to be
2614684ddb6SLionel Sambuc * linked to the same executable and both to interoperate.
2624684ddb6SLionel Sambuc */
2634684ddb6SLionel Sambuc static const uint32_t abi_exception_class =
2644684ddb6SLionel Sambuc GENERIC_EXCEPTION_CLASS('C', '+', '+', '\0');
2654684ddb6SLionel Sambuc
isCXXException(uint64_t cls)2664684ddb6SLionel Sambuc static bool isCXXException(uint64_t cls)
2674684ddb6SLionel Sambuc {
2684684ddb6SLionel Sambuc return (cls == exception_class) || (cls == dependent_exception_class);
2694684ddb6SLionel Sambuc }
2704684ddb6SLionel Sambuc
isDependentException(uint64_t cls)2714684ddb6SLionel Sambuc static bool isDependentException(uint64_t cls)
2724684ddb6SLionel Sambuc {
2734684ddb6SLionel Sambuc return cls == dependent_exception_class;
2744684ddb6SLionel Sambuc }
2754684ddb6SLionel Sambuc
exceptionFromPointer(void * ex)2764684ddb6SLionel Sambuc static __cxa_exception *exceptionFromPointer(void *ex)
2774684ddb6SLionel Sambuc {
278*0a6a1f1dSLionel Sambuc return reinterpret_cast<__cxa_exception*>(static_cast<char*>(ex) -
2794684ddb6SLionel Sambuc offsetof(struct __cxa_exception, unwindHeader));
2804684ddb6SLionel Sambuc }
realExceptionFromException(__cxa_exception * ex)2814684ddb6SLionel Sambuc static __cxa_exception *realExceptionFromException(__cxa_exception *ex)
2824684ddb6SLionel Sambuc {
2834684ddb6SLionel Sambuc if (!isDependentException(ex->unwindHeader.exception_class)) { return ex; }
284*0a6a1f1dSLionel Sambuc return reinterpret_cast<__cxa_exception*>((reinterpret_cast<__cxa_dependent_exception*>(ex))->primaryException)-1;
2854684ddb6SLionel Sambuc }
2864684ddb6SLionel Sambuc
2874684ddb6SLionel Sambuc
2884684ddb6SLionel Sambuc namespace std
2894684ddb6SLionel Sambuc {
2904684ddb6SLionel Sambuc // Forward declaration of standard library terminate() function used to
2914684ddb6SLionel Sambuc // abort execution.
2924684ddb6SLionel Sambuc void terminate(void);
2934684ddb6SLionel Sambuc }
2944684ddb6SLionel Sambuc
2954684ddb6SLionel Sambuc using namespace ABI_NAMESPACE;
2964684ddb6SLionel Sambuc
2974684ddb6SLionel Sambuc
2984684ddb6SLionel Sambuc
2994684ddb6SLionel Sambuc /** The global termination handler. */
3004684ddb6SLionel Sambuc static terminate_handler terminateHandler = abort;
3014684ddb6SLionel Sambuc /** The global unexpected exception handler. */
3024684ddb6SLionel Sambuc static unexpected_handler unexpectedHandler = std::terminate;
3034684ddb6SLionel Sambuc
3044684ddb6SLionel Sambuc /** Key used for thread-local data. */
3054684ddb6SLionel Sambuc static pthread_key_t eh_key;
3064684ddb6SLionel Sambuc
3074684ddb6SLionel Sambuc
3084684ddb6SLionel Sambuc /**
3094684ddb6SLionel Sambuc * Cleanup function, allowing foreign exception handlers to correctly destroy
3104684ddb6SLionel Sambuc * this exception if they catch it.
3114684ddb6SLionel Sambuc */
exception_cleanup(_Unwind_Reason_Code reason,struct _Unwind_Exception * ex)3124684ddb6SLionel Sambuc static void exception_cleanup(_Unwind_Reason_Code reason,
3134684ddb6SLionel Sambuc struct _Unwind_Exception *ex)
3144684ddb6SLionel Sambuc {
315*0a6a1f1dSLionel Sambuc __cxa_free_exception(static_cast<void*>(ex));
3164684ddb6SLionel Sambuc }
dependent_exception_cleanup(_Unwind_Reason_Code reason,struct _Unwind_Exception * ex)3174684ddb6SLionel Sambuc static void dependent_exception_cleanup(_Unwind_Reason_Code reason,
3184684ddb6SLionel Sambuc struct _Unwind_Exception *ex)
3194684ddb6SLionel Sambuc {
3204684ddb6SLionel Sambuc
321*0a6a1f1dSLionel Sambuc __cxa_free_dependent_exception(static_cast<void*>(ex));
3224684ddb6SLionel Sambuc }
3234684ddb6SLionel Sambuc
3244684ddb6SLionel Sambuc /**
3254684ddb6SLionel Sambuc * Recursively walk a list of exceptions and delete them all in post-order.
3264684ddb6SLionel Sambuc */
free_exception_list(__cxa_exception * ex)3274684ddb6SLionel Sambuc static void free_exception_list(__cxa_exception *ex)
3284684ddb6SLionel Sambuc {
3294684ddb6SLionel Sambuc if (0 != ex->nextException)
3304684ddb6SLionel Sambuc {
3314684ddb6SLionel Sambuc free_exception_list(ex->nextException);
3324684ddb6SLionel Sambuc }
3334684ddb6SLionel Sambuc // __cxa_free_exception() expects to be passed the thrown object, which
3344684ddb6SLionel Sambuc // immediately follows the exception, not the exception itself
3354684ddb6SLionel Sambuc __cxa_free_exception(ex+1);
3364684ddb6SLionel Sambuc }
3374684ddb6SLionel Sambuc
3384684ddb6SLionel Sambuc /**
3394684ddb6SLionel Sambuc * Cleanup function called when a thread exists to make certain that all of the
3404684ddb6SLionel Sambuc * per-thread data is deleted.
3414684ddb6SLionel Sambuc */
thread_cleanup(void * thread_info)3424684ddb6SLionel Sambuc static void thread_cleanup(void* thread_info)
3434684ddb6SLionel Sambuc {
344*0a6a1f1dSLionel Sambuc __cxa_thread_info *info = static_cast<__cxa_thread_info*>(thread_info);
3454684ddb6SLionel Sambuc if (info->globals.caughtExceptions)
3464684ddb6SLionel Sambuc {
3474684ddb6SLionel Sambuc // If this is a foreign exception, ask it to clean itself up.
3484684ddb6SLionel Sambuc if (info->foreign_exception_state != __cxa_thread_info::none)
3494684ddb6SLionel Sambuc {
350*0a6a1f1dSLionel Sambuc _Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(info->globals.caughtExceptions);
3514684ddb6SLionel Sambuc e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
3524684ddb6SLionel Sambuc }
3534684ddb6SLionel Sambuc else
3544684ddb6SLionel Sambuc {
3554684ddb6SLionel Sambuc free_exception_list(info->globals.caughtExceptions);
3564684ddb6SLionel Sambuc }
3574684ddb6SLionel Sambuc }
3584684ddb6SLionel Sambuc free(thread_info);
3594684ddb6SLionel Sambuc }
3604684ddb6SLionel Sambuc
3614684ddb6SLionel Sambuc
3624684ddb6SLionel Sambuc /**
3634684ddb6SLionel Sambuc * Once control used to protect the key creation.
3644684ddb6SLionel Sambuc */
3654684ddb6SLionel Sambuc static pthread_once_t once_control = PTHREAD_ONCE_INIT;
3664684ddb6SLionel Sambuc
3674684ddb6SLionel Sambuc /**
3684684ddb6SLionel Sambuc * We may not be linked against a full pthread implementation. If we're not,
3694684ddb6SLionel Sambuc * then we need to fake the thread-local storage by storing 'thread-local'
3704684ddb6SLionel Sambuc * things in a global.
3714684ddb6SLionel Sambuc */
3724684ddb6SLionel Sambuc static bool fakeTLS;
3734684ddb6SLionel Sambuc /**
3744684ddb6SLionel Sambuc * Thread-local storage for a single-threaded program.
3754684ddb6SLionel Sambuc */
3764684ddb6SLionel Sambuc static __cxa_thread_info singleThreadInfo;
3774684ddb6SLionel Sambuc /**
3784684ddb6SLionel Sambuc * Initialise eh_key.
3794684ddb6SLionel Sambuc */
init_key(void)3804684ddb6SLionel Sambuc static void init_key(void)
3814684ddb6SLionel Sambuc {
3824684ddb6SLionel Sambuc if ((0 == pthread_key_create) ||
3834684ddb6SLionel Sambuc (0 == pthread_setspecific) ||
3844684ddb6SLionel Sambuc (0 == pthread_getspecific))
3854684ddb6SLionel Sambuc {
3864684ddb6SLionel Sambuc fakeTLS = true;
3874684ddb6SLionel Sambuc return;
3884684ddb6SLionel Sambuc }
3894684ddb6SLionel Sambuc pthread_key_create(&eh_key, thread_cleanup);
390*0a6a1f1dSLionel Sambuc pthread_setspecific(eh_key, reinterpret_cast<void *>(0x42));
391*0a6a1f1dSLionel Sambuc fakeTLS = (pthread_getspecific(eh_key) != reinterpret_cast<void *>(0x42));
3924684ddb6SLionel Sambuc pthread_setspecific(eh_key, 0);
3934684ddb6SLionel Sambuc }
3944684ddb6SLionel Sambuc
3954684ddb6SLionel Sambuc /**
3964684ddb6SLionel Sambuc * Returns the thread info structure, creating it if it is not already created.
3974684ddb6SLionel Sambuc */
thread_info()3984684ddb6SLionel Sambuc static __cxa_thread_info *thread_info()
3994684ddb6SLionel Sambuc {
4004684ddb6SLionel Sambuc if ((0 == pthread_once) || pthread_once(&once_control, init_key))
4014684ddb6SLionel Sambuc {
4024684ddb6SLionel Sambuc fakeTLS = true;
4034684ddb6SLionel Sambuc }
4044684ddb6SLionel Sambuc if (fakeTLS) { return &singleThreadInfo; }
405*0a6a1f1dSLionel Sambuc __cxa_thread_info *info = static_cast<__cxa_thread_info*>(pthread_getspecific(eh_key));
4064684ddb6SLionel Sambuc if (0 == info)
4074684ddb6SLionel Sambuc {
408*0a6a1f1dSLionel Sambuc info = static_cast<__cxa_thread_info*>(calloc(1, sizeof(__cxa_thread_info)));
4094684ddb6SLionel Sambuc pthread_setspecific(eh_key, info);
4104684ddb6SLionel Sambuc }
4114684ddb6SLionel Sambuc return info;
4124684ddb6SLionel Sambuc }
4134684ddb6SLionel Sambuc /**
4144684ddb6SLionel Sambuc * Fast version of thread_info(). May fail if thread_info() is not called on
4154684ddb6SLionel Sambuc * this thread at least once already.
4164684ddb6SLionel Sambuc */
thread_info_fast()4174684ddb6SLionel Sambuc static __cxa_thread_info *thread_info_fast()
4184684ddb6SLionel Sambuc {
4194684ddb6SLionel Sambuc if (fakeTLS) { return &singleThreadInfo; }
420*0a6a1f1dSLionel Sambuc return static_cast<__cxa_thread_info*>(pthread_getspecific(eh_key));
4214684ddb6SLionel Sambuc }
4224684ddb6SLionel Sambuc /**
4234684ddb6SLionel Sambuc * ABI function returning the __cxa_eh_globals structure.
4244684ddb6SLionel Sambuc */
__cxa_get_globals(void)4254684ddb6SLionel Sambuc extern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals(void)
4264684ddb6SLionel Sambuc {
4274684ddb6SLionel Sambuc return &(thread_info()->globals);
4284684ddb6SLionel Sambuc }
4294684ddb6SLionel Sambuc /**
4304684ddb6SLionel Sambuc * Version of __cxa_get_globals() assuming that __cxa_get_globals() has already
4314684ddb6SLionel Sambuc * been called at least once by this thread.
4324684ddb6SLionel Sambuc */
__cxa_get_globals_fast(void)4334684ddb6SLionel Sambuc extern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals_fast(void)
4344684ddb6SLionel Sambuc {
4354684ddb6SLionel Sambuc return &(thread_info_fast()->globals);
4364684ddb6SLionel Sambuc }
4374684ddb6SLionel Sambuc
4384684ddb6SLionel Sambuc /**
4394684ddb6SLionel Sambuc * An emergency allocation reserved for when malloc fails. This is treated as
4404684ddb6SLionel Sambuc * 16 buffers of 1KB each.
4414684ddb6SLionel Sambuc */
4424684ddb6SLionel Sambuc static char emergency_buffer[16384];
4434684ddb6SLionel Sambuc /**
4444684ddb6SLionel Sambuc * Flag indicating whether each buffer is allocated.
4454684ddb6SLionel Sambuc */
4464684ddb6SLionel Sambuc static bool buffer_allocated[16];
4474684ddb6SLionel Sambuc /**
4484684ddb6SLionel Sambuc * Lock used to protect emergency allocation.
4494684ddb6SLionel Sambuc */
4504684ddb6SLionel Sambuc static pthread_mutex_t emergency_malloc_lock = PTHREAD_MUTEX_INITIALIZER;
4514684ddb6SLionel Sambuc /**
4524684ddb6SLionel Sambuc * Condition variable used to wait when two threads are both trying to use the
4534684ddb6SLionel Sambuc * emergency malloc() buffer at once.
4544684ddb6SLionel Sambuc */
4554684ddb6SLionel Sambuc static pthread_cond_t emergency_malloc_wait = PTHREAD_COND_INITIALIZER;
4564684ddb6SLionel Sambuc
4574684ddb6SLionel Sambuc /**
4584684ddb6SLionel Sambuc * Allocates size bytes from the emergency allocation mechanism, if possible.
4594684ddb6SLionel Sambuc * This function will fail if size is over 1KB or if this thread already has 4
4604684ddb6SLionel Sambuc * emergency buffers. If all emergency buffers are allocated, it will sleep
4614684ddb6SLionel Sambuc * until one becomes available.
4624684ddb6SLionel Sambuc */
emergency_malloc(size_t size)4634684ddb6SLionel Sambuc static char *emergency_malloc(size_t size)
4644684ddb6SLionel Sambuc {
4654684ddb6SLionel Sambuc if (size > 1024) { return 0; }
4664684ddb6SLionel Sambuc
4674684ddb6SLionel Sambuc __cxa_thread_info *info = thread_info();
4684684ddb6SLionel Sambuc // Only 4 emergency buffers allowed per thread!
4694684ddb6SLionel Sambuc if (info->emergencyBuffersHeld > 3) { return 0; }
4704684ddb6SLionel Sambuc
4714684ddb6SLionel Sambuc pthread_mutex_lock(&emergency_malloc_lock);
4724684ddb6SLionel Sambuc int buffer = -1;
4734684ddb6SLionel Sambuc while (buffer < 0)
4744684ddb6SLionel Sambuc {
4754684ddb6SLionel Sambuc // While we were sleeping on the lock, another thread might have free'd
4764684ddb6SLionel Sambuc // enough memory for us to use, so try the allocation again - no point
4774684ddb6SLionel Sambuc // using the emergency buffer if there is some real memory that we can
4784684ddb6SLionel Sambuc // use...
4794684ddb6SLionel Sambuc void *m = calloc(1, size);
4804684ddb6SLionel Sambuc if (0 != m)
4814684ddb6SLionel Sambuc {
4824684ddb6SLionel Sambuc pthread_mutex_unlock(&emergency_malloc_lock);
483*0a6a1f1dSLionel Sambuc return static_cast<char*>(m);
4844684ddb6SLionel Sambuc }
4854684ddb6SLionel Sambuc for (int i=0 ; i<16 ; i++)
4864684ddb6SLionel Sambuc {
4874684ddb6SLionel Sambuc if (!buffer_allocated[i])
4884684ddb6SLionel Sambuc {
4894684ddb6SLionel Sambuc buffer = i;
4904684ddb6SLionel Sambuc buffer_allocated[i] = true;
4914684ddb6SLionel Sambuc break;
4924684ddb6SLionel Sambuc }
4934684ddb6SLionel Sambuc }
4944684ddb6SLionel Sambuc // If there still isn't a buffer available, then sleep on the condition
4954684ddb6SLionel Sambuc // variable. This will be signalled when another thread releases one
4964684ddb6SLionel Sambuc // of the emergency buffers.
4974684ddb6SLionel Sambuc if (buffer < 0)
4984684ddb6SLionel Sambuc {
4994684ddb6SLionel Sambuc pthread_cond_wait(&emergency_malloc_wait, &emergency_malloc_lock);
5004684ddb6SLionel Sambuc }
5014684ddb6SLionel Sambuc }
5024684ddb6SLionel Sambuc pthread_mutex_unlock(&emergency_malloc_lock);
5034684ddb6SLionel Sambuc info->emergencyBuffersHeld++;
5044684ddb6SLionel Sambuc return emergency_buffer + (1024 * buffer);
5054684ddb6SLionel Sambuc }
5064684ddb6SLionel Sambuc
5074684ddb6SLionel Sambuc /**
5084684ddb6SLionel Sambuc * Frees a buffer returned by emergency_malloc().
5094684ddb6SLionel Sambuc *
5104684ddb6SLionel Sambuc * Note: Neither this nor emergency_malloc() is particularly efficient. This
5114684ddb6SLionel Sambuc * should not matter, because neither will be called in normal operation - they
5124684ddb6SLionel Sambuc * are only used when the program runs out of memory, which should not happen
5134684ddb6SLionel Sambuc * often.
5144684ddb6SLionel Sambuc */
emergency_malloc_free(char * ptr)5154684ddb6SLionel Sambuc static void emergency_malloc_free(char *ptr)
5164684ddb6SLionel Sambuc {
5174684ddb6SLionel Sambuc int buffer = -1;
5184684ddb6SLionel Sambuc // Find the buffer corresponding to this pointer.
5194684ddb6SLionel Sambuc for (int i=0 ; i<16 ; i++)
5204684ddb6SLionel Sambuc {
521*0a6a1f1dSLionel Sambuc if (ptr == static_cast<void*>(emergency_buffer + (1024 * i)))
5224684ddb6SLionel Sambuc {
5234684ddb6SLionel Sambuc buffer = i;
5244684ddb6SLionel Sambuc break;
5254684ddb6SLionel Sambuc }
5264684ddb6SLionel Sambuc }
5274684ddb6SLionel Sambuc assert(buffer > 0 &&
5284684ddb6SLionel Sambuc "Trying to free something that is not an emergency buffer!");
5294684ddb6SLionel Sambuc // emergency_malloc() is expected to return 0-initialized data. We don't
5304684ddb6SLionel Sambuc // zero the buffer when allocating it, because the static buffers will
5314684ddb6SLionel Sambuc // begin life containing 0 values.
532*0a6a1f1dSLionel Sambuc memset(ptr, 0, 1024);
5334684ddb6SLionel Sambuc // Signal the condition variable to wake up any threads that are blocking
5344684ddb6SLionel Sambuc // waiting for some space in the emergency buffer
5354684ddb6SLionel Sambuc pthread_mutex_lock(&emergency_malloc_lock);
5364684ddb6SLionel Sambuc // In theory, we don't need to do this with the lock held. In practice,
5374684ddb6SLionel Sambuc // our array of bools will probably be updated using 32-bit or 64-bit
5384684ddb6SLionel Sambuc // memory operations, so this update may clobber adjacent values.
5394684ddb6SLionel Sambuc buffer_allocated[buffer] = false;
5404684ddb6SLionel Sambuc pthread_cond_signal(&emergency_malloc_wait);
5414684ddb6SLionel Sambuc pthread_mutex_unlock(&emergency_malloc_lock);
5424684ddb6SLionel Sambuc }
5434684ddb6SLionel Sambuc
alloc_or_die(size_t size)5444684ddb6SLionel Sambuc static char *alloc_or_die(size_t size)
5454684ddb6SLionel Sambuc {
546*0a6a1f1dSLionel Sambuc char *buffer = static_cast<char*>(calloc(1, size));
5474684ddb6SLionel Sambuc
5484684ddb6SLionel Sambuc // If calloc() doesn't want to give us any memory, try using an emergency
5494684ddb6SLionel Sambuc // buffer.
5504684ddb6SLionel Sambuc if (0 == buffer)
5514684ddb6SLionel Sambuc {
5524684ddb6SLionel Sambuc buffer = emergency_malloc(size);
5534684ddb6SLionel Sambuc // This is only reached if the allocation is greater than 1KB, and
5544684ddb6SLionel Sambuc // anyone throwing objects that big really should know better.
5554684ddb6SLionel Sambuc if (0 == buffer)
5564684ddb6SLionel Sambuc {
5574684ddb6SLionel Sambuc fprintf(stderr, "Out of memory attempting to allocate exception\n");
5584684ddb6SLionel Sambuc std::terminate();
5594684ddb6SLionel Sambuc }
5604684ddb6SLionel Sambuc }
5614684ddb6SLionel Sambuc return buffer;
5624684ddb6SLionel Sambuc }
free_exception(char * e)5634684ddb6SLionel Sambuc static void free_exception(char *e)
5644684ddb6SLionel Sambuc {
5654684ddb6SLionel Sambuc // If this allocation is within the address range of the emergency buffer,
5664684ddb6SLionel Sambuc // don't call free() because it was not allocated with malloc()
5674684ddb6SLionel Sambuc if ((e > emergency_buffer) &&
5684684ddb6SLionel Sambuc (e < (emergency_buffer + sizeof(emergency_buffer))))
5694684ddb6SLionel Sambuc {
5704684ddb6SLionel Sambuc emergency_malloc_free(e);
5714684ddb6SLionel Sambuc }
5724684ddb6SLionel Sambuc else
5734684ddb6SLionel Sambuc {
5744684ddb6SLionel Sambuc free(e);
5754684ddb6SLionel Sambuc }
5764684ddb6SLionel Sambuc }
5774684ddb6SLionel Sambuc
5784684ddb6SLionel Sambuc /**
5794684ddb6SLionel Sambuc * Allocates an exception structure. Returns a pointer to the space that can
5804684ddb6SLionel Sambuc * be used to store an object of thrown_size bytes. This function will use an
5814684ddb6SLionel Sambuc * emergency buffer if malloc() fails, and may block if there are no such
5824684ddb6SLionel Sambuc * buffers available.
5834684ddb6SLionel Sambuc */
__cxa_allocate_exception(size_t thrown_size)5844684ddb6SLionel Sambuc extern "C" void *__cxa_allocate_exception(size_t thrown_size)
5854684ddb6SLionel Sambuc {
5864684ddb6SLionel Sambuc size_t size = thrown_size + sizeof(__cxa_exception);
5874684ddb6SLionel Sambuc char *buffer = alloc_or_die(size);
5884684ddb6SLionel Sambuc return buffer+sizeof(__cxa_exception);
5894684ddb6SLionel Sambuc }
5904684ddb6SLionel Sambuc
__cxa_allocate_dependent_exception(void)5914684ddb6SLionel Sambuc extern "C" void *__cxa_allocate_dependent_exception(void)
5924684ddb6SLionel Sambuc {
5934684ddb6SLionel Sambuc size_t size = sizeof(__cxa_dependent_exception);
5944684ddb6SLionel Sambuc char *buffer = alloc_or_die(size);
5954684ddb6SLionel Sambuc return buffer+sizeof(__cxa_dependent_exception);
5964684ddb6SLionel Sambuc }
5974684ddb6SLionel Sambuc
5984684ddb6SLionel Sambuc /**
5994684ddb6SLionel Sambuc * __cxa_free_exception() is called when an exception was thrown in between
6004684ddb6SLionel Sambuc * calling __cxa_allocate_exception() and actually throwing the exception.
6014684ddb6SLionel Sambuc * This happens when the object's copy constructor throws an exception.
6024684ddb6SLionel Sambuc *
6034684ddb6SLionel Sambuc * In this implementation, it is also called by __cxa_end_catch() and during
6044684ddb6SLionel Sambuc * thread cleanup.
6054684ddb6SLionel Sambuc */
__cxa_free_exception(void * thrown_exception)6064684ddb6SLionel Sambuc extern "C" void __cxa_free_exception(void *thrown_exception)
6074684ddb6SLionel Sambuc {
608*0a6a1f1dSLionel Sambuc __cxa_exception *ex = reinterpret_cast<__cxa_exception*>(thrown_exception) - 1;
6094684ddb6SLionel Sambuc // Free the object that was thrown, calling its destructor
6104684ddb6SLionel Sambuc if (0 != ex->exceptionDestructor)
6114684ddb6SLionel Sambuc {
6124684ddb6SLionel Sambuc try
6134684ddb6SLionel Sambuc {
6144684ddb6SLionel Sambuc ex->exceptionDestructor(thrown_exception);
6154684ddb6SLionel Sambuc }
6164684ddb6SLionel Sambuc catch(...)
6174684ddb6SLionel Sambuc {
6184684ddb6SLionel Sambuc // FIXME: Check that this is really what the spec says to do.
6194684ddb6SLionel Sambuc std::terminate();
6204684ddb6SLionel Sambuc }
6214684ddb6SLionel Sambuc }
6224684ddb6SLionel Sambuc
623*0a6a1f1dSLionel Sambuc free_exception(reinterpret_cast<char*>(ex));
6244684ddb6SLionel Sambuc }
6254684ddb6SLionel Sambuc
releaseException(__cxa_exception * exception)6264684ddb6SLionel Sambuc static void releaseException(__cxa_exception *exception)
6274684ddb6SLionel Sambuc {
6284684ddb6SLionel Sambuc if (isDependentException(exception->unwindHeader.exception_class))
6294684ddb6SLionel Sambuc {
6304684ddb6SLionel Sambuc __cxa_free_dependent_exception(exception+1);
6314684ddb6SLionel Sambuc return;
6324684ddb6SLionel Sambuc }
6334684ddb6SLionel Sambuc if (__sync_sub_and_fetch(&exception->referenceCount, 1) == 0)
6344684ddb6SLionel Sambuc {
6354684ddb6SLionel Sambuc // __cxa_free_exception() expects to be passed the thrown object,
6364684ddb6SLionel Sambuc // which immediately follows the exception, not the exception
6374684ddb6SLionel Sambuc // itself
6384684ddb6SLionel Sambuc __cxa_free_exception(exception+1);
6394684ddb6SLionel Sambuc }
6404684ddb6SLionel Sambuc }
6414684ddb6SLionel Sambuc
__cxa_free_dependent_exception(void * thrown_exception)6424684ddb6SLionel Sambuc void __cxa_free_dependent_exception(void *thrown_exception)
6434684ddb6SLionel Sambuc {
644*0a6a1f1dSLionel Sambuc __cxa_dependent_exception *ex = reinterpret_cast<__cxa_dependent_exception*>(thrown_exception) - 1;
6454684ddb6SLionel Sambuc assert(isDependentException(ex->unwindHeader.exception_class));
6464684ddb6SLionel Sambuc if (ex->primaryException)
6474684ddb6SLionel Sambuc {
648*0a6a1f1dSLionel Sambuc releaseException(realExceptionFromException(reinterpret_cast<__cxa_exception*>(ex)));
6494684ddb6SLionel Sambuc }
650*0a6a1f1dSLionel Sambuc free_exception(reinterpret_cast<char*>(ex));
6514684ddb6SLionel Sambuc }
6524684ddb6SLionel Sambuc
6534684ddb6SLionel Sambuc /**
6544684ddb6SLionel Sambuc * Callback function used with _Unwind_Backtrace().
6554684ddb6SLionel Sambuc *
6564684ddb6SLionel Sambuc * Prints a stack trace. Used only for debugging help.
6574684ddb6SLionel Sambuc *
6584684ddb6SLionel Sambuc * Note: As of FreeBSD 8.1, dladd() still doesn't work properly, so this only
6594684ddb6SLionel Sambuc * correctly prints function names from public, relocatable, symbols.
6604684ddb6SLionel Sambuc */
trace(struct _Unwind_Context * context,void * c)6614684ddb6SLionel Sambuc static _Unwind_Reason_Code trace(struct _Unwind_Context *context, void *c)
6624684ddb6SLionel Sambuc {
6634684ddb6SLionel Sambuc Dl_info myinfo;
6644684ddb6SLionel Sambuc int mylookup =
665*0a6a1f1dSLionel Sambuc dladdr(reinterpret_cast<void *>(__cxa_current_exception_type), &myinfo);
666*0a6a1f1dSLionel Sambuc void *ip = reinterpret_cast<void*>(_Unwind_GetIP(context));
6674684ddb6SLionel Sambuc Dl_info info;
6684684ddb6SLionel Sambuc if (dladdr(ip, &info) != 0)
6694684ddb6SLionel Sambuc {
6704684ddb6SLionel Sambuc if (mylookup == 0 || strcmp(info.dli_fname, myinfo.dli_fname) != 0)
6714684ddb6SLionel Sambuc {
6724684ddb6SLionel Sambuc printf("%p:%s() in %s\n", ip, info.dli_sname, info.dli_fname);
6734684ddb6SLionel Sambuc }
6744684ddb6SLionel Sambuc }
6754684ddb6SLionel Sambuc return _URC_CONTINUE_UNWIND;
6764684ddb6SLionel Sambuc }
6774684ddb6SLionel Sambuc
6784684ddb6SLionel Sambuc /**
6794684ddb6SLionel Sambuc * Report a failure that occurred when attempting to throw an exception.
6804684ddb6SLionel Sambuc *
6814684ddb6SLionel Sambuc * If the failure happened by falling off the end of the stack without finding
6824684ddb6SLionel Sambuc * a handler, prints a back trace before aborting.
6834684ddb6SLionel Sambuc */
684*0a6a1f1dSLionel Sambuc #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
685*0a6a1f1dSLionel Sambuc extern "C" void *__cxa_begin_catch(void *e) throw();
686*0a6a1f1dSLionel Sambuc #else
687*0a6a1f1dSLionel Sambuc extern "C" void *__cxa_begin_catch(void *e);
688*0a6a1f1dSLionel Sambuc #endif
report_failure(_Unwind_Reason_Code err,__cxa_exception * thrown_exception)6894684ddb6SLionel Sambuc static void report_failure(_Unwind_Reason_Code err, __cxa_exception *thrown_exception)
6904684ddb6SLionel Sambuc {
6914684ddb6SLionel Sambuc switch (err)
6924684ddb6SLionel Sambuc {
6934684ddb6SLionel Sambuc default: break;
6944684ddb6SLionel Sambuc case _URC_FATAL_PHASE1_ERROR:
6954684ddb6SLionel Sambuc fprintf(stderr, "Fatal error during phase 1 unwinding\n");
6964684ddb6SLionel Sambuc break;
697*0a6a1f1dSLionel Sambuc #if !defined(__arm__) || defined(__ARM_DWARF_EH__)
6984684ddb6SLionel Sambuc case _URC_FATAL_PHASE2_ERROR:
6994684ddb6SLionel Sambuc fprintf(stderr, "Fatal error during phase 2 unwinding\n");
7004684ddb6SLionel Sambuc break;
7014684ddb6SLionel Sambuc #endif
7024684ddb6SLionel Sambuc case _URC_END_OF_STACK:
703*0a6a1f1dSLionel Sambuc __cxa_begin_catch (&(thrown_exception->unwindHeader));
704*0a6a1f1dSLionel Sambuc std::terminate();
7054684ddb6SLionel Sambuc fprintf(stderr, "Terminating due to uncaught exception %p",
706*0a6a1f1dSLionel Sambuc static_cast<void*>(thrown_exception));
7074684ddb6SLionel Sambuc thrown_exception = realExceptionFromException(thrown_exception);
7084684ddb6SLionel Sambuc static const __class_type_info *e_ti =
7094684ddb6SLionel Sambuc static_cast<const __class_type_info*>(&typeid(std::exception));
7104684ddb6SLionel Sambuc const __class_type_info *throw_ti =
7114684ddb6SLionel Sambuc dynamic_cast<const __class_type_info*>(thrown_exception->exceptionType);
7124684ddb6SLionel Sambuc if (throw_ti)
7134684ddb6SLionel Sambuc {
7144684ddb6SLionel Sambuc std::exception *e =
715*0a6a1f1dSLionel Sambuc static_cast<std::exception*>(e_ti->cast_to(static_cast<void*>(thrown_exception+1),
716*0a6a1f1dSLionel Sambuc throw_ti));
7174684ddb6SLionel Sambuc if (e)
7184684ddb6SLionel Sambuc {
7194684ddb6SLionel Sambuc fprintf(stderr, " '%s'", e->what());
7204684ddb6SLionel Sambuc }
7214684ddb6SLionel Sambuc }
7224684ddb6SLionel Sambuc
7234684ddb6SLionel Sambuc size_t bufferSize = 128;
724*0a6a1f1dSLionel Sambuc char *demangled = static_cast<char*>(malloc(bufferSize));
7254684ddb6SLionel Sambuc const char *mangled = thrown_exception->exceptionType->name();
7264684ddb6SLionel Sambuc int status;
7274684ddb6SLionel Sambuc demangled = __cxa_demangle(mangled, demangled, &bufferSize, &status);
7284684ddb6SLionel Sambuc fprintf(stderr, " of type %s\n",
729*0a6a1f1dSLionel Sambuc status == 0 ? demangled : mangled);
7304684ddb6SLionel Sambuc if (status == 0) { free(demangled); }
7314684ddb6SLionel Sambuc // Print a back trace if no handler is found.
7324684ddb6SLionel Sambuc // TODO: Make this optional
7334684ddb6SLionel Sambuc _Unwind_Backtrace(trace, 0);
734*0a6a1f1dSLionel Sambuc
735*0a6a1f1dSLionel Sambuc // Just abort. No need to call std::terminate for the second time
736*0a6a1f1dSLionel Sambuc abort();
7374684ddb6SLionel Sambuc break;
7384684ddb6SLionel Sambuc }
7394684ddb6SLionel Sambuc std::terminate();
7404684ddb6SLionel Sambuc }
7414684ddb6SLionel Sambuc
throw_exception(__cxa_exception * ex)7424684ddb6SLionel Sambuc static void throw_exception(__cxa_exception *ex)
7434684ddb6SLionel Sambuc {
7444684ddb6SLionel Sambuc __cxa_thread_info *info = thread_info();
7454684ddb6SLionel Sambuc ex->unexpectedHandler = info->unexpectedHandler;
7464684ddb6SLionel Sambuc if (0 == ex->unexpectedHandler)
7474684ddb6SLionel Sambuc {
7484684ddb6SLionel Sambuc ex->unexpectedHandler = unexpectedHandler;
7494684ddb6SLionel Sambuc }
7504684ddb6SLionel Sambuc ex->terminateHandler = info->terminateHandler;
7514684ddb6SLionel Sambuc if (0 == ex->terminateHandler)
7524684ddb6SLionel Sambuc {
7534684ddb6SLionel Sambuc ex->terminateHandler = terminateHandler;
7544684ddb6SLionel Sambuc }
7554684ddb6SLionel Sambuc info->globals.uncaughtExceptions++;
7564684ddb6SLionel Sambuc
7574684ddb6SLionel Sambuc _Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader);
7584684ddb6SLionel Sambuc // The _Unwind_RaiseException() function should not return, it should
7594684ddb6SLionel Sambuc // unwind the stack past this function. If it does return, then something
7604684ddb6SLionel Sambuc // has gone wrong.
7614684ddb6SLionel Sambuc report_failure(err, ex);
7624684ddb6SLionel Sambuc }
7634684ddb6SLionel Sambuc
7644684ddb6SLionel Sambuc
7654684ddb6SLionel Sambuc /**
7664684ddb6SLionel Sambuc * ABI function for throwing an exception. Takes the object to be thrown (the
7674684ddb6SLionel Sambuc * pointer returned by __cxa_allocate_exception()), the type info for the
7684684ddb6SLionel Sambuc * pointee, and the destructor (if there is one) as arguments.
7694684ddb6SLionel Sambuc */
__cxa_throw(void * thrown_exception,std::type_info * tinfo,void (* dest)(void *))7704684ddb6SLionel Sambuc extern "C" void __cxa_throw(void *thrown_exception,
7714684ddb6SLionel Sambuc std::type_info *tinfo,
7724684ddb6SLionel Sambuc void(*dest)(void*))
7734684ddb6SLionel Sambuc {
774*0a6a1f1dSLionel Sambuc __cxa_exception *ex = reinterpret_cast<__cxa_exception*>(thrown_exception) - 1;
7754684ddb6SLionel Sambuc
7764684ddb6SLionel Sambuc ex->referenceCount = 1;
7774684ddb6SLionel Sambuc ex->exceptionType = tinfo;
7784684ddb6SLionel Sambuc
7794684ddb6SLionel Sambuc ex->exceptionDestructor = dest;
7804684ddb6SLionel Sambuc
7814684ddb6SLionel Sambuc ex->unwindHeader.exception_class = exception_class;
7824684ddb6SLionel Sambuc ex->unwindHeader.exception_cleanup = exception_cleanup;
7834684ddb6SLionel Sambuc
7844684ddb6SLionel Sambuc throw_exception(ex);
7854684ddb6SLionel Sambuc }
7864684ddb6SLionel Sambuc
__cxa_rethrow_primary_exception(void * thrown_exception)7874684ddb6SLionel Sambuc extern "C" void __cxa_rethrow_primary_exception(void* thrown_exception)
7884684ddb6SLionel Sambuc {
7894684ddb6SLionel Sambuc if (NULL == thrown_exception) { return; }
7904684ddb6SLionel Sambuc
7914684ddb6SLionel Sambuc __cxa_exception *original = exceptionFromPointer(thrown_exception);
792*0a6a1f1dSLionel Sambuc __cxa_dependent_exception *ex = reinterpret_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception())-1;
7934684ddb6SLionel Sambuc
7944684ddb6SLionel Sambuc ex->primaryException = thrown_exception;
7954684ddb6SLionel Sambuc __cxa_increment_exception_refcount(thrown_exception);
7964684ddb6SLionel Sambuc
7974684ddb6SLionel Sambuc ex->exceptionType = original->exceptionType;
7984684ddb6SLionel Sambuc ex->unwindHeader.exception_class = dependent_exception_class;
7994684ddb6SLionel Sambuc ex->unwindHeader.exception_cleanup = dependent_exception_cleanup;
8004684ddb6SLionel Sambuc
801*0a6a1f1dSLionel Sambuc throw_exception(reinterpret_cast<__cxa_exception*>(ex));
8024684ddb6SLionel Sambuc }
8034684ddb6SLionel Sambuc
__cxa_current_primary_exception(void)8044684ddb6SLionel Sambuc extern "C" void *__cxa_current_primary_exception(void)
8054684ddb6SLionel Sambuc {
8064684ddb6SLionel Sambuc __cxa_eh_globals* globals = __cxa_get_globals();
8074684ddb6SLionel Sambuc __cxa_exception *ex = globals->caughtExceptions;
8084684ddb6SLionel Sambuc
8094684ddb6SLionel Sambuc if (0 == ex) { return NULL; }
8104684ddb6SLionel Sambuc ex = realExceptionFromException(ex);
8114684ddb6SLionel Sambuc __sync_fetch_and_add(&ex->referenceCount, 1);
8124684ddb6SLionel Sambuc return ex + 1;
8134684ddb6SLionel Sambuc }
8144684ddb6SLionel Sambuc
__cxa_increment_exception_refcount(void * thrown_exception)8154684ddb6SLionel Sambuc extern "C" void __cxa_increment_exception_refcount(void* thrown_exception)
8164684ddb6SLionel Sambuc {
8174684ddb6SLionel Sambuc if (NULL == thrown_exception) { return; }
818*0a6a1f1dSLionel Sambuc __cxa_exception *ex = static_cast<__cxa_exception*>(thrown_exception) - 1;
8194684ddb6SLionel Sambuc if (isDependentException(ex->unwindHeader.exception_class)) { return; }
8204684ddb6SLionel Sambuc __sync_fetch_and_add(&ex->referenceCount, 1);
8214684ddb6SLionel Sambuc }
__cxa_decrement_exception_refcount(void * thrown_exception)8224684ddb6SLionel Sambuc extern "C" void __cxa_decrement_exception_refcount(void* thrown_exception)
8234684ddb6SLionel Sambuc {
8244684ddb6SLionel Sambuc if (NULL == thrown_exception) { return; }
825*0a6a1f1dSLionel Sambuc __cxa_exception *ex = static_cast<__cxa_exception*>(thrown_exception) - 1;
8264684ddb6SLionel Sambuc releaseException(ex);
8274684ddb6SLionel Sambuc }
8284684ddb6SLionel Sambuc
8294684ddb6SLionel Sambuc /**
8304684ddb6SLionel Sambuc * ABI function. Rethrows the current exception. Does not remove the
8314684ddb6SLionel Sambuc * exception from the stack or decrement its handler count - the compiler is
8324684ddb6SLionel Sambuc * expected to set the landing pad for this function to the end of the catch
8334684ddb6SLionel Sambuc * block, and then call _Unwind_Resume() to continue unwinding once
8344684ddb6SLionel Sambuc * __cxa_end_catch() has been called and any cleanup code has been run.
8354684ddb6SLionel Sambuc */
__cxa_rethrow()8364684ddb6SLionel Sambuc extern "C" void __cxa_rethrow()
8374684ddb6SLionel Sambuc {
8384684ddb6SLionel Sambuc __cxa_thread_info *ti = thread_info();
8394684ddb6SLionel Sambuc __cxa_eh_globals *globals = &ti->globals;
8404684ddb6SLionel Sambuc // Note: We don't remove this from the caught list here, because
8414684ddb6SLionel Sambuc // __cxa_end_catch will be called when we unwind out of the try block. We
8424684ddb6SLionel Sambuc // could probably make this faster by providing an alternative rethrow
8434684ddb6SLionel Sambuc // function and ensuring that all cleanup code is run before calling it, so
8444684ddb6SLionel Sambuc // we can skip the top stack frame when unwinding.
8454684ddb6SLionel Sambuc __cxa_exception *ex = globals->caughtExceptions;
8464684ddb6SLionel Sambuc
8474684ddb6SLionel Sambuc if (0 == ex)
8484684ddb6SLionel Sambuc {
8494684ddb6SLionel Sambuc fprintf(stderr,
8504684ddb6SLionel Sambuc "Attempting to rethrow an exception that doesn't exist!\n");
8514684ddb6SLionel Sambuc std::terminate();
8524684ddb6SLionel Sambuc }
8534684ddb6SLionel Sambuc
8544684ddb6SLionel Sambuc if (ti->foreign_exception_state != __cxa_thread_info::none)
8554684ddb6SLionel Sambuc {
8564684ddb6SLionel Sambuc ti->foreign_exception_state = __cxa_thread_info::rethrown;
857*0a6a1f1dSLionel Sambuc _Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(ex);
8584684ddb6SLionel Sambuc _Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(e);
8594684ddb6SLionel Sambuc report_failure(err, ex);
8604684ddb6SLionel Sambuc return;
8614684ddb6SLionel Sambuc }
8624684ddb6SLionel Sambuc
8634684ddb6SLionel Sambuc assert(ex->handlerCount > 0 && "Rethrowing uncaught exception!");
8644684ddb6SLionel Sambuc
8654684ddb6SLionel Sambuc // ex->handlerCount will be decremented in __cxa_end_catch in enclosing
8664684ddb6SLionel Sambuc // catch block
8674684ddb6SLionel Sambuc
8684684ddb6SLionel Sambuc // Make handler count negative. This will tell __cxa_end_catch that
8694684ddb6SLionel Sambuc // exception was rethrown and exception object should not be destroyed
8704684ddb6SLionel Sambuc // when handler count become zero
8714684ddb6SLionel Sambuc ex->handlerCount = -ex->handlerCount;
8724684ddb6SLionel Sambuc
8734684ddb6SLionel Sambuc // Continue unwinding the stack with this exception. This should unwind to
8744684ddb6SLionel Sambuc // the place in the caller where __cxa_end_catch() is called. The caller
8754684ddb6SLionel Sambuc // will then run cleanup code and bounce the exception back with
8764684ddb6SLionel Sambuc // _Unwind_Resume().
8774684ddb6SLionel Sambuc _Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(&ex->unwindHeader);
8784684ddb6SLionel Sambuc report_failure(err, ex);
8794684ddb6SLionel Sambuc }
8804684ddb6SLionel Sambuc
8814684ddb6SLionel Sambuc /**
8824684ddb6SLionel Sambuc * Returns the type_info object corresponding to the filter.
8834684ddb6SLionel Sambuc */
get_type_info_entry(_Unwind_Context * context,dwarf_eh_lsda * lsda,int filter)8844684ddb6SLionel Sambuc static std::type_info *get_type_info_entry(_Unwind_Context *context,
8854684ddb6SLionel Sambuc dwarf_eh_lsda *lsda,
8864684ddb6SLionel Sambuc int filter)
8874684ddb6SLionel Sambuc {
8884684ddb6SLionel Sambuc // Get the address of the record in the table.
8894684ddb6SLionel Sambuc dw_eh_ptr_t record = lsda->type_table -
8904684ddb6SLionel Sambuc dwarf_size_of_fixed_size_field(lsda->type_table_encoding)*filter;
8914684ddb6SLionel Sambuc //record -= 4;
8924684ddb6SLionel Sambuc dw_eh_ptr_t start = record;
8934684ddb6SLionel Sambuc // Read the value, but it's probably an indirect reference...
8944684ddb6SLionel Sambuc int64_t offset = read_value(lsda->type_table_encoding, &record);
8954684ddb6SLionel Sambuc
8964684ddb6SLionel Sambuc // (If the entry is 0, don't try to dereference it. That would be bad.)
8974684ddb6SLionel Sambuc if (offset == 0) { return 0; }
8984684ddb6SLionel Sambuc
8994684ddb6SLionel Sambuc // ...so we need to resolve it
900*0a6a1f1dSLionel Sambuc return reinterpret_cast<std::type_info*>(resolve_indirect_value(context,
901*0a6a1f1dSLionel Sambuc lsda->type_table_encoding, offset, start));
9024684ddb6SLionel Sambuc }
9034684ddb6SLionel Sambuc
9044684ddb6SLionel Sambuc
9054684ddb6SLionel Sambuc
9064684ddb6SLionel Sambuc /**
9074684ddb6SLionel Sambuc * Checks the type signature found in a handler against the type of the thrown
9084684ddb6SLionel Sambuc * object. If ex is 0 then it is assumed to be a foreign exception and only
9094684ddb6SLionel Sambuc * matches cleanups.
9104684ddb6SLionel Sambuc */
check_type_signature(__cxa_exception * ex,const std::type_info * type,void * & adjustedPtr)9114684ddb6SLionel Sambuc static bool check_type_signature(__cxa_exception *ex,
9124684ddb6SLionel Sambuc const std::type_info *type,
9134684ddb6SLionel Sambuc void *&adjustedPtr)
9144684ddb6SLionel Sambuc {
915*0a6a1f1dSLionel Sambuc void *exception_ptr = static_cast<void*>(ex+1);
9164684ddb6SLionel Sambuc const std::type_info *ex_type = ex ? ex->exceptionType : 0;
9174684ddb6SLionel Sambuc
9184684ddb6SLionel Sambuc bool is_ptr = ex ? ex_type->__is_pointer_p() : false;
9194684ddb6SLionel Sambuc if (is_ptr)
9204684ddb6SLionel Sambuc {
921*0a6a1f1dSLionel Sambuc exception_ptr = *static_cast<void**>(exception_ptr);
9224684ddb6SLionel Sambuc }
9234684ddb6SLionel Sambuc // Always match a catchall, even with a foreign exception
9244684ddb6SLionel Sambuc //
9254684ddb6SLionel Sambuc // Note: A 0 here is a catchall, not a cleanup, so we return true to
9264684ddb6SLionel Sambuc // indicate that we found a catch.
9274684ddb6SLionel Sambuc if (0 == type)
9284684ddb6SLionel Sambuc {
9294684ddb6SLionel Sambuc if (ex)
9304684ddb6SLionel Sambuc {
9314684ddb6SLionel Sambuc adjustedPtr = exception_ptr;
9324684ddb6SLionel Sambuc }
9334684ddb6SLionel Sambuc return true;
9344684ddb6SLionel Sambuc }
9354684ddb6SLionel Sambuc
9364684ddb6SLionel Sambuc if (0 == ex) { return false; }
9374684ddb6SLionel Sambuc
9384684ddb6SLionel Sambuc // If the types are the same, no casting is needed.
9394684ddb6SLionel Sambuc if (*type == *ex_type)
9404684ddb6SLionel Sambuc {
9414684ddb6SLionel Sambuc adjustedPtr = exception_ptr;
9424684ddb6SLionel Sambuc return true;
9434684ddb6SLionel Sambuc }
9444684ddb6SLionel Sambuc
9454684ddb6SLionel Sambuc
9464684ddb6SLionel Sambuc if (type->__do_catch(ex_type, &exception_ptr, 1))
9474684ddb6SLionel Sambuc {
9484684ddb6SLionel Sambuc adjustedPtr = exception_ptr;
9494684ddb6SLionel Sambuc return true;
9504684ddb6SLionel Sambuc }
9514684ddb6SLionel Sambuc
9524684ddb6SLionel Sambuc return false;
9534684ddb6SLionel Sambuc }
9544684ddb6SLionel Sambuc /**
9554684ddb6SLionel Sambuc * Checks whether the exception matches the type specifiers in this action
9564684ddb6SLionel Sambuc * record. If the exception only matches cleanups, then this returns false.
9574684ddb6SLionel Sambuc * If it matches a catch (including a catchall) then it returns true.
9584684ddb6SLionel Sambuc *
9594684ddb6SLionel Sambuc * The selector argument is used to return the selector that is passed in the
9604684ddb6SLionel Sambuc * second exception register when installing the context.
9614684ddb6SLionel Sambuc */
check_action_record(_Unwind_Context * context,dwarf_eh_lsda * lsda,dw_eh_ptr_t action_record,__cxa_exception * ex,unsigned long * selector,void * & adjustedPtr)9624684ddb6SLionel Sambuc static handler_type check_action_record(_Unwind_Context *context,
9634684ddb6SLionel Sambuc dwarf_eh_lsda *lsda,
9644684ddb6SLionel Sambuc dw_eh_ptr_t action_record,
9654684ddb6SLionel Sambuc __cxa_exception *ex,
9664684ddb6SLionel Sambuc unsigned long *selector,
9674684ddb6SLionel Sambuc void *&adjustedPtr)
9684684ddb6SLionel Sambuc {
9694684ddb6SLionel Sambuc if (!action_record) { return handler_cleanup; }
9704684ddb6SLionel Sambuc handler_type found = handler_none;
9714684ddb6SLionel Sambuc while (action_record)
9724684ddb6SLionel Sambuc {
9734684ddb6SLionel Sambuc int filter = read_sleb128(&action_record);
9744684ddb6SLionel Sambuc dw_eh_ptr_t action_record_offset_base = action_record;
9754684ddb6SLionel Sambuc int displacement = read_sleb128(&action_record);
9764684ddb6SLionel Sambuc action_record = displacement ?
9774684ddb6SLionel Sambuc action_record_offset_base + displacement : 0;
9784684ddb6SLionel Sambuc // We only check handler types for C++ exceptions - foreign exceptions
9794684ddb6SLionel Sambuc // are only allowed for cleanups and catchalls.
9804684ddb6SLionel Sambuc if (filter > 0)
9814684ddb6SLionel Sambuc {
9824684ddb6SLionel Sambuc std::type_info *handler_type = get_type_info_entry(context, lsda, filter);
9834684ddb6SLionel Sambuc if (check_type_signature(ex, handler_type, adjustedPtr))
9844684ddb6SLionel Sambuc {
9854684ddb6SLionel Sambuc *selector = filter;
9864684ddb6SLionel Sambuc return handler_catch;
9874684ddb6SLionel Sambuc }
9884684ddb6SLionel Sambuc }
9894684ddb6SLionel Sambuc else if (filter < 0 && 0 != ex)
9904684ddb6SLionel Sambuc {
9914684ddb6SLionel Sambuc bool matched = false;
9924684ddb6SLionel Sambuc *selector = filter;
993*0a6a1f1dSLionel Sambuc #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
9944684ddb6SLionel Sambuc filter++;
9954684ddb6SLionel Sambuc std::type_info *handler_type = get_type_info_entry(context, lsda, filter--);
9964684ddb6SLionel Sambuc while (handler_type)
9974684ddb6SLionel Sambuc {
9984684ddb6SLionel Sambuc if (check_type_signature(ex, handler_type, adjustedPtr))
9994684ddb6SLionel Sambuc {
10004684ddb6SLionel Sambuc matched = true;
10014684ddb6SLionel Sambuc break;
10024684ddb6SLionel Sambuc }
10034684ddb6SLionel Sambuc handler_type = get_type_info_entry(context, lsda, filter--);
10044684ddb6SLionel Sambuc }
10054684ddb6SLionel Sambuc #else
1006*0a6a1f1dSLionel Sambuc unsigned char *type_index = reinterpret_cast<unsigned char*>(lsda->type_table) - filter - 1;
10074684ddb6SLionel Sambuc while (*type_index)
10084684ddb6SLionel Sambuc {
10094684ddb6SLionel Sambuc std::type_info *handler_type = get_type_info_entry(context, lsda, *(type_index++));
10104684ddb6SLionel Sambuc // If the exception spec matches a permitted throw type for
10114684ddb6SLionel Sambuc // this function, don't report a handler - we are allowed to
10124684ddb6SLionel Sambuc // propagate this exception out.
10134684ddb6SLionel Sambuc if (check_type_signature(ex, handler_type, adjustedPtr))
10144684ddb6SLionel Sambuc {
10154684ddb6SLionel Sambuc matched = true;
10164684ddb6SLionel Sambuc break;
10174684ddb6SLionel Sambuc }
10184684ddb6SLionel Sambuc }
10194684ddb6SLionel Sambuc #endif
10204684ddb6SLionel Sambuc if (matched) { continue; }
10214684ddb6SLionel Sambuc // If we don't find an allowed exception spec, we need to install
10224684ddb6SLionel Sambuc // the context for this action. The landing pad will then call the
10234684ddb6SLionel Sambuc // unexpected exception function. Treat this as a catch
10244684ddb6SLionel Sambuc return handler_catch;
10254684ddb6SLionel Sambuc }
10264684ddb6SLionel Sambuc else if (filter == 0)
10274684ddb6SLionel Sambuc {
10284684ddb6SLionel Sambuc *selector = filter;
10294684ddb6SLionel Sambuc found = handler_cleanup;
10304684ddb6SLionel Sambuc }
10314684ddb6SLionel Sambuc }
10324684ddb6SLionel Sambuc return found;
10334684ddb6SLionel Sambuc }
10344684ddb6SLionel Sambuc
pushCleanupException(_Unwind_Exception * exceptionObject,__cxa_exception * ex)10354684ddb6SLionel Sambuc static void pushCleanupException(_Unwind_Exception *exceptionObject,
10364684ddb6SLionel Sambuc __cxa_exception *ex)
10374684ddb6SLionel Sambuc {
1038*0a6a1f1dSLionel Sambuc #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
10394684ddb6SLionel Sambuc __cxa_thread_info *info = thread_info_fast();
10404684ddb6SLionel Sambuc if (ex)
10414684ddb6SLionel Sambuc {
10424684ddb6SLionel Sambuc ex->cleanupCount++;
10434684ddb6SLionel Sambuc if (ex->cleanupCount > 1)
10444684ddb6SLionel Sambuc {
10454684ddb6SLionel Sambuc assert(exceptionObject == info->currentCleanup);
10464684ddb6SLionel Sambuc return;
10474684ddb6SLionel Sambuc }
10484684ddb6SLionel Sambuc ex->nextCleanup = info->currentCleanup;
10494684ddb6SLionel Sambuc }
10504684ddb6SLionel Sambuc info->currentCleanup = exceptionObject;
10514684ddb6SLionel Sambuc #endif
10524684ddb6SLionel Sambuc }
10534684ddb6SLionel Sambuc
10544684ddb6SLionel Sambuc /**
10554684ddb6SLionel Sambuc * The exception personality function. This is referenced in the unwinding
10564684ddb6SLionel Sambuc * DWARF metadata and is called by the unwind library for each C++ stack frame
10574684ddb6SLionel Sambuc * containing catch or cleanup code.
10584684ddb6SLionel Sambuc */
10594684ddb6SLionel Sambuc extern "C"
10604684ddb6SLionel Sambuc BEGIN_PERSONALITY_FUNCTION(__gxx_personality_v0)
10614684ddb6SLionel Sambuc // This personality function is for version 1 of the ABI. If you use it
10624684ddb6SLionel Sambuc // with a future version of the ABI, it won't know what to do, so it
10634684ddb6SLionel Sambuc // reports a fatal error and give up before it breaks anything.
10644684ddb6SLionel Sambuc if (1 != version)
10654684ddb6SLionel Sambuc {
10664684ddb6SLionel Sambuc return _URC_FATAL_PHASE1_ERROR;
10674684ddb6SLionel Sambuc }
10684684ddb6SLionel Sambuc __cxa_exception *ex = 0;
10694684ddb6SLionel Sambuc __cxa_exception *realEx = 0;
10704684ddb6SLionel Sambuc
10714684ddb6SLionel Sambuc // If this exception is throw by something else then we can't make any
10724684ddb6SLionel Sambuc // assumptions about its layout beyond the fields declared in
10734684ddb6SLionel Sambuc // _Unwind_Exception.
10744684ddb6SLionel Sambuc bool foreignException = !isCXXException(exceptionClass);
10754684ddb6SLionel Sambuc
10764684ddb6SLionel Sambuc // If this isn't a foreign exception, then we have a C++ exception structure
10774684ddb6SLionel Sambuc if (!foreignException)
10784684ddb6SLionel Sambuc {
10794684ddb6SLionel Sambuc ex = exceptionFromPointer(exceptionObject);
10804684ddb6SLionel Sambuc realEx = realExceptionFromException(ex);
10814684ddb6SLionel Sambuc }
10824684ddb6SLionel Sambuc
1083*0a6a1f1dSLionel Sambuc #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
10844684ddb6SLionel Sambuc unsigned char *lsda_addr =
1085*0a6a1f1dSLionel Sambuc static_cast<unsigned char*>(_Unwind_GetLanguageSpecificData(context));
1086*0a6a1f1dSLionel Sambuc #else
1087*0a6a1f1dSLionel Sambuc unsigned char *lsda_addr =
1088*0a6a1f1dSLionel Sambuc reinterpret_cast<unsigned char*>(static_cast<uintptr_t>(_Unwind_GetLanguageSpecificData(context)));
1089*0a6a1f1dSLionel Sambuc #endif
10904684ddb6SLionel Sambuc
10914684ddb6SLionel Sambuc // No LSDA implies no landing pads - try the next frame
10924684ddb6SLionel Sambuc if (0 == lsda_addr) { return continueUnwinding(exceptionObject, context); }
10934684ddb6SLionel Sambuc
10944684ddb6SLionel Sambuc // These two variables define how the exception will be handled.
10954684ddb6SLionel Sambuc dwarf_eh_action action = {0};
10964684ddb6SLionel Sambuc unsigned long selector = 0;
10974684ddb6SLionel Sambuc
10984684ddb6SLionel Sambuc // During the search phase, we do a complete lookup. If we return
10994684ddb6SLionel Sambuc // _URC_HANDLER_FOUND, then the phase 2 unwind will call this function with
11004684ddb6SLionel Sambuc // a _UA_HANDLER_FRAME action, telling us to install the handler frame. If
11014684ddb6SLionel Sambuc // we return _URC_CONTINUE_UNWIND, we may be called again later with a
11024684ddb6SLionel Sambuc // _UA_CLEANUP_PHASE action for this frame.
11034684ddb6SLionel Sambuc //
11044684ddb6SLionel Sambuc // The point of the two-stage unwind allows us to entirely avoid any stack
11054684ddb6SLionel Sambuc // unwinding if there is no handler. If there are just cleanups found,
11064684ddb6SLionel Sambuc // then we can just panic call an abort function.
11074684ddb6SLionel Sambuc //
11084684ddb6SLionel Sambuc // Matching a handler is much more expensive than matching a cleanup,
11094684ddb6SLionel Sambuc // because we don't need to bother doing type comparisons (or looking at
11104684ddb6SLionel Sambuc // the type table at all) for a cleanup. This means that there is no need
11114684ddb6SLionel Sambuc // to cache the result of finding a cleanup, because it's (quite) quick to
11124684ddb6SLionel Sambuc // look it up again from the action table.
11134684ddb6SLionel Sambuc if (actions & _UA_SEARCH_PHASE)
11144684ddb6SLionel Sambuc {
11154684ddb6SLionel Sambuc struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
11164684ddb6SLionel Sambuc
11174684ddb6SLionel Sambuc if (!dwarf_eh_find_callsite(context, &lsda, &action))
11184684ddb6SLionel Sambuc {
11194684ddb6SLionel Sambuc // EH range not found. This happens if exception is thrown and not
11204684ddb6SLionel Sambuc // caught inside a cleanup (destructor). We should call
11214684ddb6SLionel Sambuc // terminate() in this case. The catchTemp (landing pad) field of
11224684ddb6SLionel Sambuc // exception object will contain null when personality function is
11234684ddb6SLionel Sambuc // called with _UA_HANDLER_FRAME action for phase 2 unwinding.
11244684ddb6SLionel Sambuc return _URC_HANDLER_FOUND;
11254684ddb6SLionel Sambuc }
11264684ddb6SLionel Sambuc
11274684ddb6SLionel Sambuc handler_type found_handler = check_action_record(context, &lsda,
11284684ddb6SLionel Sambuc action.action_record, realEx, &selector, ex->adjustedPtr);
11294684ddb6SLionel Sambuc // If there's no action record, we've only found a cleanup, so keep
11304684ddb6SLionel Sambuc // searching for something real
11314684ddb6SLionel Sambuc if (found_handler == handler_catch)
11324684ddb6SLionel Sambuc {
11334684ddb6SLionel Sambuc // Cache the results for the phase 2 unwind, if we found a handler
11344684ddb6SLionel Sambuc // and this is not a foreign exception.
11354684ddb6SLionel Sambuc if (ex)
11364684ddb6SLionel Sambuc {
11374684ddb6SLionel Sambuc saveLandingPad(context, exceptionObject, ex, selector, action.landing_pad);
1138*0a6a1f1dSLionel Sambuc ex->languageSpecificData = reinterpret_cast<const char*>(lsda_addr);
1139*0a6a1f1dSLionel Sambuc ex->actionRecord = reinterpret_cast<const char*>(action.action_record);
11404684ddb6SLionel Sambuc // ex->adjustedPtr is set when finding the action record.
11414684ddb6SLionel Sambuc }
11424684ddb6SLionel Sambuc return _URC_HANDLER_FOUND;
11434684ddb6SLionel Sambuc }
11444684ddb6SLionel Sambuc return continueUnwinding(exceptionObject, context);
11454684ddb6SLionel Sambuc }
11464684ddb6SLionel Sambuc
11474684ddb6SLionel Sambuc
11484684ddb6SLionel Sambuc // If this is a foreign exception, we didn't have anywhere to cache the
11494684ddb6SLionel Sambuc // lookup stuff, so we need to do it again. If this is either a forced
11504684ddb6SLionel Sambuc // unwind, a foreign exception, or a cleanup, then we just install the
11514684ddb6SLionel Sambuc // context for a cleanup.
11524684ddb6SLionel Sambuc if (!(actions & _UA_HANDLER_FRAME))
11534684ddb6SLionel Sambuc {
11544684ddb6SLionel Sambuc // cleanup
11554684ddb6SLionel Sambuc struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
11564684ddb6SLionel Sambuc dwarf_eh_find_callsite(context, &lsda, &action);
11574684ddb6SLionel Sambuc if (0 == action.landing_pad) { return continueUnwinding(exceptionObject, context); }
11584684ddb6SLionel Sambuc handler_type found_handler = check_action_record(context, &lsda,
11594684ddb6SLionel Sambuc action.action_record, realEx, &selector, ex->adjustedPtr);
11604684ddb6SLionel Sambuc // Ignore handlers this time.
11614684ddb6SLionel Sambuc if (found_handler != handler_cleanup) { return continueUnwinding(exceptionObject, context); }
11624684ddb6SLionel Sambuc pushCleanupException(exceptionObject, ex);
11634684ddb6SLionel Sambuc }
11644684ddb6SLionel Sambuc else if (foreignException)
11654684ddb6SLionel Sambuc {
11664684ddb6SLionel Sambuc struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
11674684ddb6SLionel Sambuc dwarf_eh_find_callsite(context, &lsda, &action);
11684684ddb6SLionel Sambuc check_action_record(context, &lsda, action.action_record, realEx,
11694684ddb6SLionel Sambuc &selector, ex->adjustedPtr);
11704684ddb6SLionel Sambuc }
11714684ddb6SLionel Sambuc else if (ex->catchTemp == 0)
11724684ddb6SLionel Sambuc {
11734684ddb6SLionel Sambuc // Uncaught exception in cleanup, calling terminate
11744684ddb6SLionel Sambuc std::terminate();
11754684ddb6SLionel Sambuc }
11764684ddb6SLionel Sambuc else
11774684ddb6SLionel Sambuc {
11784684ddb6SLionel Sambuc // Restore the saved info if we saved some last time.
11794684ddb6SLionel Sambuc loadLandingPad(context, exceptionObject, ex, &selector, &action.landing_pad);
11804684ddb6SLionel Sambuc ex->catchTemp = 0;
11814684ddb6SLionel Sambuc ex->handlerSwitchValue = 0;
11824684ddb6SLionel Sambuc }
11834684ddb6SLionel Sambuc
11844684ddb6SLionel Sambuc
1185*0a6a1f1dSLionel Sambuc _Unwind_SetIP(context, reinterpret_cast<unsigned long>(action.landing_pad));
11864684ddb6SLionel Sambuc _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
1187*0a6a1f1dSLionel Sambuc reinterpret_cast<unsigned long>(exceptionObject));
11884684ddb6SLionel Sambuc _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector);
11894684ddb6SLionel Sambuc
11904684ddb6SLionel Sambuc return _URC_INSTALL_CONTEXT;
11914684ddb6SLionel Sambuc }
11924684ddb6SLionel Sambuc
11934684ddb6SLionel Sambuc /**
11944684ddb6SLionel Sambuc * ABI function called when entering a catch statement. The argument is the
11954684ddb6SLionel Sambuc * pointer passed out of the personality function. This is always the start of
11964684ddb6SLionel Sambuc * the _Unwind_Exception object. The return value for this function is the
11974684ddb6SLionel Sambuc * pointer to the caught exception, which is either the adjusted pointer (for
11984684ddb6SLionel Sambuc * C++ exceptions) of the unadjusted pointer (for foreign exceptions).
11994684ddb6SLionel Sambuc */
1200*0a6a1f1dSLionel Sambuc #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
12014684ddb6SLionel Sambuc extern "C" void *__cxa_begin_catch(void *e) throw()
12024684ddb6SLionel Sambuc #else
12034684ddb6SLionel Sambuc extern "C" void *__cxa_begin_catch(void *e)
12044684ddb6SLionel Sambuc #endif
12054684ddb6SLionel Sambuc {
12064684ddb6SLionel Sambuc // We can't call the fast version here, because if the first exception that
12074684ddb6SLionel Sambuc // we see is a foreign exception then we won't have called it yet.
12084684ddb6SLionel Sambuc __cxa_thread_info *ti = thread_info();
12094684ddb6SLionel Sambuc __cxa_eh_globals *globals = &ti->globals;
12104684ddb6SLionel Sambuc globals->uncaughtExceptions--;
1211*0a6a1f1dSLionel Sambuc _Unwind_Exception *exceptionObject = static_cast<_Unwind_Exception*>(e);
12124684ddb6SLionel Sambuc
12134684ddb6SLionel Sambuc if (isCXXException(exceptionObject->exception_class))
12144684ddb6SLionel Sambuc {
12154684ddb6SLionel Sambuc __cxa_exception *ex = exceptionFromPointer(exceptionObject);
12164684ddb6SLionel Sambuc
12174684ddb6SLionel Sambuc if (ex->handlerCount == 0)
12184684ddb6SLionel Sambuc {
12194684ddb6SLionel Sambuc // Add this to the front of the list of exceptions being handled
12204684ddb6SLionel Sambuc // and increment its handler count so that it won't be deleted
12214684ddb6SLionel Sambuc // prematurely.
12224684ddb6SLionel Sambuc ex->nextException = globals->caughtExceptions;
12234684ddb6SLionel Sambuc globals->caughtExceptions = ex;
12244684ddb6SLionel Sambuc }
12254684ddb6SLionel Sambuc
12264684ddb6SLionel Sambuc if (ex->handlerCount < 0)
12274684ddb6SLionel Sambuc {
12284684ddb6SLionel Sambuc // Rethrown exception is catched before end of catch block.
12294684ddb6SLionel Sambuc // Clear the rethrow flag (make value positive) - we are allowed
12304684ddb6SLionel Sambuc // to delete this exception at the end of the catch block, as long
12314684ddb6SLionel Sambuc // as it isn't thrown again later.
12324684ddb6SLionel Sambuc
12334684ddb6SLionel Sambuc // Code pattern:
12344684ddb6SLionel Sambuc //
12354684ddb6SLionel Sambuc // try {
12364684ddb6SLionel Sambuc // throw x;
12374684ddb6SLionel Sambuc // }
12384684ddb6SLionel Sambuc // catch() {
12394684ddb6SLionel Sambuc // try {
12404684ddb6SLionel Sambuc // throw;
12414684ddb6SLionel Sambuc // }
12424684ddb6SLionel Sambuc // catch() {
12434684ddb6SLionel Sambuc // __cxa_begin_catch() <- we are here
12444684ddb6SLionel Sambuc // }
12454684ddb6SLionel Sambuc // }
12464684ddb6SLionel Sambuc ex->handlerCount = -ex->handlerCount + 1;
12474684ddb6SLionel Sambuc }
12484684ddb6SLionel Sambuc else
12494684ddb6SLionel Sambuc {
12504684ddb6SLionel Sambuc ex->handlerCount++;
12514684ddb6SLionel Sambuc }
12524684ddb6SLionel Sambuc ti->foreign_exception_state = __cxa_thread_info::none;
12534684ddb6SLionel Sambuc
12544684ddb6SLionel Sambuc return ex->adjustedPtr;
12554684ddb6SLionel Sambuc }
12564684ddb6SLionel Sambuc else
12574684ddb6SLionel Sambuc {
12584684ddb6SLionel Sambuc // If this is a foreign exception, then we need to be able to
12594684ddb6SLionel Sambuc // store it. We can't chain foreign exceptions, so we give up
12604684ddb6SLionel Sambuc // if there are already some outstanding ones.
12614684ddb6SLionel Sambuc if (globals->caughtExceptions != 0)
12624684ddb6SLionel Sambuc {
12634684ddb6SLionel Sambuc std::terminate();
12644684ddb6SLionel Sambuc }
1265*0a6a1f1dSLionel Sambuc globals->caughtExceptions = reinterpret_cast<__cxa_exception*>(exceptionObject);
12664684ddb6SLionel Sambuc ti->foreign_exception_state = __cxa_thread_info::caught;
12674684ddb6SLionel Sambuc }
12684684ddb6SLionel Sambuc // exceptionObject is the pointer to the _Unwind_Exception within the
12694684ddb6SLionel Sambuc // __cxa_exception. The throw object is after this
1270*0a6a1f1dSLionel Sambuc return (reinterpret_cast<char*>(exceptionObject) + sizeof(_Unwind_Exception));
12714684ddb6SLionel Sambuc }
12724684ddb6SLionel Sambuc
12734684ddb6SLionel Sambuc
12744684ddb6SLionel Sambuc
12754684ddb6SLionel Sambuc /**
12764684ddb6SLionel Sambuc * ABI function called when exiting a catch block. This will free the current
12774684ddb6SLionel Sambuc * exception if it is no longer referenced in other catch blocks.
12784684ddb6SLionel Sambuc */
12794684ddb6SLionel Sambuc extern "C" void __cxa_end_catch()
12804684ddb6SLionel Sambuc {
12814684ddb6SLionel Sambuc // We can call the fast version here because the slow version is called in
12824684ddb6SLionel Sambuc // __cxa_throw(), which must have been called before we end a catch block
12834684ddb6SLionel Sambuc __cxa_thread_info *ti = thread_info_fast();
12844684ddb6SLionel Sambuc __cxa_eh_globals *globals = &ti->globals;
12854684ddb6SLionel Sambuc __cxa_exception *ex = globals->caughtExceptions;
12864684ddb6SLionel Sambuc
12874684ddb6SLionel Sambuc assert(0 != ex && "Ending catch when no exception is on the stack!");
12884684ddb6SLionel Sambuc
12894684ddb6SLionel Sambuc if (ti->foreign_exception_state != __cxa_thread_info::none)
12904684ddb6SLionel Sambuc {
12914684ddb6SLionel Sambuc globals->caughtExceptions = 0;
12924684ddb6SLionel Sambuc if (ti->foreign_exception_state != __cxa_thread_info::rethrown)
12934684ddb6SLionel Sambuc {
1294*0a6a1f1dSLionel Sambuc _Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(ti->globals.caughtExceptions);
12954684ddb6SLionel Sambuc e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
12964684ddb6SLionel Sambuc }
12974684ddb6SLionel Sambuc ti->foreign_exception_state = __cxa_thread_info::none;
12984684ddb6SLionel Sambuc return;
12994684ddb6SLionel Sambuc }
13004684ddb6SLionel Sambuc
13014684ddb6SLionel Sambuc bool deleteException = true;
13024684ddb6SLionel Sambuc
13034684ddb6SLionel Sambuc if (ex->handlerCount < 0)
13044684ddb6SLionel Sambuc {
13054684ddb6SLionel Sambuc // exception was rethrown. Exception should not be deleted even if
13064684ddb6SLionel Sambuc // handlerCount become zero.
13074684ddb6SLionel Sambuc // Code pattern:
13084684ddb6SLionel Sambuc // try {
13094684ddb6SLionel Sambuc // throw x;
13104684ddb6SLionel Sambuc // }
13114684ddb6SLionel Sambuc // catch() {
13124684ddb6SLionel Sambuc // {
13134684ddb6SLionel Sambuc // throw;
13144684ddb6SLionel Sambuc // }
13154684ddb6SLionel Sambuc // cleanup {
13164684ddb6SLionel Sambuc // __cxa_end_catch(); <- we are here
13174684ddb6SLionel Sambuc // }
13184684ddb6SLionel Sambuc // }
13194684ddb6SLionel Sambuc //
13204684ddb6SLionel Sambuc
13214684ddb6SLionel Sambuc ex->handlerCount++;
13224684ddb6SLionel Sambuc deleteException = false;
13234684ddb6SLionel Sambuc }
13244684ddb6SLionel Sambuc else
13254684ddb6SLionel Sambuc {
13264684ddb6SLionel Sambuc ex->handlerCount--;
13274684ddb6SLionel Sambuc }
13284684ddb6SLionel Sambuc
13294684ddb6SLionel Sambuc if (ex->handlerCount == 0)
13304684ddb6SLionel Sambuc {
13314684ddb6SLionel Sambuc globals->caughtExceptions = ex->nextException;
13324684ddb6SLionel Sambuc if (deleteException)
13334684ddb6SLionel Sambuc {
13344684ddb6SLionel Sambuc releaseException(ex);
13354684ddb6SLionel Sambuc }
13364684ddb6SLionel Sambuc }
13374684ddb6SLionel Sambuc }
13384684ddb6SLionel Sambuc
13394684ddb6SLionel Sambuc /**
13404684ddb6SLionel Sambuc * ABI function. Returns the type of the current exception.
13414684ddb6SLionel Sambuc */
13424684ddb6SLionel Sambuc extern "C" std::type_info *__cxa_current_exception_type()
13434684ddb6SLionel Sambuc {
13444684ddb6SLionel Sambuc __cxa_eh_globals *globals = __cxa_get_globals();
13454684ddb6SLionel Sambuc __cxa_exception *ex = globals->caughtExceptions;
13464684ddb6SLionel Sambuc return ex ? ex->exceptionType : 0;
13474684ddb6SLionel Sambuc }
13484684ddb6SLionel Sambuc
13494684ddb6SLionel Sambuc /**
13504684ddb6SLionel Sambuc * ABI function, called when an exception specification is violated.
13514684ddb6SLionel Sambuc *
13524684ddb6SLionel Sambuc * This function does not return.
13534684ddb6SLionel Sambuc */
13544684ddb6SLionel Sambuc extern "C" void __cxa_call_unexpected(void*exception)
13554684ddb6SLionel Sambuc {
1356*0a6a1f1dSLionel Sambuc _Unwind_Exception *exceptionObject = static_cast<_Unwind_Exception*>(exception);
13574684ddb6SLionel Sambuc if (exceptionObject->exception_class == exception_class)
13584684ddb6SLionel Sambuc {
13594684ddb6SLionel Sambuc __cxa_exception *ex = exceptionFromPointer(exceptionObject);
13604684ddb6SLionel Sambuc if (ex->unexpectedHandler)
13614684ddb6SLionel Sambuc {
13624684ddb6SLionel Sambuc ex->unexpectedHandler();
13634684ddb6SLionel Sambuc // Should not be reached.
13644684ddb6SLionel Sambuc abort();
13654684ddb6SLionel Sambuc }
13664684ddb6SLionel Sambuc }
13674684ddb6SLionel Sambuc std::unexpected();
13684684ddb6SLionel Sambuc // Should not be reached.
13694684ddb6SLionel Sambuc abort();
13704684ddb6SLionel Sambuc }
13714684ddb6SLionel Sambuc
13724684ddb6SLionel Sambuc /**
13734684ddb6SLionel Sambuc * ABI function, returns the adjusted pointer to the exception object.
13744684ddb6SLionel Sambuc */
13754684ddb6SLionel Sambuc extern "C" void *__cxa_get_exception_ptr(void *exceptionObject)
13764684ddb6SLionel Sambuc {
13774684ddb6SLionel Sambuc return exceptionFromPointer(exceptionObject)->adjustedPtr;
13784684ddb6SLionel Sambuc }
13794684ddb6SLionel Sambuc
13804684ddb6SLionel Sambuc /**
13814684ddb6SLionel Sambuc * As an extension, we provide the ability for the unexpected and terminate
13824684ddb6SLionel Sambuc * handlers to be thread-local. We default to the standards-compliant
13834684ddb6SLionel Sambuc * behaviour where they are global.
13844684ddb6SLionel Sambuc */
13854684ddb6SLionel Sambuc static bool thread_local_handlers = false;
13864684ddb6SLionel Sambuc
13874684ddb6SLionel Sambuc
13884684ddb6SLionel Sambuc namespace pathscale
13894684ddb6SLionel Sambuc {
13904684ddb6SLionel Sambuc /**
13914684ddb6SLionel Sambuc * Sets whether unexpected and terminate handlers should be thread-local.
13924684ddb6SLionel Sambuc */
13934684ddb6SLionel Sambuc void set_use_thread_local_handlers(bool flag) throw()
13944684ddb6SLionel Sambuc {
13954684ddb6SLionel Sambuc thread_local_handlers = flag;
13964684ddb6SLionel Sambuc }
13974684ddb6SLionel Sambuc /**
13984684ddb6SLionel Sambuc * Sets a thread-local unexpected handler.
13994684ddb6SLionel Sambuc */
14004684ddb6SLionel Sambuc unexpected_handler set_unexpected(unexpected_handler f) throw()
14014684ddb6SLionel Sambuc {
14024684ddb6SLionel Sambuc static __cxa_thread_info *info = thread_info();
14034684ddb6SLionel Sambuc unexpected_handler old = info->unexpectedHandler;
14044684ddb6SLionel Sambuc info->unexpectedHandler = f;
14054684ddb6SLionel Sambuc return old;
14064684ddb6SLionel Sambuc }
14074684ddb6SLionel Sambuc /**
14084684ddb6SLionel Sambuc * Sets a thread-local terminate handler.
14094684ddb6SLionel Sambuc */
14104684ddb6SLionel Sambuc terminate_handler set_terminate(terminate_handler f) throw()
14114684ddb6SLionel Sambuc {
14124684ddb6SLionel Sambuc static __cxa_thread_info *info = thread_info();
14134684ddb6SLionel Sambuc terminate_handler old = info->terminateHandler;
14144684ddb6SLionel Sambuc info->terminateHandler = f;
14154684ddb6SLionel Sambuc return old;
14164684ddb6SLionel Sambuc }
14174684ddb6SLionel Sambuc }
14184684ddb6SLionel Sambuc
14194684ddb6SLionel Sambuc namespace std
14204684ddb6SLionel Sambuc {
14214684ddb6SLionel Sambuc /**
14224684ddb6SLionel Sambuc * Sets the function that will be called when an exception specification is
14234684ddb6SLionel Sambuc * violated.
14244684ddb6SLionel Sambuc */
14254684ddb6SLionel Sambuc unexpected_handler set_unexpected(unexpected_handler f) throw()
14264684ddb6SLionel Sambuc {
14274684ddb6SLionel Sambuc if (thread_local_handlers) { return pathscale::set_unexpected(f); }
14284684ddb6SLionel Sambuc
14294684ddb6SLionel Sambuc return ATOMIC_SWAP(&unexpectedHandler, f);
14304684ddb6SLionel Sambuc }
14314684ddb6SLionel Sambuc /**
14324684ddb6SLionel Sambuc * Sets the function that is called to terminate the program.
14334684ddb6SLionel Sambuc */
14344684ddb6SLionel Sambuc terminate_handler set_terminate(terminate_handler f) throw()
14354684ddb6SLionel Sambuc {
14364684ddb6SLionel Sambuc if (thread_local_handlers) { return pathscale::set_terminate(f); }
14374684ddb6SLionel Sambuc
14384684ddb6SLionel Sambuc return ATOMIC_SWAP(&terminateHandler, f);
14394684ddb6SLionel Sambuc }
14404684ddb6SLionel Sambuc /**
14414684ddb6SLionel Sambuc * Terminates the program, calling a custom terminate implementation if
14424684ddb6SLionel Sambuc * required.
14434684ddb6SLionel Sambuc */
14444684ddb6SLionel Sambuc void terminate()
14454684ddb6SLionel Sambuc {
14464684ddb6SLionel Sambuc static __cxa_thread_info *info = thread_info();
14474684ddb6SLionel Sambuc if (0 != info && 0 != info->terminateHandler)
14484684ddb6SLionel Sambuc {
14494684ddb6SLionel Sambuc info->terminateHandler();
14504684ddb6SLionel Sambuc // Should not be reached - a terminate handler is not expected to
14514684ddb6SLionel Sambuc // return.
14524684ddb6SLionel Sambuc abort();
14534684ddb6SLionel Sambuc }
14544684ddb6SLionel Sambuc terminateHandler();
14554684ddb6SLionel Sambuc }
14564684ddb6SLionel Sambuc /**
14574684ddb6SLionel Sambuc * Called when an unexpected exception is encountered (i.e. an exception
14584684ddb6SLionel Sambuc * violates an exception specification). This calls abort() unless a
14594684ddb6SLionel Sambuc * custom handler has been set..
14604684ddb6SLionel Sambuc */
14614684ddb6SLionel Sambuc void unexpected()
14624684ddb6SLionel Sambuc {
14634684ddb6SLionel Sambuc static __cxa_thread_info *info = thread_info();
14644684ddb6SLionel Sambuc if (0 != info && 0 != info->unexpectedHandler)
14654684ddb6SLionel Sambuc {
14664684ddb6SLionel Sambuc info->unexpectedHandler();
14674684ddb6SLionel Sambuc // Should not be reached - a terminate handler is not expected to
14684684ddb6SLionel Sambuc // return.
14694684ddb6SLionel Sambuc abort();
14704684ddb6SLionel Sambuc }
14714684ddb6SLionel Sambuc unexpectedHandler();
14724684ddb6SLionel Sambuc }
14734684ddb6SLionel Sambuc /**
14744684ddb6SLionel Sambuc * Returns whether there are any exceptions currently being thrown that
14754684ddb6SLionel Sambuc * have not been caught. This can occur inside a nested catch statement.
14764684ddb6SLionel Sambuc */
14774684ddb6SLionel Sambuc bool uncaught_exception() throw()
14784684ddb6SLionel Sambuc {
14794684ddb6SLionel Sambuc __cxa_thread_info *info = thread_info();
14804684ddb6SLionel Sambuc return info->globals.uncaughtExceptions != 0;
14814684ddb6SLionel Sambuc }
14824684ddb6SLionel Sambuc /**
14834684ddb6SLionel Sambuc * Returns the current unexpected handler.
14844684ddb6SLionel Sambuc */
14854684ddb6SLionel Sambuc unexpected_handler get_unexpected() throw()
14864684ddb6SLionel Sambuc {
14874684ddb6SLionel Sambuc __cxa_thread_info *info = thread_info();
14884684ddb6SLionel Sambuc if (info->unexpectedHandler)
14894684ddb6SLionel Sambuc {
14904684ddb6SLionel Sambuc return info->unexpectedHandler;
14914684ddb6SLionel Sambuc }
14924684ddb6SLionel Sambuc return ATOMIC_LOAD(&unexpectedHandler);
14934684ddb6SLionel Sambuc }
14944684ddb6SLionel Sambuc /**
14954684ddb6SLionel Sambuc * Returns the current terminate handler.
14964684ddb6SLionel Sambuc */
14974684ddb6SLionel Sambuc terminate_handler get_terminate() throw()
14984684ddb6SLionel Sambuc {
14994684ddb6SLionel Sambuc __cxa_thread_info *info = thread_info();
15004684ddb6SLionel Sambuc if (info->terminateHandler)
15014684ddb6SLionel Sambuc {
15024684ddb6SLionel Sambuc return info->terminateHandler;
15034684ddb6SLionel Sambuc }
15044684ddb6SLionel Sambuc return ATOMIC_LOAD(&terminateHandler);
15054684ddb6SLionel Sambuc }
15064684ddb6SLionel Sambuc }
1507*0a6a1f1dSLionel Sambuc #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
15084684ddb6SLionel Sambuc extern "C" _Unwind_Exception *__cxa_get_cleanup(void)
15094684ddb6SLionel Sambuc {
15104684ddb6SLionel Sambuc __cxa_thread_info *info = thread_info_fast();
15114684ddb6SLionel Sambuc _Unwind_Exception *exceptionObject = info->currentCleanup;
15124684ddb6SLionel Sambuc if (isCXXException(exceptionObject->exception_class))
15134684ddb6SLionel Sambuc {
15144684ddb6SLionel Sambuc __cxa_exception *ex = exceptionFromPointer(exceptionObject);
15154684ddb6SLionel Sambuc ex->cleanupCount--;
15164684ddb6SLionel Sambuc if (ex->cleanupCount == 0)
15174684ddb6SLionel Sambuc {
15184684ddb6SLionel Sambuc info->currentCleanup = ex->nextCleanup;
15194684ddb6SLionel Sambuc ex->nextCleanup = 0;
15204684ddb6SLionel Sambuc }
15214684ddb6SLionel Sambuc }
15224684ddb6SLionel Sambuc else
15234684ddb6SLionel Sambuc {
15244684ddb6SLionel Sambuc info->currentCleanup = 0;
15254684ddb6SLionel Sambuc }
15264684ddb6SLionel Sambuc return exceptionObject;
15274684ddb6SLionel Sambuc }
15284684ddb6SLionel Sambuc
15294684ddb6SLionel Sambuc asm (
15304684ddb6SLionel Sambuc ".pushsection .text.__cxa_end_cleanup \n"
15314684ddb6SLionel Sambuc ".global __cxa_end_cleanup \n"
15324684ddb6SLionel Sambuc ".type __cxa_end_cleanup, \"function\" \n"
15334684ddb6SLionel Sambuc "__cxa_end_cleanup: \n"
15344684ddb6SLionel Sambuc " push {r1, r2, r3, r4} \n"
15354684ddb6SLionel Sambuc " bl __cxa_get_cleanup \n"
15364684ddb6SLionel Sambuc " push {r1, r2, r3, r4} \n"
15374684ddb6SLionel Sambuc " b _Unwind_Resume \n"
15384684ddb6SLionel Sambuc " bl abort \n"
15394684ddb6SLionel Sambuc ".popsection \n"
15404684ddb6SLionel Sambuc );
15414684ddb6SLionel Sambuc #endif
1542