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