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