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 */