os/kernelhwsrv/kernel/eka/compsupp/rvct2_1/aehabi/unwind_pr.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kernel/eka/compsupp/rvct2_1/aehabi/unwind_pr.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,785 @@
     1.4 +/* unwind_pr.c - ARM-defined model personality routines
     1.5 + *
     1.6 + * Copyright 2002-2003 ARM Limited.
     1.7 + */
     1.8 +/*
     1.9 +  Licence
    1.10 +  
    1.11 +  1. Subject to the provisions of clause 2, ARM hereby grants to LICENSEE a 
    1.12 +  perpetual, non-exclusive, nontransferable, royalty free, worldwide licence 
    1.13 +  to use this Example Implementation of Exception Handling solely for the 
    1.14 +  purpose of developing, having developed, manufacturing, having 
    1.15 +  manufactured, offering to sell, selling, supplying or otherwise 
    1.16 +  distributing products which comply with the Exception Handling ABI for the 
    1.17 +  ARM Architecture specification. All other rights are reserved to ARM or its 
    1.18 +  licensors.
    1.19 +  
    1.20 +  2. THIS EXAMPLE IMPLEMENTATION OF EXCEPTION HANDLING  IS PROVIDED "AS IS" 
    1.21 +  WITH NO WARRANTIES EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED 
    1.22 +  TO ANY WARRANTY OF SATISFACTORY QUALITY, MERCHANTABILITY, NONINFRINGEMENT 
    1.23 +  OR FITNESS FOR A PARTICULAR PURPOSE.
    1.24 +*/
    1.25 +/*
    1.26 + * RCS $Revision: 1.20 $
    1.27 + * Checkin $Date: 2003/11/10 17:13:37 $
    1.28 + * Revising $Author: achapman $
    1.29 + */
    1.30 +
    1.31 +#include <cstdlib>
    1.32 +/* Environment: */
    1.33 +#include "unwind_env.h"
    1.34 +/* Language-independent unwinder declarations: */
    1.35 +#include "unwinder.h"
    1.36 +
    1.37 +/* Define PR_DIAGNOSTICS for printed diagnostics from the personality routine */
    1.38 +
    1.39 +#ifdef PR_DIAGNOSTICS
    1.40 +extern int printf(const char *, ...);
    1.41 +#endif
    1.42 +
    1.43 +
    1.44 +/* Forward decl: */
    1.45 +extern _Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
    1.46 +                                                     _Unwind_Control_Block *ucbp,
    1.47 +                                                     _Unwind_Context *context,
    1.48 +                                                     uint32_t idx);
    1.49 +
    1.50 +/* Personality routines - external entry points.
    1.51 + * pr0: short unwind description, 16 bit EHT offsets.
    1.52 + * pr1: long unwind description, 16 bit EHT offsets.
    1.53 + * pr2: long unwind description, 32 bit EHT offsets.
    1.54 + */
    1.55 +
    1.56 +#ifdef pr0_c
    1.57 +_Unwind_Reason_Code __aeabi_unwind_cpp_pr0(_Unwind_State state,
    1.58 +                                           _Unwind_Control_Block *ucbp,
    1.59 +                                           _Unwind_Context *context) {
    1.60 +  return __ARM_unwind_cpp_prcommon(state, ucbp, context, 0);
    1.61 +}
    1.62 +#endif
    1.63 +
    1.64 +#ifdef pr1_c
    1.65 +_Unwind_Reason_Code __aeabi_unwind_cpp_pr1(_Unwind_State state,
    1.66 +                                           _Unwind_Control_Block *ucbp,
    1.67 +                                           _Unwind_Context *context) {
    1.68 +  return __ARM_unwind_cpp_prcommon(state, ucbp, context, 1);
    1.69 +}
    1.70 +#endif
    1.71 +
    1.72 +#ifdef pr2_c
    1.73 +_Unwind_Reason_Code __aeabi_unwind_cpp_pr2(_Unwind_State state,
    1.74 +                                           _Unwind_Control_Block *ucbp,
    1.75 +                                           _Unwind_Context *context) {
    1.76 +  return __ARM_unwind_cpp_prcommon(state, ucbp, context, 2);
    1.77 +}
    1.78 +#endif
    1.79 +
    1.80 +/* The rest of the file deals with the common routine */
    1.81 +
    1.82 +#ifdef prcommon_c
    1.83 +
    1.84 +/* C++ exceptions ABI required here:
    1.85 + * Declare protocol routines called by the personality routine.
    1.86 + * These are weak references so that referencing them here is
    1.87 + * insufficient to pull them into the image - they will only be
    1.88 + * included if application code uses a __cxa routine.
    1.89 + */
    1.90 +
    1.91 +typedef unsigned char bool;
    1.92 +static const bool false = 0;
    1.93 +static const bool true = !false;
    1.94 +
    1.95 +typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
    1.96 +
    1.97 +WEAKDECL void __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
    1.98 +WEAKDECL bool __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
    1.99 +WEAKDECL bool __cxa_type_match(_Unwind_Control_Block *ucbp,
   1.100 +                               const type_info *rttip,
   1.101 +                               void **matched_object);
   1.102 +
   1.103 +
   1.104 +/* ----- Address manipulation: ----- */
   1.105 +
   1.106 +/* The following helper function is never called and is present simply
   1.107 + * for ease of packaging. The constant word within is used by
   1.108 + * ER_RO_offset_to_addr to compute the RO segment base.
   1.109 + * The zero word named W is relocated relative to the base B of the
   1.110 + * segment which includes it, hence B is recoverable at runtime by
   1.111 + * computing &W - W.
   1.112 + */
   1.113 +
   1.114 +extern const uint32_t __ARM_unwind_cpp_ROSegBase_SelfOffset;
   1.115 +
   1.116 +__asm void __ARM_unwind_cpp_basehelper(void)
   1.117 +{
   1.118 +  export __ARM_unwind_cpp_ROSegBase_SelfOffset;
   1.119 +R_ARM_ROSEGREL32        EQU 39
   1.120 +__ARM_unwind_cpp_ROSegBase_SelfOffset;
   1.121 + dcd 0;
   1.122 + __RELOC R_ARM_ROSEGREL32,__ARM_unwind_cpp_ROSegBase_SelfOffset;
   1.123 +}
   1.124 +
   1.125 +#define ER_RO_SegBase ((uint32_t)&__ARM_unwind_cpp_ROSegBase_SelfOffset - \
   1.126 +                        __ARM_unwind_cpp_ROSegBase_SelfOffset)
   1.127 +
   1.128 +/* And now the function used to convert segment-relative offsets
   1.129 + * to absolute addresses.
   1.130 + */
   1.131 +
   1.132 +static __inline uint32_t ER_RO_offset_to_addr(uint32_t offset)
   1.133 +{
   1.134 +  return offset + ER_RO_SegBase;
   1.135 +}
   1.136 +
   1.137 +
   1.138 +/* --------- VRS manipulation: --------- */
   1.139 +
   1.140 +#define R_SP 13
   1.141 +#define R_LR 14
   1.142 +#define R_PC 15
   1.143 +
   1.144 +static __inline uint32_t core_get(_Unwind_Context *context, uint32_t regno)
   1.145 +{
   1.146 +  uint32_t val;
   1.147 +  /* This call is required to never fail if given a valid regno */
   1.148 +  _Unwind_VRS_Get(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
   1.149 +  return val;
   1.150 +}
   1.151 +
   1.152 +static __inline void core_set(_Unwind_Context *context, uint32_t regno, uint32_t newval)
   1.153 +{
   1.154 +  /* This call is required to never fail if given a valid regno */
   1.155 +  _Unwind_VRS_Set(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &newval);
   1.156 +}
   1.157 +
   1.158 +static __inline uint32_t count_to_mask(uint32_t count) {
   1.159 +  return (1 << count) - 1;
   1.160 +}
   1.161 +
   1.162 +/* --------- Support for unwind instruction stream: --------- */
   1.163 +
   1.164 +#define CODE_FINISH (0xb0)
   1.165 +
   1.166 +typedef struct uwdata {
   1.167 +  uint32_t unwind_word;                  /* current word of unwind description */
   1.168 +  uint32_t *unwind_word_pointer;         /* ptr to next word */
   1.169 +  uint8_t unwind_word_bytes_remaining;   /* count of bytes left in current word */
   1.170 +  uint8_t unwind_words_remaining;        /* count of words left, at ptr onwards */
   1.171 +} uwdata;
   1.172 +
   1.173 +static __inline uint8_t next_unwind_byte(uwdata *u) {
   1.174 +  uint8_t ub;
   1.175 +  if (u->unwind_word_bytes_remaining == 0) {  /* Load another word */
   1.176 +    if (u->unwind_words_remaining == 0) return CODE_FINISH; /* nothing left - yield NOP */
   1.177 +    u->unwind_words_remaining--;
   1.178 +    u->unwind_word = *(u->unwind_word_pointer++);
   1.179 +    u->unwind_word_bytes_remaining = 4;
   1.180 +  }
   1.181 +  
   1.182 +  u->unwind_word_bytes_remaining--;
   1.183 +  ub = (u->unwind_word & 0xff000000) >> 24;
   1.184 +  u->unwind_word <<= 8;
   1.185 +  return ub;
   1.186 +}
   1.187 +
   1.188 +
   1.189 +/* --------- Personality routines: --------- */
   1.190 +
   1.191 +/* The C++ Standard is silent on what is supposed to happen if an internal
   1.192 + * inconsistency occurs during unwinding. In our design, we return to the
   1.193 + * caller with _URC_FAILURE. During phase 1 this causes a return from the
   1.194 + * language-independent unwinder to its caller (__cxa_throw or __cxa_rethrow)
   1.195 + * which will then call terminate(). If an error occurs during phase 2, the
   1.196 + * caller will call abort().
   1.197 + */
   1.198 +
   1.199 +/* Types to assist with reading EHT's */
   1.200 +
   1.201 +typedef struct {
   1.202 +  uint16_t length;
   1.203 +  uint16_t offset;
   1.204 +} EHT16;
   1.205 +
   1.206 +typedef struct {
   1.207 +  uint32_t length;
   1.208 +  uint32_t offset;
   1.209 +} EHT32;
   1.210 +
   1.211 +typedef uint32_t landingpad_t;
   1.212 +
   1.213 +typedef struct {
   1.214 +  landingpad_t landingpad;
   1.215 +} EHT_cleanup_tail;
   1.216 +
   1.217 +typedef struct {
   1.218 +  landingpad_t landingpad;
   1.219 +  uint32_t rtti_offset;
   1.220 +} EHT_catch_tail;
   1.221 +
   1.222 +typedef struct {
   1.223 +  uint32_t rtti_count;           /* table count (possibly 0) */
   1.224 +  uint32_t (rtti_offsets[1]);    /* variable length table, possibly followed by landing pad */
   1.225 +} EHT_fnspec_tail;
   1.226 +
   1.227 +
   1.228 +/* Macros: */
   1.229 +
   1.230 +/* Barrier cache: */
   1.231 +/* Requirement imposed by C++ semantics module - match object in slot 0: */
   1.232 +#define BARRIER_HANDLEROBJECT (0)
   1.233 +/* Requirement imposed by C++ semantics module - function exception spec info */
   1.234 +#define BARRIER_FNSPECCOUNT  (1)
   1.235 +#define BARRIER_FNSPECBASE   (2)
   1.236 +#define BARRIER_FNSPECSTRIDE (3)
   1.237 +#define BARRIER_FNSPECARRAY  (4)
   1.238 +/* Private use for us between phase 1 & 2: */
   1.239 +#define BARRIER_EHTP (1)
   1.240 +
   1.241 +#define SAVE_PROPAGATION_BARRIER(UCB_PTR,VSP,EHTP,HANDLEROBJECT) \
   1.242 +  (UCB_PTR)->barrier_cache.sp = (VSP);    \
   1.243 +  (UCB_PTR)->barrier_cache.bitpattern[BARRIER_EHTP] = (uint32_t)(EHTP); \
   1.244 +  (UCB_PTR)->barrier_cache.bitpattern[BARRIER_HANDLEROBJECT] = (uint32_t)(HANDLEROBJECT);
   1.245 +
   1.246 +#define CHECK_FOR_PROPAGATION_BARRIER(UCB_PTR,VSP,EHTP) \
   1.247 +   ((UCB_PTR)->barrier_cache.sp == (VSP) &&    \
   1.248 +    (UCB_PTR)->barrier_cache.bitpattern[BARRIER_EHTP] == (uint32_t)(EHTP))
   1.249 +
   1.250 +
   1.251 +/* Cleanup cache: We only use one field */
   1.252 +#define CLEANUP_EHTP (0)
   1.253 +
   1.254 +
   1.255 +/* Special catch rtti values */
   1.256 +#define CATCH_ALL               (0xffffffff)
   1.257 +#define CATCH_ALL_AND_TERMINATE (0xfffffffe)
   1.258 +
   1.259 +
   1.260 +/* Common personality routine: receives pr index as an argument.
   1.261 + *
   1.262 + * Note this implementation contains no explicit check against attempting to
   1.263 + * unwind off the top of the stack. Instead it relies (in cooperation with
   1.264 + * the language-independent unwinder) on there being a propagation barrier
   1.265 + * somewhere on the stack, perhaps the caller to main being not
   1.266 + * unwindable. An alternative would be to check for the stack pointer
   1.267 + * addressing a stack limit symbol.
   1.268 + */
   1.269 +
   1.270 +_Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
   1.271 +                                              _Unwind_Control_Block *ucbp,
   1.272 +                                              _Unwind_Context *context,
   1.273 +                                              uint32_t idx)
   1.274 +{
   1.275 +  _Unwind_EHT_Header *eht_startp;  /* EHT start pointer */
   1.276 +  uint8_t *ehtp; /* EHT pointer, incremented as required */
   1.277 +  /* Flag for fnspec violations in which the frame should be unwound before calling unexpected() */
   1.278 +  bool phase2_call_unexpected_after_unwind;
   1.279 +  /* Flag for whether we have loaded r15 (pc) with a return address while executing
   1.280 +   * unwind instructions.
   1.281 +   * Set this on any write to r15 while executing the unwind instructions.
   1.282 +   */
   1.283 +  bool wrote_pc = false;
   1.284 +  /* Flag for whether we loaded r15 from r14 while executing the unwind instructions */
   1.285 +  bool wrote_pc_from_lr = false;
   1.286 +  uwdata ud;
   1.287 +
   1.288 +  /* Mark all as well and extract the EHT pointer */
   1.289 +
   1.290 +  eht_startp = ucbp->pr_cache.ehtp;
   1.291 +
   1.292 +#ifdef PR_DIAGNOSTICS
   1.293 +  printf("PR entered: state=%d, r15=0x%x, fnstart=0x%x\n",
   1.294 +         state, core_get(context, R_PC), ucbp->pr_cache.fnstart);
   1.295 +#endif
   1.296 +  
   1.297 +  /* What are we supposed to do? */
   1.298 +
   1.299 +  if (state != _US_VIRTUAL_UNWIND_FRAME &&
   1.300 +      state != _US_UNWIND_FRAME_STARTING &&
   1.301 +      state != _US_UNWIND_FRAME_RESUME) {
   1.302 +    DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_UNSPECIFIED);
   1.303 +    return _URC_FAILURE;
   1.304 +  }
   1.305 +
   1.306 +  phase2_call_unexpected_after_unwind = false;
   1.307 +
   1.308 +  /* Traverse the current EHT, if there is one.
   1.309 +   * The required behaviours are:
   1.310 +   * _US_VIRTUAL_UNWIND_FRAME: search for a propagation barrier in this frame.
   1.311 +   * otherwise look for the propagation barrier we found in phase 1,
   1.312 +   * performing cleanups on the way. In this case if state will be one of:
   1.313 +   *   _US_UNWIND_FRAME_STARTING  first time with this frame
   1.314 +   *   _US_UNWIND_FRAME_RESUME    not first time, we are part-way through the EHT.
   1.315 +   */
   1.316 +  
   1.317 +  if ((ucbp->pr_cache.additional & 1) == 0) { /* EHT inline in index table? */
   1.318 +    /* No: thus there is a real EHT */
   1.319 +    
   1.320 +    if (state == _US_UNWIND_FRAME_RESUME) {
   1.321 +      /* Recover saved pointer to next EHT entry */
   1.322 +      ehtp = (uint8_t *)ucbp->cleanup_cache.bitpattern[CLEANUP_EHTP];
   1.323 +#ifdef PR_DIAGNOSTICS
   1.324 +      printf("PR EHT recovered pointer 0x%x\n", (int)ehtp);
   1.325 +#endif
   1.326 +    } else {
   1.327 +      /* Point at the first EHT entry.
   1.328 +       * For pr0, the unwind description is entirely within the header word.
   1.329 +       * For pr1 & pr2, an unwind description extension word count is
   1.330 +       * held in bits 16-23 of the header word.
   1.331 +       */
   1.332 +      uint32_t unwind_extension_word_count = (idx == 0 ? 0 : ((*eht_startp) >> 16) & 0xff);
   1.333 +      ehtp = (uint8_t *)(eht_startp + 1 + unwind_extension_word_count);
   1.334 +      
   1.335 +#ifdef PR_DIAGNOSTICS
   1.336 +      printf("PR EHT first entry at 0x%x\n", (int)ehtp);
   1.337 +#endif
   1.338 +    }
   1.339 +    
   1.340 +    /* scan ... */
   1.341 +
   1.342 +    while (1) {
   1.343 +      
   1.344 +      /* Extract 32 bit length and offset */
   1.345 +      uint32_t length;
   1.346 +      uint32_t offset;
   1.347 +      if (idx == 2) {
   1.348 +        /* 32 bit offsets */
   1.349 +        length = ((EHT32 *)ehtp)->length;
   1.350 +        if (length == 0) break; /* end of table */
   1.351 +        offset = ((EHT32 *)ehtp)->offset;
   1.352 +        ehtp += sizeof(EHT32);
   1.353 +      } else {
   1.354 +        /* 16 bit offsets */
   1.355 +        length = ((EHT16 *)ehtp)->length;
   1.356 +        if (length == 0) break; /* end of table */
   1.357 +        offset = ((EHT16 *)ehtp)->offset;
   1.358 +        ehtp += sizeof(EHT16);
   1.359 +      }
   1.360 +      
   1.361 +#ifdef PR_DIAGNOSTICS
   1.362 +      printf("PR Got entry at 0x%x code=%d, length=0x%x, offset=0x%x\n",
   1.363 +             (int)(ehtp-4), ((offset & 1) << 1) | (length & 1),
   1.364 +             length & ~1, offset & ~1);
   1.365 +#endif
   1.366 +
   1.367 +      /* Dispatch on the kind of entry */
   1.368 +      switch (((offset & 1) << 1) | (length & 1)) {
   1.369 +      case 0: /* cleanup */
   1.370 +        if (state == _US_VIRTUAL_UNWIND_FRAME) {
   1.371 +          /* Not a propagation barrier - skip */
   1.372 +        } else {
   1.373 +          /* Phase 2: call the cleanup if the return address is in range */
   1.374 +          uint32_t padaddress;
   1.375 +          uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset;
   1.376 +          uint32_t rtn_addr = core_get(context, R_PC);
   1.377 +          if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
   1.378 +            /* It is in range. */
   1.379 +            landingpad_t landingpad = ((EHT_cleanup_tail *)ehtp)->landingpad;
   1.380 +            ehtp += sizeof(EHT_cleanup_tail);
   1.381 +            /* Dump state into the ECO so we resume correctly after the cleanup. */
   1.382 +            /* We simply save the address of the next EHT entry. */
   1.383 +            ucbp->cleanup_cache.bitpattern[CLEANUP_EHTP] = (uint32_t)ehtp;
   1.384 +            if (!__cxa_begin_cleanup(ucbp)) {
   1.385 +              /* Should be impossible, using ARM's library */
   1.386 +              DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_UNSPECIFIED);
   1.387 +              return _URC_FAILURE;
   1.388 +            }
   1.389 +            /* Set up the VRS to enter the landing pad. */
   1.390 +            padaddress = ER_RO_offset_to_addr(landingpad);
   1.391 +            core_set(context, R_PC, padaddress);
   1.392 +#ifdef PR_DIAGNOSTICS
   1.393 +            printf("PR Got cleanup in range, cleanup addr=0x%x\n", core_get(context, R_PC));
   1.394 +            printf("PR Saving EHT pointer 0x%x\n", (int)ehtp);
   1.395 +#endif
   1.396 +            DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, padaddress);
   1.397 +            /* Exit requesting upload the VRS to the real machine. */
   1.398 +           return _URC_INSTALL_CONTEXT;
   1.399 +          }
   1.400 +        }
   1.401 +        /* Phase 1, or phase 2 and not in range */
   1.402 +        ehtp += sizeof(EHT_cleanup_tail);
   1.403 +        break;
   1.404 +      case 1: /* catch */
   1.405 +        {
   1.406 +          if (state == _US_VIRTUAL_UNWIND_FRAME) {
   1.407 +            /* In range, and with a matching type? */
   1.408 +            uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset;
   1.409 +            uint32_t rtn_addr = core_get(context, R_PC);
   1.410 +            void *matched_object;
   1.411 +            length -= 1;   /* length had low bit set - clear it */
   1.412 +            if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
   1.413 +              /* In range */
   1.414 +              uint32_t rtti_val = ((EHT_catch_tail *)ehtp)->rtti_offset;
   1.415 +              if (rtti_val == CATCH_ALL_AND_TERMINATE) {
   1.416 +                /* Always matches and causes propagation failure in phase 1 */
   1.417 +#ifdef PR_DIAGNOSTICS
   1.418 +                printf("PR Got CATCH_ALL_AND_TERMINATE in phase 1\n");
   1.419 +#endif
   1.420 +                DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
   1.421 +                return _URC_FAILURE;    
   1.422 +              }
   1.423 +              if ((rtti_val == CATCH_ALL && ((matched_object = ucbp + 1),1)) ||
   1.424 +                  __cxa_type_match(ucbp,
   1.425 +                                   (type_info *)(rtti_val = ER_RO_offset_to_addr(rtti_val)),
   1.426 +                                   &matched_object)) {
   1.427 +                /* In range and matches.
   1.428 +                 * Record the propagation barrier details for ease of detection in phase 2.
   1.429 +                 * We save a pointer to the middle of the handler entry -
   1.430 +                 * this is fine, so long as we are consistent about it.
   1.431 +                 */
   1.432 +#ifdef PR_DIAGNOSTICS
   1.433 +                printf("PR Got barrier in phase 1\n");
   1.434 +                printf("PR Matched object address 0x%8.8x\n", matched_object); 
   1.435 +#endif
   1.436 +                SAVE_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp, matched_object);
   1.437 +                DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND,
   1.438 +                                    ER_RO_offset_to_addr(((EHT_catch_tail *)ehtp)->landingpad));
   1.439 +                DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_CPP_TYPEINFO, rtti_val);
   1.440 +                return _URC_HANDLER_FOUND;
   1.441 +              }
   1.442 +            }
   1.443 +            /* Not in range or no type match - fall thru to carry on scanning the table */
   1.444 +          } else {
   1.445 +            /* Else this is phase 2: have we encountered the saved barrier? */
   1.446 +            if (CHECK_FOR_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp)) {
   1.447 +              /* Yes we have.
   1.448 +               * Set up the VRS to enter the landing pad,
   1.449 +               * and upload the VRS to the real machine.
   1.450 +               */
   1.451 +              landingpad_t landingpad;
   1.452 +              uint32_t padaddress;
   1.453 +#ifdef PR_DIAGNOSTICS
   1.454 +              printf("PR Got catch barrier in phase 2\n");
   1.455 +#endif
   1.456 +              landingpad = ((EHT_catch_tail *)ehtp)->landingpad;
   1.457 +              padaddress = ER_RO_offset_to_addr(landingpad);
   1.458 +              core_set(context, R_PC, padaddress);
   1.459 +              core_set(context, 0, (uint32_t)ucbp);
   1.460 +              DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, padaddress);
   1.461 +              /* Exit requesting upload the VRS to the real machine. */
   1.462 +              return _URC_INSTALL_CONTEXT;
   1.463 +            }
   1.464 +          }
   1.465 +          /* Else carry on scanning the table */
   1.466 +          ehtp += sizeof(EHT_catch_tail);
   1.467 +          break;
   1.468 +        }
   1.469 +      case 2: /* function exception specification (fnspec) */
   1.470 +        {
   1.471 +          uint32_t counter_word = ((EHT_fnspec_tail *)ehtp)->rtti_count;
   1.472 +          uint32_t rtti_count = counter_word & 0x7fffffff;   /* Extract offset count */
   1.473 +          if (state == _US_VIRTUAL_UNWIND_FRAME) {
   1.474 +            /* Phase 1 */
   1.475 +            /* In range? Offset had low bit set - clear it */
   1.476 +            uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset - 1;
   1.477 +            uint32_t rtn_addr = core_get(context, R_PC);
   1.478 +            if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
   1.479 +              /* See if any type matches */
   1.480 +              uint32_t *rttipp = &((EHT_fnspec_tail *)ehtp)->rtti_offsets[0];
   1.481 +              uint32_t i;
   1.482 +              for (i = 0; i < rtti_count; i++) {
   1.483 +                 void *matched_object;
   1.484 +                 if (__cxa_type_match(ucbp,
   1.485 +                                      (type_info *)ER_RO_offset_to_addr(*rttipp),
   1.486 +                                      &matched_object)) {
   1.487 +#ifdef PR_DIAGNOSTICS
   1.488 +                   printf("PR Fnspec matched in phase 1\n");
   1.489 +#endif
   1.490 +                   break;
   1.491 +                 }
   1.492 +                 rttipp++;
   1.493 +              }
   1.494 +
   1.495 +              if (i == rtti_count) { /* NB case rtti_count==0 forces no match [for throw()] */
   1.496 +                /* No match - fnspec violation is a propagation barrier */
   1.497 +#ifdef PR_DIAGNOSTICS
   1.498 +                printf("PR Got fnspec barrier in phase 1\n");
   1.499 +#endif
   1.500 +                SAVE_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp, 0); /* save ptr to the count of types */
   1.501 +                /* Even if this is a fnspec with a landing pad, we always end up in
   1.502 +                 * __cxa_call_unexpected so tell the debugger thats where we're going
   1.503 +                 */
   1.504 +                DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND, &__cxa_call_unexpected);
   1.505 +                return _URC_HANDLER_FOUND;
   1.506 +              }
   1.507 +            } /* if (in range...) */
   1.508 +
   1.509 +            /* Fall out of the 'if' to continue table scanning */
   1.510 +
   1.511 +          } else {
   1.512 +            /* Else this is phase 2: have we encountered the saved barrier? */
   1.513 +            if (CHECK_FOR_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp)) {
   1.514 +              /* Yes we have. Fill in the UCB barrier_cache for entry to __cxa_call_unexpected */
   1.515 +              uint32_t *p = (uint32_t *)ehtp; /* ptr to rtti count */
   1.516 +              ucbp->barrier_cache.bitpattern[BARRIER_FNSPECCOUNT] = rtti_count;
   1.517 +              ucbp->barrier_cache.bitpattern[BARRIER_FNSPECBASE] = ER_RO_offset_to_addr(0); /* base address */
   1.518 +              ucbp->barrier_cache.bitpattern[BARRIER_FNSPECSTRIDE] = 4; /* stride */
   1.519 +              ucbp->barrier_cache.bitpattern[BARRIER_FNSPECARRAY]  = (uint32_t)(p + 1); /* address of rtti offset list */
   1.520 +
   1.521 +              /* If this is a fnspec with an attached landing pad, we must enter
   1.522 +               * the pad immediately. Otherwise we need to unwind the frame before
   1.523 +               * calling __cxa_call_unexpected() so set a flag to make this happen.
   1.524 +               */
   1.525 +              if (counter_word == rtti_count)
   1.526 +                phase2_call_unexpected_after_unwind = true; /* no pad, enter later */
   1.527 +              else { /* pad */
   1.528 +                landingpad_t landingpad;
   1.529 +                uint32_t padaddress;
   1.530 +#ifdef PR_DIAGNOSTICS
   1.531 +                printf("PR Got fnspec barrier in phase 2 (immediate entry)\n");
   1.532 +#endif
   1.533 +                ehtp += (sizeof(((EHT_fnspec_tail *)ehtp)->rtti_count) +
   1.534 +                         sizeof(uint32_t) * rtti_count);  /* point at pad offset */
   1.535 +                landingpad = *(landingpad_t *)ehtp;
   1.536 +                padaddress = ER_RO_offset_to_addr(landingpad);
   1.537 +                core_set(context, 0, (uint32_t)ucbp);
   1.538 +                core_set(context, R_PC, padaddress);
   1.539 +                /* Even if this is a fnspec with a landing pad, in phase 1 we said we'd
   1.540 +                 * end up in __cxa_call_unexpected so show the same thing now
   1.541 +                 */
   1.542 +                DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, &__cxa_call_unexpected);
   1.543 +                return _URC_INSTALL_CONTEXT;
   1.544 +              }
   1.545 +            } /* endif (barrier match) */
   1.546 +          } /* endif (which phase) */
   1.547 +          
   1.548 +          /* Advance to the next item, remembering to skip the landing pad if present */
   1.549 +          ehtp += (sizeof(((EHT_fnspec_tail *)ehtp)->rtti_count) +
   1.550 +                   sizeof(uint32_t) * rtti_count +
   1.551 +                   (counter_word == rtti_count ? 0 : sizeof(landingpad_t)));
   1.552 +          break;
   1.553 +        }
   1.554 +      case 3: /* unallocated */
   1.555 +        DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT);
   1.556 +        return _URC_FAILURE;
   1.557 +      } /* switch */
   1.558 +
   1.559 +    } /* while (1) */
   1.560 +    
   1.561 +#ifdef PR_DIAGNOSTICS
   1.562 +    printf("PR Reached end of EHT\n");
   1.563 +#endif
   1.564 +
   1.565 +  } /* if out-of-line EHT */
   1.566 +
   1.567 +
   1.568 +  /* Do a virtual unwind of this frame - load the first unwind bytes then loop.
   1.569 +   * Loop exit is by executing opcode CODE_FINISH.
   1.570 +   */
   1.571 +
   1.572 +  ud.unwind_word = *(uint32_t *)eht_startp;             /* first word */
   1.573 +  ud.unwind_word_pointer = (uint32_t *)eht_startp + 1;  /* ptr to extension words, if any */
   1.574 +  if (idx == 0) {                  /* short description */
   1.575 +    ud.unwind_words_remaining = 0; /* no further words */
   1.576 +    ud.unwind_word <<= 8;          /* 3 explicit unwind bytes in this word */
   1.577 +    ud.unwind_word_bytes_remaining = 3;
   1.578 +  } else {                         /* long description: extension word count in bits 16-23 */
   1.579 +    ud.unwind_words_remaining = ((ud.unwind_word) >> 16) & 0xff;
   1.580 +    ud.unwind_word <<= 16;         /* 2 explicit unwind bytes in this word */
   1.581 +    ud.unwind_word_bytes_remaining = 2;
   1.582 +  }
   1.583 +
   1.584 +#ifdef PR_DIAGNOSTICS
   1.585 +  /*  debug_print_vrs(context); */
   1.586 +#endif
   1.587 +
   1.588 +  while (1) {
   1.589 +    uint8_t ub = next_unwind_byte(&ud);
   1.590 +
   1.591 +#ifdef PR_DIAGNOSTICS
   1.592 +    printf("PR Unwind byte 0x%x\n", ub);
   1.593 +#endif
   1.594 +
   1.595 +    /* decode and execute the current byte ... */
   1.596 +
   1.597 +    if (ub == CODE_FINISH) { /* finished unwinding */
   1.598 +      if (!wrote_pc) {
   1.599 +        uint32_t lr;
   1.600 +        _Unwind_VRS_Get(context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, &lr);
   1.601 +        core_set(context, R_PC, lr);
   1.602 +        wrote_pc_from_lr = true;
   1.603 +      }
   1.604 +#ifdef PR_DIAGNOSTICS
   1.605 +      {
   1.606 +        uint32_t nextpc;
   1.607 +        _Unwind_VRS_Get(context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &nextpc);
   1.608 +        printf("PR Next PC is  0x%x\n", nextpc);
   1.609 +      }
   1.610 +#endif
   1.611 +      break;
   1.612 +    }
   1.613 +    if (ub <= 0x3f) { /* 00nnnnnn: vsp += (nnnnnn << 2) + 4 */
   1.614 +      uint32_t increment = ((ub & 0x3f) << 2) + 4;
   1.615 +      core_set(context, R_SP, core_get(context, R_SP) + increment);
   1.616 +      continue;
   1.617 +    }
   1.618 +    if (ub <= 0x7f) { /* 01xxxxxx: vsp -= (xxxxxx << 2) + 4 */
   1.619 +      uint32_t decrement = ((ub & 0x3f) << 2) + 4;
   1.620 +      core_set(context, R_SP, core_get(context, R_SP) - decrement);
   1.621 +      continue;
   1.622 +    }
   1.623 +    if (ub <= 0x8f) { /* 100000000 00000000: refuse, 1000rrrr rrrrrrrr: pop integer regs */
   1.624 +      uint32_t mask = (ub & 0xf) << 12;
   1.625 +      ub = next_unwind_byte(&ud);
   1.626 +      mask |= ub << 4;
   1.627 +      if (mask == 0) { /* 10000000 00000000 refuse to unwind */
   1.628 +        DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
   1.629 +        return _URC_FAILURE;
   1.630 +      }
   1.631 +      if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
   1.632 +        DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
   1.633 +        return _URC_FAILURE;
   1.634 +      }
   1.635 +      if (mask & (1 << R_PC)) wrote_pc = true;
   1.636 +      continue;
   1.637 +    }
   1.638 +    if (ub <= 0x9f) { /* 1001nnnn: vsp = r[nnnn] if not 13,15 */
   1.639 +      uint8_t regno = ub & 0xf;
   1.640 +      if (regno == 13 || regno == R_PC) {  /* reserved */
   1.641 +        DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
   1.642 +        return _URC_FAILURE;
   1.643 +      }
   1.644 +      core_set(context, R_SP, core_get(context, regno));
   1.645 +      continue;
   1.646 +    }
   1.647 +    if (ub <= 0xaf) { /* 1010xnnn: pop r4-r[4+nnn], +r14 if x */
   1.648 +      uint32_t mask = count_to_mask((ub & 0x7) + 1) << 4;
   1.649 +      if (ub & 0x8) mask |= (1 << R_LR);
   1.650 +      if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
   1.651 +        DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
   1.652 +        return _URC_FAILURE;
   1.653 +      }
   1.654 +      continue;
   1.655 +    }
   1.656 +    if (ub <= 0xb7) {
   1.657 +      /* if (ub == 0xb0) is CODE_FINISH, handled earlier */
   1.658 +      if (ub == 0xb1) { /* 10110001 0000iiii pop integer regs, others reserved */
   1.659 +        uint32_t mask = next_unwind_byte(&ud);
   1.660 +        if (mask == 0 || mask > 0xf) { /* reserved */
   1.661 +          DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
   1.662 +          return _URC_FAILURE;
   1.663 +        }
   1.664 +        if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
   1.665 +          DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
   1.666 +          return _URC_FAILURE;
   1.667 +        }
   1.668 +        continue;
   1.669 +      }
   1.670 +      if (ub == 0xb2) { /* 10110010 uleb128 : vsp += (uleb128 << 2) + 0x204 */
   1.671 +        uint32_t u = 0;
   1.672 +        uint32_t n = 0;
   1.673 +        /* decode */
   1.674 +        while (1) {
   1.675 +          ub = next_unwind_byte(&ud);
   1.676 +          u |= (ub & 0x7f) << n;
   1.677 +          if ((ub & 0x80) == 0) break;
   1.678 +          n += 7;
   1.679 +        }
   1.680 +        core_set(context, R_SP, core_get(context, R_SP) + (u << 2) + 0x204);
   1.681 +        continue;
   1.682 +      }
   1.683 +      if (ub == 0xb3) { /* 10110011: pop vfp */
   1.684 +        uint32_t discriminator = next_unwind_byte(&ud);
   1.685 +        discriminator = ((discriminator & 0xf0) << 12) | ((discriminator & 0x0f) + 1);
   1.686 +        if (_Unwind_VRS_Pop(context, _UVRSC_VFP, discriminator, _UVRSD_VFPX) != _UVRSR_OK) {
   1.687 +          DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
   1.688 +          return _URC_FAILURE;
   1.689 +        }
   1.690 +        continue;
   1.691 +      }
   1.692 +      { /* 101101nn: pop fpa */
   1.693 +        uint32_t discriminator = 0x40000 | ((ub & 0x3) + 1);
   1.694 +        if (_Unwind_VRS_Pop(context, _UVRSC_FPA, discriminator, _UVRSD_FPAX) != _UVRSR_OK) {
   1.695 +          DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
   1.696 +          return _URC_FAILURE;
   1.697 +        }
   1.698 +        continue;
   1.699 +      }
   1.700 +    } /* if (ub <= 0xb7) ... */
   1.701 +    if (ub <= 0xbf) { /* 10111nnn: pop vfp */
   1.702 +      uint32_t discriminator = 0x80000 | ((ub & 0x7) + 1);
   1.703 +      if (_Unwind_VRS_Pop(context, _UVRSC_VFP, discriminator, _UVRSD_VFPX) != _UVRSR_OK) {
   1.704 +        DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
   1.705 +        return _URC_FAILURE;
   1.706 +      }
   1.707 +      continue;
   1.708 +    }
   1.709 +    if (ub <= 0xc7) {
   1.710 +      if (ub == 0xc7) { /* 11000111: WMMX C regs */
   1.711 +        uint32_t mask = next_unwind_byte(&ud);
   1.712 +        if (mask == 0 || mask > 0xf) { /* reserved */
   1.713 +          DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
   1.714 +          return _URC_FAILURE;
   1.715 +        }
   1.716 +        if (_Unwind_VRS_Pop(context, _UVRSC_WMMXC, mask, _UVRSD_UINT32) != _UVRSR_OK) {
   1.717 +          DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
   1.718 +          return _URC_FAILURE;
   1.719 +        }
   1.720 +        continue;
   1.721 +      } else if (ub == 0xc6) { /* 11000110: WMMX D regs */
   1.722 +        uint32_t discriminator = next_unwind_byte(&ud);
   1.723 +        discriminator = ((discriminator & 0xf0) << 4) | ((discriminator & 0x0f) + 1);
   1.724 +        if (_Unwind_VRS_Pop(context, _UVRSC_WMMXD, discriminator, _UVRSD_UINT64) != _UVRSR_OK) {
   1.725 +          DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
   1.726 +          return _URC_FAILURE;
   1.727 +        }
   1.728 +        continue;
   1.729 +      } else {
   1.730 +        /* 11000nnn (nnn != 6, 7): WMMX D regs */
   1.731 +        uint32_t discriminator = 0xa00 | ((ub & 0x7) + 1);
   1.732 +        if (_Unwind_VRS_Pop(context, _UVRSC_WMMXD, discriminator, _UVRSD_UINT64) != _UVRSR_OK) {
   1.733 +          DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
   1.734 +          return _URC_FAILURE;
   1.735 +        }
   1.736 +        continue;
   1.737 +      }
   1.738 +    } /* if (ub <= 0xc7) ... */
   1.739 +    if (ub == 0xc8) { /* 11001000: pop fpa */
   1.740 +      uint32_t discriminator = next_unwind_byte(&ud);
   1.741 +      discriminator = ((discriminator & 0x70) << 12) | ((discriminator & 0x03) + 1);
   1.742 +      if (_Unwind_VRS_Pop(context, _UVRSC_FPA, discriminator, _UVRSD_FPAX) != _UVRSR_OK) {
   1.743 +        DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
   1.744 +        return _URC_FAILURE;
   1.745 +      }
   1.746 +      continue;
   1.747 +    }
   1.748 +    /* and in fact everything else is currently reserved or spare */
   1.749 +    DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
   1.750 +    return _URC_FAILURE;
   1.751 +  }
   1.752 + 
   1.753 +#ifdef PR_DIAGNOSTICS
   1.754 +  /* debug_print_vrs(context); */
   1.755 +#endif
   1.756 +
   1.757 +  /* The VRS has now been updated to reflect the virtual unwind.
   1.758 +   * If we are dealing with an unmatched fnspec, pop intervening frames 
   1.759 +   * and call unexpected(). Else return to our caller with an
   1.760 +   * indication to continue unwinding.
   1.761 +   */
   1.762 +
   1.763 +  if (phase2_call_unexpected_after_unwind) {
   1.764 +    /* Set up the VRS to enter __cxa_call_unexpected,
   1.765 +     * and upload the VRS to the real machine.
   1.766 +     * The barrier_cache was initialised earlier.
   1.767 +     */
   1.768 +#ifdef PR_DIAGNOSTICS
   1.769 +    printf("PR Got fnspec barrier in phase 2 (unwinding completed)\n");
   1.770 +#endif
   1.771 +    core_set(context, 0, (uint32_t)ucbp);
   1.772 +    if (!wrote_pc_from_lr) {
   1.773 +      uint32_t pc;
   1.774 +      /* Move the return address to lr to simulate a call */
   1.775 +      _Unwind_VRS_Get(context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &pc);
   1.776 +      core_set(context, R_LR, pc);
   1.777 +    }
   1.778 +    core_set(context, R_PC, (uint32_t)&__cxa_call_unexpected);
   1.779 +    DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, &__cxa_call_unexpected);
   1.780 +    return _URC_INSTALL_CONTEXT;
   1.781 +  }
   1.782 +  
   1.783 +  /* Else continue with next frame */
   1.784 +  return _URC_CONTINUE_UNWIND;
   1.785 +}
   1.786 +
   1.787 +#endif
   1.788 +/* end ifdef prcommon_c */