blob: 9feea29e7a13a31984663cfeb219947574042084 [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 Clow3c54f1b2011-08-09 15:09:41 +000028static __cxa_exception *exception_from_thrown_object ( void *p ) throw () {
Marshall Clowe0252022011-07-20 15:04:39 +000029 return ((__cxa_exception *) p ) - 1;
30 }
31
Marshall Clow3c54f1b2011-08-09 15:09:41 +000032static void * thrown_object_from_exception ( void *p ) throw () {
Marshall Clowe0252022011-07-20 15:04:39 +000033 return (void *) (((__cxa_exception *) p ) + 1 );
34 }
35
Marshall Clow3c54f1b2011-08-09 15:09:41 +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);
38 }
39
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 *
44exception_from_exception_object ( void *ptr ) throw () {
45 _Unwind_Exception *p = reinterpret_cast<_Unwind_Exception *> ( ptr );
46 return exception_from_thrown_object ( p + 1 );
47 }
48
49static void setExceptionClass ( _Unwind_Exception *unwind ) throw () {
50 unwind->exception_class = kOurExceptionClass;
51 }
52
53static void setDependentExceptionClass ( _Unwind_Exception *unwind ) throw () {
54 unwind->exception_class = kOurDependentExceptionClass;
55 }
56
57// Is it one of ours?
58static bool isOurExceptionClass ( _Unwind_Exception *unwind ) throw () {
59 return ( unwind->exception_class == kOurExceptionClass ) ||
60 ( unwind->exception_class == kOurDependentExceptionClass );
61 }
62
63static bool isDependentException ( _Unwind_Exception *unwind ) throw () {
64 return ( unwind->exception_class & 0xFF ) == 0x01;
65 }
66
Marshall Clowe0252022011-07-20 15:04:39 +000067#include "fallback_malloc.cpp"
68
69// Allocate some memory from _somewhere_
70static void *do_malloc ( size_t size ) throw () {
71 void *ptr = std::malloc ( size );
72 if ( NULL == ptr ) // if malloc fails, fall back to emergency stash
73 ptr = fallback_malloc ( size );
74 return ptr;
75 }
76
77// Didn't know you could "return <expression>" from a void function, did you?
78// Well, you can, if the type of the expression is "void" also.
79static void do_free ( void *ptr ) throw () {
80 return is_fallback_ptr ( ptr ) ? fallback_free ( ptr ) : std::free ( ptr );
81 }
82
Marshall Clow3c54f1b2011-08-09 15:09:41 +000083/* Howard says:
84 If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
85 stored in exc is called. Otherwise the exceptionDestructor stored in
86 exc is called, and then the memory for the exception is deallocated.
87*/
88static void exception_cleanup_func ( _Unwind_Reason_Code reason, struct _Unwind_Exception* exc ) {
89 __cxa_exception *exception = exception_from_exception_object ( exc );
90 if ( _URC_FOREIGN_EXCEPTION_CAUGHT != reason )
91 exception->terminateHandler ();
92
93 void * thrown_object = thrown_object_from_exception ( exception );
94 if ( NULL != exception->exceptionDestructor )
95 exception->exceptionDestructor ( thrown_object );
96 __cxa_free_exception( thrown_object );
97 }
98
99static LIBCXXABI_NORETURN void failed_throw ( __cxa_exception *exception ) throw () {
100// Section 2.5.3 says:
101// * For purposes of this ABI, several things are considered exception handlers:
102// ** A terminate() call due to a throw.
103// and
104// * Upon entry, Following initialization of the catch parameter,
105// a handler must call:
106// * void *__cxa_begin_catch ( void *exceptionObject );
107 (void) __cxa_begin_catch ( &exception->unwindHeader );
108 std::terminate ();
109 }
Marshall Clowe0252022011-07-20 15:04:39 +0000110
111extern "C" {
112
113// Allocate a __cxa_exception object, and zero-fill it.
114// Reserve "thrown_size" bytes on the end for the user's exception
115// object. Zero-fill the object. If memory can't be allocated, call
116// std::terminate. Return a pointer to the memory to be used for the
117// user's exception object.
118void * __cxa_allocate_exception (size_t thrown_size) throw() {
119 size_t actual_size = object_size_from_exception_size ( thrown_size );
120 void *ptr = do_malloc ( actual_size );
121 if ( NULL == ptr )
122 std::terminate ();
123 std::memset ( ptr, 0, actual_size );
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000124 return thrown_object_from_exception ( ptr );
Marshall Clowe0252022011-07-20 15:04:39 +0000125 }
126
127
128// Free a __cxa_exception object allocated with __cxa_allocate_exception.
129void __cxa_free_exception (void * thrown_exception) throw() {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000130 do_free ( exception_from_thrown_object ( thrown_exception ));
Marshall Clowe0252022011-07-20 15:04:39 +0000131 }
132
133
134// This function shall allocate a __cxa_dependent_exception and
135// return a pointer to it. (Really to the object, not past its' end).
136// Otherwise, it will work like __cxa_allocate_exception.
137void * __cxa_allocate_dependent_exception () throw() {
138 size_t actual_size = sizeof ( __cxa_dependent_exception );
139 void *ptr = do_malloc ( actual_size );
140 if ( NULL == ptr )
141 std::terminate ();
142 std::memset ( ptr, 0, actual_size );
143// bookkeeping here ?
144 return ptr;
145 }
146
147
148// This function shall free a dependent_exception.
149// It does not affect the reference count of the primary exception.
150void __cxa_free_dependent_exception (void * dependent_exception) throw() {
151// I'm pretty sure there's no bookkeeping here
152 do_free ( dependent_exception );
153 }
154
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000155
156// 2.4.3 Throwing the Exception Object
157/*
158After constructing the exception object with the throw argument value,
159the generated code calls the __cxa_throw runtime library routine. This
160routine never returns.
161
162The __cxa_throw routine will do the following:
163
164* Obtain the __cxa_exception header from the thrown exception object address,
165which can be computed as follows:
166 __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);
167* Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
168* Save the tinfo and dest arguments in the __cxa_exception header.
169* Set the exception_class field in the unwind header. This is a 64-bit value
170representing the ASCII string "XXXXC++\0", where "XXXX" is a
171vendor-dependent string. That is, for implementations conforming to this
172ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
173* Increment the uncaught_exception flag.
174* Call _Unwind_RaiseException in the system unwind library, Its argument is the
175pointer to the thrown exception, which __cxa_throw itself received as an argument.
176__Unwind_RaiseException begins the process of stack unwinding, described
177in Section 2.5. In special cases, such as an inability to find a
178handler, _Unwind_RaiseException may return. In that case, __cxa_throw
179will call terminate, assuming that there was no handler for the
180exception.
181*/
182LIBCXXABI_NORETURN void
183__cxa_throw(void * thrown_exception, std::type_info * tinfo, void (*dest)(void *)) {
184 __cxa_eh_globals *globals = __cxa_get_globals ();
185 __cxa_exception *exception = exception_from_thrown_object ( thrown_exception );
186
187 exception->unexpectedHandler = __cxxabiapple::__cxa_unexpected_handler;
188 exception->terminateHandler = __cxxabiapple::__cxa_terminate_handler;
189 exception->exceptionType = tinfo;
190 exception->exceptionDestructor = dest;
191 setExceptionClass ( &exception->unwindHeader );
192 exception->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
193 globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
194
195 exception->unwindHeader.exception_cleanup = exception_cleanup_func;
196 _Unwind_RaiseException ( &exception->unwindHeader );
197
198// If we get here, some kind of unwinding error has occurred.
199 failed_throw ( exception );
200 }
201
202
203// 2.5.3 Exception Handlers
204extern void * __cxa_get_exception_ptr(void * exceptionObject) throw() {
205 return exception_from_exception_object ( exceptionObject );
206 }
207
208
209/*
210This routine:
211* Increment's the exception's handler count.
212* Places the exception on the stack of currently-caught exceptions if it is not
213 already there, linking the exception to the previous top of the stack.
214* Decrements the uncaught_exception count.
215* Returns the adjusted pointer to the exception object.
216*/
217void * __cxa_begin_catch(void * exceptionObject) throw() {
218 __cxa_eh_globals *globals = __cxa_get_globals ();
219 __cxa_exception *exception = exception_from_exception_object ( exceptionObject );
220
221// TODO add stuff for dependent exceptions.
222
223// TODO - should this be atomic?
224// Increment the handler count, removing the flag about being rethrown
225// assert ( exception->handlerCount != 0 );
226 exception->handlerCount = exception->handlerCount < 0 ?
227 -exception->handlerCount + 1 : exception->handlerCount + 1;
228
229// place the exception on the top of the stack if it's not there.
230 if ( exception != globals->caughtExceptions ) {
231 exception->nextException = globals->caughtExceptions;
232 globals->caughtExceptions = exception;
233 }
234
235 globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
236 return thrown_object_from_exception ( exception );
237 }
238
239
240/*
241Upon exit for any reason, a handler must call:
242 void __cxa_end_catch ();
243
244This routine:
245* Locates the most recently caught exception and decrements its handler count.
246* Removes the exception from the caught exception stack, if the handler count goes to zero.
247* Destroys the exception if the handler count goes to zero, and the exception was not re-thrown by throw.
248*/
249void __cxa_end_catch() {
250 __cxa_eh_globals *globals = __cxa_get_globals ();
251 __cxa_exception *current_exception = globals->caughtExceptions;
252
253 if ( NULL != current_exception ) {
254 if ( current_exception->handlerCount < 0 ) {
255 // The exception has been rethrown
256 current_exception->handlerCount += 1; // TODO: should be atomic?
257 if ( 0 == current_exception->handlerCount )
258 globals->caughtExceptions = current_exception->nextException;
259 // Howard says: If the exception has been rethrown, don't destroy.
260 }
261 else {
262 current_exception->handlerCount -= 1; // TODO: should be atomic?
263 if ( 0 == current_exception->handlerCount ) {
264 // Remove from the chain of uncaught exceptions
265 globals->caughtExceptions = current_exception->nextException;
266 if ( !isDependentException ( &current_exception->unwindHeader ))
267 _Unwind_DeleteException ( &current_exception->unwindHeader );
268 else {
269 // TODO: deal with a dependent exception
270 }
271 }
272 }
273 }
274 }
275
276
277std::type_info * __cxa_current_exception_type() {
278// get the current exception
279 __cxa_eh_globals *globals = __cxa_get_globals ();
280 __cxa_exception *current_exception = globals->caughtExceptions;
281 if ( NULL == current_exception )
282 return NULL; // No current exception
283// TODO add stuff for dependent exceptions.
284 return current_exception->exceptionType;
285 }
286
287// 2.5.4 Rethrowing Exceptions
288/* This routine
289* marks the exception object on top of the caughtExceptions stack
290 (in an implementation-defined way) as being rethrown.
291* If the caughtExceptions stack is empty, it calls terminate()
292 (see [C++FDIS] [except.throw], 15.1.8).
293* It then returns to the handler that called it, which must call
294 __cxa_end_catch(), perform any necessary cleanup, and finally
295 call _Unwind_Resume() to continue unwinding.
296*/
297extern LIBCXXABI_NORETURN void __cxa_rethrow() {
298 __cxa_eh_globals *globals = __cxa_get_globals ();
299 __cxa_exception *exception = exception_from_exception_object ( globals->caughtExceptions );
300
301 if ( NULL == exception ) // there's no current exception!
302 std::terminate ();
303
304// Mark the exception as being rethrown
305 exception->handlerCount = -exception->handlerCount ;
306
307#if __arm__
308 (void) _Unwind_SjLj_Resume_or_Rethrow ( &exception->unwindHeader );
309#else
310 (void) _Unwind_Resume_or_Rethrow ( &exception->unwindHeader );
311#endif
312
313// If we get here, some kind of unwinding error has occurred.
314 failed_throw ( exception );
315 }
316
Marshall Clowe0252022011-07-20 15:04:39 +0000317} // extern "C"
318
319} // abi