os/kernelhwsrv/kernel/eka/compsupp/symaehabi/cppsemantics.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* The C++ exceptions runtime support
     2  *
     3  * Copyright 2002-2005 ARM Limited. All rights reserved.
     4  *
     5  * Your rights to use this code are set out in the accompanying licence
     6  * text file LICENCE.txt (ARM contract number LEC-ELA-00080 v1.0).
     7  */
     8 
     9 /* Portions copyright Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). */
    10 
    11 /*
    12  * RCS $Revision: 92950 $
    13  * Checkin $Date: 2005-10-12 11:08:47 +0100 (Wed, 12 Oct 2005) $
    14  * Revising $Author: achapman $
    15  */
    16 
    17 /* This source file is compiled automatically by ARM's make system into
    18  * multiple object files. The source regions constituting object file
    19  * xxx.o are delimited by ifdef xxx_c / endif directives.
    20  *
    21  * The source regions currently marked are:
    22  * arm_exceptions_globs_c
    23  * arm_exceptions_mem_c
    24  * arm_exceptions_uncaught_c
    25  * arm_exceptions_terminate_c
    26  * arm_exceptions_setterminate_c
    27  * arm_exceptions_unexpected_c
    28  * arm_exceptions_setunexpected_c
    29  * arm_exceptions_support_c
    30  * arm_exceptions_callterm_c
    31  * arm_exceptions_callunex_c
    32  * arm_exceptions_currenttype_c
    33  * arm_exceptions_alloc_c
    34  * arm_exceptions_free_c
    35  * arm_exceptions_throw_c
    36  * arm_exceptions_rethrow_c
    37  * arm_exceptions_foreign_c
    38  * arm_exceptions_cleanup_c
    39  * arm_exceptions_getexceptionptr_c
    40  * arm_exceptions_begincatch_c
    41  * arm_exceptions_endcatch_c
    42  * arm_exceptions_bad_typeid_c
    43  * arm_exceptions_bad_cast_c
    44  */
    45 
    46 #include <string.h>
    47 
    48 // Environment:
    49 #include "unwind_env.h"
    50 // Language-independent unwinder declarations:
    51 #include "unwinder.h"
    52 
    53 #ifdef __EPOC32__
    54 /* Symbian specific support */
    55 #include "symbian_support.h"
    56 #endif
    57 
    58 #include <new>
    59 
    60 /* Barrier cache: */
    61 /* Requirement imposed by C++ semantics module - pointer to match object in slot 0: */
    62 #define BARRIER_HANDLEROBJECT (0)
    63 /* Requirement imposed by C++ semantics module - function exception spec info */
    64 #define BARRIER_FNSPECCOUNT  (1)
    65 #define BARRIER_FNSPECBASE   (2)
    66 #define BARRIER_FNSPECSTRIDE (3)
    67 #define BARRIER_FNSPECARRAY  (4)
    68 
    69 /* By default, none of these routines are unwindable: */
    70 #pragma noexceptions_unwind
    71 
    72 /* For brevity: */
    73 
    74 typedef _Unwind_Control_Block UCB;
    75 
    76 using std::terminate_handler;
    77 using std::unexpected_handler;
    78 using std::terminate;
    79 using std::unexpected;
    80 using std::type_info;
    81 
    82 /* Redeclare these interface routines as weak, so using them does not
    83  * pull in the unwind library. We only want the unwind library if
    84  * someone throws (or raises an exception from some other language).
    85  */
    86 WEAKDECL NORETURNDECL void _Unwind_Resume(UCB *);
    87 WEAKDECL void _Unwind_Complete(UCB *);
    88 
    89 /* Diagnostics:
    90  * Define DEBUG to get extra interfaces which assist debugging this functionality.
    91  * Define CPP_DIAGNOSTICS for printed diagnostics.
    92  */
    93 #ifdef DEBUG
    94 #define CPP_DIAGNOSTICS
    95 #endif
    96 
    97 #ifdef CPP_DIAGNOSTICS
    98 #ifndef __EPOC32__
    99 extern "C" int printf(const char *, ...);
   100 #endif
   101 #endif
   102 
   103 /* --------- "Exceptions_class" string for our implementation: --------- */
   104 
   105 #define EXCEPTIONS_CLASS_SIZE 8
   106 #define ARMCPP_EXCEPTIONS_CLASS "ARM\0C++\0"
   107 
   108 
   109 /* --------- Exception control object: --------- */
   110 
   111 // Type __cxa_exception is the combined C++ housekeeping (LEO) and UCB.
   112 // It will be followed by the user exception object, hence must ensure
   113 // the latter is aligned on an 8 byte boundary.
   114 
   115 #ifndef __EPOC32__
   116 struct __cxa_exception {
   117   const type_info *exceptionType;       // RTTI object describing the type of the exception
   118   void *(*exceptionDestructor)(void *); // Destructor for the exception object (may be NULL)
   119   unexpected_handler unexpectedHandler; // Handler in force after evaluating throw expr
   120   terminate_handler terminateHandler;   // Handler in force after evaluating throw expr
   121   __cxa_exception *nextCaughtException; // Chain of "currently caught" c++ exception objects
   122   uint32_t handlerCount;                // Count of how many handlers this EO is "caught" in
   123   __cxa_exception *nextPropagatingException; // Chain of objects saved over cleanup
   124   uint32_t propagationCount;            // Count of live propagations (throws) of this EO
   125   UCB ucb;                              // Forces alignment of next item to 8-byte boundary
   126 };
   127 #endif
   128 
   129 
   130 /* --------- Control "globals": --------- */
   131 
   132 // We do this by putting all the thread-specific "globals" into a single
   133 // area of store, which we allocate space for dynamically.
   134 // We don't define a constructor for this; see comments with __cxa_get_globals.
   135 
   136 #ifndef __EPOC32__
   137 typedef void (*handler)(void);
   138 
   139 struct __cxa_eh_globals {
   140   uint32_t uncaughtExceptions;               // counter
   141   unexpected_handler unexpectedHandler;      // per-thread handler
   142   terminate_handler terminateHandler;        // per-thread handler
   143   bool implementation_ever_called_terminate; // true if it ever did
   144   handler call_hook;     // transient field to tell terminate/unexpected which hook to call
   145   __cxa_exception *caughtExceptions;         // chain of "caught" exceptions
   146   __cxa_exception *propagatingExceptions;    // chain of "propagating" (in cleanup) exceptions
   147   void *emergency_buffer;                    // emergency buffer for when rest of heap full
   148 };
   149 #endif
   150 
   151 
   152 /* ---------- Entry points: ---------- */
   153 
   154 /* There is a little type-delicacy required here as __cxa_throw takes a
   155  * function pointer. Setting aside the problem of not being able to form
   156  * a pointer to a destructor in C++, if we simply say extern "C" here
   157  * then the function pointer will also have C linkage and will be a
   158  * pointer to a C function. This causes problems when __cxa_throw is
   159  * defined (unless we repeat the extern "C" at the definition site) because
   160  * the fnptr in the definition gets C++ linkage, hence that __cxa_throw has
   161  * a different signature to the declared one, and so the function we wanted
   162  * doesn't get defined at all.
   163  * Maybe it should just take a void * but this seems more honest.
   164  */
   165 
   166 typedef void *(*cppdtorptr)(void *);
   167 
   168 extern "C" {
   169 
   170   // Protocol routines called directly from application code
   171 
   172   IMPORT_C void *__cxa_allocate_exception(size_t size);
   173   IMPORT_C void __cxa_free_exception(void *);
   174   WEAKDECL void __cxa_throw(void *, const type_info *, cppdtorptr);
   175   IMPORT_C void __cxa_rethrow(void);
   176   IMPORT_C void *__cxa_get_exception_ptr(UCB *);
   177   void *__cxa_begin_catch(UCB *);
   178   IMPORT_C void __cxa_end_catch(void);
   179   IMPORT_C void __cxa_end_cleanup(void);
   180   IMPORT_C const type_info *__cxa_current_exception_type(void);
   181 
   182   // Protocol routines usually called only by the personality routine(s).
   183 
   184   IMPORT_C void __cxa_call_terminate(UCB *);
   185   IMPORT_C void __cxa_call_unexpected(UCB *);
   186   IMPORT_C bool __cxa_begin_cleanup(UCB *);
   187   typedef enum {
   188     ctm_failed = 0,
   189     ctm_succeeded = 1,
   190     ctm_succeeded_with_ptr_to_base = 2
   191   } __cxa_type_match_result;
   192   IMPORT_C __cxa_type_match_result __cxa_type_match(UCB *, const std::type_info *,
   193                                                     bool is_reference_type, void **);
   194 
   195   // Auxilliary routines
   196 
   197   __cxa_eh_globals *__cxa_get_globals(void);
   198   IMPORT_C void __cxa_bad_typeid(void);
   199   IMPORT_C void __cxa_bad_cast(void);
   200 
   201   // Emergency memory buffer management routines
   202 
   203   void *__ARM_exceptions_buffer_init(void);
   204   void *__ARM_exceptions_buffer_allocate(void *, size_t);
   205   void *__ARM_exceptions_buffer_free(void *, void *);
   206 }
   207 
   208 
   209 // Support routines
   210 
   211 #define NAMES __ARM
   212 namespace NAMES {
   213   void default_unexpected_handler(void);
   214   void call_terminate_handler(UCB *);
   215   void eh_catch_semantics(UCB *);
   216   bool is_foreign_exception(UCB *);
   217   bool same_exceptions_class(const void *, const void *);
   218   __cxa_exception *get_foreign_intermediary(__cxa_exception *, UCB *);
   219 }
   220 
   221 // Macro: convert ucb pointer to __cxa_exception pointer
   222 
   223 #define ucbp_to_ep(UCB_P) ((__cxa_exception *)((char *)(UCB_P) - offsetof(__cxa_exception, ucb)))
   224 
   225 
   226 #ifdef arm_exceptions_globs_c
   227 
   228 /* --------- Allocating and retrieving "globals": --------- */
   229 
   230 // The exception-handling globals should be allocated per-thread.
   231 // This is done here assuming the existance of a zero-initialised void*
   232 // pointer location obtainable by the macro EH_GLOBALS.
   233 
   234 // Default terminate handler:
   235 
   236 #ifndef __EPOC32__
   237 static void __default_terminate_handler(void) {
   238   abort();
   239 }
   240 #endif
   241 
   242 // If std::unexpected() is in the image, include a default handler for it:
   243 namespace NAMES { WEAKDECL void default_unexpected_handler(void); }
   244 
   245 // ARM's toolchain documentation states that if symbol
   246 // __ARM_exceptions_buffer_required is present we should allocate
   247 // an emergency buffer.
   248 // As we aren't allowed static data in ARM library builds, reference the
   249 // symbol by declaring it a function. This causes an additional problem when
   250 // ARM libraries are built position-independent, namely that an absent
   251 // function doesn't compare address-equal to NULL. So we have to get the
   252 // "addresses" from two different compilation units and compare those.
   253 // This is a known defect, to be fixed in the compiler.
   254 extern "C" WEAKDECL void __ARM_exceptions_buffer_required(void);
   255 extern void (*(__ARM_exceptions_buffer_required_address(void)))(void);
   256 
   257 // The address comparison function only needs to be used when we are building 
   258 // position-independent.  In other cases, comparing the address to NULL is more
   259 // efficient.
   260 #if 0
   261 #  define ARM_EXCEPTIONS_BUFFER_NOT_REQUIRED() (&__ARM_exceptions_buffer_required != __ARM_exceptions_buffer_required_address())
   262 #else
   263 #  define ARM_EXCEPTIONS_BUFFER_NOT_REQUIRED() (&__ARM_exceptions_buffer_required == NULL)
   264 #endif
   265 
   266 // __cxa_eh_globals returns the per-thread memory. There are several complications,
   267 // all of which relate to not touching the exceptions system while trying to
   268 // initialise it:
   269 // 1) We can't obtain memory by calling new or nothrow new as both of these use
   270 //    exceptions internally, so we must use malloc
   271 // 2) We choose not to initialise the memory via placement new and a constructor,
   272 //    since placement new is declared with an empty function exception specification,
   273 //    which causes more of the exceptions system to always be pulled in.
   274 // 3) We can't call terminate, as terminate looks in the memory we are trying to
   275 //    allocate.
   276 
   277 EXPORT_C __cxa_eh_globals *__cxa_get_globals(void)
   278 {
   279   __cxa_eh_globals *this_thread_globals = (__cxa_eh_globals *)(EH_GLOBALS);
   280 
   281 #ifndef __EPOC32__
   282   /* The Symbian implementation allocates the required space on the threads stack
   283      at thread creation and sets up thread local storage to point to the globals
   284      which are also initialised
   285   */
   286   if (this_thread_globals == NULL) {
   287 
   288     // First call
   289     // Obtain some memory: this is thread-safe provided malloc is.
   290     this_thread_globals = (__cxa_eh_globals *)malloc(sizeof(__cxa_eh_globals));
   291     if (this_thread_globals == NULL) abort(); // NOT terminate(), which calls this fn
   292 
   293     // Save the pointer in the specially-provided location
   294     EH_GLOBALS = this_thread_globals;
   295 
   296     // Finally initialise the memory by hand
   297     this_thread_globals->uncaughtExceptions = 0;
   298     this_thread_globals->unexpectedHandler = NAMES::default_unexpected_handler;
   299     this_thread_globals->terminateHandler = __default_terminate_handler;
   300     this_thread_globals->implementation_ever_called_terminate = false;
   301     this_thread_globals->call_hook = NULL;
   302     this_thread_globals->caughtExceptions = NULL;
   303     this_thread_globals->propagatingExceptions = NULL;
   304     if (ARM_EXCEPTIONS_BUFFER_NOT_REQUIRED())
   305       this_thread_globals->emergency_buffer = NULL;
   306     else
   307       this_thread_globals->emergency_buffer = __ARM_exceptions_buffer_init();
   308   }
   309 #endif
   310   return this_thread_globals;
   311 }
   312 
   313 
   314 #endif /* arm_exceptions_globs_c */
   315 #ifdef arm_exceptions_mem_c
   316 
   317 /* --------- Emergency memory: --------- */
   318 
   319 // It is possible to reserve memory for throwing bad_alloc when the heap
   320 // is otherwise full. The ARM implementation provides hooks to do this.
   321 // The default implementation reserves just enough space for a bad_alloc
   322 // object, so if memory is later exhausted bad_alloc can still be thrown.
   323 // Note there is no guarantee or requirement that the exception being
   324 // thrown is actually bad_alloc.
   325 
   326 // A usage flag and enough space for a bad_alloc exception control object
   327 #ifndef __EPOC32__
   328 struct emergency_eco {
   329   __cxa_exception ep;
   330   std::bad_alloc b;
   331 };
   332 
   333 struct emergency_buffer {
   334   bool inuse;
   335   struct emergency_eco eco;
   336 };
   337 
   338 #endif
   339 
   340 #ifndef __EPOC32__
   341 // The SymbianOS implementation allocates this space at thread creation
   342 
   343 // Initialiser
   344 void* __ARM_exceptions_buffer_init(void)
   345 {
   346   emergency_buffer *buffer = (emergency_buffer *)malloc(sizeof(emergency_buffer));
   347   if (buffer == NULL) return NULL;
   348   buffer->inuse = false;
   349   return buffer;
   350 }
   351 #endif
   352 
   353 // Allocator
   354 void *__ARM_exceptions_buffer_allocate(void *buffer, size_t size)
   355 {
   356   emergency_buffer *b = (emergency_buffer *)buffer;
   357   if (size > sizeof(emergency_eco) || b == NULL || b->inuse) return NULL;
   358   b->inuse = true;
   359   return &b->eco;
   360 }
   361 
   362 // Deallocator: Must return non-NULL if and only if it recognises
   363 // and releases the supplied object
   364 void *__ARM_exceptions_buffer_free(void *buffer, void *addr)
   365 {
   366   emergency_buffer *b = (emergency_buffer *)buffer;
   367   if (b == NULL || addr != &b->eco) return NULL;
   368   b->inuse = false;
   369   return b;
   370 }
   371 
   372 #  if 0
   373 // Hook activation support - see comments earlier
   374 extern "C" WEAKDECL void __ARM_exceptions_buffer_required(void);
   375 void (*(__ARM_exceptions_buffer_required_address(void)))(void)
   376 {
   377   return &__ARM_exceptions_buffer_required;
   378 }
   379 #  endif
   380 
   381 
   382 #endif /* arm_exceptions_mem_c */
   383 #ifdef arm_exceptions_uncaught_c
   384 
   385 /* ---- uncaught_exception() ---- */
   386 
   387 /* The EDG (and I think our) interpretation is that if the implementation
   388  * ever called terminate(), uncaught_exception() should return true.
   389  */
   390 #if __ARMCC_VERSION < 220000
   391 bool std::uncaught_exception(void)
   392 #else
   393 EXPORT_C bool std::uncaught_exception(void)
   394 #endif
   395 {
   396    __cxa_eh_globals *g = __cxa_get_globals();
   397    return g->implementation_ever_called_terminate || g->uncaughtExceptions;
   398 }
   399 
   400 
   401 #endif /* arm_exceptions_uncaught_c */
   402 #ifdef arm_exceptions_terminate_c
   403 
   404 /* ---- terminate() etc ---- */
   405 
   406 /* The behaviour of terminate() must differ between calls by the
   407  * implementation and calls by the application. This is achieved by having the
   408  * implementation set call_hook immediately before the call to terminate().
   409  * The hook called by terminate() should terminate the program without
   410  * returning to the caller. There is no requirement for terminate() itself to
   411  * intercept throws.
   412  */
   413 
   414 EXPORT_C void std::terminate(void)
   415 {
   416   __cxa_eh_globals *g = __cxa_get_globals();
   417 
   418   if (g->call_hook != NULL) {
   419     // Clear then call hook fn we were passed
   420     handler call_hook = g->call_hook;
   421     g->call_hook = NULL;
   422     call_hook();
   423   } else {
   424     // Call global hook fn
   425     g->terminateHandler();
   426   }
   427   // If hook fn returns:
   428   abort();
   429 }
   430 
   431 
   432 #endif /* arm_exceptions_terminate_c */
   433 #ifdef arm_exceptions_setterminate_c
   434 
   435 EXPORT_C terminate_handler std::set_terminate(terminate_handler h) throw()
   436 {
   437   __cxa_eh_globals *g = __cxa_get_globals();
   438   terminate_handler old = g->terminateHandler;
   439   g->terminateHandler = h;
   440   return old;
   441 }
   442 
   443 
   444 #endif /* arm_exceptions_setterminate_c */
   445 #ifdef arm_exceptions_unexpected_c
   446 
   447 /* ---- unexpected() etc ---- */
   448 /* Comments as per terminate() */
   449 
   450 void NAMES::default_unexpected_handler(void) {
   451   terminate();
   452 }
   453 
   454 #pragma exceptions_unwind
   455 
   456 EXPORT_C void std::unexpected(void)
   457 {
   458   __cxa_eh_globals *g = __cxa_get_globals();
   459 
   460   if (g->call_hook != NULL) {
   461     // Clear then call hook fn we were passed
   462     handler call_hook = g->call_hook;
   463     g->call_hook = NULL;
   464     call_hook();
   465   } else {
   466     // Call global hook fn
   467     g->unexpectedHandler();
   468   }
   469 
   470   // If hook fn returns:
   471   abort();
   472 }
   473 
   474 
   475 #endif /* arm_exceptions_unexpected_c */
   476 #ifdef arm_exceptions_setunexpected_c
   477 
   478 EXPORT_C unexpected_handler std::set_unexpected(unexpected_handler h) throw()
   479 {
   480   __cxa_eh_globals *g = __cxa_get_globals();
   481   unexpected_handler old = g->unexpectedHandler;
   482   g->unexpectedHandler = h;
   483   return old;
   484 }
   485 
   486 
   487 #endif /* arm_exceptions_setunexpected_c */
   488 #ifdef arm_exceptions_support_c
   489 
   490 /* ---------- Helper functions: ---------- */
   491 
   492 /* Two routines to determine whether two exceptions objects share a layout.
   493  * This is determined by checking whether the UCB exception_class members
   494  * are identical.
   495  * In principle we could use memcmp to perform this check (the code is
   496  * given below) but the check is quite frequent and so that is costly.
   497  * Therefore for efficiency we make use of the fact that the UCB is
   498  * word aligned, that the exception_class member is consequently
   499  * word aligned within it, and that we know the size of the member.
   500  * We take care elsewhere to only ever call the routines with pointers
   501  * to word-aligned addresses.
   502  */
   503 
   504 #if 0
   505 
   506 // Straightforward versions
   507 
   508 bool NAMES::same_exceptions_class(const void *ec1, const void *ec2)
   509 {
   510   return memcmp(ec1, ec2, EXCEPTIONS_CLASS_SIZE) == 0; // identical
   511 }
   512 
   513 // One of our exception objects, or not?
   514 
   515 bool NAMES::is_foreign_exception(UCB *ucbp)
   516 {
   517   return !NAMES::same_exceptions_class(&ucbp->exception_class, ARMCPP_EXCEPTIONS_CLASS);
   518 }
   519 
   520 #else
   521 
   522 // Faster versions
   523 
   524 bool NAMES::same_exceptions_class(const void *ec1, const void *ec2)
   525 {
   526   uint32_t *ip1 = (uint32_t *)ec1;
   527   uint32_t *ip2 = (uint32_t *)ec2;
   528   return ip1[0] == ip2[0] && ip1[1] == ip2[1];
   529 }
   530 
   531 // One of our exception objects, or not?
   532 
   533 bool NAMES::is_foreign_exception(UCB *ucbp)
   534 {
   535   // Need a word-aligned copy of the string
   536   static const union {
   537     const char s[EXCEPTIONS_CLASS_SIZE+1]; int dummy;
   538   } is_foreign_exception_static = {ARMCPP_EXCEPTIONS_CLASS};
   539   return !NAMES::same_exceptions_class(&ucbp->exception_class, &is_foreign_exception_static.s);
   540 }
   541 
   542 #endif
   543 
   544 
   545 #endif /* arm_exceptions_support_c */
   546 #ifdef arm_exceptions_callterm_c
   547 
   548 /* When the implementation wants to call terminate(), do the following:
   549  * Mark the object as "caught" so it can be rethrown.
   550  * Set the hook function for terminate() to call;
   551  * Mark the fact that terminate() has been called by the implementation;
   552  * We have to be careful - the implementation might encounter an error while
   553  * unwinding a foreign exception, and also it is possible this might be
   554  * called after failing to obtain a ucb.
   555  */
   556 
   557 void NAMES::call_terminate_handler(UCB *ucbp)
   558 {
   559   __cxa_eh_globals *g = __cxa_get_globals();
   560 
   561   if (ucbp == NULL) {
   562     // Call global hook
   563     g->call_hook = g->terminateHandler;
   564   } else {
   565     // Extract the hook to call
   566     if (NAMES::is_foreign_exception(ucbp)) {
   567       // Someone else's
   568       g->call_hook = g->terminateHandler;  // best we can do under the circumstances
   569     } else {
   570       // One of ours
   571       __cxa_exception *ep = ucbp_to_ep(ucbp);
   572       g->call_hook = ep->terminateHandler; // the one in force at the point of throw
   573     }
   574   }
   575 
   576   g->implementation_ever_called_terminate = true;
   577   terminate();
   578   // never returns
   579 }
   580 
   581 
   582 EXPORT_C void __cxa_call_terminate(UCB *ucbp)
   583 {
   584   if (ucbp != NULL) // Record entry to (implicit) handler
   585     __cxa_begin_catch(ucbp);
   586 
   587   NAMES::call_terminate_handler(ucbp);
   588   // never returns
   589 }
   590 
   591 
   592 #endif /* arm_exceptions_callterm_c */
   593 #ifdef arm_exceptions_callunex_c
   594 
   595 /* When the implementation wants to call unexpected(), do the following:
   596  * Mark the object as "caught" so it can be rethrown.
   597  * Set the hook function for unexpected() to call;
   598  * Call unexpected and trap any throw to make sure it is acceptable.
   599  * We have to be careful - the implementation might encounter an error while
   600  * unwinding a foreign exception.
   601  */
   602 
   603 #pragma exceptions_unwind
   604 
   605 EXPORT_C void __cxa_call_unexpected(UCB *ucbp)
   606 {
   607 
   608   // Extract data we will need from the barrier cache before
   609   // anyone has a chance to overwrite it
   610 
   611   uint32_t rtti_count = ucbp->barrier_cache.bitpattern[BARRIER_FNSPECCOUNT];
   612   uint32_t base = ucbp->barrier_cache.bitpattern[BARRIER_FNSPECBASE];
   613   uint32_t stride = ucbp->barrier_cache.bitpattern[BARRIER_FNSPECSTRIDE];
   614   uint32_t rtti_offset_array_addr = ucbp->barrier_cache.bitpattern[BARRIER_FNSPECARRAY];
   615 
   616   // Also get the globals here and the eop
   617 
   618   __cxa_eh_globals *g = __cxa_get_globals();
   619   __cxa_exception *ep = ucbp_to_ep(ucbp);
   620 
   621 #ifdef ARM_EXCEPTIONS_ENABLED
   622   try {
   623 #endif
   624 
   625     // Record entry to (implicit) handler
   626 
   627     __cxa_begin_catch(ucbp);
   628 
   629     // Now extract the hook to call
   630 
   631     if (NAMES::is_foreign_exception(ucbp)) {
   632       // Someone else's
   633       g->call_hook = g->unexpectedHandler;  // best we can do under the circumstances
   634     } else {
   635       // One of ours
   636       g->call_hook = ep->unexpectedHandler; // the one in force at the point of throw
   637     }
   638     unexpected();  // never returns normally, but might throw something
   639 
   640 #ifdef ARM_EXCEPTIONS_ENABLED
   641   } catch (...) {
   642 
   643     // Unexpected() threw. This requires some delicacy.
   644     // There are 2 possibilities:
   645     // i) rethrow of the same object
   646     // ii) throw of a new object
   647     // Unexpected() is an implicit handler, and we manually called
   648     // __cxa_begin_catch on the ingoing object. We need to call
   649     // __cxa_end_catch on that object and, if the object is no longer
   650     // being handled (possible in case ii), this will cause its destruction.
   651     // The wrinkle is that in case ii the object is not on top of the catch
   652     // stack because we just caught something else.
   653 
   654     // Get hold of what was thrown (which we just caught).
   655 
   656     __cxa_exception *epnew = g->caughtExceptions;
   657 
   658     // Call __cxa_end_catch on the original object, taking care with the catch chain
   659 
   660     if (epnew == ep) {
   661       // rethrow - easy & safe - object is at top of chain and handlercount > 1
   662       __cxa_end_catch();
   663     } else {
   664       // not rethrow - unchain the top (new) object, clean up the next one,
   665       // and put the top object back
   666 
   667       // unchain
   668       g->caughtExceptions = epnew->nextCaughtException;
   669       // assert g->caughtExceptions == ep now
   670       // Decrement its handlercount (this might call a dtor if the count goes to 0,
   671       // and the dtor might throw - if it does, just give up)
   672       try {
   673 	__cxa_end_catch();
   674       } catch(...) {
   675 	terminate();
   676       }
   677       // Chain back in
   678       epnew->nextCaughtException = g->caughtExceptions;
   679       g->caughtExceptions = epnew;
   680     }
   681 
   682     // See whether what was thrown is permitted, and in passing
   683     // see if std::bad_exception is permitted
   684 
   685     bool bad_exception_permitted = false;
   686     uint32_t i;
   687     for (i = 0; i < rtti_count; i++) {
   688       void *matched_object;
   689       type_info *fnspec;
   690       if (EHABI_V2(ucbp))
   691 	fnspec = (type_info *)__ARM_resolve_target2((void *)rtti_offset_array_addr);
   692       else
   693 	fnspec = (type_info *)(*(uint32_t *)rtti_offset_array_addr + base);
   694       if (__cxa_type_match(&(epnew->ucb), fnspec, false, &matched_object)) {
   695 #ifdef CPP_DIAGNOSTICS
   696 	printf("__cxa_call_unexpected: fnspec matched\n");
   697 #endif
   698 	throw; // got a match - propagate it
   699       }
   700       if (typeid(std::bad_exception) == *fnspec)
   701 	bad_exception_permitted = true;
   702       rtti_offset_array_addr += stride;
   703     }
   704 
   705     // There was no match...
   706     if (bad_exception_permitted) throw std::bad_exception(); // transmute
   707 
   708     // Otherwise call epnew's terminate handler
   709     NAMES::call_terminate_handler(&epnew->ucb);
   710   }
   711 #endif
   712 }
   713 
   714 
   715 #endif /* arm_exceptions_callunex_c */
   716 #ifdef arm_exceptions_currenttype_c
   717 
   718 /* Yield the type of the currently handled exception, or null if none or the
   719  * object is foreign.
   720  */
   721 
   722 EXPORT_C const type_info *__cxa_current_exception_type(void)
   723 {
   724   __cxa_eh_globals *g = __cxa_get_globals();
   725   __cxa_exception *ep = g->caughtExceptions;
   726   if (ep == NULL || NAMES::is_foreign_exception(&ep->ucb)) return NULL;
   727   return ep->exceptionType;
   728 }
   729 
   730 
   731 #endif /* arm_exceptions_currenttype_c */
   732 #ifdef arm_exceptions_alloc_c
   733 
   734 /* Allocate store for controlling an exception propagation */
   735 
   736 EXPORT_C void *__cxa_allocate_exception(size_t size)
   737 {
   738   __cxa_eh_globals *g = __cxa_get_globals();
   739 
   740   // Allocate store for a __cxa_exception header and the EO.
   741   // Allocated store should be thread-safe and persistent, and must do
   742   // something sensible if the allocation fails
   743 
   744   size_t total_size = size + sizeof(__cxa_exception);
   745   // coverity[alloc_fn]
   746   __cxa_exception *ep = (__cxa_exception *)malloc(total_size);
   747   if (ep == NULL) {
   748     // Try the emergency memory pool
   749     SYMBIAN_EH_SUPPORT_PRINTF("Trying emergency buffer: size %d\n", total_size);
   750     ep = (__cxa_exception *)__ARM_exceptions_buffer_allocate(g->emergency_buffer, total_size);
   751         
   752     if (ep == NULL) {
   753       SYMBIAN_EH_SUPPORT_PRINTF("Emergency buffer allocation failed. Terminating\n");
   754       NAMES::call_terminate_handler(NULL);
   755     }
   756   }
   757 
   758   UCB *ucbp = &ep->ucb;
   759 
   760   // Initialise the UCB
   761 
   762   memcpy(ucbp->exception_class, ARMCPP_EXCEPTIONS_CLASS, EXCEPTIONS_CLASS_SIZE);
   763   ucbp->exception_cleanup = NULL; /* initialise properly before throwing */
   764   ucbp->unwinder_cache.reserved1 = 0; /* required to do this */
   765 
   766   // Initialise parts of the LEO, in case copy-construction of the EO results
   767   // in a need to call terminate (via __cxa_call_terminate)
   768 
   769   ep->handlerCount = 0;                         // Not in any handlers
   770   ep->nextCaughtException = NULL;               // Not in any handlers
   771   ep->nextPropagatingException = NULL;          // Not saved over cleanup
   772   ep->propagationCount = 0;                     // Not propagating
   773   ep->terminateHandler = g->terminateHandler;   // Cache current terminate handler
   774   ep->unexpectedHandler = g->unexpectedHandler; // Cache current unexpected handler
   775 
   776   // Return pointer to the EO
   777   // coverity[memory_leak]
   778   return ep + 1;
   779 }
   780 
   781 
   782 #endif /* arm_exceptions_alloc_c */
   783 #ifdef arm_exceptions_free_c
   784 
   785 /* Free store allocated by __cxa_allocate_exception */
   786 
   787 EXPORT_C void __cxa_free_exception(void *eop)
   788 {
   789   __cxa_eh_globals *g = __cxa_get_globals();
   790   char *ep = (char *)eop - sizeof(__cxa_exception);
   791   if (__ARM_exceptions_buffer_free(g->emergency_buffer, ep)) return;
   792   free(ep);
   793 }
   794 
   795 
   796 #endif /* arm_exceptions_free_c */
   797 #ifdef arm_exceptions_throw_c
   798 
   799 /* This routine is called when a foreign runtime catches one of our exception
   800  * objects and then exits its catch by a means other than rethrow.
   801  * We should clean it up as if we had caught it ourselves.
   802  */
   803 
   804 static void external_exception_termination(_Unwind_Reason_Code c, UCB *ucbp)
   805 {
   806   NAMES::eh_catch_semantics(ucbp);
   807   __cxa_end_catch();
   808 }
   809 
   810 
   811 /* Initiate a throw */
   812 
   813 #pragma push
   814 #pragma exceptions_unwind
   815 
   816 EXPORT_C void __cxa_throw(void *eop, const type_info *t, cppdtorptr d)
   817 {
   818   __cxa_exception *ep = (__cxa_exception *)((char *)eop - sizeof(__cxa_exception));
   819   UCB *ucbp = &ep->ucb;
   820 
   821   // Initialise the remaining LEO and UCB fields not done by __cxa_allocate_exception
   822 
   823   ucbp->exception_cleanup = external_exception_termination;
   824   ep->exceptionType = t;
   825   ep->exceptionDestructor = d;
   826   ep->propagationCount = 1;      // Propagating by 1 throw
   827 
   828   // Increment the uncaught C++ exceptions count
   829 
   830   __cxa_eh_globals *g = __cxa_get_globals();
   831   g->uncaughtExceptions++;
   832 
   833   // Tell debugger what's happening
   834 
   835   DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_STARTING, t);
   836 
   837   // Initiate unwinding - if we get control back, call C++ routine terminate()
   838 
   839   _Unwind_RaiseException(ucbp);
   840 
   841 #ifdef CPP_DIAGNOSTICS
   842   printf("__cxa_throw: throw failed\n");
   843 #endif
   844 
   845   __cxa_call_terminate(ucbp);
   846 }
   847 
   848 #pragma pop
   849 
   850 /* ----- Type matching: ----- */
   851 
   852 /* This is located here so that (in ARM's implementation) it is only retained in
   853  * an image if the application itself throws.
   854  */
   855 
   856 /* Type matching functions.
   857  * C++ DR126 says the matching rules for fnspecs are intended to be the same as
   858  * those for catch:
   859  * "A function is said to allow an exception of type E if its exception-specification
   860  * contains a type T for which a handler of type T would be a match (15.3 except.handle)
   861  * for an exception of type E."
   862  * Thus we have a single type matching rule.
   863  */
   864 
   865 /* Helper macros: */
   866 
   867 #define CV_quals_of_pointee(P) (((const abi::__pbase_type_info *)(P))->__flags & \
   868 		                (abi::__pbase_type_info::__const_mask | \
   869 		                 abi::__pbase_type_info::__volatile_mask))
   870 
   871 #define is_const(QUALS) (((QUALS) & abi::__pbase_type_info::__const_mask) != 0)
   872 
   873 #define any_qualifier_missing(TEST_QUALS, REF_QUALS) ((~(TEST_QUALS) & (REF_QUALS)) != 0)
   874 
   875 /* A routine is required for derived class to base class conversion.
   876  * This is obtained via a macro definition DERIVED_TO_BASE_CONVERSION
   877  * in unwind_env.h.
   878  */
   879 
   880 /* External entry point:
   881  * Type check the c++ rtti object for compatibility against the type of
   882  * the object containing the ucb. Return a pointer to the matched object
   883  * (possibly a non-leftmost baseclass of the exception object)
   884  */
   885 EXPORT_C __cxa_type_match_result __cxa_type_match(UCB *ucbp, const type_info *match_type,
   886                                                   bool is_reference_type, void **matched_objectpp)
   887 {
   888   if (NAMES::is_foreign_exception(ucbp))
   889     return ctm_failed;
   890 
   891   __cxa_exception *ep = ucbp_to_ep(ucbp);
   892   const type_info *throw_type = ep->exceptionType;
   893   bool previous_qualifiers_include_const = true; // for pointer qualification conversion
   894   unsigned int pointer_depth = 0;
   895   void *original_objectp = ep + 1;
   896   void *current_objectp = original_objectp;
   897 
   898   for (;;) {
   899 
   900     // Match if identical
   901 
   902     if (*throw_type == *match_type) {
   903       *matched_objectpp = original_objectp;
   904 #ifdef CPP_DIAGNOSTICS
   905       printf("__cxa_type_match: success\n");
   906 #endif
   907       return ctm_succeeded;
   908     }
   909 
   910     // Fail if one is a pointer and the other isn't
   911 
   912     const type_info &type_throw_type = typeid(*throw_type);
   913     const type_info &type_match_type = typeid(*match_type);
   914 
   915     if ((type_throw_type == typeid(abi::__pointer_type_info) ||
   916 	 type_match_type == typeid(abi::__pointer_type_info)) &&
   917 	type_throw_type != type_match_type) {
   918 #ifdef CPP_DIAGNOSTICS
   919       printf("__cxa_type_match: failed (mixed ptr/non-ptr)\n");
   920 #endif
   921       return ctm_failed;
   922     }
   923 
   924     // Both are pointers or neither is
   925     if (type_throw_type == typeid(abi::__pointer_type_info)) {
   926       // Both are pointers
   927 #ifdef CPP_DIAGNOSTICS
   928       printf("__cxa_type_match: throwing a ptr\n");
   929 #endif
   930       pointer_depth++;
   931       // Check match_type is at least as CV-qualified as throw_type
   932       unsigned int match_quals = CV_quals_of_pointee(match_type);
   933       unsigned int throw_quals = CV_quals_of_pointee(throw_type);
   934       if (any_qualifier_missing(match_quals, throw_quals)) {
   935 #ifdef CPP_DIAGNOSTICS
   936 	printf("__cxa_type_match: failed (missing qualifiers)\n");
   937 #endif
   938 	return ctm_failed;
   939       }
   940       // If the match type has additional qualifiers not found in the
   941       // throw type, any previous qualifiers must have included const
   942       if (any_qualifier_missing(throw_quals, match_quals) &&
   943 	  !previous_qualifiers_include_const) {
   944 #ifdef CPP_DIAGNOSTICS
   945 	printf("__cxa_type_match: failed (not all qualifiers have const)\n");
   946 #endif
   947 	return ctm_failed;
   948       }
   949       if (!is_const(match_quals))
   950 	previous_qualifiers_include_const = false;
   951       throw_type = ((const abi::__pbase_type_info *)throw_type)->__pointee;
   952       match_type = ((const abi::__pbase_type_info *)match_type)->__pointee;
   953       if (current_objectp != NULL)
   954         current_objectp = *(void **)current_objectp;
   955       continue;
   956     }
   957 
   958     // Neither is a pointer now but qualification conversion has been done.
   959     // See if pointer conversion on the original was possible.
   960     // T* will match void*
   961 
   962     if (pointer_depth == 1 && *match_type == typeid(void)) {
   963       if (is_reference_type) {
   964 #ifdef CPP_DIAGNOSTICS
   965         printf("__cxa_type_match: failed (void *&)\n");
   966 #endif
   967         return ctm_failed;
   968       } else {
   969         *matched_objectpp = original_objectp;
   970 #ifdef CPP_DIAGNOSTICS
   971         printf("__cxa_type_match: success (conversion to void *)\n");
   972 #endif
   973         return ctm_succeeded;
   974       }
   975     }
   976 
   977     // Else if we have 2 (different) class types, a derived class is matched by a
   978     // non-ambiguous public base class (perhaps not a leftmost one) and a
   979     // pointer to a derived class is matched by a non-reference pointer to
   980     // non-ambiguous public base class (perhaps not a leftmost one).
   981     // __si_class_type_info and __vmi_class_type_info are classes with bases.
   982 
   983     void *matched_base_p;
   984 
   985     if ((pointer_depth == 0 || (pointer_depth == 1 && !is_reference_type)) &&
   986 	(type_throw_type == typeid(abi::__si_class_type_info) ||
   987 	 type_throw_type == typeid(abi::__vmi_class_type_info))) {
   988       if (DERIVED_TO_BASE_CONVERSION(current_objectp, &matched_base_p,
   989 				     throw_type, match_type)) {
   990 #ifdef CPP_DIAGNOSTICS
   991 	printf("__cxa_type_match: success (matched base 0x%x of 0x%x%s, thrown object 0x%x)\n",
   992 	       matched_base_p, current_objectp,
   993 	       pointer_depth == 0 ? "" : " via ptr",
   994 	       original_objectp);
   995 #endif
   996         *matched_objectpp = matched_base_p;
   997         return pointer_depth == 0 ? ctm_succeeded : ctm_succeeded_with_ptr_to_base;
   998       } else {
   999 #ifdef CPP_DIAGNOSTICS
  1000 	printf("__cxa_type_match: failed (derived to base failed or ref to base pointer)\n");
  1001 #endif
  1002 	return ctm_failed;
  1003       }
  1004     }
  1005 
  1006 #ifdef CPP_DIAGNOSTICS
  1007     printf("__cxa_type_match: failed (types simply differ)\n");
  1008 #endif
  1009     return ctm_failed;
  1010   } /* for */
  1011 }
  1012 
  1013 
  1014 /* For debugging purposes: */
  1015 #ifdef DEBUG
  1016 extern "C" bool debug__cxa_type_match(void *objptr,
  1017 				      const type_info *throw_type,
  1018 				      const type_info *catch_type,
  1019 				      void **matched_objectpp)
  1020 {
  1021   /* Create enough of an exception object that the type-matcher can run, then
  1022    * check the type. Objptr is expected to be the result of a call to
  1023    * __cxa_allocate_exception, which has then been copy-constructed.
  1024    */
  1025   __cxa_exception *e = ((__cxa_exception *)objptr) - 1;
  1026   e->exceptionType = throw_type;
  1027   return __cxa_type_match(&e->ucb, catch_type, false, matched_objectpp);
  1028 }
  1029 #endif
  1030 
  1031 
  1032 #endif /* arm_exceptions_throw_c */
  1033 #ifdef arm_exceptions_rethrow_c
  1034 
  1035 /* Redeclare _Unwind_RaiseException as weak (if WEAKDECL is defined
  1036  * appropriately) so the use from __cxa_rethrow does not on its own
  1037  * force the unwind library to be loaded.
  1038  */
  1039 
  1040 extern "C" WEAKDECL _Unwind_Reason_Code _Unwind_RaiseException(UCB *ucbp);
  1041 
  1042 #pragma exceptions_unwind
  1043 
  1044 EXPORT_C void __cxa_rethrow(void)
  1045 {
  1046   // Recover the exception object - it is the most recent caught exception object
  1047   __cxa_eh_globals *g = __cxa_get_globals();
  1048   __cxa_exception *ep = g->caughtExceptions;
  1049   bool foreign;
  1050 
  1051   // Must call terminate here if no such exception
  1052   if (ep == NULL) NAMES::call_terminate_handler(NULL);
  1053 
  1054   UCB *ucbp = &ep->ucb;
  1055 
  1056   // Mark the object as being propagated by throw, preventing multiple
  1057   // propagation and also permitting __cxa_end_catch to do the right
  1058   // thing when it is called from the handler's cleanup.
  1059 
  1060   ep->propagationCount++;
  1061 
  1062   // Now reraise, taking care with foreign exceptions
  1063 
  1064   foreign = NAMES::is_foreign_exception(ucbp);
  1065   if (foreign) {
  1066     // Indirect through the intermediate object to the foreign ucb
  1067     ucbp = (UCB *)ep->exceptionType;
  1068   } else {
  1069     // Increment the uncaught C++ exceptions count
  1070     g->uncaughtExceptions++;
  1071   }
  1072 
  1073   // Tell debugger what's happening
  1074 
  1075   DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_STARTING, foreign ? NULL : ep->exceptionType);
  1076 
  1077   // Initiate unwinding - if we get control back, call C++ routine terminate()
  1078 
  1079   _Unwind_RaiseException(ucbp);
  1080 
  1081 #ifdef CPP_DIAGNOSTICS
  1082   printf("__cxa_rethrow: throw failed\n");
  1083 #endif
  1084 
  1085   __cxa_call_terminate(ucbp);
  1086 }
  1087 
  1088 #endif /* arm_exceptions_rethrow_c */
  1089 #ifdef arm_exceptions_foreign_c
  1090 
  1091 /* During catch and cleanup, foreign exception objects are dealt with using
  1092  * an intermediate __cxa_exception block in the appropriate exceptions
  1093  * chain. This block has the same exception_class as the real foreign
  1094  * ucb, and points to the real ucb via the intermediate block's exceptionType
  1095  * field. This helper function checks whether it has been passed such an
  1096  * intermediate block and sets one up if not. Only call it when the UCB
  1097  * is known to belong to a foreign exception.
  1098  */
  1099 
  1100 __cxa_exception *NAMES::get_foreign_intermediary(__cxa_exception *head_ep, UCB *ucbp)
  1101 {
  1102   if (head_ep != NULL) {
  1103     UCB *head_ucbp = &head_ep->ucb;
  1104     if (NAMES::same_exceptions_class(&head_ucbp->exception_class, &ucbp->exception_class) &&
  1105 	(UCB *)head_ep->exceptionType == ucbp)
  1106       return head_ep;
  1107   }
  1108 
  1109   // Create an intermediate block. Only initialise as much as necessary
  1110   __cxa_exception *ep = ((__cxa_exception *)__cxa_allocate_exception(0)) - 1;
  1111   UCB *new_ucbp = &ep->ucb;
  1112   memcpy(new_ucbp->exception_class, ucbp->exception_class, EXCEPTIONS_CLASS_SIZE);
  1113   ep->propagationCount = 0;                     // Not propagating
  1114   ep->handlerCount = 0;                         // Not handled
  1115   ep->nextCaughtException = NULL;               // Not in chain
  1116   ep->exceptionType = (const type_info *)ucbp;  // The foreign UCB
  1117   return ep;
  1118 }
  1119 
  1120 
  1121 #endif /* arm_exceptions_foreign_c */
  1122 #ifdef arm_exceptions_cleanup_c
  1123 
  1124 EXPORT_C bool __cxa_begin_cleanup(UCB *ucbp)
  1125 {
  1126   // Indicate that a cleanup is about to start.
  1127   // Save the exception pointer over the cleanup for recovery later, using a chain.
  1128   // If we allowed the exception to be rethrown in a cleanup, then
  1129   // the object might appear multiple times at the head of this chain,
  1130   // and the propagationCount could be used to track this - at this point,
  1131   // the object is logically in the chain propagationCount-1 times, and
  1132   // physically 0 or 1 times. Thus if propagationCount == 1 we should insert
  1133   // it physically. A similar rule is used for physical removal in
  1134   //__cxa_end_cleanup.
  1135   // Foreign exceptions are handled via an intermediate __cxa_exception object
  1136   // in a similar way as __cxa_begin_catch.
  1137 
  1138   __cxa_eh_globals *g = __cxa_get_globals();
  1139   __cxa_exception *ep;
  1140 
  1141   if (NAMES::is_foreign_exception(ucbp)) {
  1142 	// coverity[alloc_fn] coverity[var_assign]
  1143     ep = NAMES::get_foreign_intermediary(g->propagatingExceptions, ucbp);
  1144     ep->propagationCount++;  // Indicate one (or one additional) propagation
  1145   } else {
  1146     ep = ucbp_to_ep(ucbp);
  1147   }
  1148 
  1149   if (ep->propagationCount == 1) {
  1150     // Insert into chain
  1151     ep->nextPropagatingException = g->propagatingExceptions;
  1152     g->propagatingExceptions = ep;
  1153   }
  1154   // coverity[leaked_storage]
  1155   return true;
  1156 }
  1157 
  1158 
  1159 // Helper function for __cxa_end_cleanup
  1160 
  1161 extern "C" UCB * __ARM_cxa_end_cleanup(void)
  1162 {
  1163   // Recover and return the currently propagating exception (from the
  1164   // head of the propagatingExceptions chain).
  1165   // propagationCount at this moment is a logical count of how many times the
  1166   // item is in the chain so physically unchain it when this count is 1.
  1167   // Foreign exceptions use an intermediary.
  1168 
  1169   __cxa_eh_globals *g = __cxa_get_globals();
  1170   __cxa_exception *ep = g->propagatingExceptions;
  1171 
  1172   if (ep == NULL) terminate();
  1173 
  1174   UCB *ucbp = &ep->ucb;
  1175   if (NAMES::is_foreign_exception(ucbp)) {
  1176     // Get the foreign ucb
  1177     ucbp = (UCB *)ep->exceptionType;
  1178     if (ep->propagationCount == 1) {
  1179       // Free the intermediate ucb (see description in __cxa_begin_catch)
  1180       void *eop = (void *)(ep + 1);
  1181       g->propagatingExceptions = ep->nextPropagatingException;
  1182       __cxa_free_exception(eop);
  1183     } else {
  1184       ep->propagationCount--;
  1185     }
  1186   } else {
  1187     // Not foreign
  1188     if (ep->propagationCount == 1) { // logically in chain once - so unchain
  1189       g->propagatingExceptions = ep->nextPropagatingException;
  1190     }
  1191   }
  1192   return ucbp;
  1193 }
  1194 
  1195 // __cxa_end_cleanup is called at the end of a cleanup fragment.
  1196 // It must do the C++ housekeeping, then call _Unwind_Resume, but it must
  1197 // damage no significant registers in the process.
  1198 
  1199 EXPORT_C __asm void __cxa_end_cleanup(void) {
  1200   extern __ARM_cxa_end_cleanup;
  1201   extern _Unwind_Resume WEAKASMDECL;
  1202 
  1203 #ifdef __thumb
  1204   preserve8;                   // This is preserve8 (ARM assembler heuristics are inadequate)
  1205   push {r1-r7};
  1206   mov r2, r8;
  1207   mov r3, r9;
  1208   mov r4, r10;
  1209   mov r5, r11;
  1210   push {r1-r5};
  1211   bl __ARM_cxa_end_cleanup;    // returns UCB address in r0
  1212   pop {r1-r5};
  1213   mov r8, r2;
  1214   mov r9, r3;
  1215   mov r10, r4;
  1216   mov r11, r5;
  1217   pop {r1-r7};
  1218   bl _Unwind_Resume;           // won't return
  1219 #else
  1220   stmfd r13!, {r1-r12}
  1221   bl __ARM_cxa_end_cleanup;    // returns UCB address in r0
  1222   ldmia r13!, {r1-r12};
  1223   b _Unwind_Resume;            // won't return
  1224 #endif
  1225 }
  1226 
  1227 
  1228 #endif /* arm_exceptions_cleanup_c */
  1229 #ifdef arm_exceptions_catchsemantics_c
  1230 
  1231 /* Update date structures as if catching an object.
  1232  * Call this from __cxa_begin_catch when actually catching an object,
  1233  * and from external_exception_termination when called by a foreign runtime
  1234  * after one of our objects was caught.
  1235  */
  1236 
  1237 void NAMES::eh_catch_semantics(UCB *ucbp)
  1238 {
  1239   __cxa_eh_globals *g = __cxa_get_globals();
  1240   __cxa_exception *ep;
  1241 
  1242   if (NAMES::is_foreign_exception(ucbp)) {
  1243     // Foreign exception. Get the associated intermediary block or
  1244     // make one if there isn't one already.
  1245     // In the case of a rethrow, the foreign object may already be on
  1246     // the handled exceptions chain (it will be first).
  1247 	// coverity[alloc_fn] coverity[var_assign]
  1248     ep = NAMES::get_foreign_intermediary(g->caughtExceptions, ucbp);
  1249   } else {
  1250     // Not foreign
  1251     ep = ucbp_to_ep(ucbp);
  1252     // Decrement the propagation count
  1253     ep->propagationCount--;
  1254     // Decrement the total uncaught C++ exceptions count
  1255     g->uncaughtExceptions--;
  1256   }
  1257 
  1258   // Common code for our EO's, and foreign ones where we work on the intermediate EO
  1259 
  1260   // Increment the handler count for this exception object
  1261   ep->handlerCount++;
  1262 
  1263   // Push the ep onto the "handled exceptions" chain if it is not already there.
  1264   // (If catching a rethrow, it may already be there)
  1265 
  1266   if (ep->nextCaughtException == NULL) {
  1267     ep->nextCaughtException = g->caughtExceptions;
  1268     g->caughtExceptions = ep;
  1269   }
  1270   // coverity[leaked_storage]
  1271 }
  1272 
  1273 
  1274 #endif /* arm_exceptions_catchsemantics_c */
  1275 #ifdef arm_exceptions_getexceptionptr_c
  1276 
  1277 EXPORT_C void *__cxa_get_exception_ptr(UCB *ucbp)
  1278 {
  1279   return (void *)ucbp->barrier_cache.bitpattern[BARRIER_HANDLEROBJECT]; // The matched object, if any
  1280 }
  1281 
  1282 
  1283 #endif /* arm_exceptions_getexceptionptr_c */
  1284 #ifdef arm_exceptions_begincatch_c
  1285 
  1286 void *__cxa_begin_catch(UCB *ucbp)
  1287 {
  1288   void *match = (void *)ucbp->barrier_cache.bitpattern[BARRIER_HANDLEROBJECT]; // The matched object, if any
  1289 
  1290   // Update the data structures
  1291 
  1292   NAMES::eh_catch_semantics(ucbp);
  1293 
  1294   // Tell the unwinder the exception propagation has finished,
  1295   // and return the object pointer
  1296 
  1297   _Unwind_Complete(ucbp);
  1298   return match;
  1299 }
  1300 
  1301 
  1302 #endif /* arm_exceptions_begincatch_c */
  1303 #ifdef arm_exceptions_endcatch_c
  1304 
  1305 #pragma exceptions_unwind
  1306 
  1307 EXPORT_C void __cxa_end_catch(void)
  1308 {
  1309   // Recover the exception object - it is the most recent caught exception object
  1310   __cxa_eh_globals *g = __cxa_get_globals();
  1311   __cxa_exception *ep = g->caughtExceptions;
  1312 
  1313   if (ep == NULL) terminate();
  1314 
  1315   // Rethrow in progress?
  1316 
  1317   bool object_being_rethrown = ep->propagationCount != 0;
  1318 
  1319   // Decrement the handler count for this exception object
  1320   ep->handlerCount--;
  1321 
  1322   // Unstack the object if it is no longer being handled anywhere.
  1323   // Destroy and free the object if it is no longer alive -
  1324   // it is dead if its handler count becomes 0, unless it is
  1325   // about to be rethrown.
  1326   // If the dtor throws, allow its exception to propagate.
  1327   // Do different things if it is a foreign exception object.
  1328 
  1329   if (ep->handlerCount == 0) {
  1330     void *eop = (void *)(ep + 1);
  1331     UCB *ucbp = &ep->ucb;
  1332     bool foreign = NAMES::is_foreign_exception(ucbp);
  1333 
  1334     // Unstack it from the caught exceptions stack - it is guaranteed to be top item.
  1335     g->caughtExceptions = ep->nextCaughtException;
  1336 
  1337     if (foreign) {
  1338       // Get the foreign ucb and free the intermediate ucb (see description in __cxa_begin_catch)
  1339       ucbp = (UCB *)ep->exceptionType;
  1340       __cxa_free_exception(eop);
  1341     } else {
  1342       ep->nextCaughtException = NULL;  // So __cxa_begin_catch knows it isn't in the chain
  1343     }
  1344 
  1345     // Now destroy the exception object if it's no longer needed
  1346     if (!object_being_rethrown) {
  1347       if (foreign) {
  1348 
  1349 	// Notify the foreign language, if it so requested
  1350 	if (ucbp->exception_cleanup != NULL)
  1351 	  (ucbp->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, ucbp);
  1352 
  1353       } else {
  1354 
  1355         // One of our objects: do C++-specific semantics
  1356 
  1357 	if (ep->exceptionDestructor != NULL) {
  1358 	  // Run the dtor. If it throws, free the memory anyway and
  1359 	  // propagate the new exception.
  1360 #ifdef ARM_EXCEPTIONS_ENABLED
  1361 	  try {
  1362 	    (ep->exceptionDestructor)(eop);
  1363 	  } catch(...) {
  1364 	    // Free the memory and reraise
  1365 	    __cxa_free_exception(eop);
  1366 	    throw;
  1367 	  }
  1368 #else
  1369 	  (ep->exceptionDestructor)(eop);
  1370 #endif
  1371 	}
  1372 	// Dtor (if there was one) didn't throw. Free the memory.
  1373 	__cxa_free_exception(eop);
  1374       }  // !foreign
  1375     }  // !object_being_rethrown
  1376   }  // ep->handlerCount == 0
  1377 }
  1378 
  1379 
  1380 #endif /* arm_exceptions_endcatch_c */
  1381 #ifdef arm_exceptions_bad_typeid_c
  1382 
  1383 #pragma exceptions_unwind
  1384 
  1385 EXPORT_C void __cxa_bad_typeid(void)
  1386 {
  1387   throw std::bad_typeid();
  1388 }
  1389 
  1390 
  1391 #endif /* arm_exceptions_bad_typeid_c */
  1392 #ifdef arm_exceptions_bad_cast_c
  1393 
  1394 #pragma exceptions_unwind
  1395 
  1396 EXPORT_C void __cxa_bad_cast(void)
  1397 {
  1398   throw std::bad_cast();
  1399 }
  1400 
  1401 
  1402 #endif /* arm_exceptions_bad_cast_c */