kernel/eka/compsupp/rvct2_1/aehabi/unwinder.c
changeset 266 0008ccd16016
parent 259 57b9594f5772
child 272 70a6efdb753f
child 281 13fbfa31d2ba
equal deleted inserted replaced
259:57b9594f5772 266:0008ccd16016
     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 */