kernel/eka/compsupp/symaehabi/unwinder.c
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 /* unwinder.c
       
     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 /* Language-independent unwinder implementation */
       
    18 
       
    19 /* This source file is compiled automatically by ARM's make system into
       
    20  * multiple object files. The source regions constituting object file
       
    21  * xxx.o are delimited by ifdef xxx_c / endif directives.
       
    22  *
       
    23  * The source regions currently marked are:
       
    24  * unwinder_c
       
    25  * unwind_activity_c
       
    26  */
       
    27 
       
    28 #ifndef __EPOC32__
       
    29 #include <stddef.h>
       
    30 #include <stdlib.h>
       
    31 #else
       
    32 #include <e32def.h>
       
    33 #endif
       
    34 /* Environment: */
       
    35 #include "unwind_env.h"
       
    36 /* Language-independent unwinder declarations: */
       
    37 #include "unwinder.h"
       
    38 
       
    39 #ifdef __EPOC32__
       
    40 /* Symbian specific support */
       
    41 #include "symbian_support.h"
       
    42 #endif
       
    43 
       
    44 /* Define UNWIND_ACTIVITY_DIAGNOSTICS for printed information from _Unwind_Activity */
       
    45 /* Define VRS_DIAGNOSTICS for printed diagnostics about VRS operations */
       
    46 
       
    47 #if defined(VRS_DIAGNOSTICS) || defined(UNWIND_ACTIVITY_DIAGNOSTICS)
       
    48 #ifndef __EPOC32__
       
    49 extern int printf(const char *, ...);
       
    50 #endif
       
    51 #endif
       
    52 
       
    53 #ifdef SUPPORT_NESTED_EXCEPTIONS
       
    54 extern _Unwind_Control_Block *AllocSavedUCB();
       
    55 extern void FreeSavedUCB(_Unwind_Control_Block *context);
       
    56 #endif
       
    57 
       
    58 #ifdef unwinder_c
       
    59 
       
    60 /* =========================                      ========================= */
       
    61 /* ========================= Virtual register set ========================= */
       
    62 /* =========================                      ========================= */
       
    63 
       
    64 /* The approach taken by this implementation is to use the real machine
       
    65  * registers to hold all but the values of core (integer)
       
    66  * registers. Consequently the implementation must use only the core
       
    67  * registers except when manipulating the virtual register set. Non-core
       
    68  * registers are saved only on first use, so the single implementation can
       
    69  * cope with execution on processors which lack certain registers.  The
       
    70  * registers as they were at the start of the propagation must be preserved
       
    71  * over phase 1 so that the machine state is correct at the start of phase
       
    72  * 2. This requires a copy to be taken (which can be stack allocated). During
       
    73  * a stack unwind (phase 1 or phase 2), the "current" virtual register set is
       
    74  * implemented as core register values held in a data structure, and non-core
       
    75  * register values held in the registers themselves. To ensure that all
       
    76  * original register values are available at the beginning of phase 2, the
       
    77  * core registers are saved in a second structure at the start of phase 1 and
       
    78  * the non-core registers are demand-saved into another part of the data
       
    79  * structure that holds the current core registers during the phase 1 stack
       
    80  * unwind.
       
    81  */
       
    82 /* Extent to which the access routines are implemented:
       
    83  * _Unwind_VRS_Get and _Unwind_VRS_Set implement only access to the core registers.
       
    84  * _Unwind_VRS_Pop implements only popping of core and vfp registers.
       
    85  * There is no support here for the Intel WMMX registers, but space is nevertheless
       
    86  * reserved in the virtual register set structure to indicate whether demand-saving
       
    87  * of those registers is required (as they are unsupported, it never is). The space
       
    88  * costs nothing as it is required for alignment.
       
    89  * The level of supported functionality is compliant with the requirements of the
       
    90  * Exceptions ABI.
       
    91  */
       
    92 
       
    93 typedef unsigned char bool;
       
    94 struct core_s  { uint32_t r[16]; };        /* core integer regs */
       
    95 struct vfp_s   { uint64_t d[32]; };        /* VFP registers saved in FSTMD format */
       
    96 
       
    97 /* Phase 1 virtual register set includes demand-save areas */
       
    98 /* The phase 2 virtual register set must be a prefix of the phase 1 set */
       
    99 typedef struct phase1_virtual_register_set_s {
       
   100   /* demand_save flag == 1 means save the registers in the demand-save area */
       
   101   bool demand_save_vfp_low;
       
   102   bool demand_save_vfp_high;
       
   103   bool demand_save_wmmxd;
       
   104   bool demand_save_wmmxc;
       
   105   struct core_s core;      /* current core registers */
       
   106   struct vfp_s  vfp;       /* demand-saved vfp registers */
       
   107 } phase1_virtual_register_set;
       
   108 
       
   109 /* Phase 2 virtual register set has no demand-save areas */
       
   110 /* The phase 2 virtual register set must be a prefix of the phase 1 set */
       
   111 /* The assembly fragments for _Unwind_RaiseException and _Unwind_Resume create
       
   112  * a phase2_virtual_register_set_s by hand so be careful.
       
   113  */
       
   114 typedef struct phase2_virtual_register_set_s {
       
   115   /* demand_save flag == 1 means save the registers in the demand-save area */
       
   116   /* Always 0 in phase 2 */
       
   117   bool demand_save_vfp_low;
       
   118   bool demand_save_vfp_high;
       
   119   bool demand_save_wmmxd;
       
   120   bool demand_save_wmmxc;
       
   121   struct core_s core;      /* current core registers */
       
   122 } phase2_virtual_register_set;
       
   123 
       
   124 /* -- Helper macros for the embedded assembly */
       
   125 
       
   126 #if defined(__TARGET_ARCH_5T)  || defined(__TARGET_ARCH_5TXM) || \
       
   127     defined(__TARGET_ARCH_5TE) || defined(__TARGET_ARCH_6) || \
       
   128     defined(__TARGET_ARCH_6T2) || defined(__TARGET_ARCH_7_A) /* || ... */
       
   129   #define ARCH_5T_OR_LATER 1
       
   130 #else
       
   131   #define ARCH_5T_OR_LATER 0
       
   132 #endif
       
   133 
       
   134 #if defined(__APCS_INTERWORK) && !ARCH_5T_OR_LATER
       
   135   #define OLD_STYLE_INTERWORKING 1
       
   136 #else
       
   137   #define OLD_STYLE_INTERWORKING 0
       
   138 #endif
       
   139 
       
   140 #if defined(__TARGET_ARCH_4T) || defined(__TARGET_ARCH_4TXM) || ARCH_5T_OR_LATER
       
   141   #define HAVE_BX 1
       
   142 #else
       
   143   #define HAVE_BX 0
       
   144 #endif
       
   145 
       
   146 #if defined(__TARGET_ARCH_THUMBNAIL)
       
   147   #define THUMBNAIL 1
       
   148 #else
       
   149   #define THUMBNAIL 0
       
   150 #endif
       
   151 
       
   152 #if HAVE_BX
       
   153   #define RET_LR bx lr
       
   154 #else
       
   155   #define RET_LR mov pc,lr
       
   156 #endif
       
   157 
       
   158 /* ----- Routines: ----- */
       
   159 
       
   160 /* ----- Helper routines, private ----- */
       
   161 
       
   162 /* R_ARM_PREL31 is a place-relative 31-bit signed relocation.  The
       
   163  * routine takes the address of a location that was relocated by
       
   164  * R_ARM_PREL31, and returns an absolute address.
       
   165  */
       
   166 static FORCEINLINE uint32_t __ARM_resolve_prel31(void *p)
       
   167 {
       
   168   return (uint32_t)((((*(int32_t *)p) << 1) >> 1) + (int32_t)p);
       
   169 }
       
   170 
       
   171 /* ----- Helper routines, private but external ----- */
       
   172 
       
   173 /* Note '%0' refers to local label '0' */
       
   174 #if defined(__thumb)
       
   175 #define MAYBE_SWITCH_TO_ARM_STATE SWITCH_TO_ARM_STATE
       
   176 #define MAYBE_CODE16 code16
       
   177 #else
       
   178 #define MAYBE_SWITCH_TO_ARM_STATE /* nothing */
       
   179 #define MAYBE_CODE16              /* nothing */
       
   180 #endif
       
   181 __asm void __ARM_Unwind_VRS_VFPpreserve_low(void *vfpp)
       
   182 {
       
   183 vfp_d0 CN 0;
       
   184   /* Preserve the low vfp registers in the passed memory */
       
   185 #if defined(__thumb)
       
   186   macro;
       
   187   SWITCH_TO_ARM_STATE;
       
   188 1
       
   189   align 4;
       
   190 2
       
   191   assert (%2 - %1) = 0;
       
   192   bx pc;
       
   193   nop;
       
   194   code32;
       
   195   mend;
       
   196 #endif
       
   197 
       
   198   MAYBE_SWITCH_TO_ARM_STATE;
       
   199   stc   p11,vfp_d0,[r0],{0x20};  /* 0xec800b20  FSTMIAD r0,{d0-d15} */
       
   200   RET_LR;
       
   201   MAYBE_CODE16;
       
   202 }
       
   203 
       
   204 __asm void __ARM_Unwind_VRS_VFPpreserve_high(void *vfpp)
       
   205 {
       
   206 vfp_d16 CN 0;                      /* =16 when used with stcl */
       
   207   /* Preserve the high vfp registers in the passed memory */
       
   208   MAYBE_SWITCH_TO_ARM_STATE;
       
   209   stcl  p11,vfp_d16,[r0],{0x20};  /* 0xecc00b20  FSTMIAD r0,{d16-d31} */
       
   210   RET_LR;
       
   211   MAYBE_CODE16;
       
   212 }
       
   213 
       
   214 __asm void __ARM_Unwind_VRS_VFPrestore_low(void *vfpp)
       
   215 {
       
   216   /* Restore the low vfp registers from the passed memory */
       
   217 vfp_d0 CN 0;
       
   218   MAYBE_SWITCH_TO_ARM_STATE;
       
   219   ldc   p11,vfp_d0,[r0],{0x20};  /* 0xec900b20  FLDMIAD r0,{d0-d15} */
       
   220   RET_LR;
       
   221   MAYBE_CODE16;
       
   222 }
       
   223 
       
   224 __asm void __ARM_Unwind_VRS_VFPrestore_high(void *vfpp)
       
   225 {
       
   226   /* Restore the high vfp registers from the passed memory */
       
   227 vfp_d16 CN 0;                      /* =16 when used with ldcl */
       
   228   MAYBE_SWITCH_TO_ARM_STATE;
       
   229   ldcl   p11,vfp_d16,[r0],{0x20};  /* 0xecd00b20  FLDMIAD r0,{d16-d31} */
       
   230   RET_LR;
       
   231   MAYBE_CODE16;
       
   232 }
       
   233 
       
   234 
       
   235 __asm NORETURNDECL void __ARM_Unwind_VRS_corerestore(void *corep)
       
   236 {
       
   237   /* We rely here on corep pointing to a location in the stack,
       
   238    * as we briefly assign it to sp. This allows us to safely do
       
   239    * ldmia's which restore sp (if we use a different base register,
       
   240    * the updated sp may be used by the handler of any data abort
       
   241    * that occurs during the ldmia, and the stack gets overwritten).
       
   242    * By hypothesis this is preserve8 but the load of sp means the
       
   243    * assembler can't infer that.
       
   244    */
       
   245 #if THUMBNAIL
       
   246   preserve8;
       
   247   mov.w   r13, r0;
       
   248   ldmia.w r13!,{r0-r12};
       
   249   ldr.w   r14, [r13, #4]   /* lr */
       
   250   ldr.w   r12, [r13, #4*2] /* pc */
       
   251   ldr.w   r13, [r13, #0]   /* sp */
       
   252   bx      r12
       
   253   
       
   254 #else
       
   255   preserve8;
       
   256   MAYBE_SWITCH_TO_ARM_STATE;
       
   257 #if OLD_STYLE_INTERWORKING
       
   258   mov   r13, r0;
       
   259   ldmia r13!,{r0-r12};
       
   260   ldr   r12,[r13, #4*2]; /* pc */
       
   261   ldmia r13,{r13-r14};
       
   262   bx    r12;
       
   263 #else
       
   264 
       
   265   #if __ARMCC_VERSION < 300000
       
   266   mov   r13, r0;
       
   267   ldmia r13,{r0-r15};
       
   268   #else
       
   269   mov r14, r0;
       
   270   ldmia r14!, {r0-r12};
       
   271   ldr r13, [r14], #4;
       
   272   ldmia r14, {r14,r15};
       
   273   #endif
       
   274 
       
   275 #endif
       
   276   MAYBE_CODE16;
       
   277 #endif
       
   278 }
       
   279 
       
   280 
       
   281 /* ----- Development support ----- */
       
   282 
       
   283 #ifdef VRS_DIAGNOSTICS
       
   284 static void debug_print_vrs_vfp(uint32_t base, uint64_t *lp)
       
   285 {
       
   286   int c = 0;
       
   287   int i;
       
   288   for (i = 0; i < 16; i++) {
       
   289     printf("D%-2d  0x%16.16llx    ", i + base, *lp);
       
   290     lp++;
       
   291     if (c++ == 1) {
       
   292       c = 0;
       
   293       printf("\n");
       
   294     }
       
   295   }
       
   296 }
       
   297 
       
   298 
       
   299 static void debug_print_vrs(_Unwind_Context *context)
       
   300 {
       
   301   phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context;
       
   302   int i;
       
   303   int c;
       
   304   printf("------------------------------------------------------------------------\n");
       
   305   c = 0;
       
   306   for (i = 0; i < 16; i++) {
       
   307     printf("r%-2d  0x%8.8x    ", i, vrsp->core.r[i]);
       
   308     if (c++ == 3) {
       
   309       c = 0;
       
   310       printf("\n");
       
   311     }
       
   312   }
       
   313 
       
   314   printf("-----\n");
       
   315   if (vrsp->demand_save_vfp_low == 1)
       
   316     printf("VFP low registers not saved\n");
       
   317   else
       
   318     debug_print_vrs_vfp(0, &vrsp->vfp.d[0]);
       
   319   printf("-----\n");
       
   320   if (vrsp->demand_save_vfp_high == 1)
       
   321     printf("VFP high registers not saved\n");
       
   322   else
       
   323     debug_print_vrs_vfp(16, &vrsp->vfp.d[16]);
       
   324   printf("------------------------------------------------------------------------\n");
       
   325 }
       
   326 #endif
       
   327 
       
   328 
       
   329 /* ----- Public routines ----- */
       
   330 
       
   331 EXPORT_C _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context,
       
   332                                             _Unwind_VRS_RegClass regclass,
       
   333                                             uint32_t regno,
       
   334                                             _Unwind_VRS_DataRepresentation representation,
       
   335                                             void *valuep)
       
   336 {
       
   337   phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context;
       
   338   switch (regclass) {
       
   339   case _UVRSC_CORE:
       
   340     {
       
   341       if (representation != _UVRSD_UINT32 || regno > 15)
       
   342         return _UVRSR_FAILED;
       
   343        vrsp->core.r[regno] = *(uint32_t *)valuep;
       
   344        return _UVRSR_OK;
       
   345     }
       
   346   case _UVRSC_VFP:
       
   347   case _UVRSC_WMMXD:
       
   348   case _UVRSC_WMMXC:
       
   349     return _UVRSR_NOT_IMPLEMENTED;
       
   350   default:
       
   351     break;
       
   352   }
       
   353   return _UVRSR_FAILED;
       
   354 }
       
   355 
       
   356 
       
   357 EXPORT_C _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
       
   358                                             _Unwind_VRS_RegClass regclass,
       
   359                                             uint32_t regno,
       
   360                                             _Unwind_VRS_DataRepresentation representation,
       
   361                                             void *valuep)
       
   362 {
       
   363   phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context;
       
   364   switch (regclass) {
       
   365   case _UVRSC_CORE:
       
   366     {
       
   367       if (representation != _UVRSD_UINT32 || regno > 15)
       
   368         return _UVRSR_FAILED;
       
   369       *(uint32_t *)valuep = vrsp->core.r[regno];
       
   370       return _UVRSR_OK;
       
   371     }
       
   372   case _UVRSC_VFP:
       
   373   case _UVRSC_WMMXD:
       
   374   case _UVRSC_WMMXC:
       
   375     return _UVRSR_NOT_IMPLEMENTED;
       
   376   default:
       
   377     break;
       
   378   }
       
   379   return _UVRSR_FAILED;
       
   380 }
       
   381 
       
   382 
       
   383 #define R_SP 13
       
   384 
       
   385 EXPORT_C _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *context,
       
   386                                             _Unwind_VRS_RegClass regclass,
       
   387                                             uint32_t descriminator,
       
   388                                             _Unwind_VRS_DataRepresentation representation)
       
   389 {
       
   390   phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context;
       
   391   switch (regclass) {
       
   392   case _UVRSC_CORE:
       
   393     {
       
   394       /* If SP is included in the mask, the loaded value is used in preference to
       
   395        * the writeback value, but only on completion of the loading.
       
   396        */
       
   397       uint32_t mask, *vsp, *rp, sp_loaded;
       
   398       if (representation != _UVRSD_UINT32)
       
   399         return _UVRSR_FAILED;
       
   400       vsp = (uint32_t *)vrsp->core.r[R_SP];
       
   401       rp = (uint32_t *)&vrsp->core;
       
   402       mask = descriminator & 0xffff;
       
   403       sp_loaded = mask & (1 << R_SP);
       
   404       while (mask != 0) {
       
   405         if (mask & 1) {
       
   406 #ifdef VRS_DIAGNOSTICS
       
   407           printf("VRS Pop r%d\n", rp - &vrsp->core.r[0]);
       
   408 #endif
       
   409           *rp = *vsp++;
       
   410         }
       
   411         rp++;
       
   412         mask >>= 1;
       
   413       }
       
   414       if (!sp_loaded)
       
   415         vrsp->core.r[R_SP] = (uint32_t)vsp;
       
   416       return _UVRSR_OK;
       
   417     }
       
   418   case _UVRSC_VFP:
       
   419     {
       
   420       uint32_t start = descriminator >> 16;
       
   421       uint32_t count = descriminator & 0xffff;
       
   422       bool some_low = start < 16;
       
   423       bool some_high = start + count > 16;
       
   424       if ((representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) ||
       
   425           (representation == _UVRSD_VFPX && some_high) ||
       
   426           (representation == _UVRSD_DOUBLE && start + count > 32))
       
   427         return _UVRSR_FAILED;
       
   428       if (some_low && vrsp->demand_save_vfp_low == 1) { /* Demand-save over phase 1 */
       
   429         vrsp->demand_save_vfp_low = 0;
       
   430         __ARM_Unwind_VRS_VFPpreserve_low(&vrsp->vfp.d[0]);
       
   431       }
       
   432       if (some_high && vrsp->demand_save_vfp_high == 1) { /* Demand-save over phase 1 */
       
   433         vrsp->demand_save_vfp_high = 0;
       
   434         __ARM_Unwind_VRS_VFPpreserve_high(&vrsp->vfp.d[16]);
       
   435       }
       
   436       /* Now recover from the stack into the real machine registers.
       
   437        * Note for _UVRSD_VFPX we assume FSTMX standard format 1.
       
   438        * Do this by saving the current VFP registers to a memory area,
       
   439        * moving the in-memory values into that area, and
       
   440        * restoring from the whole area.
       
   441        * Must be careful as the 64-bit values saved by FSTMX might be
       
   442        * only 32-bit aligned.
       
   443        */
       
   444       {
       
   445         struct unaligned_vfp_reg_s { uint32_t w1; uint32_t w2; };
       
   446         struct unaligned_vfp_reg_s *vsp;
       
   447         struct vfp_s temp_vfp;
       
   448         if (some_low)
       
   449           __ARM_Unwind_VRS_VFPpreserve_low(&temp_vfp.d[0]);
       
   450         if (some_high)
       
   451           __ARM_Unwind_VRS_VFPpreserve_high(&temp_vfp.d[16]);
       
   452         vsp = (struct unaligned_vfp_reg_s *)vrsp->core.r[R_SP];
       
   453         while (count--) {
       
   454           struct unaligned_vfp_reg_s *v =
       
   455             (struct unaligned_vfp_reg_s *)&temp_vfp.d[start++];
       
   456           *v = *vsp++;
       
   457 #ifdef VRS_DIAGNOSTICS
       
   458           printf("VRS Pop D%d = 0x%llx\n", start - 1, temp_vfp.d[start - 1]);
       
   459 #endif
       
   460         }
       
   461         vrsp->core.r[R_SP] = (uint32_t)((uint32_t *)vsp +
       
   462                                         (representation == _UVRSD_VFPX ?
       
   463                                          1 : /* +1 to skip the format word */
       
   464                                          0));
       
   465         if (some_low)
       
   466           __ARM_Unwind_VRS_VFPrestore_low(&temp_vfp.d[0]);
       
   467         if (some_high)
       
   468           __ARM_Unwind_VRS_VFPrestore_high(&temp_vfp.d[16]);
       
   469       }
       
   470       return _UVRSR_OK;
       
   471     }
       
   472   case _UVRSC_WMMXD:
       
   473   case _UVRSC_WMMXC:
       
   474     return _UVRSR_NOT_IMPLEMENTED;
       
   475   default:
       
   476     break;
       
   477   }
       
   478   return _UVRSR_FAILED;
       
   479 }
       
   480 
       
   481 
       
   482 
       
   483 /* =========================              ========================= */
       
   484 /* ========================= The unwinder ========================= */
       
   485 /* =========================              ========================= */
       
   486 
       
   487 
       
   488 /* This implementation uses the UCB unwinder_cache as follows:
       
   489  * reserved1 is documented in the EABI as requiring initialisation to 0.
       
   490  *  It is used to manage nested simultaneous propagation. If the value is 0,
       
   491  *  the UCB is participating in no propagations. If the value is 1, the UCB
       
   492  *  is participating in one propagation. Otherwise the value is a pointer to
       
   493  *  a structure holding saved UCB state from the next propagation out.
       
   494  *  The structure used is simply a mallocated UCB.
       
   495  * reserved2 is used to preserve the call-site address over calls to a
       
   496  *  personality routine and cleanup.
       
   497  * reserved3 is used to cache the PR address.
       
   498  * reserved4 is used by the Symbian implementation to cache the ROM exeception 
       
   499  *  search table
       
   500  * reserved5 is used by the symbian implementation to cache the 
       
   501  *  TExceptionDescriptor for the executable of the 'current' frame
       
   502  */
       
   503 
       
   504 #define NESTED_CONTEXT      unwinder_cache.reserved1
       
   505 #define SAVED_CALLSITE_ADDR unwinder_cache.reserved2
       
   506 #define PR_ADDR             unwinder_cache.reserved3
       
   507 
       
   508 /* Index table entry: */
       
   509 
       
   510 #ifndef __EPOC32__  // Symbian OS defines this in symbian_support.h
       
   511 typedef struct __EIT_entry {
       
   512   uint32_t fnoffset; /* Place-relative */
       
   513   uint32_t content;
       
   514 } __EIT_entry;
       
   515 #endif
       
   516 
       
   517 /* Private defines etc: */
       
   518 
       
   519 static const uint32_t EXIDX_CANTUNWIND = 1;
       
   520 static const uint32_t uint32_highbit = 0x80000000;
       
   521 
       
   522 /* ARM C++ personality routines: */
       
   523 
       
   524 typedef _Unwind_Reason_Code (*personality_routine)(_Unwind_State,
       
   525                                                    _Unwind_Control_Block *,
       
   526                                                    _Unwind_Context *);
       
   527 
       
   528 WEAKDECL _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *,
       
   529                                                     _Unwind_Context *context);
       
   530 IMPORT_C WEAKDECL _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *,
       
   531                                                              _Unwind_Context *context);
       
   532 IMPORT_C WEAKDECL _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *,
       
   533                                                              _Unwind_Context *context);
       
   534 
       
   535 
       
   536 /* Various image symbols: */
       
   537 
       
   538 struct ExceptionTableInfo {
       
   539   uint32_t EIT_base;
       
   540   uint32_t EIT_limit;
       
   541 };
       
   542 
       
   543 #ifndef __EPOC32__
       
   544 /* We define __ARM_ETInfo to allow access to some linker-generated
       
   545    names that are not legal C identifiers. __ARM_ETInfo is extern only
       
   546    because of scope limitations of the embedded assembler */
       
   547 extern const struct ExceptionTableInfo __ARM_ETInfo;
       
   548 #define EIT_base \
       
   549     ((const __EIT_entry *)(__ARM_ETInfo.EIT_base + (const char *)&__ARM_ETInfo))
       
   550 #define EIT_limit \
       
   551     ((const __EIT_entry *)(__ARM_ETInfo.EIT_limit + (const char *)&__ARM_ETInfo))
       
   552 
       
   553 #endif
       
   554 
       
   555 
       
   556 /* ----- Index table processing ----- */
       
   557 
       
   558 /* find_and_expand_eit_entry is a support function used in both phases to set
       
   559  * ucb.pr_cache and internal cache.
       
   560  * Call with a pointer to the ucb and the return address to look up.
       
   561  *
       
   562  * The table is contained in the half-open interval
       
   563  * [EIT_base, EIT_limit) and is an ordered array of __EIT_entrys.
       
   564  * Perform a binary search via C library routine bsearch.
       
   565  * The table contains only function start addresses (encoded as offsets), so
       
   566  * we need to special-case the end table entry in the comparison function,
       
   567  * which we do by assuming the function it describes extends to end of memory.
       
   568  * This causes us problems indirectly in that we would like to fault as
       
   569  * many attempts as possible to look up an invalid return address. There are
       
   570  * several ways an invalid return address can be obtained from a broken
       
   571  * program, such as someone corrupting the stack or broken unwind instructions
       
   572  * recovered the wrong value. It is plausible that many bad return addresses
       
   573  * will be either small integers or will point into the heap or stack, hence
       
   574  * it's desirable to get the length of that final function roughly right.
       
   575  * Here we make no attempt to do it. Code exclusively for use in toolchains
       
   576  * which define a suitable limit symbol could make use of that symbol.
       
   577  * Alternatively (QoI) a smart linker could augment the index table with a
       
   578  * dummy EXIDX_CANTUNWIND entry pointing just past the last real function.
       
   579  */
       
   580 
       
   581 #ifndef __EPOC32__
       
   582 static int EIT_comparator(const void *ck, const void *ce)
       
   583 {
       
   584   uint32_t return_address = *(const uint32_t *)ck;
       
   585   const __EIT_entry *eitp = (const __EIT_entry *)ce;
       
   586   const __EIT_entry *next_eitp = eitp + 1;
       
   587   uint32_t next_fn;
       
   588   if (next_eitp != EIT_limit)
       
   589     next_fn = __ARM_resolve_prel31((void *)&next_eitp->fnoffset);
       
   590   else
       
   591     next_fn = 0xffffffffU;
       
   592   if (return_address < __ARM_resolve_prel31((void *)&eitp->fnoffset)) return -1;
       
   593   if (return_address >= next_fn) return 1;
       
   594   return 0;
       
   595 }
       
   596 #endif
       
   597 
       
   598 
       
   599 static _Unwind_Reason_Code find_and_expand_eit_entry_V2(_Unwind_Control_Block *ucbp,
       
   600                                                      uint32_t return_address)
       
   601 {
       
   602   /* Search the index table for an entry containing the specified return
       
   603    * address. Subtract the 2 from the return address, as the index table
       
   604    * contains function start addresses (a trailing noreturn BL would
       
   605    * appear to return to the first address of the next function (perhaps
       
   606    * +1 if Thumb); a leading BL would appear to return to function start
       
   607    * + instruction size (perhaps +1 if Thumb)).
       
   608    */
       
   609 
       
   610 #ifndef __EPOC32__
       
   611   const __EIT_entry *base = EIT_base;
       
   612   size_t nelems = EIT_limit - EIT_base;
       
   613   __EIT_entry *eitp;
       
   614 
       
   615   return_address -= 2;
       
   616 
       
   617   eitp = (__EIT_entry *) bsearch(&return_address, base, nelems,
       
   618                                  sizeof(__EIT_entry), EIT_comparator);
       
   619 #else
       
   620   const __EIT_entry *base = EIT_base(ucbp);
       
   621   size_t nelems = EIT_limit(ucbp) - base;
       
   622   __EIT_entry *eitp;
       
   623 
       
   624   return_address -= 2;
       
   625 
       
   626   // This must succeed on SymbianOS or else an error will have occured already.
       
   627   eitp = SearchEITV2(return_address, base, nelems);
       
   628 #endif
       
   629 
       
   630   if (eitp == NULL) {
       
   631     /* The return address we have was not found in the EIT.
       
   632      * This breaks the scan and we have to indicate failure.
       
   633      */
       
   634     ucbp->PR_ADDR = NULL;
       
   635     DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_UNWINDER_LOOKUPFAILED);
       
   636     return _URC_FAILURE;
       
   637   }
       
   638 
       
   639   /* Cache the function offset */
       
   640 
       
   641   ucbp->pr_cache.fnstart = __ARM_resolve_prel31((void *)&eitp->fnoffset);
       
   642 
       
   643   /* Can this frame be unwound at all? */
       
   644 
       
   645   if (eitp->content == EXIDX_CANTUNWIND) {
       
   646     ucbp->PR_ADDR = NULL;
       
   647     DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
       
   648     return _URC_FAILURE;
       
   649   }
       
   650 
       
   651   /* Obtain the address of the "real" __EHT_Header word */
       
   652 
       
   653   if (eitp->content & uint32_highbit) {
       
   654     /* It is immediate data */
       
   655     ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content;
       
   656     ucbp->pr_cache.additional = 1;
       
   657   } else {
       
   658     /* The content field is a 31-bit place-relative offset to an _Unwind_EHT_Entry structure */
       
   659     ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)__ARM_resolve_prel31((void *)&eitp->content);
       
   660     ucbp->pr_cache.additional = 0;
       
   661   }
       
   662 
       
   663   /* Discover the personality routine address */
       
   664 
       
   665   if (*(uint32_t *)(ucbp->pr_cache.ehtp) & uint32_highbit) {
       
   666     /* It is immediate data - compute matching pr */
       
   667     uint32_t idx = ((*(uint32_t *)(ucbp->pr_cache.ehtp)) >> 24) & 0xf;
       
   668     if (idx == 0) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr0;
       
   669     else if (idx == 1) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr1;
       
   670     else if (idx == 2) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr2;
       
   671     else { /* Failed */
       
   672       ucbp->PR_ADDR = NULL;
       
   673       DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT);
       
   674       return _URC_FAILURE;
       
   675     }
       
   676   } else {
       
   677     /* It's a place-relative offset to pr */
       
   678     ucbp->PR_ADDR = __ARM_resolve_prel31((void *)(ucbp->pr_cache.ehtp));
       
   679   }
       
   680   return _URC_OK;
       
   681 }
       
   682 
       
   683 static _Unwind_Reason_Code find_and_expand_eit_entry_V1(_Unwind_Control_Block *ucbp,
       
   684                                                      uint32_t return_address)
       
   685 {
       
   686   /* Search the index table for an entry containing the specified return
       
   687    * address. The EIT contains function offsets relative to the base of the
       
   688    * execute region so adjust the return address accordingly.
       
   689    */
       
   690 
       
   691 #ifndef __EPOC32__
       
   692   uint32_t return_address_offset = ADDR_TO_ER_RO_OFFSET(return_address, ucbp);
       
   693   const __EIT_entry *base = EIT_base;
       
   694   size_t nelems = EIT_limit - EIT_base;
       
   695 
       
   696    const __EIT_entry *eitp =
       
   697      (const __EIT_entry *) bsearch(&return_address_offset, base, nelems, 
       
   698                                    sizeof(__EIT_entry), EIT_comparator);
       
   699   if (eitp == NULL) {
       
   700     /* The return address we have was not found in the EIT.
       
   701      * This breaks the scan and we have to indicate failure.
       
   702      */
       
   703     ucbp->PR_ADDR = NULL;
       
   704     DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_UNWINDER_LOOKUPFAILED);
       
   705     return _URC_FAILURE;
       
   706   }
       
   707 #else
       
   708   /* Shouldn't we subtract 2 from here just like in the V2 lookup? 
       
   709    */
       
   710   uint32_t return_address_offset = ADDR_TO_ER_RO_OFFSET(return_address, ucbp);
       
   711   const __EIT_entry *base = EIT_base(ucbp);
       
   712   size_t nelems = EIT_limit(ucbp) - base;
       
   713 
       
   714   // This must succeed or else an error will have occured already.
       
   715   const __EIT_entry *eitp = SearchEITV1(return_address_offset, base, nelems);
       
   716 
       
   717 #endif
       
   718 
       
   719 
       
   720   /* Cache the function offset */
       
   721 
       
   722   ucbp->pr_cache.fnstart = ER_RO_OFFSET_TO_ADDR(eitp->fnoffset, ucbp);
       
   723 
       
   724   /* Can this frame be unwound at all? */
       
   725 
       
   726   if (eitp->content == EXIDX_CANTUNWIND) {
       
   727     ucbp->PR_ADDR = NULL;
       
   728     DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
       
   729     return _URC_FAILURE;
       
   730   }
       
   731 
       
   732   /* Obtain the address of the "real" __EHT_Header word */
       
   733   if (eitp->content & uint32_highbit) {
       
   734     /* It is immediate data */
       
   735     ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content;
       
   736     ucbp->pr_cache.additional = 1;
       
   737   } else {
       
   738     /* The content field is a segment relative offset to an _Unwind_EHT_Entry structure */
       
   739     ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)ER_RO_OFFSET_TO_ADDR(eitp->content, ucbp);
       
   740     ucbp->pr_cache.additional = 0;
       
   741   }
       
   742 
       
   743   /* Discover the personality routine address */
       
   744 
       
   745   if (*(uint32_t *)(ucbp->pr_cache.ehtp) & uint32_highbit) {
       
   746     /* It is immediate data - compute matching pr */
       
   747     uint32_t idx = ((*(uint32_t *)(ucbp->pr_cache.ehtp)) >> 24) & 0xf;
       
   748 
       
   749     if (idx == 0) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr0;
       
   750     else if (idx == 1) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr1;
       
   751     else if (idx == 2) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr2;
       
   752     else { /* Failed */
       
   753       ucbp->PR_ADDR = NULL;
       
   754       DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT);
       
   755       return _URC_FAILURE;
       
   756     }
       
   757   } else {
       
   758     /* Execute region offset to PR */
       
   759     ucbp->PR_ADDR = ER_RO_OFFSET_TO_ADDR(*(uint32_t *)(ucbp->pr_cache.ehtp), ucbp);
       
   760 
       
   761   }
       
   762   return _URC_OK;
       
   763 }
       
   764 
       
   765 static _Unwind_Reason_Code find_and_expand_eit_entry(_Unwind_Control_Block *ucbp,
       
   766                                                      uint32_t return_address)
       
   767 {
       
   768   ValidateExceptionDescriptor(return_address, ucbp);
       
   769   if (EHABI_V2(ucbp))
       
   770     return find_and_expand_eit_entry_V2(ucbp, return_address);
       
   771   else
       
   772     return find_and_expand_eit_entry_V1(ucbp, return_address);
       
   773 }
       
   774 
       
   775 
       
   776 /* ----- Unwinding: ----- */
       
   777 
       
   778 /* Fwd decl */
       
   779 static NORETURNDECL void unwind_next_frame(_Unwind_Control_Block *ucbp, phase2_virtual_register_set *vrsp);
       
   780 
       
   781 /* Helper fn: If the demand_save flag in a phase1_virtual_register_set was
       
   782  * zeroed, the registers were demand-saved. This function restores from
       
   783  * the save area.
       
   784 */
       
   785 static FORCEINLINE void restore_non_core_regs(phase1_virtual_register_set *vrsp)
       
   786 {
       
   787   if (vrsp->demand_save_vfp_low == 0)
       
   788     __ARM_Unwind_VRS_VFPrestore_low(&vrsp->vfp.d[0]);
       
   789   if (vrsp->demand_save_vfp_high == 0)
       
   790     __ARM_Unwind_VRS_VFPrestore_high(&vrsp->vfp.d[16]);
       
   791 }
       
   792 
       
   793 /* _Unwind_RaiseException is the external entry point to begin unwinding */
       
   794 __asm _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp)
       
   795 {
       
   796   extern __ARM_Unwind_RaiseException;
       
   797 
       
   798 #if THUMBNAIL
       
   799 
       
   800   /* Create a phase2_virtual_register_set on the stack */
       
   801   /* Save the core registers, carefully writing the original sp value */
       
   802   /* Note we account for the pc but do not actually write it's value here */
       
   803   str.w    r14,[sp, #-8]!;
       
   804   add.w    r14, r13, #8;
       
   805   str.w    r14,[sp, #-4]!  /* pushed 3 words => 3 words */
       
   806   stmfd.w  sp!,{r0-r12};   /* pushed 13 words => 16 words */
       
   807   /* Write zeroes for the demand_save bytes so no saving occurs in phase 2 */
       
   808   mov.w    r1,#0;
       
   809   str.w    r1,[sp,#-4]!;   /* pushed 1 word => 17 words */
       
   810   mov.w    r1,sp;
       
   811   sub.w    sp,sp,#4;       /* preserve 8 byte alignment => 18 words */
       
   812 
       
   813   /* Now pass to C (with r0 still valid) to do the real work.
       
   814    * r0 = ucbp, r1 = phase2_virtual_register_set.
       
   815    * If we get control back, pop the stack and return preserving r0.
       
   816    */
       
   817 
       
   818   /* on arch 5T and later the linker will fix 'bl' => 'blx' as
       
   819      needed */
       
   820   bl.w     __ARM_Unwind_RaiseException;
       
   821   ldr.w    r14,[sp,#16*4];
       
   822   add.w    sp,sp,#18*4;
       
   823   bx lr;
       
   824 
       
   825 #else
       
   826 
       
   827   MAYBE_SWITCH_TO_ARM_STATE;
       
   828 
       
   829   /* Create a phase2_virtual_register_set on the stack */
       
   830   /* Save the core registers, carefully writing the original sp value */
       
   831   #if __ARMCC_VERSION < 300000
       
   832   stmfd sp!,{r13-r15};  /* pushed 3 words => 3 words */
       
   833   #else
       
   834   stmdb r13, {r14,r15};
       
   835   str r13, [r13,#-3*4];
       
   836   sub r13, r13, #3*4;
       
   837   #endif
       
   838   stmfd sp!,{r0-r12};   /* pushed 13 words => 16 words */
       
   839   /* Write zeroes for the demand_save bytes so no saving occurs in phase 2 */
       
   840   mov r1,#0;
       
   841   str r1,[sp,#-4]!;     /* pushed 1 word => 17 words */
       
   842   mov r1,sp;
       
   843   sub sp,sp,#4;         /* preserve 8 byte alignment => 18 words */
       
   844 
       
   845   /* Now pass to C (with r0 still valid) to do the real work.
       
   846    * r0 = ucbp, r1 = phase2_virtual_register_set.
       
   847    * If we get control back, pop the stack and return preserving r0.
       
   848    */
       
   849 
       
   850 #if OLD_STYLE_INTERWORKING
       
   851   ldr r2,Unwind_RaiseException_Offset;
       
   852   add r2,r2,pc;
       
   853   mov lr,pc;
       
   854 Offset_Base
       
   855   bx    r2;
       
   856 #else
       
   857   /* on arch 5T and later the linker will fix 'bl' => 'blx' as
       
   858      needed */
       
   859   bl  __ARM_Unwind_RaiseException;
       
   860 #endif
       
   861   ldr r14,[sp,#16*4];
       
   862   add sp,sp,#18*4;
       
   863   RET_LR;
       
   864 #if OLD_STYLE_INTERWORKING
       
   865 Unwind_RaiseException_Offset dcd __ARM_Unwind_RaiseException - Offset_Base;
       
   866 #endif
       
   867   MAYBE_CODE16;
       
   868 
       
   869 #endif
       
   870 
       
   871 #ifndef __EPOC32__
       
   872   /* Alternate symbol names for difficult symbols.
       
   873    * It is possible no functions included in the image require
       
   874    * a handler table. Therefore make only a weak reference to
       
   875    * the handler table base symbol, which may be absent.
       
   876    */
       
   877   align 4
       
   878   extern |.ARM.exidx$$Base|;
       
   879   extern |.ARM.exidx$$Limit|;
       
   880   extern |.ARM.extab$$Base| WEAKASMDECL;
       
   881   export __ARM_ETInfo;
       
   882   /* these are offsets for /ropi */
       
   883 __ARM_ETInfo /* layout must match struct ExceptionTableInfo */
       
   884 eit_base   dcd |.ARM.exidx$$Base|  - __ARM_ETInfo; /* index table base */
       
   885 eit_limit  dcd |.ARM.exidx$$Limit| - __ARM_ETInfo; /* index table limit */
       
   886 #endif
       
   887 }
       
   888 
       
   889 
       
   890 /* __ARM_Unwind_RaiseException performs phase 1 unwinding */
       
   891 
       
   892 _Unwind_Reason_Code __ARM_Unwind_RaiseException(_Unwind_Control_Block *ucbp,
       
   893                                                 phase2_virtual_register_set *entry_VRSp)
       
   894 {
       
   895   phase1_virtual_register_set phase1_VRS;
       
   896 
       
   897   /* Is this a nested simultaneous propagation?
       
   898    * (see comments with _Unwind_Complete)
       
   899    */
       
   900   if (ucbp->NESTED_CONTEXT == 0) {
       
   901     /* No - this is only propagation */
       
   902     ucbp->NESTED_CONTEXT = 1;
       
   903   } else {
       
   904 #ifdef SUPPORT_NESTED_EXCEPTIONS
       
   905     /* Yes - cache the state elsewhere and restore it when the propagation ends */
       
   906     /* This representation wastes space and uses malloc; do better?
       
   907      * On the other hand will it ever be used in practice?
       
   908      */
       
   909     _Unwind_Control_Block *saved_ucbp = AllocSavedUCB();
       
   910     if (ucbp == NULL) {
       
   911       DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_UNWINDER_BUFFERFAILED);
       
   912       return _URC_FAILURE;
       
   913     }
       
   914     saved_ucbp->unwinder_cache = ucbp->unwinder_cache;
       
   915     saved_ucbp->barrier_cache = ucbp->barrier_cache;
       
   916     saved_ucbp->cleanup_cache = ucbp->cleanup_cache;
       
   917     ucbp->NESTED_CONTEXT = (uint32_t)saved_ucbp;
       
   918 #else
       
   919     abort();
       
   920 #endif
       
   921   }
       
   922 
       
   923   /* entry_VRSp contains the core registers as they were when
       
   924    * _Unwind_RaiseException was called.  Copy the call-site address to r15
       
   925    * then copy all the registers to phase1_VRS for the phase 1 stack scan.
       
   926    */
       
   927 
       
   928   entry_VRSp->core.r[15] = entry_VRSp->core.r[14];
       
   929   phase1_VRS.core = entry_VRSp->core;
       
   930 
       
   931   /* For phase 1 only ensure non-core registers are saved before use.
       
   932    * If WMMX registers are supported, initialise their flags here and
       
   933    * take appropriate action elsewhere.
       
   934    */
       
   935 
       
   936   phase1_VRS.demand_save_vfp_low = 1;
       
   937   phase1_VRS.demand_save_vfp_high = 1;
       
   938 #ifdef __EPOC32__
       
   939   /* Set up Symbian specific caches in the _Unwind_Control_Block's 
       
   940      unwinder_cache. 
       
   941   */
       
   942   InitialiseSymbianSpecificUnwinderCache(phase1_VRS.core.r[15], ucbp);
       
   943 #endif
       
   944 
       
   945 
       
   946   /* Now perform a virtual unwind until a propagation barrier is met, or
       
   947    * until something goes wrong.  If something does go wrong, we ought (I
       
   948    * suppose) to restore registers we may have destroyed.
       
   949    */
       
   950 
       
   951   while (1) {
       
   952 
       
   953     _Unwind_Reason_Code pr_result;
       
   954 
       
   955     /* Search the index table for the required entry.  Cache the index table
       
   956      * pointer, and obtain and cache the addresses of the "real" __EHT_Header
       
   957      * word and the personality routine.
       
   958      */
       
   959 
       
   960     if (find_and_expand_eit_entry(ucbp, phase1_VRS.core.r[15]) != _URC_OK) {
       
   961       restore_non_core_regs(&phase1_VRS);
       
   962       /* Debugger bottleneck fn called during lookup */
       
   963       return _URC_FAILURE;
       
   964     }
       
   965 
       
   966     /* Call the pr to decide what to do */
       
   967 
       
   968     pr_result = ((personality_routine)ucbp->PR_ADDR)(_US_VIRTUAL_UNWIND_FRAME,
       
   969                                                      ucbp,
       
   970                                                      (_Unwind_Context *)&phase1_VRS);
       
   971 
       
   972     if (pr_result == _URC_HANDLER_FOUND) break;
       
   973     if (pr_result == _URC_CONTINUE_UNWIND) continue;
       
   974 
       
   975     /* If we get here some sort of failure has occurred in the
       
   976      * pr and probably the pr returned _URC_FAILURE
       
   977      */
       
   978     restore_non_core_regs(&phase1_VRS);
       
   979     return _URC_FAILURE;
       
   980   }
       
   981 
       
   982   /* Propagation barrier located... restore entry register state of non-core regs */
       
   983 
       
   984   restore_non_core_regs(&phase1_VRS);
       
   985 
       
   986   /* Initiate real unwinding */
       
   987   unwind_next_frame(ucbp, entry_VRSp);
       
   988   /* Unreached, but keep compiler quiet: */
       
   989   return _URC_FAILURE;
       
   990 }
       
   991 
       
   992 
       
   993 /* unwind_next_frame performs phase 2 unwinding */
       
   994 
       
   995 static NORETURNDECL void unwind_next_frame(_Unwind_Control_Block *ucbp, phase2_virtual_register_set *vrsp)
       
   996 {
       
   997   while (1) {
       
   998 
       
   999     _Unwind_Reason_Code pr_result;
       
  1000 
       
  1001     /* Search the index table for the required entry.  Cache the index table
       
  1002      * pointer, and obtain and cache the addresses of the "real" __EHT_Header
       
  1003      * word and the personality routine.
       
  1004      */
       
  1005 
       
  1006     if (find_and_expand_eit_entry(ucbp, vrsp->core.r[15]) != _URC_OK)
       
  1007       abort();
       
  1008 
       
  1009     /* Save the call-site address and call the pr to do whatever it
       
  1010      * wants to do on this new frame.
       
  1011      */
       
  1012 
       
  1013     ucbp->SAVED_CALLSITE_ADDR = vrsp->core.r[15];
       
  1014     pr_result = ((personality_routine)ucbp->PR_ADDR)(_US_UNWIND_FRAME_STARTING, ucbp,
       
  1015                                                      (_Unwind_Context *)vrsp);
       
  1016 
       
  1017     if (pr_result == _URC_INSTALL_CONTEXT) {
       
  1018       /* Upload the registers */
       
  1019       __ARM_Unwind_VRS_corerestore(&vrsp->core);
       
  1020     } else if (pr_result == _URC_CONTINUE_UNWIND)
       
  1021       continue;
       
  1022     else
       
  1023       abort();
       
  1024   }
       
  1025 }
       
  1026 
       
  1027 
       
  1028 /* _Unwind_Resume is the external entry point called after a cleanup
       
  1029  * to resume unwinding. It tail-calls a helper function,
       
  1030  * __ARM_Unwind_Resume, which never returns.
       
  1031  */
       
  1032 __asm NORETURNDECL void _Unwind_Resume(_Unwind_Control_Block *ucbp)
       
  1033 {
       
  1034   extern __ARM_Unwind_Resume;
       
  1035 
       
  1036 #if THUMBNAIL
       
  1037 
       
  1038   /* Create a phase2_virtual_register_set on the stack */
       
  1039   /* Save the core registers, carefully writing the original sp value */
       
  1040   /* Note we account for the pc but do not actually write it's value here */
       
  1041   str.w    r14,[sp, #-8]!;
       
  1042   add.w    r14, r13, #8;
       
  1043   str.w    r14,[sp, #-4]!    /* pushed 3 words => 3 words */
       
  1044   stmfd.w  sp!,{r0-r12};     /* pushed 13 words => 16 words */
       
  1045   /* Write zeroes for the demand_save bytes so no saving occurs in phase 2 */
       
  1046   mov.w    r1,#0;
       
  1047   str.w    r1,[sp,#-4]!;     /* pushed 1 word => 17 words */
       
  1048   mov.w    r1,sp;
       
  1049   sub.w    sp,sp,#4;         /* preserve 8 byte alignment => 18 words */
       
  1050 
       
  1051   /* Now pass to C (with r0 still valid) to do the real work.
       
  1052    * r0 = ucbp, r1 = phase2_virtual_register_set.
       
  1053    * This call never returns.
       
  1054    */
       
  1055 
       
  1056   mov      pc,r2
       
  1057 
       
  1058 #else
       
  1059 
       
  1060   MAYBE_SWITCH_TO_ARM_STATE;
       
  1061 
       
  1062   /* Create a phase2_virtual_register_set on the stack */
       
  1063   /* Save the core registers, carefully writing the original sp value */
       
  1064 
       
  1065   #if __ARMCC_VERSION < 300000
       
  1066   stmfd sp!,{r13-r15};  /* pushed 3 words => 3 words */
       
  1067   #else
       
  1068   stmdb r13, {r14,r15};
       
  1069   str r13, [r13,#-3*4];
       
  1070   sub r13, r13, #3*4;
       
  1071   #endif
       
  1072 
       
  1073   stmfd sp!,{r0-r12};   /* pushed 13 words => 16 words */
       
  1074   /* Write zeroes for the demand_save bytes so no saving occurs in phase 2 */
       
  1075   mov r1,#0;
       
  1076   str r1,[sp,#-4]!;     /* pushed 1 word => 17 words */
       
  1077   mov r1,sp;
       
  1078   sub sp,sp,#4;         /* preserve 8 byte alignment => 18 words */
       
  1079 
       
  1080   /* Now pass to C (with r0 still valid) to do the real work.
       
  1081    * r0 = ucbp, r1 = phase2_virtual_register_set.
       
  1082    * This call never returns.
       
  1083    */
       
  1084 
       
  1085 #ifdef __APCS_INTERWORK
       
  1086   ldr r2,Unwind_Resume_Offset;
       
  1087   add r2,r2,pc;
       
  1088   bx    r2;
       
  1089 Unwind_Resume_Offset dcd __ARM_Unwind_Resume - .;
       
  1090 #else
       
  1091   b __ARM_Unwind_Resume;
       
  1092 #endif
       
  1093   MAYBE_CODE16;
       
  1094 
       
  1095 #endif
       
  1096 }
       
  1097 
       
  1098 
       
  1099 /* Helper function for _Unwind_Resume */
       
  1100 
       
  1101 NORETURNDECL void __ARM_Unwind_Resume(_Unwind_Control_Block *ucbp,
       
  1102                                   phase2_virtual_register_set *entry_VRSp)
       
  1103 {
       
  1104   _Unwind_Reason_Code pr_result;
       
  1105 
       
  1106   /* Recover saved state */
       
  1107 
       
  1108   entry_VRSp->core.r[15] = ucbp->SAVED_CALLSITE_ADDR;
       
  1109 
       
  1110   /* Call the cached PR and dispatch */
       
  1111 
       
  1112   pr_result = ((personality_routine)ucbp->PR_ADDR)(_US_UNWIND_FRAME_RESUME, ucbp,
       
  1113                                                    (_Unwind_Context *)entry_VRSp);
       
  1114 
       
  1115   if (pr_result == _URC_INSTALL_CONTEXT) {
       
  1116    /* Upload the registers */
       
  1117     __ARM_Unwind_VRS_corerestore(&entry_VRSp->core);
       
  1118   } else if (pr_result == _URC_CONTINUE_UNWIND)
       
  1119     unwind_next_frame(ucbp, entry_VRSp);
       
  1120   else
       
  1121     abort();
       
  1122 }
       
  1123 
       
  1124 
       
  1125 /* _Unwind_Complete is called at the end of a propagation.
       
  1126  * If we support multiple simultaneous propagations, restore the cached state
       
  1127  * of the previous propagation here.
       
  1128  */
       
  1129 
       
  1130 void _Unwind_Complete(_Unwind_Control_Block *ucbp)
       
  1131 {
       
  1132   _Unwind_Control_Block *context = (_Unwind_Control_Block *)ucbp->NESTED_CONTEXT;
       
  1133   if ((uint32_t)context == 0) abort();  /* should be impossible */
       
  1134   if ((uint32_t)context == 1) {
       
  1135     /* This was the only ongoing propagation of this object */
       
  1136     ucbp->NESTED_CONTEXT--;
       
  1137     return;
       
  1138   }
       
  1139 #ifdef SUPPORT_NESTED_EXCEPTIONS
       
  1140   /* Otherwise we copy the state back from the cache structure pointed to
       
  1141    * by ucbp->NESTED_CONTEXT.
       
  1142    */
       
  1143   /* This first one updates ucbp->NESTED_CONTEXT */
       
  1144   ucbp->unwinder_cache = context->unwinder_cache;
       
  1145   ucbp->barrier_cache = context->barrier_cache;
       
  1146   ucbp->cleanup_cache = context->cleanup_cache;
       
  1147   FreeSavedUCB(context);
       
  1148 #else
       
  1149   abort();
       
  1150 #endif
       
  1151 }
       
  1152 
       
  1153 /* _Unwind_DeleteException can be used to invoke the exception_cleanup
       
  1154  * function after catching a foreign exception.
       
  1155  */
       
  1156 
       
  1157 void _Unwind_DeleteException(_Unwind_Control_Block *ucbp)
       
  1158 {
       
  1159   if (ucbp->exception_cleanup != NULL)
       
  1160     (ucbp->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, ucbp);
       
  1161 }
       
  1162 
       
  1163 #endif /* unwinder_c */
       
  1164 #ifdef unwind_activity_c
       
  1165 
       
  1166 /* Runtime debug "bottleneck function": */
       
  1167 /* (not in the current Exceptions EABI document) */
       
  1168 
       
  1169 void _Unwind_Activity(_Unwind_Control_Block *ucbp, uint32_t reason, uint32_t arg)
       
  1170 {
       
  1171 #ifdef UNWIND_ACTIVITY_DIAGNOSTICS
       
  1172   uint32_t who = reason >> 24;
       
  1173   uint32_t activity = reason & 0xffffff;
       
  1174   printf("_Unwind_Activity: UCB=0x%8.8x Reason=(", (uint32_t)ucbp);
       
  1175   switch (who) {
       
  1176   case _UASUBSYS_UNWINDER:
       
  1177     printf("unw,");
       
  1178     if (activity >= 0x80)
       
  1179       printf("%x) Arg=0x%8.8x\n", activity, arg);
       
  1180     break;
       
  1181   case _UASUBSYS_CPP:
       
  1182     printf("C++,");
       
  1183     if (activity >= 0x80) {
       
  1184       if (activity == _UAACT_CPP_TYPEINFO)
       
  1185         printf("typeinfo) Typeinfo=0x%8.8x\n", arg);
       
  1186       else
       
  1187         printf("%x) Arg=0x%8.8x\n", activity, arg);
       
  1188     }
       
  1189     break;
       
  1190   default:
       
  1191     printf("???,");
       
  1192     if (activity >= 0x80)
       
  1193       printf("%x) Arg=0x%8.8x\n", activity, arg);
       
  1194     break;
       
  1195   }
       
  1196   if (activity < 0x80) {
       
  1197     switch (activity) {
       
  1198     case _UAACT_STARTING:
       
  1199       printf("starting) Typeinfo=0x%8.8x\n", arg);
       
  1200       break;
       
  1201     case _UAACT_ENDING:
       
  1202       printf("ending) Cause=%d\n", arg);
       
  1203       break;
       
  1204     case _UAACT_BARRIERFOUND:
       
  1205       printf("barrierfound) Pad=0x%8.8x\n", arg);
       
  1206       break;
       
  1207     case _UAACT_PADENTRY:
       
  1208       printf("padentry) Pad=0x%8.8x\n", arg);
       
  1209       break;
       
  1210     default:
       
  1211       printf("%x) Arg=0x%8.8x\n", activity, arg);
       
  1212       break;
       
  1213     }
       
  1214   }
       
  1215 #endif
       
  1216 }
       
  1217 
       
  1218 #endif /* unwind_activity_c */