xref: /minix3/external/bsd/libc++/dist/libcxxrt/src/exception.cc (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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