|         |      1 /* unwinder.c | 
|         |      2  * | 
|         |      3  * Copyright 2002-2003 ARM Limited. | 
|         |      4  */ | 
|         |      5 /* | 
|         |      6   Licence | 
|         |      7  | 
|         |      8   1. Subject to the provisions of clause 2, ARM hereby grants to LICENSEE a | 
|         |      9   perpetual, non-exclusive, nontransferable, royalty free, worldwide licence | 
|         |     10   to use this Example Implementation of Exception Handling solely for the | 
|         |     11   purpose of developing, having developed, manufacturing, having | 
|         |     12   manufactured, offering to sell, selling, supplying or otherwise | 
|         |     13   distributing products which comply with the Exception Handling ABI for the | 
|         |     14   ARM Architecture specification. All other rights are reserved to ARM or its | 
|         |     15   licensors. | 
|         |     16  | 
|         |     17   2. THIS EXAMPLE IMPLEMENTATION OF EXCEPTION HANDLING  IS PROVIDED "AS IS" | 
|         |     18   WITH NO WARRANTIES EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED | 
|         |     19   TO ANY WARRANTY OF SATISFACTORY QUALITY, MERCHANTABILITY, NONINFRINGEMENT | 
|         |     20   OR FITNESS FOR A PARTICULAR PURPOSE. | 
|         |     21 */ | 
|         |     22 /* | 
|         |     23  * RCS $Revision: 1.16 $ | 
|         |     24  * Checkin $Date: 2003/10/23 13:57:39 $ | 
|         |     25  * Revising $Author: agrant $ | 
|         |     26  */ | 
|         |     27  | 
|         |     28 /* Language-independent unwinder implementation */ | 
|         |     29  | 
|         |     30 /* This source file is compiled automatically by ARM's make system into | 
|         |     31  * multiple object files. The source regions constituting object file | 
|         |     32  * xxx.o are delimited by ifdef xxx_c / endif directives. | 
|         |     33  * | 
|         |     34  * The source regions currently marked are: | 
|         |     35  * unwinder_c | 
|         |     36  * unwind_activity_c | 
|         |     37  */ | 
|         |     38  | 
|         |     39 #include <stddef.h> | 
|         |     40 #include <stdlib.h> | 
|         |     41 /* Environment: */ | 
|         |     42 #include "unwind_env.h" | 
|         |     43 /* Language-independent unwinder declarations: */ | 
|         |     44 #include "unwinder.h" | 
|         |     45  | 
|         |     46 /* Define UNWIND_ACTIVITY_DIAGNOSTICS for printed information from _Unwind_Activity */ | 
|         |     47 /* Define VRS_DIAGNOSTICS for printed diagnostics about VRS operations */ | 
|         |     48  | 
|         |     49 #if defined(VRS_DIAGNOSTICS) || defined(UNWIND_ACTIVITY_DIAGNOSTICS) | 
|         |     50 extern int printf(const char *, ...); | 
|         |     51 #endif | 
|         |     52  | 
|         |     53  | 
|         |     54 #ifdef unwinder_c | 
|         |     55  | 
|         |     56 /* =========================                      ========================= */ | 
|         |     57 /* ========================= Virtual register set ========================= */ | 
|         |     58 /* =========================                      ========================= */ | 
|         |     59  | 
|         |     60 /* The approach taken by this implementation is to use the real machine | 
|         |     61  * registers to hold all but the values of core (integer) | 
|         |     62  * registers. Consequently the implementation must use only the core | 
|         |     63  * registers except when manipulating the virtual register set. Non-core | 
|         |     64  * registers are saved only on first use, so the single implementation can | 
|         |     65  * cope with execution on processors which lack certain registers.  The | 
|         |     66  * registers as they were at the start of the propagation must be preserved | 
|         |     67  * over phase 1 so that the machine state is correct at the start of phase | 
|         |     68  * 2. This requires a copy to be taken (which can be stack allocated). During | 
|         |     69  * a stack unwind (phase 1 or phase 2), the "current" virtual register set is | 
|         |     70  * implemented as core register values held in a data structure, and non-core | 
|         |     71  * register values held in the registers themselves. To ensure that all | 
|         |     72  * original register values are available at the beginning of phase 2, the | 
|         |     73  * core registers are saved in a second structure at the start of phase 1 and | 
|         |     74  * the non-core registers are demand-saved into another part of the data | 
|         |     75  * structure that holds the current core registers during the phase 1 stack | 
|         |     76  * unwind. | 
|         |     77  */ | 
|         |     78 /* Extent to which the access routines are implemented: | 
|         |     79  * _Unwind_VRS_Get and _Unwind_VRS_Set implement only access to the core registers. | 
|         |     80  * _Unwind_VRS_Pop implements only popping of core, vfp and fpa registers. | 
|         |     81  * There is no support here for the Intel WMMX registers, but space is nevertheless | 
|         |     82  * reserved in the virtual register set structure to indicate whether demand-saving | 
|         |     83  * of those registers is required (as they are unsupported, it never is). The space | 
|         |     84  * costs nothing as it is required for alignment. | 
|         |     85  * The level of supported functionality is compliant with the requirements of the | 
|         |     86  * Exceptions ABI. | 
|         |     87  */ | 
|         |     88  | 
|         |     89 typedef unsigned char bool; | 
|         |     90 struct core_s  { uint32_t r[16]; };        /* core integer regs */ | 
|         |     91 struct vfp_s   { uint64_t vfp[16+1]; };    /* VFP registers saved in FSTMX format */ | 
|         |     92                                            /* Extra 2 words for the format word + unused  */ | 
|         |     93 struct fpa_reg { uint32_t word[3]; }; | 
|         |     94 struct fpa_s   { struct fpa_reg fpa[8]; }; /* FPA registers saved in SFM format */ | 
|         |     95  | 
|         |     96 /* Phase 1 virtual register set includes demand-save areas */ | 
|         |     97 /* The phase 2 virtual register set must be a prefix of the phase 1 set */ | 
|         |     98 typedef struct phase1_virtual_register_set_s { | 
|         |     99   /* demand_save flag == 1 means save the registers in the demand-save area */ | 
|         |    100   bool demand_save_vfp; | 
|         |    101   bool demand_save_fpa; | 
|         |    102   bool demand_save_wmmxd; | 
|         |    103   bool demand_save_wmmxc; | 
|         |    104   struct core_s core;      /* current core registers */ | 
|         |    105   struct vfp_s  vfp;       /* demand-saved vfp registers */ | 
|         |    106   struct fpa_s  fpa;       /* demand-saved fpa 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; | 
|         |    118   bool demand_save_fpa; | 
|         |    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) || defined(__TARGET_ARCH_5TE) || \ | 
|         |    127     defined(__TARGET_ARCH_6)  /* || ... */ | 
|         |    128   #define ARCH_5T_OR_LATER 1 | 
|         |    129 #else | 
|         |    130   #define ARCH_5T_OR_LATER 0 | 
|         |    131 #endif | 
|         |    132  | 
|         |    133 #if defined(__APCS_INTERWORK) && !ARCH_5T_OR_LATER | 
|         |    134   #define OLD_STYLE_INTERWORKING 1 | 
|         |    135 #else | 
|         |    136   #define OLD_STYLE_INTERWORKING 0 | 
|         |    137 #endif | 
|         |    138  | 
|         |    139 #if defined(__TARGET_ARCH_4T) || defined(__TARGET_ARCH_4TXM) || ARCH_5T_OR_LATER | 
|         |    140   #define HAVE_BX 1 | 
|         |    141 #else | 
|         |    142   #define HAVE_BX 0 | 
|         |    143 #endif | 
|         |    144  | 
|         |    145 #if HAVE_BX | 
|         |    146   #define RET_LR bx lr | 
|         |    147 #else | 
|         |    148   #define RET_LR mov pc,lr | 
|         |    149 #endif | 
|         |    150  | 
|         |    151 /* ----- Routines: ----- */ | 
|         |    152  | 
|         |    153 /* ----- Helper routines, private but external ----- */ | 
|         |    154 /* Note '%0' refers to local label '0' */ | 
|         |    155  | 
|         |    156 __asm void __ARM_Unwind_VRS_VFPpreserve(void *vfpp) | 
|         |    157 { | 
|         |    158   /* Preserve the vfp registers in the passed memory */ | 
|         |    159 #ifdef __thumb | 
|         |    160   #define MAYBE_SWITCH_TO_ARM_STATE SWITCH_TO_ARM_STATE | 
|         |    161   #define MAYBE_CODE16 code16 | 
|         |    162   macro; | 
|         |    163   SWITCH_TO_ARM_STATE; | 
|         |    164 1 | 
|         |    165   align 4; | 
|         |    166 2 | 
|         |    167   assert (%2 - %1) = 0; | 
|         |    168   bx pc; | 
|         |    169   nop; | 
|         |    170   code32; | 
|         |    171   mend; | 
|         |    172 #else | 
|         |    173   #define MAYBE_SWITCH_TO_ARM_STATE /* nothing */ | 
|         |    174   #define MAYBE_CODE16 /* nothing */ | 
|         |    175 #endif | 
|         |    176  | 
|         |    177 vfp_d0 CN 0; | 
|         |    178   MAYBE_SWITCH_TO_ARM_STATE; | 
|         |    179   stc   p11,vfp_d0,[r0],{0x21};  /* 0xec800b21  FSTMIAX r0,{d0-d15} */ | 
|         |    180   RET_LR; | 
|         |    181   MAYBE_CODE16; | 
|         |    182 } | 
|         |    183  | 
|         |    184 __asm void __ARM_Unwind_VRS_VFPrestore(void *vfpp) | 
|         |    185 { | 
|         |    186   /* Restore the vfp registers from the passed memory */ | 
|         |    187 vfp_d0 CN 0; | 
|         |    188   MAYBE_SWITCH_TO_ARM_STATE; | 
|         |    189   ldc   p11,vfp_d0,[r0],{0x21};  /* 0xec900b21  FLDMIAX r0,{d0-d15} */ | 
|         |    190   RET_LR; | 
|         |    191   MAYBE_CODE16; | 
|         |    192 } | 
|         |    193  | 
|         |    194 __asm void __ARM_Unwind_VRS_FPApreserve(void *vfpp) | 
|         |    195 { | 
|         |    196   /* Preserve the fpa registers in the passed memory */ | 
|         |    197 fpa_f0 CN 0; | 
|         |    198 fpa_f4 CN 0; | 
|         |    199   MAYBE_SWITCH_TO_ARM_STATE; | 
|         |    200   stc   p2, fpa_f0, [r0];       /* 0xed800200  SFM f0,4,[r0,#0]    */ | 
|         |    201   stc   p2, fpa_f4, [r0, #48];  /* 0xed80420c  SFM f4,4,[r0,#0x30] */ | 
|         |    202   RET_LR; | 
|         |    203   MAYBE_CODE16; | 
|         |    204 } | 
|         |    205  | 
|         |    206 __asm void __ARM_Unwind_VRS_FPArestore(void *vfpp) | 
|         |    207 { | 
|         |    208   /* Restore the fpa registers from the passed memory */ | 
|         |    209 fpa_f0 CN 0; | 
|         |    210 fpa_f4 CN 0; | 
|         |    211   MAYBE_SWITCH_TO_ARM_STATE; | 
|         |    212   ldc   p2, fpa_f0, [r0];       /* 0xed900200  LFM f0,4,[r0,#0]    */ | 
|         |    213   ldc   p2, fpa_f4, [r0, #48];  /* 0xed90020c  LFM f4,4,[r0,#0x30] */ | 
|         |    214   RET_LR; | 
|         |    215   MAYBE_CODE16; | 
|         |    216 } | 
|         |    217  | 
|         |    218 __asm NORETURNDECL void __ARM_Unwind_VRS_corerestore(void *corep) | 
|         |    219 { | 
|         |    220   /* By hypothesis this is preserve8 but the load of sp means the | 
|         |    221    * assembler can't infer that. | 
|         |    222    */ | 
|         |    223   preserve8; | 
|         |    224   MAYBE_SWITCH_TO_ARM_STATE; | 
|         |    225 #if OLD_STYLE_INTERWORKING | 
|         |    226   mov r14, r0; | 
|         |    227   ldmia r14!,{r0-r12}; | 
|         |    228   ldr   r12,[r14, #4*2]; /* pc */ | 
|         |    229   ldmia r14,{r13-r14}; | 
|         |    230   bx    r12; | 
|         |    231 #else | 
|         |    232   ldmia r0,{r0-r15}; | 
|         |    233 #endif | 
|         |    234   MAYBE_CODE16; | 
|         |    235 } | 
|         |    236  | 
|         |    237  | 
|         |    238 /* ----- Development support ----- */ | 
|         |    239  | 
|         |    240 #ifdef VRS_DIAGNOSTICS | 
|         |    241 static void debug_print_vrs_vfp(struct vfp_s *vfpp) | 
|         |    242 { | 
|         |    243   uint64_t *lp = (uint64_t *)vfpp; | 
|         |    244   int c = 0; | 
|         |    245   int i; | 
|         |    246   for (i = 0; i < 16; i++) { | 
|         |    247     printf("D%-2d  0x%16.16llx    ", i, *lp); | 
|         |    248     lp++; | 
|         |    249     if (c++ == 1) { | 
|         |    250       c = 0; | 
|         |    251       printf("\n"); | 
|         |    252     } | 
|         |    253   } | 
|         |    254 } | 
|         |    255  | 
|         |    256 static void debug_print_vrs_fpa(struct fpa_s *fpap) | 
|         |    257 { | 
|         |    258   uint32_t *lp = (uint32_t *)fpap; | 
|         |    259   int c = 0; | 
|         |    260   int i; | 
|         |    261   for (i = 0; i < 8; i++) { | 
|         |    262     printf("F%-2d  0x%8.8x%8.8x%8.8x    ", i, *lp, *(lp+1), *(lp+2)); | 
|         |    263     lp+=3; | 
|         |    264     if (c++ == 1) { | 
|         |    265       c = 0; | 
|         |    266       printf("\n"); | 
|         |    267     } | 
|         |    268   } | 
|         |    269 } | 
|         |    270  | 
|         |    271 static void debug_print_vrs(_Unwind_Context *context) | 
|         |    272 { | 
|         |    273   phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context; | 
|         |    274   int i; | 
|         |    275   int c; | 
|         |    276   printf("------------------------------------------------------------------------\n"); | 
|         |    277   c = 0; | 
|         |    278   for (i = 0; i < 16; i++) { | 
|         |    279     printf("r%-2d  0x%8.8x    ", i, vrsp->core.r[i]); | 
|         |    280     if (c++ == 3) { | 
|         |    281       c = 0; | 
|         |    282       printf("\n"); | 
|         |    283     } | 
|         |    284   } | 
|         |    285  | 
|         |    286   printf("-----\n"); | 
|         |    287   if (vrsp->demand_save_vfp == 1) | 
|         |    288     printf("VFP is not saved\n"); | 
|         |    289   else | 
|         |    290     debug_print_vrs_vfp(&vrsp->vfp); | 
|         |    291   printf("-----\n"); | 
|         |    292   if (vrsp->demand_save_fpa == 1) | 
|         |    293     printf("FPA is not saved\n"); | 
|         |    294   else | 
|         |    295     debug_print_vrs_fpa(&vrsp->fpa); | 
|         |    296   printf("------------------------------------------------------------------------\n"); | 
|         |    297 } | 
|         |    298 #endif | 
|         |    299  | 
|         |    300  | 
|         |    301 /* ----- Public routines ----- */ | 
|         |    302  | 
|         |    303 _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context, | 
|         |    304                                    _Unwind_VRS_RegClass regclass, | 
|         |    305                                    uint32_t regno, | 
|         |    306                                    _Unwind_VRS_DataRepresentation representation, | 
|         |    307                                    void *valuep) | 
|         |    308 { | 
|         |    309   phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context; | 
|         |    310   switch (regclass) { | 
|         |    311   case _UVRSC_CORE: | 
|         |    312     { | 
|         |    313       if (representation != _UVRSD_UINT32 || regno > 15) | 
|         |    314         return _UVRSR_FAILED; | 
|         |    315        vrsp->core.r[regno] = *(uint32_t *)valuep; | 
|         |    316        return _UVRSR_OK; | 
|         |    317     } | 
|         |    318   case _UVRSC_VFP: | 
|         |    319   case _UVRSC_FPA: | 
|         |    320   case _UVRSC_WMMXD: | 
|         |    321   case _UVRSC_WMMXC: | 
|         |    322     return _UVRSR_NOT_IMPLEMENTED; | 
|         |    323   default: | 
|         |    324     break; | 
|         |    325   } | 
|         |    326   return _UVRSR_FAILED; | 
|         |    327 } | 
|         |    328  | 
|         |    329  | 
|         |    330 _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context, | 
|         |    331                                    _Unwind_VRS_RegClass regclass, | 
|         |    332                                    uint32_t regno, | 
|         |    333                                    _Unwind_VRS_DataRepresentation representation, | 
|         |    334                                    void *valuep) | 
|         |    335 { | 
|         |    336   phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context; | 
|         |    337   switch (regclass) { | 
|         |    338   case _UVRSC_CORE: | 
|         |    339     { | 
|         |    340       if (representation != _UVRSD_UINT32 || regno > 15) | 
|         |    341         return _UVRSR_FAILED; | 
|         |    342       *(uint32_t *)valuep = vrsp->core.r[regno]; | 
|         |    343       return _UVRSR_OK; | 
|         |    344     } | 
|         |    345   case _UVRSC_VFP: | 
|         |    346   case _UVRSC_FPA: | 
|         |    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 #define R_SP 13 | 
|         |    358  | 
|         |    359 _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *context, | 
|         |    360                                    _Unwind_VRS_RegClass regclass, | 
|         |    361                                    uint32_t descriminator, | 
|         |    362                                    _Unwind_VRS_DataRepresentation representation) | 
|         |    363 { | 
|         |    364   phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context; | 
|         |    365   switch (regclass) { | 
|         |    366   case _UVRSC_CORE: | 
|         |    367     { | 
|         |    368       /* If SP is included in the mask, the loaded value is used in preference to | 
|         |    369        * the writeback value, but only on completion of the loading. | 
|         |    370        */ | 
|         |    371       uint32_t mask, *vsp, *rp, sp_loaded; | 
|         |    372       if (representation != _UVRSD_UINT32) | 
|         |    373         return _UVRSR_FAILED; | 
|         |    374       vsp = (uint32_t *)vrsp->core.r[R_SP]; | 
|         |    375       rp = (uint32_t *)&vrsp->core; | 
|         |    376       mask = descriminator & 0xffff; | 
|         |    377       sp_loaded = mask & (1 << R_SP); | 
|         |    378       while (mask != 0) { | 
|         |    379         if (mask & 1) { | 
|         |    380 #ifdef VRS_DIAGNOSTICS | 
|         |    381           printf("VRS Pop r%d\n", rp - &vrsp->core.r[0]); | 
|         |    382 #endif | 
|         |    383           *rp = *vsp++; | 
|         |    384         } | 
|         |    385         rp++; | 
|         |    386         mask >>= 1; | 
|         |    387       } | 
|         |    388       if (!sp_loaded) | 
|         |    389         vrsp->core.r[R_SP] = (uint32_t)vsp; | 
|         |    390       return _UVRSR_OK; | 
|         |    391     } | 
|         |    392   case _UVRSC_VFP: | 
|         |    393     { | 
|         |    394       uint32_t start = descriminator >> 16; | 
|         |    395       uint32_t count = descriminator & 0xffff; | 
|         |    396       if (representation != _UVRSD_VFPX || start + count > 16) | 
|         |    397         return _UVRSR_FAILED; | 
|         |    398       if (vrsp->demand_save_vfp == 1) { /* Demand-save over phase 1 */ | 
|         |    399        vrsp->demand_save_vfp = 0; | 
|         |    400        __ARM_Unwind_VRS_VFPpreserve(&vrsp->vfp); | 
|         |    401       } | 
|         |    402       /* Now recover from the stack into the real machine registers. | 
|         |    403        * Note we assume FSTMX standard format 1. | 
|         |    404        * Do this by saving the current VFP registers to a memory area, | 
|         |    405        * moving the in-memory values over that area, and | 
|         |    406        * restoring from the whole area. | 
|         |    407        */ | 
|         |    408       { | 
|         |    409         struct vfp_s temp_vfp; | 
|         |    410         uint64_t *vsp; | 
|         |    411         __ARM_Unwind_VRS_VFPpreserve(&temp_vfp); | 
|         |    412         vsp = (uint64_t *)vrsp->core.r[R_SP]; | 
|         |    413         while (count--) { | 
|         |    414 #ifdef VRS_DIAGNOSTICS | 
|         |    415           printf("VRS Pop D%d = 0x%llx\n", start, *vsp); | 
|         |    416 #endif | 
|         |    417           temp_vfp.vfp[start++] = *vsp++; | 
|         |    418         } | 
|         |    419         vrsp->core.r[R_SP] = (uint32_t)((uint32_t *)vsp + 1); /* +1 to skip the format word */ | 
|         |    420         __ARM_Unwind_VRS_VFPrestore(&temp_vfp); | 
|         |    421       } | 
|         |    422       return _UVRSR_OK; | 
|         |    423     } | 
|         |    424   case _UVRSC_FPA: | 
|         |    425     { | 
|         |    426       uint32_t start = descriminator >> 16; | 
|         |    427       uint32_t count = descriminator & 0xffff; | 
|         |    428       if (representation != _UVRSD_FPAX || start > 7 || count > 4) | 
|         |    429         return _UVRSR_FAILED; | 
|         |    430       if (vrsp->demand_save_fpa == 1) { /* Demand-save over phase 1 */ | 
|         |    431         vrsp->demand_save_fpa = 0; | 
|         |    432         __ARM_Unwind_VRS_FPApreserve(&vrsp->fpa); | 
|         |    433       } | 
|         |    434       /* Now recover from the stack into the real machine registers. | 
|         |    435        * Do this by saving the current FPA registers to a memory area, | 
|         |    436        * moving the in-memory values over that area, and | 
|         |    437        * restoring from the whole area. | 
|         |    438        * Unlike VFP, here the range is allowed to wrap round. | 
|         |    439        */ | 
|         |    440       { | 
|         |    441         struct fpa_s temp_fpa; | 
|         |    442         struct fpa_reg *vsp; | 
|         |    443         __ARM_Unwind_VRS_FPApreserve(&temp_fpa); | 
|         |    444         vsp = (struct fpa_reg *)vrsp->core.r[R_SP]; | 
|         |    445         while (count--) { | 
|         |    446 #ifdef VRS_DIAGNOSTICS | 
|         |    447           printf("VRS Pop F%d = 0x%-8.8x%-8.8x%-8.8x\n", start, *(uint32_t *)vsp, | 
|         |    448                  *((uint32_t *)vsp + 1), *((uint32_t *)vsp + 2)); | 
|         |    449 #endif | 
|         |    450           temp_fpa.fpa[start++] = *vsp++; | 
|         |    451           start &= 7; | 
|         |    452         } | 
|         |    453         vrsp->core.r[R_SP] = (uint32_t)vsp; | 
|         |    454         __ARM_Unwind_VRS_FPArestore(&temp_fpa); | 
|         |    455       } | 
|         |    456       return _UVRSR_OK; | 
|         |    457     } | 
|         |    458   case _UVRSC_WMMXD: | 
|         |    459   case _UVRSC_WMMXC: | 
|         |    460     return _UVRSR_NOT_IMPLEMENTED; | 
|         |    461   default: | 
|         |    462     break; | 
|         |    463   } | 
|         |    464   return _UVRSR_FAILED; | 
|         |    465 } | 
|         |    466  | 
|         |    467  | 
|         |    468  | 
|         |    469 /* =========================              ========================= */ | 
|         |    470 /* ========================= The unwinder ========================= */ | 
|         |    471 /* =========================              ========================= */ | 
|         |    472  | 
|         |    473  | 
|         |    474 /* This implementation uses the UCB unwinder_cache as follows: | 
|         |    475  * reserved1 is documented in the EABI as requiring initialisation to 0. | 
|         |    476  *  It is used to manage nested simultaneous propagation. If the value is 0, | 
|         |    477  *  the UCB is participating in no propagations. If the value is 1, the UCB | 
|         |    478  *  is participating in one propagation. Otherwise the value is a pointer to | 
|         |    479  *  a structure holding saved UCB state from the next propagation out. | 
|         |    480  *  The structure used is simply a mallocated UCB. | 
|         |    481  * reserved2 is used to preserve the call-site address over calls to a | 
|         |    482  *  personality routine and cleanup. | 
|         |    483  * reserved3 is used to cache the PR address. | 
|         |    484  * reserved4 is not used. | 
|         |    485  * reserved5 is not used. | 
|         |    486  */ | 
|         |    487  | 
|         |    488 #define NESTED_CONTEXT      unwinder_cache.reserved1 | 
|         |    489 #define SAVED_CALLSITE_ADDR unwinder_cache.reserved2 | 
|         |    490 #define PR_ADDR             unwinder_cache.reserved3 | 
|         |    491  | 
|         |    492 /* Index table entry: */ | 
|         |    493  | 
|         |    494 typedef struct __EIT_entry { | 
|         |    495   uint32_t fnoffset; /* Relative to base of execution region */ | 
|         |    496   uint32_t content; | 
|         |    497 } __EIT_entry; | 
|         |    498  | 
|         |    499  | 
|         |    500 /* Private defines etc: */ | 
|         |    501  | 
|         |    502 static const uint32_t EXIDX_CANTUNWIND = 1; | 
|         |    503 static const uint32_t uint32_highbit = 0x80000000; | 
|         |    504  | 
|         |    505 /* ARM C++ personality routines: */ | 
|         |    506  | 
|         |    507 typedef _Unwind_Reason_Code (*personality_routine)(_Unwind_State, | 
|         |    508                                                    _Unwind_Control_Block *, | 
|         |    509                                                    _Unwind_Context *); | 
|         |    510  | 
|         |    511 WEAKDECL _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *, | 
|         |    512                                                     _Unwind_Context *context); | 
|         |    513 WEAKDECL _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *, | 
|         |    514                                                     _Unwind_Context *context); | 
|         |    515 WEAKDECL _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *, | 
|         |    516                                                     _Unwind_Context *context); | 
|         |    517  | 
|         |    518  | 
|         |    519 /* Various image symbols: */ | 
|         |    520  | 
|         |    521 struct ExceptionTableInfo { | 
|         |    522   uint32_t EIT_base; | 
|         |    523   uint32_t EIT_limit; | 
|         |    524 }; | 
|         |    525 /* We define __ARM_ETInfo to allow access to some linker-generated | 
|         |    526    names that are not legal C identifiers. __ARM_ETInfo is extern only | 
|         |    527    because of scope limitations of the embedded assembler */ | 
|         |    528 extern const struct ExceptionTableInfo __ARM_ETInfo; | 
|         |    529 #define EIT_base \ | 
|         |    530     ((const __EIT_entry *)(__ARM_ETInfo.EIT_base + (const char *)&__ARM_ETInfo)) | 
|         |    531 #define EIT_limit \ | 
|         |    532     ((const __EIT_entry *)(__ARM_ETInfo.EIT_limit + (const char *)&__ARM_ETInfo)) | 
|         |    533  | 
|         |    534  | 
|         |    535 /* ----- Address manipulation: ----- */ | 
|         |    536  | 
|         |    537 /* The following helper function is never called and is present simply | 
|         |    538  * for ease of packaging. The constant word within is used by | 
|         |    539  * ER_RO_offset_to_addr to compute the RO segment base. | 
|         |    540  * The zero word named W is relocated relative to the base B of the | 
|         |    541  * segment which includes it, hence B is recoverable at runtime by | 
|         |    542  * computing &W - W. | 
|         |    543  */ | 
|         |    544  | 
|         |    545 extern const uint32_t __ARM_unwind_ROSegBase_SelfOffset; | 
|         |    546  | 
|         |    547 __asm void __ARM_unwind_basehelper(void) | 
|         |    548 { | 
|         |    549   export __ARM_unwind_ROSegBase_SelfOffset; | 
|         |    550 R_ARM_ROSEGREL32        EQU 39 | 
|         |    551 __ARM_unwind_ROSegBase_SelfOffset; | 
|         |    552  dcd 0; | 
|         |    553  __RELOC R_ARM_ROSEGREL32,__ARM_unwind_ROSegBase_SelfOffset; | 
|         |    554 } | 
|         |    555  | 
|         |    556 #define ER_RO_SegBase ((uint32_t)&__ARM_unwind_ROSegBase_SelfOffset - \ | 
|         |    557                         __ARM_unwind_ROSegBase_SelfOffset) | 
|         |    558  | 
|         |    559 /* And now functions used to convert between segment-relative offsets | 
|         |    560  * and absolute addresses. | 
|         |    561  */ | 
|         |    562  | 
|         |    563 static __inline uint32_t addr_to_ER_RO_offset(uint32_t addr) | 
|         |    564 { | 
|         |    565   return addr - ER_RO_SegBase; | 
|         |    566 } | 
|         |    567  | 
|         |    568 static __inline uint32_t ER_RO_offset_to_addr(uint32_t offset) | 
|         |    569 { | 
|         |    570   extern const uint32_t __ARM_unwind_ROSegBase_SelfOffset; | 
|         |    571   return offset + ER_RO_SegBase; | 
|         |    572 } | 
|         |    573  | 
|         |    574  | 
|         |    575 /* ----- Index table processing ----- */ | 
|         |    576  | 
|         |    577 /* find_and_expand_eit_entry is a support function used in both phases to set | 
|         |    578  * ucb.pr_cache and internal cache. | 
|         |    579  * Call with a pointer to the ucb and the return address to look up. | 
|         |    580  * | 
|         |    581  * The table is contained in the half-open interval | 
|         |    582  * [EIT_base, EIT_limit) and is an ordered array of __EIT_entrys. | 
|         |    583  * Perform a binary search via C library routine bsearch. | 
|         |    584  * The table contains only function start addresses (encoded as offsets), so | 
|         |    585  * we need to special-case the end table entry in the comparison function, | 
|         |    586  * which we do by assuming the function it describes extends to end of memory. | 
|         |    587  * This causes us problems indirectly in that we would like to fault as | 
|         |    588  * many attempts as possible to look up an invalid return address. There are | 
|         |    589  * several ways an invalid return address can be obtained from a broken | 
|         |    590  * program, such as someone corrupting the stack or broken unwind instructions | 
|         |    591  * recovered the wrong value. It is plausible that many bad return addresses | 
|         |    592  * will be either small integers or will point into the heap or stack, hence | 
|         |    593  * it's desirable to get the length of that final function roughly right. | 
|         |    594  * Here we make no attempt to do it. Code exclusively for use in toolchains | 
|         |    595  * which define a suitable limit symbol could make use of that symbol. | 
|         |    596  * Alternatively (QoI) a smart linker could augment the index table with a | 
|         |    597  * dummy EXIDX_CANTUNWIND entry pointing just past the last real function. | 
|         |    598  */ | 
|         |    599  | 
|         |    600 static int EIT_comparator(const void *ck, const void *ce) | 
|         |    601 { | 
|         |    602   uint32_t return_address_offset = *(const uint32_t *)ck; | 
|         |    603   const __EIT_entry *eitp = (const __EIT_entry *)ce; | 
|         |    604   const __EIT_entry *next_eitp = eitp + 1; | 
|         |    605   uint32_t next_fn; | 
|         |    606   if (next_eitp != EIT_limit) | 
|         |    607     next_fn = next_eitp->fnoffset; | 
|         |    608   else | 
|         |    609     next_fn = addr_to_ER_RO_offset(0); /* address 0 is 'just past' the end of memory */ | 
|         |    610   if (return_address_offset < eitp->fnoffset) return -1; | 
|         |    611   if (return_address_offset >= next_fn) return 1; | 
|         |    612   return 0; | 
|         |    613 } | 
|         |    614  | 
|         |    615  | 
|         |    616 static _Unwind_Reason_Code find_and_expand_eit_entry(_Unwind_Control_Block *ucbp, | 
|         |    617                                                      uint32_t return_address) | 
|         |    618 { | 
|         |    619   /* Search the index table for an entry containing the specified return | 
|         |    620    * address. The EIT contains function offsets relative to the base of the | 
|         |    621    * execute region so adjust the return address accordingly. | 
|         |    622    */ | 
|         |    623  | 
|         |    624   uint32_t return_address_offset = addr_to_ER_RO_offset(return_address); | 
|         |    625   const __EIT_entry *base = EIT_base; | 
|         |    626   size_t nelems = EIT_limit - EIT_base; | 
|         |    627  | 
|         |    628    const __EIT_entry *eitp = | 
|         |    629      (const __EIT_entry *) bsearch(&return_address_offset, base, nelems, | 
|         |    630                                    sizeof(__EIT_entry), EIT_comparator); | 
|         |    631  | 
|         |    632   if (eitp == NULL) { | 
|         |    633     /* The return address we have was not found in the EIT. | 
|         |    634      * This breaks the scan and we have to indicate failure. | 
|         |    635      */ | 
|         |    636     ucbp->PR_ADDR = NULL; | 
|         |    637     DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_UNWINDER_LOOKUPFAILED); | 
|         |    638     return _URC_FAILURE; | 
|         |    639   } | 
|         |    640  | 
|         |    641   /* Cache the function offset */ | 
|         |    642  | 
|         |    643   ucbp->pr_cache.fnstart = ER_RO_offset_to_addr(eitp->fnoffset); | 
|         |    644  | 
|         |    645   /* Can this frame be unwound at all? */ | 
|         |    646  | 
|         |    647   if (eitp->content == EXIDX_CANTUNWIND) { | 
|         |    648     ucbp->PR_ADDR = NULL; | 
|         |    649     DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND); | 
|         |    650     return _URC_FAILURE; | 
|         |    651   } | 
|         |    652  | 
|         |    653   /* Obtain the address of the "real" __EHT_Header word */ | 
|         |    654  | 
|         |    655   if (eitp->content & uint32_highbit) { | 
|         |    656     /* It is immediate data */ | 
|         |    657     ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content; | 
|         |    658     ucbp->pr_cache.additional = 1; | 
|         |    659   } else { | 
|         |    660     /* The content field is a segment relative offset to an _Unwind_EHT_Entry structure */ | 
|         |    661     ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)ER_RO_offset_to_addr(eitp->content); | 
|         |    662     ucbp->pr_cache.additional = 0; | 
|         |    663   } | 
|         |    664  | 
|         |    665   /* Discover the personality routine address */ | 
|         |    666  | 
|         |    667   if (*(uint32_t *)(ucbp->pr_cache.ehtp) & uint32_highbit) { | 
|         |    668     /* It is immediate data - compute matching pr */ | 
|         |    669     uint32_t idx = ((*(uint32_t *)(ucbp->pr_cache.ehtp)) >> 24) & 0xf; | 
|         |    670     if (idx == 0) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr0; | 
|         |    671     else if (idx == 1) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr1; | 
|         |    672     else if (idx == 2) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr2; | 
|         |    673     else { /* Failed */ | 
|         |    674       ucbp->PR_ADDR = NULL; | 
|         |    675       DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT); | 
|         |    676       return _URC_FAILURE; | 
|         |    677     } | 
|         |    678   } else { | 
|         |    679     /* Execute region offset to PR */ | 
|         |    680     ucbp->PR_ADDR = ER_RO_offset_to_addr(*(uint32_t *)(ucbp->pr_cache.ehtp)); | 
|         |    681   } | 
|         |    682   return _URC_OK; | 
|         |    683 } | 
|         |    684  | 
|         |    685  | 
|         |    686  | 
|         |    687  | 
|         |    688 /* ----- Unwinding: ----- */ | 
|         |    689  | 
|         |    690 /* Fwd decl */ | 
|         |    691 static NORETURNDECL void unwind_next_frame(_Unwind_Control_Block *ucbp, phase2_virtual_register_set *vrsp); | 
|         |    692  | 
|         |    693 /* Helper fn: If the demand_save flag in a phase1_virtual_register_set was | 
|         |    694  * zeroed, the registers were demand-saved. This function restores from | 
|         |    695  * the save area. | 
|         |    696 */ | 
|         |    697 static void restore_non_core_regs(phase1_virtual_register_set *vrsp) | 
|         |    698 { | 
|         |    699   if (vrsp->demand_save_vfp == 0) | 
|         |    700     __ARM_Unwind_VRS_VFPrestore(&vrsp->vfp); | 
|         |    701   if (vrsp->demand_save_fpa == 0) | 
|         |    702     __ARM_Unwind_VRS_FPArestore(&vrsp->fpa); | 
|         |    703 } | 
|         |    704  | 
|         |    705 /* _Unwind_RaiseException is the external entry point to begin unwinding */ | 
|         |    706  | 
|         |    707 __asm _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp) | 
|         |    708 { | 
|         |    709   extern __ARM_Unwind_RaiseException; | 
|         |    710  | 
|         |    711   MAYBE_SWITCH_TO_ARM_STATE; | 
|         |    712  | 
|         |    713   /* Create a phase2_virtual_register_set on the stack */ | 
|         |    714   /* Save the core registers, carefully writing the original sp value */ | 
|         |    715   stmfd sp!,{r13-r15};  /* pushed 3 words => 3 words */ | 
|         |    716   stmfd sp!,{r0-r12};   /* pushed 13 words => 16 words */ | 
|         |    717   /* Write zeroes for the demand_save bytes so no saving occurs in phase 2 */ | 
|         |    718   mov r1,#0; | 
|         |    719   str r1,[sp,#-4]!;     /* pushed 1 word => 17 words */ | 
|         |    720   mov r1,sp; | 
|         |    721   sub sp,sp,#4;         /* preserve 8 byte alignment => 18 words */ | 
|         |    722  | 
|         |    723   /* Now pass to C (with r0 still valid) to do the real work. | 
|         |    724    * r0 = ucbp, r1 = phase2_virtual_register_set. | 
|         |    725    * If we get control back, pop the stack and return preserving r0. | 
|         |    726    */ | 
|         |    727  | 
|         |    728 #if OLD_STYLE_INTERWORKING | 
|         |    729   ldr r2,Unwind_RaiseException_Offset; | 
|         |    730   add r2,r2,pc; | 
|         |    731   mov lr,pc; | 
|         |    732 Offset_Base | 
|         |    733   bx r2; | 
|         |    734 #else | 
|         |    735   /* on arch 5T and later the linker will fix 'bl' => 'blx' as | 
|         |    736      needed */ | 
|         |    737   bl  __ARM_Unwind_RaiseException; | 
|         |    738 #endif | 
|         |    739   ldr r14,[sp,#16*4]; | 
|         |    740   add sp,sp,#18*4; | 
|         |    741   RET_LR; | 
|         |    742 #if OLD_STYLE_INTERWORKING | 
|         |    743 Unwind_RaiseException_Offset dcd __ARM_Unwind_RaiseException - Offset_Base; | 
|         |    744 #endif | 
|         |    745   MAYBE_CODE16; | 
|         |    746  | 
|         |    747   /* Alternate symbol names for difficult symbols. | 
|         |    748    * It is possible no functions included in the image require | 
|         |    749    * a handler table. Therefore make only a weak reference to | 
|         |    750    * the handler table base symbol, which may be absent. | 
|         |    751    */ | 
|         |    752   extern |.ARM.exidx$$Base|; | 
|         |    753   extern |.ARM.exidx$$Limit|; | 
|         |    754   extern |.ARM.extab$$Base| WEAKASMDECL; | 
|         |    755   export __ARM_ETInfo; | 
|         |    756   /* these are offsets for /ropi */ | 
|         |    757 __ARM_ETInfo /* layout must match struct ExceptionTableInfo */ | 
|         |    758 eit_base   dcd |.ARM.exidx$$Base|  - __ARM_ETInfo; /* index table base */ | 
|         |    759 eit_limit  dcd |.ARM.exidx$$Limit| - __ARM_ETInfo; /* index table limit */ | 
|         |    760 } | 
|         |    761  | 
|         |    762  | 
|         |    763 /* __ARM_Unwind_RaiseException performs phase 1 unwinding */ | 
|         |    764  | 
|         |    765 _Unwind_Reason_Code __ARM_Unwind_RaiseException(_Unwind_Control_Block *ucbp, | 
|         |    766                                                 phase2_virtual_register_set *entry_VRSp) | 
|         |    767 { | 
|         |    768   phase1_virtual_register_set phase1_VRS; | 
|         |    769  | 
|         |    770   /* Is this a nested simultaneous propagation? | 
|         |    771    * (see comments with _Unwind_Complete) | 
|         |    772    */ | 
|         |    773   if (ucbp->NESTED_CONTEXT == 0) { | 
|         |    774     /* No - this is only propagation */ | 
|         |    775     ucbp->NESTED_CONTEXT = 1; | 
|         |    776   } else { | 
|         |    777     /* Yes - cache the state elsewhere and restore it when the propagation ends */ | 
|         |    778     /* This representation wastes space and uses malloc; do better? | 
|         |    779      * On the other hand will it ever be used in practice? | 
|         |    780      */ | 
|         |    781     _Unwind_Control_Block *saved_ucbp = | 
|         |    782       (_Unwind_Control_Block *)malloc(sizeof(_Unwind_Control_Block)); | 
|         |    783     if (ucbp == NULL) { | 
|         |    784       DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_UNWINDER_BUFFERFAILED); | 
|         |    785       return _URC_FAILURE; | 
|         |    786     } | 
|         |    787     saved_ucbp->unwinder_cache = ucbp->unwinder_cache; | 
|         |    788     saved_ucbp->barrier_cache = ucbp->barrier_cache; | 
|         |    789     saved_ucbp->cleanup_cache = ucbp->cleanup_cache; | 
|         |    790     ucbp->NESTED_CONTEXT = (uint32_t)saved_ucbp; | 
|         |    791   } | 
|         |    792  | 
|         |    793   /* entry_VRSp contains the core registers as they were when | 
|         |    794    * _Unwind_RaiseException was called.  Copy the call-site address to r15 | 
|         |    795    * then copy all the registers to phase1_VRS for the phase 1 stack scan. | 
|         |    796    */ | 
|         |    797  | 
|         |    798   entry_VRSp->core.r[15] = entry_VRSp->core.r[14]; | 
|         |    799   phase1_VRS.core = entry_VRSp->core; | 
|         |    800  | 
|         |    801   /* For phase 1 only ensure non-core registers are saved before use. | 
|         |    802    * If WMMX registers are supported, initialise their flags here and | 
|         |    803    * take appropriate action elsewhere. | 
|         |    804    */ | 
|         |    805  | 
|         |    806   phase1_VRS.demand_save_vfp = 1; | 
|         |    807   phase1_VRS.demand_save_fpa = 1; | 
|         |    808  | 
|         |    809   /* Now perform a virtual unwind until a propagation barrier is met, or | 
|         |    810    * until something goes wrong.  If something does go wrong, we ought (I | 
|         |    811    * suppose) to restore registers we may have destroyed. | 
|         |    812    */ | 
|         |    813  | 
|         |    814   while (1) { | 
|         |    815  | 
|         |    816     _Unwind_Reason_Code pr_result; | 
|         |    817  | 
|         |    818     /* Search the index table for the required entry.  Cache the index table | 
|         |    819      * pointer, and obtain and cache the addresses of the "real" __EHT_Header | 
|         |    820      * word and the personality routine. | 
|         |    821      */ | 
|         |    822  | 
|         |    823     if (find_and_expand_eit_entry(ucbp, phase1_VRS.core.r[15]) != _URC_OK) { | 
|         |    824       restore_non_core_regs(&phase1_VRS); | 
|         |    825       /* Debugger bottleneck fn called during lookup */ | 
|         |    826       return _URC_FAILURE; | 
|         |    827     } | 
|         |    828  | 
|         |    829     /* Call the pr to decide what to do */ | 
|         |    830  | 
|         |    831     pr_result = ((personality_routine)ucbp->PR_ADDR)(_US_VIRTUAL_UNWIND_FRAME, | 
|         |    832                                                      ucbp, | 
|         |    833                                                      (_Unwind_Context *)&phase1_VRS); | 
|         |    834  | 
|         |    835     if (pr_result == _URC_HANDLER_FOUND) break; | 
|         |    836     if (pr_result == _URC_CONTINUE_UNWIND) continue; | 
|         |    837  | 
|         |    838     /* If we get here some sort of failure has occurred in the | 
|         |    839      * pr and probably the pr returned _URC_FAILURE | 
|         |    840      */ | 
|         |    841     restore_non_core_regs(&phase1_VRS); | 
|         |    842     return _URC_FAILURE; | 
|         |    843   } | 
|         |    844  | 
|         |    845   /* Propagation barrier located... restore entry register state of non-core regs */ | 
|         |    846  | 
|         |    847   restore_non_core_regs(&phase1_VRS); | 
|         |    848  | 
|         |    849   /* Initiate real unwinding */ | 
|         |    850   unwind_next_frame(ucbp, entry_VRSp); | 
|         |    851   /* Unreached, but keep compiler quiet: */ | 
|         |    852   return _URC_FAILURE; | 
|         |    853 } | 
|         |    854  | 
|         |    855  | 
|         |    856 /* unwind_next_frame performs phase 2 unwinding */ | 
|         |    857  | 
|         |    858 static NORETURNDECL void unwind_next_frame(_Unwind_Control_Block *ucbp, phase2_virtual_register_set *vrsp) | 
|         |    859 { | 
|         |    860   while (1) { | 
|         |    861  | 
|         |    862     _Unwind_Reason_Code pr_result; | 
|         |    863  | 
|         |    864     /* Search the index table for the required entry.  Cache the index table | 
|         |    865      * pointer, and obtain and cache the addresses of the "real" __EHT_Header | 
|         |    866      * word and the personality routine. | 
|         |    867      */ | 
|         |    868  | 
|         |    869     if (find_and_expand_eit_entry(ucbp, vrsp->core.r[15]) != _URC_OK) | 
|         |    870       abort(); | 
|         |    871  | 
|         |    872     /* Save the call-site address and call the pr to do whatever it | 
|         |    873      * wants to do on this new frame. | 
|         |    874      */ | 
|         |    875  | 
|         |    876     ucbp->SAVED_CALLSITE_ADDR = vrsp->core.r[15]; | 
|         |    877     pr_result = ((personality_routine)ucbp->PR_ADDR)(_US_UNWIND_FRAME_STARTING, ucbp, | 
|         |    878                                                      (_Unwind_Context *)vrsp); | 
|         |    879  | 
|         |    880     if (pr_result == _URC_INSTALL_CONTEXT) { | 
|         |    881       /* Upload the registers */ | 
|         |    882       __ARM_Unwind_VRS_corerestore(&vrsp->core); | 
|         |    883     } else if (pr_result == _URC_CONTINUE_UNWIND) | 
|         |    884       continue; | 
|         |    885     else | 
|         |    886       abort(); | 
|         |    887   } | 
|         |    888 } | 
|         |    889  | 
|         |    890  | 
|         |    891 /* _Unwind_Resume is the external entry point called after a cleanup | 
|         |    892  * to resume unwinding. It tail-calls a helper function, | 
|         |    893  * __ARM_Unwind_Resume, which never returns. | 
|         |    894  */ | 
|         |    895 __asm NORETURNDECL void _Unwind_Resume(_Unwind_Control_Block *ucbp) | 
|         |    896 { | 
|         |    897   extern __ARM_Unwind_Resume; | 
|         |    898  | 
|         |    899   MAYBE_SWITCH_TO_ARM_STATE; | 
|         |    900  | 
|         |    901   /* Create a phase2_virtual_register_set on the stack */ | 
|         |    902   /* Save the core registers, carefully writing the original sp value */ | 
|         |    903  | 
|         |    904   stmfd sp!,{r13-r15};  /* pushed 3 words => 3 words */ | 
|         |    905   stmfd sp!,{r0-r12};   /* pushed 13 words => 16 words */ | 
|         |    906   /* Write zeroes for the demand_save bytes so no saving occurs in phase 2 */ | 
|         |    907   mov r1,#0; | 
|         |    908   str r1,[sp,#-4]!;     /* pushed 1 word => 17 words */ | 
|         |    909   mov r1,sp; | 
|         |    910   sub sp,sp,#4;         /* preserve 8 byte alignment => 18 words */ | 
|         |    911  | 
|         |    912   /* Now pass to C (with r0 still valid) to do the real work. | 
|         |    913    * r0 = ucbp, r1 = phase2_virtual_register_set. | 
|         |    914    * This call never returns. | 
|         |    915    */ | 
|         |    916  | 
|         |    917 #ifdef __APCS_INTERWORK | 
|         |    918   ldr r2,Unwind_Resume_Offset; | 
|         |    919   add r2,r2,pc; | 
|         |    920   bx r2; | 
|         |    921 Unwind_Resume_Offset dcd __ARM_Unwind_Resume - .; | 
|         |    922 #else | 
|         |    923   b __ARM_Unwind_Resume; | 
|         |    924 #endif | 
|         |    925   MAYBE_CODE16; | 
|         |    926 } | 
|         |    927  | 
|         |    928  | 
|         |    929 /* Helper function for _Unwind_Resume */ | 
|         |    930  | 
|         |    931 NORETURNDECL void __ARM_Unwind_Resume(_Unwind_Control_Block *ucbp, | 
|         |    932                                   phase2_virtual_register_set *entry_VRSp) | 
|         |    933 { | 
|         |    934   _Unwind_Reason_Code pr_result; | 
|         |    935  | 
|         |    936   /* Recover saved state */ | 
|         |    937  | 
|         |    938   entry_VRSp->core.r[15] = ucbp->SAVED_CALLSITE_ADDR; | 
|         |    939  | 
|         |    940   /* Call the cached PR and dispatch */ | 
|         |    941  | 
|         |    942   pr_result = ((personality_routine)ucbp->PR_ADDR)(_US_UNWIND_FRAME_RESUME, ucbp, | 
|         |    943                                                    (_Unwind_Context *)entry_VRSp); | 
|         |    944  | 
|         |    945   if (pr_result == _URC_INSTALL_CONTEXT) { | 
|         |    946    /* Upload the registers */ | 
|         |    947     __ARM_Unwind_VRS_corerestore(&entry_VRSp->core); | 
|         |    948   } else if (pr_result == _URC_CONTINUE_UNWIND) | 
|         |    949     unwind_next_frame(ucbp, entry_VRSp); | 
|         |    950   else | 
|         |    951     abort(); | 
|         |    952 } | 
|         |    953  | 
|         |    954  | 
|         |    955 /* _Unwind_Complete is called at the end of a propagation. | 
|         |    956  * If we support multiple simultaneous propagations, restore the cached state | 
|         |    957  * of the previous propagation here. | 
|         |    958  */ | 
|         |    959  | 
|         |    960 void _Unwind_Complete(_Unwind_Control_Block *ucbp) | 
|         |    961 { | 
|         |    962   _Unwind_Control_Block *context = (_Unwind_Control_Block *)ucbp->NESTED_CONTEXT; | 
|         |    963   if ((uint32_t)context == 0) abort();  /* should be impossible */ | 
|         |    964   if ((uint32_t)context == 1) { | 
|         |    965     /* This was the only ongoing propagation of this object */ | 
|         |    966     ucbp->NESTED_CONTEXT--; | 
|         |    967     return; | 
|         |    968   } | 
|         |    969   /* Otherwise we copy the state back from the cache structure pointed to | 
|         |    970    * by ucbp->NESTED_CONTEXT. | 
|         |    971    */ | 
|         |    972   /* This first one updates ucbp->NESTED_CONTEXT */ | 
|         |    973   ucbp->unwinder_cache = context->unwinder_cache; | 
|         |    974   ucbp->barrier_cache = context->barrier_cache; | 
|         |    975   ucbp->cleanup_cache = context->cleanup_cache; | 
|         |    976   free(context); | 
|         |    977 } | 
|         |    978  | 
|         |    979 #endif /* unwinder_c */ | 
|         |    980 #ifdef unwind_activity_c | 
|         |    981  | 
|         |    982 /* Runtime debug "bottleneck function": */ | 
|         |    983 /* (not in the current Exceptions EABI document) */ | 
|         |    984  | 
|         |    985 void _Unwind_Activity(_Unwind_Control_Block *ucbp, uint32_t reason, uint32_t arg) | 
|         |    986 { | 
|         |    987 #ifdef UNWIND_ACTIVITY_DIAGNOSTICS | 
|         |    988   uint32_t who = reason >> 24; | 
|         |    989   uint32_t activity = reason & 0xffffff; | 
|         |    990   printf("_Unwind_Activity: UCB=0x%8.8x Reason=(", (uint32_t)ucbp); | 
|         |    991   switch (who) { | 
|         |    992   case _UASUBSYS_UNWINDER: | 
|         |    993     printf("unw,"); | 
|         |    994     if (activity >= 0x80) | 
|         |    995       printf("%x) Arg=0x%8.8x\n", activity, arg); | 
|         |    996     break; | 
|         |    997   case _UASUBSYS_CPP: | 
|         |    998     printf("C++,"); | 
|         |    999     if (activity >= 0x80) { | 
|         |   1000       if (activity == _UAACT_CPP_TYPEINFO) | 
|         |   1001         printf("typeinfo) Typeinfo=0x%8.8x\n", arg); | 
|         |   1002       else | 
|         |   1003         printf("%x) Arg=0x%8.8x\n", activity, arg); | 
|         |   1004     } | 
|         |   1005     break; | 
|         |   1006   default: | 
|         |   1007     printf("???,"); | 
|         |   1008     if (activity >= 0x80) | 
|         |   1009       printf("%x) Arg=0x%8.8x\n", activity, arg); | 
|         |   1010     break; | 
|         |   1011   } | 
|         |   1012   if (activity < 0x80) { | 
|         |   1013     switch (activity) { | 
|         |   1014     case _UAACT_STARTING: | 
|         |   1015       printf("starting) Typeinfo=0x%8.8x\n", arg); | 
|         |   1016       break; | 
|         |   1017     case _UAACT_ENDING: | 
|         |   1018       printf("ending) Cause=%d\n", arg); | 
|         |   1019       break; | 
|         |   1020     case _UAACT_BARRIERFOUND: | 
|         |   1021       printf("barrierfound) Pad=0x%8.8x\n", arg); | 
|         |   1022       break; | 
|         |   1023     case _UAACT_PADENTRY: | 
|         |   1024       printf("padentry) Pad=0x%8.8x\n", arg); | 
|         |   1025       break; | 
|         |   1026     default: | 
|         |   1027       printf("%x) Arg=0x%8.8x\n", activity, arg); | 
|         |   1028       break; | 
|         |   1029     } | 
|         |   1030   } | 
|         |   1031 #endif | 
|         |   1032 } | 
|         |   1033  | 
|         |   1034 #endif /* unwind_activity_c */ |