exception.cc revision 250241
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" 35250241Sdim#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 42228004Stheraven 43227825Stheravenusing namespace ABI_NAMESPACE; 44227825Stheraven 45227972Stheraven/** 46227972Stheraven * Saves the result of the landing pad that we have found. For ARM, this is 47227972Stheraven * stored in the generic unwind structure, while on other platforms it is 48227972Stheraven * stored in the C++ exception. 49227972Stheraven */ 50227972Stheravenstatic void saveLandingPad(struct _Unwind_Context *context, 51227972Stheraven struct _Unwind_Exception *ucb, 52227972Stheraven struct __cxa_exception *ex, 53227972Stheraven int selector, 54227972Stheraven dw_eh_ptr_t landingPad) 55227972Stheraven{ 56227972Stheraven#ifdef __arm__ 57227972Stheraven // On ARM, we store the saved exception in the generic part of the structure 58227972Stheraven ucb->barrier_cache.sp = _Unwind_GetGR(context, 13); 59227972Stheraven ucb->barrier_cache.bitpattern[1] = (uint32_t)selector; 60227972Stheraven ucb->barrier_cache.bitpattern[3] = (uint32_t)landingPad; 61227972Stheraven#endif 62227972Stheraven // Cache the results for the phase 2 unwind, if we found a handler 63227972Stheraven // and this is not a foreign exception. 64227972Stheraven if (ex) 65227972Stheraven { 66227972Stheraven ex->handlerSwitchValue = selector; 67227972Stheraven ex->catchTemp = landingPad; 68227972Stheraven } 69227972Stheraven} 70227972Stheraven 71227972Stheraven/** 72227972Stheraven * Loads the saved landing pad. Returns 1 on success, 0 on failure. 73227972Stheraven */ 74227972Stheravenstatic int loadLandingPad(struct _Unwind_Context *context, 75227972Stheraven struct _Unwind_Exception *ucb, 76227972Stheraven struct __cxa_exception *ex, 77227972Stheraven unsigned long *selector, 78227972Stheraven dw_eh_ptr_t *landingPad) 79227972Stheraven{ 80227972Stheraven#ifdef __arm__ 81227972Stheraven *selector = ucb->barrier_cache.bitpattern[1]; 82227972Stheraven *landingPad = (dw_eh_ptr_t)ucb->barrier_cache.bitpattern[3]; 83227972Stheraven return 1; 84227972Stheraven#else 85227972Stheraven if (ex) 86227972Stheraven { 87227972Stheraven *selector = ex->handlerSwitchValue; 88227972Stheraven *landingPad = (dw_eh_ptr_t)ex->catchTemp; 89227972Stheraven return 0; 90227972Stheraven } 91227972Stheraven return 0; 92227972Stheraven#endif 93227972Stheraven} 94227972Stheraven 95227972Stheravenstatic inline _Unwind_Reason_Code continueUnwinding(struct _Unwind_Exception *ex, 96227972Stheraven struct _Unwind_Context *context) 97227972Stheraven{ 98227972Stheraven#ifdef __arm__ 99227972Stheraven if (__gnu_unwind_frame(ex, context) != _URC_OK) { return _URC_FAILURE; } 100227972Stheraven#endif 101227972Stheraven return _URC_CONTINUE_UNWIND; 102227972Stheraven} 103227972Stheraven 104227972Stheraven 105227825Stheravenextern "C" void __cxa_free_exception(void *thrown_exception); 106227825Stheravenextern "C" void __cxa_free_dependent_exception(void *thrown_exception); 107227825Stheravenextern "C" void* __dynamic_cast(const void *sub, 108227825Stheraven const __class_type_info *src, 109227825Stheraven const __class_type_info *dst, 110227825Stheraven ptrdiff_t src2dst_offset); 111227825Stheraven 112227825Stheraven/** 113227825Stheraven * The type of a handler that has been found. 114227825Stheraven */ 115227825Stheraventypedef enum 116227825Stheraven{ 117227825Stheraven /** No handler. */ 118227825Stheraven handler_none, 119227825Stheraven /** 120227825Stheraven * A cleanup - the exception will propagate through this frame, but code 121227825Stheraven * must be run when this happens. 122227825Stheraven */ 123227825Stheraven handler_cleanup, 124227825Stheraven /** 125227825Stheraven * A catch statement. The exception will not propagate past this frame 126227825Stheraven * (without an explicit rethrow). 127227825Stheraven */ 128227825Stheraven handler_catch 129227825Stheraven} handler_type; 130227825Stheraven 131227825Stheraven/** 132227825Stheraven * Per-thread info required by the runtime. We store a single structure 133227825Stheraven * pointer in thread-local storage, because this tends to be a scarce resource 134227825Stheraven * and it's impolite to steal all of it and not leave any for the rest of the 135227825Stheraven * program. 136227825Stheraven * 137227825Stheraven * Instances of this structure are allocated lazily - at most one per thread - 138227825Stheraven * and are destroyed on thread termination. 139227825Stheraven */ 140227825Stheravenstruct __cxa_thread_info 141227825Stheraven{ 142227825Stheraven /** The termination handler for this thread. */ 143227825Stheraven terminate_handler terminateHandler; 144227825Stheraven /** The unexpected exception handler for this thread. */ 145227825Stheraven unexpected_handler unexpectedHandler; 146227825Stheraven /** 147227825Stheraven * The number of emergency buffers held by this thread. This is 0 in 148227825Stheraven * normal operation - the emergency buffers are only used when malloc() 149227825Stheraven * fails to return memory for allocating an exception. Threads are not 150227825Stheraven * permitted to hold more than 4 emergency buffers (as per recommendation 151227825Stheraven * in ABI spec [3.3.1]). 152227825Stheraven */ 153227825Stheraven int emergencyBuffersHeld; 154227825Stheraven /** 155227972Stheraven * The exception currently running in a cleanup. 156227972Stheraven */ 157227972Stheraven _Unwind_Exception *currentCleanup; 158227972Stheraven /** 159250241Sdim * Our state with respect to foreign exceptions. Usually none, set to 160250241Sdim * caught if we have just caught an exception and rethrown if we are 161250241Sdim * rethrowing it. 162250241Sdim */ 163250241Sdim enum 164250241Sdim { 165250241Sdim none, 166250241Sdim caught, 167250241Sdim rethrown 168250241Sdim } foreign_exception_state; 169250241Sdim /** 170227825Stheraven * The public part of this structure, accessible from outside of this 171227825Stheraven * module. 172227825Stheraven */ 173227825Stheraven __cxa_eh_globals globals; 174227825Stheraven}; 175227825Stheraven/** 176227825Stheraven * Dependent exception. This 177227825Stheraven */ 178227825Stheravenstruct __cxa_dependent_exception 179227825Stheraven{ 180227825Stheraven#if __LP64__ 181227825Stheraven void *primaryException; 182227825Stheraven#endif 183227825Stheraven std::type_info *exceptionType; 184227825Stheraven void (*exceptionDestructor) (void *); 185227825Stheraven unexpected_handler unexpectedHandler; 186227825Stheraven terminate_handler terminateHandler; 187227825Stheraven __cxa_exception *nextException; 188227825Stheraven int handlerCount; 189227972Stheraven#ifdef __arm__ 190227972Stheraven _Unwind_Exception *nextCleanup; 191227972Stheraven int cleanupCount; 192227972Stheraven#endif 193227825Stheraven int handlerSwitchValue; 194227825Stheraven const char *actionRecord; 195227825Stheraven const char *languageSpecificData; 196227825Stheraven void *catchTemp; 197227825Stheraven void *adjustedPtr; 198227825Stheraven#if !__LP64__ 199227825Stheraven void *primaryException; 200227825Stheraven#endif 201227825Stheraven _Unwind_Exception unwindHeader; 202227825Stheraven}; 203227825Stheraven 204227825Stheraven 205227825Stheravennamespace std 206227825Stheraven{ 207227825Stheraven void unexpected(); 208227825Stheraven class exception 209227825Stheraven { 210227825Stheraven public: 211227825Stheraven virtual ~exception() throw(); 212227825Stheraven virtual const char* what() const throw(); 213227825Stheraven }; 214227825Stheraven 215227825Stheraven} 216227825Stheraven 217227825Stheravenextern "C" std::type_info *__cxa_current_exception_type(); 218227825Stheraven 219227825Stheraven/** 220227825Stheraven * Class of exceptions to distinguish between this and other exception types. 221227825Stheraven * 222227825Stheraven * The first four characters are the vendor ID. Currently, we use GNUC, 223227825Stheraven * because we aim for ABI-compatibility with the GNU implementation, and 224227825Stheraven * various checks may test for equality of the class, which is incorrect. 225227825Stheraven */ 226227825Stheravenstatic const uint64_t exception_class = 227227825Stheraven EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\0'); 228227825Stheraven/** 229227825Stheraven * Class used for dependent exceptions. 230227825Stheraven */ 231227825Stheravenstatic const uint64_t dependent_exception_class = 232227825Stheraven EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\x01'); 233227825Stheraven/** 234227825Stheraven * The low four bytes of the exception class, indicating that we conform to the 235227825Stheraven * Itanium C++ ABI. This is currently unused, but should be used in the future 236227825Stheraven * if we change our exception class, to allow this library and libsupc++ to be 237227825Stheraven * linked to the same executable and both to interoperate. 238227825Stheraven */ 239227825Stheravenstatic const uint32_t abi_exception_class = 240227825Stheraven GENERIC_EXCEPTION_CLASS('C', '+', '+', '\0'); 241227825Stheraven 242227825Stheravenstatic bool isCXXException(uint64_t cls) 243227825Stheraven{ 244227825Stheraven return (cls == exception_class) || (cls == dependent_exception_class); 245227825Stheraven} 246227825Stheraven 247227825Stheravenstatic bool isDependentException(uint64_t cls) 248227825Stheraven{ 249227825Stheraven return cls == dependent_exception_class; 250227825Stheraven} 251227825Stheraven 252227825Stheravenstatic __cxa_exception *exceptionFromPointer(void *ex) 253227825Stheraven{ 254227825Stheraven return (__cxa_exception*)((char*)ex - 255227825Stheraven offsetof(struct __cxa_exception, unwindHeader)); 256227825Stheraven} 257227825Stheravenstatic __cxa_exception *realExceptionFromException(__cxa_exception *ex) 258227825Stheraven{ 259227825Stheraven if (!isDependentException(ex->unwindHeader.exception_class)) { return ex; } 260227825Stheraven return ((__cxa_exception*)(((__cxa_dependent_exception*)ex)->primaryException))-1; 261227825Stheraven} 262227825Stheraven 263227825Stheraven 264227825Stheravennamespace std 265227825Stheraven{ 266227825Stheraven // Forward declaration of standard library terminate() function used to 267227825Stheraven // abort execution. 268227825Stheraven void terminate(void); 269227825Stheraven} 270227825Stheraven 271227825Stheravenusing namespace ABI_NAMESPACE; 272227825Stheraven 273227825Stheraven 274227825Stheraven 275227825Stheraven/** The global termination handler. */ 276227825Stheravenstatic terminate_handler terminateHandler = abort; 277227825Stheraven/** The global unexpected exception handler. */ 278227825Stheravenstatic unexpected_handler unexpectedHandler = std::terminate; 279227825Stheraven 280227825Stheraven/** Key used for thread-local data. */ 281227825Stheravenstatic pthread_key_t eh_key; 282227825Stheraven 283227825Stheraven 284227825Stheraven/** 285227825Stheraven * Cleanup function, allowing foreign exception handlers to correctly destroy 286227825Stheraven * this exception if they catch it. 287227825Stheraven */ 288227825Stheravenstatic void exception_cleanup(_Unwind_Reason_Code reason, 289227825Stheraven struct _Unwind_Exception *ex) 290227825Stheraven{ 291227825Stheraven __cxa_free_exception((void*)ex); 292227825Stheraven} 293227825Stheravenstatic void dependent_exception_cleanup(_Unwind_Reason_Code reason, 294227825Stheraven struct _Unwind_Exception *ex) 295227825Stheraven{ 296227825Stheraven 297227825Stheraven __cxa_free_dependent_exception((void*)ex); 298227825Stheraven} 299227825Stheraven 300227825Stheraven/** 301227825Stheraven * Recursively walk a list of exceptions and delete them all in post-order. 302227825Stheraven */ 303227825Stheravenstatic void free_exception_list(__cxa_exception *ex) 304227825Stheraven{ 305227825Stheraven if (0 != ex->nextException) 306227825Stheraven { 307227825Stheraven free_exception_list(ex->nextException); 308227825Stheraven } 309227825Stheraven // __cxa_free_exception() expects to be passed the thrown object, which 310227825Stheraven // immediately follows the exception, not the exception itself 311227825Stheraven __cxa_free_exception(ex+1); 312227825Stheraven} 313227825Stheraven 314227825Stheraven/** 315227825Stheraven * Cleanup function called when a thread exists to make certain that all of the 316227825Stheraven * per-thread data is deleted. 317227825Stheraven */ 318227825Stheravenstatic void thread_cleanup(void* thread_info) 319227825Stheraven{ 320227825Stheraven __cxa_thread_info *info = (__cxa_thread_info*)thread_info; 321227825Stheraven if (info->globals.caughtExceptions) 322227825Stheraven { 323250241Sdim // If this is a foreign exception, ask it to clean itself up. 324250241Sdim if (info->foreign_exception_state != __cxa_thread_info::none) 325250241Sdim { 326250241Sdim _Unwind_Exception *e = (_Unwind_Exception*)info->globals.caughtExceptions; 327250241Sdim e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e); 328250241Sdim } 329250241Sdim else 330250241Sdim { 331250241Sdim free_exception_list(info->globals.caughtExceptions); 332250241Sdim } 333227825Stheraven } 334227825Stheraven free(thread_info); 335227825Stheraven} 336227825Stheraven 337227825Stheraven 338227825Stheraven/** 339227825Stheraven * Once control used to protect the key creation. 340227825Stheraven */ 341227825Stheravenstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 342227825Stheraven 343227825Stheraven/** 344228004Stheraven * We may not be linked against a full pthread implementation. If we're not, 345228004Stheraven * then we need to fake the thread-local storage by storing 'thread-local' 346228004Stheraven * things in a global. 347228004Stheraven */ 348228004Stheravenstatic bool fakeTLS; 349228004Stheraven/** 350228004Stheraven * Thread-local storage for a single-threaded program. 351228004Stheraven */ 352228004Stheravenstatic __cxa_thread_info singleThreadInfo; 353228004Stheraven/** 354227825Stheraven * Initialise eh_key. 355227825Stheraven */ 356227825Stheravenstatic void init_key(void) 357227825Stheraven{ 358228004Stheraven if ((0 == pthread_key_create) || 359228004Stheraven (0 == pthread_setspecific) || 360228004Stheraven (0 == pthread_getspecific)) 361228004Stheraven { 362228004Stheraven fakeTLS = true; 363228004Stheraven return; 364228004Stheraven } 365227825Stheraven pthread_key_create(&eh_key, thread_cleanup); 366228004Stheraven pthread_setspecific(eh_key, (void*)0x42); 367228004Stheraven fakeTLS = (pthread_getspecific(eh_key) != (void*)0x42); 368228004Stheraven pthread_setspecific(eh_key, 0); 369227825Stheraven} 370227825Stheraven 371227825Stheraven/** 372227825Stheraven * Returns the thread info structure, creating it if it is not already created. 373227825Stheraven */ 374227825Stheravenstatic __cxa_thread_info *thread_info() 375227825Stheraven{ 376228004Stheraven if ((0 == pthread_once) || pthread_once(&once_control, init_key)) 377228004Stheraven { 378228004Stheraven fakeTLS = true; 379228004Stheraven } 380228004Stheraven if (fakeTLS) { return &singleThreadInfo; } 381227825Stheraven __cxa_thread_info *info = (__cxa_thread_info*)pthread_getspecific(eh_key); 382227825Stheraven if (0 == info) 383227825Stheraven { 384227825Stheraven info = (__cxa_thread_info*)calloc(1, sizeof(__cxa_thread_info)); 385227825Stheraven pthread_setspecific(eh_key, info); 386227825Stheraven } 387227825Stheraven return info; 388227825Stheraven} 389227825Stheraven/** 390227825Stheraven * Fast version of thread_info(). May fail if thread_info() is not called on 391227825Stheraven * this thread at least once already. 392227825Stheraven */ 393227825Stheravenstatic __cxa_thread_info *thread_info_fast() 394227825Stheraven{ 395228004Stheraven if (fakeTLS) { return &singleThreadInfo; } 396227825Stheraven return (__cxa_thread_info*)pthread_getspecific(eh_key); 397227825Stheraven} 398227825Stheraven/** 399227825Stheraven * ABI function returning the __cxa_eh_globals structure. 400227825Stheraven */ 401227825Stheravenextern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals(void) 402227825Stheraven{ 403227825Stheraven return &(thread_info()->globals); 404227825Stheraven} 405227825Stheraven/** 406227825Stheraven * Version of __cxa_get_globals() assuming that __cxa_get_globals() has already 407227825Stheraven * been called at least once by this thread. 408227825Stheraven */ 409227825Stheravenextern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals_fast(void) 410227825Stheraven{ 411227825Stheraven return &(thread_info_fast()->globals); 412227825Stheraven} 413227825Stheraven 414227825Stheraven/** 415227825Stheraven * An emergency allocation reserved for when malloc fails. This is treated as 416227825Stheraven * 16 buffers of 1KB each. 417227825Stheraven */ 418227825Stheravenstatic char emergency_buffer[16384]; 419227825Stheraven/** 420227825Stheraven * Flag indicating whether each buffer is allocated. 421227825Stheraven */ 422227825Stheravenstatic bool buffer_allocated[16]; 423227825Stheraven/** 424227825Stheraven * Lock used to protect emergency allocation. 425227825Stheraven */ 426227825Stheravenstatic pthread_mutex_t emergency_malloc_lock = PTHREAD_MUTEX_INITIALIZER; 427227825Stheraven/** 428227825Stheraven * Condition variable used to wait when two threads are both trying to use the 429227825Stheraven * emergency malloc() buffer at once. 430227825Stheraven */ 431227825Stheravenstatic pthread_cond_t emergency_malloc_wait = PTHREAD_COND_INITIALIZER; 432227825Stheraven 433227825Stheraven/** 434227825Stheraven * Allocates size bytes from the emergency allocation mechanism, if possible. 435227825Stheraven * This function will fail if size is over 1KB or if this thread already has 4 436227825Stheraven * emergency buffers. If all emergency buffers are allocated, it will sleep 437227825Stheraven * until one becomes available. 438227825Stheraven */ 439227825Stheravenstatic char *emergency_malloc(size_t size) 440227825Stheraven{ 441227825Stheraven if (size > 1024) { return 0; } 442227825Stheraven 443227825Stheraven __cxa_thread_info *info = thread_info(); 444227825Stheraven // Only 4 emergency buffers allowed per thread! 445227825Stheraven if (info->emergencyBuffersHeld > 3) { return 0; } 446227825Stheraven 447232950Stheraven pthread_mutex_lock(&emergency_malloc_lock); 448227825Stheraven int buffer = -1; 449227825Stheraven while (buffer < 0) 450227825Stheraven { 451227825Stheraven // While we were sleeping on the lock, another thread might have free'd 452227825Stheraven // enough memory for us to use, so try the allocation again - no point 453227825Stheraven // using the emergency buffer if there is some real memory that we can 454227825Stheraven // use... 455227825Stheraven void *m = calloc(1, size); 456227825Stheraven if (0 != m) 457227825Stheraven { 458232950Stheraven pthread_mutex_unlock(&emergency_malloc_lock); 459227825Stheraven return (char*)m; 460227825Stheraven } 461227825Stheraven for (int i=0 ; i<16 ; i++) 462227825Stheraven { 463227825Stheraven if (!buffer_allocated[i]) 464227825Stheraven { 465227825Stheraven buffer = i; 466227825Stheraven buffer_allocated[i] = true; 467227825Stheraven break; 468227825Stheraven } 469227825Stheraven } 470227825Stheraven // If there still isn't a buffer available, then sleep on the condition 471227825Stheraven // variable. This will be signalled when another thread releases one 472227825Stheraven // of the emergency buffers. 473227825Stheraven if (buffer < 0) 474227825Stheraven { 475227825Stheraven pthread_cond_wait(&emergency_malloc_wait, &emergency_malloc_lock); 476227825Stheraven } 477227825Stheraven } 478232950Stheraven pthread_mutex_unlock(&emergency_malloc_lock); 479227825Stheraven info->emergencyBuffersHeld++; 480227825Stheraven return emergency_buffer + (1024 * buffer); 481227825Stheraven} 482227825Stheraven 483227825Stheraven/** 484227825Stheraven * Frees a buffer returned by emergency_malloc(). 485227825Stheraven * 486227825Stheraven * Note: Neither this nor emergency_malloc() is particularly efficient. This 487227825Stheraven * should not matter, because neither will be called in normal operation - they 488227825Stheraven * are only used when the program runs out of memory, which should not happen 489227825Stheraven * often. 490227825Stheraven */ 491227825Stheravenstatic void emergency_malloc_free(char *ptr) 492227825Stheraven{ 493227825Stheraven int buffer = -1; 494227825Stheraven // Find the buffer corresponding to this pointer. 495227825Stheraven for (int i=0 ; i<16 ; i++) 496227825Stheraven { 497227825Stheraven if (ptr == (void*)(emergency_buffer + (1024 * i))) 498227825Stheraven { 499227825Stheraven buffer = i; 500227825Stheraven break; 501227825Stheraven } 502227825Stheraven } 503227825Stheraven assert(buffer > 0 && 504227825Stheraven "Trying to free something that is not an emergency buffer!"); 505227825Stheraven // emergency_malloc() is expected to return 0-initialized data. We don't 506227825Stheraven // zero the buffer when allocating it, because the static buffers will 507227825Stheraven // begin life containing 0 values. 508227825Stheraven memset((void*)ptr, 0, 1024); 509227825Stheraven // Signal the condition variable to wake up any threads that are blocking 510227825Stheraven // waiting for some space in the emergency buffer 511232950Stheraven pthread_mutex_lock(&emergency_malloc_lock); 512227825Stheraven // In theory, we don't need to do this with the lock held. In practice, 513227825Stheraven // our array of bools will probably be updated using 32-bit or 64-bit 514227825Stheraven // memory operations, so this update may clobber adjacent values. 515227825Stheraven buffer_allocated[buffer] = false; 516232950Stheraven pthread_cond_signal(&emergency_malloc_wait); 517232950Stheraven pthread_mutex_unlock(&emergency_malloc_lock); 518227825Stheraven} 519227825Stheraven 520227825Stheravenstatic char *alloc_or_die(size_t size) 521227825Stheraven{ 522227825Stheraven char *buffer = (char*)calloc(1, size); 523227825Stheraven 524227825Stheraven // If calloc() doesn't want to give us any memory, try using an emergency 525227825Stheraven // buffer. 526227825Stheraven if (0 == buffer) 527227825Stheraven { 528227825Stheraven buffer = emergency_malloc(size); 529227825Stheraven // This is only reached if the allocation is greater than 1KB, and 530227825Stheraven // anyone throwing objects that big really should know better. 531227825Stheraven if (0 == buffer) 532227825Stheraven { 533227825Stheraven fprintf(stderr, "Out of memory attempting to allocate exception\n"); 534227825Stheraven std::terminate(); 535227825Stheraven } 536227825Stheraven } 537227825Stheraven return buffer; 538227825Stheraven} 539227825Stheravenstatic void free_exception(char *e) 540227825Stheraven{ 541227825Stheraven // If this allocation is within the address range of the emergency buffer, 542227825Stheraven // don't call free() because it was not allocated with malloc() 543227825Stheraven if ((e > emergency_buffer) && 544227825Stheraven (e < (emergency_buffer + sizeof(emergency_buffer)))) 545227825Stheraven { 546227825Stheraven emergency_malloc_free(e); 547227825Stheraven } 548227825Stheraven else 549227825Stheraven { 550227825Stheraven free(e); 551227825Stheraven } 552227825Stheraven} 553227825Stheraven 554227825Stheraven/** 555227825Stheraven * Allocates an exception structure. Returns a pointer to the space that can 556227825Stheraven * be used to store an object of thrown_size bytes. This function will use an 557227825Stheraven * emergency buffer if malloc() fails, and may block if there are no such 558227825Stheraven * buffers available. 559227825Stheraven */ 560227825Stheravenextern "C" void *__cxa_allocate_exception(size_t thrown_size) 561227825Stheraven{ 562227825Stheraven size_t size = thrown_size + sizeof(__cxa_exception); 563227825Stheraven char *buffer = alloc_or_die(size); 564227825Stheraven return buffer+sizeof(__cxa_exception); 565227825Stheraven} 566227825Stheraven 567227825Stheravenextern "C" void *__cxa_allocate_dependent_exception(void) 568227825Stheraven{ 569227825Stheraven size_t size = sizeof(__cxa_dependent_exception); 570227825Stheraven char *buffer = alloc_or_die(size); 571227825Stheraven return buffer+sizeof(__cxa_dependent_exception); 572227825Stheraven} 573227825Stheraven 574227825Stheraven/** 575227825Stheraven * __cxa_free_exception() is called when an exception was thrown in between 576227825Stheraven * calling __cxa_allocate_exception() and actually throwing the exception. 577227825Stheraven * This happens when the object's copy constructor throws an exception. 578227825Stheraven * 579227825Stheraven * In this implementation, it is also called by __cxa_end_catch() and during 580227825Stheraven * thread cleanup. 581227825Stheraven */ 582227825Stheravenextern "C" void __cxa_free_exception(void *thrown_exception) 583227825Stheraven{ 584227825Stheraven __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1; 585227825Stheraven // Free the object that was thrown, calling its destructor 586227825Stheraven if (0 != ex->exceptionDestructor) 587227825Stheraven { 588227825Stheraven try 589227825Stheraven { 590227825Stheraven ex->exceptionDestructor(thrown_exception); 591227825Stheraven } 592227825Stheraven catch(...) 593227825Stheraven { 594227825Stheraven // FIXME: Check that this is really what the spec says to do. 595227825Stheraven std::terminate(); 596227825Stheraven } 597227825Stheraven } 598227825Stheraven 599227825Stheraven free_exception((char*)ex); 600227825Stheraven} 601227825Stheraven 602227825Stheravenstatic void releaseException(__cxa_exception *exception) 603227825Stheraven{ 604227825Stheraven if (isDependentException(exception->unwindHeader.exception_class)) 605227825Stheraven { 606227825Stheraven __cxa_free_dependent_exception(exception+1); 607227825Stheraven return; 608227825Stheraven } 609227825Stheraven if (__sync_sub_and_fetch(&exception->referenceCount, 1) == 0) 610227825Stheraven { 611227825Stheraven // __cxa_free_exception() expects to be passed the thrown object, 612227825Stheraven // which immediately follows the exception, not the exception 613227825Stheraven // itself 614227825Stheraven __cxa_free_exception(exception+1); 615227825Stheraven } 616227825Stheraven} 617227825Stheraven 618227825Stheravenvoid __cxa_free_dependent_exception(void *thrown_exception) 619227825Stheraven{ 620227825Stheraven __cxa_dependent_exception *ex = ((__cxa_dependent_exception*)thrown_exception) - 1; 621227825Stheraven assert(isDependentException(ex->unwindHeader.exception_class)); 622227825Stheraven if (ex->primaryException) 623227825Stheraven { 624227825Stheraven releaseException(realExceptionFromException((__cxa_exception*)ex)); 625227825Stheraven } 626227825Stheraven free_exception((char*)ex); 627227825Stheraven} 628227825Stheraven 629227825Stheraven/** 630227825Stheraven * Callback function used with _Unwind_Backtrace(). 631227825Stheraven * 632227825Stheraven * Prints a stack trace. Used only for debugging help. 633227825Stheraven * 634227825Stheraven * Note: As of FreeBSD 8.1, dladd() still doesn't work properly, so this only 635227825Stheraven * correctly prints function names from public, relocatable, symbols. 636227825Stheraven */ 637227825Stheravenstatic _Unwind_Reason_Code trace(struct _Unwind_Context *context, void *c) 638227825Stheraven{ 639227825Stheraven Dl_info myinfo; 640227825Stheraven int mylookup = 641227825Stheraven dladdr((void*)(uintptr_t)__cxa_current_exception_type, &myinfo); 642227825Stheraven void *ip = (void*)_Unwind_GetIP(context); 643227825Stheraven Dl_info info; 644227825Stheraven if (dladdr(ip, &info) != 0) 645227825Stheraven { 646227825Stheraven if (mylookup == 0 || strcmp(info.dli_fname, myinfo.dli_fname) != 0) 647227825Stheraven { 648227825Stheraven printf("%p:%s() in %s\n", ip, info.dli_sname, info.dli_fname); 649227825Stheraven } 650227825Stheraven } 651227825Stheraven return _URC_CONTINUE_UNWIND; 652227825Stheraven} 653227825Stheraven 654227825Stheraven/** 655227825Stheraven * Report a failure that occurred when attempting to throw an exception. 656227825Stheraven * 657227825Stheraven * If the failure happened by falling off the end of the stack without finding 658227825Stheraven * a handler, prints a back trace before aborting. 659227825Stheraven */ 660227825Stheravenstatic void report_failure(_Unwind_Reason_Code err, __cxa_exception *thrown_exception) 661227825Stheraven{ 662227825Stheraven switch (err) 663227825Stheraven { 664227825Stheraven default: break; 665227825Stheraven case _URC_FATAL_PHASE1_ERROR: 666227825Stheraven fprintf(stderr, "Fatal error during phase 1 unwinding\n"); 667227825Stheraven break; 668227972Stheraven#ifndef __arm__ 669227825Stheraven case _URC_FATAL_PHASE2_ERROR: 670227825Stheraven fprintf(stderr, "Fatal error during phase 2 unwinding\n"); 671227825Stheraven break; 672227972Stheraven#endif 673227825Stheraven case _URC_END_OF_STACK: 674227825Stheraven fprintf(stderr, "Terminating due to uncaught exception %p", 675227825Stheraven (void*)thrown_exception); 676227825Stheraven thrown_exception = realExceptionFromException(thrown_exception); 677227825Stheraven static const __class_type_info *e_ti = 678227825Stheraven static_cast<const __class_type_info*>(&typeid(std::exception)); 679227825Stheraven const __class_type_info *throw_ti = 680227825Stheraven dynamic_cast<const __class_type_info*>(thrown_exception->exceptionType); 681227825Stheraven if (throw_ti) 682227825Stheraven { 683227825Stheraven std::exception *e = 684227825Stheraven (std::exception*)e_ti->cast_to((void*)(thrown_exception+1), 685227825Stheraven throw_ti); 686227825Stheraven if (e) 687227825Stheraven { 688227825Stheraven fprintf(stderr, " '%s'", e->what()); 689227825Stheraven } 690227825Stheraven } 691227825Stheraven 692227825Stheraven size_t bufferSize = 128; 693227825Stheraven char *demangled = (char*)malloc(bufferSize); 694227825Stheraven const char *mangled = thrown_exception->exceptionType->name(); 695227825Stheraven int status; 696227825Stheraven demangled = __cxa_demangle(mangled, demangled, &bufferSize, &status); 697227825Stheraven fprintf(stderr, " of type %s\n", 698227825Stheraven status == 0 ? (const char*)demangled : mangled); 699227825Stheraven if (status == 0) { free(demangled); } 700227825Stheraven // Print a back trace if no handler is found. 701227825Stheraven // TODO: Make this optional 702227825Stheraven _Unwind_Backtrace(trace, 0); 703227825Stheraven break; 704227825Stheraven } 705227825Stheraven std::terminate(); 706227825Stheraven} 707227825Stheraven 708227825Stheravenstatic void throw_exception(__cxa_exception *ex) 709227825Stheraven{ 710227825Stheraven __cxa_thread_info *info = thread_info(); 711227825Stheraven ex->unexpectedHandler = info->unexpectedHandler; 712227825Stheraven if (0 == ex->unexpectedHandler) 713227825Stheraven { 714227825Stheraven ex->unexpectedHandler = unexpectedHandler; 715227825Stheraven } 716227825Stheraven ex->terminateHandler = info->terminateHandler; 717227825Stheraven if (0 == ex->terminateHandler) 718227825Stheraven { 719227825Stheraven ex->terminateHandler = terminateHandler; 720227825Stheraven } 721227825Stheraven info->globals.uncaughtExceptions++; 722227825Stheraven 723227825Stheraven _Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader); 724227825Stheraven // The _Unwind_RaiseException() function should not return, it should 725227825Stheraven // unwind the stack past this function. If it does return, then something 726227825Stheraven // has gone wrong. 727227825Stheraven report_failure(err, ex); 728227825Stheraven} 729227825Stheraven 730227825Stheraven 731227825Stheraven/** 732227825Stheraven * ABI function for throwing an exception. Takes the object to be thrown (the 733227825Stheraven * pointer returned by __cxa_allocate_exception()), the type info for the 734227825Stheraven * pointee, and the destructor (if there is one) as arguments. 735227825Stheraven */ 736227825Stheravenextern "C" void __cxa_throw(void *thrown_exception, 737227825Stheraven std::type_info *tinfo, 738227825Stheraven void(*dest)(void*)) 739227825Stheraven{ 740227825Stheraven __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1; 741227825Stheraven 742227825Stheraven ex->referenceCount = 1; 743227825Stheraven ex->exceptionType = tinfo; 744227825Stheraven 745227825Stheraven ex->exceptionDestructor = dest; 746227825Stheraven 747227825Stheraven ex->unwindHeader.exception_class = exception_class; 748227825Stheraven ex->unwindHeader.exception_cleanup = exception_cleanup; 749227825Stheraven 750227825Stheraven throw_exception(ex); 751227825Stheraven} 752227825Stheraven 753227825Stheravenextern "C" void __cxa_rethrow_primary_exception(void* thrown_exception) 754227825Stheraven{ 755227825Stheraven if (NULL == thrown_exception) { return; } 756227825Stheraven 757227825Stheraven __cxa_exception *original = exceptionFromPointer(thrown_exception); 758227825Stheraven __cxa_dependent_exception *ex = ((__cxa_dependent_exception*)__cxa_allocate_dependent_exception())-1; 759227825Stheraven 760227825Stheraven ex->primaryException = thrown_exception; 761227825Stheraven __cxa_increment_exception_refcount(thrown_exception); 762227825Stheraven 763227825Stheraven ex->exceptionType = original->exceptionType; 764227825Stheraven ex->unwindHeader.exception_class = dependent_exception_class; 765227825Stheraven ex->unwindHeader.exception_cleanup = dependent_exception_cleanup; 766227825Stheraven 767227825Stheraven throw_exception((__cxa_exception*)ex); 768227825Stheraven} 769227825Stheraven 770227825Stheravenextern "C" void *__cxa_current_primary_exception(void) 771227825Stheraven{ 772227825Stheraven __cxa_eh_globals* globals = __cxa_get_globals(); 773227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 774227825Stheraven 775227825Stheraven if (0 == ex) { return NULL; } 776227825Stheraven ex = realExceptionFromException(ex); 777227825Stheraven __sync_fetch_and_add(&ex->referenceCount, 1); 778227825Stheraven return ex + 1; 779227825Stheraven} 780227825Stheraven 781227825Stheravenextern "C" void __cxa_increment_exception_refcount(void* thrown_exception) 782227825Stheraven{ 783227825Stheraven if (NULL == thrown_exception) { return; } 784227825Stheraven __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1; 785227825Stheraven if (isDependentException(ex->unwindHeader.exception_class)) { return; } 786227825Stheraven __sync_fetch_and_add(&ex->referenceCount, 1); 787227825Stheraven} 788227825Stheravenextern "C" void __cxa_decrement_exception_refcount(void* thrown_exception) 789227825Stheraven{ 790227825Stheraven if (NULL == thrown_exception) { return; } 791227825Stheraven __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1; 792227825Stheraven releaseException(ex); 793227825Stheraven} 794227825Stheraven 795227825Stheraven/** 796227825Stheraven * ABI function. Rethrows the current exception. Does not remove the 797227825Stheraven * exception from the stack or decrement its handler count - the compiler is 798227825Stheraven * expected to set the landing pad for this function to the end of the catch 799227825Stheraven * block, and then call _Unwind_Resume() to continue unwinding once 800227825Stheraven * __cxa_end_catch() has been called and any cleanup code has been run. 801227825Stheraven */ 802227825Stheravenextern "C" void __cxa_rethrow() 803227825Stheraven{ 804250241Sdim __cxa_thread_info *ti = thread_info(); 805250241Sdim __cxa_eh_globals *globals = &ti->globals; 806227825Stheraven // Note: We don't remove this from the caught list here, because 807227825Stheraven // __cxa_end_catch will be called when we unwind out of the try block. We 808227825Stheraven // could probably make this faster by providing an alternative rethrow 809227825Stheraven // function and ensuring that all cleanup code is run before calling it, so 810227825Stheraven // we can skip the top stack frame when unwinding. 811227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 812227825Stheraven 813227825Stheraven if (0 == ex) 814227825Stheraven { 815227825Stheraven fprintf(stderr, 816227825Stheraven "Attempting to rethrow an exception that doesn't exist!\n"); 817227825Stheraven std::terminate(); 818227825Stheraven } 819227825Stheraven 820250241Sdim if (ti->foreign_exception_state != __cxa_thread_info::none) 821250241Sdim { 822250241Sdim ti->foreign_exception_state = __cxa_thread_info::rethrown; 823250241Sdim _Unwind_Exception *e = (_Unwind_Exception*)ex; 824250241Sdim _Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(e); 825250241Sdim report_failure(err, ex); 826250241Sdim return; 827250241Sdim } 828250241Sdim 829227825Stheraven assert(ex->handlerCount > 0 && "Rethrowing uncaught exception!"); 830227825Stheraven 831227825Stheraven // ex->handlerCount will be decremented in __cxa_end_catch in enclosing 832227825Stheraven // catch block 833227825Stheraven 834227825Stheraven // Make handler count negative. This will tell __cxa_end_catch that 835227825Stheraven // exception was rethrown and exception object should not be destroyed 836227825Stheraven // when handler count become zero 837227825Stheraven ex->handlerCount = -ex->handlerCount; 838227825Stheraven 839227825Stheraven // Continue unwinding the stack with this exception. This should unwind to 840227825Stheraven // the place in the caller where __cxa_end_catch() is called. The caller 841227825Stheraven // will then run cleanup code and bounce the exception back with 842227825Stheraven // _Unwind_Resume(). 843227825Stheraven _Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(&ex->unwindHeader); 844227825Stheraven report_failure(err, ex); 845227825Stheraven} 846227825Stheraven 847227825Stheraven/** 848227825Stheraven * Returns the type_info object corresponding to the filter. 849227825Stheraven */ 850227825Stheravenstatic std::type_info *get_type_info_entry(_Unwind_Context *context, 851227825Stheraven dwarf_eh_lsda *lsda, 852227825Stheraven int filter) 853227825Stheraven{ 854227825Stheraven // Get the address of the record in the table. 855227825Stheraven dw_eh_ptr_t record = lsda->type_table - 856227825Stheraven dwarf_size_of_fixed_size_field(lsda->type_table_encoding)*filter; 857227972Stheraven //record -= 4; 858227825Stheraven dw_eh_ptr_t start = record; 859227825Stheraven // Read the value, but it's probably an indirect reference... 860227825Stheraven int64_t offset = read_value(lsda->type_table_encoding, &record); 861227825Stheraven 862227825Stheraven // (If the entry is 0, don't try to dereference it. That would be bad.) 863227825Stheraven if (offset == 0) { return 0; } 864227825Stheraven 865227825Stheraven // ...so we need to resolve it 866227825Stheraven return (std::type_info*)resolve_indirect_value(context, 867227825Stheraven lsda->type_table_encoding, offset, start); 868227825Stheraven} 869227825Stheraven 870227825Stheraven 871227972Stheraven 872227825Stheraven/** 873227825Stheraven * Checks the type signature found in a handler against the type of the thrown 874227825Stheraven * object. If ex is 0 then it is assumed to be a foreign exception and only 875227825Stheraven * matches cleanups. 876227825Stheraven */ 877227825Stheravenstatic bool check_type_signature(__cxa_exception *ex, 878227825Stheraven const std::type_info *type, 879227825Stheraven void *&adjustedPtr) 880227825Stheraven{ 881227825Stheraven void *exception_ptr = (void*)(ex+1); 882250241Sdim const std::type_info *ex_type = ex ? ex->exceptionType : 0; 883227825Stheraven 884250241Sdim bool is_ptr = ex ? ex_type->__is_pointer_p() : false; 885233235Stheraven if (is_ptr) 886227825Stheraven { 887227825Stheraven exception_ptr = *(void**)exception_ptr; 888227825Stheraven } 889227825Stheraven // Always match a catchall, even with a foreign exception 890227825Stheraven // 891227825Stheraven // Note: A 0 here is a catchall, not a cleanup, so we return true to 892227825Stheraven // indicate that we found a catch. 893227825Stheraven if (0 == type) 894227825Stheraven { 895227825Stheraven if (ex) 896227825Stheraven { 897227825Stheraven adjustedPtr = exception_ptr; 898227825Stheraven } 899227825Stheraven return true; 900227825Stheraven } 901227825Stheraven 902227825Stheraven if (0 == ex) { return false; } 903227825Stheraven 904227825Stheraven // If the types are the same, no casting is needed. 905227825Stheraven if (*type == *ex_type) 906227825Stheraven { 907227825Stheraven adjustedPtr = exception_ptr; 908227825Stheraven return true; 909227825Stheraven } 910227825Stheraven 911227825Stheraven 912233235Stheraven if (type->__do_catch(ex_type, &exception_ptr, 1)) 913227825Stheraven { 914233235Stheraven adjustedPtr = exception_ptr; 915227825Stheraven return true; 916227825Stheraven } 917233235Stheraven 918227825Stheraven return false; 919227825Stheraven} 920227825Stheraven/** 921227825Stheraven * Checks whether the exception matches the type specifiers in this action 922227825Stheraven * record. If the exception only matches cleanups, then this returns false. 923227825Stheraven * If it matches a catch (including a catchall) then it returns true. 924227825Stheraven * 925227825Stheraven * The selector argument is used to return the selector that is passed in the 926227825Stheraven * second exception register when installing the context. 927227825Stheraven */ 928227825Stheravenstatic handler_type check_action_record(_Unwind_Context *context, 929227825Stheraven dwarf_eh_lsda *lsda, 930227825Stheraven dw_eh_ptr_t action_record, 931227825Stheraven __cxa_exception *ex, 932227825Stheraven unsigned long *selector, 933227825Stheraven void *&adjustedPtr) 934227825Stheraven{ 935227825Stheraven if (!action_record) { return handler_cleanup; } 936227825Stheraven handler_type found = handler_none; 937227825Stheraven while (action_record) 938227825Stheraven { 939227825Stheraven int filter = read_sleb128(&action_record); 940227825Stheraven dw_eh_ptr_t action_record_offset_base = action_record; 941227825Stheraven int displacement = read_sleb128(&action_record); 942227825Stheraven action_record = displacement ? 943227825Stheraven action_record_offset_base + displacement : 0; 944227825Stheraven // We only check handler types for C++ exceptions - foreign exceptions 945250241Sdim // are only allowed for cleanups and catchalls. 946250241Sdim if (filter > 0) 947227825Stheraven { 948227825Stheraven std::type_info *handler_type = get_type_info_entry(context, lsda, filter); 949227825Stheraven if (check_type_signature(ex, handler_type, adjustedPtr)) 950227825Stheraven { 951227825Stheraven *selector = filter; 952227825Stheraven return handler_catch; 953227825Stheraven } 954227825Stheraven } 955227825Stheraven else if (filter < 0 && 0 != ex) 956227825Stheraven { 957227825Stheraven bool matched = false; 958227825Stheraven *selector = filter; 959227972Stheraven#ifdef __arm__ 960227972Stheraven filter++; 961227972Stheraven std::type_info *handler_type = get_type_info_entry(context, lsda, filter--); 962227972Stheraven while (handler_type) 963227972Stheraven { 964227972Stheraven if (check_type_signature(ex, handler_type, adjustedPtr)) 965227972Stheraven { 966227972Stheraven matched = true; 967227972Stheraven break; 968227972Stheraven } 969227972Stheraven handler_type = get_type_info_entry(context, lsda, filter--); 970227972Stheraven } 971227972Stheraven#else 972227972Stheraven unsigned char *type_index = ((unsigned char*)lsda->type_table - filter - 1); 973227825Stheraven while (*type_index) 974227825Stheraven { 975227825Stheraven std::type_info *handler_type = get_type_info_entry(context, lsda, *(type_index++)); 976227825Stheraven // If the exception spec matches a permitted throw type for 977227825Stheraven // this function, don't report a handler - we are allowed to 978227825Stheraven // propagate this exception out. 979227825Stheraven if (check_type_signature(ex, handler_type, adjustedPtr)) 980227825Stheraven { 981227825Stheraven matched = true; 982227825Stheraven break; 983227825Stheraven } 984227825Stheraven } 985227972Stheraven#endif 986227825Stheraven if (matched) { continue; } 987227825Stheraven // If we don't find an allowed exception spec, we need to install 988227825Stheraven // the context for this action. The landing pad will then call the 989227825Stheraven // unexpected exception function. Treat this as a catch 990227825Stheraven return handler_catch; 991227825Stheraven } 992227825Stheraven else if (filter == 0) 993227825Stheraven { 994227825Stheraven *selector = filter; 995227825Stheraven found = handler_cleanup; 996227825Stheraven } 997227825Stheraven } 998227825Stheraven return found; 999227825Stheraven} 1000227825Stheraven 1001227972Stheravenstatic void pushCleanupException(_Unwind_Exception *exceptionObject, 1002227972Stheraven __cxa_exception *ex) 1003227972Stheraven{ 1004227972Stheraven#ifdef __arm__ 1005227972Stheraven __cxa_thread_info *info = thread_info_fast(); 1006227972Stheraven if (ex) 1007227972Stheraven { 1008227972Stheraven ex->cleanupCount++; 1009227972Stheraven if (ex->cleanupCount > 1) 1010227972Stheraven { 1011227972Stheraven assert(exceptionObject == info->currentCleanup); 1012227972Stheraven return; 1013227972Stheraven } 1014227972Stheraven ex->nextCleanup = info->currentCleanup; 1015227972Stheraven } 1016227972Stheraven info->currentCleanup = exceptionObject; 1017227972Stheraven#endif 1018227972Stheraven} 1019227972Stheraven 1020227825Stheraven/** 1021227825Stheraven * The exception personality function. This is referenced in the unwinding 1022227825Stheraven * DWARF metadata and is called by the unwind library for each C++ stack frame 1023227825Stheraven * containing catch or cleanup code. 1024227825Stheraven */ 1025227972Stheravenextern "C" 1026227972StheravenBEGIN_PERSONALITY_FUNCTION(__gxx_personality_v0) 1027227825Stheraven // This personality function is for version 1 of the ABI. If you use it 1028227825Stheraven // with a future version of the ABI, it won't know what to do, so it 1029227825Stheraven // reports a fatal error and give up before it breaks anything. 1030227825Stheraven if (1 != version) 1031227825Stheraven { 1032227825Stheraven return _URC_FATAL_PHASE1_ERROR; 1033227825Stheraven } 1034227825Stheraven __cxa_exception *ex = 0; 1035227825Stheraven __cxa_exception *realEx = 0; 1036227825Stheraven 1037227825Stheraven // If this exception is throw by something else then we can't make any 1038227825Stheraven // assumptions about its layout beyond the fields declared in 1039227825Stheraven // _Unwind_Exception. 1040227825Stheraven bool foreignException = !isCXXException(exceptionClass); 1041227825Stheraven 1042227825Stheraven // If this isn't a foreign exception, then we have a C++ exception structure 1043227825Stheraven if (!foreignException) 1044227825Stheraven { 1045227825Stheraven ex = exceptionFromPointer(exceptionObject); 1046227825Stheraven realEx = realExceptionFromException(ex); 1047227825Stheraven } 1048227825Stheraven 1049227825Stheraven unsigned char *lsda_addr = 1050227825Stheraven (unsigned char*)_Unwind_GetLanguageSpecificData(context); 1051227825Stheraven 1052227825Stheraven // No LSDA implies no landing pads - try the next frame 1053227972Stheraven if (0 == lsda_addr) { return continueUnwinding(exceptionObject, context); } 1054227825Stheraven 1055227825Stheraven // These two variables define how the exception will be handled. 1056227825Stheraven dwarf_eh_action action = {0}; 1057227825Stheraven unsigned long selector = 0; 1058227825Stheraven 1059227825Stheraven // During the search phase, we do a complete lookup. If we return 1060227825Stheraven // _URC_HANDLER_FOUND, then the phase 2 unwind will call this function with 1061227825Stheraven // a _UA_HANDLER_FRAME action, telling us to install the handler frame. If 1062227825Stheraven // we return _URC_CONTINUE_UNWIND, we may be called again later with a 1063227825Stheraven // _UA_CLEANUP_PHASE action for this frame. 1064227825Stheraven // 1065227825Stheraven // The point of the two-stage unwind allows us to entirely avoid any stack 1066227825Stheraven // unwinding if there is no handler. If there are just cleanups found, 1067227825Stheraven // then we can just panic call an abort function. 1068227825Stheraven // 1069227825Stheraven // Matching a handler is much more expensive than matching a cleanup, 1070227825Stheraven // because we don't need to bother doing type comparisons (or looking at 1071227825Stheraven // the type table at all) for a cleanup. This means that there is no need 1072227825Stheraven // to cache the result of finding a cleanup, because it's (quite) quick to 1073227825Stheraven // look it up again from the action table. 1074227825Stheraven if (actions & _UA_SEARCH_PHASE) 1075227825Stheraven { 1076227825Stheraven struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); 1077227825Stheraven 1078227825Stheraven if (!dwarf_eh_find_callsite(context, &lsda, &action)) 1079227825Stheraven { 1080227825Stheraven // EH range not found. This happens if exception is thrown and not 1081227825Stheraven // caught inside a cleanup (destructor). We should call 1082227825Stheraven // terminate() in this case. The catchTemp (landing pad) field of 1083227825Stheraven // exception object will contain null when personality function is 1084227825Stheraven // called with _UA_HANDLER_FRAME action for phase 2 unwinding. 1085227825Stheraven return _URC_HANDLER_FOUND; 1086227825Stheraven } 1087227825Stheraven 1088227825Stheraven handler_type found_handler = check_action_record(context, &lsda, 1089227825Stheraven action.action_record, realEx, &selector, ex->adjustedPtr); 1090227825Stheraven // If there's no action record, we've only found a cleanup, so keep 1091227825Stheraven // searching for something real 1092227825Stheraven if (found_handler == handler_catch) 1093227825Stheraven { 1094227825Stheraven // Cache the results for the phase 2 unwind, if we found a handler 1095227825Stheraven // and this is not a foreign exception. 1096227825Stheraven if (ex) 1097227825Stheraven { 1098227972Stheraven saveLandingPad(context, exceptionObject, ex, selector, action.landing_pad); 1099227972Stheraven ex->languageSpecificData = (const char*)lsda_addr; 1100227825Stheraven ex->actionRecord = (const char*)action.action_record; 1101227825Stheraven // ex->adjustedPtr is set when finding the action record. 1102227825Stheraven } 1103227825Stheraven return _URC_HANDLER_FOUND; 1104227825Stheraven } 1105227972Stheraven return continueUnwinding(exceptionObject, context); 1106227825Stheraven } 1107227825Stheraven 1108227825Stheraven 1109227825Stheraven // If this is a foreign exception, we didn't have anywhere to cache the 1110227825Stheraven // lookup stuff, so we need to do it again. If this is either a forced 1111227825Stheraven // unwind, a foreign exception, or a cleanup, then we just install the 1112227825Stheraven // context for a cleanup. 1113227825Stheraven if (!(actions & _UA_HANDLER_FRAME)) 1114227825Stheraven { 1115227825Stheraven // cleanup 1116227825Stheraven struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); 1117227825Stheraven dwarf_eh_find_callsite(context, &lsda, &action); 1118227972Stheraven if (0 == action.landing_pad) { return continueUnwinding(exceptionObject, context); } 1119227825Stheraven handler_type found_handler = check_action_record(context, &lsda, 1120227825Stheraven action.action_record, realEx, &selector, ex->adjustedPtr); 1121227825Stheraven // Ignore handlers this time. 1122227972Stheraven if (found_handler != handler_cleanup) { return continueUnwinding(exceptionObject, context); } 1123227972Stheraven pushCleanupException(exceptionObject, ex); 1124227825Stheraven } 1125227825Stheraven else if (foreignException) 1126227825Stheraven { 1127227825Stheraven struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); 1128227825Stheraven dwarf_eh_find_callsite(context, &lsda, &action); 1129227825Stheraven check_action_record(context, &lsda, action.action_record, realEx, 1130227825Stheraven &selector, ex->adjustedPtr); 1131227825Stheraven } 1132227825Stheraven else if (ex->catchTemp == 0) 1133227825Stheraven { 1134227825Stheraven // Uncaught exception in cleanup, calling terminate 1135227825Stheraven std::terminate(); 1136227825Stheraven } 1137227825Stheraven else 1138227825Stheraven { 1139227825Stheraven // Restore the saved info if we saved some last time. 1140227972Stheraven loadLandingPad(context, exceptionObject, ex, &selector, &action.landing_pad); 1141227825Stheraven ex->catchTemp = 0; 1142227825Stheraven ex->handlerSwitchValue = 0; 1143227825Stheraven } 1144227825Stheraven 1145227825Stheraven 1146227825Stheraven _Unwind_SetIP(context, (unsigned long)action.landing_pad); 1147227825Stheraven _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), 1148227825Stheraven (unsigned long)exceptionObject); 1149227825Stheraven _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector); 1150227825Stheraven 1151227825Stheraven return _URC_INSTALL_CONTEXT; 1152227825Stheraven} 1153227825Stheraven 1154227825Stheraven/** 1155227825Stheraven * ABI function called when entering a catch statement. The argument is the 1156227825Stheraven * pointer passed out of the personality function. This is always the start of 1157227825Stheraven * the _Unwind_Exception object. The return value for this function is the 1158227825Stheraven * pointer to the caught exception, which is either the adjusted pointer (for 1159227825Stheraven * C++ exceptions) of the unadjusted pointer (for foreign exceptions). 1160227825Stheraven */ 1161227825Stheraven#if __GNUC__ > 3 && __GNUC_MINOR__ > 2 1162227825Stheravenextern "C" void *__cxa_begin_catch(void *e) throw() 1163227825Stheraven#else 1164227825Stheravenextern "C" void *__cxa_begin_catch(void *e) 1165227825Stheraven#endif 1166227825Stheraven{ 1167250241Sdim // We can't call the fast version here, because if the first exception that 1168250241Sdim // we see is a foreign exception then we won't have called it yet. 1169250241Sdim __cxa_thread_info *ti = thread_info(); 1170250241Sdim __cxa_eh_globals *globals = &ti->globals; 1171227825Stheraven globals->uncaughtExceptions--; 1172227825Stheraven _Unwind_Exception *exceptionObject = (_Unwind_Exception*)e; 1173227825Stheraven 1174227825Stheraven if (isCXXException(exceptionObject->exception_class)) 1175227825Stheraven { 1176227825Stheraven __cxa_exception *ex = exceptionFromPointer(exceptionObject); 1177227825Stheraven 1178227825Stheraven if (ex->handlerCount == 0) 1179227825Stheraven { 1180227825Stheraven // Add this to the front of the list of exceptions being handled 1181227825Stheraven // and increment its handler count so that it won't be deleted 1182227825Stheraven // prematurely. 1183227825Stheraven ex->nextException = globals->caughtExceptions; 1184227825Stheraven globals->caughtExceptions = ex; 1185227825Stheraven } 1186227825Stheraven 1187227825Stheraven if (ex->handlerCount < 0) 1188227825Stheraven { 1189227825Stheraven // Rethrown exception is catched before end of catch block. 1190227825Stheraven // Clear the rethrow flag (make value positive) - we are allowed 1191227825Stheraven // to delete this exception at the end of the catch block, as long 1192227825Stheraven // as it isn't thrown again later. 1193227825Stheraven 1194227825Stheraven // Code pattern: 1195227825Stheraven // 1196227825Stheraven // try { 1197227825Stheraven // throw x; 1198227825Stheraven // } 1199227825Stheraven // catch() { 1200227825Stheraven // try { 1201227825Stheraven // throw; 1202227825Stheraven // } 1203227825Stheraven // catch() { 1204227825Stheraven // __cxa_begin_catch() <- we are here 1205227825Stheraven // } 1206227825Stheraven // } 1207227825Stheraven ex->handlerCount = -ex->handlerCount + 1; 1208227825Stheraven } 1209227825Stheraven else 1210227825Stheraven { 1211227825Stheraven ex->handlerCount++; 1212227825Stheraven } 1213250241Sdim ti->foreign_exception_state = __cxa_thread_info::none; 1214227825Stheraven 1215227825Stheraven return ex->adjustedPtr; 1216227825Stheraven } 1217250241Sdim else 1218250241Sdim { 1219250241Sdim // If this is a foreign exception, then we need to be able to 1220250241Sdim // store it. We can't chain foreign exceptions, so we give up 1221250241Sdim // if there are already some outstanding ones. 1222250241Sdim if (globals->caughtExceptions != 0) 1223250241Sdim { 1224250241Sdim std::terminate(); 1225250241Sdim } 1226250241Sdim globals->caughtExceptions = (__cxa_exception*)exceptionObject; 1227250241Sdim ti->foreign_exception_state = __cxa_thread_info::caught; 1228250241Sdim } 1229227825Stheraven // exceptionObject is the pointer to the _Unwind_Exception within the 1230227825Stheraven // __cxa_exception. The throw object is after this 1231227825Stheraven return ((char*)exceptionObject + sizeof(_Unwind_Exception)); 1232227825Stheraven} 1233227825Stheraven 1234227972Stheraven 1235227972Stheraven 1236227825Stheraven/** 1237227825Stheraven * ABI function called when exiting a catch block. This will free the current 1238227825Stheraven * exception if it is no longer referenced in other catch blocks. 1239227825Stheraven */ 1240227825Stheravenextern "C" void __cxa_end_catch() 1241227825Stheraven{ 1242227825Stheraven // We can call the fast version here because the slow version is called in 1243227825Stheraven // __cxa_throw(), which must have been called before we end a catch block 1244250241Sdim __cxa_thread_info *ti = thread_info_fast(); 1245250241Sdim __cxa_eh_globals *globals = &ti->globals; 1246227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 1247227825Stheraven 1248227825Stheraven assert(0 != ex && "Ending catch when no exception is on the stack!"); 1249250241Sdim 1250250241Sdim if (ti->foreign_exception_state != __cxa_thread_info::none) 1251250241Sdim { 1252250241Sdim globals->caughtExceptions = 0; 1253250241Sdim if (ti->foreign_exception_state != __cxa_thread_info::rethrown) 1254250241Sdim { 1255250241Sdim _Unwind_Exception *e = (_Unwind_Exception*)ti->globals.caughtExceptions; 1256250241Sdim e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e); 1257250241Sdim } 1258250241Sdim ti->foreign_exception_state = __cxa_thread_info::none; 1259250241Sdim return; 1260250241Sdim } 1261227825Stheraven 1262227825Stheraven bool deleteException = true; 1263227825Stheraven 1264227825Stheraven if (ex->handlerCount < 0) 1265227825Stheraven { 1266227825Stheraven // exception was rethrown. Exception should not be deleted even if 1267227825Stheraven // handlerCount become zero. 1268227825Stheraven // Code pattern: 1269227825Stheraven // try { 1270227825Stheraven // throw x; 1271227825Stheraven // } 1272227825Stheraven // catch() { 1273227825Stheraven // { 1274227825Stheraven // throw; 1275227825Stheraven // } 1276227825Stheraven // cleanup { 1277227825Stheraven // __cxa_end_catch(); <- we are here 1278227825Stheraven // } 1279227825Stheraven // } 1280227825Stheraven // 1281227825Stheraven 1282227825Stheraven ex->handlerCount++; 1283227825Stheraven deleteException = false; 1284227825Stheraven } 1285227825Stheraven else 1286227825Stheraven { 1287227825Stheraven ex->handlerCount--; 1288227825Stheraven } 1289227825Stheraven 1290227825Stheraven if (ex->handlerCount == 0) 1291227825Stheraven { 1292227825Stheraven globals->caughtExceptions = ex->nextException; 1293227825Stheraven if (deleteException) 1294227825Stheraven { 1295227825Stheraven releaseException(ex); 1296227825Stheraven } 1297227825Stheraven } 1298227825Stheraven} 1299227825Stheraven 1300227825Stheraven/** 1301227825Stheraven * ABI function. Returns the type of the current exception. 1302227825Stheraven */ 1303227825Stheravenextern "C" std::type_info *__cxa_current_exception_type() 1304227825Stheraven{ 1305227825Stheraven __cxa_eh_globals *globals = __cxa_get_globals(); 1306227825Stheraven __cxa_exception *ex = globals->caughtExceptions; 1307227825Stheraven return ex ? ex->exceptionType : 0; 1308227825Stheraven} 1309227825Stheraven 1310227825Stheraven/** 1311227825Stheraven * ABI function, called when an exception specification is violated. 1312227825Stheraven * 1313227825Stheraven * This function does not return. 1314227825Stheraven */ 1315227825Stheravenextern "C" void __cxa_call_unexpected(void*exception) 1316227825Stheraven{ 1317227825Stheraven _Unwind_Exception *exceptionObject = (_Unwind_Exception*)exception; 1318227825Stheraven if (exceptionObject->exception_class == exception_class) 1319227825Stheraven { 1320227825Stheraven __cxa_exception *ex = exceptionFromPointer(exceptionObject); 1321227825Stheraven if (ex->unexpectedHandler) 1322227825Stheraven { 1323227825Stheraven ex->unexpectedHandler(); 1324227825Stheraven // Should not be reached. 1325227825Stheraven abort(); 1326227825Stheraven } 1327227825Stheraven } 1328227825Stheraven std::unexpected(); 1329227825Stheraven // Should not be reached. 1330227825Stheraven abort(); 1331227825Stheraven} 1332227825Stheraven 1333227825Stheraven/** 1334227825Stheraven * ABI function, returns the adjusted pointer to the exception object. 1335227825Stheraven */ 1336227825Stheravenextern "C" void *__cxa_get_exception_ptr(void *exceptionObject) 1337227825Stheraven{ 1338227825Stheraven return exceptionFromPointer(exceptionObject)->adjustedPtr; 1339227825Stheraven} 1340227825Stheraven 1341227825Stheraven/** 1342227825Stheraven * As an extension, we provide the ability for the unexpected and terminate 1343227825Stheraven * handlers to be thread-local. We default to the standards-compliant 1344227825Stheraven * behaviour where they are global. 1345227825Stheraven */ 1346227825Stheravenstatic bool thread_local_handlers = false; 1347227825Stheraven 1348227825Stheraven 1349227825Stheravennamespace pathscale 1350227825Stheraven{ 1351227825Stheraven /** 1352227825Stheraven * Sets whether unexpected and terminate handlers should be thread-local. 1353227825Stheraven */ 1354227825Stheraven void set_use_thread_local_handlers(bool flag) throw() 1355227825Stheraven { 1356227825Stheraven thread_local_handlers = flag; 1357227825Stheraven } 1358227825Stheraven /** 1359227825Stheraven * Sets a thread-local unexpected handler. 1360227825Stheraven */ 1361227825Stheraven unexpected_handler set_unexpected(unexpected_handler f) throw() 1362227825Stheraven { 1363227825Stheraven static __cxa_thread_info *info = thread_info(); 1364227825Stheraven unexpected_handler old = info->unexpectedHandler; 1365227825Stheraven info->unexpectedHandler = f; 1366227825Stheraven return old; 1367227825Stheraven } 1368227825Stheraven /** 1369227825Stheraven * Sets a thread-local terminate handler. 1370227825Stheraven */ 1371227825Stheraven terminate_handler set_terminate(terminate_handler f) throw() 1372227825Stheraven { 1373227825Stheraven static __cxa_thread_info *info = thread_info(); 1374227825Stheraven terminate_handler old = info->terminateHandler; 1375227825Stheraven info->terminateHandler = f; 1376227825Stheraven return old; 1377227825Stheraven } 1378227825Stheraven} 1379227825Stheraven 1380227825Stheravennamespace std 1381227825Stheraven{ 1382227825Stheraven /** 1383227825Stheraven * Sets the function that will be called when an exception specification is 1384227825Stheraven * violated. 1385227825Stheraven */ 1386227825Stheraven unexpected_handler set_unexpected(unexpected_handler f) throw() 1387227825Stheraven { 1388227825Stheraven if (thread_local_handlers) { return pathscale::set_unexpected(f); } 1389227825Stheraven 1390250241Sdim return ATOMIC_SWAP(&unexpectedHandler, f); 1391227825Stheraven } 1392227825Stheraven /** 1393227825Stheraven * Sets the function that is called to terminate the program. 1394227825Stheraven */ 1395227825Stheraven terminate_handler set_terminate(terminate_handler f) throw() 1396227825Stheraven { 1397227825Stheraven if (thread_local_handlers) { return pathscale::set_terminate(f); } 1398250241Sdim 1399250241Sdim return ATOMIC_SWAP(&terminateHandler, f); 1400227825Stheraven } 1401227825Stheraven /** 1402227825Stheraven * Terminates the program, calling a custom terminate implementation if 1403227825Stheraven * required. 1404227825Stheraven */ 1405227825Stheraven void terminate() 1406227825Stheraven { 1407250241Sdim static __cxa_thread_info *info = thread_info(); 1408227825Stheraven if (0 != info && 0 != info->terminateHandler) 1409227825Stheraven { 1410227825Stheraven info->terminateHandler(); 1411227825Stheraven // Should not be reached - a terminate handler is not expected to 1412227825Stheraven // return. 1413227825Stheraven abort(); 1414227825Stheraven } 1415227825Stheraven terminateHandler(); 1416227825Stheraven } 1417227825Stheraven /** 1418227825Stheraven * Called when an unexpected exception is encountered (i.e. an exception 1419227825Stheraven * violates an exception specification). This calls abort() unless a 1420227825Stheraven * custom handler has been set.. 1421227825Stheraven */ 1422227825Stheraven void unexpected() 1423227825Stheraven { 1424250241Sdim static __cxa_thread_info *info = thread_info(); 1425227825Stheraven if (0 != info && 0 != info->unexpectedHandler) 1426227825Stheraven { 1427227825Stheraven info->unexpectedHandler(); 1428227825Stheraven // Should not be reached - a terminate handler is not expected to 1429227825Stheraven // return. 1430227825Stheraven abort(); 1431227825Stheraven } 1432227825Stheraven unexpectedHandler(); 1433227825Stheraven } 1434227825Stheraven /** 1435227825Stheraven * Returns whether there are any exceptions currently being thrown that 1436227825Stheraven * have not been caught. This can occur inside a nested catch statement. 1437227825Stheraven */ 1438227825Stheraven bool uncaught_exception() throw() 1439227825Stheraven { 1440227825Stheraven __cxa_thread_info *info = thread_info(); 1441227825Stheraven return info->globals.uncaughtExceptions != 0; 1442227825Stheraven } 1443227825Stheraven /** 1444227825Stheraven * Returns the current unexpected handler. 1445227825Stheraven */ 1446227825Stheraven unexpected_handler get_unexpected() throw() 1447227825Stheraven { 1448227825Stheraven __cxa_thread_info *info = thread_info(); 1449227825Stheraven if (info->unexpectedHandler) 1450227825Stheraven { 1451227825Stheraven return info->unexpectedHandler; 1452227825Stheraven } 1453250241Sdim return ATOMIC_LOAD(&unexpectedHandler); 1454227825Stheraven } 1455227825Stheraven /** 1456227825Stheraven * Returns the current terminate handler. 1457227825Stheraven */ 1458227825Stheraven terminate_handler get_terminate() throw() 1459227825Stheraven { 1460227825Stheraven __cxa_thread_info *info = thread_info(); 1461227825Stheraven if (info->terminateHandler) 1462227825Stheraven { 1463227825Stheraven return info->terminateHandler; 1464227825Stheraven } 1465250241Sdim return ATOMIC_LOAD(&terminateHandler); 1466227825Stheraven } 1467227825Stheraven} 1468227972Stheraven#ifdef __arm__ 1469227972Stheravenextern "C" _Unwind_Exception *__cxa_get_cleanup(void) 1470227972Stheraven{ 1471227972Stheraven __cxa_thread_info *info = thread_info_fast(); 1472227972Stheraven _Unwind_Exception *exceptionObject = info->currentCleanup; 1473227972Stheraven if (isCXXException(exceptionObject->exception_class)) 1474227972Stheraven { 1475227972Stheraven __cxa_exception *ex = exceptionFromPointer(exceptionObject); 1476227972Stheraven ex->cleanupCount--; 1477227972Stheraven if (ex->cleanupCount == 0) 1478227972Stheraven { 1479227972Stheraven info->currentCleanup = ex->nextCleanup; 1480227972Stheraven ex->nextCleanup = 0; 1481227972Stheraven } 1482227972Stheraven } 1483227972Stheraven else 1484227972Stheraven { 1485227972Stheraven info->currentCleanup = 0; 1486227972Stheraven } 1487227972Stheraven return exceptionObject; 1488227972Stheraven} 1489227972Stheraven 1490227972Stheravenasm ( 1491227972Stheraven".pushsection .text.__cxa_end_cleanup \n" 1492227972Stheraven".global __cxa_end_cleanup \n" 1493227972Stheraven".type __cxa_end_cleanup, \"function\" \n" 1494227972Stheraven"__cxa_end_cleanup: \n" 1495227972Stheraven" push {r1, r2, r3, r4} \n" 1496227972Stheraven" bl __cxa_get_cleanup \n" 1497227972Stheraven" push {r1, r2, r3, r4} \n" 1498227972Stheraven" b _Unwind_Resume \n" 1499227972Stheraven" bl abort \n" 1500227972Stheraven".popsection \n" 1501227972Stheraven); 1502227972Stheraven#endif 1503