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(¤t_exception->unwindHeader)) 276 _Unwind_DeleteException(¤t_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