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