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 
24 namespace __cxxabiv1 {
25 static const uint64_t kOurExceptionClass          = 0x434C4E47432B2B00; // CLNGC++\0
26 static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
27 
28 //  Utility routines
29 static inline __cxa_exception *exception_from_thrown_object(void *p) throw() {
30     return ((__cxa_exception *) p) - 1;
31 }
32 
33 static inline void * thrown_object_from_exception(void *p) throw() {
34     return (void *) (((__cxa_exception *) p) + 1 );
35 }
36 
37 static 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
44 static __cxa_exception *
45 exception_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 
50 static void setExceptionClass(_Unwind_Exception *unwind) throw() {
51     unwind->exception_class = kOurExceptionClass;
52 }
53 
54 static void setDependentExceptionClass(_Unwind_Exception *unwind) throw() {
55     unwind->exception_class = kOurDependentExceptionClass;
56 }
57 
58 //  Is it one of ours?
59 static bool isOurExceptionClass(_Unwind_Exception *unwind) throw() {
60     return(unwind->exception_class == kOurExceptionClass)||
61                (unwind->exception_class == kOurDependentExceptionClass);
62 }
63 
64 static bool isDependentException(_Unwind_Exception *unwind) throw() {
65     return (unwind->exception_class & 0xFF) == 0x01;
66 }
67 
68 //	TODO: This needs to be atomic
69 static int incrementHandlerCount(__cxa_exception *exception) throw() {
70 	return ++exception->handlerCount;
71 }
72 
73 //	TODO: This needs to be atomic
74 static int decrementHandlerCount(__cxa_exception *exception) throw() {
75 	return --exception->handlerCount;
76 }
77 
78 #include "fallback_malloc.cpp"
79 
80 //  Allocate some memory from _somewhere_
81 static 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.
90 static 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 */
99 static 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 
110 static 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 
122 extern "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.
129 void * __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.
140 void __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.
148 void * __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.
160 void __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 /*
167 After constructing the exception object with the throw argument value,
168 the generated code calls the __cxa_throw runtime library routine. This
169 routine never returns.
170 
171 The __cxa_throw routine will do the following:
172 
173 * Obtain the __cxa_exception header from the thrown exception object address,
174 which 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
179 representing the ASCII string "XXXXC++\0", where "XXXX" is a
180 vendor-dependent string. That is, for implementations conforming to this
181 ABI, 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
184 pointer to the thrown exception, which __cxa_throw itself received as an argument.
185 __Unwind_RaiseException begins the process of stack unwinding, described
186 in Section 2.5. In special cases, such as an inability to find a
187 handler, _Unwind_RaiseException may return. In that case, __cxa_throw
188 will call terminate, assuming that there was no handler for the
189 exception.
190 */
191 LIBCXXABI_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
213 extern void * __cxa_get_exception_ptr(void * exceptionObject) throw() {
214     return exception_from_exception_object(exceptionObject);
215 }
216 
217 
218 /*
219 This 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 */
226 void * __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 /*
246 Upon exit for any reason, a handler must call:
247     void __cxa_end_catch ();
248 
249 This 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 */
254 void __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 
281 std::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 */
301 extern 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