blob: 90e9032d7cbf4c45baa5c4fe030929bba81551d0 [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"
Howard Hinnantb80931e2011-12-07 21:16:40 +000022#include "cxa_handlers.hpp"
Marshall Clowe0252022011-07-20 15:04:39 +000023
24namespace __cxxabiv1 {
Marshall Clow3c54f1b2011-08-09 15:09:41 +000025static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0
26static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
27
Marshall Clowe0252022011-07-20 15:04:39 +000028// Utility routines
Howard Hinnantb80931e2011-12-07 21:16:40 +000029static inline __cxa_exception *exception_from_thrown_object(void *p) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +000030 return ((__cxa_exception *) p) - 1;
31}
Marshall Clowe0252022011-07-20 15:04:39 +000032
Howard Hinnantb80931e2011-12-07 21:16:40 +000033static inline void * thrown_object_from_exception(void *p) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +000034 return (void *) (((__cxa_exception *) p) + 1 );
35}
Marshall Clowe0252022011-07-20 15:04:39 +000036
Howard Hinnantb80931e2011-12-07 21:16:40 +000037static inline size_t object_size_from_exception_size(size_t size) throw() {
Marshall Clowe0252022011-07-20 15:04:39 +000038 return size + sizeof (__cxa_exception);
Marshall Clowfb69a8b2011-08-15 18:06:47 +000039}
Marshall Clowe0252022011-07-20 15:04:39 +000040
Marshall Clow3c54f1b2011-08-09 15:09:41 +000041// Get the exception object from the unwind pointer.
42// Relies on the structure layout, where the unwind pointer is right in
43// front of the user's exception object
44static __cxa_exception *
Marshall Clowfb69a8b2011-08-15 18:06:47 +000045exception_from_exception_object(void *ptr) throw() {
46 _Unwind_Exception *p = reinterpret_cast<_Unwind_Exception *>(ptr);
47 return exception_from_thrown_object(p + 1 );
48}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000049
Marshall Clowfb69a8b2011-08-15 18:06:47 +000050static void setExceptionClass(_Unwind_Exception *unwind) throw() {
Marshall Clow3c54f1b2011-08-09 15:09:41 +000051 unwind->exception_class = kOurExceptionClass;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000052}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000053
Marshall Clowfb69a8b2011-08-15 18:06:47 +000054static void setDependentExceptionClass(_Unwind_Exception *unwind) throw() {
Marshall Clow3c54f1b2011-08-09 15:09:41 +000055 unwind->exception_class = kOurDependentExceptionClass;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000056}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000057
58// Is it one of ours?
Marshall Clowfb69a8b2011-08-15 18:06:47 +000059static bool isOurExceptionClass(_Unwind_Exception *unwind) throw() {
60 return(unwind->exception_class == kOurExceptionClass)||
61 (unwind->exception_class == kOurDependentExceptionClass);
62}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000063
Marshall Clowfb69a8b2011-08-15 18:06:47 +000064static bool isDependentException(_Unwind_Exception *unwind) throw() {
65 return (unwind->exception_class & 0xFF) == 0x01;
66}
67
68// TODO: This needs to be atomic
69static int incrementHandlerCount(__cxa_exception *exception) throw() {
70 return ++exception->handlerCount;
71}
72
73// TODO: This needs to be atomic
74static int decrementHandlerCount(__cxa_exception *exception) throw() {
75 return --exception->handlerCount;
76}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000077
Marshall Clowe0252022011-07-20 15:04:39 +000078#include "fallback_malloc.cpp"
79
80// Allocate some memory from _somewhere_
Marshall Clowfb69a8b2011-08-15 18:06:47 +000081static void *do_malloc(size_t size) throw() {
82 void *ptr = std::malloc(size);
83 if (NULL == ptr) // if malloc fails, fall back to emergency stash
84 ptr = fallback_malloc(size);
Marshall Clowe0252022011-07-20 15:04:39 +000085 return ptr;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000086}
Marshall Clowe0252022011-07-20 15:04:39 +000087
88// Didn't know you could "return <expression>" from a void function, did you?
89// Well, you can, if the type of the expression is "void" also.
Marshall Clowfb69a8b2011-08-15 18:06:47 +000090static void do_free(void *ptr) throw() {
91 return is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr);
92}
Marshall Clowe0252022011-07-20 15:04:39 +000093
Howard Hinnantb80931e2011-12-07 21:16:40 +000094/*
Marshall Clow3c54f1b2011-08-09 15:09:41 +000095 If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
96 stored in exc is called. Otherwise the exceptionDestructor stored in
97 exc is called, and then the memory for the exception is deallocated.
98*/
Marshall Clowfb69a8b2011-08-15 18:06:47 +000099static void exception_cleanup_func(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc) {
100 __cxa_exception *exception = exception_from_exception_object(exc);
101 if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
Howard Hinnantb80931e2011-12-07 21:16:40 +0000102 std::__terminate(exception->terminateHandler);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000103
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000104 void * thrown_object = thrown_object_from_exception(exception);
105 if (NULL != exception->exceptionDestructor)
106 exception->exceptionDestructor(thrown_object);
107 __cxa_free_exception(thrown_object);
108}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000109
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000110static LIBCXXABI_NORETURN void failed_throw(__cxa_exception *exception) throw() {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000111// Section 2.5.3 says:
112// * For purposes of this ABI, several things are considered exception handlers:
113// ** A terminate() call due to a throw.
114// and
115// * Upon entry, Following initialization of the catch parameter,
116// a handler must call:
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000117// * void *__cxa_begin_catch(void *exceptionObject );
118 (void) __cxa_begin_catch(&exception->unwindHeader);
Howard Hinnantb80931e2011-12-07 21:16:40 +0000119 std::__terminate(exception->terminateHandler);
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000120}
Marshall Clowe0252022011-07-20 15:04:39 +0000121
122extern "C" {
123
124// Allocate a __cxa_exception object, and zero-fill it.
125// Reserve "thrown_size" bytes on the end for the user's exception
126// object. Zero-fill the object. If memory can't be allocated, call
127// std::terminate. Return a pointer to the memory to be used for the
128// user's exception object.
129void * __cxa_allocate_exception (size_t thrown_size) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000130 size_t actual_size = object_size_from_exception_size(thrown_size);
131 void *ptr = do_malloc(actual_size);
132 if (NULL == ptr)
133 std::terminate();
134 std::memset(ptr, 0, actual_size);
135 return thrown_object_from_exception(ptr);
136}
Marshall Clowe0252022011-07-20 15:04:39 +0000137
138
139// Free a __cxa_exception object allocated with __cxa_allocate_exception.
140void __cxa_free_exception (void * thrown_exception) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000141 do_free(exception_from_thrown_object(thrown_exception));
142}
Marshall Clowe0252022011-07-20 15:04:39 +0000143
144
145// This function shall allocate a __cxa_dependent_exception and
146// return a pointer to it. (Really to the object, not past its' end).
147// Otherwise, it will work like __cxa_allocate_exception.
148void * __cxa_allocate_dependent_exception () throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000149 size_t actual_size = sizeof(__cxa_dependent_exception);
150 void *ptr = do_malloc(actual_size);
151 if (NULL == ptr)
152 std::terminate();
153 std::memset(ptr, 0, actual_size);
Marshall Clowe0252022011-07-20 15:04:39 +0000154 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() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000161 do_free(dependent_exception);
162}
Marshall Clowe0252022011-07-20 15:04:39 +0000163
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000164
165// 2.4.3 Throwing the Exception Object
166/*
167After constructing the exception object with the throw argument value,
168the generated code calls the __cxa_throw runtime library routine. This
169routine never returns.
170
171The __cxa_throw routine will do the following:
172
173* Obtain the __cxa_exception header from the thrown exception object address,
174which can be computed as follows:
175 __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);
176* Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
177* Save the tinfo and dest arguments in the __cxa_exception header.
178* Set the exception_class field in the unwind header. This is a 64-bit value
179representing the ASCII string "XXXXC++\0", where "XXXX" is a
180vendor-dependent string. That is, for implementations conforming to this
181ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
182* Increment the uncaught_exception flag.
183* Call _Unwind_RaiseException in the system unwind library, Its argument is the
184pointer to the thrown exception, which __cxa_throw itself received as an argument.
185__Unwind_RaiseException begins the process of stack unwinding, described
186in Section 2.5. In special cases, such as an inability to find a
187handler, _Unwind_RaiseException may return. In that case, __cxa_throw
188will call terminate, assuming that there was no handler for the
189exception.
190*/
191LIBCXXABI_NORETURN void
192__cxa_throw(void * thrown_exception, std::type_info * tinfo, void (*dest)(void *)) {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000193 __cxa_eh_globals *globals = __cxa_get_globals();
194 __cxa_exception *exception = exception_from_thrown_object(thrown_exception);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000195
Howard Hinnantd9ad30c2011-12-06 19:02:03 +0000196 exception->unexpectedHandler = std::get_unexpected();
197 exception->terminateHandler = std::get_terminate();
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000198 exception->exceptionType = tinfo;
199 exception->exceptionDestructor = dest;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000200 setExceptionClass(&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000201 exception->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
202 globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
203
204 exception->unwindHeader.exception_cleanup = exception_cleanup_func;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000205 _Unwind_RaiseException(&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000206
207// If we get here, some kind of unwinding error has occurred.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000208 failed_throw(exception);
209}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000210
211
212// 2.5.3 Exception Handlers
213extern void * __cxa_get_exception_ptr(void * exceptionObject) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000214 return exception_from_exception_object(exceptionObject);
215}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000216
217
218/*
219This routine:
220* Increment's the exception's handler count.
221* Places the exception on the stack of currently-caught exceptions if it is not
222 already there, linking the exception to the previous top of the stack.
223* Decrements the uncaught_exception count.
224* Returns the adjusted pointer to the exception object.
225*/
226void * __cxa_begin_catch(void * exceptionObject) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000227 __cxa_eh_globals *globals = __cxa_get_globals();
228 __cxa_exception *exception = exception_from_exception_object(exceptionObject);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000229
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000230// Increment the handler count, removing the flag about being rethrown
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000231 exception->handlerCount = exception->handlerCount < 0 ?
232 -exception->handlerCount + 1 : exception->handlerCount + 1;
233
234// place the exception on the top of the stack if it's not there.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000235 if (exception != globals->caughtExceptions) {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000236 exception->nextException = globals->caughtExceptions;
237 globals->caughtExceptions = exception;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000238 }
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000239
240 globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000241 return thrown_object_from_exception(exception);
242}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000243
244
245/*
246Upon exit for any reason, a handler must call:
247 void __cxa_end_catch ();
248
249This routine:
250* Locates the most recently caught exception and decrements its handler count.
251* Removes the exception from the caught exception stack, if the handler count goes to zero.
252* Destroys the exception if the handler count goes to zero, and the exception was not re-thrown by throw.
253*/
254void __cxa_end_catch() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000255 __cxa_eh_globals *globals = __cxa_get_globals();
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000256 __cxa_exception *current_exception = globals->caughtExceptions;
257
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000258 if (NULL != current_exception) {
259 if (current_exception->handlerCount < 0) {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000260 // The exception has been rethrown
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000261 if (0 == incrementHandlerCount(current_exception)) {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000262 globals->caughtExceptions = current_exception->nextException;
263 // Howard says: If the exception has been rethrown, don't destroy.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000264 }
265 }
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000266 else {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000267 if (0 == decrementHandlerCount(current_exception)) {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000268 // Remove from the chain of uncaught exceptions
269 globals->caughtExceptions = current_exception->nextException;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000270 if (!isDependentException(&current_exception->unwindHeader))
271 _Unwind_DeleteException(&current_exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000272 else {
273 // TODO: deal with a dependent exception
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000274 }
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000275 }
276 }
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000277 }
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000278}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000279
280
281std::type_info * __cxa_current_exception_type() {
282// get the current exception
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000283 __cxa_eh_globals *globals = __cxa_get_globals();
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000284 __cxa_exception *current_exception = globals->caughtExceptions;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000285 if (NULL == current_exception)
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000286 return NULL; // No current exception
287// TODO add stuff for dependent exceptions.
288 return current_exception->exceptionType;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000289}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000290
291// 2.5.4 Rethrowing Exceptions
292/* This routine
293* marks the exception object on top of the caughtExceptions stack
294 (in an implementation-defined way) as being rethrown.
295* If the caughtExceptions stack is empty, it calls terminate()
296 (see [C++FDIS] [except.throw], 15.1.8).
297* It then returns to the handler that called it, which must call
298 __cxa_end_catch(), perform any necessary cleanup, and finally
299 call _Unwind_Resume() to continue unwinding.
300*/
301extern LIBCXXABI_NORETURN void __cxa_rethrow() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000302 __cxa_eh_globals *globals = __cxa_get_globals();
303 __cxa_exception *exception = exception_from_exception_object(globals->caughtExceptions );
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000304
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000305 if (NULL == exception) // there's no current exception!
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000306 std::terminate ();
307
308// Mark the exception as being rethrown
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000309 exception->handlerCount = -exception->handlerCount ; // TODO: Atomic
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000310
311#if __arm__
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000312 (void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000313#else
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000314 (void) _Unwind_Resume_or_Rethrow (&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000315#endif
316
317// If we get here, some kind of unwinding error has occurred.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000318 failed_throw(exception);
319}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000320
Marshall Clowe0252022011-07-20 15:04:39 +0000321} // extern "C"
322
323} // abi