cxa_exception.cpp revision 8ca7603d21b85b03a57d703feb9e8e8bcd6dcfd0
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// This does not need to be atomic 69static inline int incrementHandlerCount(__cxa_exception *exception) throw() { 70 return ++exception->handlerCount; 71} 72 73// This does not need to be atomic 74static inline 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#if __arm__ 206 _Unwind_SjLj_RaiseException(&exception->unwindHeader); 207#else 208 _Unwind_RaiseException(&exception->unwindHeader); 209#endif 210// If we get here, some kind of unwinding error has occurred. 211 failed_throw(exception); 212} 213 214 215// 2.5.3 Exception Handlers 216extern void * __cxa_get_exception_ptr(void * exceptionObject) throw() { 217// TODO: This must return the *adjusted* pointer to the exception object. 218 return exception_from_exception_object(exceptionObject); 219} 220 221 222/* 223This routine: 224* Increment's the exception's handler count. 225* Places the exception on the stack of currently-caught exceptions if it is not 226 already there, linking the exception to the previous top of the stack. 227* Decrements the uncaught_exception count. 228* Returns the adjusted pointer to the exception object. 229*/ 230void * __cxa_begin_catch(void * exceptionObject) throw() { 231 __cxa_eh_globals *globals = __cxa_get_globals(); 232 __cxa_exception *exception = exception_from_exception_object(exceptionObject); 233 234// TODO: Handle foreign exceptions? How? 235 236// Increment the handler count, removing the flag about being rethrown 237 exception->handlerCount = exception->handlerCount < 0 ? 238 -exception->handlerCount + 1 : exception->handlerCount + 1; 239 240// place the exception on the top of the stack if it's not there. 241 if (exception != globals->caughtExceptions) { 242 exception->nextException = globals->caughtExceptions; 243 globals->caughtExceptions = exception; 244 } 245 246 globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local 247 return __cxa_get_exception_ptr(exceptionObject); 248} 249 250 251/* 252Upon exit for any reason, a handler must call: 253 void __cxa_end_catch (); 254 255This routine: 256* Locates the most recently caught exception and decrements its handler count. 257* Removes the exception from the caught exception stack, if the handler count goes to zero. 258* If the handler count goes down to zero, and the exception was not re-thrown 259 by throw, it locates the primary exception (which may be the same as the one 260 it's handling) and decrements its reference count. If that reference count 261 goes to zero, the function destroys the exception. In any case, if the current 262 exception is a dependent exception, it destroys that. 263*/ 264void __cxa_end_catch() { 265 __cxa_eh_globals *globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch 266 __cxa_exception *current_exception = globals->caughtExceptions; 267 268 if (NULL != current_exception) { 269 // TODO: Handle foreign exceptions? How? 270 if (current_exception->handlerCount < 0) { 271 // The exception has been rethrown 272 if (0 == incrementHandlerCount(current_exception)) { 273 // Remove from the chain of uncaught exceptions 274 globals->caughtExceptions = current_exception->nextException; 275 // but don't destroy 276 } 277 } 278 else { // The exception has not been rethrown 279 if (0 == decrementHandlerCount(current_exception)) { 280 // Remove from the chain of uncaught exceptions 281 globals->caughtExceptions = current_exception->nextException; 282 if (isDependentException(¤t_exception->unwindHeader)) { 283 // Reset current_exception to primaryException and deallocate the dependent exception 284 __cxa_dependent_exception* deh = 285 reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1; 286 current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1; 287 __cxa_free_dependent_exception(deh); 288 } 289 // Destroy the primary exception only if its referenceCount goes to 0 290 // (this decrement must be atomic) 291 __cxa_decrement_exception_refcount(thrown_object_from_exception(current_exception)); 292 } 293 } 294 } 295} 296 297 298std::type_info * __cxa_current_exception_type() { 299// FIXME: I don't think we need to drill down into __cxa_dependent_exception 300// because the exceptionType is replicated in the __cxa_dependent_exception 301// get the current exception 302 __cxa_eh_globals *globals = __cxa_get_globals_fast(); 303 if (NULL == globals) 304 return NULL; // If there have never been any exceptions, there are none now. 305 __cxa_exception *current_exception = globals->caughtExceptions; 306 if (NULL == current_exception) 307 return NULL; // No current exception 308 if (isDependentException(¤t_exception->unwindHeader)) { 309 __cxa_dependent_exception* deh = 310 reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1; 311 current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1; 312 } 313 return current_exception->exceptionType; 314} 315 316// 2.5.4 Rethrowing Exceptions 317/* This routine 318* marks the exception object on top of the caughtExceptions stack 319 (in an implementation-defined way) as being rethrown. 320* If the caughtExceptions stack is empty, it calls terminate() 321 (see [C++FDIS] [except.throw], 15.1.8). 322* It then calls _Unwind_Resume_or_Rethrow which should not return 323 (terminate if it does). 324*/ 325extern LIBCXXABI_NORETURN void __cxa_rethrow() { 326 __cxa_eh_globals *globals = __cxa_get_globals(); 327 __cxa_exception *exception = globals->caughtExceptions; 328 329 if (NULL == exception) // there's no current exception! 330 std::terminate (); 331 332// TODO: Handle foreign exceptions? How? 333 334// Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch) 335 exception->handlerCount = -exception->handlerCount; 336 globals->uncaughtExceptions += 1; 337// __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary 338 339#if __arm__ 340 (void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader); 341#else 342 (void) _Unwind_Resume_or_Rethrow (&exception->unwindHeader); 343#endif 344 345// If we get here, some kind of unwinding error has occurred. 346 failed_throw(exception); 347} 348 349/* 350 If p is not null, atomically increment the referenceCount field of the 351 __cxa_exception header associated with the thrown object referred to by p. 352*/ 353void 354__cxa_increment_exception_refcount(void* p) throw() 355{ 356 if (p != NULL ) 357 { 358 __cxa_exception* header = exception_from_thrown_object(p); 359 __sync_add_and_fetch(&header->referenceCount, 1); 360 } 361} 362 363/* 364 If p is not null, atomically decrement the referenceCount field of the 365 __cxa_exception header associated with the thrown object referred to by p. 366 If the referenceCount drops to zero, destroy and deallocate the exception. 367*/ 368void 369__cxa_decrement_exception_refcount(void* thrown_object) throw() 370{ 371 if (thrown_object != NULL ) 372 { 373 __cxa_exception* header = exception_from_thrown_object(thrown_object); 374 if (__sync_sub_and_fetch(&header->referenceCount, size_t(1)) == 0) 375 { 376 if (NULL != header->exceptionDestructor) 377 header->exceptionDestructor(thrown_object); 378 __cxa_free_exception(thrown_object); 379 } 380 } 381} 382 383/* 384 Returns a pointer to the thrown object (if any) at the top of the 385 caughtExceptions stack. Atommically increment the exception's referenceCount. 386 If there is no such thrown object, returns null. 387 388 We can use __cxa_get_globals_fast here to get the globals because if there have 389 been no exceptions thrown, ever, on this thread, we can return NULL without 390 the need to allocate the exception-handling globals. 391*/ 392void* 393__cxa_current_primary_exception() throw() 394{ 395// get the current exception 396 __cxa_eh_globals* globals = __cxa_get_globals_fast(); 397 if (NULL == globals) 398 return NULL; // If there are no globals, there is no exception 399 __cxa_exception* current_exception = globals->caughtExceptions; 400 if (NULL == current_exception) 401 return NULL; // No current exception 402 if (isDependentException(¤t_exception->unwindHeader)) { 403 __cxa_dependent_exception* deh = 404 reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1; 405 current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1; 406 } 407 void* thrown_object = thrown_object_from_exception(current_exception); 408 __cxa_increment_exception_refcount(thrown_object); 409 return thrown_object; 410} 411 412/* 413 If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler 414 stored in exc is called. Otherwise the referenceCount stored in the 415 primary exception is decremented, destroying the primary if necessary. 416 Finally the dependent exception is destroyed. 417*/ 418static 419void 420dependent_exception_cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc) 421{ 422 __cxa_dependent_exception* deh = 423 reinterpret_cast<__cxa_dependent_exception*>(exc + 1) - 1; 424 if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) 425 std::__terminate(deh->terminateHandler); 426 __cxa_decrement_exception_refcount(deh->primaryException); 427 __cxa_free_dependent_exception(deh); 428} 429 430/* 431 If thrown_object is not null, allocate, initialize and thow a dependent 432 exception. 433*/ 434void 435__cxa_rethrow_primary_exception(void* thrown_object) 436{ 437 if ( thrown_object != NULL ) 438 { 439 __cxa_exception* header = exception_from_thrown_object(thrown_object); 440 __cxa_dependent_exception* deh = 441 (__cxa_dependent_exception*)__cxa_allocate_dependent_exception(); 442 deh->primaryException = thrown_object; 443 __cxa_increment_exception_refcount(thrown_object); 444 deh->exceptionType = header->exceptionType; 445 deh->unexpectedHandler = std::get_unexpected(); 446 deh->terminateHandler = std::get_terminate(); 447 setDependentExceptionClass(&deh->unwindHeader); 448 __cxa_get_globals()->uncaughtExceptions += 1; 449 deh->unwindHeader.exception_cleanup = dependent_exception_cleanup; 450#if __arm__ 451 _Unwind_SjLj_RaiseException(&deh->unwindHeader); 452#else 453 _Unwind_RaiseException(&deh->unwindHeader); 454#endif 455 // Some sort of unwinding error. Note that terminate is a handler. 456 __cxa_begin_catch(&deh->unwindHeader); 457 } 458 // If we return client will call terminate() 459} 460 461} // extern "C" 462 463} // abi 464