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