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 
23 namespace __cxxabiv1 {
24 static const uint64_t kOurExceptionClass          = 0x434C4E47432B2B00; // CLNGC++\0
25 static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
26 
27 //  Utility routines
28 static __cxa_exception *exception_from_thrown_object(void *p) throw() {
29     return ((__cxa_exception *) p) - 1;
30 }
31 
32 static void * thrown_object_from_exception(void *p) throw() {
33     return (void *) (((__cxa_exception *) p) + 1 );
34 }
35 
36 static size_t object_size_from_exception_size(size_t size) throw() {
37     return size + sizeof (__cxa_exception);
38 }
39 
40 //  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
43 static __cxa_exception *
44 exception_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 
49 static void setExceptionClass(_Unwind_Exception *unwind) throw() {
50     unwind->exception_class = kOurExceptionClass;
51 }
52 
53 static void setDependentExceptionClass(_Unwind_Exception *unwind) throw() {
54     unwind->exception_class = kOurDependentExceptionClass;
55 }
56 
57 //  Is it one of ours?
58 static bool isOurExceptionClass(_Unwind_Exception *unwind) throw() {
59     return(unwind->exception_class == kOurExceptionClass)||
60                (unwind->exception_class == kOurDependentExceptionClass);
61 }
62 
63 static bool isDependentException(_Unwind_Exception *unwind) throw() {
64     return (unwind->exception_class & 0xFF) == 0x01;
65 }
66 
67 //	TODO: This needs to be atomic
68 static int incrementHandlerCount(__cxa_exception *exception) throw() {
69 	return ++exception->handlerCount;
70 }
71 
72 //	TODO: This needs to be atomic
73 static int decrementHandlerCount(__cxa_exception *exception) throw() {
74 	return --exception->handlerCount;
75 }
76 
77 #include "fallback_malloc.cpp"
78 
79 //  Allocate some memory from _somewhere_
80 static 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);
84     return ptr;
85 }
86 
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.
89 static void do_free(void *ptr) throw() {
90     return is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr);
91 }
92 
93 /*  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 */
98 static 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)
101         exception->terminateHandler ();
102 
103     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 }
108 
109 static LIBCXXABI_NORETURN void failed_throw(__cxa_exception *exception) throw() {
110 //  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:
116 //      * void *__cxa_begin_catch(void *exceptionObject );
117     (void) __cxa_begin_catch(&exception->unwindHeader);
118     std::terminate();
119 }
120 
121 extern "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.
128 void * __cxa_allocate_exception (size_t thrown_size) throw() {
129     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 }
136 
137 
138 //  Free a __cxa_exception object allocated with __cxa_allocate_exception.
139 void __cxa_free_exception (void * thrown_exception) throw() {
140     do_free(exception_from_thrown_object(thrown_exception));
141 }
142 
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.
147 void * __cxa_allocate_dependent_exception () throw() {
148     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);
153 //  bookkeeping here ?
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.
160 void __cxa_free_dependent_exception (void * dependent_exception) throw() {
161 //  I'm pretty sure there's no bookkeeping here
162     do_free(dependent_exception);
163 }
164 
165 
166 // 2.4.3 Throwing the Exception Object
167 /*
168 After constructing the exception object with the throw argument value,
169 the generated code calls the __cxa_throw runtime library routine. This
170 routine never returns.
171 
172 The __cxa_throw routine will do the following:
173 
174 * Obtain the __cxa_exception header from the thrown exception object address,
175 which 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
180 representing the ASCII string "XXXXC++\0", where "XXXX" is a
181 vendor-dependent string. That is, for implementations conforming to this
182 ABI, 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
185 pointer to the thrown exception, which __cxa_throw itself received as an argument.
186 __Unwind_RaiseException begins the process of stack unwinding, described
187 in Section 2.5. In special cases, such as an inability to find a
188 handler, _Unwind_RaiseException may return. In that case, __cxa_throw
189 will call terminate, assuming that there was no handler for the
190 exception.
191 */
192 LIBCXXABI_NORETURN void
193 __cxa_throw(void * thrown_exception, std::type_info * tinfo, void (*dest)(void *)) {
194     __cxa_eh_globals *globals = __cxa_get_globals();
195     __cxa_exception *exception = exception_from_thrown_object(thrown_exception);
196 
197     exception->unexpectedHandler = __cxxabiapple::__cxa_unexpected_handler;
198     exception->terminateHandler  = __cxxabiapple::__cxa_terminate_handler;
199     exception->exceptionType = tinfo;
200     exception->exceptionDestructor = dest;
201     setExceptionClass(&exception->unwindHeader);
202     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;
206     _Unwind_RaiseException(&exception->unwindHeader);
207 
208 //  If we get here, some kind of unwinding error has occurred.
209     failed_throw(exception);
210 }
211 
212 
213 // 2.5.3 Exception Handlers
214 extern void * __cxa_get_exception_ptr(void * exceptionObject) throw() {
215     return exception_from_exception_object(exceptionObject);
216 }
217 
218 
219 /*
220 This 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 */
227 void * __cxa_begin_catch(void * exceptionObject) throw() {
228     __cxa_eh_globals *globals = __cxa_get_globals();
229     __cxa_exception *exception = exception_from_exception_object(exceptionObject);
230 
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
235 //  assert(exception->handlerCount != 0);
236     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.
240     if (exception != globals->caughtExceptions) {
241         exception->nextException = globals->caughtExceptions;
242         globals->caughtExceptions = exception;
243     }
244 
245     globals->uncaughtExceptions -= 1;   // Not atomically, since globals are thread-local
246     return thrown_object_from_exception(exception);
247 }
248 
249 
250 /*
251 Upon exit for any reason, a handler must call:
252     void __cxa_end_catch ();
253 
254 This 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 */
259 void __cxa_end_catch() {
260     __cxa_eh_globals *globals = __cxa_get_globals();
261     __cxa_exception *current_exception = globals->caughtExceptions;
262 
263     if (NULL != current_exception) {
264         if (current_exception->handlerCount < 0) {
265         //  The exception has been rethrown
266             if (0 == incrementHandlerCount(current_exception)) {
267                 globals->caughtExceptions = current_exception->nextException;
268             //	Howard says: If the exception has been rethrown, don't destroy.
269         	}
270         }
271         else {
272             if (0 == decrementHandlerCount(current_exception)) {
273             //  Remove from the chain of uncaught exceptions
274                 globals->caughtExceptions = current_exception->nextException;
275                 if (!isDependentException(&current_exception->unwindHeader))
276                     _Unwind_DeleteException(&current_exception->unwindHeader);
277                 else {
278                 //  TODO: deal with a dependent exception
279                 }
280             }
281         }
282     }
283 }
284 
285 
286 std::type_info * __cxa_current_exception_type() {
287 //  get the current exception
288     __cxa_eh_globals *globals = __cxa_get_globals();
289     __cxa_exception *current_exception = globals->caughtExceptions;
290     if (NULL == current_exception)
291         return NULL;        //  No current exception
292 //  TODO add stuff for dependent exceptions.
293     return current_exception->exceptionType;
294 }
295 
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 */
306 extern LIBCXXABI_NORETURN void __cxa_rethrow() {
307     __cxa_eh_globals *globals = __cxa_get_globals();
308     __cxa_exception *exception = exception_from_exception_object(globals->caughtExceptions );
309 
310     if (NULL == exception)   // there's no current exception!
311         std::terminate ();
312 
313 //  Mark the exception as being rethrown
314     exception->handlerCount = -exception->handlerCount ;	// TODO: Atomic
315 
316 #if __arm__
317     (void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader);
318 #else
319     (void) _Unwind_Resume_or_Rethrow     (&exception->unwindHeader);
320 #endif
321 
322 //  If we get here, some kind of unwinding error has occurred.
323     failed_throw(exception);
324 }
325 
326 }  // extern "C"
327 
328 }  // abi
329