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