1232950Stheraven/* 2232950Stheraven * Copyright 2010-2011 PathScale, Inc. All rights reserved. 3232950Stheraven * 4232950Stheraven * Redistribution and use in source and binary forms, with or without 5232950Stheraven * modification, are permitted provided that the following conditions are met: 6232950Stheraven * 7232950Stheraven * 1. Redistributions of source code must retain the above copyright notice, 8232950Stheraven * this list of conditions and the following disclaimer. 9232950Stheraven * 10232950Stheraven * 2. Redistributions in binary form must reproduce the above copyright notice, 11232950Stheraven * this list of conditions and the following disclaimer in the documentation 12232950Stheraven * and/or other materials provided with the distribution. 13232950Stheraven * 14232950Stheraven * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 15232950Stheraven * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16232950Stheraven * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17232950Stheraven * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 18232950Stheraven * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19232950Stheraven * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20232950Stheraven * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21232950Stheraven * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22232950Stheraven * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23232950Stheraven * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24232950Stheraven * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25232950Stheraven */ 26232950Stheraven 27227825Stheraven#include <stdlib.h> 28227825Stheraven#include <dlfcn.h> 29227825Stheraven#include <stdio.h> 30227825Stheraven#include <string.h> 31227972Stheraven#include <stdint.h> 32227825Stheraven#include <pthread.h> 33227825Stheraven#include "typeinfo.h" 34227825Stheraven#include "dwarf_eh.h" 35245304Stheraven#include "atomic.h" 36227825Stheraven#include "cxxabi.h" 37227825Stheraven 38228004Stheraven#pragma weak pthread_key_create 39228004Stheraven#pragma weak pthread_setspecific 40228004Stheraven#pragma weak pthread_getspecific 41228004Stheraven#pragma weak pthread_once 42253159Stheraven#ifdef LIBCXXRT_WEAK_LOCKS 43253159Stheraven#pragma weak pthread_mutex_lock 44253159Stheraven#define pthread_mutex_lock(mtx) do {\ 45253159Stheraven if (pthread_mutex_lock) pthread_mutex_lock(mtx);\ 46253159Stheraven } while(0) 47253159Stheraven#pragma weak pthread_mutex_unlock 48253159Stheraven#define pthread_mutex_unlock(mtx) do {\ 49253159Stheraven if (pthread_mutex_unlock) pthread_mutex_unlock(mtx);\ 50253159Stheraven } while(0) 51253159Stheraven#pragma weak pthread_cond_signal 52253159Stheraven#define pthread_cond_signal(cv) do {\ 53253159Stheraven if (pthread_cond_signal) pthread_cond_signal(cv);\ 54253159Stheraven } while(0) 55253159Stheraven#pragma weak pthread_cond_wait 56253159Stheraven#define pthread_cond_wait(cv, mtx) do {\ 57253159Stheraven if (pthread_cond_wait) pthread_cond_wait(cv, mtx);\ 58253159Stheraven } while(0) 59253159Stheraven#endif 60228004Stheraven 61227825Stheravenusing namespace ABI_NAMESPACE; 62227825Stheraven 63227972Stheraven/** 64227972Stheraven * Saves the result of the landing pad that we have found. For ARM, this is 65227972Stheraven * stored in the generic unwind structure, while on other platforms it is 66227972Stheraven * stored in the C++ exception. 67227972Stheraven */ 68227972Stheravenstatic void saveLandingPad(struct _Unwind_Context *context, 69227972Stheraven struct _Unwind_Exception *ucb, 70227972Stheraven struct __cxa_exception *ex, 71227972Stheraven int selector, 72227972Stheraven dw_eh_ptr_t landingPad) 73227972Stheraven{ 74227972Stheraven#ifdef __arm__ 75227972Stheraven // On ARM, we store the saved exception in the generic part of the structure 76227972Stheraven ucb->barrier_cache.sp = _Unwind_GetGR(context, 13); 77227972Stheraven ucb->barrier_cache.bitpattern[1] = (uint32_t)selector; 78227972Stheraven ucb->barrier_cache.bitpattern[3] = (uint32_t)landingPad; 79227972Stheraven#endif 80227972Stheraven // Cache the results for the phase 2 unwind, if we found a handler 81227972Stheraven // and this is not a foreign exception. 82227972Stheraven if (ex) 83227972Stheraven { 84227972Stheraven ex->handlerSwitchValue = selector; 85227972Stheraven ex->catchTemp = landingPad; 86227972Stheraven } 87227972Stheraven} 88227972Stheraven 89227972Stheraven/** 90227972Stheraven * Loads the saved landing pad. Returns 1 on success, 0 on failure. 91227972Stheraven */ 92227972Stheravenstatic int loadLandingPad(struct _Unwind_Context *context, 93227972Stheraven struct _Unwind_Exception *ucb, 94227972Stheraven struct __cxa_exception *ex, 95227972Stheraven unsigned long *selector, 96227972Stheraven dw_eh_ptr_t *landingPad) 97227972Stheraven{ 98227972Stheraven#ifdef __arm__ 99227972Stheraven *selector = ucb->barrier_cache.bitpattern[1]; 100227972Stheraven *landingPad = (dw_eh_ptr_t)ucb->barrier_cache.bitpattern[3]; 101227972Stheraven return 1; 102227972Stheraven#else 103227972Stheraven if (ex) 104227972Stheraven { 105227972Stheraven *selector = ex->handlerSwitchValue; 106227972Stheraven *landingPad = (dw_eh_ptr_t)ex->catchTemp; 107227972Stheraven return 0; 108227972Stheraven } 109227972Stheraven return 0; 110227972Stheraven#endif 111227972Stheraven} 112227972Stheraven 113227972Stheravenstatic inline _Unwind_Reason_Code continueUnwinding(struct _Unwind_Exception *ex, 114227972Stheraven struct _Unwind_Context *context) 115227972Stheraven{ 116227972Stheraven#ifdef __arm__ 117227972Stheraven if (__gnu_unwind_frame(ex, context) != _URC_OK) { return _URC_FAILURE; } 118227972Stheraven#endif 119227972Stheraven return _URC_CONTINUE_UNWIND; 120227972Stheraven} 121227972Stheraven 122227972Stheraven 123227825Stheravenextern "C" void __cxa_free_exception(void *thrown_exception); 124227825Stheravenextern "C" void __cxa_free_dependent_exception(void *thrown_exception); 125227825Stheravenextern "C" void* __dynamic_cast(const void *sub, 126227825Stheraven const __class_type_info *src, 127227825Stheraven const __class_type_info *dst, 128227825Stheraven ptrdiff_t src2dst_offset); 129227825Stheraven 130227825Stheraven/** 131227825Stheraven * The type of a handler that has been found. 132227825Stheraven */ 133227825Stheraventypedef enum 134227825Stheraven{ 135227825Stheraven /** No handler. */ 136227825Stheraven handler_none, 137227825Stheraven /** 138227825Stheraven * A cleanup - the exception will propagate through this frame, but code 139227825Stheraven * must be run when this happens. 140227825Stheraven */ 141227825Stheraven handler_cleanup, 142227825Stheraven /** 143227825Stheraven * A catch statement. The exception will not propagate past this frame 144227825Stheraven * (without an explicit rethrow). 145227825Stheraven */ 146227825Stheraven handler_catch 147227825Stheraven} handler_type; 148227825Stheraven 149227825Stheraven/** 150227825Stheraven * Per-thread info required by the runtime. We store a single structure 151227825Stheraven * pointer in thread-local storage, because this tends to be a scarce resource 152227825Stheraven * and it's impolite to steal all of it and not leave any for the rest of the 153227825Stheraven * program. 154227825Stheraven * 155227825Stheraven * Instances of this structure are allocated lazily - at most one per thread - 156227825Stheraven * and are destroyed on thread termination. 157227825Stheraven */ 158227825Stheravenstruct __cxa_thread_info 159227825Stheraven{ 160227825Stheraven /** The termination handler for this thread. */ 161227825Stheraven terminate_handler terminateHandler; 162227825Stheraven /** The unexpected exception handler for this thread. */ 163227825Stheraven unexpected_handler unexpectedHandler; 164227825Stheraven /** 165227825Stheraven * The number of emergency buffers held by this thread. This is 0 in 166227825Stheraven * normal operation - the emergency buffers are only used when malloc() 167227825Stheraven * fails to return memory for allocating an exception. Threads are not 168227825Stheraven * permitted to hold more than 4 emergency buffers (as per recommendation 169227825Stheraven * in ABI spec [3.3.1]). 170227825Stheraven */ 171227825Stheraven int emergencyBuffersHeld; 172227825Stheraven /** 173227972Stheraven * The exception currently running in a cleanup. 174227972Stheraven */ 175227972Stheraven _Unwind_Exception *currentCleanup; 176227972Stheraven /** 177245304Stheraven * Our state with respect to foreign exceptions. Usually none, set to 178245304Stheraven * caught if we have just caught an exception and rethrown if we are 179245304Stheraven * rethrowing it. 180245304Stheraven */ 181245304Stheraven enum 182245304Stheraven { 183245304Stheraven none, 184245304Stheraven caught, 185245304Stheraven rethrown 186245304Stheraven } foreign_exception_state; 187245304Stheraven /** 188227825Stheraven * The public part of this structure, accessible from outside of this 189227825Stheraven * module. 190227825Stheraven */ 191227825Stheraven __cxa_eh_globals globals; 192227825Stheraven}; 193227825Stheraven/** 194227825Stheraven * Dependent exception. This 195227825Stheraven */ 196227825Stheravenstruct __cxa_dependent_exception 197227825Stheraven{ 198227825Stheraven#if __LP64__ 199227825Stheraven void *primaryException; 200227825Stheraven#endif 201227825Stheraven std::type_info *exceptionType; 202227825Stheraven void (*exceptionDestructor) (void *); 203227825Stheraven unexpected_handler unexpectedHandler; 204227825Stheraven terminate_handler terminateHandler; 205227825Stheraven __cxa_exception *nextException; 206227825Stheraven int handlerCount; 207227972Stheraven#ifdef __arm__ 208227972Stheraven _Unwind_Exception *nextCleanup; 209227972Stheraven int cleanupCount; 210227972Stheraven#endif 211227825Stheraven int handlerSwitchValue; 212227825Stheraven const char *actionRecord; 213227825Stheraven const char *languageSpecificData; 214227825Stheraven void *catchTemp; 215227825Stheraven void *adjustedPtr; 216227825Stheraven#if !__LP64__ 217227825Stheraven void *primaryException; 218227825Stheraven#endif 219227825Stheraven _Unwind_Exception unwindHeader; 220227825Stheraven}; 221227825Stheraven 222227825Stheraven 223227825Stheravennamespace std 224227825Stheraven{ 225227825Stheraven void unexpected(); 226227825Stheraven class exception 227227825Stheraven { 228227825Stheraven public: 229227825Stheraven virtual ~exception() throw(); 230227825Stheraven virtual const char* what() const throw(); 231227825Stheraven }; 232227825Stheraven 233227825Stheraven} 234227825Stheraven 235227825Stheraven/** 236227825Stheraven * Class of exceptions to distinguish between this and other exception types. 237227825Stheraven * 238227825Stheraven * The first four characters are the vendor ID. Currently, we use GNUC, 239227825Stheraven * because we aim for ABI-compatibility with the GNU implementation, and 240227825Stheraven * various checks may test for equality of the class, which is incorrect. 241227825Stheraven */ 242227825Stheravenstatic const uint64_t exception_class = 243227825Stheraven EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\0'); 244227825Stheraven/** 245227825Stheraven * Class used for dependent exceptions. 246227825Stheraven */ 247227825Stheravenstatic const uint64_t dependent_exception_class = 248227825Stheraven EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\x01'); 249227825Stheraven/** 250227825Stheraven * The low four bytes of the exception class, indicating that we conform to the 251227825Stheraven * Itanium C++ ABI. This is currently unused, but should be used in the future 252227825Stheraven * if we change our exception class, to allow this library and libsupc++ to be 253227825Stheraven * linked to the same executable and both to interoperate. 254227825Stheraven */ 255227825Stheravenstatic const uint32_t abi_exception_class = 256227825Stheraven GENERIC_EXCEPTION_CLASS('C', '+', '+', '\0'); 257227825Stheraven 258227825Stheravenstatic bool isCXXException(uint64_t cls) 259227825Stheraven{ 260227825Stheraven return (cls == exception_class) || (cls == dependent_exception_class); 261227825Stheraven} 262227825Stheraven 263227825Stheravenstatic bool isDependentException(uint64_t cls) 264227825Stheraven{ 265227825Stheraven return cls == dependent_exception_class; 266227825Stheraven} 267227825Stheraven 268227825Stheravenstatic __cxa_exception *exceptionFromPointer(void *ex) 269227825Stheraven{ 270227825Stheraven return (__cxa_exception*)((char*)ex - 271227825Stheraven offsetof(struct __cxa_exception, unwindHeader)); 272227825Stheraven} 273227825Stheravenstatic __cxa_exception *realExceptionFromException(__cxa_exception *ex) 274227825Stheraven{ 275227825Stheraven if (!isDependentException(ex->unwindHeader.exception_class)) { return ex; } 276227825Stheraven return ((__cxa_exception*)(((__cxa_dependent_exception*)ex)->primaryException))-1; 277227825Stheraven} 278227825Stheraven 279227825Stheraven 280227825Stheravennamespace std 281227825Stheraven{ 282227825Stheraven // Forward declaration of standard library terminate() function used to 283227825Stheraven // abort execution. 284227825Stheraven void terminate(void); 285227825Stheraven} 286227825Stheraven 287227825Stheravenusing namespace ABI_NAMESPACE; 288227825Stheraven 289227825Stheraven 290227825Stheraven 291227825Stheraven/** The global termination handler. */ 292227825Stheravenstatic terminate_handler terminateHandler = abort; 293227825Stheraven/** The global unexpected exception handler. */ 294227825Stheravenstatic unexpected_handler unexpectedHandler = std::terminate; 295227825Stheraven 296227825Stheraven/** Key used for thread-local data. */ 297227825Stheravenstatic pthread_key_t eh_key; 298227825Stheraven 299227825Stheraven 300227825Stheraven/** 301227825Stheraven * Cleanup function, allowing foreign exception handlers to correctly destroy 302227825Stheraven * this exception if they catch it. 303227825Stheraven */ 304227825Stheravenstatic void exception_cleanup(_Unwind_Reason_Code reason, 305227825Stheraven struct _Unwind_Exception *ex) 306227825Stheraven{ 307227825Stheraven __cxa_free_exception((void*)ex); 308227825Stheraven} 309227825Stheravenstatic void dependent_exception_cleanup(_Unwind_Reason_Code reason, 310227825Stheraven struct _Unwind_Exception *ex) 311227825Stheraven{ 312227825Stheraven 313227825Stheraven __cxa_free_dependent_exception((void*)ex); 314227825Stheraven} 315227825Stheraven 316227825Stheraven/** 317227825Stheraven * Recursively walk a list of exceptions and delete them all in post-order. 318227825Stheraven */ 319227825Stheravenstatic void free_exception_list(__cxa_exception *ex) 320227825Stheraven{ 321227825Stheraven if (0 != ex->nextException) 322227825Stheraven { 323227825Stheraven free_exception_list(ex->nextException); 324227825Stheraven } 325227825Stheraven // __cxa_free_exception() expects to be passed the thrown object, which 326227825Stheraven // immediately follows the exception, not the exception itself 327227825Stheraven __cxa_free_exception(ex+1); 328227825Stheraven} 329227825Stheraven 330227825Stheraven/** 331227825Stheraven * Cleanup function called when a thread exists to make certain that all of the 332227825Stheraven * per-thread data is deleted. 333227825Stheraven */ 334227825Stheravenstatic void thread_cleanup(void* thread_info) 335227825Stheraven{ 336227825Stheraven __cxa_thread_info *info = (__cxa_thread_info*)thread_info; 337227825Stheraven if (info->globals.caughtExceptions) 338227825Stheraven { 339245304Stheraven // If this is a foreign exception, ask it to clean itself up. 340245304Stheraven if (info->foreign_exception_state != __cxa_thread_info::none) 341245304Stheraven { 342245304Stheraven _Unwind_Exception *e = (_Unwind_Exception*)info->globals.caughtExceptions; 343245304Stheraven e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e); 344245304Stheraven } 345245304Stheraven else 346245304Stheraven { 347245304Stheraven free_exception_list(info->globals.caughtExceptions); 348245304Stheraven } 349227825Stheraven } 350227825Stheraven free(thread_info); 351227825Stheraven} 352227825Stheraven 353227825Stheraven 354227825Stheraven/** 355227825Stheraven * Once control used to protect the key creation. 356227825Stheraven */ 357227825Stheravenstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 358227825Stheraven 359227825Stheraven/** 360228004Stheraven * We may not be linked against a full pthread implementation. If we're not, 361228004Stheraven * then we need to fake the thread-local storage by storing 'thread-local' 362228004Stheraven * things in a global. 363228004Stheraven */ 364228004Stheravenstatic bool fakeTLS; 365228004Stheraven/** 366228004Stheraven * Thread-local storage for a single-threaded program. 367228004Stheraven */ 368228004Stheravenstatic __cxa_thread_info singleThreadInfo; 369228004Stheraven/** 370227825Stheraven * Initialise eh_key. 371227825Stheraven */ 372227825Stheravenstatic void init_key(void) 373227825Stheraven{ 374228004Stheraven if ((0 == pthread_key_create) || 375228004Stheraven (0 == pthread_setspecific) || 376228004Stheraven (0 == pthread_getspecific)) 377228004Stheraven { 378228004Stheraven fakeTLS = true; 379228004Stheraven return; 380228004Stheraven } 381227825Stheraven pthread_key_create(&eh_key, thread_cleanup); 382228004Stheraven pthread_setspecific(eh_key, (void*)0x42); 383228004Stheraven fakeTLS = (pthread_getspecific(eh_key) != (void*)0x42); 384228004Stheraven pthread_setspecific(eh_key, 0); 385227825Stheraven} 386227825Stheraven 387227825Stheraven/** 388227825Stheraven * Returns the thread info structure, creating it if it is not already created. 389227825Stheraven */ 390227825Stheravenstatic __cxa_thread_info *thread_info() 391227825Stheraven{ 392228004Stheraven if ((0 == pthread_once) || pthread_once(&once_control, init_key)) 393228004Stheraven { 394228004Stheraven fakeTLS = true; 395228004Stheraven } 396228004Stheraven if (fakeTLS) { return &singleThreadInfo; } 397227825Stheraven __cxa_thread_info *info = (__cxa_thread_info*)pthread_getspecific(eh_key); 398227825Stheraven if (0 == info) 399227825Stheraven { 400227825Stheraven info = (__cxa_thread_info*)calloc(1, sizeof(__cxa_thread_info)); 401227825Stheraven pthread_setspecific(eh_key, info); 402227825Stheraven } 403227825Stheraven return info; 404227825Stheraven} 405227825Stheraven/** 406227825Stheraven * Fast version of thread_info(). May fail if thread_info() is not called on 407227825Stheraven * this thread at least once already. 408227825Stheraven */ 409227825Stheravenstatic __cxa_thread_info *thread_info_fast() 410227825Stheraven{ 411228004Stheraven if (fakeTLS) { return &singleThreadInfo; } 412227825Stheraven return (__cxa_thread_info*)pthread_getspecific(eh_key); 413227825Stheraven} 414227825Stheraven/** 415227825Stheraven * ABI function returning the __cxa_eh_globals structure. 416227825Stheraven */ 417227825Stheravenextern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals(void) 418227825Stheraven{ 419227825Stheraven return &(thread_info()->globals); 420227825Stheraven} 421227825Stheraven/** 422227825Stheraven * Version of __cxa_get_globals() assuming that __cxa_get_globals() has already 423227825Stheraven * been called at least once by this thread. 424227825Stheraven */ 425227825Stheravenextern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals_fast(void) 426227825Stheraven{ 427227825Stheraven return &(thread_info_fast()->globals); 428227825Stheraven} 429227825Stheraven 430227825Stheraven/** 431227825Stheraven * An emergency allocation reserved for when malloc fails. This is treated as 432227825Stheraven * 16 buffers of 1KB each. 433227825Stheraven */ 434227825Stheravenstatic char emergency_buffer[16384]; 435227825Stheraven/** 436227825Stheraven * Flag indicating whether each buffer is allocated. 437227825Stheraven */ 438227825Stheravenstatic bool buffer_allocated[16]; 439227825Stheraven/** 440227825Stheraven * Lock used to protect emergency allocation. 441227825Stheraven */ 442227825Stheravenstatic pthread_mutex_t emergency_malloc_lock = PTHREAD_MUTEX_INITIALIZER; 443227825Stheraven/** 444227825Stheraven * Condition variable used to wait when two threads are both trying to use the 445227825Stheraven * emergency malloc() buffer at once. 446227825Stheraven */ 447227825Stheravenstatic pthread_cond_t emergency_malloc_wait = PTHREAD_COND_INITIALIZER; 448227825Stheraven 449227825Stheraven/** 450227825Stheraven * Allocates size bytes from the emergency allocation mechanism, if possible. 451227825Stheraven * This function will fail if size is over 1KB or if this thread already has 4 452227825Stheraven * emergency buffers. If all emergency buffers are allocated, it will sleep 453227825Stheraven * until one becomes available. 454227825Stheraven */ 455227825Stheravenstatic char *emergency_malloc(size_t size) 456227825Stheraven{ 457227825Stheraven if (size > 1024) { return 0; } 458227825Stheraven 459227825Stheraven __cxa_thread_info *info = thread_info(); 460227825Stheraven // Only 4 emergency buffers allowed per thread! 461227825Stheraven if (info->emergencyBuffersHeld > 3) { return 0; } 462227825Stheraven 463232950Stheraven pthread_mutex_lock(&emergency_malloc_lock); 464227825Stheraven int buffer = -1; 465227825Stheraven while (buffer < 0) 466227825Stheraven { 467227825Stheraven // While we were sleeping on the lock, another thread might have free'd 468227825Stheraven // enough memory for us to use, so try the allocation again - no point 469227825Stheraven // using the emergency buffer if there is some real memory that we can 470227825Stheraven // use... 471227825Stheraven void *m = calloc(1, size); 472227825Stheraven if (0 != m) 473227825Stheraven { 474232950Stheraven pthread_mutex_unlock(&emergency_malloc_lock); 475227825Stheraven return (char*)m; 476227825Stheraven } 477227825Stheraven for (int i=0 ; i<16 ; i++) 478227825Stheraven { 479227825Stheraven if (!buffer_allocated[i]) 480227825Stheraven { 481227825Stheraven buffer = i; 482227825Stheraven buffer_allocated[i] = true; 483227825Stheraven break; 484227825Stheraven } 485227825Stheraven } 486227825Stheraven // If there still isn't a buffer available, then sleep on the condition 487227825Stheraven // variable. This will be signalled when another thread releases one 488227825Stheraven // of the emergency buffers. 489227825Stheraven if (buffer < 0) 490227825Stheraven { 491227825Stheraven pthread_cond_wait(&emergency_malloc_wait, &emergency_malloc_lock); 492227825Stheraven } 493227825Stheraven } 494232950Stheraven pthread_mutex_unlock(&emergency_malloc_lock); 495227825Stheraven info->emergencyBuffersHeld++; 496227825Stheraven return emergency_buffer + (1024 * buffer); 497227825Stheraven} 498227825Stheraven 499227825Stheraven/** 500227825Stheraven * Frees a buffer returned by emergency_malloc(). 501227825Stheraven * 502227825Stheraven * Note: Neither this nor emergency_malloc() is particularly efficient. This 503227825Stheraven * should not matter, because neither will be called in normal operation - they 504227825Stheraven * are only used when the program runs out of memory, which should not happen 505227825Stheraven * often. 506227825Stheraven */ 507227825Stheravenstatic void emergency_malloc_free(char *ptr) 508227825Stheraven{ 509227825Stheraven int buffer = -1; 510227825Stheraven // Find the buffer corresponding to this pointer. 511227825Stheraven for (int i=0 ; i<16 ; i++) 512227825Stheraven { 513227825Stheraven if (ptr == (void*)(emergency_buffer + (1024 * i))) 514227825Stheraven { 515227825Stheraven buffer = i; 516227825Stheraven break; 517227825Stheraven } 518227825Stheraven } 519227825Stheraven assert(buffer > 0 && 520227825Stheraven "Trying to free something that is not an emergency buffer!"); 521227825Stheraven // emergency_malloc() is expected to return 0-initialized data. We don't 522227825Stheraven // zero the buffer when allocating it, because the static buffers will 523227825Stheraven // begin life containing 0 values. 524227825Stheraven memset((void*)ptr, 0, 1024); 525227825Stheraven // Signal the condition variable to wake up any threads that are blocking 526227825Stheraven // waiting for some space in the emergency buffer 527232950Stheraven pthread_mutex_lock(&emergency_malloc_lock); 528227825Stheraven // In theory, we don't need to do this with the lock held. In practice, 529227825Stheraven // our array of bools will probably be updated using 32-bit or 64-bit 530227825Stheraven // memory operations, so this update may clobber adjacent values. 531227825Stheraven buffer_allocated[buffer] = false; 532232950Stheraven pthread_cond_signal(&emergency_malloc_wait); 533232950Stheraven pthread_mutex_unlock(&emergency_malloc_lock); 534227825Stheraven} 535227825Stheraven 536227825Stheravenstatic char *alloc_or_die(size_t size) 537227825Stheraven{ 538227825Stheraven char *buffer = (char*)calloc(1, size); 539227825Stheraven 540227825Stheraven // If calloc() doesn't want to give us any memory, try using an emergency 541227825Stheraven // buffer. 542227825Stheraven if (0 == buffer) 543227825Stheraven { 544227825Stheraven buffer = emergency_malloc(size); 545227825Stheraven // This is only reached if the allocation is greater than 1KB, and 546227825Stheraven // anyone throwing objects that big really should know better. 547227825Stheraven if (0 == buffer) 548227825Stheraven { 549227825Stheraven fprintf(stderr, "Out of memory attempting to allocate exception\n"); 550227825Stheraven std::terminate(); 551227825Stheraven } 552227825Stheraven } 553227825Stheraven return buffer; 554227825Stheraven} 555227825Stheravenstatic void free_exception(char *e) 556227825Stheraven{ 557227825Stheraven // If this allocation is within the address range of the emergency buffer, 558227825Stheraven // don't call free() because it was not allocated with malloc() 559227825Stheraven if ((e > emergency_buffer) && 560227825Stheraven (e < (emergency_buffer + sizeof(emergency_buffer)))) 561227825Stheraven { 562227825Stheraven emergency_malloc_free(e); 563227825Stheraven } 564227825Stheraven else 565227825Stheraven { 566227825Stheraven free(e); 567227825Stheraven } 568227825Stheraven} 569227825Stheraven 570227825Stheraven/** 571227825Stheraven * Allocates an exception structure. Returns a pointer to the space that can 572227825Stheraven * be used to store an object of thrown_size bytes. This function will use an 573227825Stheraven * emergency buffer if malloc() fails, and may block if there are no such 574227825Stheraven * buffers available. 575227825Stheraven */ 576227825Stheravenextern "C" void *__cxa_allocate_exception(size_t thrown_size) 577227825Stheraven{ 578227825Stheraven size_t size = thrown_size + sizeof(__cxa_exception); 579227825Stheraven char *buffer = alloc_or_die(size); 580227825Stheraven return buffer+sizeof(__cxa_exception); 581227825Stheraven} 582227825Stheraven 583227825Stheravenextern "C" void *__cxa_allocate_dependent_exception(void) 584227825Stheraven{ 585227825Stheraven size_t size = sizeof(__cxa_dependent_exception); 586227825Stheraven char *buffer = alloc_or_die(size); 587227825Stheraven return buffer+sizeof(__cxa_dependent_exception); 588227825Stheraven} 589227825Stheraven 590227825Stheraven/** 591227825Stheraven * __cxa_free_exception() is called when an exception was thrown in between 592227825Stheraven * calling __cxa_allocate_exception() and actually throwing the exception. 593227825Stheraven * This happens when the object's copy constructor throws an exception. 594227825Stheraven * 595227825Stheraven * In this implementation, it is also called by __cxa_end_catch() and during 596227825Stheraven * thread cleanup. 597227825Stheraven */ 598227825Stheravenextern "C" void __cxa_free_exception(void *thrown_exception) 599227825Stheraven{ 600227825Stheraven __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1; 601227825Stheraven // Free the object that was thrown, calling its destructor 602227825Stheraven if (0 != ex->exceptionDestructor) 603227825Stheraven { 604227825Stheraven try 605227825Stheraven { 606227825Stheraven ex->exceptionDestructor(thrown_exception); 607227825Stheraven } 608227825Stheraven catch(...) 609227825Stheraven { 610227825Stheraven // FIXME: Check that this is really what the spec says to do. 611227825Stheraven std::terminate(); 612227825Stheraven } 613227825Stheraven } 614227825Stheraven 615227825Stheraven free_exception((char*)ex); 616227825Stheraven} 617227825Stheraven 618227825Stheravenstatic void releaseException(__cxa_exception *exception) 619227825Stheraven{ 620227825Stheraven if (isDependentException(exception->unwindHeader.exception_class)) 621227825Stheraven { 622227825Stheraven __cxa_free_dependent_exception(exception+1); 623227825Stheraven return; 624227825Stheraven } 625227825Stheraven if (__sync_sub_and_fetch(&exception->referenceCount, 1) == 0) 626227825Stheraven { 627227825Stheraven // __cxa_free_exception() expects to be passed the thrown object, 628227825Stheraven // which immediately follows the exception, not the exception 629227825Stheraven // itself 630227825Stheraven __cxa_free_exception(exception+1); 631227825Stheraven } 632227825Stheraven} 633227825Stheraven 634227825Stheravenvoid __cxa_free_dependent_exception(void *thrown_exception) 635227825Stheraven{ 636227825Stheraven __cxa_dependent_exception *ex = ((__cxa_dependent_exception*)thrown_exception) - 1; 637227825Stheraven assert(isDependentException(ex->unwindHeader.exception_class)); 638227825Stheraven if (ex->primaryException) 639227825Stheraven { 640227825Stheraven releaseException(realExceptionFromException((__cxa_exception*)ex)); 641227825Stheraven } 642227825Stheraven free_exception((char*)ex); 643227825Stheraven} 644227825Stheraven 645227825Stheraven/** 646227825Stheraven * Callback function used with _Unwind_Backtrace(). 647227825Stheraven * 648227825Stheraven * Prints a stack trace. Used only for debugging help. 649227825Stheraven * 650227825Stheraven * Note: As of FreeBSD 8.1, dladd() still doesn't work properly, so this only 651227825Stheraven * correctly prints function names from public, relocatable, symbols. 652227825Stheraven */ 653227825Stheravenstatic _Unwind_Reason_Code trace(struct _Unwind_Context *context, void *c) 654227825Stheraven{ 655227825Stheraven Dl_info myinfo; 656227825Stheraven int mylookup = 657227825Stheraven dladdr((void*)(uintptr_t)__cxa_current_exception_type, &myinfo); 658227825Stheraven void *ip = (void*)_Unwind_GetIP(context); 659227825Stheraven Dl_info info; 660227825Stheraven if (dladdr(ip, &info) != 0) 661227825Stheraven { 662227825Stheraven if (mylookup == 0 || strcmp(info.dli_fname, myinfo.dli_fname) != 0) 663227825Stheraven { 664227825Stheraven printf("%p:%s() in %s\n", ip, info.dli_sname, info.dli_fname); 665227825Stheraven } 666227825Stheraven } 667227825Stheraven return _URC_CONTINUE_UNWIND; 668227825Stheraven} 669227825Stheraven 670227825Stheraven/** 671227825Stheraven * Report a failure that occurred when attempting to throw an exception. 672227825Stheraven * 673227825Stheraven * If the failure happened by falling off the end of the stack without finding 674227825Stheraven * a handler, prints a back trace before aborting. 675227825Stheraven */ 676227825Stheravenstatic void report_failure(_Unwind_Reason_Code err, __cxa_exception *thrown_exception) 677227825Stheraven{ 678227825Stheraven switch (err) 679227825Stheraven { 680227825Stheraven default: break; 681227825Stheraven case _URC_FATAL_PHASE1_ERROR: 682227825Stheraven fprintf(stderr, "Fatal error during phase 1 unwinding\n"); 683227825Stheraven break; 684227972Stheraven#ifndef __arm__ 685227825Stheraven case _URC_FATAL_PHASE2_ERROR: 686227825Stheraven fprintf(stderr, "Fatal error during phase 2 unwinding\n"); 687227825Stheraven break; 688227972Stheraven#endif 689227825Stheraven case _URC_END_OF_STACK: 690227825Stheraven fprintf(stderr, "Terminating due to uncaught exception %p", 691227825Stheraven (void*)thrown_exception); 692227825Stheraven thrown_exception = realExceptionFromException(thrown_exception); 693227825Stheraven static const __class_type_info *e_ti = 694227825Stheraven static_cast<const __class_type_info*>(&typeid(std::exception)); 695227825Stheraven const __class_type_info *throw_ti = 696227825Stheraven dynamic_cast<const __class_type_info*>(thrown_exception->exceptionType); 697227825Stheraven if (throw_ti) 698227825Stheraven { 699227825Stheraven std::exception *e = 700227825Stheraven (std::exception*)e_ti->cast_to((void*)(thrown_exception+1), 701227825Stheraven throw_ti); 702227825Stheraven if (e) 703227825Stheraven { 704227825Stheraven fprintf(stderr, " '%s'", e->what()); 705227825Stheraven } 706227825Stheraven } 707227825Stheraven 708227825Stheraven size_t bufferSize = 128; 709227825Stheraven char *demangled = (char*)malloc(bufferSize); 710227825Stheraven const char *mangled = thrown_exception->exceptionType->name(); 711227825Stheraven int status; 712227825Stheraven demangled = __cxa_demangle(mangled, demangled, &bufferSize, &status); 713227825Stheraven fprintf(stderr, " of type %s\n", 714227825Stheraven status == 0 ? (const char*)demangled : mangled); 715227825Stheraven if (status == 0) { free(demangled); } 716227825Stheraven // Print a back trace if no handler is found. 717227825Stheraven // TODO: Make this optional 718255093Stheraven#ifndef __arm__ 719227825Stheraven _Unwind_Backtrace(trace, 0); 720255093Stheraven#endif 721227825Stheraven break; 722227825Stheraven } 723227825Stheraven std::terminate(); 724227825Stheraven} 725227825Stheraven 726227825Stheravenstatic void throw_exception(__cxa_exception *ex) 727227825Stheraven{ 728227825Stheraven __cxa_thread_info *info = thread_info(); 729227825Stheraven ex->unexpectedHandler = info->unexpectedHandler; 730227825Stheraven if (0 == ex->unexpectedHandler) 731227825Stheraven { 732227825Stheraven ex->unexpectedHandler = unexpectedHandler; 733227825Stheraven } 734227825Stheraven ex->terminateHandler = info->terminateHandler; 735227825Stheraven if (0 == ex->terminateHandler) 736227825Stheraven { 737227825Stheraven ex->terminateHandler = terminateHandler; 738227825Stheraven } 739227825Stheraven info->globals.uncaughtExceptions++; 740227825Stheraven 741227825Stheraven _Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader); 742227825Stheraven // The _Unwind_RaiseException() function should not return, it should 743227825Stheraven // unwind the stack past this function. If it does return, then something 744227825Stheraven // has gone wrong. 745227825Stheraven report_failure(err, ex); 746227825Stheraven} 747227825Stheraven 748227825Stheraven 749227825Stheraven/** 750227825Stheraven * ABI function for throwing an exception. Takes the object to be thrown (the 751227825Stheraven * pointer returned by __cxa_allocate_exception()), the type info for the 752227825Stheraven * pointee, and the destructor (if there is one) as arguments. 753227825Stheraven */ 754227825Stheravenextern "C" void __cxa_throw(void *thrown_exception, 755227825Stheraven std::type_info *tinfo, 756227825Stheraven void(*dest)(void*)) 757227825Stheraven{ 758227825Stheraven __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1; 759227825Stheraven 760227825Stheraven ex->referenceCount = 1; 761227825Stheraven ex->exceptionType = tinfo; 762227825Stheraven 763227825Stheraven ex->exceptionDestructor = dest; 764227825Stheraven 765227825Stheraven ex->unwindHeader.exception_class = exception_class; 766227825Stheraven ex->unwindHeader.exception_cleanup = exception_cleanup; 767227825Stheraven 768227825Stheraven throw_exception(ex); 769227825Stheraven} 770227825Stheraven 771227825Stheravenextern "C" void __cxa_rethrow_primary_exception(void* thrown_exception) 772227825Stheraven{ 773227825Stheraven if (NULL == thrown_exception) { return; } 774227825Stheraven 775227825Stheraven __cxa_exception *original = exceptionFromPointer(thrown_exception); 776227825Stheraven __cxa_dependent_exception *ex = ((__cxa_dependent_exception*)__cxa_allocate_dependent_exception())-1; 777227825Stheraven 778227825Stheraven ex->primaryException = thrown_exception; 779227825Stheraven __cxa_increment_exception_refcount(thrown_exception); 780227825Stheraven 781227825Stheraven ex->exceptionType = original->exceptionType; 782227825Stheraven ex->unwindHeader.exception_class = dependent_exception_class; 783227825Stheraven ex->unwindHeader.exception_cleanup = dependent_exception_cleanup; 784227825Stheraven 785227825Stheraven throw_exception((__cxa_exception*)ex); 786227825Stheraven} 787227825Stheraven 788227825Stheravenextern "C" void *__cxa_current_primary_exception(void) 789227825Stheraven{ 790227825Stheraven __cxa_eh_globals* globals = __cxa_get_globals(); 791227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 792227825Stheraven 793227825Stheraven if (0 == ex) { return NULL; } 794227825Stheraven ex = realExceptionFromException(ex); 795227825Stheraven __sync_fetch_and_add(&ex->referenceCount, 1); 796227825Stheraven return ex + 1; 797227825Stheraven} 798227825Stheraven 799227825Stheravenextern "C" void __cxa_increment_exception_refcount(void* thrown_exception) 800227825Stheraven{ 801227825Stheraven if (NULL == thrown_exception) { return; } 802227825Stheraven __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1; 803227825Stheraven if (isDependentException(ex->unwindHeader.exception_class)) { return; } 804227825Stheraven __sync_fetch_and_add(&ex->referenceCount, 1); 805227825Stheraven} 806227825Stheravenextern "C" void __cxa_decrement_exception_refcount(void* thrown_exception) 807227825Stheraven{ 808227825Stheraven if (NULL == thrown_exception) { return; } 809227825Stheraven __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1; 810227825Stheraven releaseException(ex); 811227825Stheraven} 812227825Stheraven 813227825Stheraven/** 814227825Stheraven * ABI function. Rethrows the current exception. Does not remove the 815227825Stheraven * exception from the stack or decrement its handler count - the compiler is 816227825Stheraven * expected to set the landing pad for this function to the end of the catch 817227825Stheraven * block, and then call _Unwind_Resume() to continue unwinding once 818227825Stheraven * __cxa_end_catch() has been called and any cleanup code has been run. 819227825Stheraven */ 820227825Stheravenextern "C" void __cxa_rethrow() 821227825Stheraven{ 822245745Stheraven __cxa_thread_info *ti = thread_info(); 823245304Stheraven __cxa_eh_globals *globals = &ti->globals; 824227825Stheraven // Note: We don't remove this from the caught list here, because 825227825Stheraven // __cxa_end_catch will be called when we unwind out of the try block. We 826227825Stheraven // could probably make this faster by providing an alternative rethrow 827227825Stheraven // function and ensuring that all cleanup code is run before calling it, so 828227825Stheraven // we can skip the top stack frame when unwinding. 829227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 830227825Stheraven 831227825Stheraven if (0 == ex) 832227825Stheraven { 833227825Stheraven fprintf(stderr, 834227825Stheraven "Attempting to rethrow an exception that doesn't exist!\n"); 835227825Stheraven std::terminate(); 836227825Stheraven } 837227825Stheraven 838245304Stheraven if (ti->foreign_exception_state != __cxa_thread_info::none) 839245304Stheraven { 840245304Stheraven ti->foreign_exception_state = __cxa_thread_info::rethrown; 841245304Stheraven _Unwind_Exception *e = (_Unwind_Exception*)ex; 842245304Stheraven _Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(e); 843245304Stheraven report_failure(err, ex); 844245304Stheraven return; 845245304Stheraven } 846245304Stheraven 847227825Stheraven assert(ex->handlerCount > 0 && "Rethrowing uncaught exception!"); 848227825Stheraven 849227825Stheraven // ex->handlerCount will be decremented in __cxa_end_catch in enclosing 850227825Stheraven // catch block 851227825Stheraven 852227825Stheraven // Make handler count negative. This will tell __cxa_end_catch that 853227825Stheraven // exception was rethrown and exception object should not be destroyed 854227825Stheraven // when handler count become zero 855227825Stheraven ex->handlerCount = -ex->handlerCount; 856227825Stheraven 857227825Stheraven // Continue unwinding the stack with this exception. This should unwind to 858227825Stheraven // the place in the caller where __cxa_end_catch() is called. The caller 859227825Stheraven // will then run cleanup code and bounce the exception back with 860227825Stheraven // _Unwind_Resume(). 861227825Stheraven _Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(&ex->unwindHeader); 862227825Stheraven report_failure(err, ex); 863227825Stheraven} 864227825Stheraven 865227825Stheraven/** 866227825Stheraven * Returns the type_info object corresponding to the filter. 867227825Stheraven */ 868227825Stheravenstatic std::type_info *get_type_info_entry(_Unwind_Context *context, 869227825Stheraven dwarf_eh_lsda *lsda, 870227825Stheraven int filter) 871227825Stheraven{ 872227825Stheraven // Get the address of the record in the table. 873227825Stheraven dw_eh_ptr_t record = lsda->type_table - 874227825Stheraven dwarf_size_of_fixed_size_field(lsda->type_table_encoding)*filter; 875227972Stheraven //record -= 4; 876227825Stheraven dw_eh_ptr_t start = record; 877227825Stheraven // Read the value, but it's probably an indirect reference... 878227825Stheraven int64_t offset = read_value(lsda->type_table_encoding, &record); 879227825Stheraven 880227825Stheraven // (If the entry is 0, don't try to dereference it. That would be bad.) 881227825Stheraven if (offset == 0) { return 0; } 882227825Stheraven 883227825Stheraven // ...so we need to resolve it 884227825Stheraven return (std::type_info*)resolve_indirect_value(context, 885227825Stheraven lsda->type_table_encoding, offset, start); 886227825Stheraven} 887227825Stheraven 888227825Stheraven 889227972Stheraven 890227825Stheraven/** 891227825Stheraven * Checks the type signature found in a handler against the type of the thrown 892227825Stheraven * object. If ex is 0 then it is assumed to be a foreign exception and only 893227825Stheraven * matches cleanups. 894227825Stheraven */ 895227825Stheravenstatic bool check_type_signature(__cxa_exception *ex, 896227825Stheraven const std::type_info *type, 897227825Stheraven void *&adjustedPtr) 898227825Stheraven{ 899227825Stheraven void *exception_ptr = (void*)(ex+1); 900245304Stheraven const std::type_info *ex_type = ex ? ex->exceptionType : 0; 901227825Stheraven 902245304Stheraven bool is_ptr = ex ? ex_type->__is_pointer_p() : false; 903233235Stheraven if (is_ptr) 904227825Stheraven { 905227825Stheraven exception_ptr = *(void**)exception_ptr; 906227825Stheraven } 907227825Stheraven // Always match a catchall, even with a foreign exception 908227825Stheraven // 909227825Stheraven // Note: A 0 here is a catchall, not a cleanup, so we return true to 910227825Stheraven // indicate that we found a catch. 911227825Stheraven if (0 == type) 912227825Stheraven { 913227825Stheraven if (ex) 914227825Stheraven { 915227825Stheraven adjustedPtr = exception_ptr; 916227825Stheraven } 917227825Stheraven return true; 918227825Stheraven } 919227825Stheraven 920227825Stheraven if (0 == ex) { return false; } 921227825Stheraven 922227825Stheraven // If the types are the same, no casting is needed. 923227825Stheraven if (*type == *ex_type) 924227825Stheraven { 925227825Stheraven adjustedPtr = exception_ptr; 926227825Stheraven return true; 927227825Stheraven } 928227825Stheraven 929227825Stheraven 930233235Stheraven if (type->__do_catch(ex_type, &exception_ptr, 1)) 931227825Stheraven { 932233235Stheraven adjustedPtr = exception_ptr; 933227825Stheraven return true; 934227825Stheraven } 935233235Stheraven 936227825Stheraven return false; 937227825Stheraven} 938227825Stheraven/** 939227825Stheraven * Checks whether the exception matches the type specifiers in this action 940227825Stheraven * record. If the exception only matches cleanups, then this returns false. 941227825Stheraven * If it matches a catch (including a catchall) then it returns true. 942227825Stheraven * 943227825Stheraven * The selector argument is used to return the selector that is passed in the 944227825Stheraven * second exception register when installing the context. 945227825Stheraven */ 946227825Stheravenstatic handler_type check_action_record(_Unwind_Context *context, 947227825Stheraven dwarf_eh_lsda *lsda, 948227825Stheraven dw_eh_ptr_t action_record, 949227825Stheraven __cxa_exception *ex, 950227825Stheraven unsigned long *selector, 951227825Stheraven void *&adjustedPtr) 952227825Stheraven{ 953227825Stheraven if (!action_record) { return handler_cleanup; } 954227825Stheraven handler_type found = handler_none; 955227825Stheraven while (action_record) 956227825Stheraven { 957227825Stheraven int filter = read_sleb128(&action_record); 958227825Stheraven dw_eh_ptr_t action_record_offset_base = action_record; 959227825Stheraven int displacement = read_sleb128(&action_record); 960227825Stheraven action_record = displacement ? 961227825Stheraven action_record_offset_base + displacement : 0; 962227825Stheraven // We only check handler types for C++ exceptions - foreign exceptions 963245304Stheraven // are only allowed for cleanups and catchalls. 964245304Stheraven if (filter > 0) 965227825Stheraven { 966227825Stheraven std::type_info *handler_type = get_type_info_entry(context, lsda, filter); 967227825Stheraven if (check_type_signature(ex, handler_type, adjustedPtr)) 968227825Stheraven { 969227825Stheraven *selector = filter; 970227825Stheraven return handler_catch; 971227825Stheraven } 972227825Stheraven } 973227825Stheraven else if (filter < 0 && 0 != ex) 974227825Stheraven { 975227825Stheraven bool matched = false; 976227825Stheraven *selector = filter; 977227972Stheraven#ifdef __arm__ 978227972Stheraven filter++; 979227972Stheraven std::type_info *handler_type = get_type_info_entry(context, lsda, filter--); 980227972Stheraven while (handler_type) 981227972Stheraven { 982227972Stheraven if (check_type_signature(ex, handler_type, adjustedPtr)) 983227972Stheraven { 984227972Stheraven matched = true; 985227972Stheraven break; 986227972Stheraven } 987227972Stheraven handler_type = get_type_info_entry(context, lsda, filter--); 988227972Stheraven } 989227972Stheraven#else 990227972Stheraven unsigned char *type_index = ((unsigned char*)lsda->type_table - filter - 1); 991227825Stheraven while (*type_index) 992227825Stheraven { 993227825Stheraven std::type_info *handler_type = get_type_info_entry(context, lsda, *(type_index++)); 994227825Stheraven // If the exception spec matches a permitted throw type for 995227825Stheraven // this function, don't report a handler - we are allowed to 996227825Stheraven // propagate this exception out. 997227825Stheraven if (check_type_signature(ex, handler_type, adjustedPtr)) 998227825Stheraven { 999227825Stheraven matched = true; 1000227825Stheraven break; 1001227825Stheraven } 1002227825Stheraven } 1003227972Stheraven#endif 1004227825Stheraven if (matched) { continue; } 1005227825Stheraven // If we don't find an allowed exception spec, we need to install 1006227825Stheraven // the context for this action. The landing pad will then call the 1007227825Stheraven // unexpected exception function. Treat this as a catch 1008227825Stheraven return handler_catch; 1009227825Stheraven } 1010227825Stheraven else if (filter == 0) 1011227825Stheraven { 1012227825Stheraven *selector = filter; 1013227825Stheraven found = handler_cleanup; 1014227825Stheraven } 1015227825Stheraven } 1016227825Stheraven return found; 1017227825Stheraven} 1018227825Stheraven 1019227972Stheravenstatic void pushCleanupException(_Unwind_Exception *exceptionObject, 1020227972Stheraven __cxa_exception *ex) 1021227972Stheraven{ 1022227972Stheraven#ifdef __arm__ 1023227972Stheraven __cxa_thread_info *info = thread_info_fast(); 1024227972Stheraven if (ex) 1025227972Stheraven { 1026227972Stheraven ex->cleanupCount++; 1027227972Stheraven if (ex->cleanupCount > 1) 1028227972Stheraven { 1029227972Stheraven assert(exceptionObject == info->currentCleanup); 1030227972Stheraven return; 1031227972Stheraven } 1032227972Stheraven ex->nextCleanup = info->currentCleanup; 1033227972Stheraven } 1034227972Stheraven info->currentCleanup = exceptionObject; 1035227972Stheraven#endif 1036227972Stheraven} 1037227972Stheraven 1038227825Stheraven/** 1039227825Stheraven * The exception personality function. This is referenced in the unwinding 1040227825Stheraven * DWARF metadata and is called by the unwind library for each C++ stack frame 1041227825Stheraven * containing catch or cleanup code. 1042227825Stheraven */ 1043227972Stheravenextern "C" 1044227972StheravenBEGIN_PERSONALITY_FUNCTION(__gxx_personality_v0) 1045227825Stheraven // This personality function is for version 1 of the ABI. If you use it 1046227825Stheraven // with a future version of the ABI, it won't know what to do, so it 1047227825Stheraven // reports a fatal error and give up before it breaks anything. 1048227825Stheraven if (1 != version) 1049227825Stheraven { 1050227825Stheraven return _URC_FATAL_PHASE1_ERROR; 1051227825Stheraven } 1052227825Stheraven __cxa_exception *ex = 0; 1053227825Stheraven __cxa_exception *realEx = 0; 1054227825Stheraven 1055227825Stheraven // If this exception is throw by something else then we can't make any 1056227825Stheraven // assumptions about its layout beyond the fields declared in 1057227825Stheraven // _Unwind_Exception. 1058227825Stheraven bool foreignException = !isCXXException(exceptionClass); 1059227825Stheraven 1060227825Stheraven // If this isn't a foreign exception, then we have a C++ exception structure 1061227825Stheraven if (!foreignException) 1062227825Stheraven { 1063227825Stheraven ex = exceptionFromPointer(exceptionObject); 1064227825Stheraven realEx = realExceptionFromException(ex); 1065227825Stheraven } 1066227825Stheraven 1067227825Stheraven unsigned char *lsda_addr = 1068227825Stheraven (unsigned char*)_Unwind_GetLanguageSpecificData(context); 1069227825Stheraven 1070227825Stheraven // No LSDA implies no landing pads - try the next frame 1071227972Stheraven if (0 == lsda_addr) { return continueUnwinding(exceptionObject, context); } 1072227825Stheraven 1073227825Stheraven // These two variables define how the exception will be handled. 1074227825Stheraven dwarf_eh_action action = {0}; 1075227825Stheraven unsigned long selector = 0; 1076227825Stheraven 1077227825Stheraven // During the search phase, we do a complete lookup. If we return 1078227825Stheraven // _URC_HANDLER_FOUND, then the phase 2 unwind will call this function with 1079227825Stheraven // a _UA_HANDLER_FRAME action, telling us to install the handler frame. If 1080227825Stheraven // we return _URC_CONTINUE_UNWIND, we may be called again later with a 1081227825Stheraven // _UA_CLEANUP_PHASE action for this frame. 1082227825Stheraven // 1083227825Stheraven // The point of the two-stage unwind allows us to entirely avoid any stack 1084227825Stheraven // unwinding if there is no handler. If there are just cleanups found, 1085227825Stheraven // then we can just panic call an abort function. 1086227825Stheraven // 1087227825Stheraven // Matching a handler is much more expensive than matching a cleanup, 1088227825Stheraven // because we don't need to bother doing type comparisons (or looking at 1089227825Stheraven // the type table at all) for a cleanup. This means that there is no need 1090227825Stheraven // to cache the result of finding a cleanup, because it's (quite) quick to 1091227825Stheraven // look it up again from the action table. 1092227825Stheraven if (actions & _UA_SEARCH_PHASE) 1093227825Stheraven { 1094227825Stheraven struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); 1095227825Stheraven 1096227825Stheraven if (!dwarf_eh_find_callsite(context, &lsda, &action)) 1097227825Stheraven { 1098227825Stheraven // EH range not found. This happens if exception is thrown and not 1099227825Stheraven // caught inside a cleanup (destructor). We should call 1100227825Stheraven // terminate() in this case. The catchTemp (landing pad) field of 1101227825Stheraven // exception object will contain null when personality function is 1102227825Stheraven // called with _UA_HANDLER_FRAME action for phase 2 unwinding. 1103227825Stheraven return _URC_HANDLER_FOUND; 1104227825Stheraven } 1105227825Stheraven 1106227825Stheraven handler_type found_handler = check_action_record(context, &lsda, 1107227825Stheraven action.action_record, realEx, &selector, ex->adjustedPtr); 1108227825Stheraven // If there's no action record, we've only found a cleanup, so keep 1109227825Stheraven // searching for something real 1110227825Stheraven if (found_handler == handler_catch) 1111227825Stheraven { 1112227825Stheraven // Cache the results for the phase 2 unwind, if we found a handler 1113227825Stheraven // and this is not a foreign exception. 1114227825Stheraven if (ex) 1115227825Stheraven { 1116227972Stheraven saveLandingPad(context, exceptionObject, ex, selector, action.landing_pad); 1117227972Stheraven ex->languageSpecificData = (const char*)lsda_addr; 1118227825Stheraven ex->actionRecord = (const char*)action.action_record; 1119227825Stheraven // ex->adjustedPtr is set when finding the action record. 1120227825Stheraven } 1121227825Stheraven return _URC_HANDLER_FOUND; 1122227825Stheraven } 1123227972Stheraven return continueUnwinding(exceptionObject, context); 1124227825Stheraven } 1125227825Stheraven 1126227825Stheraven 1127227825Stheraven // If this is a foreign exception, we didn't have anywhere to cache the 1128227825Stheraven // lookup stuff, so we need to do it again. If this is either a forced 1129227825Stheraven // unwind, a foreign exception, or a cleanup, then we just install the 1130227825Stheraven // context for a cleanup. 1131227825Stheraven if (!(actions & _UA_HANDLER_FRAME)) 1132227825Stheraven { 1133227825Stheraven // cleanup 1134227825Stheraven struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); 1135227825Stheraven dwarf_eh_find_callsite(context, &lsda, &action); 1136227972Stheraven if (0 == action.landing_pad) { return continueUnwinding(exceptionObject, context); } 1137227825Stheraven handler_type found_handler = check_action_record(context, &lsda, 1138227825Stheraven action.action_record, realEx, &selector, ex->adjustedPtr); 1139227825Stheraven // Ignore handlers this time. 1140227972Stheraven if (found_handler != handler_cleanup) { return continueUnwinding(exceptionObject, context); } 1141227972Stheraven pushCleanupException(exceptionObject, ex); 1142227825Stheraven } 1143227825Stheraven else if (foreignException) 1144227825Stheraven { 1145227825Stheraven struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); 1146227825Stheraven dwarf_eh_find_callsite(context, &lsda, &action); 1147227825Stheraven check_action_record(context, &lsda, action.action_record, realEx, 1148227825Stheraven &selector, ex->adjustedPtr); 1149227825Stheraven } 1150227825Stheraven else if (ex->catchTemp == 0) 1151227825Stheraven { 1152227825Stheraven // Uncaught exception in cleanup, calling terminate 1153227825Stheraven std::terminate(); 1154227825Stheraven } 1155227825Stheraven else 1156227825Stheraven { 1157227825Stheraven // Restore the saved info if we saved some last time. 1158227972Stheraven loadLandingPad(context, exceptionObject, ex, &selector, &action.landing_pad); 1159227825Stheraven ex->catchTemp = 0; 1160227825Stheraven ex->handlerSwitchValue = 0; 1161227825Stheraven } 1162227825Stheraven 1163227825Stheraven 1164227825Stheraven _Unwind_SetIP(context, (unsigned long)action.landing_pad); 1165227825Stheraven _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), 1166227825Stheraven (unsigned long)exceptionObject); 1167227825Stheraven _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector); 1168227825Stheraven 1169227825Stheraven return _URC_INSTALL_CONTEXT; 1170227825Stheraven} 1171227825Stheraven 1172227825Stheraven/** 1173227825Stheraven * ABI function called when entering a catch statement. The argument is the 1174227825Stheraven * pointer passed out of the personality function. This is always the start of 1175227825Stheraven * the _Unwind_Exception object. The return value for this function is the 1176227825Stheraven * pointer to the caught exception, which is either the adjusted pointer (for 1177227825Stheraven * C++ exceptions) of the unadjusted pointer (for foreign exceptions). 1178227825Stheraven */ 1179227825Stheraven#if __GNUC__ > 3 && __GNUC_MINOR__ > 2 1180227825Stheravenextern "C" void *__cxa_begin_catch(void *e) throw() 1181227825Stheraven#else 1182227825Stheravenextern "C" void *__cxa_begin_catch(void *e) 1183227825Stheraven#endif 1184227825Stheraven{ 1185245304Stheraven // We can't call the fast version here, because if the first exception that 1186245304Stheraven // we see is a foreign exception then we won't have called it yet. 1187245304Stheraven __cxa_thread_info *ti = thread_info(); 1188245304Stheraven __cxa_eh_globals *globals = &ti->globals; 1189227825Stheraven globals->uncaughtExceptions--; 1190227825Stheraven _Unwind_Exception *exceptionObject = (_Unwind_Exception*)e; 1191227825Stheraven 1192227825Stheraven if (isCXXException(exceptionObject->exception_class)) 1193227825Stheraven { 1194227825Stheraven __cxa_exception *ex = exceptionFromPointer(exceptionObject); 1195227825Stheraven 1196227825Stheraven if (ex->handlerCount == 0) 1197227825Stheraven { 1198227825Stheraven // Add this to the front of the list of exceptions being handled 1199227825Stheraven // and increment its handler count so that it won't be deleted 1200227825Stheraven // prematurely. 1201227825Stheraven ex->nextException = globals->caughtExceptions; 1202227825Stheraven globals->caughtExceptions = ex; 1203227825Stheraven } 1204227825Stheraven 1205227825Stheraven if (ex->handlerCount < 0) 1206227825Stheraven { 1207227825Stheraven // Rethrown exception is catched before end of catch block. 1208227825Stheraven // Clear the rethrow flag (make value positive) - we are allowed 1209227825Stheraven // to delete this exception at the end of the catch block, as long 1210227825Stheraven // as it isn't thrown again later. 1211227825Stheraven 1212227825Stheraven // Code pattern: 1213227825Stheraven // 1214227825Stheraven // try { 1215227825Stheraven // throw x; 1216227825Stheraven // } 1217227825Stheraven // catch() { 1218227825Stheraven // try { 1219227825Stheraven // throw; 1220227825Stheraven // } 1221227825Stheraven // catch() { 1222227825Stheraven // __cxa_begin_catch() <- we are here 1223227825Stheraven // } 1224227825Stheraven // } 1225227825Stheraven ex->handlerCount = -ex->handlerCount + 1; 1226227825Stheraven } 1227227825Stheraven else 1228227825Stheraven { 1229227825Stheraven ex->handlerCount++; 1230227825Stheraven } 1231245304Stheraven ti->foreign_exception_state = __cxa_thread_info::none; 1232227825Stheraven 1233227825Stheraven return ex->adjustedPtr; 1234227825Stheraven } 1235245304Stheraven else 1236245304Stheraven { 1237245304Stheraven // If this is a foreign exception, then we need to be able to 1238245304Stheraven // store it. We can't chain foreign exceptions, so we give up 1239245304Stheraven // if there are already some outstanding ones. 1240245304Stheraven if (globals->caughtExceptions != 0) 1241245304Stheraven { 1242245304Stheraven std::terminate(); 1243245304Stheraven } 1244245304Stheraven globals->caughtExceptions = (__cxa_exception*)exceptionObject; 1245245304Stheraven ti->foreign_exception_state = __cxa_thread_info::caught; 1246245304Stheraven } 1247227825Stheraven // exceptionObject is the pointer to the _Unwind_Exception within the 1248227825Stheraven // __cxa_exception. The throw object is after this 1249227825Stheraven return ((char*)exceptionObject + sizeof(_Unwind_Exception)); 1250227825Stheraven} 1251227825Stheraven 1252227972Stheraven 1253227972Stheraven 1254227825Stheraven/** 1255227825Stheraven * ABI function called when exiting a catch block. This will free the current 1256227825Stheraven * exception if it is no longer referenced in other catch blocks. 1257227825Stheraven */ 1258227825Stheravenextern "C" void __cxa_end_catch() 1259227825Stheraven{ 1260227825Stheraven // We can call the fast version here because the slow version is called in 1261227825Stheraven // __cxa_throw(), which must have been called before we end a catch block 1262245304Stheraven __cxa_thread_info *ti = thread_info_fast(); 1263245304Stheraven __cxa_eh_globals *globals = &ti->globals; 1264227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 1265227825Stheraven 1266227825Stheraven assert(0 != ex && "Ending catch when no exception is on the stack!"); 1267245304Stheraven 1268245304Stheraven if (ti->foreign_exception_state != __cxa_thread_info::none) 1269245304Stheraven { 1270245304Stheraven globals->caughtExceptions = 0; 1271245304Stheraven if (ti->foreign_exception_state != __cxa_thread_info::rethrown) 1272245304Stheraven { 1273245304Stheraven _Unwind_Exception *e = (_Unwind_Exception*)ti->globals.caughtExceptions; 1274245304Stheraven e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e); 1275245304Stheraven } 1276245304Stheraven ti->foreign_exception_state = __cxa_thread_info::none; 1277245304Stheraven return; 1278245304Stheraven } 1279227825Stheraven 1280227825Stheraven bool deleteException = true; 1281227825Stheraven 1282227825Stheraven if (ex->handlerCount < 0) 1283227825Stheraven { 1284227825Stheraven // exception was rethrown. Exception should not be deleted even if 1285227825Stheraven // handlerCount become zero. 1286227825Stheraven // Code pattern: 1287227825Stheraven // try { 1288227825Stheraven // throw x; 1289227825Stheraven // } 1290227825Stheraven // catch() { 1291227825Stheraven // { 1292227825Stheraven // throw; 1293227825Stheraven // } 1294227825Stheraven // cleanup { 1295227825Stheraven // __cxa_end_catch(); <- we are here 1296227825Stheraven // } 1297227825Stheraven // } 1298227825Stheraven // 1299227825Stheraven 1300227825Stheraven ex->handlerCount++; 1301227825Stheraven deleteException = false; 1302227825Stheraven } 1303227825Stheraven else 1304227825Stheraven { 1305227825Stheraven ex->handlerCount--; 1306227825Stheraven } 1307227825Stheraven 1308227825Stheraven if (ex->handlerCount == 0) 1309227825Stheraven { 1310227825Stheraven globals->caughtExceptions = ex->nextException; 1311227825Stheraven if (deleteException) 1312227825Stheraven { 1313227825Stheraven releaseException(ex); 1314227825Stheraven } 1315227825Stheraven } 1316227825Stheraven} 1317227825Stheraven 1318227825Stheraven/** 1319227825Stheraven * ABI function. Returns the type of the current exception. 1320227825Stheraven */ 1321227825Stheravenextern "C" std::type_info *__cxa_current_exception_type() 1322227825Stheraven{ 1323227825Stheraven __cxa_eh_globals *globals = __cxa_get_globals(); 1324227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 1325227825Stheraven return ex ? ex->exceptionType : 0; 1326227825Stheraven} 1327227825Stheraven 1328227825Stheraven/** 1329227825Stheraven * ABI function, called when an exception specification is violated. 1330227825Stheraven * 1331227825Stheraven * This function does not return. 1332227825Stheraven */ 1333227825Stheravenextern "C" void __cxa_call_unexpected(void*exception) 1334227825Stheraven{ 1335227825Stheraven _Unwind_Exception *exceptionObject = (_Unwind_Exception*)exception; 1336227825Stheraven if (exceptionObject->exception_class == exception_class) 1337227825Stheraven { 1338227825Stheraven __cxa_exception *ex = exceptionFromPointer(exceptionObject); 1339227825Stheraven if (ex->unexpectedHandler) 1340227825Stheraven { 1341227825Stheraven ex->unexpectedHandler(); 1342227825Stheraven // Should not be reached. 1343227825Stheraven abort(); 1344227825Stheraven } 1345227825Stheraven } 1346227825Stheraven std::unexpected(); 1347227825Stheraven // Should not be reached. 1348227825Stheraven abort(); 1349227825Stheraven} 1350227825Stheraven 1351227825Stheraven/** 1352227825Stheraven * ABI function, returns the adjusted pointer to the exception object. 1353227825Stheraven */ 1354227825Stheravenextern "C" void *__cxa_get_exception_ptr(void *exceptionObject) 1355227825Stheraven{ 1356227825Stheraven return exceptionFromPointer(exceptionObject)->adjustedPtr; 1357227825Stheraven} 1358227825Stheraven 1359227825Stheraven/** 1360227825Stheraven * As an extension, we provide the ability for the unexpected and terminate 1361227825Stheraven * handlers to be thread-local. We default to the standards-compliant 1362227825Stheraven * behaviour where they are global. 1363227825Stheraven */ 1364227825Stheravenstatic bool thread_local_handlers = false; 1365227825Stheraven 1366227825Stheraven 1367227825Stheravennamespace pathscale 1368227825Stheraven{ 1369227825Stheraven /** 1370227825Stheraven * Sets whether unexpected and terminate handlers should be thread-local. 1371227825Stheraven */ 1372227825Stheraven void set_use_thread_local_handlers(bool flag) throw() 1373227825Stheraven { 1374227825Stheraven thread_local_handlers = flag; 1375227825Stheraven } 1376227825Stheraven /** 1377227825Stheraven * Sets a thread-local unexpected handler. 1378227825Stheraven */ 1379227825Stheraven unexpected_handler set_unexpected(unexpected_handler f) throw() 1380227825Stheraven { 1381227825Stheraven static __cxa_thread_info *info = thread_info(); 1382227825Stheraven unexpected_handler old = info->unexpectedHandler; 1383227825Stheraven info->unexpectedHandler = f; 1384227825Stheraven return old; 1385227825Stheraven } 1386227825Stheraven /** 1387227825Stheraven * Sets a thread-local terminate handler. 1388227825Stheraven */ 1389227825Stheraven terminate_handler set_terminate(terminate_handler f) throw() 1390227825Stheraven { 1391227825Stheraven static __cxa_thread_info *info = thread_info(); 1392227825Stheraven terminate_handler old = info->terminateHandler; 1393227825Stheraven info->terminateHandler = f; 1394227825Stheraven return old; 1395227825Stheraven } 1396227825Stheraven} 1397227825Stheraven 1398227825Stheravennamespace std 1399227825Stheraven{ 1400227825Stheraven /** 1401227825Stheraven * Sets the function that will be called when an exception specification is 1402227825Stheraven * violated. 1403227825Stheraven */ 1404227825Stheraven unexpected_handler set_unexpected(unexpected_handler f) throw() 1405227825Stheraven { 1406227825Stheraven if (thread_local_handlers) { return pathscale::set_unexpected(f); } 1407227825Stheraven 1408246462Stheraven return ATOMIC_SWAP(&unexpectedHandler, f); 1409227825Stheraven } 1410227825Stheraven /** 1411227825Stheraven * Sets the function that is called to terminate the program. 1412227825Stheraven */ 1413227825Stheraven terminate_handler set_terminate(terminate_handler f) throw() 1414227825Stheraven { 1415227825Stheraven if (thread_local_handlers) { return pathscale::set_terminate(f); } 1416245304Stheraven 1417245304Stheraven return ATOMIC_SWAP(&terminateHandler, f); 1418227825Stheraven } 1419227825Stheraven /** 1420227825Stheraven * Terminates the program, calling a custom terminate implementation if 1421227825Stheraven * required. 1422227825Stheraven */ 1423227825Stheraven void terminate() 1424227825Stheraven { 1425249993Sdim static __cxa_thread_info *info = thread_info(); 1426227825Stheraven if (0 != info && 0 != info->terminateHandler) 1427227825Stheraven { 1428227825Stheraven info->terminateHandler(); 1429227825Stheraven // Should not be reached - a terminate handler is not expected to 1430227825Stheraven // return. 1431227825Stheraven abort(); 1432227825Stheraven } 1433227825Stheraven terminateHandler(); 1434227825Stheraven } 1435227825Stheraven /** 1436227825Stheraven * Called when an unexpected exception is encountered (i.e. an exception 1437227825Stheraven * violates an exception specification). This calls abort() unless a 1438227825Stheraven * custom handler has been set.. 1439227825Stheraven */ 1440227825Stheraven void unexpected() 1441227825Stheraven { 1442249993Sdim static __cxa_thread_info *info = thread_info(); 1443227825Stheraven if (0 != info && 0 != info->unexpectedHandler) 1444227825Stheraven { 1445227825Stheraven info->unexpectedHandler(); 1446227825Stheraven // Should not be reached - a terminate handler is not expected to 1447227825Stheraven // return. 1448227825Stheraven abort(); 1449227825Stheraven } 1450227825Stheraven unexpectedHandler(); 1451227825Stheraven } 1452227825Stheraven /** 1453227825Stheraven * Returns whether there are any exceptions currently being thrown that 1454227825Stheraven * have not been caught. This can occur inside a nested catch statement. 1455227825Stheraven */ 1456227825Stheraven bool uncaught_exception() throw() 1457227825Stheraven { 1458227825Stheraven __cxa_thread_info *info = thread_info(); 1459227825Stheraven return info->globals.uncaughtExceptions != 0; 1460227825Stheraven } 1461227825Stheraven /** 1462227825Stheraven * Returns the current unexpected handler. 1463227825Stheraven */ 1464227825Stheraven unexpected_handler get_unexpected() throw() 1465227825Stheraven { 1466227825Stheraven __cxa_thread_info *info = thread_info(); 1467227825Stheraven if (info->unexpectedHandler) 1468227825Stheraven { 1469227825Stheraven return info->unexpectedHandler; 1470227825Stheraven } 1471245304Stheraven return ATOMIC_LOAD(&unexpectedHandler); 1472227825Stheraven } 1473227825Stheraven /** 1474227825Stheraven * Returns the current terminate handler. 1475227825Stheraven */ 1476227825Stheraven terminate_handler get_terminate() throw() 1477227825Stheraven { 1478227825Stheraven __cxa_thread_info *info = thread_info(); 1479227825Stheraven if (info->terminateHandler) 1480227825Stheraven { 1481227825Stheraven return info->terminateHandler; 1482227825Stheraven } 1483245304Stheraven return ATOMIC_LOAD(&terminateHandler); 1484227825Stheraven } 1485227825Stheraven} 1486227972Stheraven#ifdef __arm__ 1487227972Stheravenextern "C" _Unwind_Exception *__cxa_get_cleanup(void) 1488227972Stheraven{ 1489227972Stheraven __cxa_thread_info *info = thread_info_fast(); 1490227972Stheraven _Unwind_Exception *exceptionObject = info->currentCleanup; 1491227972Stheraven if (isCXXException(exceptionObject->exception_class)) 1492227972Stheraven { 1493227972Stheraven __cxa_exception *ex = exceptionFromPointer(exceptionObject); 1494227972Stheraven ex->cleanupCount--; 1495227972Stheraven if (ex->cleanupCount == 0) 1496227972Stheraven { 1497227972Stheraven info->currentCleanup = ex->nextCleanup; 1498227972Stheraven ex->nextCleanup = 0; 1499227972Stheraven } 1500227972Stheraven } 1501227972Stheraven else 1502227972Stheraven { 1503227972Stheraven info->currentCleanup = 0; 1504227972Stheraven } 1505227972Stheraven return exceptionObject; 1506227972Stheraven} 1507227972Stheraven 1508227972Stheravenasm ( 1509227972Stheraven".pushsection .text.__cxa_end_cleanup \n" 1510227972Stheraven".global __cxa_end_cleanup \n" 1511227972Stheraven".type __cxa_end_cleanup, \"function\" \n" 1512227972Stheraven"__cxa_end_cleanup: \n" 1513227972Stheraven" push {r1, r2, r3, r4} \n" 1514227972Stheraven" bl __cxa_get_cleanup \n" 1515227972Stheraven" push {r1, r2, r3, r4} \n" 1516227972Stheraven" b _Unwind_Resume \n" 1517227972Stheraven" bl abort \n" 1518227972Stheraven".popsection \n" 1519227972Stheraven); 1520227972Stheraven#endif 1521