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