kernel/eka/compsupp/symaehabi/cppsemantics.cpp
changeset 9 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     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 */