blob: 3e20c16d95d819f5ceb6359beab235653a1afb03 [file] [log] [blame]
Marshall Clowe0252022011-07-20 15:04:39 +00001//===------------------------- cxa_exception.cpp --------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//
9// This file implements the "Exception Handling APIs"
10// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
11//
12//===----------------------------------------------------------------------===//
13
14#include "cxxabi.h"
15
16#include <exception> // for std::terminate
17#include <cstdlib> // for malloc, free
18#include <string> // for memset
19#include <pthread.h>
20
21#include "cxa_exception.hpp"
Marshall Clowe0252022011-07-20 15:04:39 +000022
23namespace __cxxabiv1 {
Marshall Clow3c54f1b2011-08-09 15:09:41 +000024static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0
25static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
26
Marshall Clowe0252022011-07-20 15:04:39 +000027// Utility routines
Marshall Clowfb69a8b2011-08-15 18:06:47 +000028static __cxa_exception *exception_from_thrown_object(void *p) throw() {
29 return ((__cxa_exception *) p) - 1;
30}
Marshall Clowe0252022011-07-20 15:04:39 +000031
Marshall Clowfb69a8b2011-08-15 18:06:47 +000032static void * thrown_object_from_exception(void *p) throw() {
33 return (void *) (((__cxa_exception *) p) + 1 );
34}
Marshall Clowe0252022011-07-20 15:04:39 +000035
Marshall Clowfb69a8b2011-08-15 18:06:47 +000036static size_t object_size_from_exception_size(size_t size) throw() {
Marshall Clowe0252022011-07-20 15:04:39 +000037 return size + sizeof (__cxa_exception);
Marshall Clowfb69a8b2011-08-15 18:06:47 +000038}
Marshall Clowe0252022011-07-20 15:04:39 +000039
Marshall Clow3c54f1b2011-08-09 15:09:41 +000040// Get the exception object from the unwind pointer.
41// Relies on the structure layout, where the unwind pointer is right in
42// front of the user's exception object
43static __cxa_exception *
Marshall Clowfb69a8b2011-08-15 18:06:47 +000044exception_from_exception_object(void *ptr) throw() {
45 _Unwind_Exception *p = reinterpret_cast<_Unwind_Exception *>(ptr);
46 return exception_from_thrown_object(p + 1 );
47}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000048
Marshall Clowfb69a8b2011-08-15 18:06:47 +000049static void setExceptionClass(_Unwind_Exception *unwind) throw() {
Marshall Clow3c54f1b2011-08-09 15:09:41 +000050 unwind->exception_class = kOurExceptionClass;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000051}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000052
Marshall Clowfb69a8b2011-08-15 18:06:47 +000053static void setDependentExceptionClass(_Unwind_Exception *unwind) throw() {
Marshall Clow3c54f1b2011-08-09 15:09:41 +000054 unwind->exception_class = kOurDependentExceptionClass;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000055}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000056
57// Is it one of ours?
Marshall Clowfb69a8b2011-08-15 18:06:47 +000058static bool isOurExceptionClass(_Unwind_Exception *unwind) throw() {
59 return(unwind->exception_class == kOurExceptionClass)||
60 (unwind->exception_class == kOurDependentExceptionClass);
61}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000062
Marshall Clowfb69a8b2011-08-15 18:06:47 +000063static bool isDependentException(_Unwind_Exception *unwind) throw() {
64 return (unwind->exception_class & 0xFF) == 0x01;
65}
66
67// TODO: This needs to be atomic
68static int incrementHandlerCount(__cxa_exception *exception) throw() {
69 return ++exception->handlerCount;
70}
71
72// TODO: This needs to be atomic
73static int decrementHandlerCount(__cxa_exception *exception) throw() {
74 return --exception->handlerCount;
75}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000076
Marshall Clowe0252022011-07-20 15:04:39 +000077#include "fallback_malloc.cpp"
78
79// Allocate some memory from _somewhere_
Marshall Clowfb69a8b2011-08-15 18:06:47 +000080static void *do_malloc(size_t size) throw() {
81 void *ptr = std::malloc(size);
82 if (NULL == ptr) // if malloc fails, fall back to emergency stash
83 ptr = fallback_malloc(size);
Marshall Clowe0252022011-07-20 15:04:39 +000084 return ptr;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000085}
Marshall Clowe0252022011-07-20 15:04:39 +000086
87// Didn't know you could "return <expression>" from a void function, did you?
88// Well, you can, if the type of the expression is "void" also.
Marshall Clowfb69a8b2011-08-15 18:06:47 +000089static void do_free(void *ptr) throw() {
90 return is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr);
91}
Marshall Clowe0252022011-07-20 15:04:39 +000092
Marshall Clow3c54f1b2011-08-09 15:09:41 +000093/* Howard says:
94 If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
95 stored in exc is called. Otherwise the exceptionDestructor stored in
96 exc is called, and then the memory for the exception is deallocated.
97*/
Marshall Clowfb69a8b2011-08-15 18:06:47 +000098static void exception_cleanup_func(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc) {
99 __cxa_exception *exception = exception_from_exception_object(exc);
100 if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000101 exception->terminateHandler ();
102
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000103 void * thrown_object = thrown_object_from_exception(exception);
104 if (NULL != exception->exceptionDestructor)
105 exception->exceptionDestructor(thrown_object);
106 __cxa_free_exception(thrown_object);
107}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000108
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000109static LIBCXXABI_NORETURN void failed_throw(__cxa_exception *exception) throw() {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000110// Section 2.5.3 says:
111// * For purposes of this ABI, several things are considered exception handlers:
112// ** A terminate() call due to a throw.
113// and
114// * Upon entry, Following initialization of the catch parameter,
115// a handler must call:
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000116// * void *__cxa_begin_catch(void *exceptionObject );
117 (void) __cxa_begin_catch(&exception->unwindHeader);
118 std::terminate();
119}
Marshall Clowe0252022011-07-20 15:04:39 +0000120
121extern "C" {
122
123// Allocate a __cxa_exception object, and zero-fill it.
124// Reserve "thrown_size" bytes on the end for the user's exception
125// object. Zero-fill the object. If memory can't be allocated, call
126// std::terminate. Return a pointer to the memory to be used for the
127// user's exception object.
128void * __cxa_allocate_exception (size_t thrown_size) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000129 size_t actual_size = object_size_from_exception_size(thrown_size);
130 void *ptr = do_malloc(actual_size);
131 if (NULL == ptr)
132 std::terminate();
133 std::memset(ptr, 0, actual_size);
134 return thrown_object_from_exception(ptr);
135}
Marshall Clowe0252022011-07-20 15:04:39 +0000136
137
138// Free a __cxa_exception object allocated with __cxa_allocate_exception.
139void __cxa_free_exception (void * thrown_exception) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000140 do_free(exception_from_thrown_object(thrown_exception));
141}
Marshall Clowe0252022011-07-20 15:04:39 +0000142
143
144// This function shall allocate a __cxa_dependent_exception and
145// return a pointer to it. (Really to the object, not past its' end).
146// Otherwise, it will work like __cxa_allocate_exception.
147void * __cxa_allocate_dependent_exception () throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000148 size_t actual_size = sizeof(__cxa_dependent_exception);
149 void *ptr = do_malloc(actual_size);
150 if (NULL == ptr)
151 std::terminate();
152 std::memset(ptr, 0, actual_size);
Marshall Clowe0252022011-07-20 15:04:39 +0000153// bookkeeping here ?
154 return ptr;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000155}
Marshall Clowe0252022011-07-20 15:04:39 +0000156
157
158// This function shall free a dependent_exception.
159// It does not affect the reference count of the primary exception.
160void __cxa_free_dependent_exception (void * dependent_exception) throw() {
161// I'm pretty sure there's no bookkeeping here
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000162 do_free(dependent_exception);
163}
Marshall Clowe0252022011-07-20 15:04:39 +0000164
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000165
166// 2.4.3 Throwing the Exception Object
167/*
168After constructing the exception object with the throw argument value,
169the generated code calls the __cxa_throw runtime library routine. This
170routine never returns.
171
172The __cxa_throw routine will do the following:
173
174* Obtain the __cxa_exception header from the thrown exception object address,
175which can be computed as follows:
176 __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);
177* Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
178* Save the tinfo and dest arguments in the __cxa_exception header.
179* Set the exception_class field in the unwind header. This is a 64-bit value
180representing the ASCII string "XXXXC++\0", where "XXXX" is a
181vendor-dependent string. That is, for implementations conforming to this
182ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
183* Increment the uncaught_exception flag.
184* Call _Unwind_RaiseException in the system unwind library, Its argument is the
185pointer to the thrown exception, which __cxa_throw itself received as an argument.
186__Unwind_RaiseException begins the process of stack unwinding, described
187in Section 2.5. In special cases, such as an inability to find a
188handler, _Unwind_RaiseException may return. In that case, __cxa_throw
189will call terminate, assuming that there was no handler for the
190exception.
191*/
192LIBCXXABI_NORETURN void
193__cxa_throw(void * thrown_exception, std::type_info * tinfo, void (*dest)(void *)) {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000194 __cxa_eh_globals *globals = __cxa_get_globals();
195 __cxa_exception *exception = exception_from_thrown_object(thrown_exception);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000196
Howard Hinnantd9ad30c2011-12-06 19:02:03 +0000197 exception->unexpectedHandler = std::get_unexpected();
198 exception->terminateHandler = std::get_terminate();
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000199 exception->exceptionType = tinfo;
200 exception->exceptionDestructor = dest;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000201 setExceptionClass(&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000202 exception->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
203 globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
204
205 exception->unwindHeader.exception_cleanup = exception_cleanup_func;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000206 _Unwind_RaiseException(&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000207
208// If we get here, some kind of unwinding error has occurred.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000209 failed_throw(exception);
210}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000211
212
213// 2.5.3 Exception Handlers
214extern void * __cxa_get_exception_ptr(void * exceptionObject) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000215 return exception_from_exception_object(exceptionObject);
216}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000217
218
219/*
220This routine:
221* Increment's the exception's handler count.
222* Places the exception on the stack of currently-caught exceptions if it is not
223 already there, linking the exception to the previous top of the stack.
224* Decrements the uncaught_exception count.
225* Returns the adjusted pointer to the exception object.
226*/
227void * __cxa_begin_catch(void * exceptionObject) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000228 __cxa_eh_globals *globals = __cxa_get_globals();
229 __cxa_exception *exception = exception_from_exception_object(exceptionObject);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000230
231// TODO add stuff for dependent exceptions.
232
233// TODO - should this be atomic?
234// Increment the handler count, removing the flag about being rethrown
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000235// assert(exception->handlerCount != 0);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000236 exception->handlerCount = exception->handlerCount < 0 ?
237 -exception->handlerCount + 1 : exception->handlerCount + 1;
238
239// place the exception on the top of the stack if it's not there.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000240 if (exception != globals->caughtExceptions) {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000241 exception->nextException = globals->caughtExceptions;
242 globals->caughtExceptions = exception;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000243 }
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000244
245 globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000246 return thrown_object_from_exception(exception);
247}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000248
249
250/*
251Upon exit for any reason, a handler must call:
252 void __cxa_end_catch ();
253
254This routine:
255* Locates the most recently caught exception and decrements its handler count.
256* Removes the exception from the caught exception stack, if the handler count goes to zero.
257* Destroys the exception if the handler count goes to zero, and the exception was not re-thrown by throw.
258*/
259void __cxa_end_catch() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000260 __cxa_eh_globals *globals = __cxa_get_globals();
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000261 __cxa_exception *current_exception = globals->caughtExceptions;
262
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000263 if (NULL != current_exception) {
264 if (current_exception->handlerCount < 0) {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000265 // The exception has been rethrown
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000266 if (0 == incrementHandlerCount(current_exception)) {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000267 globals->caughtExceptions = current_exception->nextException;
268 // Howard says: If the exception has been rethrown, don't destroy.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000269 }
270 }
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000271 else {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000272 if (0 == decrementHandlerCount(current_exception)) {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000273 // Remove from the chain of uncaught exceptions
274 globals->caughtExceptions = current_exception->nextException;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000275 if (!isDependentException(&current_exception->unwindHeader))
276 _Unwind_DeleteException(&current_exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000277 else {
278 // TODO: deal with a dependent exception
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000279 }
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000280 }
281 }
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000282 }
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000283}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000284
285
286std::type_info * __cxa_current_exception_type() {
287// get the current exception
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000288 __cxa_eh_globals *globals = __cxa_get_globals();
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000289 __cxa_exception *current_exception = globals->caughtExceptions;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000290 if (NULL == current_exception)
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000291 return NULL; // No current exception
292// TODO add stuff for dependent exceptions.
293 return current_exception->exceptionType;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000294}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000295
296// 2.5.4 Rethrowing Exceptions
297/* This routine
298* marks the exception object on top of the caughtExceptions stack
299 (in an implementation-defined way) as being rethrown.
300* If the caughtExceptions stack is empty, it calls terminate()
301 (see [C++FDIS] [except.throw], 15.1.8).
302* It then returns to the handler that called it, which must call
303 __cxa_end_catch(), perform any necessary cleanup, and finally
304 call _Unwind_Resume() to continue unwinding.
305*/
306extern LIBCXXABI_NORETURN void __cxa_rethrow() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000307 __cxa_eh_globals *globals = __cxa_get_globals();
308 __cxa_exception *exception = exception_from_exception_object(globals->caughtExceptions );
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000309
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000310 if (NULL == exception) // there's no current exception!
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000311 std::terminate ();
312
313// Mark the exception as being rethrown
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000314 exception->handlerCount = -exception->handlerCount ; // TODO: Atomic
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000315
316#if __arm__
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000317 (void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000318#else
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000319 (void) _Unwind_Resume_or_Rethrow (&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000320#endif
321
322// If we get here, some kind of unwinding error has occurred.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000323 failed_throw(exception);
324}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000325
Marshall Clowe0252022011-07-20 15:04:39 +0000326} // extern "C"
327
328} // abi