os/kernelhwsrv/kernel/eka/compsupp/aehabi/cppsemantics.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kernel/eka/compsupp/aehabi/cppsemantics.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1311 @@
     1.4 +/* The C++ exceptions runtime support
     1.5 + *
     1.6 + * Copyright 2002-2003 ARM Limited.
     1.7 + */
     1.8 +/*
     1.9 +  Licence
    1.10 +
    1.11 +  1. Subject to the provisions of clause 2, ARM hereby grants to LICENSEE a
    1.12 +  perpetual, non-exclusive, nontransferable, royalty free, worldwide licence
    1.13 +  to use this Example Implementation of Exception Handling solely for the
    1.14 +  purpose of developing, having developed, manufacturing, having
    1.15 +  manufactured, offering to sell, selling, supplying or otherwise
    1.16 +  distributing products which comply with the Exception Handling ABI for the
    1.17 +  ARM Architecture specification. All other rights are reserved to ARM or its
    1.18 +  licensors.
    1.19 +
    1.20 +  2. THIS EXAMPLE IMPLEMENTATION OF EXCEPTION HANDLING  IS PROVIDED "AS IS"
    1.21 +  WITH NO WARRANTIES EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED
    1.22 +  TO ANY WARRANTY OF SATISFACTORY QUALITY, MERCHANTABILITY, NONINFRINGEMENT
    1.23 +  OR FITNESS FOR A PARTICULAR PURPOSE.
    1.24 +*/
    1.25 +/*
    1.26 + * RCS $Revision: 1.29.2.1 $
    1.27 + * Checkin $Date: 2004/01/20 15:11:16 $
    1.28 + * Revising $Author: achapman $
    1.29 + */
    1.30 +
    1.31 +/* This source file is compiled automatically by ARM's make system into
    1.32 + * multiple object files. The source regions constituting object file
    1.33 + * xxx.o are delimited by ifdef xxx_c / endif directives.
    1.34 + *
    1.35 + * The source regions currently marked are:
    1.36 + * arm_exceptions_globs_c
    1.37 + * arm_exceptions_mem_c
    1.38 + * arm_exceptions_uncaught_c
    1.39 + * arm_exceptions_terminate_c
    1.40 + * arm_exceptions_setterminate_c
    1.41 + * arm_exceptions_unexpected_c
    1.42 + * arm_exceptions_setunexpected_c
    1.43 + * arm_exceptions_support_c
    1.44 + * arm_exceptions_callterm_c
    1.45 + * arm_exceptions_callunex_c
    1.46 + * arm_exceptions_currenttype_c
    1.47 + * arm_exceptions_alloc_c
    1.48 + * arm_exceptions_free_c
    1.49 + * arm_exceptions_throw_c
    1.50 + * arm_exceptions_rethrow_c
    1.51 + * arm_exceptions_foreign_c
    1.52 + * arm_exceptions_cleanup_c
    1.53 + * arm_exceptions_begincatch_c
    1.54 + * arm_exceptions_endcatch_c
    1.55 + * arm_exceptions_bad_typeid_c
    1.56 + * arm_exceptions_bad_cast_c
    1.57 + */
    1.58 +
    1.59 +#include <string.h>
    1.60 +#include <typeinfo>
    1.61 +#include <exception>
    1.62 +#include <new>
    1.63 +// Environment:
    1.64 +#include "unwind_env.h"
    1.65 +// Language-independent unwinder declarations:
    1.66 +#include "unwinder.h"
    1.67 +
    1.68 +/* By default, none of these routines are unwindable: */
    1.69 +#pragma noexceptions_unwind
    1.70 +
    1.71 +/* For brevity: */
    1.72 +
    1.73 +typedef _Unwind_Control_Block UCB;
    1.74 +
    1.75 +using std::terminate_handler;
    1.76 +using std::unexpected_handler;
    1.77 +using std::terminate;
    1.78 +using std::unexpected;
    1.79 +using std::type_info;
    1.80 +
    1.81 +/* Redeclare these interface routines as weak, so using them does not
    1.82 + * pull in the unwind library. We only want the unwind library if
    1.83 + * someone throws (or raises an exception from some other language).
    1.84 + */
    1.85 +WEAKDECL NORETURNDECL void _Unwind_Resume(UCB *);
    1.86 +WEAKDECL void _Unwind_Complete(UCB *);
    1.87 +
    1.88 +/* Diagnostics:
    1.89 + * Define DEBUG to get extra interfaces which assist debugging this functionality.
    1.90 + * Define PRINTED_DIAGNOSTICS for printed diagnostics.
    1.91 + */
    1.92 +#ifdef DEBUG
    1.93 +#define PRINTED_DIAGNOSTICS
    1.94 +#endif
    1.95 +
    1.96 +#ifdef PRINTED_DIAGNOSTICS
    1.97 +extern "C" int printf(const char *, ...);
    1.98 +#endif
    1.99 +
   1.100 +/* --------- "Exceptions_class" string for our implementation: --------- */
   1.101 +
   1.102 +#define EXCEPTIONS_CLASS_SIZE 8
   1.103 +#define ARMCPP_EXCEPTIONS_CLASS "ARM\0C++\0"
   1.104 +
   1.105 +
   1.106 +/* --------- Exception control object: --------- */
   1.107 +
   1.108 +// Type __cxa_exception is the combined C++ housekeeping (LEO) and UCB.
   1.109 +// It will be followed by the user exception object, hence must ensure
   1.110 +// the latter is aligned on an 8 byte boundary.
   1.111 +
   1.112 +struct __cxa_exception {
   1.113 +  const type_info *exceptionType;       // RTTI object describing the type of the exception
   1.114 +  void *(*exceptionDestructor)(void *); // Destructor for the exception object (may be NULL)
   1.115 +  unexpected_handler unexpectedHandler; // Handler in force after evaluating throw expr
   1.116 +  terminate_handler terminateHandler;   // Handler in force after evaluating throw expr
   1.117 +  __cxa_exception *nextCaughtException; // Chain of "currently caught" c++ exception objects
   1.118 +  uint32_t handlerCount;                // Count of how many handlers this EO is "caught" in
   1.119 +  __cxa_exception *nextPropagatingException; // Chain of objects saved over cleanup
   1.120 +  uint32_t propagationCount;            // Count of live propagations (throws) of this EO
   1.121 +  UCB ucb;                              // Forces alignment of next item to 8-byte boundary
   1.122 +};
   1.123 +
   1.124 +
   1.125 +/* --------- Control "globals": --------- */
   1.126 +
   1.127 +// We do this by putting all the thread-specific "globals" into a single
   1.128 +// area of store, which we allocate space for dynamically.
   1.129 +// We don't define a constructor for this; see comments with __cxa_get_globals.
   1.130 +
   1.131 +typedef void (*handler)(void);
   1.132 +
   1.133 +struct __cxa_eh_globals {
   1.134 +  uint32_t uncaughtExceptions;               // counter
   1.135 +  unexpected_handler unexpectedHandler;      // per-thread handler
   1.136 +  terminate_handler terminateHandler;        // per-thread handler
   1.137 +  bool implementation_ever_called_terminate; // true if it ever did
   1.138 +  handler call_hook;     // transient field to tell terminate/unexpected which hook to call
   1.139 +  __cxa_exception *caughtExceptions;         // chain of "caught" exceptions
   1.140 +  __cxa_exception *propagatingExceptions;    // chain of "propagating" (in cleanup) exceptions
   1.141 +  void *emergency_buffer;                    // emergency buffer for when rest of heap full
   1.142 +};
   1.143 +
   1.144 +
   1.145 +/* ---------- Entry points: ---------- */
   1.146 +
   1.147 +/* There is a little type-delicacy required here as __cxa_throw takes a
   1.148 + * function pointer. Setting aside the problem of not being able to form
   1.149 + * a pointer to a destructor in C++, if we simply say extern "C" here
   1.150 + * then the function pointer will also have C linkage and will be a
   1.151 + * pointer to a C function. This causes problems when __cxa_throw is
   1.152 + * defined (unless we repeat the extern "C" at the definition site) because
   1.153 + * the fnptr in the definition gets C++ linkage, hence that __cxa_throw has
   1.154 + * a different signature to the declared one, and so the function we wanted
   1.155 + * doesn't get defined at all.
   1.156 + * Maybe it should just take a void * but this seems more honest.
   1.157 + */
   1.158 +
   1.159 +typedef void *(*cppdtorptr)(void *);
   1.160 +
   1.161 +extern "C" {
   1.162 +
   1.163 +  // Protocol routines called directly from application code
   1.164 +
   1.165 +  void *__cxa_allocate_exception(size_t size);
   1.166 +  void __cxa_free_exception(void *);
   1.167 +  WEAKDECL void __cxa_throw(void *, const type_info *, cppdtorptr);
   1.168 +  void __cxa_rethrow(void);
   1.169 +  void *__cxa_begin_catch(UCB *);
   1.170 +  void __cxa_end_catch(void);
   1.171 +  void __cxa_end_cleanup(void);
   1.172 +  const type_info *__cxa_current_exception_type(void);
   1.173 +
   1.174 +  // Protocol routines usually called only by the personality routine(s).
   1.175 +
   1.176 +  void __cxa_call_terminate(UCB *);
   1.177 +  void __cxa_call_unexpected(UCB *);
   1.178 +  bool __cxa_begin_cleanup(UCB *);
   1.179 +  bool __cxa_type_match(UCB *, const std::type_info *, void **);
   1.180 +
   1.181 +  // Auxilliary routines
   1.182 +
   1.183 +  __cxa_eh_globals *__cxa_get_globals(void);
   1.184 +  void __cxa_bad_typeid(void);
   1.185 +  void __cxa_bad_cast(void);
   1.186 +
   1.187 +  // Emergency memory buffer management routines
   1.188 +
   1.189 +  void *__ARM_exceptions_buffer_init(void);
   1.190 +  void *__ARM_exceptions_buffer_allocate(void *, size_t);
   1.191 +  void *__ARM_exceptions_buffer_free(void *, void *);
   1.192 +}
   1.193 +
   1.194 +
   1.195 +// Support routines
   1.196 +
   1.197 +#define NAMES __ARM
   1.198 +namespace NAMES {
   1.199 +  void default_unexpected_handler(void);
   1.200 +  void call_terminate_handler(UCB *);
   1.201 +  void eh_catch_semantics(UCB *);
   1.202 +  bool is_foreign_exception(UCB *);
   1.203 +  bool same_exceptions_class(const void *, const void *);
   1.204 +  __cxa_exception *get_foreign_intermediary(__cxa_exception *, UCB *);
   1.205 +}
   1.206 +
   1.207 +// Macro: convert ucb pointer to __cxa_exception pointer
   1.208 +
   1.209 +#define ucbp_to_ep(UCB_P) ((__cxa_exception *)((char *)(UCB_P) - offsetof(__cxa_exception, ucb)))
   1.210 +
   1.211 +
   1.212 +#ifdef arm_exceptions_globs_c
   1.213 +
   1.214 +/* --------- Allocating and retrieving "globals": --------- */
   1.215 +
   1.216 +// The exception-handling globals should be allocated per-thread.
   1.217 +// This is done here assuming the existance of a zero-initialised void*
   1.218 +// pointer location obtainable by the macro EH_GLOBALS.
   1.219 +
   1.220 +// Default terminate handler:
   1.221 +
   1.222 +static void __default_terminate_handler(void) {
   1.223 +  abort();
   1.224 +}
   1.225 +
   1.226 +// If std::unexpected() is in the image, include a default handler for it:
   1.227 +namespace NAMES { WEAKDECL void default_unexpected_handler(void); }
   1.228 +
   1.229 +// If this symbol is present, allocate an emergency buffer.
   1.230 +// As we aren't allowed static data, make it a function
   1.231 +extern "C" WEAKDECL void __ARM_exceptions_buffer_required(void);
   1.232 +
   1.233 +
   1.234 +// __cxa_eh_globals returns the per-thread memory. There are several complications,
   1.235 +// all of which relate to not touching the exceptions system while trying to
   1.236 +// initialise it:
   1.237 +// 1) We can't obtain memory by calling new or nothrow new as both of these use
   1.238 +//    exceptions internally, so we must use malloc
   1.239 +// 2) We choose not to initialise the memory via placement new and a constructor,
   1.240 +//    since placement new is declared with an empty function exception specification,
   1.241 +//    which causes more of the exceptions system to always be pulled in.
   1.242 +// 3) We can't call terminate, as terminate looks in the memory we are trying to
   1.243 +//    allocate.
   1.244 +
   1.245 +__cxa_eh_globals *__cxa_get_globals(void)
   1.246 +{
   1.247 +  __cxa_eh_globals *this_thread_globals = (__cxa_eh_globals *)(EH_GLOBALS);
   1.248 +  if (this_thread_globals == NULL) {
   1.249 +
   1.250 +    // First call
   1.251 +    // Obtain some memory: this is thread-safe provided malloc is.
   1.252 +    this_thread_globals = (__cxa_eh_globals *)malloc(sizeof(__cxa_eh_globals));
   1.253 +    if (this_thread_globals == NULL) abort(); // NOT terminate(), which calls this fn
   1.254 +
   1.255 +    // Save the pointer in the specially-provided location
   1.256 +    EH_GLOBALS = this_thread_globals;
   1.257 +
   1.258 +    // Finally initialise the memory by hand
   1.259 +    this_thread_globals->uncaughtExceptions = 0;
   1.260 +    this_thread_globals->unexpectedHandler = NAMES::default_unexpected_handler;
   1.261 +    this_thread_globals->terminateHandler = __default_terminate_handler;
   1.262 +    this_thread_globals->implementation_ever_called_terminate = false;
   1.263 +    this_thread_globals->call_hook = NULL;
   1.264 +    this_thread_globals->caughtExceptions = NULL;
   1.265 +    this_thread_globals->propagatingExceptions = NULL;
   1.266 +    if (&__ARM_exceptions_buffer_required == NULL)
   1.267 +      this_thread_globals->emergency_buffer = NULL;
   1.268 +    else
   1.269 +      this_thread_globals->emergency_buffer = __ARM_exceptions_buffer_init();
   1.270 +  }
   1.271 +
   1.272 +  return this_thread_globals;
   1.273 +}
   1.274 +
   1.275 +
   1.276 +#endif /* arm_exceptions_globs_c */
   1.277 +#ifdef arm_exceptions_mem_c
   1.278 +
   1.279 +/* --------- Emergency memory: --------- */
   1.280 +
   1.281 +// It is possible to reserve memory for throwing bad_alloc when the heap
   1.282 +// is otherwise full. The ARM implementation provides hooks to do this.
   1.283 +// The default implementation reserves just enough space for a bad_alloc
   1.284 +// object, so if memory is later exhausted bad_alloc can still be thrown.
   1.285 +// Note there is no guarantee or requirement that the exception being
   1.286 +// thrown is actually bad_alloc.
   1.287 +
   1.288 +// A usage flag and enough space for a bad_alloc exception control object
   1.289 +
   1.290 +struct emergency_eco {
   1.291 +  __cxa_exception ep;
   1.292 +  std::bad_alloc b;
   1.293 +};
   1.294 +
   1.295 +struct emergency_buffer {
   1.296 +  bool inuse;
   1.297 +  struct emergency_eco eco;
   1.298 +};
   1.299 +
   1.300 +// Initialiser
   1.301 +void* __ARM_exceptions_buffer_init(void)
   1.302 +{
   1.303 +  emergency_buffer *buffer = (emergency_buffer *)malloc(sizeof(emergency_buffer));
   1.304 +  if (buffer == NULL) return NULL;
   1.305 +  buffer->inuse = false;
   1.306 +  return buffer;
   1.307 +}
   1.308 +
   1.309 +// Allocator
   1.310 +void *__ARM_exceptions_buffer_allocate(void *buffer, size_t size)
   1.311 +{
   1.312 +  emergency_buffer *b = (emergency_buffer *)buffer;
   1.313 +  if (size > sizeof(emergency_eco) || b == NULL || b->inuse) return NULL;
   1.314 +  b->inuse = true;
   1.315 +  return &b->eco;
   1.316 +}
   1.317 +
   1.318 +// Deallocator: Must return non-NULL if and only if it recognises
   1.319 +// and releases the supplied object
   1.320 +void *__ARM_exceptions_buffer_free(void *buffer, void *addr)
   1.321 +{
   1.322 +  emergency_buffer *b = (emergency_buffer *)buffer;
   1.323 +  if (b == NULL || addr != &b->eco) return NULL;
   1.324 +  b->inuse = false;
   1.325 +  return b;
   1.326 +}
   1.327 +
   1.328 +
   1.329 +#endif /* arm_exceptions_mem_c */
   1.330 +#ifdef arm_exceptions_uncaught_c
   1.331 +
   1.332 +/* ---- uncaught_exception() ---- */
   1.333 +
   1.334 +/* The EDG (and I think our) interpretation is that if the implementation
   1.335 + * ever called terminate(), uncaught_exception() should return true.
   1.336 + */
   1.337 +
   1.338 +bool std::uncaught_exception(void)
   1.339 +{
   1.340 +   __cxa_eh_globals *g = __cxa_get_globals();
   1.341 +   return g->implementation_ever_called_terminate || g->uncaughtExceptions;
   1.342 +}
   1.343 +
   1.344 +
   1.345 +#endif /* arm_exceptions_uncaught_c */
   1.346 +#ifdef arm_exceptions_terminate_c
   1.347 +
   1.348 +/* ---- terminate() etc ---- */
   1.349 +
   1.350 +/* The behaviour of terminate() must differ between calls by the
   1.351 + * implementation and calls by the application. This is achieved by having the
   1.352 + * implementation set call_hook immediately before the call to terminate().
   1.353 + * The hook called by terminate() should terminate the program without
   1.354 + * returning to the caller. There is no requirement for terminate() itself to
   1.355 + * intercept throws.
   1.356 + */
   1.357 +
   1.358 +void std::terminate(void)
   1.359 +{
   1.360 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.361 +
   1.362 +  if (g->call_hook != NULL) {
   1.363 +    // Clear then call hook fn we were passed
   1.364 +    handler call_hook = g->call_hook;
   1.365 +    g->call_hook = NULL;
   1.366 +    call_hook();
   1.367 +  } else {
   1.368 +    // Call global hook fn
   1.369 +    g->terminateHandler();
   1.370 +  }
   1.371 +  // If hook fn returns:
   1.372 +  abort();
   1.373 +}
   1.374 +
   1.375 +
   1.376 +#endif /* arm_exceptions_terminate_c */
   1.377 +#ifdef arm_exceptions_setterminate_c
   1.378 +
   1.379 +terminate_handler std::set_terminate(terminate_handler h) throw()
   1.380 +{
   1.381 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.382 +  terminate_handler old = g->terminateHandler;
   1.383 +  g->terminateHandler = h;
   1.384 +  return old;
   1.385 +}
   1.386 +
   1.387 +
   1.388 +#endif /* arm_exceptions_setterminate_c */
   1.389 +#ifdef arm_exceptions_unexpected_c
   1.390 +
   1.391 +/* ---- unexpected() etc ---- */
   1.392 +/* Comments as per terminate() */
   1.393 +
   1.394 +void NAMES::default_unexpected_handler(void) {
   1.395 +  terminate();
   1.396 +}
   1.397 +
   1.398 +#pragma exceptions_unwind
   1.399 +
   1.400 +void std::unexpected(void)
   1.401 +{
   1.402 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.403 +
   1.404 +  if (g->call_hook != NULL) {
   1.405 +    // Clear then call hook fn we were passed
   1.406 +    handler call_hook = g->call_hook;
   1.407 +    g->call_hook = NULL;
   1.408 +    call_hook();
   1.409 +  } else {
   1.410 +    // Call global hook fn
   1.411 +    g->unexpectedHandler();
   1.412 +  }
   1.413 +
   1.414 +  // If hook fn returns:
   1.415 +  abort();
   1.416 +}
   1.417 +
   1.418 +
   1.419 +#endif /* arm_exceptions_unexpected_c */
   1.420 +#ifdef arm_exceptions_setunexpected_c
   1.421 +
   1.422 +unexpected_handler std::set_unexpected(unexpected_handler h) throw()
   1.423 +{
   1.424 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.425 +  unexpected_handler old = g->unexpectedHandler;
   1.426 +  g->unexpectedHandler = h;
   1.427 +  return old;
   1.428 +}
   1.429 +
   1.430 +
   1.431 +#endif /* arm_exceptions_setunexpected_c */
   1.432 +#ifdef arm_exceptions_support_c
   1.433 +
   1.434 +/* ---------- Helper functions: ---------- */
   1.435 +
   1.436 +/* Two routines to determine whether two exceptions objects share a layout.
   1.437 + * This is determined by checking whether the UCB exception_class members
   1.438 + * are identical.
   1.439 + * In principle we could use memcmp to perform this check (the code is
   1.440 + * given below) but the check is quite frequent and so that is costly.
   1.441 + * Therefore for efficiency we make use of the fact that the UCB is
   1.442 + * word aligned, that the exception_class member is consequently
   1.443 + * word aligned within it, and that we know the size of the member.
   1.444 + * We take care elsewhere to only ever call the routines with pointers
   1.445 + * to word-aligned addresses.
   1.446 + */
   1.447 +
   1.448 +#if 0
   1.449 +
   1.450 +// Straightforward versions
   1.451 +
   1.452 +bool NAMES::same_exceptions_class(const void *ec1, const void *ec2)
   1.453 +{
   1.454 +  return memcmp(ec1, ec2, EXCEPTIONS_CLASS_SIZE) == 0; // identical
   1.455 +}
   1.456 +
   1.457 +// One of our exception objects, or not?
   1.458 +
   1.459 +bool NAMES::is_foreign_exception(UCB *ucbp)
   1.460 +{
   1.461 +  return !NAMES::same_exceptions_class(&ucbp->exception_class, ARMCPP_EXCEPTIONS_CLASS);
   1.462 +}
   1.463 +
   1.464 +#else
   1.465 +
   1.466 +// Faster versions
   1.467 +
   1.468 +bool NAMES::same_exceptions_class(const void *ec1, const void *ec2)
   1.469 +{
   1.470 +  uint32_t *ip1 = (uint32_t *)ec1;
   1.471 +  uint32_t *ip2 = (uint32_t *)ec2;
   1.472 +  return ip1[0] == ip2[0] && ip1[1] == ip2[1];
   1.473 +}
   1.474 +
   1.475 +// One of our exception objects, or not?
   1.476 +
   1.477 +bool NAMES::is_foreign_exception(UCB *ucbp)
   1.478 +{
   1.479 +  // Need a word-aligned copy of the string
   1.480 +  static const union {
   1.481 +    const char s[EXCEPTIONS_CLASS_SIZE+1]; int dummy;
   1.482 +  } is_foreign_exception_static = {ARMCPP_EXCEPTIONS_CLASS};
   1.483 +  return !NAMES::same_exceptions_class(&ucbp->exception_class, &is_foreign_exception_static.s);
   1.484 +}
   1.485 +
   1.486 +#endif
   1.487 +
   1.488 +
   1.489 +#endif /* arm_exceptions_support_c */
   1.490 +#ifdef arm_exceptions_callterm_c
   1.491 +
   1.492 +/* When the implementation wants to call terminate(), do the following:
   1.493 + * Mark the object as "caught" so it can be rethrown.
   1.494 + * Set the hook function for terminate() to call;
   1.495 + * Mark the fact that terminate() has been called by the implementation;
   1.496 + * We have to be careful - the implementation might encounter an error while
   1.497 + * unwinding a foreign exception, and also it is possible this might be
   1.498 + * called after failing to obtain a ucb.
   1.499 + */
   1.500 +
   1.501 +void NAMES::call_terminate_handler(UCB *ucbp)
   1.502 +{
   1.503 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.504 +
   1.505 +  if (ucbp == NULL) {
   1.506 +    // Call global hook
   1.507 +    g->call_hook = g->terminateHandler;
   1.508 +  } else {
   1.509 +    // Extract the hook to call
   1.510 +    if (NAMES::is_foreign_exception(ucbp)) {
   1.511 +      // Someone else's
   1.512 +      g->call_hook = g->terminateHandler;  // best we can do under the circumstances
   1.513 +    } else {
   1.514 +      // One of ours
   1.515 +      __cxa_exception *ep = ucbp_to_ep(ucbp);
   1.516 +      g->call_hook = ep->terminateHandler; // the one in force at the point of throw
   1.517 +    }
   1.518 +  }
   1.519 +
   1.520 +  g->implementation_ever_called_terminate = true;
   1.521 +  terminate();
   1.522 +  // never returns
   1.523 +}
   1.524 +
   1.525 +
   1.526 +void __cxa_call_terminate(UCB *ucbp)
   1.527 +{
   1.528 +  if (ucbp != NULL) // Record entry to (implicit) handler
   1.529 +    __cxa_begin_catch(ucbp);
   1.530 +
   1.531 +  NAMES::call_terminate_handler(ucbp);
   1.532 +  // never returns
   1.533 +}
   1.534 +
   1.535 +
   1.536 +#endif /* arm_exceptions_callterm_c */
   1.537 +#ifdef arm_exceptions_callunex_c
   1.538 +
   1.539 +/* When the implementation wants to call unexpected(), do the following:
   1.540 + * Mark the object as "caught" so it can be rethrown.
   1.541 + * Set the hook function for unexpected() to call;
   1.542 + * Call unexpected and trap any throw to make sure it is acceptable.
   1.543 + * We have to be careful - the implementation might encounter an error while
   1.544 + * unwinding a foreign exception.
   1.545 + */
   1.546 +
   1.547 +#pragma exceptions_unwind
   1.548 +
   1.549 +void __cxa_call_unexpected(UCB *ucbp)
   1.550 +{
   1.551 +
   1.552 +  // Extract data we will need from the barrier cache before
   1.553 +  // anyone has a chance to overwrite it
   1.554 +
   1.555 +  uint32_t rtti_count = ucbp->barrier_cache.bitpattern[1];
   1.556 +  uint32_t base = ucbp->barrier_cache.bitpattern[2];
   1.557 +  uint32_t stride = ucbp->barrier_cache.bitpattern[3];
   1.558 +  uint32_t rtti_offset_array_addr = ucbp->barrier_cache.bitpattern[4];
   1.559 +
   1.560 +  // Also get the globals here and the eop
   1.561 +
   1.562 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.563 +  __cxa_exception *ep = ucbp_to_ep(ucbp);
   1.564 +
   1.565 +#ifdef ARM_EXCEPTIONS_ENABLED
   1.566 +  try {
   1.567 +#endif
   1.568 +
   1.569 +    // Record entry to (implicit) handler
   1.570 +
   1.571 +    __cxa_begin_catch(ucbp);
   1.572 +
   1.573 +    // Now extract the hook to call
   1.574 +
   1.575 +    if (NAMES::is_foreign_exception(ucbp)) {
   1.576 +      // Someone else's
   1.577 +      g->call_hook = g->unexpectedHandler;  // best we can do under the circumstances
   1.578 +    } else {
   1.579 +      // One of ours
   1.580 +      g->call_hook = ep->unexpectedHandler; // the one in force at the point of throw
   1.581 +    }
   1.582 +    unexpected();  // never returns normally, but might throw something
   1.583 +
   1.584 +#ifdef ARM_EXCEPTIONS_ENABLED
   1.585 +  } catch (...) {
   1.586 +
   1.587 +    // Unexpected() threw. This requires some delicacy.
   1.588 +    // There are 2 possibilities:
   1.589 +    // i) rethrow of the same object
   1.590 +    // ii) throw of a new object
   1.591 +    // Unexpected() is an implicit handler, and we manually called
   1.592 +    // __cxa_begin_catch on the ingoing object. We need to call
   1.593 +    // __cxa_end_catch on that object and, if the object is no longer
   1.594 +    // being handled (possible in case ii), this will cause its destruction.
   1.595 +    // The wrinkle is that in case ii the object is not on top of the catch
   1.596 +    // stack because we just caught something else.
   1.597 +
   1.598 +    // Get hold of what was thrown (which we just caught).
   1.599 +
   1.600 +    __cxa_exception *epnew = g->caughtExceptions;
   1.601 +
   1.602 +    // Call __cxa_end_catch on the original object, taking care with the catch chain
   1.603 +
   1.604 +    if (epnew == ep) {
   1.605 +      // rethrow - easy & safe - object is at top of chain and handlercount > 1
   1.606 +      __cxa_end_catch();
   1.607 +    } else {
   1.608 +      // not rethrow - unchain the top (new) object, clean up the next one,
   1.609 +      // and put the top object back
   1.610 +
   1.611 +      // unchain
   1.612 +      g->caughtExceptions = epnew->nextCaughtException;
   1.613 +      // assert g->caughtExceptions == ep now
   1.614 +      // Decrement its handlercount (this might call a dtor if the count goes to 0,
   1.615 +      // and the dtor might throw - if it does, just give up)
   1.616 +      try {
   1.617 +	__cxa_end_catch();
   1.618 +      } catch(...) {
   1.619 +	terminate();
   1.620 +      }
   1.621 +      // Chain back in
   1.622 +      epnew->nextCaughtException = g->caughtExceptions;
   1.623 +      g->caughtExceptions = epnew;
   1.624 +    }
   1.625 +
   1.626 +    // See whether what was thrown is permitted, and in passing
   1.627 +    // see if std::bad_exception is permitted
   1.628 +
   1.629 +    bool bad_exception_permitted = false;
   1.630 +    uint32_t i;
   1.631 +    for (i = 0; i < rtti_count; i++) {
   1.632 +      void *matched_object;
   1.633 +      const type_info *fnspec = (const type_info *)(*(uint32_t *)rtti_offset_array_addr + base);
   1.634 +      if (__cxa_type_match(&(epnew->ucb), fnspec, &matched_object)) {
   1.635 +#ifdef PRINTED_DIAGNOSTICS
   1.636 +	printf("__cxa_call_unexpected: fnspec matched\n");
   1.637 +#endif
   1.638 +	throw; // got a match - propagate it
   1.639 +      }
   1.640 +      if (&typeid(std::bad_exception) == fnspec)
   1.641 +	bad_exception_permitted = true;
   1.642 +      rtti_offset_array_addr += stride;
   1.643 +    }
   1.644 +
   1.645 +    // There was no match...
   1.646 +    if (bad_exception_permitted) throw std::bad_exception(); // transmute
   1.647 +
   1.648 +    // Otherwise call epnew's terminate handler
   1.649 +    NAMES::call_terminate_handler(&epnew->ucb);
   1.650 +  }
   1.651 +#endif
   1.652 +}
   1.653 +
   1.654 +
   1.655 +#endif /* arm_exceptions_callunex_c */
   1.656 +#ifdef arm_exceptions_currenttype_c
   1.657 +
   1.658 +/* Yield the type of the currently handled exception, or null if none or the
   1.659 + * object is foreign.
   1.660 + */
   1.661 +
   1.662 +const type_info *__cxa_current_exception_type(void)
   1.663 +{
   1.664 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.665 +  __cxa_exception *ep = g->caughtExceptions;
   1.666 +  if (ep == NULL || NAMES::is_foreign_exception(&ep->ucb)) return NULL;
   1.667 +  return ep->exceptionType;
   1.668 +}
   1.669 +
   1.670 +
   1.671 +#endif /* arm_exceptions_currenttype_c */
   1.672 +#ifdef arm_exceptions_alloc_c
   1.673 +
   1.674 +/* Allocate store for controlling an exception propagation */
   1.675 +
   1.676 +void *__cxa_allocate_exception(size_t size)
   1.677 +{
   1.678 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.679 +
   1.680 +  // Allocate store for a __cxa_exception header and the EO.
   1.681 +  // Allocated store should be thread-safe and persistent, and must do
   1.682 +  // something sensible if the allocation fails
   1.683 +
   1.684 +  size_t total_size = size + sizeof(__cxa_exception);
   1.685 +  __cxa_exception *ep = (__cxa_exception *)malloc(total_size);
   1.686 +  if (ep == NULL) {
   1.687 +    // Try the emergency memory pool
   1.688 +    ep = (__cxa_exception *)__ARM_exceptions_buffer_allocate(g->emergency_buffer, total_size);
   1.689 +    if (ep == NULL) NAMES::call_terminate_handler(NULL);
   1.690 +  }
   1.691 +
   1.692 +  UCB *ucbp = &ep->ucb;
   1.693 +
   1.694 +  // Initialise the UCB
   1.695 +
   1.696 +  memcpy(ucbp->exception_class, ARMCPP_EXCEPTIONS_CLASS, EXCEPTIONS_CLASS_SIZE);
   1.697 +  ucbp->exception_cleanup = NULL; /* initialise properly before throwing */
   1.698 +  ucbp->unwinder_cache.reserved1 = 0; /* required to do this */
   1.699 +
   1.700 +  // Initialise parts of the LEO, in case copy-construction of the EO results
   1.701 +  // in a need to call terminate (via __cxa_call_terminate)
   1.702 +
   1.703 +  ep->handlerCount = 0;                         // Not in any handlers
   1.704 +  ep->nextCaughtException = NULL;               // Not in any handlers
   1.705 +  ep->nextPropagatingException = NULL;          // Not saved over cleanup
   1.706 +  ep->propagationCount = 0;                     // Not propagating
   1.707 +  ep->terminateHandler = g->terminateHandler;   // Cache current terminate handler
   1.708 +  ep->unexpectedHandler = g->unexpectedHandler; // Cache current unexpected handler
   1.709 +
   1.710 +  // Return pointer to the EO
   1.711 +
   1.712 +  return ep + 1;
   1.713 +}
   1.714 +
   1.715 +
   1.716 +#endif /* arm_exceptions_alloc_c */
   1.717 +#ifdef arm_exceptions_free_c
   1.718 +
   1.719 +/* Free store allocated by __cxa_allocate_exception */
   1.720 +
   1.721 +void __cxa_free_exception(void *eop)
   1.722 +{
   1.723 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.724 +  char *ep = (char *)eop - sizeof(__cxa_exception);
   1.725 +  if (__ARM_exceptions_buffer_free(g->emergency_buffer, ep)) return;
   1.726 +  free(ep);
   1.727 +}
   1.728 +
   1.729 +
   1.730 +#endif /* arm_exceptions_free_c */
   1.731 +#ifdef arm_exceptions_throw_c
   1.732 +
   1.733 +/* This routine is called when a foreign runtime catches one of our exception
   1.734 + * objects and then exits its catch by a means other than rethrow.
   1.735 + * We should clean it up as if we had caught it ourselves.
   1.736 + */
   1.737 +
   1.738 +static void external_exception_termination(_Unwind_Reason_Code c, UCB *ucbp)
   1.739 +{
   1.740 +  NAMES::eh_catch_semantics(ucbp);
   1.741 +  __cxa_end_catch();
   1.742 +}
   1.743 +
   1.744 +
   1.745 +/* Initiate a throw */
   1.746 +
   1.747 +#pragma push
   1.748 +#pragma exceptions_unwind
   1.749 +
   1.750 +void __cxa_throw(void *eop, const type_info *t, cppdtorptr d)
   1.751 +{
   1.752 +  __cxa_exception *ep = (__cxa_exception *)((char *)eop - sizeof(__cxa_exception));
   1.753 +  UCB *ucbp = &ep->ucb;
   1.754 +
   1.755 +  // Initialise the remaining LEO and UCB fields not done by __cxa_allocate_exception
   1.756 +
   1.757 +  ucbp->exception_cleanup = external_exception_termination;
   1.758 +  ep->exceptionType = t;
   1.759 +  ep->exceptionDestructor = d;
   1.760 +  ep->propagationCount = 1;      // Propagating by 1 throw
   1.761 +
   1.762 +  // Increment the uncaught C++ exceptions count
   1.763 +
   1.764 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.765 +  g->uncaughtExceptions++;
   1.766 +
   1.767 +  // Tell debugger what's happening
   1.768 +
   1.769 +  DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_STARTING, t);
   1.770 +
   1.771 +  // Initiate unwinding - if we get control back, call C++ routine terminate()
   1.772 +
   1.773 +  _Unwind_RaiseException(ucbp);
   1.774 +
   1.775 +#ifdef PRINTED_DIAGNOSTICS
   1.776 +  printf("__cxa_throw: throw failed\n");
   1.777 +#endif
   1.778 +
   1.779 +  __cxa_call_terminate(ucbp);
   1.780 +}
   1.781 +
   1.782 +#pragma pop
   1.783 +
   1.784 +/* ----- Type matching: ----- */
   1.785 +
   1.786 +/* This is located here so that (in ARM's implementation) it is only retained in
   1.787 + * an image if the application itself throws.
   1.788 + */
   1.789 +
   1.790 +/* Type matching functions.
   1.791 + * C++ DR126 says the matching rules for fnspecs are intended to be the same as
   1.792 + * those for catch:
   1.793 + * "A function is said to allow an exception of type E if its exception-specification
   1.794 + * contains a type T for which a handler of type T would be a match (15.3 except.handle)
   1.795 + * for an exception of type E."
   1.796 + * Thus we have a single type matching rule.
   1.797 + */
   1.798 +
   1.799 +/* Helper macros: */
   1.800 +
   1.801 +#define CV_quals_of_pointee(P) (((const abi::__pbase_type_info *)(P))->__flags & \
   1.802 +		                (abi::__pbase_type_info::__const_mask | \
   1.803 +		                 abi::__pbase_type_info::__volatile_mask))
   1.804 +
   1.805 +#define is_const(QUALS) (((QUALS) & abi::__pbase_type_info::__const_mask) != 0)
   1.806 +
   1.807 +#define any_qualifier_missing(TEST_QUALS, REF_QUALS) ((~(TEST_QUALS) & (REF_QUALS)) != 0)
   1.808 +
   1.809 +/* A routine is required for derived class to base class conversion.
   1.810 + * This is obtained via a macro definition DERIVED_TO_BASE_CONVERSION
   1.811 + * in unwind_env.h.
   1.812 + */
   1.813 +
   1.814 +/* External entry point:
   1.815 + * Type check the c++ rtti object for compatibility against the type of
   1.816 + * the object containing the ucb. Return a pointer to the matched object
   1.817 + * (possibly a non-leftmost baseclass of the exception object)
   1.818 + */
   1.819 +bool __cxa_type_match(UCB *ucbp, const type_info *match_type, void **matched_objectpp)
   1.820 +{
   1.821 +  if (NAMES::is_foreign_exception(ucbp))
   1.822 +    return false;
   1.823 +
   1.824 +  __cxa_exception *ep = ucbp_to_ep(ucbp);
   1.825 +  const type_info *throw_type = ep->exceptionType;
   1.826 +  bool previous_qualifiers_include_const = true; // for pointer qualification conversion
   1.827 +  unsigned int pointer_depth = 0;
   1.828 +  void *original_objectp = ep + 1;
   1.829 +  void *current_objectp = original_objectp;
   1.830 +
   1.831 +  for (;;) {
   1.832 +
   1.833 +    // Match if identical
   1.834 +
   1.835 +    if (throw_type == match_type) {
   1.836 +      *matched_objectpp = original_objectp;
   1.837 +#ifdef PRINTED_DIAGNOSTICS
   1.838 +      printf("__cxa_type_match: success (exact match after any ptrs)\n");
   1.839 +#endif
   1.840 +      return true;
   1.841 +    }
   1.842 +
   1.843 +    // Fail if one is a pointer and the other isn't
   1.844 +
   1.845 +    const type_info *type_throw_type = &typeid(*throw_type);
   1.846 +    const type_info *type_match_type = &typeid(*match_type);
   1.847 +
   1.848 +    if ((type_throw_type == &typeid(abi::__pointer_type_info) ||
   1.849 +	 type_match_type == &typeid(abi::__pointer_type_info)) &&
   1.850 +	type_throw_type != type_match_type) {
   1.851 +#ifdef PRINTED_DIAGNOSTICS
   1.852 +      printf("__cxa_type_match: failed (mixed ptr/non-ptr)\n");
   1.853 +#endif
   1.854 +      return false;
   1.855 +    }
   1.856 +
   1.857 +    // Both are pointers or neither is
   1.858 +    if (type_throw_type == &typeid(abi::__pointer_type_info)) {
   1.859 +      // Both are pointers
   1.860 +#ifdef PRINTED_DIAGNOSTICS
   1.861 +      printf("__cxa_type_match: throwing a ptr\n");
   1.862 +#endif
   1.863 +      pointer_depth++;
   1.864 +      // Check match_type is at least as CV-qualified as throw_type
   1.865 +      unsigned int match_quals = CV_quals_of_pointee(match_type);
   1.866 +      unsigned int throw_quals = CV_quals_of_pointee(throw_type);
   1.867 +      if (any_qualifier_missing(match_quals, throw_quals)) {
   1.868 +#ifdef PRINTED_DIAGNOSTICS
   1.869 +	printf("__cxa_type_match: failed (missing qualifiers)\n");
   1.870 +#endif
   1.871 +	return false;
   1.872 +      }
   1.873 +      // If the match type has additional qualifiers not found in the
   1.874 +      // throw type, any previous qualifiers must have included const
   1.875 +      if (any_qualifier_missing(throw_quals, match_quals) &&
   1.876 +	  !previous_qualifiers_include_const) {
   1.877 +#ifdef PRINTED_DIAGNOSTICS
   1.878 +	printf("__cxa_type_match: failed (not all qualifiers have const)\n");
   1.879 +#endif
   1.880 +	return false;
   1.881 +      }
   1.882 +      if (!is_const(match_quals))
   1.883 +	previous_qualifiers_include_const = false;
   1.884 +      throw_type = ((const abi::__pbase_type_info *)throw_type)->__pointee;
   1.885 +      match_type = ((const abi::__pbase_type_info *)match_type)->__pointee;
   1.886 +      if (current_objectp != NULL)
   1.887 +        current_objectp = *(void **)current_objectp;
   1.888 +      continue;
   1.889 +    }
   1.890 +
   1.891 +    // Neither is a pointer now but qualification conversion has been done.
   1.892 +    // See if pointer conversion on the original was possible.
   1.893 +    // T* will match void*
   1.894 +
   1.895 +    if (pointer_depth == 1 && match_type == &typeid(void)) {
   1.896 +      *matched_objectpp = original_objectp;
   1.897 +#ifdef PRINTED_DIAGNOSTICS
   1.898 +      printf("__cxa_type_match: success(conversion to void *)\n");
   1.899 +#endif
   1.900 +      return true;
   1.901 +    }
   1.902 +
   1.903 +    // Else if we have 2 class types, a derived class is matched by a
   1.904 +    // non-ambiguous public base class (perhaps not a leftmost one).
   1.905 +    // __si_class_type_info and __vmi_class_type_info are classes with bases.
   1.906 +
   1.907 +    void *matched_base_p;
   1.908 +
   1.909 +    if (pointer_depth < 2 &&
   1.910 +	(type_throw_type == &typeid(abi::__si_class_type_info) ||
   1.911 +	 type_throw_type == &typeid(abi::__vmi_class_type_info))) {
   1.912 +      if (DERIVED_TO_BASE_CONVERSION(current_objectp, &matched_base_p,
   1.913 +				     throw_type, match_type)) {
   1.914 +#ifdef PRINTED_DIAGNOSTICS
   1.915 +	printf("__cxa_type_match: success (matched base 0x%x of 0x%x%s, thrown object 0x%x)\n",
   1.916 +	       matched_base_p, current_objectp,
   1.917 +	       pointer_depth == 0 ? "" : " via ptr",
   1.918 +	       original_objectp);
   1.919 +#endif
   1.920 +	*matched_objectpp = pointer_depth == 0 ? matched_base_p : original_objectp;
   1.921 +	return true;
   1.922 +      } else {
   1.923 +#ifdef PRINTED_DIAGNOSTICS
   1.924 +	printf("__cxa_type_match: failed (derived to base failed)\n");
   1.925 +#endif
   1.926 +	return false;
   1.927 +      }
   1.928 +    }
   1.929 +
   1.930 +#ifdef PRINTED_DIAGNOSTICS
   1.931 +    printf("__cxa_type_match: failed (types simply differ)\n");
   1.932 +#endif
   1.933 +    return false;
   1.934 +  } /* for */
   1.935 +}
   1.936 +
   1.937 +
   1.938 +/* For debugging purposes: */
   1.939 +#ifdef DEBUG
   1.940 +extern "C" bool debug__cxa_type_match(void *objptr,
   1.941 +				      const type_info *throw_type,
   1.942 +				      const type_info *catch_type,
   1.943 +				      void **matched_objectpp)
   1.944 +{
   1.945 +  /* Create enough of an exception object that the type-matcher can run, then
   1.946 +   * check the type. Objptr is expected to be the result of a call to
   1.947 +   * __cxa_allocate_exception, which has then been copy-constructed.
   1.948 +   */
   1.949 +  __cxa_exception *e = ((__cxa_exception *)objptr) - 1;
   1.950 +  e->exceptionType = throw_type;
   1.951 +  return __cxa_type_match(&e->ucb, catch_type, matched_objectpp);
   1.952 +}
   1.953 +#endif
   1.954 +
   1.955 +
   1.956 +#endif /* arm_exceptions_throw_c */
   1.957 +#ifdef arm_exceptions_rethrow_c
   1.958 +
   1.959 +/* Redeclare _Unwind_RaiseException as weak (if WEAKDECL is defined
   1.960 + * appropriately) so the use from __cxa_rethrow does not on its own
   1.961 + * force the unwind library to be loaded.
   1.962 + */
   1.963 +
   1.964 +extern "C" WEAKDECL _Unwind_Reason_Code _Unwind_RaiseException(UCB *ucbp);
   1.965 +
   1.966 +#pragma exceptions_unwind
   1.967 +
   1.968 +void __cxa_rethrow(void)
   1.969 +{
   1.970 +  // Recover the exception object - it is the most recent caught exception object
   1.971 +  __cxa_eh_globals *g = __cxa_get_globals();
   1.972 +  __cxa_exception *ep = g->caughtExceptions;
   1.973 +  bool foreign;
   1.974 +
   1.975 +  // Must call terminate here if no such exception
   1.976 +  if (ep == NULL) NAMES::call_terminate_handler(NULL);
   1.977 +
   1.978 +  UCB *ucbp = &ep->ucb;
   1.979 +
   1.980 +  // Mark the object as being propagated by throw, preventing multiple
   1.981 +  // propagation and also permitting __cxa_end_catch to do the right
   1.982 +  // thing when it is called from the handler's cleanup.
   1.983 +
   1.984 +  ep->propagationCount++;
   1.985 +
   1.986 +  // Now reraise, taking care with foreign exceptions
   1.987 +
   1.988 +  foreign = NAMES::is_foreign_exception(ucbp);
   1.989 +  if (foreign) {
   1.990 +    // Indirect through the intermediate object to the foreign ucb
   1.991 +    ucbp = (UCB *)ep->exceptionType;
   1.992 +  } else {
   1.993 +    // Increment the uncaught C++ exceptions count
   1.994 +    g->uncaughtExceptions++;
   1.995 +  }
   1.996 +
   1.997 +  // Tell debugger what's happening
   1.998 +
   1.999 +  DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_STARTING, foreign ? NULL : ep->exceptionType);
  1.1000 +
  1.1001 +  // Initiate unwinding - if we get control back, call C++ routine terminate()
  1.1002 +
  1.1003 +  _Unwind_RaiseException(ucbp);
  1.1004 +
  1.1005 +#ifdef PRINTED_DIAGNOSTICS
  1.1006 +  printf("__cxa_rethrow: throw failed\n");
  1.1007 +#endif
  1.1008 +
  1.1009 +  __cxa_call_terminate(ucbp);
  1.1010 +}
  1.1011 +
  1.1012 +#endif /* arm_exceptions_rethrow_c */
  1.1013 +#ifdef arm_exceptions_foreign_c
  1.1014 +
  1.1015 +/* During catch and cleanup, foreign exception objects are dealt with using
  1.1016 + * an intermediate __cxa_exception block in the appropriate exceptions
  1.1017 + * chain. This block has the same exception_class as the real foreign
  1.1018 + * ucb, and points to the real ucb via the intermediate block's exceptionType
  1.1019 + * field. This helper function checks whether it has been passed such an
  1.1020 + * intermediate block and sets one up if not. Only call it when the UCB
  1.1021 + * is known to belong to a foreign exception.
  1.1022 + */
  1.1023 +
  1.1024 +__cxa_exception *NAMES::get_foreign_intermediary(__cxa_exception *head_ep, UCB *ucbp)
  1.1025 +{
  1.1026 +  if (head_ep != NULL) {
  1.1027 +    UCB *head_ucbp = &head_ep->ucb;
  1.1028 +    if (NAMES::same_exceptions_class(&head_ucbp->exception_class, &ucbp->exception_class) &&
  1.1029 +	(UCB *)head_ep->exceptionType == ucbp)
  1.1030 +      return head_ep;
  1.1031 +  }
  1.1032 +
  1.1033 +  // Create an intermediate block. Only initialise as much as necessary
  1.1034 +  __cxa_exception *ep = ((__cxa_exception *)__cxa_allocate_exception(0)) - 1;
  1.1035 +  UCB *new_ucbp = &ep->ucb;
  1.1036 +  memcpy(new_ucbp->exception_class, ucbp->exception_class, EXCEPTIONS_CLASS_SIZE);
  1.1037 +  ep->propagationCount = 0;                     // Not propagating
  1.1038 +  ep->handlerCount = 0;                         // Not handled
  1.1039 +  ep->nextCaughtException = NULL;               // Not in chain
  1.1040 +  ep->exceptionType = (const type_info *)ucbp;  // The foreign UCB
  1.1041 +  return ep;
  1.1042 +}
  1.1043 +
  1.1044 +
  1.1045 +#endif /* arm_exceptions_foreign_c */
  1.1046 +#ifdef arm_exceptions_cleanup_c
  1.1047 +
  1.1048 +bool __cxa_begin_cleanup(UCB *ucbp)
  1.1049 +{
  1.1050 +  // Indicate that a cleanup is about to start.
  1.1051 +  // Save the exception pointer over the cleanup for recovery later, using a chain.
  1.1052 +  // If we allowed the exception to be rethrown in a cleanup, then
  1.1053 +  // the object might appear multiple times at the head of this chain,
  1.1054 +  // and the propagationCount could be used to track this - at this point,
  1.1055 +  // the object is logically in the chain propagationCount-1 times, and
  1.1056 +  // physically 0 or 1 times. Thus if propagationCount == 1 we should insert
  1.1057 +  // it physically. A similar rule is used for physical removal in
  1.1058 +  //__cxa_end_cleanup.
  1.1059 +  // Foreign exceptions are handled via an intermediate __cxa_exception object
  1.1060 +  // in a similar way as __cxa_begin_catch.
  1.1061 +
  1.1062 +  __cxa_eh_globals *g = __cxa_get_globals();
  1.1063 +  __cxa_exception *ep;
  1.1064 +
  1.1065 +  if (NAMES::is_foreign_exception(ucbp)) {
  1.1066 +    ep = NAMES::get_foreign_intermediary(g->propagatingExceptions, ucbp);
  1.1067 +    ep->propagationCount++;  // Indicate one (or one additional) propagation
  1.1068 +  } else {
  1.1069 +    ep = ucbp_to_ep(ucbp);
  1.1070 +  }
  1.1071 +
  1.1072 +  if (ep->propagationCount == 1) {
  1.1073 +    // Insert into chain
  1.1074 +    ep->nextPropagatingException = g->propagatingExceptions;
  1.1075 +    g->propagatingExceptions = ep;
  1.1076 +  }
  1.1077 +
  1.1078 +  return true;
  1.1079 +}
  1.1080 +
  1.1081 +
  1.1082 +// Helper function for __cxa_end_cleanup
  1.1083 +
  1.1084 +extern "C" UCB * __ARM_cxa_end_cleanup(void)
  1.1085 +{
  1.1086 +  // Recover and return the currently propagating exception (from the
  1.1087 +  // head of the propagatingExceptions chain).
  1.1088 +  // propagationCount at this moment is a logical count of how many times the
  1.1089 +  // item is in the chain so physically unchain it when this count is 1.
  1.1090 +  // Foreign exceptions use an intermediary.
  1.1091 +
  1.1092 +  __cxa_eh_globals *g = __cxa_get_globals();
  1.1093 +  __cxa_exception *ep = g->propagatingExceptions;
  1.1094 +
  1.1095 +  if (ep == NULL) terminate();
  1.1096 +
  1.1097 +  UCB *ucbp = &ep->ucb;
  1.1098 +  if (NAMES::is_foreign_exception(ucbp)) {
  1.1099 +    // Get the foreign ucb
  1.1100 +    ucbp = (UCB *)ep->exceptionType;
  1.1101 +    if (ep->propagationCount == 1) {
  1.1102 +      // Free the intermediate ucb (see description in __cxa_begin_catch)
  1.1103 +      void *eop = (void *)(ep + 1);
  1.1104 +      g->propagatingExceptions = ep->nextPropagatingException;
  1.1105 +      __cxa_free_exception(eop);
  1.1106 +    } else {
  1.1107 +      ep->propagationCount--;
  1.1108 +    }
  1.1109 +  } else {
  1.1110 +    // Not foreign
  1.1111 +    if (ep->propagationCount == 1) { // logically in chain once - so unchain
  1.1112 +      g->propagatingExceptions = ep->nextPropagatingException;
  1.1113 +    }
  1.1114 +  }
  1.1115 +  return ucbp;
  1.1116 +}
  1.1117 +
  1.1118 +// __cxa_end_cleanup is called at the end of a cleanup fragment.
  1.1119 +// It must do the C++ housekeeping, then call _Unwind_Resume, but it must
  1.1120 +// damage no significant registers in the process.
  1.1121 +
  1.1122 +__asm void __cxa_end_cleanup(void) {
  1.1123 +  extern __ARM_cxa_end_cleanup;
  1.1124 +  extern _Unwind_Resume WEAKASMDECL;
  1.1125 +
  1.1126 +#ifdef __thumb
  1.1127 +  preserve8;                   // This is preserve8 (ARM assembler heuristics are inadequate)
  1.1128 +  push {r1-r7};
  1.1129 +  mov r2, r8;
  1.1130 +  mov r3, r9;
  1.1131 +  mov r4, r10;
  1.1132 +  mov r5, r11;
  1.1133 +  push {r1-r5};
  1.1134 +  bl __ARM_cxa_end_cleanup;    // returns UCB address in r0
  1.1135 +  pop {r1-r5};
  1.1136 +  mov r8, r2;
  1.1137 +  mov r9, r3;
  1.1138 +  mov r10, r4;
  1.1139 +  mov r11, r5;
  1.1140 +  pop {r1-r7};
  1.1141 +  bl _Unwind_Resume;           // won't return
  1.1142 +#else
  1.1143 +  stmfd r13!, {r1-r12}
  1.1144 +  bl __ARM_cxa_end_cleanup;    // returns UCB address in r0
  1.1145 +  ldmia r13!, {r1-r12};
  1.1146 +  b _Unwind_Resume;            // won't return
  1.1147 +#endif
  1.1148 +}
  1.1149 +
  1.1150 +
  1.1151 +#endif /* arm_exceptions_cleanup_c */
  1.1152 +#ifdef arm_exceptions_catchsemantics_c
  1.1153 +
  1.1154 +/* Update date structures as if catching an object.
  1.1155 + * Call this from __cxa_begin_catch when actually catching an object,
  1.1156 + * and from external_exception_termination when called by a foreign runtime
  1.1157 + * after one of our objects was caught.
  1.1158 + */
  1.1159 +
  1.1160 +void NAMES::eh_catch_semantics(UCB *ucbp)
  1.1161 +{
  1.1162 +  __cxa_eh_globals *g = __cxa_get_globals();
  1.1163 +  __cxa_exception *ep;
  1.1164 +
  1.1165 +  if (NAMES::is_foreign_exception(ucbp)) {
  1.1166 +    // Foreign exception. Get the associated intermediary block or
  1.1167 +    // make one if there isn't one already.
  1.1168 +    // In the case of a rethrow, the foreign object may already be on
  1.1169 +    // the handled exceptions chain (it will be first).
  1.1170 +    ep = NAMES::get_foreign_intermediary(g->caughtExceptions, ucbp);
  1.1171 +  } else {
  1.1172 +    // Not foreign
  1.1173 +    ep = ucbp_to_ep(ucbp);
  1.1174 +    // Decrement the propagation count
  1.1175 +    ep->propagationCount--;
  1.1176 +    // Decrement the total uncaught C++ exceptions count
  1.1177 +    g->uncaughtExceptions--;
  1.1178 +  }
  1.1179 +
  1.1180 +  // Common code for our EO's, and foreign ones where we work on the intermediate EO
  1.1181 +
  1.1182 +  // Increment the handler count for this exception object
  1.1183 +  ep->handlerCount++;
  1.1184 +
  1.1185 +  // Push the ep onto the "handled exceptions" chain if it is not already there.
  1.1186 +  // (If catching a rethrow, it may already be there)
  1.1187 +
  1.1188 +  if (ep->nextCaughtException == NULL) {
  1.1189 +    ep->nextCaughtException = g->caughtExceptions;
  1.1190 +    g->caughtExceptions = ep;
  1.1191 +  }
  1.1192 +}
  1.1193 +
  1.1194 +
  1.1195 +#endif /* arm_exceptions_catchsemantics_c */
  1.1196 +#ifdef arm_exceptions_begincatch_c
  1.1197 +
  1.1198 +void *__cxa_begin_catch(UCB *ucbp)
  1.1199 +{
  1.1200 +  void *match = (void *)ucbp->barrier_cache.bitpattern[0]; // The matched object, if any
  1.1201 +
  1.1202 +  // Update the data structures
  1.1203 +
  1.1204 +  NAMES::eh_catch_semantics(ucbp);
  1.1205 +
  1.1206 +  // Tell the unwinder the exception propagation has finished,
  1.1207 +  // and return the object pointer
  1.1208 +
  1.1209 +  _Unwind_Complete(ucbp);
  1.1210 +  return match;
  1.1211 +}
  1.1212 +
  1.1213 +
  1.1214 +#endif /* arm_exceptions_begincatch_c */
  1.1215 +#ifdef arm_exceptions_endcatch_c
  1.1216 +
  1.1217 +#pragma exceptions_unwind
  1.1218 +
  1.1219 +void __cxa_end_catch(void)
  1.1220 +{
  1.1221 +  // Recover the exception object - it is the most recent caught exception object
  1.1222 +  __cxa_eh_globals *g = __cxa_get_globals();
  1.1223 +  __cxa_exception *ep = g->caughtExceptions;
  1.1224 +
  1.1225 +  if (ep == NULL) terminate();
  1.1226 +
  1.1227 +  // Rethrow in progress?
  1.1228 +
  1.1229 +  bool object_being_rethrown = ep->propagationCount != 0;
  1.1230 +
  1.1231 +  // Decrement the handler count for this exception object
  1.1232 +  ep->handlerCount--;
  1.1233 +
  1.1234 +  // Unstack the object if it is no longer being handled anywhere.
  1.1235 +  // Destroy and free the object if it is no longer alive -
  1.1236 +  // it is dead if its handler count becomes 0, unless it is
  1.1237 +  // about to be rethrown.
  1.1238 +  // If the dtor throws, allow its exception to propagate.
  1.1239 +  // Do different things if it is a foreign exception object.
  1.1240 +
  1.1241 +  if (ep->handlerCount == 0) {
  1.1242 +    void *eop = (void *)(ep + 1);
  1.1243 +    UCB *ucbp = &ep->ucb;
  1.1244 +    bool foreign = NAMES::is_foreign_exception(ucbp);
  1.1245 +
  1.1246 +    // Unstack it from the caught exceptions stack - it is guaranteed to be top item.
  1.1247 +    g->caughtExceptions = ep->nextCaughtException;
  1.1248 +
  1.1249 +    if (foreign) {
  1.1250 +      // Get the foreign ucb and free the intermediate ucb (see description in __cxa_begin_catch)
  1.1251 +      ucbp = (UCB *)ep->exceptionType;
  1.1252 +      __cxa_free_exception(eop);
  1.1253 +    } else {
  1.1254 +      ep->nextCaughtException = NULL;  // So __cxa_begin_catch knows it isn't in the chain
  1.1255 +    }
  1.1256 +
  1.1257 +    // Now destroy the exception object if it's no longer needed
  1.1258 +    if (!object_being_rethrown) {
  1.1259 +      if (foreign) {
  1.1260 +
  1.1261 +	// Notify the foreign language, if it so requested
  1.1262 +	if (ucbp->exception_cleanup != NULL)
  1.1263 +	  (ucbp->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, ucbp);
  1.1264 +
  1.1265 +      } else {
  1.1266 +
  1.1267 +        // One of our objects: do C++-specific semantics
  1.1268 +
  1.1269 +	if (ep->exceptionDestructor != NULL) {
  1.1270 +	  // Run the dtor. If it throws, free the memory anyway and
  1.1271 +	  // propagate the new exception.
  1.1272 +#ifdef ARM_EXCEPTIONS_ENABLED
  1.1273 +	  try {
  1.1274 +	    (ep->exceptionDestructor)(eop);
  1.1275 +	  } catch(...) {
  1.1276 +	    // Free the memory and reraise
  1.1277 +	    __cxa_free_exception(eop);
  1.1278 +	    throw;
  1.1279 +	  }
  1.1280 +#else
  1.1281 +	  (ep->exceptionDestructor)(eop);
  1.1282 +#endif
  1.1283 +	}
  1.1284 +	// Dtor (if there was one) didn't throw. Free the memory.
  1.1285 +	__cxa_free_exception(eop);
  1.1286 +      }  // !foreign
  1.1287 +    }  // !object_being_rethrown
  1.1288 +  }  // ep->handlerCount == 0
  1.1289 +}
  1.1290 +
  1.1291 +
  1.1292 +#endif /* arm_exceptions_endcatch_c */
  1.1293 +#ifdef arm_exceptions_bad_typeid_c
  1.1294 +
  1.1295 +#pragma exceptions_unwind
  1.1296 +
  1.1297 +void __cxa_bad_typeid(void)
  1.1298 +{
  1.1299 +  throw std::bad_typeid();
  1.1300 +}
  1.1301 +
  1.1302 +
  1.1303 +#endif /* arm_exceptions_bad_typeid_c */
  1.1304 +#ifdef arm_exceptions_bad_cast_c
  1.1305 +
  1.1306 +#pragma exceptions_unwind
  1.1307 +
  1.1308 +void __cxa_bad_cast(void)
  1.1309 +{
  1.1310 +  throw std::bad_cast();
  1.1311 +}
  1.1312 +
  1.1313 +
  1.1314 +#endif /* arm_exceptions_bad_cast_c */