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{ 74278724Sdim#if defined(__arm__) && !defined(__ARM_DWARF_EH__) 75227972Stheraven // On ARM, we store the saved exception in the generic part of the structure 76227972Stheraven ucb->barrier_cache.sp = _Unwind_GetGR(context, 13); 77278724Sdim ucb->barrier_cache.bitpattern[1] = static_cast<uint32_t>(selector); 78278724Sdim ucb->barrier_cache.bitpattern[3] = reinterpret_cast<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{ 98278724Sdim#if defined(__arm__) && !defined(__ARM_DWARF_EH__) 99227972Stheraven *selector = ucb->barrier_cache.bitpattern[1]; 100278724Sdim *landingPad = reinterpret_cast<dw_eh_ptr_t>(ucb->barrier_cache.bitpattern[3]); 101227972Stheraven return 1; 102227972Stheraven#else 103227972Stheraven if (ex) 104227972Stheraven { 105227972Stheraven *selector = ex->handlerSwitchValue; 106278724Sdim *landingPad = reinterpret_cast<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{ 116278724Sdim#if defined(__arm__) && !defined(__ARM_DWARF_EH__) 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; 207278724Sdim#if defined(__arm__) && !defined(__ARM_DWARF_EH__) 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{ 270278724Sdim return reinterpret_cast<__cxa_exception*>(static_cast<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; } 276278724Sdim return reinterpret_cast<__cxa_exception*>((reinterpret_cast<__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{ 307315965Sdim // Exception layout: 308315965Sdim // [__cxa_exception [_Unwind_Exception]] [exception object] 309315965Sdim // 310315965Sdim // __cxa_free_exception expects a pointer to the exception object 311315965Sdim __cxa_free_exception(static_cast<void*>(ex + 1)); 312227825Stheraven} 313227825Stheravenstatic void dependent_exception_cleanup(_Unwind_Reason_Code reason, 314227825Stheraven struct _Unwind_Exception *ex) 315227825Stheraven{ 316227825Stheraven 317315965Sdim __cxa_free_dependent_exception(static_cast<void*>(ex + 1)); 318227825Stheraven} 319227825Stheraven 320227825Stheraven/** 321227825Stheraven * Recursively walk a list of exceptions and delete them all in post-order. 322227825Stheraven */ 323227825Stheravenstatic void free_exception_list(__cxa_exception *ex) 324227825Stheraven{ 325227825Stheraven if (0 != ex->nextException) 326227825Stheraven { 327227825Stheraven free_exception_list(ex->nextException); 328227825Stheraven } 329227825Stheraven // __cxa_free_exception() expects to be passed the thrown object, which 330227825Stheraven // immediately follows the exception, not the exception itself 331227825Stheraven __cxa_free_exception(ex+1); 332227825Stheraven} 333227825Stheraven 334227825Stheraven/** 335227825Stheraven * Cleanup function called when a thread exists to make certain that all of the 336227825Stheraven * per-thread data is deleted. 337227825Stheraven */ 338227825Stheravenstatic void thread_cleanup(void* thread_info) 339227825Stheraven{ 340278724Sdim __cxa_thread_info *info = static_cast<__cxa_thread_info*>(thread_info); 341227825Stheraven if (info->globals.caughtExceptions) 342227825Stheraven { 343245304Stheraven // If this is a foreign exception, ask it to clean itself up. 344245304Stheraven if (info->foreign_exception_state != __cxa_thread_info::none) 345245304Stheraven { 346278724Sdim _Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(info->globals.caughtExceptions); 347315965Sdim if (e->exception_cleanup) 348315965Sdim e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e); 349245304Stheraven } 350245304Stheraven else 351245304Stheraven { 352245304Stheraven free_exception_list(info->globals.caughtExceptions); 353245304Stheraven } 354227825Stheraven } 355227825Stheraven free(thread_info); 356227825Stheraven} 357227825Stheraven 358227825Stheraven 359227825Stheraven/** 360227825Stheraven * Once control used to protect the key creation. 361227825Stheraven */ 362227825Stheravenstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 363227825Stheraven 364227825Stheraven/** 365228004Stheraven * We may not be linked against a full pthread implementation. If we're not, 366228004Stheraven * then we need to fake the thread-local storage by storing 'thread-local' 367228004Stheraven * things in a global. 368228004Stheraven */ 369228004Stheravenstatic bool fakeTLS; 370228004Stheraven/** 371228004Stheraven * Thread-local storage for a single-threaded program. 372228004Stheraven */ 373228004Stheravenstatic __cxa_thread_info singleThreadInfo; 374228004Stheraven/** 375227825Stheraven * Initialise eh_key. 376227825Stheraven */ 377227825Stheravenstatic void init_key(void) 378227825Stheraven{ 379228004Stheraven if ((0 == pthread_key_create) || 380228004Stheraven (0 == pthread_setspecific) || 381228004Stheraven (0 == pthread_getspecific)) 382228004Stheraven { 383228004Stheraven fakeTLS = true; 384228004Stheraven return; 385228004Stheraven } 386227825Stheraven pthread_key_create(&eh_key, thread_cleanup); 387278724Sdim pthread_setspecific(eh_key, reinterpret_cast<void *>(0x42)); 388278724Sdim fakeTLS = (pthread_getspecific(eh_key) != reinterpret_cast<void *>(0x42)); 389228004Stheraven pthread_setspecific(eh_key, 0); 390227825Stheraven} 391227825Stheraven 392227825Stheraven/** 393227825Stheraven * Returns the thread info structure, creating it if it is not already created. 394227825Stheraven */ 395227825Stheravenstatic __cxa_thread_info *thread_info() 396227825Stheraven{ 397228004Stheraven if ((0 == pthread_once) || pthread_once(&once_control, init_key)) 398228004Stheraven { 399228004Stheraven fakeTLS = true; 400228004Stheraven } 401228004Stheraven if (fakeTLS) { return &singleThreadInfo; } 402278724Sdim __cxa_thread_info *info = static_cast<__cxa_thread_info*>(pthread_getspecific(eh_key)); 403227825Stheraven if (0 == info) 404227825Stheraven { 405278724Sdim info = static_cast<__cxa_thread_info*>(calloc(1, sizeof(__cxa_thread_info))); 406227825Stheraven pthread_setspecific(eh_key, info); 407227825Stheraven } 408227825Stheraven return info; 409227825Stheraven} 410227825Stheraven/** 411227825Stheraven * Fast version of thread_info(). May fail if thread_info() is not called on 412227825Stheraven * this thread at least once already. 413227825Stheraven */ 414227825Stheravenstatic __cxa_thread_info *thread_info_fast() 415227825Stheraven{ 416228004Stheraven if (fakeTLS) { return &singleThreadInfo; } 417278724Sdim return static_cast<__cxa_thread_info*>(pthread_getspecific(eh_key)); 418227825Stheraven} 419227825Stheraven/** 420227825Stheraven * ABI function returning the __cxa_eh_globals structure. 421227825Stheraven */ 422227825Stheravenextern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals(void) 423227825Stheraven{ 424227825Stheraven return &(thread_info()->globals); 425227825Stheraven} 426227825Stheraven/** 427227825Stheraven * Version of __cxa_get_globals() assuming that __cxa_get_globals() has already 428227825Stheraven * been called at least once by this thread. 429227825Stheraven */ 430227825Stheravenextern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals_fast(void) 431227825Stheraven{ 432227825Stheraven return &(thread_info_fast()->globals); 433227825Stheraven} 434227825Stheraven 435227825Stheraven/** 436227825Stheraven * An emergency allocation reserved for when malloc fails. This is treated as 437227825Stheraven * 16 buffers of 1KB each. 438227825Stheraven */ 439227825Stheravenstatic char emergency_buffer[16384]; 440227825Stheraven/** 441227825Stheraven * Flag indicating whether each buffer is allocated. 442227825Stheraven */ 443227825Stheravenstatic bool buffer_allocated[16]; 444227825Stheraven/** 445227825Stheraven * Lock used to protect emergency allocation. 446227825Stheraven */ 447227825Stheravenstatic pthread_mutex_t emergency_malloc_lock = PTHREAD_MUTEX_INITIALIZER; 448227825Stheraven/** 449227825Stheraven * Condition variable used to wait when two threads are both trying to use the 450227825Stheraven * emergency malloc() buffer at once. 451227825Stheraven */ 452227825Stheravenstatic pthread_cond_t emergency_malloc_wait = PTHREAD_COND_INITIALIZER; 453227825Stheraven 454227825Stheraven/** 455227825Stheraven * Allocates size bytes from the emergency allocation mechanism, if possible. 456227825Stheraven * This function will fail if size is over 1KB or if this thread already has 4 457227825Stheraven * emergency buffers. If all emergency buffers are allocated, it will sleep 458227825Stheraven * until one becomes available. 459227825Stheraven */ 460227825Stheravenstatic char *emergency_malloc(size_t size) 461227825Stheraven{ 462227825Stheraven if (size > 1024) { return 0; } 463227825Stheraven 464227825Stheraven __cxa_thread_info *info = thread_info(); 465227825Stheraven // Only 4 emergency buffers allowed per thread! 466227825Stheraven if (info->emergencyBuffersHeld > 3) { return 0; } 467227825Stheraven 468232950Stheraven pthread_mutex_lock(&emergency_malloc_lock); 469227825Stheraven int buffer = -1; 470227825Stheraven while (buffer < 0) 471227825Stheraven { 472227825Stheraven // While we were sleeping on the lock, another thread might have free'd 473227825Stheraven // enough memory for us to use, so try the allocation again - no point 474227825Stheraven // using the emergency buffer if there is some real memory that we can 475227825Stheraven // use... 476227825Stheraven void *m = calloc(1, size); 477227825Stheraven if (0 != m) 478227825Stheraven { 479232950Stheraven pthread_mutex_unlock(&emergency_malloc_lock); 480278724Sdim return static_cast<char*>(m); 481227825Stheraven } 482227825Stheraven for (int i=0 ; i<16 ; i++) 483227825Stheraven { 484227825Stheraven if (!buffer_allocated[i]) 485227825Stheraven { 486227825Stheraven buffer = i; 487227825Stheraven buffer_allocated[i] = true; 488227825Stheraven break; 489227825Stheraven } 490227825Stheraven } 491227825Stheraven // If there still isn't a buffer available, then sleep on the condition 492227825Stheraven // variable. This will be signalled when another thread releases one 493227825Stheraven // of the emergency buffers. 494227825Stheraven if (buffer < 0) 495227825Stheraven { 496227825Stheraven pthread_cond_wait(&emergency_malloc_wait, &emergency_malloc_lock); 497227825Stheraven } 498227825Stheraven } 499232950Stheraven pthread_mutex_unlock(&emergency_malloc_lock); 500227825Stheraven info->emergencyBuffersHeld++; 501227825Stheraven return emergency_buffer + (1024 * buffer); 502227825Stheraven} 503227825Stheraven 504227825Stheraven/** 505227825Stheraven * Frees a buffer returned by emergency_malloc(). 506227825Stheraven * 507227825Stheraven * Note: Neither this nor emergency_malloc() is particularly efficient. This 508227825Stheraven * should not matter, because neither will be called in normal operation - they 509227825Stheraven * are only used when the program runs out of memory, which should not happen 510227825Stheraven * often. 511227825Stheraven */ 512227825Stheravenstatic void emergency_malloc_free(char *ptr) 513227825Stheraven{ 514227825Stheraven int buffer = -1; 515227825Stheraven // Find the buffer corresponding to this pointer. 516227825Stheraven for (int i=0 ; i<16 ; i++) 517227825Stheraven { 518278724Sdim if (ptr == static_cast<void*>(emergency_buffer + (1024 * i))) 519227825Stheraven { 520227825Stheraven buffer = i; 521227825Stheraven break; 522227825Stheraven } 523227825Stheraven } 524289047Sbdrewery assert(buffer >= 0 && 525227825Stheraven "Trying to free something that is not an emergency buffer!"); 526227825Stheraven // emergency_malloc() is expected to return 0-initialized data. We don't 527227825Stheraven // zero the buffer when allocating it, because the static buffers will 528227825Stheraven // begin life containing 0 values. 529278724Sdim memset(ptr, 0, 1024); 530227825Stheraven // Signal the condition variable to wake up any threads that are blocking 531227825Stheraven // waiting for some space in the emergency buffer 532232950Stheraven pthread_mutex_lock(&emergency_malloc_lock); 533227825Stheraven // In theory, we don't need to do this with the lock held. In practice, 534227825Stheraven // our array of bools will probably be updated using 32-bit or 64-bit 535227825Stheraven // memory operations, so this update may clobber adjacent values. 536227825Stheraven buffer_allocated[buffer] = false; 537232950Stheraven pthread_cond_signal(&emergency_malloc_wait); 538232950Stheraven pthread_mutex_unlock(&emergency_malloc_lock); 539227825Stheraven} 540227825Stheraven 541227825Stheravenstatic char *alloc_or_die(size_t size) 542227825Stheraven{ 543278724Sdim char *buffer = static_cast<char*>(calloc(1, size)); 544227825Stheraven 545227825Stheraven // If calloc() doesn't want to give us any memory, try using an emergency 546227825Stheraven // buffer. 547227825Stheraven if (0 == buffer) 548227825Stheraven { 549227825Stheraven buffer = emergency_malloc(size); 550227825Stheraven // This is only reached if the allocation is greater than 1KB, and 551227825Stheraven // anyone throwing objects that big really should know better. 552227825Stheraven if (0 == buffer) 553227825Stheraven { 554227825Stheraven fprintf(stderr, "Out of memory attempting to allocate exception\n"); 555227825Stheraven std::terminate(); 556227825Stheraven } 557227825Stheraven } 558227825Stheraven return buffer; 559227825Stheraven} 560227825Stheravenstatic void free_exception(char *e) 561227825Stheraven{ 562227825Stheraven // If this allocation is within the address range of the emergency buffer, 563227825Stheraven // don't call free() because it was not allocated with malloc() 564289047Sbdrewery if ((e >= emergency_buffer) && 565227825Stheraven (e < (emergency_buffer + sizeof(emergency_buffer)))) 566227825Stheraven { 567227825Stheraven emergency_malloc_free(e); 568227825Stheraven } 569227825Stheraven else 570227825Stheraven { 571227825Stheraven free(e); 572227825Stheraven } 573227825Stheraven} 574227825Stheraven 575315965Sdim#ifdef __LP64__ 576227825Stheraven/** 577315965Sdim * There's an ABI bug in __cxa_exception: unwindHeader requires 16-byte 578315965Sdim * alignment but it was broken by the addition of the referenceCount. 579315965Sdim * The unwindHeader is at offset 0x58 in __cxa_exception. In order to keep 580315965Sdim * compatibility with consumers of the broken __cxa_exception, explicitly add 581315965Sdim * padding on allocation (and account for it on free). 582315965Sdim */ 583315965Sdimstatic const int exception_alignment_padding = 8; 584315965Sdim#else 585315965Sdimstatic const int exception_alignment_padding = 0; 586315965Sdim#endif 587315965Sdim 588315965Sdim/** 589227825Stheraven * Allocates an exception structure. Returns a pointer to the space that can 590227825Stheraven * be used to store an object of thrown_size bytes. This function will use an 591227825Stheraven * emergency buffer if malloc() fails, and may block if there are no such 592227825Stheraven * buffers available. 593227825Stheraven */ 594227825Stheravenextern "C" void *__cxa_allocate_exception(size_t thrown_size) 595227825Stheraven{ 596315965Sdim size_t size = exception_alignment_padding + sizeof(__cxa_exception) + 597315965Sdim thrown_size; 598227825Stheraven char *buffer = alloc_or_die(size); 599315965Sdim return buffer + exception_alignment_padding + sizeof(__cxa_exception); 600227825Stheraven} 601227825Stheraven 602227825Stheravenextern "C" void *__cxa_allocate_dependent_exception(void) 603227825Stheraven{ 604315965Sdim size_t size = exception_alignment_padding + 605315965Sdim sizeof(__cxa_dependent_exception); 606227825Stheraven char *buffer = alloc_or_die(size); 607315965Sdim return buffer + exception_alignment_padding + 608315965Sdim sizeof(__cxa_dependent_exception); 609227825Stheraven} 610227825Stheraven 611227825Stheraven/** 612227825Stheraven * __cxa_free_exception() is called when an exception was thrown in between 613227825Stheraven * calling __cxa_allocate_exception() and actually throwing the exception. 614227825Stheraven * This happens when the object's copy constructor throws an exception. 615227825Stheraven * 616227825Stheraven * In this implementation, it is also called by __cxa_end_catch() and during 617227825Stheraven * thread cleanup. 618227825Stheraven */ 619227825Stheravenextern "C" void __cxa_free_exception(void *thrown_exception) 620227825Stheraven{ 621278724Sdim __cxa_exception *ex = reinterpret_cast<__cxa_exception*>(thrown_exception) - 1; 622227825Stheraven // Free the object that was thrown, calling its destructor 623227825Stheraven if (0 != ex->exceptionDestructor) 624227825Stheraven { 625227825Stheraven try 626227825Stheraven { 627227825Stheraven ex->exceptionDestructor(thrown_exception); 628227825Stheraven } 629227825Stheraven catch(...) 630227825Stheraven { 631227825Stheraven // FIXME: Check that this is really what the spec says to do. 632227825Stheraven std::terminate(); 633227825Stheraven } 634227825Stheraven } 635227825Stheraven 636315965Sdim free_exception(reinterpret_cast<char*>(ex) - 637315965Sdim exception_alignment_padding); 638227825Stheraven} 639227825Stheraven 640227825Stheravenstatic void releaseException(__cxa_exception *exception) 641227825Stheraven{ 642227825Stheraven if (isDependentException(exception->unwindHeader.exception_class)) 643227825Stheraven { 644227825Stheraven __cxa_free_dependent_exception(exception+1); 645227825Stheraven return; 646227825Stheraven } 647227825Stheraven if (__sync_sub_and_fetch(&exception->referenceCount, 1) == 0) 648227825Stheraven { 649227825Stheraven // __cxa_free_exception() expects to be passed the thrown object, 650227825Stheraven // which immediately follows the exception, not the exception 651227825Stheraven // itself 652227825Stheraven __cxa_free_exception(exception+1); 653227825Stheraven } 654227825Stheraven} 655227825Stheraven 656227825Stheravenvoid __cxa_free_dependent_exception(void *thrown_exception) 657227825Stheraven{ 658278724Sdim __cxa_dependent_exception *ex = reinterpret_cast<__cxa_dependent_exception*>(thrown_exception) - 1; 659227825Stheraven assert(isDependentException(ex->unwindHeader.exception_class)); 660227825Stheraven if (ex->primaryException) 661227825Stheraven { 662278724Sdim releaseException(realExceptionFromException(reinterpret_cast<__cxa_exception*>(ex))); 663227825Stheraven } 664315965Sdim free_exception(reinterpret_cast<char*>(ex) - 665315965Sdim exception_alignment_padding); 666227825Stheraven} 667227825Stheraven 668227825Stheraven/** 669227825Stheraven * Callback function used with _Unwind_Backtrace(). 670227825Stheraven * 671227825Stheraven * Prints a stack trace. Used only for debugging help. 672227825Stheraven * 673227825Stheraven * Note: As of FreeBSD 8.1, dladd() still doesn't work properly, so this only 674227825Stheraven * correctly prints function names from public, relocatable, symbols. 675227825Stheraven */ 676227825Stheravenstatic _Unwind_Reason_Code trace(struct _Unwind_Context *context, void *c) 677227825Stheraven{ 678227825Stheraven Dl_info myinfo; 679227825Stheraven int mylookup = 680278724Sdim dladdr(reinterpret_cast<void *>(__cxa_current_exception_type), &myinfo); 681278724Sdim void *ip = reinterpret_cast<void*>(_Unwind_GetIP(context)); 682227825Stheraven Dl_info info; 683227825Stheraven if (dladdr(ip, &info) != 0) 684227825Stheraven { 685227825Stheraven if (mylookup == 0 || strcmp(info.dli_fname, myinfo.dli_fname) != 0) 686227825Stheraven { 687227825Stheraven printf("%p:%s() in %s\n", ip, info.dli_sname, info.dli_fname); 688227825Stheraven } 689227825Stheraven } 690227825Stheraven return _URC_CONTINUE_UNWIND; 691227825Stheraven} 692227825Stheraven 693227825Stheraven/** 694227825Stheraven * Report a failure that occurred when attempting to throw an exception. 695227825Stheraven * 696227825Stheraven * If the failure happened by falling off the end of the stack without finding 697227825Stheraven * a handler, prints a back trace before aborting. 698227825Stheraven */ 699278724Sdim#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) 700278724Sdimextern "C" void *__cxa_begin_catch(void *e) throw(); 701278724Sdim#else 702278724Sdimextern "C" void *__cxa_begin_catch(void *e); 703278724Sdim#endif 704227825Stheravenstatic void report_failure(_Unwind_Reason_Code err, __cxa_exception *thrown_exception) 705227825Stheraven{ 706227825Stheraven switch (err) 707227825Stheraven { 708227825Stheraven default: break; 709227825Stheraven case _URC_FATAL_PHASE1_ERROR: 710227825Stheraven fprintf(stderr, "Fatal error during phase 1 unwinding\n"); 711227825Stheraven break; 712278724Sdim#if !defined(__arm__) || defined(__ARM_DWARF_EH__) 713227825Stheraven case _URC_FATAL_PHASE2_ERROR: 714227825Stheraven fprintf(stderr, "Fatal error during phase 2 unwinding\n"); 715227825Stheraven break; 716227972Stheraven#endif 717227825Stheraven case _URC_END_OF_STACK: 718278724Sdim __cxa_begin_catch (&(thrown_exception->unwindHeader)); 719278724Sdim std::terminate(); 720227825Stheraven fprintf(stderr, "Terminating due to uncaught exception %p", 721278724Sdim static_cast<void*>(thrown_exception)); 722227825Stheraven thrown_exception = realExceptionFromException(thrown_exception); 723227825Stheraven static const __class_type_info *e_ti = 724227825Stheraven static_cast<const __class_type_info*>(&typeid(std::exception)); 725227825Stheraven const __class_type_info *throw_ti = 726227825Stheraven dynamic_cast<const __class_type_info*>(thrown_exception->exceptionType); 727227825Stheraven if (throw_ti) 728227825Stheraven { 729227825Stheraven std::exception *e = 730278724Sdim static_cast<std::exception*>(e_ti->cast_to(static_cast<void*>(thrown_exception+1), 731278724Sdim throw_ti)); 732227825Stheraven if (e) 733227825Stheraven { 734227825Stheraven fprintf(stderr, " '%s'", e->what()); 735227825Stheraven } 736227825Stheraven } 737227825Stheraven 738227825Stheraven size_t bufferSize = 128; 739278724Sdim char *demangled = static_cast<char*>(malloc(bufferSize)); 740227825Stheraven const char *mangled = thrown_exception->exceptionType->name(); 741227825Stheraven int status; 742227825Stheraven demangled = __cxa_demangle(mangled, demangled, &bufferSize, &status); 743227825Stheraven fprintf(stderr, " of type %s\n", 744278724Sdim status == 0 ? demangled : mangled); 745227825Stheraven if (status == 0) { free(demangled); } 746227825Stheraven // Print a back trace if no handler is found. 747227825Stheraven // TODO: Make this optional 748255093Stheraven#ifndef __arm__ 749227825Stheraven _Unwind_Backtrace(trace, 0); 750255093Stheraven#endif 751278724Sdim 752278724Sdim // Just abort. No need to call std::terminate for the second time 753278724Sdim abort(); 754227825Stheraven break; 755227825Stheraven } 756227825Stheraven std::terminate(); 757227825Stheraven} 758227825Stheraven 759227825Stheravenstatic void throw_exception(__cxa_exception *ex) 760227825Stheraven{ 761227825Stheraven __cxa_thread_info *info = thread_info(); 762227825Stheraven ex->unexpectedHandler = info->unexpectedHandler; 763227825Stheraven if (0 == ex->unexpectedHandler) 764227825Stheraven { 765227825Stheraven ex->unexpectedHandler = unexpectedHandler; 766227825Stheraven } 767227825Stheraven ex->terminateHandler = info->terminateHandler; 768227825Stheraven if (0 == ex->terminateHandler) 769227825Stheraven { 770227825Stheraven ex->terminateHandler = terminateHandler; 771227825Stheraven } 772227825Stheraven info->globals.uncaughtExceptions++; 773227825Stheraven 774227825Stheraven _Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader); 775227825Stheraven // The _Unwind_RaiseException() function should not return, it should 776227825Stheraven // unwind the stack past this function. If it does return, then something 777227825Stheraven // has gone wrong. 778227825Stheraven report_failure(err, ex); 779227825Stheraven} 780227825Stheraven 781227825Stheraven 782227825Stheraven/** 783227825Stheraven * ABI function for throwing an exception. Takes the object to be thrown (the 784227825Stheraven * pointer returned by __cxa_allocate_exception()), the type info for the 785227825Stheraven * pointee, and the destructor (if there is one) as arguments. 786227825Stheraven */ 787227825Stheravenextern "C" void __cxa_throw(void *thrown_exception, 788227825Stheraven std::type_info *tinfo, 789227825Stheraven void(*dest)(void*)) 790227825Stheraven{ 791278724Sdim __cxa_exception *ex = reinterpret_cast<__cxa_exception*>(thrown_exception) - 1; 792227825Stheraven 793227825Stheraven ex->referenceCount = 1; 794227825Stheraven ex->exceptionType = tinfo; 795227825Stheraven 796227825Stheraven ex->exceptionDestructor = dest; 797227825Stheraven 798227825Stheraven ex->unwindHeader.exception_class = exception_class; 799227825Stheraven ex->unwindHeader.exception_cleanup = exception_cleanup; 800227825Stheraven 801227825Stheraven throw_exception(ex); 802227825Stheraven} 803227825Stheraven 804227825Stheravenextern "C" void __cxa_rethrow_primary_exception(void* thrown_exception) 805227825Stheraven{ 806227825Stheraven if (NULL == thrown_exception) { return; } 807227825Stheraven 808227825Stheraven __cxa_exception *original = exceptionFromPointer(thrown_exception); 809278724Sdim __cxa_dependent_exception *ex = reinterpret_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception())-1; 810227825Stheraven 811227825Stheraven ex->primaryException = thrown_exception; 812227825Stheraven __cxa_increment_exception_refcount(thrown_exception); 813227825Stheraven 814227825Stheraven ex->exceptionType = original->exceptionType; 815227825Stheraven ex->unwindHeader.exception_class = dependent_exception_class; 816227825Stheraven ex->unwindHeader.exception_cleanup = dependent_exception_cleanup; 817227825Stheraven 818278724Sdim throw_exception(reinterpret_cast<__cxa_exception*>(ex)); 819227825Stheraven} 820227825Stheraven 821227825Stheravenextern "C" void *__cxa_current_primary_exception(void) 822227825Stheraven{ 823227825Stheraven __cxa_eh_globals* globals = __cxa_get_globals(); 824227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 825227825Stheraven 826227825Stheraven if (0 == ex) { return NULL; } 827227825Stheraven ex = realExceptionFromException(ex); 828227825Stheraven __sync_fetch_and_add(&ex->referenceCount, 1); 829227825Stheraven return ex + 1; 830227825Stheraven} 831227825Stheraven 832227825Stheravenextern "C" void __cxa_increment_exception_refcount(void* thrown_exception) 833227825Stheraven{ 834227825Stheraven if (NULL == thrown_exception) { return; } 835278724Sdim __cxa_exception *ex = static_cast<__cxa_exception*>(thrown_exception) - 1; 836227825Stheraven if (isDependentException(ex->unwindHeader.exception_class)) { return; } 837227825Stheraven __sync_fetch_and_add(&ex->referenceCount, 1); 838227825Stheraven} 839227825Stheravenextern "C" void __cxa_decrement_exception_refcount(void* thrown_exception) 840227825Stheraven{ 841227825Stheraven if (NULL == thrown_exception) { return; } 842278724Sdim __cxa_exception *ex = static_cast<__cxa_exception*>(thrown_exception) - 1; 843227825Stheraven releaseException(ex); 844227825Stheraven} 845227825Stheraven 846227825Stheraven/** 847227825Stheraven * ABI function. Rethrows the current exception. Does not remove the 848227825Stheraven * exception from the stack or decrement its handler count - the compiler is 849227825Stheraven * expected to set the landing pad for this function to the end of the catch 850227825Stheraven * block, and then call _Unwind_Resume() to continue unwinding once 851227825Stheraven * __cxa_end_catch() has been called and any cleanup code has been run. 852227825Stheraven */ 853227825Stheravenextern "C" void __cxa_rethrow() 854227825Stheraven{ 855245745Stheraven __cxa_thread_info *ti = thread_info(); 856245304Stheraven __cxa_eh_globals *globals = &ti->globals; 857227825Stheraven // Note: We don't remove this from the caught list here, because 858227825Stheraven // __cxa_end_catch will be called when we unwind out of the try block. We 859227825Stheraven // could probably make this faster by providing an alternative rethrow 860227825Stheraven // function and ensuring that all cleanup code is run before calling it, so 861227825Stheraven // we can skip the top stack frame when unwinding. 862227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 863227825Stheraven 864227825Stheraven if (0 == ex) 865227825Stheraven { 866227825Stheraven fprintf(stderr, 867227825Stheraven "Attempting to rethrow an exception that doesn't exist!\n"); 868227825Stheraven std::terminate(); 869227825Stheraven } 870227825Stheraven 871245304Stheraven if (ti->foreign_exception_state != __cxa_thread_info::none) 872245304Stheraven { 873245304Stheraven ti->foreign_exception_state = __cxa_thread_info::rethrown; 874278724Sdim _Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(ex); 875245304Stheraven _Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(e); 876245304Stheraven report_failure(err, ex); 877245304Stheraven return; 878245304Stheraven } 879245304Stheraven 880227825Stheraven assert(ex->handlerCount > 0 && "Rethrowing uncaught exception!"); 881227825Stheraven 882227825Stheraven // ex->handlerCount will be decremented in __cxa_end_catch in enclosing 883227825Stheraven // catch block 884227825Stheraven 885227825Stheraven // Make handler count negative. This will tell __cxa_end_catch that 886227825Stheraven // exception was rethrown and exception object should not be destroyed 887227825Stheraven // when handler count become zero 888227825Stheraven ex->handlerCount = -ex->handlerCount; 889227825Stheraven 890227825Stheraven // Continue unwinding the stack with this exception. This should unwind to 891227825Stheraven // the place in the caller where __cxa_end_catch() is called. The caller 892227825Stheraven // will then run cleanup code and bounce the exception back with 893227825Stheraven // _Unwind_Resume(). 894227825Stheraven _Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(&ex->unwindHeader); 895227825Stheraven report_failure(err, ex); 896227825Stheraven} 897227825Stheraven 898227825Stheraven/** 899227825Stheraven * Returns the type_info object corresponding to the filter. 900227825Stheraven */ 901227825Stheravenstatic std::type_info *get_type_info_entry(_Unwind_Context *context, 902227825Stheraven dwarf_eh_lsda *lsda, 903227825Stheraven int filter) 904227825Stheraven{ 905227825Stheraven // Get the address of the record in the table. 906227825Stheraven dw_eh_ptr_t record = lsda->type_table - 907227825Stheraven dwarf_size_of_fixed_size_field(lsda->type_table_encoding)*filter; 908227972Stheraven //record -= 4; 909227825Stheraven dw_eh_ptr_t start = record; 910227825Stheraven // Read the value, but it's probably an indirect reference... 911227825Stheraven int64_t offset = read_value(lsda->type_table_encoding, &record); 912227825Stheraven 913227825Stheraven // (If the entry is 0, don't try to dereference it. That would be bad.) 914227825Stheraven if (offset == 0) { return 0; } 915227825Stheraven 916227825Stheraven // ...so we need to resolve it 917278724Sdim return reinterpret_cast<std::type_info*>(resolve_indirect_value(context, 918278724Sdim lsda->type_table_encoding, offset, start)); 919227825Stheraven} 920227825Stheraven 921227825Stheraven 922227972Stheraven 923227825Stheraven/** 924227825Stheraven * Checks the type signature found in a handler against the type of the thrown 925227825Stheraven * object. If ex is 0 then it is assumed to be a foreign exception and only 926227825Stheraven * matches cleanups. 927227825Stheraven */ 928227825Stheravenstatic bool check_type_signature(__cxa_exception *ex, 929227825Stheraven const std::type_info *type, 930227825Stheraven void *&adjustedPtr) 931227825Stheraven{ 932278724Sdim void *exception_ptr = static_cast<void*>(ex+1); 933245304Stheraven const std::type_info *ex_type = ex ? ex->exceptionType : 0; 934227825Stheraven 935245304Stheraven bool is_ptr = ex ? ex_type->__is_pointer_p() : false; 936233235Stheraven if (is_ptr) 937227825Stheraven { 938278724Sdim exception_ptr = *static_cast<void**>(exception_ptr); 939227825Stheraven } 940227825Stheraven // Always match a catchall, even with a foreign exception 941227825Stheraven // 942227825Stheraven // Note: A 0 here is a catchall, not a cleanup, so we return true to 943227825Stheraven // indicate that we found a catch. 944227825Stheraven if (0 == type) 945227825Stheraven { 946227825Stheraven if (ex) 947227825Stheraven { 948227825Stheraven adjustedPtr = exception_ptr; 949227825Stheraven } 950227825Stheraven return true; 951227825Stheraven } 952227825Stheraven 953227825Stheraven if (0 == ex) { return false; } 954227825Stheraven 955227825Stheraven // If the types are the same, no casting is needed. 956227825Stheraven if (*type == *ex_type) 957227825Stheraven { 958227825Stheraven adjustedPtr = exception_ptr; 959227825Stheraven return true; 960227825Stheraven } 961227825Stheraven 962227825Stheraven 963233235Stheraven if (type->__do_catch(ex_type, &exception_ptr, 1)) 964227825Stheraven { 965233235Stheraven adjustedPtr = exception_ptr; 966227825Stheraven return true; 967227825Stheraven } 968233235Stheraven 969227825Stheraven return false; 970227825Stheraven} 971227825Stheraven/** 972227825Stheraven * Checks whether the exception matches the type specifiers in this action 973227825Stheraven * record. If the exception only matches cleanups, then this returns false. 974227825Stheraven * If it matches a catch (including a catchall) then it returns true. 975227825Stheraven * 976227825Stheraven * The selector argument is used to return the selector that is passed in the 977227825Stheraven * second exception register when installing the context. 978227825Stheraven */ 979227825Stheravenstatic handler_type check_action_record(_Unwind_Context *context, 980227825Stheraven dwarf_eh_lsda *lsda, 981227825Stheraven dw_eh_ptr_t action_record, 982227825Stheraven __cxa_exception *ex, 983227825Stheraven unsigned long *selector, 984227825Stheraven void *&adjustedPtr) 985227825Stheraven{ 986227825Stheraven if (!action_record) { return handler_cleanup; } 987227825Stheraven handler_type found = handler_none; 988227825Stheraven while (action_record) 989227825Stheraven { 990227825Stheraven int filter = read_sleb128(&action_record); 991227825Stheraven dw_eh_ptr_t action_record_offset_base = action_record; 992227825Stheraven int displacement = read_sleb128(&action_record); 993227825Stheraven action_record = displacement ? 994227825Stheraven action_record_offset_base + displacement : 0; 995227825Stheraven // We only check handler types for C++ exceptions - foreign exceptions 996245304Stheraven // are only allowed for cleanups and catchalls. 997245304Stheraven if (filter > 0) 998227825Stheraven { 999227825Stheraven std::type_info *handler_type = get_type_info_entry(context, lsda, filter); 1000227825Stheraven if (check_type_signature(ex, handler_type, adjustedPtr)) 1001227825Stheraven { 1002227825Stheraven *selector = filter; 1003227825Stheraven return handler_catch; 1004227825Stheraven } 1005227825Stheraven } 1006227825Stheraven else if (filter < 0 && 0 != ex) 1007227825Stheraven { 1008227825Stheraven bool matched = false; 1009227825Stheraven *selector = filter; 1010278724Sdim#if defined(__arm__) && !defined(__ARM_DWARF_EH__) 1011227972Stheraven filter++; 1012227972Stheraven std::type_info *handler_type = get_type_info_entry(context, lsda, filter--); 1013227972Stheraven while (handler_type) 1014227972Stheraven { 1015227972Stheraven if (check_type_signature(ex, handler_type, adjustedPtr)) 1016227972Stheraven { 1017227972Stheraven matched = true; 1018227972Stheraven break; 1019227972Stheraven } 1020227972Stheraven handler_type = get_type_info_entry(context, lsda, filter--); 1021227972Stheraven } 1022227972Stheraven#else 1023278724Sdim unsigned char *type_index = reinterpret_cast<unsigned char*>(lsda->type_table) - filter - 1; 1024227825Stheraven while (*type_index) 1025227825Stheraven { 1026227825Stheraven std::type_info *handler_type = get_type_info_entry(context, lsda, *(type_index++)); 1027227825Stheraven // If the exception spec matches a permitted throw type for 1028227825Stheraven // this function, don't report a handler - we are allowed to 1029227825Stheraven // propagate this exception out. 1030227825Stheraven if (check_type_signature(ex, handler_type, adjustedPtr)) 1031227825Stheraven { 1032227825Stheraven matched = true; 1033227825Stheraven break; 1034227825Stheraven } 1035227825Stheraven } 1036227972Stheraven#endif 1037227825Stheraven if (matched) { continue; } 1038227825Stheraven // If we don't find an allowed exception spec, we need to install 1039227825Stheraven // the context for this action. The landing pad will then call the 1040227825Stheraven // unexpected exception function. Treat this as a catch 1041227825Stheraven return handler_catch; 1042227825Stheraven } 1043227825Stheraven else if (filter == 0) 1044227825Stheraven { 1045227825Stheraven *selector = filter; 1046227825Stheraven found = handler_cleanup; 1047227825Stheraven } 1048227825Stheraven } 1049227825Stheraven return found; 1050227825Stheraven} 1051227825Stheraven 1052227972Stheravenstatic void pushCleanupException(_Unwind_Exception *exceptionObject, 1053227972Stheraven __cxa_exception *ex) 1054227972Stheraven{ 1055278724Sdim#if defined(__arm__) && !defined(__ARM_DWARF_EH__) 1056227972Stheraven __cxa_thread_info *info = thread_info_fast(); 1057227972Stheraven if (ex) 1058227972Stheraven { 1059227972Stheraven ex->cleanupCount++; 1060227972Stheraven if (ex->cleanupCount > 1) 1061227972Stheraven { 1062227972Stheraven assert(exceptionObject == info->currentCleanup); 1063227972Stheraven return; 1064227972Stheraven } 1065227972Stheraven ex->nextCleanup = info->currentCleanup; 1066227972Stheraven } 1067227972Stheraven info->currentCleanup = exceptionObject; 1068227972Stheraven#endif 1069227972Stheraven} 1070227972Stheraven 1071227825Stheraven/** 1072227825Stheraven * The exception personality function. This is referenced in the unwinding 1073227825Stheraven * DWARF metadata and is called by the unwind library for each C++ stack frame 1074227825Stheraven * containing catch or cleanup code. 1075227825Stheraven */ 1076227972Stheravenextern "C" 1077227972StheravenBEGIN_PERSONALITY_FUNCTION(__gxx_personality_v0) 1078227825Stheraven // This personality function is for version 1 of the ABI. If you use it 1079227825Stheraven // with a future version of the ABI, it won't know what to do, so it 1080227825Stheraven // reports a fatal error and give up before it breaks anything. 1081227825Stheraven if (1 != version) 1082227825Stheraven { 1083227825Stheraven return _URC_FATAL_PHASE1_ERROR; 1084227825Stheraven } 1085227825Stheraven __cxa_exception *ex = 0; 1086227825Stheraven __cxa_exception *realEx = 0; 1087227825Stheraven 1088227825Stheraven // If this exception is throw by something else then we can't make any 1089227825Stheraven // assumptions about its layout beyond the fields declared in 1090227825Stheraven // _Unwind_Exception. 1091227825Stheraven bool foreignException = !isCXXException(exceptionClass); 1092227825Stheraven 1093227825Stheraven // If this isn't a foreign exception, then we have a C++ exception structure 1094227825Stheraven if (!foreignException) 1095227825Stheraven { 1096227825Stheraven ex = exceptionFromPointer(exceptionObject); 1097227825Stheraven realEx = realExceptionFromException(ex); 1098227825Stheraven } 1099227825Stheraven 1100278724Sdim#if defined(__arm__) && !defined(__ARM_DWARF_EH__) 1101227825Stheraven unsigned char *lsda_addr = 1102278724Sdim static_cast<unsigned char*>(_Unwind_GetLanguageSpecificData(context)); 1103278724Sdim#else 1104278724Sdim unsigned char *lsda_addr = 1105278724Sdim reinterpret_cast<unsigned char*>(static_cast<uintptr_t>(_Unwind_GetLanguageSpecificData(context))); 1106278724Sdim#endif 1107227825Stheraven 1108227825Stheraven // No LSDA implies no landing pads - try the next frame 1109227972Stheraven if (0 == lsda_addr) { return continueUnwinding(exceptionObject, context); } 1110227825Stheraven 1111227825Stheraven // These two variables define how the exception will be handled. 1112227825Stheraven dwarf_eh_action action = {0}; 1113227825Stheraven unsigned long selector = 0; 1114227825Stheraven 1115227825Stheraven // During the search phase, we do a complete lookup. If we return 1116227825Stheraven // _URC_HANDLER_FOUND, then the phase 2 unwind will call this function with 1117227825Stheraven // a _UA_HANDLER_FRAME action, telling us to install the handler frame. If 1118227825Stheraven // we return _URC_CONTINUE_UNWIND, we may be called again later with a 1119227825Stheraven // _UA_CLEANUP_PHASE action for this frame. 1120227825Stheraven // 1121227825Stheraven // The point of the two-stage unwind allows us to entirely avoid any stack 1122227825Stheraven // unwinding if there is no handler. If there are just cleanups found, 1123227825Stheraven // then we can just panic call an abort function. 1124227825Stheraven // 1125227825Stheraven // Matching a handler is much more expensive than matching a cleanup, 1126227825Stheraven // because we don't need to bother doing type comparisons (or looking at 1127227825Stheraven // the type table at all) for a cleanup. This means that there is no need 1128227825Stheraven // to cache the result of finding a cleanup, because it's (quite) quick to 1129227825Stheraven // look it up again from the action table. 1130227825Stheraven if (actions & _UA_SEARCH_PHASE) 1131227825Stheraven { 1132227825Stheraven struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); 1133227825Stheraven 1134227825Stheraven if (!dwarf_eh_find_callsite(context, &lsda, &action)) 1135227825Stheraven { 1136227825Stheraven // EH range not found. This happens if exception is thrown and not 1137227825Stheraven // caught inside a cleanup (destructor). We should call 1138227825Stheraven // terminate() in this case. The catchTemp (landing pad) field of 1139227825Stheraven // exception object will contain null when personality function is 1140227825Stheraven // called with _UA_HANDLER_FRAME action for phase 2 unwinding. 1141227825Stheraven return _URC_HANDLER_FOUND; 1142227825Stheraven } 1143227825Stheraven 1144227825Stheraven handler_type found_handler = check_action_record(context, &lsda, 1145227825Stheraven action.action_record, realEx, &selector, ex->adjustedPtr); 1146227825Stheraven // If there's no action record, we've only found a cleanup, so keep 1147227825Stheraven // searching for something real 1148227825Stheraven if (found_handler == handler_catch) 1149227825Stheraven { 1150227825Stheraven // Cache the results for the phase 2 unwind, if we found a handler 1151227825Stheraven // and this is not a foreign exception. 1152227825Stheraven if (ex) 1153227825Stheraven { 1154227972Stheraven saveLandingPad(context, exceptionObject, ex, selector, action.landing_pad); 1155278724Sdim ex->languageSpecificData = reinterpret_cast<const char*>(lsda_addr); 1156278724Sdim ex->actionRecord = reinterpret_cast<const char*>(action.action_record); 1157227825Stheraven // ex->adjustedPtr is set when finding the action record. 1158227825Stheraven } 1159227825Stheraven return _URC_HANDLER_FOUND; 1160227825Stheraven } 1161227972Stheraven return continueUnwinding(exceptionObject, context); 1162227825Stheraven } 1163227825Stheraven 1164227825Stheraven 1165227825Stheraven // If this is a foreign exception, we didn't have anywhere to cache the 1166227825Stheraven // lookup stuff, so we need to do it again. If this is either a forced 1167227825Stheraven // unwind, a foreign exception, or a cleanup, then we just install the 1168227825Stheraven // context for a cleanup. 1169227825Stheraven if (!(actions & _UA_HANDLER_FRAME)) 1170227825Stheraven { 1171227825Stheraven // cleanup 1172227825Stheraven struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); 1173227825Stheraven dwarf_eh_find_callsite(context, &lsda, &action); 1174227972Stheraven if (0 == action.landing_pad) { return continueUnwinding(exceptionObject, context); } 1175227825Stheraven handler_type found_handler = check_action_record(context, &lsda, 1176227825Stheraven action.action_record, realEx, &selector, ex->adjustedPtr); 1177227825Stheraven // Ignore handlers this time. 1178227972Stheraven if (found_handler != handler_cleanup) { return continueUnwinding(exceptionObject, context); } 1179227972Stheraven pushCleanupException(exceptionObject, ex); 1180227825Stheraven } 1181227825Stheraven else if (foreignException) 1182227825Stheraven { 1183227825Stheraven struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); 1184227825Stheraven dwarf_eh_find_callsite(context, &lsda, &action); 1185227825Stheraven check_action_record(context, &lsda, action.action_record, realEx, 1186227825Stheraven &selector, ex->adjustedPtr); 1187227825Stheraven } 1188227825Stheraven else if (ex->catchTemp == 0) 1189227825Stheraven { 1190227825Stheraven // Uncaught exception in cleanup, calling terminate 1191227825Stheraven std::terminate(); 1192227825Stheraven } 1193227825Stheraven else 1194227825Stheraven { 1195227825Stheraven // Restore the saved info if we saved some last time. 1196227972Stheraven loadLandingPad(context, exceptionObject, ex, &selector, &action.landing_pad); 1197227825Stheraven ex->catchTemp = 0; 1198227825Stheraven ex->handlerSwitchValue = 0; 1199227825Stheraven } 1200227825Stheraven 1201227825Stheraven 1202278724Sdim _Unwind_SetIP(context, reinterpret_cast<unsigned long>(action.landing_pad)); 1203227825Stheraven _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), 1204278724Sdim reinterpret_cast<unsigned long>(exceptionObject)); 1205227825Stheraven _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector); 1206227825Stheraven 1207227825Stheraven return _URC_INSTALL_CONTEXT; 1208227825Stheraven} 1209227825Stheraven 1210227825Stheraven/** 1211227825Stheraven * ABI function called when entering a catch statement. The argument is the 1212227825Stheraven * pointer passed out of the personality function. This is always the start of 1213227825Stheraven * the _Unwind_Exception object. The return value for this function is the 1214227825Stheraven * pointer to the caught exception, which is either the adjusted pointer (for 1215227825Stheraven * C++ exceptions) of the unadjusted pointer (for foreign exceptions). 1216227825Stheraven */ 1217278724Sdim#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) 1218227825Stheravenextern "C" void *__cxa_begin_catch(void *e) throw() 1219227825Stheraven#else 1220227825Stheravenextern "C" void *__cxa_begin_catch(void *e) 1221227825Stheraven#endif 1222227825Stheraven{ 1223245304Stheraven // We can't call the fast version here, because if the first exception that 1224245304Stheraven // we see is a foreign exception then we won't have called it yet. 1225245304Stheraven __cxa_thread_info *ti = thread_info(); 1226245304Stheraven __cxa_eh_globals *globals = &ti->globals; 1227227825Stheraven globals->uncaughtExceptions--; 1228278724Sdim _Unwind_Exception *exceptionObject = static_cast<_Unwind_Exception*>(e); 1229227825Stheraven 1230227825Stheraven if (isCXXException(exceptionObject->exception_class)) 1231227825Stheraven { 1232227825Stheraven __cxa_exception *ex = exceptionFromPointer(exceptionObject); 1233227825Stheraven 1234227825Stheraven if (ex->handlerCount == 0) 1235227825Stheraven { 1236227825Stheraven // Add this to the front of the list of exceptions being handled 1237227825Stheraven // and increment its handler count so that it won't be deleted 1238227825Stheraven // prematurely. 1239227825Stheraven ex->nextException = globals->caughtExceptions; 1240227825Stheraven globals->caughtExceptions = ex; 1241227825Stheraven } 1242227825Stheraven 1243227825Stheraven if (ex->handlerCount < 0) 1244227825Stheraven { 1245227825Stheraven // Rethrown exception is catched before end of catch block. 1246227825Stheraven // Clear the rethrow flag (make value positive) - we are allowed 1247227825Stheraven // to delete this exception at the end of the catch block, as long 1248227825Stheraven // as it isn't thrown again later. 1249227825Stheraven 1250227825Stheraven // Code pattern: 1251227825Stheraven // 1252227825Stheraven // try { 1253227825Stheraven // throw x; 1254227825Stheraven // } 1255227825Stheraven // catch() { 1256227825Stheraven // try { 1257227825Stheraven // throw; 1258227825Stheraven // } 1259227825Stheraven // catch() { 1260227825Stheraven // __cxa_begin_catch() <- we are here 1261227825Stheraven // } 1262227825Stheraven // } 1263227825Stheraven ex->handlerCount = -ex->handlerCount + 1; 1264227825Stheraven } 1265227825Stheraven else 1266227825Stheraven { 1267227825Stheraven ex->handlerCount++; 1268227825Stheraven } 1269245304Stheraven ti->foreign_exception_state = __cxa_thread_info::none; 1270227825Stheraven 1271227825Stheraven return ex->adjustedPtr; 1272227825Stheraven } 1273245304Stheraven else 1274245304Stheraven { 1275245304Stheraven // If this is a foreign exception, then we need to be able to 1276245304Stheraven // store it. We can't chain foreign exceptions, so we give up 1277245304Stheraven // if there are already some outstanding ones. 1278245304Stheraven if (globals->caughtExceptions != 0) 1279245304Stheraven { 1280245304Stheraven std::terminate(); 1281245304Stheraven } 1282278724Sdim globals->caughtExceptions = reinterpret_cast<__cxa_exception*>(exceptionObject); 1283245304Stheraven ti->foreign_exception_state = __cxa_thread_info::caught; 1284245304Stheraven } 1285227825Stheraven // exceptionObject is the pointer to the _Unwind_Exception within the 1286227825Stheraven // __cxa_exception. The throw object is after this 1287278724Sdim return (reinterpret_cast<char*>(exceptionObject) + sizeof(_Unwind_Exception)); 1288227825Stheraven} 1289227825Stheraven 1290227972Stheraven 1291227972Stheraven 1292227825Stheraven/** 1293227825Stheraven * ABI function called when exiting a catch block. This will free the current 1294227825Stheraven * exception if it is no longer referenced in other catch blocks. 1295227825Stheraven */ 1296227825Stheravenextern "C" void __cxa_end_catch() 1297227825Stheraven{ 1298227825Stheraven // We can call the fast version here because the slow version is called in 1299227825Stheraven // __cxa_throw(), which must have been called before we end a catch block 1300245304Stheraven __cxa_thread_info *ti = thread_info_fast(); 1301245304Stheraven __cxa_eh_globals *globals = &ti->globals; 1302227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 1303227825Stheraven 1304227825Stheraven assert(0 != ex && "Ending catch when no exception is on the stack!"); 1305245304Stheraven 1306245304Stheraven if (ti->foreign_exception_state != __cxa_thread_info::none) 1307245304Stheraven { 1308245304Stheraven if (ti->foreign_exception_state != __cxa_thread_info::rethrown) 1309245304Stheraven { 1310278724Sdim _Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(ti->globals.caughtExceptions); 1311315965Sdim if (e->exception_cleanup) 1312315965Sdim e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e); 1313245304Stheraven } 1314315965Sdim globals->caughtExceptions = 0; 1315245304Stheraven ti->foreign_exception_state = __cxa_thread_info::none; 1316245304Stheraven return; 1317245304Stheraven } 1318227825Stheraven 1319227825Stheraven bool deleteException = true; 1320227825Stheraven 1321227825Stheraven if (ex->handlerCount < 0) 1322227825Stheraven { 1323227825Stheraven // exception was rethrown. Exception should not be deleted even if 1324227825Stheraven // handlerCount become zero. 1325227825Stheraven // Code pattern: 1326227825Stheraven // try { 1327227825Stheraven // throw x; 1328227825Stheraven // } 1329227825Stheraven // catch() { 1330227825Stheraven // { 1331227825Stheraven // throw; 1332227825Stheraven // } 1333227825Stheraven // cleanup { 1334227825Stheraven // __cxa_end_catch(); <- we are here 1335227825Stheraven // } 1336227825Stheraven // } 1337227825Stheraven // 1338227825Stheraven 1339227825Stheraven ex->handlerCount++; 1340227825Stheraven deleteException = false; 1341227825Stheraven } 1342227825Stheraven else 1343227825Stheraven { 1344227825Stheraven ex->handlerCount--; 1345227825Stheraven } 1346227825Stheraven 1347227825Stheraven if (ex->handlerCount == 0) 1348227825Stheraven { 1349227825Stheraven globals->caughtExceptions = ex->nextException; 1350227825Stheraven if (deleteException) 1351227825Stheraven { 1352227825Stheraven releaseException(ex); 1353227825Stheraven } 1354227825Stheraven } 1355227825Stheraven} 1356227825Stheraven 1357227825Stheraven/** 1358227825Stheraven * ABI function. Returns the type of the current exception. 1359227825Stheraven */ 1360227825Stheravenextern "C" std::type_info *__cxa_current_exception_type() 1361227825Stheraven{ 1362227825Stheraven __cxa_eh_globals *globals = __cxa_get_globals(); 1363227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 1364227825Stheraven return ex ? ex->exceptionType : 0; 1365227825Stheraven} 1366227825Stheraven 1367227825Stheraven/** 1368227825Stheraven * ABI function, called when an exception specification is violated. 1369227825Stheraven * 1370227825Stheraven * This function does not return. 1371227825Stheraven */ 1372227825Stheravenextern "C" void __cxa_call_unexpected(void*exception) 1373227825Stheraven{ 1374278724Sdim _Unwind_Exception *exceptionObject = static_cast<_Unwind_Exception*>(exception); 1375227825Stheraven if (exceptionObject->exception_class == exception_class) 1376227825Stheraven { 1377227825Stheraven __cxa_exception *ex = exceptionFromPointer(exceptionObject); 1378227825Stheraven if (ex->unexpectedHandler) 1379227825Stheraven { 1380227825Stheraven ex->unexpectedHandler(); 1381227825Stheraven // Should not be reached. 1382227825Stheraven abort(); 1383227825Stheraven } 1384227825Stheraven } 1385227825Stheraven std::unexpected(); 1386227825Stheraven // Should not be reached. 1387227825Stheraven abort(); 1388227825Stheraven} 1389227825Stheraven 1390227825Stheraven/** 1391227825Stheraven * ABI function, returns the adjusted pointer to the exception object. 1392227825Stheraven */ 1393227825Stheravenextern "C" void *__cxa_get_exception_ptr(void *exceptionObject) 1394227825Stheraven{ 1395227825Stheraven return exceptionFromPointer(exceptionObject)->adjustedPtr; 1396227825Stheraven} 1397227825Stheraven 1398227825Stheraven/** 1399227825Stheraven * As an extension, we provide the ability for the unexpected and terminate 1400227825Stheraven * handlers to be thread-local. We default to the standards-compliant 1401227825Stheraven * behaviour where they are global. 1402227825Stheraven */ 1403227825Stheravenstatic bool thread_local_handlers = false; 1404227825Stheraven 1405227825Stheraven 1406227825Stheravennamespace pathscale 1407227825Stheraven{ 1408227825Stheraven /** 1409227825Stheraven * Sets whether unexpected and terminate handlers should be thread-local. 1410227825Stheraven */ 1411227825Stheraven void set_use_thread_local_handlers(bool flag) throw() 1412227825Stheraven { 1413227825Stheraven thread_local_handlers = flag; 1414227825Stheraven } 1415227825Stheraven /** 1416227825Stheraven * Sets a thread-local unexpected handler. 1417227825Stheraven */ 1418227825Stheraven unexpected_handler set_unexpected(unexpected_handler f) throw() 1419227825Stheraven { 1420227825Stheraven static __cxa_thread_info *info = thread_info(); 1421227825Stheraven unexpected_handler old = info->unexpectedHandler; 1422227825Stheraven info->unexpectedHandler = f; 1423227825Stheraven return old; 1424227825Stheraven } 1425227825Stheraven /** 1426227825Stheraven * Sets a thread-local terminate handler. 1427227825Stheraven */ 1428227825Stheraven terminate_handler set_terminate(terminate_handler f) throw() 1429227825Stheraven { 1430227825Stheraven static __cxa_thread_info *info = thread_info(); 1431227825Stheraven terminate_handler old = info->terminateHandler; 1432227825Stheraven info->terminateHandler = f; 1433227825Stheraven return old; 1434227825Stheraven } 1435227825Stheraven} 1436227825Stheraven 1437227825Stheravennamespace std 1438227825Stheraven{ 1439227825Stheraven /** 1440227825Stheraven * Sets the function that will be called when an exception specification is 1441227825Stheraven * violated. 1442227825Stheraven */ 1443227825Stheraven unexpected_handler set_unexpected(unexpected_handler f) throw() 1444227825Stheraven { 1445227825Stheraven if (thread_local_handlers) { return pathscale::set_unexpected(f); } 1446227825Stheraven 1447246462Stheraven return ATOMIC_SWAP(&unexpectedHandler, f); 1448227825Stheraven } 1449227825Stheraven /** 1450227825Stheraven * Sets the function that is called to terminate the program. 1451227825Stheraven */ 1452227825Stheraven terminate_handler set_terminate(terminate_handler f) throw() 1453227825Stheraven { 1454227825Stheraven if (thread_local_handlers) { return pathscale::set_terminate(f); } 1455245304Stheraven 1456245304Stheraven return ATOMIC_SWAP(&terminateHandler, f); 1457227825Stheraven } 1458227825Stheraven /** 1459227825Stheraven * Terminates the program, calling a custom terminate implementation if 1460227825Stheraven * required. 1461227825Stheraven */ 1462227825Stheraven void terminate() 1463227825Stheraven { 1464249993Sdim static __cxa_thread_info *info = thread_info(); 1465227825Stheraven if (0 != info && 0 != info->terminateHandler) 1466227825Stheraven { 1467227825Stheraven info->terminateHandler(); 1468227825Stheraven // Should not be reached - a terminate handler is not expected to 1469227825Stheraven // return. 1470227825Stheraven abort(); 1471227825Stheraven } 1472227825Stheraven terminateHandler(); 1473227825Stheraven } 1474227825Stheraven /** 1475227825Stheraven * Called when an unexpected exception is encountered (i.e. an exception 1476227825Stheraven * violates an exception specification). This calls abort() unless a 1477227825Stheraven * custom handler has been set.. 1478227825Stheraven */ 1479227825Stheraven void unexpected() 1480227825Stheraven { 1481249993Sdim static __cxa_thread_info *info = thread_info(); 1482227825Stheraven if (0 != info && 0 != info->unexpectedHandler) 1483227825Stheraven { 1484227825Stheraven info->unexpectedHandler(); 1485227825Stheraven // Should not be reached - a terminate handler is not expected to 1486227825Stheraven // return. 1487227825Stheraven abort(); 1488227825Stheraven } 1489227825Stheraven unexpectedHandler(); 1490227825Stheraven } 1491227825Stheraven /** 1492227825Stheraven * Returns whether there are any exceptions currently being thrown that 1493227825Stheraven * have not been caught. This can occur inside a nested catch statement. 1494227825Stheraven */ 1495227825Stheraven bool uncaught_exception() throw() 1496227825Stheraven { 1497227825Stheraven __cxa_thread_info *info = thread_info(); 1498227825Stheraven return info->globals.uncaughtExceptions != 0; 1499227825Stheraven } 1500227825Stheraven /** 1501315965Sdim * Returns the number of exceptions currently being thrown that have not 1502315965Sdim * been caught. This can occur inside a nested catch statement. 1503315965Sdim */ 1504315965Sdim int uncaught_exceptions() throw() 1505315965Sdim { 1506315965Sdim __cxa_thread_info *info = thread_info(); 1507315965Sdim return info->globals.uncaughtExceptions; 1508315965Sdim } 1509315965Sdim /** 1510227825Stheraven * Returns the current unexpected handler. 1511227825Stheraven */ 1512227825Stheraven unexpected_handler get_unexpected() throw() 1513227825Stheraven { 1514227825Stheraven __cxa_thread_info *info = thread_info(); 1515227825Stheraven if (info->unexpectedHandler) 1516227825Stheraven { 1517227825Stheraven return info->unexpectedHandler; 1518227825Stheraven } 1519245304Stheraven return ATOMIC_LOAD(&unexpectedHandler); 1520227825Stheraven } 1521227825Stheraven /** 1522227825Stheraven * Returns the current terminate handler. 1523227825Stheraven */ 1524227825Stheraven terminate_handler get_terminate() throw() 1525227825Stheraven { 1526227825Stheraven __cxa_thread_info *info = thread_info(); 1527227825Stheraven if (info->terminateHandler) 1528227825Stheraven { 1529227825Stheraven return info->terminateHandler; 1530227825Stheraven } 1531245304Stheraven return ATOMIC_LOAD(&terminateHandler); 1532227825Stheraven } 1533227825Stheraven} 1534278724Sdim#if defined(__arm__) && !defined(__ARM_DWARF_EH__) 1535227972Stheravenextern "C" _Unwind_Exception *__cxa_get_cleanup(void) 1536227972Stheraven{ 1537227972Stheraven __cxa_thread_info *info = thread_info_fast(); 1538227972Stheraven _Unwind_Exception *exceptionObject = info->currentCleanup; 1539227972Stheraven if (isCXXException(exceptionObject->exception_class)) 1540227972Stheraven { 1541227972Stheraven __cxa_exception *ex = exceptionFromPointer(exceptionObject); 1542227972Stheraven ex->cleanupCount--; 1543227972Stheraven if (ex->cleanupCount == 0) 1544227972Stheraven { 1545227972Stheraven info->currentCleanup = ex->nextCleanup; 1546227972Stheraven ex->nextCleanup = 0; 1547227972Stheraven } 1548227972Stheraven } 1549227972Stheraven else 1550227972Stheraven { 1551227972Stheraven info->currentCleanup = 0; 1552227972Stheraven } 1553227972Stheraven return exceptionObject; 1554227972Stheraven} 1555227972Stheraven 1556227972Stheravenasm ( 1557227972Stheraven".pushsection .text.__cxa_end_cleanup \n" 1558227972Stheraven".global __cxa_end_cleanup \n" 1559227972Stheraven".type __cxa_end_cleanup, \"function\" \n" 1560227972Stheraven"__cxa_end_cleanup: \n" 1561227972Stheraven" push {r1, r2, r3, r4} \n" 1562227972Stheraven" bl __cxa_get_cleanup \n" 1563227972Stheraven" push {r1, r2, r3, r4} \n" 1564227972Stheraven" b _Unwind_Resume \n" 1565227972Stheraven" bl abort \n" 1566227972Stheraven".popsection \n" 1567227972Stheraven); 1568227972Stheraven#endif 1569