xref: /netbsd-src/external/bsd/libc++/dist/libcxxrt/src/exception.cc (revision 387d62228c66ba3e9bde0e695bfdcdf48c46ece5)
1ccec91a1Sjoerg /*
2ccec91a1Sjoerg  * Copyright 2010-2011 PathScale, Inc. All rights reserved.
3ccec91a1Sjoerg  *
4ccec91a1Sjoerg  * Redistribution and use in source and binary forms, with or without
5ccec91a1Sjoerg  * modification, are permitted provided that the following conditions are met:
6ccec91a1Sjoerg  *
7ccec91a1Sjoerg  * 1. Redistributions of source code must retain the above copyright notice,
8ccec91a1Sjoerg  *    this list of conditions and the following disclaimer.
9ccec91a1Sjoerg  *
10ccec91a1Sjoerg  * 2. Redistributions in binary form must reproduce the above copyright notice,
11ccec91a1Sjoerg  *    this list of conditions and the following disclaimer in the documentation
12ccec91a1Sjoerg  *    and/or other materials provided with the distribution.
13ccec91a1Sjoerg  *
14ccec91a1Sjoerg  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
15ccec91a1Sjoerg  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16ccec91a1Sjoerg  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17ccec91a1Sjoerg  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
18ccec91a1Sjoerg  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19ccec91a1Sjoerg  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20ccec91a1Sjoerg  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21ccec91a1Sjoerg  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22ccec91a1Sjoerg  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23ccec91a1Sjoerg  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24ccec91a1Sjoerg  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25ccec91a1Sjoerg  */
26ccec91a1Sjoerg 
27ccec91a1Sjoerg #include <stdlib.h>
28ccec91a1Sjoerg #include <dlfcn.h>
29ccec91a1Sjoerg #include <stdio.h>
30ccec91a1Sjoerg #include <string.h>
31ccec91a1Sjoerg #include <stdint.h>
32ccec91a1Sjoerg #include <pthread.h>
33ccec91a1Sjoerg #include "typeinfo.h"
34ccec91a1Sjoerg #include "dwarf_eh.h"
35ccec91a1Sjoerg #include "atomic.h"
36ccec91a1Sjoerg #include "cxxabi.h"
37ccec91a1Sjoerg 
38ccec91a1Sjoerg #pragma weak pthread_key_create
39ccec91a1Sjoerg #pragma weak pthread_setspecific
40ccec91a1Sjoerg #pragma weak pthread_getspecific
41ccec91a1Sjoerg #pragma weak pthread_once
425067d178Sjoerg #ifdef LIBCXXRT_WEAK_LOCKS
435067d178Sjoerg #pragma weak pthread_mutex_lock
445067d178Sjoerg #define pthread_mutex_lock(mtx) do {\
455067d178Sjoerg 	if (pthread_mutex_lock) pthread_mutex_lock(mtx);\
465067d178Sjoerg 	} while(0)
475067d178Sjoerg #pragma weak pthread_mutex_unlock
485067d178Sjoerg #define pthread_mutex_unlock(mtx) do {\
495067d178Sjoerg 	if (pthread_mutex_unlock) pthread_mutex_unlock(mtx);\
505067d178Sjoerg 	} while(0)
515067d178Sjoerg #pragma weak pthread_cond_signal
525067d178Sjoerg #define pthread_cond_signal(cv) do {\
535067d178Sjoerg 	if (pthread_cond_signal) pthread_cond_signal(cv);\
545067d178Sjoerg 	} while(0)
555067d178Sjoerg #pragma weak pthread_cond_wait
565067d178Sjoerg #define pthread_cond_wait(cv, mtx) do {\
575067d178Sjoerg 	if (pthread_cond_wait) pthread_cond_wait(cv, mtx);\
585067d178Sjoerg 	} while(0)
595067d178Sjoerg #endif
60ccec91a1Sjoerg 
61ccec91a1Sjoerg using namespace ABI_NAMESPACE;
62ccec91a1Sjoerg 
63ccec91a1Sjoerg /**
64ccec91a1Sjoerg  * Saves the result of the landing pad that we have found.  For ARM, this is
65ccec91a1Sjoerg  * stored in the generic unwind structure, while on other platforms it is
66ccec91a1Sjoerg  * stored in the C++ exception.
67ccec91a1Sjoerg  */
saveLandingPad(struct _Unwind_Context * context,struct _Unwind_Exception * ucb,struct __cxa_exception * ex,int selector,dw_eh_ptr_t landingPad)68ccec91a1Sjoerg static void saveLandingPad(struct _Unwind_Context *context,
69ccec91a1Sjoerg                            struct _Unwind_Exception *ucb,
70ccec91a1Sjoerg                            struct __cxa_exception *ex,
71ccec91a1Sjoerg                            int selector,
72ccec91a1Sjoerg                            dw_eh_ptr_t landingPad)
73ccec91a1Sjoerg {
74534cb174Sjoerg #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
75ccec91a1Sjoerg 	// On ARM, we store the saved exception in the generic part of the structure
76ccec91a1Sjoerg 	ucb->barrier_cache.sp = _Unwind_GetGR(context, 13);
77d0b6b5d5Sjoerg 	ucb->barrier_cache.bitpattern[1] = static_cast<uint32_t>(selector);
78d0b6b5d5Sjoerg 	ucb->barrier_cache.bitpattern[3] = reinterpret_cast<uint32_t>(landingPad);
79ccec91a1Sjoerg #endif
80ccec91a1Sjoerg 	// Cache the results for the phase 2 unwind, if we found a handler
81ccec91a1Sjoerg 	// and this is not a foreign exception.
82ccec91a1Sjoerg 	if (ex)
83ccec91a1Sjoerg 	{
84ccec91a1Sjoerg 		ex->handlerSwitchValue = selector;
85ccec91a1Sjoerg 		ex->catchTemp = landingPad;
86ccec91a1Sjoerg 	}
87ccec91a1Sjoerg }
88ccec91a1Sjoerg 
89ccec91a1Sjoerg /**
90ccec91a1Sjoerg  * Loads the saved landing pad.  Returns 1 on success, 0 on failure.
91ccec91a1Sjoerg  */
loadLandingPad(struct _Unwind_Context * context,struct _Unwind_Exception * ucb,struct __cxa_exception * ex,unsigned long * selector,dw_eh_ptr_t * landingPad)92ccec91a1Sjoerg static int loadLandingPad(struct _Unwind_Context *context,
93ccec91a1Sjoerg                           struct _Unwind_Exception *ucb,
94ccec91a1Sjoerg                           struct __cxa_exception *ex,
95ccec91a1Sjoerg                           unsigned long *selector,
96ccec91a1Sjoerg                           dw_eh_ptr_t *landingPad)
97ccec91a1Sjoerg {
98534cb174Sjoerg #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
99ccec91a1Sjoerg 	*selector = ucb->barrier_cache.bitpattern[1];
100d0b6b5d5Sjoerg 	*landingPad = reinterpret_cast<dw_eh_ptr_t>(ucb->barrier_cache.bitpattern[3]);
101ccec91a1Sjoerg 	return 1;
102ccec91a1Sjoerg #else
103ccec91a1Sjoerg 	if (ex)
104ccec91a1Sjoerg 	{
105ccec91a1Sjoerg 		*selector = ex->handlerSwitchValue;
106d0b6b5d5Sjoerg 		*landingPad = reinterpret_cast<dw_eh_ptr_t>(ex->catchTemp);
107ccec91a1Sjoerg 		return 0;
108ccec91a1Sjoerg 	}
109ccec91a1Sjoerg 	return 0;
110ccec91a1Sjoerg #endif
111ccec91a1Sjoerg }
112ccec91a1Sjoerg 
continueUnwinding(struct _Unwind_Exception * ex,struct _Unwind_Context * context)113ccec91a1Sjoerg static inline _Unwind_Reason_Code continueUnwinding(struct _Unwind_Exception *ex,
114ccec91a1Sjoerg                                                     struct _Unwind_Context *context)
115ccec91a1Sjoerg {
116534cb174Sjoerg #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
117ccec91a1Sjoerg 	if (__gnu_unwind_frame(ex, context) != _URC_OK) { return _URC_FAILURE; }
118ccec91a1Sjoerg #endif
119ccec91a1Sjoerg 	return _URC_CONTINUE_UNWIND;
120ccec91a1Sjoerg }
121ccec91a1Sjoerg 
122ccec91a1Sjoerg 
123ccec91a1Sjoerg extern "C" void __cxa_free_exception(void *thrown_exception);
124ccec91a1Sjoerg extern "C" void __cxa_free_dependent_exception(void *thrown_exception);
125ccec91a1Sjoerg extern "C" void* __dynamic_cast(const void *sub,
126ccec91a1Sjoerg                                 const __class_type_info *src,
127ccec91a1Sjoerg                                 const __class_type_info *dst,
128ccec91a1Sjoerg                                 ptrdiff_t src2dst_offset);
129ccec91a1Sjoerg 
130ccec91a1Sjoerg /**
131ccec91a1Sjoerg  * The type of a handler that has been found.
132ccec91a1Sjoerg  */
133ccec91a1Sjoerg typedef enum
134ccec91a1Sjoerg {
135ccec91a1Sjoerg 	/** No handler. */
136ccec91a1Sjoerg 	handler_none,
137ccec91a1Sjoerg 	/**
138ccec91a1Sjoerg 	 * A cleanup - the exception will propagate through this frame, but code
139ccec91a1Sjoerg 	 * must be run when this happens.
140ccec91a1Sjoerg 	 */
141ccec91a1Sjoerg 	handler_cleanup,
142ccec91a1Sjoerg 	/**
143ccec91a1Sjoerg 	 * A catch statement.  The exception will not propagate past this frame
144ccec91a1Sjoerg 	 * (without an explicit rethrow).
145ccec91a1Sjoerg 	 */
146ccec91a1Sjoerg 	handler_catch
147ccec91a1Sjoerg } handler_type;
148ccec91a1Sjoerg 
149ccec91a1Sjoerg /**
150ccec91a1Sjoerg  * Per-thread info required by the runtime.  We store a single structure
151ccec91a1Sjoerg  * pointer in thread-local storage, because this tends to be a scarce resource
152ccec91a1Sjoerg  * and it's impolite to steal all of it and not leave any for the rest of the
153ccec91a1Sjoerg  * program.
154ccec91a1Sjoerg  *
155ccec91a1Sjoerg  * Instances of this structure are allocated lazily - at most one per thread -
156ccec91a1Sjoerg  * and are destroyed on thread termination.
157ccec91a1Sjoerg  */
158ccec91a1Sjoerg struct __cxa_thread_info
159ccec91a1Sjoerg {
160ccec91a1Sjoerg 	/** The termination handler for this thread. */
161ccec91a1Sjoerg 	terminate_handler terminateHandler;
162ccec91a1Sjoerg 	/** The unexpected exception handler for this thread. */
163ccec91a1Sjoerg 	unexpected_handler unexpectedHandler;
164ccec91a1Sjoerg 	/**
165ccec91a1Sjoerg 	 * The number of emergency buffers held by this thread.  This is 0 in
166ccec91a1Sjoerg 	 * normal operation - the emergency buffers are only used when malloc()
167ccec91a1Sjoerg 	 * fails to return memory for allocating an exception.  Threads are not
168ccec91a1Sjoerg 	 * permitted to hold more than 4 emergency buffers (as per recommendation
169ccec91a1Sjoerg 	 * in ABI spec [3.3.1]).
170ccec91a1Sjoerg 	 */
171ccec91a1Sjoerg 	int emergencyBuffersHeld;
172ccec91a1Sjoerg 	/**
173ccec91a1Sjoerg 	 * The exception currently running in a cleanup.
174ccec91a1Sjoerg 	 */
175ccec91a1Sjoerg 	_Unwind_Exception *currentCleanup;
176ccec91a1Sjoerg 	/**
177ccec91a1Sjoerg 	 * Our state with respect to foreign exceptions.  Usually none, set to
178ccec91a1Sjoerg 	 * caught if we have just caught an exception and rethrown if we are
179ccec91a1Sjoerg 	 * rethrowing it.
180ccec91a1Sjoerg 	 */
181ccec91a1Sjoerg 	enum
182ccec91a1Sjoerg 	{
183ccec91a1Sjoerg 		none,
184ccec91a1Sjoerg 		caught,
185ccec91a1Sjoerg 		rethrown
186ccec91a1Sjoerg 	} foreign_exception_state;
187ccec91a1Sjoerg 	/**
188ccec91a1Sjoerg 	 * The public part of this structure, accessible from outside of this
189ccec91a1Sjoerg 	 * module.
190ccec91a1Sjoerg 	 */
191ccec91a1Sjoerg 	__cxa_eh_globals globals;
192ccec91a1Sjoerg };
193ccec91a1Sjoerg /**
194ccec91a1Sjoerg  * Dependent exception.  This
195ccec91a1Sjoerg  */
196ccec91a1Sjoerg struct __cxa_dependent_exception
197ccec91a1Sjoerg {
198ccec91a1Sjoerg #if __LP64__
199ccec91a1Sjoerg 	void *primaryException;
200ccec91a1Sjoerg #endif
201ccec91a1Sjoerg 	std::type_info *exceptionType;
202ccec91a1Sjoerg 	void (*exceptionDestructor) (void *);
203ccec91a1Sjoerg 	unexpected_handler unexpectedHandler;
204ccec91a1Sjoerg 	terminate_handler terminateHandler;
205ccec91a1Sjoerg 	__cxa_exception *nextException;
206ccec91a1Sjoerg 	int handlerCount;
207534cb174Sjoerg #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
208ccec91a1Sjoerg 	_Unwind_Exception *nextCleanup;
209ccec91a1Sjoerg 	int cleanupCount;
210ccec91a1Sjoerg #endif
211ccec91a1Sjoerg 	int handlerSwitchValue;
212ccec91a1Sjoerg 	const char *actionRecord;
213ccec91a1Sjoerg 	const char *languageSpecificData;
214ccec91a1Sjoerg 	void *catchTemp;
215ccec91a1Sjoerg 	void *adjustedPtr;
216ccec91a1Sjoerg #if !__LP64__
217ccec91a1Sjoerg 	void *primaryException;
218ccec91a1Sjoerg #endif
219ccec91a1Sjoerg 	_Unwind_Exception unwindHeader;
220ccec91a1Sjoerg };
221ccec91a1Sjoerg 
222ccec91a1Sjoerg 
223ccec91a1Sjoerg namespace std
224ccec91a1Sjoerg {
225ccec91a1Sjoerg 	void unexpected();
226ccec91a1Sjoerg 	class exception
227ccec91a1Sjoerg 	{
228ccec91a1Sjoerg 		public:
229ccec91a1Sjoerg 			virtual ~exception() throw();
230ccec91a1Sjoerg 			virtual const char* what() const throw();
231ccec91a1Sjoerg 	};
232ccec91a1Sjoerg 
233ccec91a1Sjoerg }
234ccec91a1Sjoerg 
235ccec91a1Sjoerg /**
236ccec91a1Sjoerg  * Class of exceptions to distinguish between this and other exception types.
237ccec91a1Sjoerg  *
238ccec91a1Sjoerg  * The first four characters are the vendor ID.  Currently, we use GNUC,
239ccec91a1Sjoerg  * because we aim for ABI-compatibility with the GNU implementation, and
240ccec91a1Sjoerg  * various checks may test for equality of the class, which is incorrect.
241ccec91a1Sjoerg  */
242ccec91a1Sjoerg static const uint64_t exception_class =
243ccec91a1Sjoerg 	EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\0');
244ccec91a1Sjoerg /**
245ccec91a1Sjoerg  * Class used for dependent exceptions.
246ccec91a1Sjoerg  */
247ccec91a1Sjoerg static const uint64_t dependent_exception_class =
248ccec91a1Sjoerg 	EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\x01');
249ccec91a1Sjoerg /**
250ccec91a1Sjoerg  * The low four bytes of the exception class, indicating that we conform to the
251ccec91a1Sjoerg  * Itanium C++ ABI.  This is currently unused, but should be used in the future
252ccec91a1Sjoerg  * if we change our exception class, to allow this library and libsupc++ to be
253ccec91a1Sjoerg  * linked to the same executable and both to interoperate.
254ccec91a1Sjoerg  */
255ccec91a1Sjoerg static const uint32_t abi_exception_class =
256ccec91a1Sjoerg 	GENERIC_EXCEPTION_CLASS('C', '+', '+', '\0');
257ccec91a1Sjoerg 
isCXXException(uint64_t cls)258ccec91a1Sjoerg static bool isCXXException(uint64_t cls)
259ccec91a1Sjoerg {
260ccec91a1Sjoerg 	return (cls == exception_class) || (cls == dependent_exception_class);
261ccec91a1Sjoerg }
262ccec91a1Sjoerg 
isDependentException(uint64_t cls)263ccec91a1Sjoerg static bool isDependentException(uint64_t cls)
264ccec91a1Sjoerg {
265ccec91a1Sjoerg 	return cls == dependent_exception_class;
266ccec91a1Sjoerg }
267ccec91a1Sjoerg 
exceptionFromPointer(void * ex)268ccec91a1Sjoerg static __cxa_exception *exceptionFromPointer(void *ex)
269ccec91a1Sjoerg {
270d0b6b5d5Sjoerg 	return reinterpret_cast<__cxa_exception*>(static_cast<char*>(ex) -
271ccec91a1Sjoerg 			offsetof(struct __cxa_exception, unwindHeader));
272ccec91a1Sjoerg }
realExceptionFromException(__cxa_exception * ex)273ccec91a1Sjoerg static __cxa_exception *realExceptionFromException(__cxa_exception *ex)
274ccec91a1Sjoerg {
275ccec91a1Sjoerg 	if (!isDependentException(ex->unwindHeader.exception_class)) { return ex; }
276d0b6b5d5Sjoerg 	return reinterpret_cast<__cxa_exception*>((reinterpret_cast<__cxa_dependent_exception*>(ex))->primaryException)-1;
277ccec91a1Sjoerg }
278ccec91a1Sjoerg 
279ccec91a1Sjoerg 
280ccec91a1Sjoerg namespace std
281ccec91a1Sjoerg {
282ccec91a1Sjoerg 	// Forward declaration of standard library terminate() function used to
283ccec91a1Sjoerg 	// abort execution.
284ccec91a1Sjoerg 	void terminate(void);
285ccec91a1Sjoerg }
286ccec91a1Sjoerg 
287ccec91a1Sjoerg using namespace ABI_NAMESPACE;
288ccec91a1Sjoerg 
289ccec91a1Sjoerg 
290ccec91a1Sjoerg 
291ccec91a1Sjoerg /** The global termination handler. */
292ccec91a1Sjoerg static terminate_handler terminateHandler = abort;
293ccec91a1Sjoerg /** The global unexpected exception handler. */
294ccec91a1Sjoerg static unexpected_handler unexpectedHandler = std::terminate;
295ccec91a1Sjoerg 
296ccec91a1Sjoerg /** Key used for thread-local data. */
297ccec91a1Sjoerg static pthread_key_t eh_key;
298ccec91a1Sjoerg 
299ccec91a1Sjoerg 
300ccec91a1Sjoerg /**
301ccec91a1Sjoerg  * Cleanup function, allowing foreign exception handlers to correctly destroy
302ccec91a1Sjoerg  * this exception if they catch it.
303ccec91a1Sjoerg  */
exception_cleanup(_Unwind_Reason_Code reason,struct _Unwind_Exception * ex)304ccec91a1Sjoerg static void exception_cleanup(_Unwind_Reason_Code reason,
305ccec91a1Sjoerg                               struct _Unwind_Exception *ex)
306ccec91a1Sjoerg {
307*387d6222Sjoerg 	// Exception layout:
308*387d6222Sjoerg 	// [__cxa_exception [_Unwind_Exception]] [exception object]
309*387d6222Sjoerg 	//
310*387d6222Sjoerg 	// __cxa_free_exception expects a pointer to the exception object
311*387d6222Sjoerg 	__cxa_free_exception(static_cast<void*>(ex + 1));
312ccec91a1Sjoerg }
dependent_exception_cleanup(_Unwind_Reason_Code reason,struct _Unwind_Exception * ex)313ccec91a1Sjoerg static void dependent_exception_cleanup(_Unwind_Reason_Code reason,
314ccec91a1Sjoerg                               struct _Unwind_Exception *ex)
315ccec91a1Sjoerg {
316ccec91a1Sjoerg 
317*387d6222Sjoerg 	__cxa_free_dependent_exception(static_cast<void*>(ex + 1));
318ccec91a1Sjoerg }
319ccec91a1Sjoerg 
320ccec91a1Sjoerg /**
321ccec91a1Sjoerg  * Recursively walk a list of exceptions and delete them all in post-order.
322ccec91a1Sjoerg  */
free_exception_list(__cxa_exception * ex)323ccec91a1Sjoerg static void free_exception_list(__cxa_exception *ex)
324ccec91a1Sjoerg {
325ccec91a1Sjoerg 	if (0 != ex->nextException)
326ccec91a1Sjoerg 	{
327ccec91a1Sjoerg 		free_exception_list(ex->nextException);
328ccec91a1Sjoerg 	}
329ccec91a1Sjoerg 	// __cxa_free_exception() expects to be passed the thrown object, which
330ccec91a1Sjoerg 	// immediately follows the exception, not the exception itself
331ccec91a1Sjoerg 	__cxa_free_exception(ex+1);
332ccec91a1Sjoerg }
333ccec91a1Sjoerg 
334ccec91a1Sjoerg /**
335ccec91a1Sjoerg  * Cleanup function called when a thread exists to make certain that all of the
336ccec91a1Sjoerg  * per-thread data is deleted.
337ccec91a1Sjoerg  */
thread_cleanup(void * thread_info)338ccec91a1Sjoerg static void thread_cleanup(void* thread_info)
339ccec91a1Sjoerg {
340d0b6b5d5Sjoerg 	__cxa_thread_info *info = static_cast<__cxa_thread_info*>(thread_info);
341ccec91a1Sjoerg 	if (info->globals.caughtExceptions)
342ccec91a1Sjoerg 	{
343ccec91a1Sjoerg 		// If this is a foreign exception, ask it to clean itself up.
344ccec91a1Sjoerg 		if (info->foreign_exception_state != __cxa_thread_info::none)
345ccec91a1Sjoerg 		{
346d0b6b5d5Sjoerg 			_Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(info->globals.caughtExceptions);
347*387d6222Sjoerg 			if (e->exception_cleanup)
348ccec91a1Sjoerg 				e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
349ccec91a1Sjoerg 		}
350ccec91a1Sjoerg 		else
351ccec91a1Sjoerg 		{
352ccec91a1Sjoerg 			free_exception_list(info->globals.caughtExceptions);
353ccec91a1Sjoerg 		}
354ccec91a1Sjoerg 	}
355ccec91a1Sjoerg 	free(thread_info);
356ccec91a1Sjoerg }
357ccec91a1Sjoerg 
358ccec91a1Sjoerg 
359ccec91a1Sjoerg /**
360ccec91a1Sjoerg  * Once control used to protect the key creation.
361ccec91a1Sjoerg  */
362ccec91a1Sjoerg static pthread_once_t once_control = PTHREAD_ONCE_INIT;
363ccec91a1Sjoerg 
364ccec91a1Sjoerg /**
365ccec91a1Sjoerg  * We may not be linked against a full pthread implementation.  If we're not,
366ccec91a1Sjoerg  * then we need to fake the thread-local storage by storing 'thread-local'
367ccec91a1Sjoerg  * things in a global.
368ccec91a1Sjoerg  */
369ccec91a1Sjoerg static bool fakeTLS;
370ccec91a1Sjoerg /**
371ccec91a1Sjoerg  * Thread-local storage for a single-threaded program.
372ccec91a1Sjoerg  */
373ccec91a1Sjoerg static __cxa_thread_info singleThreadInfo;
374ccec91a1Sjoerg /**
375ccec91a1Sjoerg  * Initialise eh_key.
376ccec91a1Sjoerg  */
init_key(void)377ccec91a1Sjoerg static void init_key(void)
378ccec91a1Sjoerg {
379ccec91a1Sjoerg 	if ((0 == pthread_key_create) ||
380ccec91a1Sjoerg 	    (0 == pthread_setspecific) ||
381ccec91a1Sjoerg 	    (0 == pthread_getspecific))
382ccec91a1Sjoerg 	{
383ccec91a1Sjoerg 		fakeTLS = true;
384ccec91a1Sjoerg 		return;
385ccec91a1Sjoerg 	}
386ccec91a1Sjoerg 	pthread_key_create(&eh_key, thread_cleanup);
387d0b6b5d5Sjoerg 	pthread_setspecific(eh_key, reinterpret_cast<void *>(0x42));
388d0b6b5d5Sjoerg 	fakeTLS = (pthread_getspecific(eh_key) != reinterpret_cast<void *>(0x42));
389ccec91a1Sjoerg 	pthread_setspecific(eh_key, 0);
390ccec91a1Sjoerg }
391ccec91a1Sjoerg 
392ccec91a1Sjoerg /**
393ccec91a1Sjoerg  * Returns the thread info structure, creating it if it is not already created.
394ccec91a1Sjoerg  */
thread_info()395ccec91a1Sjoerg static __cxa_thread_info *thread_info()
396ccec91a1Sjoerg {
397ccec91a1Sjoerg 	if ((0 == pthread_once) || pthread_once(&once_control, init_key))
398ccec91a1Sjoerg 	{
399ccec91a1Sjoerg 		fakeTLS = true;
400ccec91a1Sjoerg 	}
401ccec91a1Sjoerg 	if (fakeTLS) { return &singleThreadInfo; }
402d0b6b5d5Sjoerg 	__cxa_thread_info *info = static_cast<__cxa_thread_info*>(pthread_getspecific(eh_key));
403ccec91a1Sjoerg 	if (0 == info)
404ccec91a1Sjoerg 	{
405d0b6b5d5Sjoerg 		info = static_cast<__cxa_thread_info*>(calloc(1, sizeof(__cxa_thread_info)));
406ccec91a1Sjoerg 		pthread_setspecific(eh_key, info);
407ccec91a1Sjoerg 	}
408ccec91a1Sjoerg 	return info;
409ccec91a1Sjoerg }
410ccec91a1Sjoerg /**
411ccec91a1Sjoerg  * Fast version of thread_info().  May fail if thread_info() is not called on
412ccec91a1Sjoerg  * this thread at least once already.
413ccec91a1Sjoerg  */
thread_info_fast()414ccec91a1Sjoerg static __cxa_thread_info *thread_info_fast()
415ccec91a1Sjoerg {
416ccec91a1Sjoerg 	if (fakeTLS) { return &singleThreadInfo; }
417d0b6b5d5Sjoerg 	return static_cast<__cxa_thread_info*>(pthread_getspecific(eh_key));
418ccec91a1Sjoerg }
419ccec91a1Sjoerg /**
420ccec91a1Sjoerg  * ABI function returning the __cxa_eh_globals structure.
421ccec91a1Sjoerg  */
__cxa_get_globals(void)422ccec91a1Sjoerg extern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals(void)
423ccec91a1Sjoerg {
424ccec91a1Sjoerg 	return &(thread_info()->globals);
425ccec91a1Sjoerg }
426ccec91a1Sjoerg /**
427ccec91a1Sjoerg  * Version of __cxa_get_globals() assuming that __cxa_get_globals() has already
428ccec91a1Sjoerg  * been called at least once by this thread.
429ccec91a1Sjoerg  */
__cxa_get_globals_fast(void)430ccec91a1Sjoerg extern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals_fast(void)
431ccec91a1Sjoerg {
432ccec91a1Sjoerg 	return &(thread_info_fast()->globals);
433ccec91a1Sjoerg }
434ccec91a1Sjoerg 
435ccec91a1Sjoerg /**
436ccec91a1Sjoerg  * An emergency allocation reserved for when malloc fails.  This is treated as
437ccec91a1Sjoerg  * 16 buffers of 1KB each.
438ccec91a1Sjoerg  */
439ccec91a1Sjoerg static char emergency_buffer[16384];
440ccec91a1Sjoerg /**
441ccec91a1Sjoerg  * Flag indicating whether each buffer is allocated.
442ccec91a1Sjoerg  */
443ccec91a1Sjoerg static bool buffer_allocated[16];
444ccec91a1Sjoerg /**
445ccec91a1Sjoerg  * Lock used to protect emergency allocation.
446ccec91a1Sjoerg  */
447ccec91a1Sjoerg static pthread_mutex_t emergency_malloc_lock = PTHREAD_MUTEX_INITIALIZER;
448ccec91a1Sjoerg /**
449ccec91a1Sjoerg  * Condition variable used to wait when two threads are both trying to use the
450ccec91a1Sjoerg  * emergency malloc() buffer at once.
451ccec91a1Sjoerg  */
452ccec91a1Sjoerg static pthread_cond_t emergency_malloc_wait = PTHREAD_COND_INITIALIZER;
453ccec91a1Sjoerg 
454ccec91a1Sjoerg /**
455ccec91a1Sjoerg  * Allocates size bytes from the emergency allocation mechanism, if possible.
456ccec91a1Sjoerg  * This function will fail if size is over 1KB or if this thread already has 4
457ccec91a1Sjoerg  * emergency buffers.  If all emergency buffers are allocated, it will sleep
458ccec91a1Sjoerg  * until one becomes available.
459ccec91a1Sjoerg  */
emergency_malloc(size_t size)460ccec91a1Sjoerg static char *emergency_malloc(size_t size)
461ccec91a1Sjoerg {
462ccec91a1Sjoerg 	if (size > 1024) { return 0; }
463ccec91a1Sjoerg 
464ccec91a1Sjoerg 	__cxa_thread_info *info = thread_info();
465ccec91a1Sjoerg 	// Only 4 emergency buffers allowed per thread!
466ccec91a1Sjoerg 	if (info->emergencyBuffersHeld > 3) { return 0; }
467ccec91a1Sjoerg 
468ccec91a1Sjoerg 	pthread_mutex_lock(&emergency_malloc_lock);
469ccec91a1Sjoerg 	int buffer = -1;
470ccec91a1Sjoerg 	while (buffer < 0)
471ccec91a1Sjoerg 	{
472ccec91a1Sjoerg 		// While we were sleeping on the lock, another thread might have free'd
473ccec91a1Sjoerg 		// enough memory for us to use, so try the allocation again - no point
474ccec91a1Sjoerg 		// using the emergency buffer if there is some real memory that we can
475ccec91a1Sjoerg 		// use...
476ccec91a1Sjoerg 		void *m = calloc(1, size);
477ccec91a1Sjoerg 		if (0 != m)
478ccec91a1Sjoerg 		{
479ccec91a1Sjoerg 			pthread_mutex_unlock(&emergency_malloc_lock);
480d0b6b5d5Sjoerg 			return static_cast<char*>(m);
481ccec91a1Sjoerg 		}
482ccec91a1Sjoerg 		for (int i=0 ; i<16 ; i++)
483ccec91a1Sjoerg 		{
484ccec91a1Sjoerg 			if (!buffer_allocated[i])
485ccec91a1Sjoerg 			{
486ccec91a1Sjoerg 				buffer = i;
487ccec91a1Sjoerg 				buffer_allocated[i] = true;
488ccec91a1Sjoerg 				break;
489ccec91a1Sjoerg 			}
490ccec91a1Sjoerg 		}
491ccec91a1Sjoerg 		// If there still isn't a buffer available, then sleep on the condition
492ccec91a1Sjoerg 		// variable.  This will be signalled when another thread releases one
493ccec91a1Sjoerg 		// of the emergency buffers.
494ccec91a1Sjoerg 		if (buffer < 0)
495ccec91a1Sjoerg 		{
496ccec91a1Sjoerg 			pthread_cond_wait(&emergency_malloc_wait, &emergency_malloc_lock);
497ccec91a1Sjoerg 		}
498ccec91a1Sjoerg 	}
499ccec91a1Sjoerg 	pthread_mutex_unlock(&emergency_malloc_lock);
500ccec91a1Sjoerg 	info->emergencyBuffersHeld++;
501ccec91a1Sjoerg 	return emergency_buffer + (1024 * buffer);
502ccec91a1Sjoerg }
503ccec91a1Sjoerg 
504ccec91a1Sjoerg /**
505ccec91a1Sjoerg  * Frees a buffer returned by emergency_malloc().
506ccec91a1Sjoerg  *
507ccec91a1Sjoerg  * Note: Neither this nor emergency_malloc() is particularly efficient.  This
508ccec91a1Sjoerg  * should not matter, because neither will be called in normal operation - they
509ccec91a1Sjoerg  * are only used when the program runs out of memory, which should not happen
510ccec91a1Sjoerg  * often.
511ccec91a1Sjoerg  */
emergency_malloc_free(char * ptr)512ccec91a1Sjoerg static void emergency_malloc_free(char *ptr)
513ccec91a1Sjoerg {
514ccec91a1Sjoerg 	int buffer = -1;
515ccec91a1Sjoerg 	// Find the buffer corresponding to this pointer.
516ccec91a1Sjoerg 	for (int i=0 ; i<16 ; i++)
517ccec91a1Sjoerg 	{
518d0b6b5d5Sjoerg 		if (ptr == static_cast<void*>(emergency_buffer + (1024 * i)))
519ccec91a1Sjoerg 		{
520ccec91a1Sjoerg 			buffer = i;
521ccec91a1Sjoerg 			break;
522ccec91a1Sjoerg 		}
523ccec91a1Sjoerg 	}
524*387d6222Sjoerg 	assert(buffer >= 0 &&
525ccec91a1Sjoerg 	       "Trying to free something that is not an emergency buffer!");
526ccec91a1Sjoerg 	// emergency_malloc() is expected to return 0-initialized data.  We don't
527ccec91a1Sjoerg 	// zero the buffer when allocating it, because the static buffers will
528ccec91a1Sjoerg 	// begin life containing 0 values.
529d0b6b5d5Sjoerg 	memset(ptr, 0, 1024);
530ccec91a1Sjoerg 	// Signal the condition variable to wake up any threads that are blocking
531ccec91a1Sjoerg 	// waiting for some space in the emergency buffer
532ccec91a1Sjoerg 	pthread_mutex_lock(&emergency_malloc_lock);
533ccec91a1Sjoerg 	// In theory, we don't need to do this with the lock held.  In practice,
534ccec91a1Sjoerg 	// our array of bools will probably be updated using 32-bit or 64-bit
535ccec91a1Sjoerg 	// memory operations, so this update may clobber adjacent values.
536ccec91a1Sjoerg 	buffer_allocated[buffer] = false;
537ccec91a1Sjoerg 	pthread_cond_signal(&emergency_malloc_wait);
538ccec91a1Sjoerg 	pthread_mutex_unlock(&emergency_malloc_lock);
539ccec91a1Sjoerg }
540ccec91a1Sjoerg 
alloc_or_die(size_t size)541ccec91a1Sjoerg static char *alloc_or_die(size_t size)
542ccec91a1Sjoerg {
543d0b6b5d5Sjoerg 	char *buffer = static_cast<char*>(calloc(1, size));
544ccec91a1Sjoerg 
545ccec91a1Sjoerg 	// If calloc() doesn't want to give us any memory, try using an emergency
546ccec91a1Sjoerg 	// buffer.
547ccec91a1Sjoerg 	if (0 == buffer)
548ccec91a1Sjoerg 	{
549ccec91a1Sjoerg 		buffer = emergency_malloc(size);
550ccec91a1Sjoerg 		// This is only reached if the allocation is greater than 1KB, and
551ccec91a1Sjoerg 		// anyone throwing objects that big really should know better.
552ccec91a1Sjoerg 		if (0 == buffer)
553ccec91a1Sjoerg 		{
554ccec91a1Sjoerg 			fprintf(stderr, "Out of memory attempting to allocate exception\n");
555ccec91a1Sjoerg 			std::terminate();
556ccec91a1Sjoerg 		}
557ccec91a1Sjoerg 	}
558ccec91a1Sjoerg 	return buffer;
559ccec91a1Sjoerg }
free_exception(char * e)560ccec91a1Sjoerg static void free_exception(char *e)
561ccec91a1Sjoerg {
562ccec91a1Sjoerg 	// If this allocation is within the address range of the emergency buffer,
563ccec91a1Sjoerg 	// don't call free() because it was not allocated with malloc()
564*387d6222Sjoerg 	if ((e >= emergency_buffer) &&
565ccec91a1Sjoerg 	    (e < (emergency_buffer + sizeof(emergency_buffer))))
566ccec91a1Sjoerg 	{
567ccec91a1Sjoerg 		emergency_malloc_free(e);
568ccec91a1Sjoerg 	}
569ccec91a1Sjoerg 	else
570ccec91a1Sjoerg 	{
571ccec91a1Sjoerg 		free(e);
572ccec91a1Sjoerg 	}
573ccec91a1Sjoerg }
574ccec91a1Sjoerg 
575ccec91a1Sjoerg /**
576ccec91a1Sjoerg  * Allocates an exception structure.  Returns a pointer to the space that can
577ccec91a1Sjoerg  * be used to store an object of thrown_size bytes.  This function will use an
578ccec91a1Sjoerg  * emergency buffer if malloc() fails, and may block if there are no such
579ccec91a1Sjoerg  * buffers available.
580ccec91a1Sjoerg  */
__cxa_allocate_exception(size_t thrown_size)581ccec91a1Sjoerg extern "C" void *__cxa_allocate_exception(size_t thrown_size)
582ccec91a1Sjoerg {
583ccec91a1Sjoerg 	size_t size = thrown_size + sizeof(__cxa_exception);
584ccec91a1Sjoerg 	char *buffer = alloc_or_die(size);
585ccec91a1Sjoerg 	return buffer+sizeof(__cxa_exception);
586ccec91a1Sjoerg }
587ccec91a1Sjoerg 
__cxa_allocate_dependent_exception(void)588ccec91a1Sjoerg extern "C" void *__cxa_allocate_dependent_exception(void)
589ccec91a1Sjoerg {
590ccec91a1Sjoerg 	size_t size = sizeof(__cxa_dependent_exception);
591ccec91a1Sjoerg 	char *buffer = alloc_or_die(size);
592ccec91a1Sjoerg 	return buffer+sizeof(__cxa_dependent_exception);
593ccec91a1Sjoerg }
594ccec91a1Sjoerg 
595ccec91a1Sjoerg /**
596ccec91a1Sjoerg  * __cxa_free_exception() is called when an exception was thrown in between
597ccec91a1Sjoerg  * calling __cxa_allocate_exception() and actually throwing the exception.
598ccec91a1Sjoerg  * This happens when the object's copy constructor throws an exception.
599ccec91a1Sjoerg  *
600ccec91a1Sjoerg  * In this implementation, it is also called by __cxa_end_catch() and during
601ccec91a1Sjoerg  * thread cleanup.
602ccec91a1Sjoerg  */
__cxa_free_exception(void * thrown_exception)603ccec91a1Sjoerg extern "C" void __cxa_free_exception(void *thrown_exception)
604ccec91a1Sjoerg {
605d0b6b5d5Sjoerg 	__cxa_exception *ex = reinterpret_cast<__cxa_exception*>(thrown_exception) - 1;
606ccec91a1Sjoerg 	// Free the object that was thrown, calling its destructor
607ccec91a1Sjoerg 	if (0 != ex->exceptionDestructor)
608ccec91a1Sjoerg 	{
609ccec91a1Sjoerg 		try
610ccec91a1Sjoerg 		{
611ccec91a1Sjoerg 			ex->exceptionDestructor(thrown_exception);
612ccec91a1Sjoerg 		}
613ccec91a1Sjoerg 		catch(...)
614ccec91a1Sjoerg 		{
615ccec91a1Sjoerg 			// FIXME: Check that this is really what the spec says to do.
616ccec91a1Sjoerg 			std::terminate();
617ccec91a1Sjoerg 		}
618ccec91a1Sjoerg 	}
619ccec91a1Sjoerg 
620d0b6b5d5Sjoerg 	free_exception(reinterpret_cast<char*>(ex));
621ccec91a1Sjoerg }
622ccec91a1Sjoerg 
releaseException(__cxa_exception * exception)623ccec91a1Sjoerg static void releaseException(__cxa_exception *exception)
624ccec91a1Sjoerg {
625ccec91a1Sjoerg 	if (isDependentException(exception->unwindHeader.exception_class))
626ccec91a1Sjoerg 	{
627ccec91a1Sjoerg 		__cxa_free_dependent_exception(exception+1);
628ccec91a1Sjoerg 		return;
629ccec91a1Sjoerg 	}
630ccec91a1Sjoerg 	if (__sync_sub_and_fetch(&exception->referenceCount, 1) == 0)
631ccec91a1Sjoerg 	{
632ccec91a1Sjoerg 		// __cxa_free_exception() expects to be passed the thrown object,
633ccec91a1Sjoerg 		// which immediately follows the exception, not the exception
634ccec91a1Sjoerg 		// itself
635ccec91a1Sjoerg 		__cxa_free_exception(exception+1);
636ccec91a1Sjoerg 	}
637ccec91a1Sjoerg }
638ccec91a1Sjoerg 
__cxa_free_dependent_exception(void * thrown_exception)639ccec91a1Sjoerg void __cxa_free_dependent_exception(void *thrown_exception)
640ccec91a1Sjoerg {
641d0b6b5d5Sjoerg 	__cxa_dependent_exception *ex = reinterpret_cast<__cxa_dependent_exception*>(thrown_exception) - 1;
642ccec91a1Sjoerg 	assert(isDependentException(ex->unwindHeader.exception_class));
643ccec91a1Sjoerg 	if (ex->primaryException)
644ccec91a1Sjoerg 	{
645d0b6b5d5Sjoerg 		releaseException(realExceptionFromException(reinterpret_cast<__cxa_exception*>(ex)));
646ccec91a1Sjoerg 	}
647d0b6b5d5Sjoerg 	free_exception(reinterpret_cast<char*>(ex));
648ccec91a1Sjoerg }
649ccec91a1Sjoerg 
650ccec91a1Sjoerg /**
651ccec91a1Sjoerg  * Callback function used with _Unwind_Backtrace().
652ccec91a1Sjoerg  *
653ccec91a1Sjoerg  * Prints a stack trace.  Used only for debugging help.
654ccec91a1Sjoerg  *
655ccec91a1Sjoerg  * Note: As of FreeBSD 8.1, dladd() still doesn't work properly, so this only
656ccec91a1Sjoerg  * correctly prints function names from public, relocatable, symbols.
657ccec91a1Sjoerg  */
trace(struct _Unwind_Context * context,void * c)658ccec91a1Sjoerg static _Unwind_Reason_Code trace(struct _Unwind_Context *context, void *c)
659ccec91a1Sjoerg {
660ccec91a1Sjoerg 	Dl_info myinfo;
661ccec91a1Sjoerg 	int mylookup =
662534cb174Sjoerg 		dladdr(reinterpret_cast<void *>(__cxa_current_exception_type), &myinfo);
663d0b6b5d5Sjoerg 	void *ip = reinterpret_cast<void*>(_Unwind_GetIP(context));
664ccec91a1Sjoerg 	Dl_info info;
665ccec91a1Sjoerg 	if (dladdr(ip, &info) != 0)
666ccec91a1Sjoerg 	{
667ccec91a1Sjoerg 		if (mylookup == 0 || strcmp(info.dli_fname, myinfo.dli_fname) != 0)
668ccec91a1Sjoerg 		{
669ccec91a1Sjoerg 			printf("%p:%s() in %s\n", ip, info.dli_sname, info.dli_fname);
670ccec91a1Sjoerg 		}
671ccec91a1Sjoerg 	}
672ccec91a1Sjoerg 	return _URC_CONTINUE_UNWIND;
673ccec91a1Sjoerg }
674ccec91a1Sjoerg 
675ccec91a1Sjoerg /**
676ccec91a1Sjoerg  * Report a failure that occurred when attempting to throw an exception.
677ccec91a1Sjoerg  *
678ccec91a1Sjoerg  * If the failure happened by falling off the end of the stack without finding
679ccec91a1Sjoerg  * a handler, prints a back trace before aborting.
680ccec91a1Sjoerg  */
6811ca55825Spooka #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
682534cb174Sjoerg extern "C" void *__cxa_begin_catch(void *e) throw();
683534cb174Sjoerg #else
684534cb174Sjoerg extern "C" void *__cxa_begin_catch(void *e);
685534cb174Sjoerg #endif
report_failure(_Unwind_Reason_Code err,__cxa_exception * thrown_exception)686ccec91a1Sjoerg static void report_failure(_Unwind_Reason_Code err, __cxa_exception *thrown_exception)
687ccec91a1Sjoerg {
688ccec91a1Sjoerg 	switch (err)
689ccec91a1Sjoerg 	{
690ccec91a1Sjoerg 		default: break;
691ccec91a1Sjoerg 		case _URC_FATAL_PHASE1_ERROR:
692ccec91a1Sjoerg 			fprintf(stderr, "Fatal error during phase 1 unwinding\n");
693ccec91a1Sjoerg 			break;
694534cb174Sjoerg #if !defined(__arm__) || defined(__ARM_DWARF_EH__)
695ccec91a1Sjoerg 		case _URC_FATAL_PHASE2_ERROR:
696ccec91a1Sjoerg 			fprintf(stderr, "Fatal error during phase 2 unwinding\n");
697ccec91a1Sjoerg 			break;
698ccec91a1Sjoerg #endif
699ccec91a1Sjoerg 		case _URC_END_OF_STACK:
700534cb174Sjoerg 			__cxa_begin_catch (&(thrown_exception->unwindHeader));
701534cb174Sjoerg  			std::terminate();
702ccec91a1Sjoerg 			fprintf(stderr, "Terminating due to uncaught exception %p",
703d0b6b5d5Sjoerg 					static_cast<void*>(thrown_exception));
704ccec91a1Sjoerg 			thrown_exception = realExceptionFromException(thrown_exception);
705ccec91a1Sjoerg 			static const __class_type_info *e_ti =
706ccec91a1Sjoerg 				static_cast<const __class_type_info*>(&typeid(std::exception));
707ccec91a1Sjoerg 			const __class_type_info *throw_ti =
708ccec91a1Sjoerg 				dynamic_cast<const __class_type_info*>(thrown_exception->exceptionType);
709ccec91a1Sjoerg 			if (throw_ti)
710ccec91a1Sjoerg 			{
711ccec91a1Sjoerg 				std::exception *e =
712d0b6b5d5Sjoerg 					static_cast<std::exception*>(e_ti->cast_to(static_cast<void*>(thrown_exception+1),
713d0b6b5d5Sjoerg 							throw_ti));
714ccec91a1Sjoerg 				if (e)
715ccec91a1Sjoerg 				{
716ccec91a1Sjoerg 					fprintf(stderr, " '%s'", e->what());
717ccec91a1Sjoerg 				}
718ccec91a1Sjoerg 			}
719ccec91a1Sjoerg 
720ccec91a1Sjoerg 			size_t bufferSize = 128;
721d0b6b5d5Sjoerg 			char *demangled = static_cast<char*>(malloc(bufferSize));
722ccec91a1Sjoerg 			const char *mangled = thrown_exception->exceptionType->name();
723ccec91a1Sjoerg 			int status;
724ccec91a1Sjoerg 			demangled = __cxa_demangle(mangled, demangled, &bufferSize, &status);
725ccec91a1Sjoerg 			fprintf(stderr, " of type %s\n",
726d0b6b5d5Sjoerg 				status == 0 ? demangled : mangled);
727ccec91a1Sjoerg 			if (status == 0) { free(demangled); }
728ccec91a1Sjoerg 			// Print a back trace if no handler is found.
729ccec91a1Sjoerg 			// TODO: Make this optional
730ccec91a1Sjoerg 			_Unwind_Backtrace(trace, 0);
731534cb174Sjoerg 
732534cb174Sjoerg 			// Just abort. No need to call std::terminate for the second time
733534cb174Sjoerg 			abort();
734ccec91a1Sjoerg 			break;
735ccec91a1Sjoerg 	}
736ccec91a1Sjoerg 	std::terminate();
737ccec91a1Sjoerg }
738ccec91a1Sjoerg 
throw_exception(__cxa_exception * ex)739ccec91a1Sjoerg static void throw_exception(__cxa_exception *ex)
740ccec91a1Sjoerg {
741ccec91a1Sjoerg 	__cxa_thread_info *info = thread_info();
742ccec91a1Sjoerg 	ex->unexpectedHandler = info->unexpectedHandler;
743ccec91a1Sjoerg 	if (0 == ex->unexpectedHandler)
744ccec91a1Sjoerg 	{
745ccec91a1Sjoerg 		ex->unexpectedHandler = unexpectedHandler;
746ccec91a1Sjoerg 	}
747ccec91a1Sjoerg 	ex->terminateHandler  = info->terminateHandler;
748ccec91a1Sjoerg 	if (0 == ex->terminateHandler)
749ccec91a1Sjoerg 	{
750ccec91a1Sjoerg 		ex->terminateHandler = terminateHandler;
751ccec91a1Sjoerg 	}
752ccec91a1Sjoerg 	info->globals.uncaughtExceptions++;
753ccec91a1Sjoerg 
754ccec91a1Sjoerg 	_Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader);
755ccec91a1Sjoerg 	// The _Unwind_RaiseException() function should not return, it should
756ccec91a1Sjoerg 	// unwind the stack past this function.  If it does return, then something
757ccec91a1Sjoerg 	// has gone wrong.
758ccec91a1Sjoerg 	report_failure(err, ex);
759ccec91a1Sjoerg }
760ccec91a1Sjoerg 
761ccec91a1Sjoerg 
762ccec91a1Sjoerg /**
763ccec91a1Sjoerg  * ABI function for throwing an exception.  Takes the object to be thrown (the
764ccec91a1Sjoerg  * pointer returned by __cxa_allocate_exception()), the type info for the
765ccec91a1Sjoerg  * pointee, and the destructor (if there is one) as arguments.
766ccec91a1Sjoerg  */
__cxa_throw(void * thrown_exception,std::type_info * tinfo,void (* dest)(void *))767ccec91a1Sjoerg extern "C" void __cxa_throw(void *thrown_exception,
768ccec91a1Sjoerg                             std::type_info *tinfo,
769ccec91a1Sjoerg                             void(*dest)(void*))
770ccec91a1Sjoerg {
771d0b6b5d5Sjoerg 	__cxa_exception *ex = reinterpret_cast<__cxa_exception*>(thrown_exception) - 1;
772ccec91a1Sjoerg 
773ccec91a1Sjoerg 	ex->referenceCount = 1;
774ccec91a1Sjoerg 	ex->exceptionType = tinfo;
775ccec91a1Sjoerg 
776ccec91a1Sjoerg 	ex->exceptionDestructor = dest;
777ccec91a1Sjoerg 
778ccec91a1Sjoerg 	ex->unwindHeader.exception_class = exception_class;
779ccec91a1Sjoerg 	ex->unwindHeader.exception_cleanup = exception_cleanup;
780ccec91a1Sjoerg 
781ccec91a1Sjoerg 	throw_exception(ex);
782ccec91a1Sjoerg }
783ccec91a1Sjoerg 
__cxa_rethrow_primary_exception(void * thrown_exception)784ccec91a1Sjoerg extern "C" void __cxa_rethrow_primary_exception(void* thrown_exception)
785ccec91a1Sjoerg {
786ccec91a1Sjoerg 	if (NULL == thrown_exception) { return; }
787ccec91a1Sjoerg 
788ccec91a1Sjoerg 	__cxa_exception *original = exceptionFromPointer(thrown_exception);
789d0b6b5d5Sjoerg 	__cxa_dependent_exception *ex = reinterpret_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception())-1;
790ccec91a1Sjoerg 
791ccec91a1Sjoerg 	ex->primaryException = thrown_exception;
792ccec91a1Sjoerg 	__cxa_increment_exception_refcount(thrown_exception);
793ccec91a1Sjoerg 
794ccec91a1Sjoerg 	ex->exceptionType = original->exceptionType;
795ccec91a1Sjoerg 	ex->unwindHeader.exception_class = dependent_exception_class;
796ccec91a1Sjoerg 	ex->unwindHeader.exception_cleanup = dependent_exception_cleanup;
797ccec91a1Sjoerg 
798d0b6b5d5Sjoerg 	throw_exception(reinterpret_cast<__cxa_exception*>(ex));
799ccec91a1Sjoerg }
800ccec91a1Sjoerg 
__cxa_current_primary_exception(void)801ccec91a1Sjoerg extern "C" void *__cxa_current_primary_exception(void)
802ccec91a1Sjoerg {
803ccec91a1Sjoerg 	__cxa_eh_globals* globals = __cxa_get_globals();
804ccec91a1Sjoerg 	__cxa_exception *ex = globals->caughtExceptions;
805ccec91a1Sjoerg 
806ccec91a1Sjoerg 	if (0 == ex) { return NULL; }
807ccec91a1Sjoerg 	ex = realExceptionFromException(ex);
808ccec91a1Sjoerg 	__sync_fetch_and_add(&ex->referenceCount, 1);
809ccec91a1Sjoerg 	return ex + 1;
810ccec91a1Sjoerg }
811ccec91a1Sjoerg 
__cxa_increment_exception_refcount(void * thrown_exception)812ccec91a1Sjoerg extern "C" void __cxa_increment_exception_refcount(void* thrown_exception)
813ccec91a1Sjoerg {
814ccec91a1Sjoerg 	if (NULL == thrown_exception) { return; }
815d0b6b5d5Sjoerg 	__cxa_exception *ex = static_cast<__cxa_exception*>(thrown_exception) - 1;
816ccec91a1Sjoerg 	if (isDependentException(ex->unwindHeader.exception_class)) { return; }
817ccec91a1Sjoerg 	__sync_fetch_and_add(&ex->referenceCount, 1);
818ccec91a1Sjoerg }
__cxa_decrement_exception_refcount(void * thrown_exception)819ccec91a1Sjoerg extern "C" void __cxa_decrement_exception_refcount(void* thrown_exception)
820ccec91a1Sjoerg {
821ccec91a1Sjoerg 	if (NULL == thrown_exception) { return; }
822d0b6b5d5Sjoerg 	__cxa_exception *ex = static_cast<__cxa_exception*>(thrown_exception) - 1;
823ccec91a1Sjoerg 	releaseException(ex);
824ccec91a1Sjoerg }
825ccec91a1Sjoerg 
826ccec91a1Sjoerg /**
827ccec91a1Sjoerg  * ABI function.  Rethrows the current exception.  Does not remove the
828ccec91a1Sjoerg  * exception from the stack or decrement its handler count - the compiler is
829ccec91a1Sjoerg  * expected to set the landing pad for this function to the end of the catch
830ccec91a1Sjoerg  * block, and then call _Unwind_Resume() to continue unwinding once
831ccec91a1Sjoerg  * __cxa_end_catch() has been called and any cleanup code has been run.
832ccec91a1Sjoerg  */
__cxa_rethrow()833ccec91a1Sjoerg extern "C" void __cxa_rethrow()
834ccec91a1Sjoerg {
835ccec91a1Sjoerg 	__cxa_thread_info *ti = thread_info();
836ccec91a1Sjoerg 	__cxa_eh_globals *globals = &ti->globals;
837ccec91a1Sjoerg 	// Note: We don't remove this from the caught list here, because
838ccec91a1Sjoerg 	// __cxa_end_catch will be called when we unwind out of the try block.  We
839ccec91a1Sjoerg 	// could probably make this faster by providing an alternative rethrow
840ccec91a1Sjoerg 	// function and ensuring that all cleanup code is run before calling it, so
841ccec91a1Sjoerg 	// we can skip the top stack frame when unwinding.
842ccec91a1Sjoerg 	__cxa_exception *ex = globals->caughtExceptions;
843ccec91a1Sjoerg 
844ccec91a1Sjoerg 	if (0 == ex)
845ccec91a1Sjoerg 	{
846ccec91a1Sjoerg 		fprintf(stderr,
847ccec91a1Sjoerg 		        "Attempting to rethrow an exception that doesn't exist!\n");
848ccec91a1Sjoerg 		std::terminate();
849ccec91a1Sjoerg 	}
850ccec91a1Sjoerg 
851ccec91a1Sjoerg 	if (ti->foreign_exception_state != __cxa_thread_info::none)
852ccec91a1Sjoerg 	{
853ccec91a1Sjoerg 		ti->foreign_exception_state = __cxa_thread_info::rethrown;
854d0b6b5d5Sjoerg 		_Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(ex);
855ccec91a1Sjoerg 		_Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(e);
856ccec91a1Sjoerg 		report_failure(err, ex);
857ccec91a1Sjoerg 		return;
858ccec91a1Sjoerg 	}
859ccec91a1Sjoerg 
860ccec91a1Sjoerg 	assert(ex->handlerCount > 0 && "Rethrowing uncaught exception!");
861ccec91a1Sjoerg 
862*387d6222Sjoerg 	// `globals->uncaughtExceptions` was decremented by `__cxa_begin_catch`.
863*387d6222Sjoerg 	// It's normally incremented by `throw_exception`, but this path invokes
864*387d6222Sjoerg 	// `_Unwind_Resume_or_Rethrow` directly to rethrow the exception.
865*387d6222Sjoerg 	// This path is only reachable if we're rethrowing a C++ exception -
866*387d6222Sjoerg 	// foreign exceptions don't adjust any of this state.
867*387d6222Sjoerg 	globals->uncaughtExceptions++;
868*387d6222Sjoerg 
869ccec91a1Sjoerg 	// ex->handlerCount will be decremented in __cxa_end_catch in enclosing
870ccec91a1Sjoerg 	// catch block
871ccec91a1Sjoerg 
872ccec91a1Sjoerg 	// Make handler count negative. This will tell __cxa_end_catch that
873ccec91a1Sjoerg 	// exception was rethrown and exception object should not be destroyed
874ccec91a1Sjoerg 	// when handler count become zero
875ccec91a1Sjoerg 	ex->handlerCount = -ex->handlerCount;
876ccec91a1Sjoerg 
877ccec91a1Sjoerg 	// Continue unwinding the stack with this exception.  This should unwind to
878ccec91a1Sjoerg 	// the place in the caller where __cxa_end_catch() is called.  The caller
879ccec91a1Sjoerg 	// will then run cleanup code and bounce the exception back with
880ccec91a1Sjoerg 	// _Unwind_Resume().
881ccec91a1Sjoerg 	_Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(&ex->unwindHeader);
882ccec91a1Sjoerg 	report_failure(err, ex);
883ccec91a1Sjoerg }
884ccec91a1Sjoerg 
885ccec91a1Sjoerg /**
886ccec91a1Sjoerg  * Returns the type_info object corresponding to the filter.
887ccec91a1Sjoerg  */
get_type_info_entry(_Unwind_Context * context,dwarf_eh_lsda * lsda,int filter)888ccec91a1Sjoerg static std::type_info *get_type_info_entry(_Unwind_Context *context,
889ccec91a1Sjoerg                                            dwarf_eh_lsda *lsda,
890ccec91a1Sjoerg                                            int filter)
891ccec91a1Sjoerg {
892ccec91a1Sjoerg 	// Get the address of the record in the table.
893ccec91a1Sjoerg 	dw_eh_ptr_t record = lsda->type_table -
894ccec91a1Sjoerg 		dwarf_size_of_fixed_size_field(lsda->type_table_encoding)*filter;
895ccec91a1Sjoerg 	//record -= 4;
896ccec91a1Sjoerg 	dw_eh_ptr_t start = record;
897ccec91a1Sjoerg 	// Read the value, but it's probably an indirect reference...
898ccec91a1Sjoerg 	int64_t offset = read_value(lsda->type_table_encoding, &record);
899ccec91a1Sjoerg 
900ccec91a1Sjoerg 	// (If the entry is 0, don't try to dereference it.  That would be bad.)
901ccec91a1Sjoerg 	if (offset == 0) { return 0; }
902ccec91a1Sjoerg 
903ccec91a1Sjoerg 	// ...so we need to resolve it
904d0b6b5d5Sjoerg 	return reinterpret_cast<std::type_info*>(resolve_indirect_value(context,
905d0b6b5d5Sjoerg 			lsda->type_table_encoding, offset, start));
906ccec91a1Sjoerg }
907ccec91a1Sjoerg 
908ccec91a1Sjoerg 
909ccec91a1Sjoerg 
910ccec91a1Sjoerg /**
911ccec91a1Sjoerg  * Checks the type signature found in a handler against the type of the thrown
912ccec91a1Sjoerg  * object.  If ex is 0 then it is assumed to be a foreign exception and only
913ccec91a1Sjoerg  * matches cleanups.
914ccec91a1Sjoerg  */
check_type_signature(__cxa_exception * ex,const std::type_info * type,void * & adjustedPtr)915ccec91a1Sjoerg static bool check_type_signature(__cxa_exception *ex,
916ccec91a1Sjoerg                                  const std::type_info *type,
917ccec91a1Sjoerg                                  void *&adjustedPtr)
918ccec91a1Sjoerg {
919d0b6b5d5Sjoerg 	void *exception_ptr = static_cast<void*>(ex+1);
920ccec91a1Sjoerg 	const std::type_info *ex_type = ex ? ex->exceptionType : 0;
921ccec91a1Sjoerg 
922ccec91a1Sjoerg 	bool is_ptr = ex ? ex_type->__is_pointer_p() : false;
923ccec91a1Sjoerg 	if (is_ptr)
924ccec91a1Sjoerg 	{
925d0b6b5d5Sjoerg 		exception_ptr = *static_cast<void**>(exception_ptr);
926ccec91a1Sjoerg 	}
927ccec91a1Sjoerg 	// Always match a catchall, even with a foreign exception
928ccec91a1Sjoerg 	//
929ccec91a1Sjoerg 	// Note: A 0 here is a catchall, not a cleanup, so we return true to
930ccec91a1Sjoerg 	// indicate that we found a catch.
931ccec91a1Sjoerg 	if (0 == type)
932ccec91a1Sjoerg 	{
933ccec91a1Sjoerg 		if (ex)
934ccec91a1Sjoerg 		{
935ccec91a1Sjoerg 			adjustedPtr = exception_ptr;
936ccec91a1Sjoerg 		}
937ccec91a1Sjoerg 		return true;
938ccec91a1Sjoerg 	}
939ccec91a1Sjoerg 
940ccec91a1Sjoerg 	if (0 == ex) { return false; }
941ccec91a1Sjoerg 
942ccec91a1Sjoerg 	// If the types are the same, no casting is needed.
943ccec91a1Sjoerg 	if (*type == *ex_type)
944ccec91a1Sjoerg 	{
945ccec91a1Sjoerg 		adjustedPtr = exception_ptr;
946ccec91a1Sjoerg 		return true;
947ccec91a1Sjoerg 	}
948ccec91a1Sjoerg 
949ccec91a1Sjoerg 
950ccec91a1Sjoerg 	if (type->__do_catch(ex_type, &exception_ptr, 1))
951ccec91a1Sjoerg 	{
952ccec91a1Sjoerg 		adjustedPtr = exception_ptr;
953ccec91a1Sjoerg 		return true;
954ccec91a1Sjoerg 	}
955ccec91a1Sjoerg 
956ccec91a1Sjoerg 	return false;
957ccec91a1Sjoerg }
958ccec91a1Sjoerg /**
959ccec91a1Sjoerg  * Checks whether the exception matches the type specifiers in this action
960ccec91a1Sjoerg  * record.  If the exception only matches cleanups, then this returns false.
961ccec91a1Sjoerg  * If it matches a catch (including a catchall) then it returns true.
962ccec91a1Sjoerg  *
963ccec91a1Sjoerg  * The selector argument is used to return the selector that is passed in the
964ccec91a1Sjoerg  * second exception register when installing the context.
965ccec91a1Sjoerg  */
check_action_record(_Unwind_Context * context,dwarf_eh_lsda * lsda,dw_eh_ptr_t action_record,__cxa_exception * ex,unsigned long * selector,void * & adjustedPtr)966ccec91a1Sjoerg static handler_type check_action_record(_Unwind_Context *context,
967ccec91a1Sjoerg                                         dwarf_eh_lsda *lsda,
968ccec91a1Sjoerg                                         dw_eh_ptr_t action_record,
969ccec91a1Sjoerg                                         __cxa_exception *ex,
970ccec91a1Sjoerg                                         unsigned long *selector,
971ccec91a1Sjoerg                                         void *&adjustedPtr)
972ccec91a1Sjoerg {
973ccec91a1Sjoerg 	if (!action_record) { return handler_cleanup; }
974ccec91a1Sjoerg 	handler_type found = handler_none;
975ccec91a1Sjoerg 	while (action_record)
976ccec91a1Sjoerg 	{
977ccec91a1Sjoerg 		int filter = read_sleb128(&action_record);
978ccec91a1Sjoerg 		dw_eh_ptr_t action_record_offset_base = action_record;
979ccec91a1Sjoerg 		int displacement = read_sleb128(&action_record);
980ccec91a1Sjoerg 		action_record = displacement ?
981ccec91a1Sjoerg 			action_record_offset_base + displacement : 0;
982ccec91a1Sjoerg 		// We only check handler types for C++ exceptions - foreign exceptions
983ccec91a1Sjoerg 		// are only allowed for cleanups and catchalls.
984ccec91a1Sjoerg 		if (filter > 0)
985ccec91a1Sjoerg 		{
986ccec91a1Sjoerg 			std::type_info *handler_type = get_type_info_entry(context, lsda, filter);
987ccec91a1Sjoerg 			if (check_type_signature(ex, handler_type, adjustedPtr))
988ccec91a1Sjoerg 			{
989ccec91a1Sjoerg 				*selector = filter;
990ccec91a1Sjoerg 				return handler_catch;
991ccec91a1Sjoerg 			}
992ccec91a1Sjoerg 		}
993ccec91a1Sjoerg 		else if (filter < 0 && 0 != ex)
994ccec91a1Sjoerg 		{
995ccec91a1Sjoerg 			bool matched = false;
996ccec91a1Sjoerg 			*selector = filter;
997534cb174Sjoerg #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
998ccec91a1Sjoerg 			filter++;
999ccec91a1Sjoerg 			std::type_info *handler_type = get_type_info_entry(context, lsda, filter--);
1000ccec91a1Sjoerg 			while (handler_type)
1001ccec91a1Sjoerg 			{
1002ccec91a1Sjoerg 				if (check_type_signature(ex, handler_type, adjustedPtr))
1003ccec91a1Sjoerg 				{
1004ccec91a1Sjoerg 					matched = true;
1005ccec91a1Sjoerg 					break;
1006ccec91a1Sjoerg 				}
1007ccec91a1Sjoerg 				handler_type = get_type_info_entry(context, lsda, filter--);
1008ccec91a1Sjoerg 			}
1009ccec91a1Sjoerg #else
1010d0b6b5d5Sjoerg 			unsigned char *type_index = reinterpret_cast<unsigned char*>(lsda->type_table) - filter - 1;
1011ccec91a1Sjoerg 			while (*type_index)
1012ccec91a1Sjoerg 			{
1013ccec91a1Sjoerg 				std::type_info *handler_type = get_type_info_entry(context, lsda, *(type_index++));
1014ccec91a1Sjoerg 				// If the exception spec matches a permitted throw type for
1015ccec91a1Sjoerg 				// this function, don't report a handler - we are allowed to
1016ccec91a1Sjoerg 				// propagate this exception out.
1017ccec91a1Sjoerg 				if (check_type_signature(ex, handler_type, adjustedPtr))
1018ccec91a1Sjoerg 				{
1019ccec91a1Sjoerg 					matched = true;
1020ccec91a1Sjoerg 					break;
1021ccec91a1Sjoerg 				}
1022ccec91a1Sjoerg 			}
1023ccec91a1Sjoerg #endif
1024ccec91a1Sjoerg 			if (matched) { continue; }
1025ccec91a1Sjoerg 			// If we don't find an allowed exception spec, we need to install
1026ccec91a1Sjoerg 			// the context for this action.  The landing pad will then call the
1027ccec91a1Sjoerg 			// unexpected exception function.  Treat this as a catch
1028ccec91a1Sjoerg 			return handler_catch;
1029ccec91a1Sjoerg 		}
1030ccec91a1Sjoerg 		else if (filter == 0)
1031ccec91a1Sjoerg 		{
1032ccec91a1Sjoerg 			*selector = filter;
1033ccec91a1Sjoerg 			found = handler_cleanup;
1034ccec91a1Sjoerg 		}
1035ccec91a1Sjoerg 	}
1036ccec91a1Sjoerg 	return found;
1037ccec91a1Sjoerg }
1038ccec91a1Sjoerg 
pushCleanupException(_Unwind_Exception * exceptionObject,__cxa_exception * ex)1039ccec91a1Sjoerg static void pushCleanupException(_Unwind_Exception *exceptionObject,
1040ccec91a1Sjoerg                                  __cxa_exception *ex)
1041ccec91a1Sjoerg {
1042534cb174Sjoerg #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
1043ccec91a1Sjoerg 	__cxa_thread_info *info = thread_info_fast();
1044ccec91a1Sjoerg 	if (ex)
1045ccec91a1Sjoerg 	{
1046ccec91a1Sjoerg 		ex->cleanupCount++;
1047ccec91a1Sjoerg 		if (ex->cleanupCount > 1)
1048ccec91a1Sjoerg 		{
1049ccec91a1Sjoerg 			assert(exceptionObject == info->currentCleanup);
1050ccec91a1Sjoerg 			return;
1051ccec91a1Sjoerg 		}
1052ccec91a1Sjoerg 		ex->nextCleanup = info->currentCleanup;
1053ccec91a1Sjoerg 	}
1054ccec91a1Sjoerg 	info->currentCleanup = exceptionObject;
1055ccec91a1Sjoerg #endif
1056ccec91a1Sjoerg }
1057ccec91a1Sjoerg 
1058ccec91a1Sjoerg /**
1059ccec91a1Sjoerg  * The exception personality function.  This is referenced in the unwinding
1060ccec91a1Sjoerg  * DWARF metadata and is called by the unwind library for each C++ stack frame
1061ccec91a1Sjoerg  * containing catch or cleanup code.
1062ccec91a1Sjoerg  */
1063ccec91a1Sjoerg extern "C"
1064ccec91a1Sjoerg BEGIN_PERSONALITY_FUNCTION(__gxx_personality_v0)
1065ccec91a1Sjoerg 	// This personality function is for version 1 of the ABI.  If you use it
1066ccec91a1Sjoerg 	// with a future version of the ABI, it won't know what to do, so it
1067ccec91a1Sjoerg 	// reports a fatal error and give up before it breaks anything.
1068ccec91a1Sjoerg 	if (1 != version)
1069ccec91a1Sjoerg 	{
1070ccec91a1Sjoerg 		return _URC_FATAL_PHASE1_ERROR;
1071ccec91a1Sjoerg 	}
1072ccec91a1Sjoerg 	__cxa_exception *ex = 0;
1073ccec91a1Sjoerg 	__cxa_exception *realEx = 0;
1074ccec91a1Sjoerg 
1075ccec91a1Sjoerg 	// If this exception is throw by something else then we can't make any
1076ccec91a1Sjoerg 	// assumptions about its layout beyond the fields declared in
1077ccec91a1Sjoerg 	// _Unwind_Exception.
1078ccec91a1Sjoerg 	bool foreignException = !isCXXException(exceptionClass);
1079ccec91a1Sjoerg 
1080ccec91a1Sjoerg 	// If this isn't a foreign exception, then we have a C++ exception structure
1081ccec91a1Sjoerg 	if (!foreignException)
1082ccec91a1Sjoerg 	{
1083ccec91a1Sjoerg 		ex = exceptionFromPointer(exceptionObject);
1084ccec91a1Sjoerg 		realEx = realExceptionFromException(ex);
1085ccec91a1Sjoerg 	}
1086ccec91a1Sjoerg 
1087534cb174Sjoerg #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
1088ccec91a1Sjoerg 	unsigned char *lsda_addr =
1089d0b6b5d5Sjoerg 		static_cast<unsigned char*>(_Unwind_GetLanguageSpecificData(context));
1090d0b6b5d5Sjoerg #else
1091d0b6b5d5Sjoerg 	unsigned char *lsda_addr =
1092d0b6b5d5Sjoerg 		reinterpret_cast<unsigned char*>(static_cast<uintptr_t>(_Unwind_GetLanguageSpecificData(context)));
1093d0b6b5d5Sjoerg #endif
1094ccec91a1Sjoerg 
1095ccec91a1Sjoerg 	// No LSDA implies no landing pads - try the next frame
1096ccec91a1Sjoerg 	if (0 == lsda_addr) { return continueUnwinding(exceptionObject, context); }
1097ccec91a1Sjoerg 
1098ccec91a1Sjoerg 	// These two variables define how the exception will be handled.
1099ccec91a1Sjoerg 	dwarf_eh_action action = {0};
1100ccec91a1Sjoerg 	unsigned long selector = 0;
1101ccec91a1Sjoerg 
1102ccec91a1Sjoerg 	// During the search phase, we do a complete lookup.  If we return
1103ccec91a1Sjoerg 	// _URC_HANDLER_FOUND, then the phase 2 unwind will call this function with
1104ccec91a1Sjoerg 	// a _UA_HANDLER_FRAME action, telling us to install the handler frame.  If
1105ccec91a1Sjoerg 	// we return _URC_CONTINUE_UNWIND, we may be called again later with a
1106ccec91a1Sjoerg 	// _UA_CLEANUP_PHASE action for this frame.
1107ccec91a1Sjoerg 	//
1108ccec91a1Sjoerg 	// The point of the two-stage unwind allows us to entirely avoid any stack
1109ccec91a1Sjoerg 	// unwinding if there is no handler.  If there are just cleanups found,
1110ccec91a1Sjoerg 	// then we can just panic call an abort function.
1111ccec91a1Sjoerg 	//
1112ccec91a1Sjoerg 	// Matching a handler is much more expensive than matching a cleanup,
1113ccec91a1Sjoerg 	// because we don't need to bother doing type comparisons (or looking at
1114ccec91a1Sjoerg 	// the type table at all) for a cleanup.  This means that there is no need
1115ccec91a1Sjoerg 	// to cache the result of finding a cleanup, because it's (quite) quick to
1116ccec91a1Sjoerg 	// look it up again from the action table.
1117ccec91a1Sjoerg 	if (actions & _UA_SEARCH_PHASE)
1118ccec91a1Sjoerg 	{
1119ccec91a1Sjoerg 		struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
1120ccec91a1Sjoerg 
1121ccec91a1Sjoerg 		if (!dwarf_eh_find_callsite(context, &lsda, &action))
1122ccec91a1Sjoerg 		{
1123ccec91a1Sjoerg 			// EH range not found. This happens if exception is thrown and not
1124ccec91a1Sjoerg 			// caught inside a cleanup (destructor).  We should call
1125ccec91a1Sjoerg 			// terminate() in this case.  The catchTemp (landing pad) field of
1126ccec91a1Sjoerg 			// exception object will contain null when personality function is
1127ccec91a1Sjoerg 			// called with _UA_HANDLER_FRAME action for phase 2 unwinding.
1128ccec91a1Sjoerg 			return _URC_HANDLER_FOUND;
1129ccec91a1Sjoerg 		}
1130ccec91a1Sjoerg 
1131ccec91a1Sjoerg 		handler_type found_handler = check_action_record(context, &lsda,
1132ccec91a1Sjoerg 				action.action_record, realEx, &selector, ex->adjustedPtr);
1133ccec91a1Sjoerg 		// If there's no action record, we've only found a cleanup, so keep
1134ccec91a1Sjoerg 		// searching for something real
1135ccec91a1Sjoerg 		if (found_handler == handler_catch)
1136ccec91a1Sjoerg 		{
1137ccec91a1Sjoerg 			// Cache the results for the phase 2 unwind, if we found a handler
1138ccec91a1Sjoerg 			// and this is not a foreign exception.
1139ccec91a1Sjoerg 			if (ex)
1140ccec91a1Sjoerg 			{
1141ccec91a1Sjoerg 				saveLandingPad(context, exceptionObject, ex, selector, action.landing_pad);
1142d0b6b5d5Sjoerg 				ex->languageSpecificData = reinterpret_cast<const char*>(lsda_addr);
1143d0b6b5d5Sjoerg 				ex->actionRecord = reinterpret_cast<const char*>(action.action_record);
1144ccec91a1Sjoerg 				// ex->adjustedPtr is set when finding the action record.
1145ccec91a1Sjoerg 			}
1146ccec91a1Sjoerg 			return _URC_HANDLER_FOUND;
1147ccec91a1Sjoerg 		}
1148ccec91a1Sjoerg 		return continueUnwinding(exceptionObject, context);
1149ccec91a1Sjoerg 	}
1150ccec91a1Sjoerg 
1151ccec91a1Sjoerg 
1152ccec91a1Sjoerg 	// If this is a foreign exception, we didn't have anywhere to cache the
1153ccec91a1Sjoerg 	// lookup stuff, so we need to do it again.  If this is either a forced
1154ccec91a1Sjoerg 	// unwind, a foreign exception, or a cleanup, then we just install the
1155ccec91a1Sjoerg 	// context for a cleanup.
1156ccec91a1Sjoerg 	if (!(actions & _UA_HANDLER_FRAME))
1157ccec91a1Sjoerg 	{
1158ccec91a1Sjoerg 		// cleanup
1159ccec91a1Sjoerg 		struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
1160ccec91a1Sjoerg 		dwarf_eh_find_callsite(context, &lsda, &action);
1161ccec91a1Sjoerg 		if (0 == action.landing_pad) { return continueUnwinding(exceptionObject, context); }
1162ccec91a1Sjoerg 		handler_type found_handler = check_action_record(context, &lsda,
1163ccec91a1Sjoerg 				action.action_record, realEx, &selector, ex->adjustedPtr);
1164ccec91a1Sjoerg 		// Ignore handlers this time.
1165ccec91a1Sjoerg 		if (found_handler != handler_cleanup) { return continueUnwinding(exceptionObject, context); }
1166ccec91a1Sjoerg 		pushCleanupException(exceptionObject, ex);
1167ccec91a1Sjoerg 	}
1168ccec91a1Sjoerg 	else if (foreignException)
1169ccec91a1Sjoerg 	{
1170ccec91a1Sjoerg 		struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
1171ccec91a1Sjoerg 		dwarf_eh_find_callsite(context, &lsda, &action);
1172ccec91a1Sjoerg 		check_action_record(context, &lsda, action.action_record, realEx,
1173ccec91a1Sjoerg 				&selector, ex->adjustedPtr);
1174ccec91a1Sjoerg 	}
1175ccec91a1Sjoerg 	else if (ex->catchTemp == 0)
1176ccec91a1Sjoerg 	{
1177ccec91a1Sjoerg 		// Uncaught exception in cleanup, calling terminate
1178ccec91a1Sjoerg 		std::terminate();
1179ccec91a1Sjoerg 	}
1180ccec91a1Sjoerg 	else
1181ccec91a1Sjoerg 	{
1182ccec91a1Sjoerg 		// Restore the saved info if we saved some last time.
1183ccec91a1Sjoerg 		loadLandingPad(context, exceptionObject, ex, &selector, &action.landing_pad);
1184ccec91a1Sjoerg 		ex->catchTemp = 0;
1185ccec91a1Sjoerg 		ex->handlerSwitchValue = 0;
1186ccec91a1Sjoerg 	}
1187ccec91a1Sjoerg 
1188ccec91a1Sjoerg 
1189d0b6b5d5Sjoerg 	_Unwind_SetIP(context, reinterpret_cast<unsigned long>(action.landing_pad));
1190ccec91a1Sjoerg 	_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
1191d0b6b5d5Sjoerg 	              reinterpret_cast<unsigned long>(exceptionObject));
1192ccec91a1Sjoerg 	_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector);
1193ccec91a1Sjoerg 
1194ccec91a1Sjoerg 	return _URC_INSTALL_CONTEXT;
1195ccec91a1Sjoerg }
1196ccec91a1Sjoerg 
1197ccec91a1Sjoerg /**
1198ccec91a1Sjoerg  * ABI function called when entering a catch statement.  The argument is the
1199ccec91a1Sjoerg  * pointer passed out of the personality function.  This is always the start of
1200ccec91a1Sjoerg  * the _Unwind_Exception object.  The return value for this function is the
1201ccec91a1Sjoerg  * pointer to the caught exception, which is either the adjusted pointer (for
1202ccec91a1Sjoerg  * C++ exceptions) of the unadjusted pointer (for foreign exceptions).
1203ccec91a1Sjoerg  */
12041ca55825Spooka #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
1205ccec91a1Sjoerg extern "C" void *__cxa_begin_catch(void *e) throw()
1206ccec91a1Sjoerg #else
1207ccec91a1Sjoerg extern "C" void *__cxa_begin_catch(void *e)
1208ccec91a1Sjoerg #endif
1209ccec91a1Sjoerg {
1210ccec91a1Sjoerg 	// We can't call the fast version here, because if the first exception that
1211ccec91a1Sjoerg 	// we see is a foreign exception then we won't have called it yet.
1212ccec91a1Sjoerg 	__cxa_thread_info *ti = thread_info();
1213ccec91a1Sjoerg 	__cxa_eh_globals *globals = &ti->globals;
1214d0b6b5d5Sjoerg 	_Unwind_Exception *exceptionObject = static_cast<_Unwind_Exception*>(e);
1215ccec91a1Sjoerg 
1216ccec91a1Sjoerg 	if (isCXXException(exceptionObject->exception_class))
1217ccec91a1Sjoerg 	{
1218*387d6222Sjoerg 		// Only exceptions thrown with a C++ exception throwing function will
1219*387d6222Sjoerg 		// increment this, so don't decrement it here.
1220*387d6222Sjoerg 		globals->uncaughtExceptions--;
1221ccec91a1Sjoerg 		__cxa_exception *ex =  exceptionFromPointer(exceptionObject);
1222ccec91a1Sjoerg 
1223ccec91a1Sjoerg 		if (ex->handlerCount == 0)
1224ccec91a1Sjoerg 		{
1225ccec91a1Sjoerg 			// Add this to the front of the list of exceptions being handled
1226ccec91a1Sjoerg 			// and increment its handler count so that it won't be deleted
1227ccec91a1Sjoerg 			// prematurely.
1228ccec91a1Sjoerg 			ex->nextException = globals->caughtExceptions;
1229ccec91a1Sjoerg 			globals->caughtExceptions = ex;
1230ccec91a1Sjoerg 		}
1231ccec91a1Sjoerg 
1232ccec91a1Sjoerg 		if (ex->handlerCount < 0)
1233ccec91a1Sjoerg 		{
1234ccec91a1Sjoerg 			// Rethrown exception is catched before end of catch block.
1235ccec91a1Sjoerg 			// Clear the rethrow flag (make value positive) - we are allowed
1236ccec91a1Sjoerg 			// to delete this exception at the end of the catch block, as long
1237ccec91a1Sjoerg 			// as it isn't thrown again later.
1238ccec91a1Sjoerg 
1239ccec91a1Sjoerg 			// Code pattern:
1240ccec91a1Sjoerg 			//
1241ccec91a1Sjoerg 			// try {
1242ccec91a1Sjoerg 			//     throw x;
1243ccec91a1Sjoerg 			// }
1244ccec91a1Sjoerg 			// catch() {
1245ccec91a1Sjoerg 			//     try {
1246ccec91a1Sjoerg 			//         throw;
1247ccec91a1Sjoerg 			//     }
1248ccec91a1Sjoerg 			//     catch() {
1249ccec91a1Sjoerg 			//         __cxa_begin_catch() <- we are here
1250ccec91a1Sjoerg 			//     }
1251ccec91a1Sjoerg 			// }
1252ccec91a1Sjoerg 			ex->handlerCount = -ex->handlerCount + 1;
1253ccec91a1Sjoerg 		}
1254ccec91a1Sjoerg 		else
1255ccec91a1Sjoerg 		{
1256ccec91a1Sjoerg 			ex->handlerCount++;
1257ccec91a1Sjoerg 		}
1258ccec91a1Sjoerg 		ti->foreign_exception_state = __cxa_thread_info::none;
1259ccec91a1Sjoerg 
1260ccec91a1Sjoerg 		return ex->adjustedPtr;
1261ccec91a1Sjoerg 	}
1262ccec91a1Sjoerg 	else
1263ccec91a1Sjoerg 	{
1264ccec91a1Sjoerg 		// If this is a foreign exception, then we need to be able to
1265ccec91a1Sjoerg 		// store it.  We can't chain foreign exceptions, so we give up
1266ccec91a1Sjoerg 		// if there are already some outstanding ones.
1267ccec91a1Sjoerg 		if (globals->caughtExceptions != 0)
1268ccec91a1Sjoerg 		{
1269ccec91a1Sjoerg 			std::terminate();
1270ccec91a1Sjoerg 		}
1271d0b6b5d5Sjoerg 		globals->caughtExceptions = reinterpret_cast<__cxa_exception*>(exceptionObject);
1272ccec91a1Sjoerg 		ti->foreign_exception_state = __cxa_thread_info::caught;
1273ccec91a1Sjoerg 	}
1274ccec91a1Sjoerg 	// exceptionObject is the pointer to the _Unwind_Exception within the
1275ccec91a1Sjoerg 	// __cxa_exception.  The throw object is after this
1276d0b6b5d5Sjoerg 	return (reinterpret_cast<char*>(exceptionObject) + sizeof(_Unwind_Exception));
1277ccec91a1Sjoerg }
1278ccec91a1Sjoerg 
1279ccec91a1Sjoerg 
1280ccec91a1Sjoerg 
1281ccec91a1Sjoerg /**
1282ccec91a1Sjoerg  * ABI function called when exiting a catch block.  This will free the current
1283ccec91a1Sjoerg  * exception if it is no longer referenced in other catch blocks.
1284ccec91a1Sjoerg  */
1285ccec91a1Sjoerg extern "C" void __cxa_end_catch()
1286ccec91a1Sjoerg {
1287ccec91a1Sjoerg 	// We can call the fast version here because the slow version is called in
1288ccec91a1Sjoerg 	// __cxa_throw(), which must have been called before we end a catch block
1289ccec91a1Sjoerg 	__cxa_thread_info *ti = thread_info_fast();
1290ccec91a1Sjoerg 	__cxa_eh_globals *globals = &ti->globals;
1291ccec91a1Sjoerg 	__cxa_exception *ex = globals->caughtExceptions;
1292ccec91a1Sjoerg 
1293ccec91a1Sjoerg 	assert(0 != ex && "Ending catch when no exception is on the stack!");
1294ccec91a1Sjoerg 
1295ccec91a1Sjoerg 	if (ti->foreign_exception_state != __cxa_thread_info::none)
1296ccec91a1Sjoerg 	{
1297ccec91a1Sjoerg 		if (ti->foreign_exception_state != __cxa_thread_info::rethrown)
1298ccec91a1Sjoerg 		{
1299d0b6b5d5Sjoerg 			_Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(ti->globals.caughtExceptions);
1300*387d6222Sjoerg 			if (e->exception_cleanup)
1301ccec91a1Sjoerg 				e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
1302ccec91a1Sjoerg 		}
1303*387d6222Sjoerg 		globals->caughtExceptions = 0;
1304ccec91a1Sjoerg 		ti->foreign_exception_state = __cxa_thread_info::none;
1305ccec91a1Sjoerg 		return;
1306ccec91a1Sjoerg 	}
1307ccec91a1Sjoerg 
1308ccec91a1Sjoerg 	bool deleteException = true;
1309ccec91a1Sjoerg 
1310ccec91a1Sjoerg 	if (ex->handlerCount < 0)
1311ccec91a1Sjoerg 	{
1312ccec91a1Sjoerg 		// exception was rethrown. Exception should not be deleted even if
1313ccec91a1Sjoerg 		// handlerCount become zero.
1314ccec91a1Sjoerg 		// Code pattern:
1315ccec91a1Sjoerg 		// try {
1316ccec91a1Sjoerg 		//     throw x;
1317ccec91a1Sjoerg 		// }
1318ccec91a1Sjoerg 		// catch() {
1319ccec91a1Sjoerg 		//     {
1320ccec91a1Sjoerg 		//         throw;
1321ccec91a1Sjoerg 		//     }
1322ccec91a1Sjoerg 		//     cleanup {
1323ccec91a1Sjoerg 		//         __cxa_end_catch();   <- we are here
1324ccec91a1Sjoerg 		//     }
1325ccec91a1Sjoerg 		// }
1326ccec91a1Sjoerg 		//
1327ccec91a1Sjoerg 
1328ccec91a1Sjoerg 		ex->handlerCount++;
1329ccec91a1Sjoerg 		deleteException = false;
1330ccec91a1Sjoerg 	}
1331ccec91a1Sjoerg 	else
1332ccec91a1Sjoerg 	{
1333ccec91a1Sjoerg 		ex->handlerCount--;
1334ccec91a1Sjoerg 	}
1335ccec91a1Sjoerg 
1336ccec91a1Sjoerg 	if (ex->handlerCount == 0)
1337ccec91a1Sjoerg 	{
1338ccec91a1Sjoerg 		globals->caughtExceptions = ex->nextException;
1339ccec91a1Sjoerg 		if (deleteException)
1340ccec91a1Sjoerg 		{
1341ccec91a1Sjoerg 			releaseException(ex);
1342ccec91a1Sjoerg 		}
1343ccec91a1Sjoerg 	}
1344ccec91a1Sjoerg }
1345ccec91a1Sjoerg 
1346ccec91a1Sjoerg /**
1347ccec91a1Sjoerg  * ABI function.  Returns the type of the current exception.
1348ccec91a1Sjoerg  */
1349ccec91a1Sjoerg extern "C" std::type_info *__cxa_current_exception_type()
1350ccec91a1Sjoerg {
1351ccec91a1Sjoerg 	__cxa_eh_globals *globals = __cxa_get_globals();
1352ccec91a1Sjoerg 	__cxa_exception *ex = globals->caughtExceptions;
1353ccec91a1Sjoerg 	return ex ? ex->exceptionType : 0;
1354ccec91a1Sjoerg }
1355ccec91a1Sjoerg 
1356ccec91a1Sjoerg /**
1357*387d6222Sjoerg  * Cleanup, ensures that `__cxa_end_catch` is called to balance an explicit
1358*387d6222Sjoerg  * `__cxa_begin_catch` call.
1359*387d6222Sjoerg  */
1360*387d6222Sjoerg static void end_catch(char *)
1361*387d6222Sjoerg {
1362*387d6222Sjoerg 	__cxa_end_catch();
1363*387d6222Sjoerg }
1364*387d6222Sjoerg /**
1365ccec91a1Sjoerg  * ABI function, called when an exception specification is violated.
1366ccec91a1Sjoerg  *
1367ccec91a1Sjoerg  * This function does not return.
1368ccec91a1Sjoerg  */
1369ccec91a1Sjoerg extern "C" void __cxa_call_unexpected(void*exception)
1370ccec91a1Sjoerg {
1371d0b6b5d5Sjoerg 	_Unwind_Exception *exceptionObject = static_cast<_Unwind_Exception*>(exception);
1372*387d6222Sjoerg 	// Wrap the call to the unexpected handler in calls to `__cxa_begin_catch`
1373*387d6222Sjoerg 	// and `__cxa_end_catch` so that we correctly update exception counts if
1374*387d6222Sjoerg 	// the unexpected handler throws an exception.
1375*387d6222Sjoerg 	__cxa_begin_catch(exceptionObject);
1376*387d6222Sjoerg 	__attribute__((cleanup(end_catch)))
1377*387d6222Sjoerg 	char unused;
1378ccec91a1Sjoerg 	if (exceptionObject->exception_class == exception_class)
1379ccec91a1Sjoerg 	{
1380ccec91a1Sjoerg 		__cxa_exception *ex =  exceptionFromPointer(exceptionObject);
1381ccec91a1Sjoerg 		if (ex->unexpectedHandler)
1382ccec91a1Sjoerg 		{
1383ccec91a1Sjoerg 			ex->unexpectedHandler();
1384ccec91a1Sjoerg 			// Should not be reached.
1385ccec91a1Sjoerg 			abort();
1386ccec91a1Sjoerg 		}
1387ccec91a1Sjoerg 	}
1388ccec91a1Sjoerg 	std::unexpected();
1389ccec91a1Sjoerg 	// Should not be reached.
1390ccec91a1Sjoerg 	abort();
1391ccec91a1Sjoerg }
1392ccec91a1Sjoerg 
1393ccec91a1Sjoerg /**
1394ccec91a1Sjoerg  * ABI function, returns the adjusted pointer to the exception object.
1395ccec91a1Sjoerg  */
1396ccec91a1Sjoerg extern "C" void *__cxa_get_exception_ptr(void *exceptionObject)
1397ccec91a1Sjoerg {
1398ccec91a1Sjoerg 	return exceptionFromPointer(exceptionObject)->adjustedPtr;
1399ccec91a1Sjoerg }
1400ccec91a1Sjoerg 
1401ccec91a1Sjoerg /**
1402ccec91a1Sjoerg  * As an extension, we provide the ability for the unexpected and terminate
1403ccec91a1Sjoerg  * handlers to be thread-local.  We default to the standards-compliant
1404ccec91a1Sjoerg  * behaviour where they are global.
1405ccec91a1Sjoerg  */
1406ccec91a1Sjoerg static bool thread_local_handlers = false;
1407ccec91a1Sjoerg 
1408ccec91a1Sjoerg 
1409ccec91a1Sjoerg namespace pathscale
1410ccec91a1Sjoerg {
1411ccec91a1Sjoerg 	/**
1412ccec91a1Sjoerg 	 * Sets whether unexpected and terminate handlers should be thread-local.
1413ccec91a1Sjoerg 	 */
1414ccec91a1Sjoerg 	void set_use_thread_local_handlers(bool flag) throw()
1415ccec91a1Sjoerg 	{
1416ccec91a1Sjoerg 		thread_local_handlers = flag;
1417ccec91a1Sjoerg 	}
1418ccec91a1Sjoerg 	/**
1419ccec91a1Sjoerg 	 * Sets a thread-local unexpected handler.
1420ccec91a1Sjoerg 	 */
1421ccec91a1Sjoerg 	unexpected_handler set_unexpected(unexpected_handler f) throw()
1422ccec91a1Sjoerg 	{
1423ccec91a1Sjoerg 		static __cxa_thread_info *info = thread_info();
1424ccec91a1Sjoerg 		unexpected_handler old = info->unexpectedHandler;
1425ccec91a1Sjoerg 		info->unexpectedHandler = f;
1426ccec91a1Sjoerg 		return old;
1427ccec91a1Sjoerg 	}
1428ccec91a1Sjoerg 	/**
1429ccec91a1Sjoerg 	 * Sets a thread-local terminate handler.
1430ccec91a1Sjoerg 	 */
1431ccec91a1Sjoerg 	terminate_handler set_terminate(terminate_handler f) throw()
1432ccec91a1Sjoerg 	{
1433ccec91a1Sjoerg 		static __cxa_thread_info *info = thread_info();
1434ccec91a1Sjoerg 		terminate_handler old = info->terminateHandler;
1435ccec91a1Sjoerg 		info->terminateHandler = f;
1436ccec91a1Sjoerg 		return old;
1437ccec91a1Sjoerg 	}
1438ccec91a1Sjoerg }
1439ccec91a1Sjoerg 
1440ccec91a1Sjoerg namespace std
1441ccec91a1Sjoerg {
1442ccec91a1Sjoerg 	/**
1443ccec91a1Sjoerg 	 * Sets the function that will be called when an exception specification is
1444ccec91a1Sjoerg 	 * violated.
1445ccec91a1Sjoerg 	 */
1446ccec91a1Sjoerg 	unexpected_handler set_unexpected(unexpected_handler f) throw()
1447ccec91a1Sjoerg 	{
1448ccec91a1Sjoerg 		if (thread_local_handlers) { return pathscale::set_unexpected(f); }
1449ccec91a1Sjoerg 
1450ccec91a1Sjoerg 		return ATOMIC_SWAP(&unexpectedHandler, f);
1451ccec91a1Sjoerg 	}
1452ccec91a1Sjoerg 	/**
1453ccec91a1Sjoerg 	 * Sets the function that is called to terminate the program.
1454ccec91a1Sjoerg 	 */
1455ccec91a1Sjoerg 	terminate_handler set_terminate(terminate_handler f) throw()
1456ccec91a1Sjoerg 	{
1457ccec91a1Sjoerg 		if (thread_local_handlers) { return pathscale::set_terminate(f); }
1458ccec91a1Sjoerg 
1459ccec91a1Sjoerg 		return ATOMIC_SWAP(&terminateHandler, f);
1460ccec91a1Sjoerg 	}
1461ccec91a1Sjoerg 	/**
1462ccec91a1Sjoerg 	 * Terminates the program, calling a custom terminate implementation if
1463ccec91a1Sjoerg 	 * required.
1464ccec91a1Sjoerg 	 */
1465ccec91a1Sjoerg 	void terminate()
1466ccec91a1Sjoerg 	{
1467ccec91a1Sjoerg 		static __cxa_thread_info *info = thread_info();
1468ccec91a1Sjoerg 		if (0 != info && 0 != info->terminateHandler)
1469ccec91a1Sjoerg 		{
1470ccec91a1Sjoerg 			info->terminateHandler();
1471ccec91a1Sjoerg 			// Should not be reached - a terminate handler is not expected to
1472ccec91a1Sjoerg 			// return.
1473ccec91a1Sjoerg 			abort();
1474ccec91a1Sjoerg 		}
1475ccec91a1Sjoerg 		terminateHandler();
1476ccec91a1Sjoerg 	}
1477ccec91a1Sjoerg 	/**
1478ccec91a1Sjoerg 	 * Called when an unexpected exception is encountered (i.e. an exception
1479ccec91a1Sjoerg 	 * violates an exception specification).  This calls abort() unless a
1480ccec91a1Sjoerg 	 * custom handler has been set..
1481ccec91a1Sjoerg 	 */
1482ccec91a1Sjoerg 	void unexpected()
1483ccec91a1Sjoerg 	{
1484ccec91a1Sjoerg 		static __cxa_thread_info *info = thread_info();
1485ccec91a1Sjoerg 		if (0 != info && 0 != info->unexpectedHandler)
1486ccec91a1Sjoerg 		{
1487ccec91a1Sjoerg 			info->unexpectedHandler();
1488ccec91a1Sjoerg 			// Should not be reached - a terminate handler is not expected to
1489ccec91a1Sjoerg 			// return.
1490ccec91a1Sjoerg 			abort();
1491ccec91a1Sjoerg 		}
1492ccec91a1Sjoerg 		unexpectedHandler();
1493ccec91a1Sjoerg 	}
1494ccec91a1Sjoerg 	/**
1495ccec91a1Sjoerg 	 * Returns whether there are any exceptions currently being thrown that
1496ccec91a1Sjoerg 	 * have not been caught.  This can occur inside a nested catch statement.
1497ccec91a1Sjoerg 	 */
1498ccec91a1Sjoerg 	bool uncaught_exception() throw()
1499ccec91a1Sjoerg 	{
1500ccec91a1Sjoerg 		__cxa_thread_info *info = thread_info();
1501ccec91a1Sjoerg 		return info->globals.uncaughtExceptions != 0;
1502ccec91a1Sjoerg 	}
1503ccec91a1Sjoerg 	/**
1504*387d6222Sjoerg 	 * Returns the number of exceptions currently being thrown that have not
1505*387d6222Sjoerg 	 * been caught.  This can occur inside a nested catch statement.
1506*387d6222Sjoerg 	 */
1507*387d6222Sjoerg 	int uncaught_exceptions() throw()
1508*387d6222Sjoerg 	{
1509*387d6222Sjoerg 		__cxa_thread_info *info = thread_info();
1510*387d6222Sjoerg 		return info->globals.uncaughtExceptions;
1511*387d6222Sjoerg 	}
1512*387d6222Sjoerg 	/**
1513ccec91a1Sjoerg 	 * Returns the current unexpected handler.
1514ccec91a1Sjoerg 	 */
1515ccec91a1Sjoerg 	unexpected_handler get_unexpected() throw()
1516ccec91a1Sjoerg 	{
1517ccec91a1Sjoerg 		__cxa_thread_info *info = thread_info();
1518ccec91a1Sjoerg 		if (info->unexpectedHandler)
1519ccec91a1Sjoerg 		{
1520ccec91a1Sjoerg 			return info->unexpectedHandler;
1521ccec91a1Sjoerg 		}
1522ccec91a1Sjoerg 		return ATOMIC_LOAD(&unexpectedHandler);
1523ccec91a1Sjoerg 	}
1524ccec91a1Sjoerg 	/**
1525ccec91a1Sjoerg 	 * Returns the current terminate handler.
1526ccec91a1Sjoerg 	 */
1527ccec91a1Sjoerg 	terminate_handler get_terminate() throw()
1528ccec91a1Sjoerg 	{
1529ccec91a1Sjoerg 		__cxa_thread_info *info = thread_info();
1530ccec91a1Sjoerg 		if (info->terminateHandler)
1531ccec91a1Sjoerg 		{
1532ccec91a1Sjoerg 			return info->terminateHandler;
1533ccec91a1Sjoerg 		}
1534ccec91a1Sjoerg 		return ATOMIC_LOAD(&terminateHandler);
1535ccec91a1Sjoerg 	}
1536ccec91a1Sjoerg }
1537534cb174Sjoerg #if defined(__arm__) && !defined(__ARM_DWARF_EH__)
1538ccec91a1Sjoerg extern "C" _Unwind_Exception *__cxa_get_cleanup(void)
1539ccec91a1Sjoerg {
1540ccec91a1Sjoerg 	__cxa_thread_info *info = thread_info_fast();
1541ccec91a1Sjoerg 	_Unwind_Exception *exceptionObject = info->currentCleanup;
1542ccec91a1Sjoerg 	if (isCXXException(exceptionObject->exception_class))
1543ccec91a1Sjoerg 	{
1544ccec91a1Sjoerg 		__cxa_exception *ex =  exceptionFromPointer(exceptionObject);
1545ccec91a1Sjoerg 		ex->cleanupCount--;
1546ccec91a1Sjoerg 		if (ex->cleanupCount == 0)
1547ccec91a1Sjoerg 		{
1548ccec91a1Sjoerg 			info->currentCleanup = ex->nextCleanup;
1549ccec91a1Sjoerg 			ex->nextCleanup = 0;
1550ccec91a1Sjoerg 		}
1551ccec91a1Sjoerg 	}
1552ccec91a1Sjoerg 	else
1553ccec91a1Sjoerg 	{
1554ccec91a1Sjoerg 		info->currentCleanup = 0;
1555ccec91a1Sjoerg 	}
1556ccec91a1Sjoerg 	return exceptionObject;
1557ccec91a1Sjoerg }
1558ccec91a1Sjoerg 
1559ccec91a1Sjoerg asm (
1560ccec91a1Sjoerg ".pushsection .text.__cxa_end_cleanup    \n"
1561ccec91a1Sjoerg ".global __cxa_end_cleanup               \n"
1562ccec91a1Sjoerg ".type __cxa_end_cleanup, \"function\"   \n"
1563ccec91a1Sjoerg "__cxa_end_cleanup:                      \n"
1564ccec91a1Sjoerg "	push {r1, r2, r3, r4}                \n"
1565ccec91a1Sjoerg "	bl __cxa_get_cleanup                 \n"
1566ccec91a1Sjoerg "	push {r1, r2, r3, r4}                \n"
1567ccec91a1Sjoerg "	b _Unwind_Resume                     \n"
1568ccec91a1Sjoerg "	bl abort                             \n"
1569ccec91a1Sjoerg ".popsection                             \n"
1570ccec91a1Sjoerg );
1571ccec91a1Sjoerg #endif
1572