cxa_exception.cpp revision e8fcf83b576ff70ba5886fbd73434218a68ac414
1//===------------------------- 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"
22#include "cxa_handlers.hpp"
23
24namespace __cxxabiv1 {
25static const uint64_t kOurExceptionClass          = 0x434C4E47432B2B00; // CLNGC++\0
26static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
27
28//  Utility routines
29static inline __cxa_exception *exception_from_thrown_object(void *p) throw() {
30    return ((__cxa_exception *) p) - 1;
31}
32
33static inline void * thrown_object_from_exception(void *p) throw() {
34    return (void *) (((__cxa_exception *) p) + 1 );
35}
36
37static inline size_t object_size_from_exception_size(size_t size) throw() {
38    return size + sizeof (__cxa_exception);
39}
40
41//  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 *
45exception_from_exception_object(void *ptr) throw() {
46    _Unwind_Exception *p = reinterpret_cast<_Unwind_Exception *>(ptr);
47    return exception_from_thrown_object(p + 1 );
48}
49
50static void setExceptionClass(_Unwind_Exception *unwind) throw() {
51    unwind->exception_class = kOurExceptionClass;
52}
53
54static void setDependentExceptionClass(_Unwind_Exception *unwind) throw() {
55    unwind->exception_class = kOurDependentExceptionClass;
56}
57
58//  Is it one of ours?
59static bool isOurExceptionClass(_Unwind_Exception *unwind) throw() {
60    return(unwind->exception_class == kOurExceptionClass)||
61               (unwind->exception_class == kOurDependentExceptionClass);
62}
63
64static 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}
77
78#include "fallback_malloc.cpp"
79
80//  Allocate some memory from _somewhere_
81static 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);
85    return ptr;
86}
87
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.
90static void do_free(void *ptr) throw() {
91    return is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr);
92}
93
94/*
95    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*/
99static 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)
102        std::__terminate(exception->terminateHandler);
103
104    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}
109
110static LIBCXXABI_NORETURN void failed_throw(__cxa_exception *exception) throw() {
111//  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:
117//      * void *__cxa_begin_catch(void *exceptionObject );
118    (void) __cxa_begin_catch(&exception->unwindHeader);
119    std::__terminate(exception->terminateHandler);
120}
121
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() {
130    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}
137
138
139//  Free a __cxa_exception object allocated with __cxa_allocate_exception.
140void __cxa_free_exception (void * thrown_exception) throw() {
141    do_free(exception_from_thrown_object(thrown_exception));
142}
143
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() {
149    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);
154    return ptr;
155}
156
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    do_free(dependent_exception);
162}
163
164
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 *)) {
193    __cxa_eh_globals *globals = __cxa_get_globals();
194    __cxa_exception *exception = exception_from_thrown_object(thrown_exception);
195
196    exception->unexpectedHandler = std::get_unexpected();
197    exception->terminateHandler  = std::get_terminate();
198    exception->exceptionType = tinfo;
199    exception->exceptionDestructor = dest;
200    setExceptionClass(&exception->unwindHeader);
201    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;
205    _Unwind_RaiseException(&exception->unwindHeader);
206
207//  If we get here, some kind of unwinding error has occurred.
208    failed_throw(exception);
209}
210
211
212// 2.5.3 Exception Handlers
213extern void * __cxa_get_exception_ptr(void * exceptionObject) throw() {
214    return exception_from_exception_object(exceptionObject);
215}
216
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() {
227    __cxa_eh_globals *globals = __cxa_get_globals();
228    __cxa_exception *exception = exception_from_exception_object(exceptionObject);
229
230//  Increment the handler count, removing the flag about being rethrown
231    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.
235    if (exception != globals->caughtExceptions) {
236        exception->nextException = globals->caughtExceptions;
237        globals->caughtExceptions = exception;
238    }
239
240    globals->uncaughtExceptions -= 1;   // Not atomically, since globals are thread-local
241    return thrown_object_from_exception(exception);
242}
243
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() {
255    __cxa_eh_globals *globals = __cxa_get_globals();
256    __cxa_exception *current_exception = globals->caughtExceptions;
257
258    if (NULL != current_exception) {
259        if (current_exception->handlerCount < 0) {
260        //  The exception has been rethrown
261            if (0 == incrementHandlerCount(current_exception)) {
262                globals->caughtExceptions = current_exception->nextException;
263            //	Howard says: If the exception has been rethrown, don't destroy.
264        	}
265        }
266        else {
267            if (0 == decrementHandlerCount(current_exception)) {
268            //  Remove from the chain of uncaught exceptions
269                globals->caughtExceptions = current_exception->nextException;
270                if (!isDependentException(&current_exception->unwindHeader))
271                    _Unwind_DeleteException(&current_exception->unwindHeader);
272                else {
273                //  TODO: deal with a dependent exception
274                }
275            }
276        }
277    }
278}
279
280
281std::type_info * __cxa_current_exception_type() {
282//  get the current exception
283    __cxa_eh_globals *globals = __cxa_get_globals();
284    __cxa_exception *current_exception = globals->caughtExceptions;
285    if (NULL == current_exception)
286        return NULL;        //  No current exception
287//  TODO add stuff for dependent exceptions.
288    return current_exception->exceptionType;
289}
290
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() {
302    __cxa_eh_globals *globals = __cxa_get_globals();
303    __cxa_exception *exception = exception_from_exception_object(globals->caughtExceptions );
304
305    if (NULL == exception)   // there's no current exception!
306        std::terminate ();
307
308//  Mark the exception as being rethrown
309    exception->handlerCount = -exception->handlerCount ;	// TODO: Atomic
310
311#if __arm__
312    (void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader);
313#else
314    (void) _Unwind_Resume_or_Rethrow     (&exception->unwindHeader);
315#endif
316
317//  If we get here, some kind of unwinding error has occurred.
318    failed_throw(exception);
319}
320
321}  // extern "C"
322
323}  // abi
324