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