kernel/eka/compsupp/rvct2_1/aehabi/unwind_pr.c
changeset 266 0008ccd16016
parent 259 57b9594f5772
child 272 70a6efdb753f
child 281 13fbfa31d2ba
equal deleted inserted replaced
259:57b9594f5772 266:0008ccd16016
     1 /* unwind_pr.c - ARM-defined model personality routines
       
     2  *
       
     3  * Copyright 2002-2003 ARM Limited.
       
     4  */
       
     5 /*
       
     6   Licence
       
     7   
       
     8   1. Subject to the provisions of clause 2, ARM hereby grants to LICENSEE a 
       
     9   perpetual, non-exclusive, nontransferable, royalty free, worldwide licence 
       
    10   to use this Example Implementation of Exception Handling solely for the 
       
    11   purpose of developing, having developed, manufacturing, having 
       
    12   manufactured, offering to sell, selling, supplying or otherwise 
       
    13   distributing products which comply with the Exception Handling ABI for the 
       
    14   ARM Architecture specification. All other rights are reserved to ARM or its 
       
    15   licensors.
       
    16   
       
    17   2. THIS EXAMPLE IMPLEMENTATION OF EXCEPTION HANDLING  IS PROVIDED "AS IS" 
       
    18   WITH NO WARRANTIES EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED 
       
    19   TO ANY WARRANTY OF SATISFACTORY QUALITY, MERCHANTABILITY, NONINFRINGEMENT 
       
    20   OR FITNESS FOR A PARTICULAR PURPOSE.
       
    21 */
       
    22 /*
       
    23  * RCS $Revision: 1.20 $
       
    24  * Checkin $Date: 2003/11/10 17:13:37 $
       
    25  * Revising $Author: achapman $
       
    26  */
       
    27 
       
    28 #include <cstdlib>
       
    29 /* Environment: */
       
    30 #include "unwind_env.h"
       
    31 /* Language-independent unwinder declarations: */
       
    32 #include "unwinder.h"
       
    33 
       
    34 /* Define PR_DIAGNOSTICS for printed diagnostics from the personality routine */
       
    35 
       
    36 #ifdef PR_DIAGNOSTICS
       
    37 extern int printf(const char *, ...);
       
    38 #endif
       
    39 
       
    40 
       
    41 /* Forward decl: */
       
    42 extern _Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
       
    43                                                      _Unwind_Control_Block *ucbp,
       
    44                                                      _Unwind_Context *context,
       
    45                                                      uint32_t idx);
       
    46 
       
    47 /* Personality routines - external entry points.
       
    48  * pr0: short unwind description, 16 bit EHT offsets.
       
    49  * pr1: long unwind description, 16 bit EHT offsets.
       
    50  * pr2: long unwind description, 32 bit EHT offsets.
       
    51  */
       
    52 
       
    53 #ifdef pr0_c
       
    54 _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(_Unwind_State state,
       
    55                                            _Unwind_Control_Block *ucbp,
       
    56                                            _Unwind_Context *context) {
       
    57   return __ARM_unwind_cpp_prcommon(state, ucbp, context, 0);
       
    58 }
       
    59 #endif
       
    60 
       
    61 #ifdef pr1_c
       
    62 _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(_Unwind_State state,
       
    63                                            _Unwind_Control_Block *ucbp,
       
    64                                            _Unwind_Context *context) {
       
    65   return __ARM_unwind_cpp_prcommon(state, ucbp, context, 1);
       
    66 }
       
    67 #endif
       
    68 
       
    69 #ifdef pr2_c
       
    70 _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(_Unwind_State state,
       
    71                                            _Unwind_Control_Block *ucbp,
       
    72                                            _Unwind_Context *context) {
       
    73   return __ARM_unwind_cpp_prcommon(state, ucbp, context, 2);
       
    74 }
       
    75 #endif
       
    76 
       
    77 /* The rest of the file deals with the common routine */
       
    78 
       
    79 #ifdef prcommon_c
       
    80 
       
    81 /* C++ exceptions ABI required here:
       
    82  * Declare protocol routines called by the personality routine.
       
    83  * These are weak references so that referencing them here is
       
    84  * insufficient to pull them into the image - they will only be
       
    85  * included if application code uses a __cxa routine.
       
    86  */
       
    87 
       
    88 typedef unsigned char bool;
       
    89 static const bool false = 0;
       
    90 static const bool true = !false;
       
    91 
       
    92 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
       
    93 
       
    94 WEAKDECL void __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
       
    95 WEAKDECL bool __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
       
    96 WEAKDECL bool __cxa_type_match(_Unwind_Control_Block *ucbp,
       
    97                                const type_info *rttip,
       
    98                                void **matched_object);
       
    99 
       
   100 
       
   101 /* ----- Address manipulation: ----- */
       
   102 
       
   103 /* The following helper function is never called and is present simply
       
   104  * for ease of packaging. The constant word within is used by
       
   105  * ER_RO_offset_to_addr to compute the RO segment base.
       
   106  * The zero word named W is relocated relative to the base B of the
       
   107  * segment which includes it, hence B is recoverable at runtime by
       
   108  * computing &W - W.
       
   109  */
       
   110 
       
   111 extern const uint32_t __ARM_unwind_cpp_ROSegBase_SelfOffset;
       
   112 
       
   113 __asm void __ARM_unwind_cpp_basehelper(void)
       
   114 {
       
   115   export __ARM_unwind_cpp_ROSegBase_SelfOffset;
       
   116 R_ARM_ROSEGREL32        EQU 39
       
   117 __ARM_unwind_cpp_ROSegBase_SelfOffset;
       
   118  dcd 0;
       
   119  __RELOC R_ARM_ROSEGREL32,__ARM_unwind_cpp_ROSegBase_SelfOffset;
       
   120 }
       
   121 
       
   122 #define ER_RO_SegBase ((uint32_t)&__ARM_unwind_cpp_ROSegBase_SelfOffset - \
       
   123                         __ARM_unwind_cpp_ROSegBase_SelfOffset)
       
   124 
       
   125 /* And now the function used to convert segment-relative offsets
       
   126  * to absolute addresses.
       
   127  */
       
   128 
       
   129 static __inline uint32_t ER_RO_offset_to_addr(uint32_t offset)
       
   130 {
       
   131   return offset + ER_RO_SegBase;
       
   132 }
       
   133 
       
   134 
       
   135 /* --------- VRS manipulation: --------- */
       
   136 
       
   137 #define R_SP 13
       
   138 #define R_LR 14
       
   139 #define R_PC 15
       
   140 
       
   141 static __inline uint32_t core_get(_Unwind_Context *context, uint32_t regno)
       
   142 {
       
   143   uint32_t val;
       
   144   /* This call is required to never fail if given a valid regno */
       
   145   _Unwind_VRS_Get(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
       
   146   return val;
       
   147 }
       
   148 
       
   149 static __inline void core_set(_Unwind_Context *context, uint32_t regno, uint32_t newval)
       
   150 {
       
   151   /* This call is required to never fail if given a valid regno */
       
   152   _Unwind_VRS_Set(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &newval);
       
   153 }
       
   154 
       
   155 static __inline uint32_t count_to_mask(uint32_t count) {
       
   156   return (1 << count) - 1;
       
   157 }
       
   158 
       
   159 /* --------- Support for unwind instruction stream: --------- */
       
   160 
       
   161 #define CODE_FINISH (0xb0)
       
   162 
       
   163 typedef struct uwdata {
       
   164   uint32_t unwind_word;                  /* current word of unwind description */
       
   165   uint32_t *unwind_word_pointer;         /* ptr to next word */
       
   166   uint8_t unwind_word_bytes_remaining;   /* count of bytes left in current word */
       
   167   uint8_t unwind_words_remaining;        /* count of words left, at ptr onwards */
       
   168 } uwdata;
       
   169 
       
   170 static __inline uint8_t next_unwind_byte(uwdata *u) {
       
   171   uint8_t ub;
       
   172   if (u->unwind_word_bytes_remaining == 0) {  /* Load another word */
       
   173     if (u->unwind_words_remaining == 0) return CODE_FINISH; /* nothing left - yield NOP */
       
   174     u->unwind_words_remaining--;
       
   175     u->unwind_word = *(u->unwind_word_pointer++);
       
   176     u->unwind_word_bytes_remaining = 4;
       
   177   }
       
   178   
       
   179   u->unwind_word_bytes_remaining--;
       
   180   ub = (u->unwind_word & 0xff000000) >> 24;
       
   181   u->unwind_word <<= 8;
       
   182   return ub;
       
   183 }
       
   184 
       
   185 
       
   186 /* --------- Personality routines: --------- */
       
   187 
       
   188 /* The C++ Standard is silent on what is supposed to happen if an internal
       
   189  * inconsistency occurs during unwinding. In our design, we return to the
       
   190  * caller with _URC_FAILURE. During phase 1 this causes a return from the
       
   191  * language-independent unwinder to its caller (__cxa_throw or __cxa_rethrow)
       
   192  * which will then call terminate(). If an error occurs during phase 2, the
       
   193  * caller will call abort().
       
   194  */
       
   195 
       
   196 /* Types to assist with reading EHT's */
       
   197 
       
   198 typedef struct {
       
   199   uint16_t length;
       
   200   uint16_t offset;
       
   201 } EHT16;
       
   202 
       
   203 typedef struct {
       
   204   uint32_t length;
       
   205   uint32_t offset;
       
   206 } EHT32;
       
   207 
       
   208 typedef uint32_t landingpad_t;
       
   209 
       
   210 typedef struct {
       
   211   landingpad_t landingpad;
       
   212 } EHT_cleanup_tail;
       
   213 
       
   214 typedef struct {
       
   215   landingpad_t landingpad;
       
   216   uint32_t rtti_offset;
       
   217 } EHT_catch_tail;
       
   218 
       
   219 typedef struct {
       
   220   uint32_t rtti_count;           /* table count (possibly 0) */
       
   221   uint32_t (rtti_offsets[1]);    /* variable length table, possibly followed by landing pad */
       
   222 } EHT_fnspec_tail;
       
   223 
       
   224 
       
   225 /* Macros: */
       
   226 
       
   227 /* Barrier cache: */
       
   228 /* Requirement imposed by C++ semantics module - match object in slot 0: */
       
   229 #define BARRIER_HANDLEROBJECT (0)
       
   230 /* Requirement imposed by C++ semantics module - function exception spec info */
       
   231 #define BARRIER_FNSPECCOUNT  (1)
       
   232 #define BARRIER_FNSPECBASE   (2)
       
   233 #define BARRIER_FNSPECSTRIDE (3)
       
   234 #define BARRIER_FNSPECARRAY  (4)
       
   235 /* Private use for us between phase 1 & 2: */
       
   236 #define BARRIER_EHTP (1)
       
   237 
       
   238 #define SAVE_PROPAGATION_BARRIER(UCB_PTR,VSP,EHTP,HANDLEROBJECT) \
       
   239   (UCB_PTR)->barrier_cache.sp = (VSP);    \
       
   240   (UCB_PTR)->barrier_cache.bitpattern[BARRIER_EHTP] = (uint32_t)(EHTP); \
       
   241   (UCB_PTR)->barrier_cache.bitpattern[BARRIER_HANDLEROBJECT] = (uint32_t)(HANDLEROBJECT);
       
   242 
       
   243 #define CHECK_FOR_PROPAGATION_BARRIER(UCB_PTR,VSP,EHTP) \
       
   244    ((UCB_PTR)->barrier_cache.sp == (VSP) &&    \
       
   245     (UCB_PTR)->barrier_cache.bitpattern[BARRIER_EHTP] == (uint32_t)(EHTP))
       
   246 
       
   247 
       
   248 /* Cleanup cache: We only use one field */
       
   249 #define CLEANUP_EHTP (0)
       
   250 
       
   251 
       
   252 /* Special catch rtti values */
       
   253 #define CATCH_ALL               (0xffffffff)
       
   254 #define CATCH_ALL_AND_TERMINATE (0xfffffffe)
       
   255 
       
   256 
       
   257 /* Common personality routine: receives pr index as an argument.
       
   258  *
       
   259  * Note this implementation contains no explicit check against attempting to
       
   260  * unwind off the top of the stack. Instead it relies (in cooperation with
       
   261  * the language-independent unwinder) on there being a propagation barrier
       
   262  * somewhere on the stack, perhaps the caller to main being not
       
   263  * unwindable. An alternative would be to check for the stack pointer
       
   264  * addressing a stack limit symbol.
       
   265  */
       
   266 
       
   267 _Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
       
   268                                               _Unwind_Control_Block *ucbp,
       
   269                                               _Unwind_Context *context,
       
   270                                               uint32_t idx)
       
   271 {
       
   272   _Unwind_EHT_Header *eht_startp;  /* EHT start pointer */
       
   273   uint8_t *ehtp; /* EHT pointer, incremented as required */
       
   274   /* Flag for fnspec violations in which the frame should be unwound before calling unexpected() */
       
   275   bool phase2_call_unexpected_after_unwind;
       
   276   /* Flag for whether we have loaded r15 (pc) with a return address while executing
       
   277    * unwind instructions.
       
   278    * Set this on any write to r15 while executing the unwind instructions.
       
   279    */
       
   280   bool wrote_pc = false;
       
   281   /* Flag for whether we loaded r15 from r14 while executing the unwind instructions */
       
   282   bool wrote_pc_from_lr = false;
       
   283   uwdata ud;
       
   284 
       
   285   /* Mark all as well and extract the EHT pointer */
       
   286 
       
   287   eht_startp = ucbp->pr_cache.ehtp;
       
   288 
       
   289 #ifdef PR_DIAGNOSTICS
       
   290   printf("PR entered: state=%d, r15=0x%x, fnstart=0x%x\n",
       
   291          state, core_get(context, R_PC), ucbp->pr_cache.fnstart);
       
   292 #endif
       
   293   
       
   294   /* What are we supposed to do? */
       
   295 
       
   296   if (state != _US_VIRTUAL_UNWIND_FRAME &&
       
   297       state != _US_UNWIND_FRAME_STARTING &&
       
   298       state != _US_UNWIND_FRAME_RESUME) {
       
   299     DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_UNSPECIFIED);
       
   300     return _URC_FAILURE;
       
   301   }
       
   302 
       
   303   phase2_call_unexpected_after_unwind = false;
       
   304 
       
   305   /* Traverse the current EHT, if there is one.
       
   306    * The required behaviours are:
       
   307    * _US_VIRTUAL_UNWIND_FRAME: search for a propagation barrier in this frame.
       
   308    * otherwise look for the propagation barrier we found in phase 1,
       
   309    * performing cleanups on the way. In this case if state will be one of:
       
   310    *   _US_UNWIND_FRAME_STARTING  first time with this frame
       
   311    *   _US_UNWIND_FRAME_RESUME    not first time, we are part-way through the EHT.
       
   312    */
       
   313   
       
   314   if ((ucbp->pr_cache.additional & 1) == 0) { /* EHT inline in index table? */
       
   315     /* No: thus there is a real EHT */
       
   316     
       
   317     if (state == _US_UNWIND_FRAME_RESUME) {
       
   318       /* Recover saved pointer to next EHT entry */
       
   319       ehtp = (uint8_t *)ucbp->cleanup_cache.bitpattern[CLEANUP_EHTP];
       
   320 #ifdef PR_DIAGNOSTICS
       
   321       printf("PR EHT recovered pointer 0x%x\n", (int)ehtp);
       
   322 #endif
       
   323     } else {
       
   324       /* Point at the first EHT entry.
       
   325        * For pr0, the unwind description is entirely within the header word.
       
   326        * For pr1 & pr2, an unwind description extension word count is
       
   327        * held in bits 16-23 of the header word.
       
   328        */
       
   329       uint32_t unwind_extension_word_count = (idx == 0 ? 0 : ((*eht_startp) >> 16) & 0xff);
       
   330       ehtp = (uint8_t *)(eht_startp + 1 + unwind_extension_word_count);
       
   331       
       
   332 #ifdef PR_DIAGNOSTICS
       
   333       printf("PR EHT first entry at 0x%x\n", (int)ehtp);
       
   334 #endif
       
   335     }
       
   336     
       
   337     /* scan ... */
       
   338 
       
   339     while (1) {
       
   340       
       
   341       /* Extract 32 bit length and offset */
       
   342       uint32_t length;
       
   343       uint32_t offset;
       
   344       if (idx == 2) {
       
   345         /* 32 bit offsets */
       
   346         length = ((EHT32 *)ehtp)->length;
       
   347         if (length == 0) break; /* end of table */
       
   348         offset = ((EHT32 *)ehtp)->offset;
       
   349         ehtp += sizeof(EHT32);
       
   350       } else {
       
   351         /* 16 bit offsets */
       
   352         length = ((EHT16 *)ehtp)->length;
       
   353         if (length == 0) break; /* end of table */
       
   354         offset = ((EHT16 *)ehtp)->offset;
       
   355         ehtp += sizeof(EHT16);
       
   356       }
       
   357       
       
   358 #ifdef PR_DIAGNOSTICS
       
   359       printf("PR Got entry at 0x%x code=%d, length=0x%x, offset=0x%x\n",
       
   360              (int)(ehtp-4), ((offset & 1) << 1) | (length & 1),
       
   361              length & ~1, offset & ~1);
       
   362 #endif
       
   363 
       
   364       /* Dispatch on the kind of entry */
       
   365       switch (((offset & 1) << 1) | (length & 1)) {
       
   366       case 0: /* cleanup */
       
   367         if (state == _US_VIRTUAL_UNWIND_FRAME) {
       
   368           /* Not a propagation barrier - skip */
       
   369         } else {
       
   370           /* Phase 2: call the cleanup if the return address is in range */
       
   371           uint32_t padaddress;
       
   372           uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset;
       
   373           uint32_t rtn_addr = core_get(context, R_PC);
       
   374           if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
       
   375             /* It is in range. */
       
   376             landingpad_t landingpad = ((EHT_cleanup_tail *)ehtp)->landingpad;
       
   377             ehtp += sizeof(EHT_cleanup_tail);
       
   378             /* Dump state into the ECO so we resume correctly after the cleanup. */
       
   379             /* We simply save the address of the next EHT entry. */
       
   380             ucbp->cleanup_cache.bitpattern[CLEANUP_EHTP] = (uint32_t)ehtp;
       
   381             if (!__cxa_begin_cleanup(ucbp)) {
       
   382               /* Should be impossible, using ARM's library */
       
   383               DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_UNSPECIFIED);
       
   384               return _URC_FAILURE;
       
   385             }
       
   386             /* Set up the VRS to enter the landing pad. */
       
   387             padaddress = ER_RO_offset_to_addr(landingpad);
       
   388             core_set(context, R_PC, padaddress);
       
   389 #ifdef PR_DIAGNOSTICS
       
   390             printf("PR Got cleanup in range, cleanup addr=0x%x\n", core_get(context, R_PC));
       
   391             printf("PR Saving EHT pointer 0x%x\n", (int)ehtp);
       
   392 #endif
       
   393             DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, padaddress);
       
   394             /* Exit requesting upload the VRS to the real machine. */
       
   395            return _URC_INSTALL_CONTEXT;
       
   396           }
       
   397         }
       
   398         /* Phase 1, or phase 2 and not in range */
       
   399         ehtp += sizeof(EHT_cleanup_tail);
       
   400         break;
       
   401       case 1: /* catch */
       
   402         {
       
   403           if (state == _US_VIRTUAL_UNWIND_FRAME) {
       
   404             /* In range, and with a matching type? */
       
   405             uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset;
       
   406             uint32_t rtn_addr = core_get(context, R_PC);
       
   407             void *matched_object;
       
   408             length -= 1;   /* length had low bit set - clear it */
       
   409             if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
       
   410               /* In range */
       
   411               uint32_t rtti_val = ((EHT_catch_tail *)ehtp)->rtti_offset;
       
   412               if (rtti_val == CATCH_ALL_AND_TERMINATE) {
       
   413                 /* Always matches and causes propagation failure in phase 1 */
       
   414 #ifdef PR_DIAGNOSTICS
       
   415                 printf("PR Got CATCH_ALL_AND_TERMINATE in phase 1\n");
       
   416 #endif
       
   417                 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
       
   418                 return _URC_FAILURE;    
       
   419               }
       
   420               if ((rtti_val == CATCH_ALL && ((matched_object = ucbp + 1),1)) ||
       
   421                   __cxa_type_match(ucbp,
       
   422                                    (type_info *)(rtti_val = ER_RO_offset_to_addr(rtti_val)),
       
   423                                    &matched_object)) {
       
   424                 /* In range and matches.
       
   425                  * Record the propagation barrier details for ease of detection in phase 2.
       
   426                  * We save a pointer to the middle of the handler entry -
       
   427                  * this is fine, so long as we are consistent about it.
       
   428                  */
       
   429 #ifdef PR_DIAGNOSTICS
       
   430                 printf("PR Got barrier in phase 1\n");
       
   431                 printf("PR Matched object address 0x%8.8x\n", matched_object); 
       
   432 #endif
       
   433                 SAVE_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp, matched_object);
       
   434                 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND,
       
   435                                     ER_RO_offset_to_addr(((EHT_catch_tail *)ehtp)->landingpad));
       
   436                 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_CPP_TYPEINFO, rtti_val);
       
   437                 return _URC_HANDLER_FOUND;
       
   438               }
       
   439             }
       
   440             /* Not in range or no type match - fall thru to carry on scanning the table */
       
   441           } else {
       
   442             /* Else this is phase 2: have we encountered the saved barrier? */
       
   443             if (CHECK_FOR_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp)) {
       
   444               /* Yes we have.
       
   445                * Set up the VRS to enter the landing pad,
       
   446                * and upload the VRS to the real machine.
       
   447                */
       
   448               landingpad_t landingpad;
       
   449               uint32_t padaddress;
       
   450 #ifdef PR_DIAGNOSTICS
       
   451               printf("PR Got catch barrier in phase 2\n");
       
   452 #endif
       
   453               landingpad = ((EHT_catch_tail *)ehtp)->landingpad;
       
   454               padaddress = ER_RO_offset_to_addr(landingpad);
       
   455               core_set(context, R_PC, padaddress);
       
   456               core_set(context, 0, (uint32_t)ucbp);
       
   457               DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, padaddress);
       
   458               /* Exit requesting upload the VRS to the real machine. */
       
   459               return _URC_INSTALL_CONTEXT;
       
   460             }
       
   461           }
       
   462           /* Else carry on scanning the table */
       
   463           ehtp += sizeof(EHT_catch_tail);
       
   464           break;
       
   465         }
       
   466       case 2: /* function exception specification (fnspec) */
       
   467         {
       
   468           uint32_t counter_word = ((EHT_fnspec_tail *)ehtp)->rtti_count;
       
   469           uint32_t rtti_count = counter_word & 0x7fffffff;   /* Extract offset count */
       
   470           if (state == _US_VIRTUAL_UNWIND_FRAME) {
       
   471             /* Phase 1 */
       
   472             /* In range? Offset had low bit set - clear it */
       
   473             uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset - 1;
       
   474             uint32_t rtn_addr = core_get(context, R_PC);
       
   475             if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
       
   476               /* See if any type matches */
       
   477               uint32_t *rttipp = &((EHT_fnspec_tail *)ehtp)->rtti_offsets[0];
       
   478               uint32_t i;
       
   479               for (i = 0; i < rtti_count; i++) {
       
   480                  void *matched_object;
       
   481                  if (__cxa_type_match(ucbp,
       
   482                                       (type_info *)ER_RO_offset_to_addr(*rttipp),
       
   483                                       &matched_object)) {
       
   484 #ifdef PR_DIAGNOSTICS
       
   485                    printf("PR Fnspec matched in phase 1\n");
       
   486 #endif
       
   487                    break;
       
   488                  }
       
   489                  rttipp++;
       
   490               }
       
   491 
       
   492               if (i == rtti_count) { /* NB case rtti_count==0 forces no match [for throw()] */
       
   493                 /* No match - fnspec violation is a propagation barrier */
       
   494 #ifdef PR_DIAGNOSTICS
       
   495                 printf("PR Got fnspec barrier in phase 1\n");
       
   496 #endif
       
   497                 SAVE_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp, 0); /* save ptr to the count of types */
       
   498                 /* Even if this is a fnspec with a landing pad, we always end up in
       
   499                  * __cxa_call_unexpected so tell the debugger thats where we're going
       
   500                  */
       
   501                 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND, &__cxa_call_unexpected);
       
   502                 return _URC_HANDLER_FOUND;
       
   503               }
       
   504             } /* if (in range...) */
       
   505 
       
   506             /* Fall out of the 'if' to continue table scanning */
       
   507 
       
   508           } else {
       
   509             /* Else this is phase 2: have we encountered the saved barrier? */
       
   510             if (CHECK_FOR_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp)) {
       
   511               /* Yes we have. Fill in the UCB barrier_cache for entry to __cxa_call_unexpected */
       
   512               uint32_t *p = (uint32_t *)ehtp; /* ptr to rtti count */
       
   513               ucbp->barrier_cache.bitpattern[BARRIER_FNSPECCOUNT] = rtti_count;
       
   514               ucbp->barrier_cache.bitpattern[BARRIER_FNSPECBASE] = ER_RO_offset_to_addr(0); /* base address */
       
   515               ucbp->barrier_cache.bitpattern[BARRIER_FNSPECSTRIDE] = 4; /* stride */
       
   516               ucbp->barrier_cache.bitpattern[BARRIER_FNSPECARRAY]  = (uint32_t)(p + 1); /* address of rtti offset list */
       
   517 
       
   518               /* If this is a fnspec with an attached landing pad, we must enter
       
   519                * the pad immediately. Otherwise we need to unwind the frame before
       
   520                * calling __cxa_call_unexpected() so set a flag to make this happen.
       
   521                */
       
   522               if (counter_word == rtti_count)
       
   523                 phase2_call_unexpected_after_unwind = true; /* no pad, enter later */
       
   524               else { /* pad */
       
   525                 landingpad_t landingpad;
       
   526                 uint32_t padaddress;
       
   527 #ifdef PR_DIAGNOSTICS
       
   528                 printf("PR Got fnspec barrier in phase 2 (immediate entry)\n");
       
   529 #endif
       
   530                 ehtp += (sizeof(((EHT_fnspec_tail *)ehtp)->rtti_count) +
       
   531                          sizeof(uint32_t) * rtti_count);  /* point at pad offset */
       
   532                 landingpad = *(landingpad_t *)ehtp;
       
   533                 padaddress = ER_RO_offset_to_addr(landingpad);
       
   534                 core_set(context, 0, (uint32_t)ucbp);
       
   535                 core_set(context, R_PC, padaddress);
       
   536                 /* Even if this is a fnspec with a landing pad, in phase 1 we said we'd
       
   537                  * end up in __cxa_call_unexpected so show the same thing now
       
   538                  */
       
   539                 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, &__cxa_call_unexpected);
       
   540                 return _URC_INSTALL_CONTEXT;
       
   541               }
       
   542             } /* endif (barrier match) */
       
   543           } /* endif (which phase) */
       
   544           
       
   545           /* Advance to the next item, remembering to skip the landing pad if present */
       
   546           ehtp += (sizeof(((EHT_fnspec_tail *)ehtp)->rtti_count) +
       
   547                    sizeof(uint32_t) * rtti_count +
       
   548                    (counter_word == rtti_count ? 0 : sizeof(landingpad_t)));
       
   549           break;
       
   550         }
       
   551       case 3: /* unallocated */
       
   552         DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT);
       
   553         return _URC_FAILURE;
       
   554       } /* switch */
       
   555 
       
   556     } /* while (1) */
       
   557     
       
   558 #ifdef PR_DIAGNOSTICS
       
   559     printf("PR Reached end of EHT\n");
       
   560 #endif
       
   561 
       
   562   } /* if out-of-line EHT */
       
   563 
       
   564 
       
   565   /* Do a virtual unwind of this frame - load the first unwind bytes then loop.
       
   566    * Loop exit is by executing opcode CODE_FINISH.
       
   567    */
       
   568 
       
   569   ud.unwind_word = *(uint32_t *)eht_startp;             /* first word */
       
   570   ud.unwind_word_pointer = (uint32_t *)eht_startp + 1;  /* ptr to extension words, if any */
       
   571   if (idx == 0) {                  /* short description */
       
   572     ud.unwind_words_remaining = 0; /* no further words */
       
   573     ud.unwind_word <<= 8;          /* 3 explicit unwind bytes in this word */
       
   574     ud.unwind_word_bytes_remaining = 3;
       
   575   } else {                         /* long description: extension word count in bits 16-23 */
       
   576     ud.unwind_words_remaining = ((ud.unwind_word) >> 16) & 0xff;
       
   577     ud.unwind_word <<= 16;         /* 2 explicit unwind bytes in this word */
       
   578     ud.unwind_word_bytes_remaining = 2;
       
   579   }
       
   580 
       
   581 #ifdef PR_DIAGNOSTICS
       
   582   /*  debug_print_vrs(context); */
       
   583 #endif
       
   584 
       
   585   while (1) {
       
   586     uint8_t ub = next_unwind_byte(&ud);
       
   587 
       
   588 #ifdef PR_DIAGNOSTICS
       
   589     printf("PR Unwind byte 0x%x\n", ub);
       
   590 #endif
       
   591 
       
   592     /* decode and execute the current byte ... */
       
   593 
       
   594     if (ub == CODE_FINISH) { /* finished unwinding */
       
   595       if (!wrote_pc) {
       
   596         uint32_t lr;
       
   597         _Unwind_VRS_Get(context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, &lr);
       
   598         core_set(context, R_PC, lr);
       
   599         wrote_pc_from_lr = true;
       
   600       }
       
   601 #ifdef PR_DIAGNOSTICS
       
   602       {
       
   603         uint32_t nextpc;
       
   604         _Unwind_VRS_Get(context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &nextpc);
       
   605         printf("PR Next PC is  0x%x\n", nextpc);
       
   606       }
       
   607 #endif
       
   608       break;
       
   609     }
       
   610     if (ub <= 0x3f) { /* 00nnnnnn: vsp += (nnnnnn << 2) + 4 */
       
   611       uint32_t increment = ((ub & 0x3f) << 2) + 4;
       
   612       core_set(context, R_SP, core_get(context, R_SP) + increment);
       
   613       continue;
       
   614     }
       
   615     if (ub <= 0x7f) { /* 01xxxxxx: vsp -= (xxxxxx << 2) + 4 */
       
   616       uint32_t decrement = ((ub & 0x3f) << 2) + 4;
       
   617       core_set(context, R_SP, core_get(context, R_SP) - decrement);
       
   618       continue;
       
   619     }
       
   620     if (ub <= 0x8f) { /* 100000000 00000000: refuse, 1000rrrr rrrrrrrr: pop integer regs */
       
   621       uint32_t mask = (ub & 0xf) << 12;
       
   622       ub = next_unwind_byte(&ud);
       
   623       mask |= ub << 4;
       
   624       if (mask == 0) { /* 10000000 00000000 refuse to unwind */
       
   625         DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
       
   626         return _URC_FAILURE;
       
   627       }
       
   628       if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
       
   629         DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
       
   630         return _URC_FAILURE;
       
   631       }
       
   632       if (mask & (1 << R_PC)) wrote_pc = true;
       
   633       continue;
       
   634     }
       
   635     if (ub <= 0x9f) { /* 1001nnnn: vsp = r[nnnn] if not 13,15 */
       
   636       uint8_t regno = ub & 0xf;
       
   637       if (regno == 13 || regno == R_PC) {  /* reserved */
       
   638         DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
       
   639         return _URC_FAILURE;
       
   640       }
       
   641       core_set(context, R_SP, core_get(context, regno));
       
   642       continue;
       
   643     }
       
   644     if (ub <= 0xaf) { /* 1010xnnn: pop r4-r[4+nnn], +r14 if x */
       
   645       uint32_t mask = count_to_mask((ub & 0x7) + 1) << 4;
       
   646       if (ub & 0x8) mask |= (1 << R_LR);
       
   647       if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
       
   648         DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
       
   649         return _URC_FAILURE;
       
   650       }
       
   651       continue;
       
   652     }
       
   653     if (ub <= 0xb7) {
       
   654       /* if (ub == 0xb0) is CODE_FINISH, handled earlier */
       
   655       if (ub == 0xb1) { /* 10110001 0000iiii pop integer regs, others reserved */
       
   656         uint32_t mask = next_unwind_byte(&ud);
       
   657         if (mask == 0 || mask > 0xf) { /* reserved */
       
   658           DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
       
   659           return _URC_FAILURE;
       
   660         }
       
   661         if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
       
   662           DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
       
   663           return _URC_FAILURE;
       
   664         }
       
   665         continue;
       
   666       }
       
   667       if (ub == 0xb2) { /* 10110010 uleb128 : vsp += (uleb128 << 2) + 0x204 */
       
   668         uint32_t u = 0;
       
   669         uint32_t n = 0;
       
   670         /* decode */
       
   671         while (1) {
       
   672           ub = next_unwind_byte(&ud);
       
   673           u |= (ub & 0x7f) << n;
       
   674           if ((ub & 0x80) == 0) break;
       
   675           n += 7;
       
   676         }
       
   677         core_set(context, R_SP, core_get(context, R_SP) + (u << 2) + 0x204);
       
   678         continue;
       
   679       }
       
   680       if (ub == 0xb3) { /* 10110011: pop vfp */
       
   681         uint32_t discriminator = next_unwind_byte(&ud);
       
   682         discriminator = ((discriminator & 0xf0) << 12) | ((discriminator & 0x0f) + 1);
       
   683         if (_Unwind_VRS_Pop(context, _UVRSC_VFP, discriminator, _UVRSD_VFPX) != _UVRSR_OK) {
       
   684           DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
       
   685           return _URC_FAILURE;
       
   686         }
       
   687         continue;
       
   688       }
       
   689       { /* 101101nn: pop fpa */
       
   690         uint32_t discriminator = 0x40000 | ((ub & 0x3) + 1);
       
   691         if (_Unwind_VRS_Pop(context, _UVRSC_FPA, discriminator, _UVRSD_FPAX) != _UVRSR_OK) {
       
   692           DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
       
   693           return _URC_FAILURE;
       
   694         }
       
   695         continue;
       
   696       }
       
   697     } /* if (ub <= 0xb7) ... */
       
   698     if (ub <= 0xbf) { /* 10111nnn: pop vfp */
       
   699       uint32_t discriminator = 0x80000 | ((ub & 0x7) + 1);
       
   700       if (_Unwind_VRS_Pop(context, _UVRSC_VFP, discriminator, _UVRSD_VFPX) != _UVRSR_OK) {
       
   701         DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
       
   702         return _URC_FAILURE;
       
   703       }
       
   704       continue;
       
   705     }
       
   706     if (ub <= 0xc7) {
       
   707       if (ub == 0xc7) { /* 11000111: WMMX C regs */
       
   708         uint32_t mask = next_unwind_byte(&ud);
       
   709         if (mask == 0 || mask > 0xf) { /* reserved */
       
   710           DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
       
   711           return _URC_FAILURE;
       
   712         }
       
   713         if (_Unwind_VRS_Pop(context, _UVRSC_WMMXC, mask, _UVRSD_UINT32) != _UVRSR_OK) {
       
   714           DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
       
   715           return _URC_FAILURE;
       
   716         }
       
   717         continue;
       
   718       } else if (ub == 0xc6) { /* 11000110: WMMX D regs */
       
   719         uint32_t discriminator = next_unwind_byte(&ud);
       
   720         discriminator = ((discriminator & 0xf0) << 4) | ((discriminator & 0x0f) + 1);
       
   721         if (_Unwind_VRS_Pop(context, _UVRSC_WMMXD, discriminator, _UVRSD_UINT64) != _UVRSR_OK) {
       
   722           DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
       
   723           return _URC_FAILURE;
       
   724         }
       
   725         continue;
       
   726       } else {
       
   727         /* 11000nnn (nnn != 6, 7): WMMX D regs */
       
   728         uint32_t discriminator = 0xa00 | ((ub & 0x7) + 1);
       
   729         if (_Unwind_VRS_Pop(context, _UVRSC_WMMXD, discriminator, _UVRSD_UINT64) != _UVRSR_OK) {
       
   730           DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
       
   731           return _URC_FAILURE;
       
   732         }
       
   733         continue;
       
   734       }
       
   735     } /* if (ub <= 0xc7) ... */
       
   736     if (ub == 0xc8) { /* 11001000: pop fpa */
       
   737       uint32_t discriminator = next_unwind_byte(&ud);
       
   738       discriminator = ((discriminator & 0x70) << 12) | ((discriminator & 0x03) + 1);
       
   739       if (_Unwind_VRS_Pop(context, _UVRSC_FPA, discriminator, _UVRSD_FPAX) != _UVRSR_OK) {
       
   740         DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
       
   741         return _URC_FAILURE;
       
   742       }
       
   743       continue;
       
   744     }
       
   745     /* and in fact everything else is currently reserved or spare */
       
   746     DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
       
   747     return _URC_FAILURE;
       
   748   }
       
   749  
       
   750 #ifdef PR_DIAGNOSTICS
       
   751   /* debug_print_vrs(context); */
       
   752 #endif
       
   753 
       
   754   /* The VRS has now been updated to reflect the virtual unwind.
       
   755    * If we are dealing with an unmatched fnspec, pop intervening frames 
       
   756    * and call unexpected(). Else return to our caller with an
       
   757    * indication to continue unwinding.
       
   758    */
       
   759 
       
   760   if (phase2_call_unexpected_after_unwind) {
       
   761     /* Set up the VRS to enter __cxa_call_unexpected,
       
   762      * and upload the VRS to the real machine.
       
   763      * The barrier_cache was initialised earlier.
       
   764      */
       
   765 #ifdef PR_DIAGNOSTICS
       
   766     printf("PR Got fnspec barrier in phase 2 (unwinding completed)\n");
       
   767 #endif
       
   768     core_set(context, 0, (uint32_t)ucbp);
       
   769     if (!wrote_pc_from_lr) {
       
   770       uint32_t pc;
       
   771       /* Move the return address to lr to simulate a call */
       
   772       _Unwind_VRS_Get(context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &pc);
       
   773       core_set(context, R_LR, pc);
       
   774     }
       
   775     core_set(context, R_PC, (uint32_t)&__cxa_call_unexpected);
       
   776     DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, &__cxa_call_unexpected);
       
   777     return _URC_INSTALL_CONTEXT;
       
   778   }
       
   779   
       
   780   /* Else continue with next frame */
       
   781   return _URC_CONTINUE_UNWIND;
       
   782 }
       
   783 
       
   784 #endif
       
   785 /* end ifdef prcommon_c */