OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [arm/] [unwind-arm.c] - Blame information for rev 801

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 734 jeremybenn
/* ARM EABI compliant unwinding routines.
2
   Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc.
3
   Contributed by Paul Brook
4
 
5
   This file is free software; you can redistribute it and/or modify it
6
   under the terms of the GNU General Public License as published by the
7
   Free Software Foundation; either version 3, or (at your option) any
8
   later version.
9
 
10
   This file is distributed in the hope that it will be useful, but
11
   WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
   General Public License for more details.
14
 
15
   Under Section 7 of GPL version 3, you are granted additional
16
   permissions described in the GCC Runtime Library Exception, version
17
   3.1, as published by the Free Software Foundation.
18
 
19
   You should have received a copy of the GNU General Public License and
20
   a copy of the GCC Runtime Library Exception along with this program;
21
   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
22
   <http://www.gnu.org/licenses/>.  */
23
 
24
#include "unwind.h"
25
 
26
/* Misc constants.  */
27
#define R_IP    12
28
#define R_SP    13
29
#define R_LR    14
30
#define R_PC    15
31
 
32
#define VRS_PC(vrs) ((vrs)->core.r[R_PC])
33
#define VRS_SP(vrs) ((vrs)->core.r[R_SP])
34
#define VRS_RETURN(vrs) ((vrs)->core.r[R_LR])
35
 
36
struct core_regs
37
{
38
  _uw r[16];
39
};
40
 
41
/* We use normal integer types here to avoid the compiler generating
42
   coprocessor instructions.  */
43
struct vfp_regs
44
{
45
  _uw64 d[16];
46
  _uw pad;
47
};
48
 
49
struct vfpv3_regs
50
{
51
  /* Always populated via VSTM, so no need for the "pad" field from
52
     vfp_regs (which is used to store the format word for FSTMX).  */
53
  _uw64 d[16];
54
};
55
 
56
struct fpa_reg
57
{
58
  _uw w[3];
59
};
60
 
61
struct fpa_regs
62
{
63
  struct fpa_reg f[8];
64
};
65
 
66
struct wmmxd_regs
67
{
68
  _uw64 wd[16];
69
};
70
 
71
struct wmmxc_regs
72
{
73
  _uw wc[4];
74
};
75
 
76
/* The ABI specifies that the unwind routines may only use core registers,
77
   except when actually manipulating coprocessor state.  This allows
78
   us to write one implementation that works on all platforms by
79
   demand-saving coprocessor registers.
80
 
81
   During unwinding we hold the coprocessor state in the actual hardware
82
   registers and allocate demand-save areas for use during phase1
83
   unwinding.  */
84
 
85
typedef struct
86
{
87
  /* The first fields must be the same as a phase2_vrs.  */
88
  _uw demand_save_flags;
89
  struct core_regs core;
90
  _uw prev_sp; /* Only valid during forced unwinding.  */
91
  struct vfp_regs vfp;
92
  struct vfpv3_regs vfp_regs_16_to_31;
93
  struct fpa_regs fpa;
94
  struct wmmxd_regs wmmxd;
95
  struct wmmxc_regs wmmxc;
96
} phase1_vrs;
97
 
98
#define DEMAND_SAVE_VFP 1       /* VFP state has been saved if not set */
99
#define DEMAND_SAVE_VFP_D 2     /* VFP state is for FLDMD/FSTMD if set */
100
#define DEMAND_SAVE_VFP_V3 4    /* VFPv3 state for regs 16 .. 31 has
101
                                   been saved if not set */
102
#define DEMAND_SAVE_WMMXD 8     /* iWMMXt data registers have been
103
                                   saved if not set.  */
104
#define DEMAND_SAVE_WMMXC 16    /* iWMMXt control registers have been
105
                                   saved if not set.  */
106
 
107
/* This must match the structure created by the assembly wrappers.  */
108
typedef struct
109
{
110
  _uw demand_save_flags;
111
  struct core_regs core;
112
} phase2_vrs;
113
 
114
/* Coprocessor register state manipulation functions.  */
115
 
116
/* Routines for FLDMX/FSTMX format...  */
117
void __gnu_Unwind_Save_VFP (struct vfp_regs * p);
118
void __gnu_Unwind_Restore_VFP (struct vfp_regs * p);
119
void __gnu_Unwind_Save_WMMXD (struct wmmxd_regs * p);
120
void __gnu_Unwind_Restore_WMMXD (struct wmmxd_regs * p);
121
void __gnu_Unwind_Save_WMMXC (struct wmmxc_regs * p);
122
void __gnu_Unwind_Restore_WMMXC (struct wmmxc_regs * p);
123
 
124
/* ...and those for FLDMD/FSTMD format...  */
125
void __gnu_Unwind_Save_VFP_D (struct vfp_regs * p);
126
void __gnu_Unwind_Restore_VFP_D (struct vfp_regs * p);
127
 
128
/* ...and those for VLDM/VSTM format, saving/restoring only registers
129
   16 through 31.  */
130
void __gnu_Unwind_Save_VFP_D_16_to_31 (struct vfpv3_regs * p);
131
void __gnu_Unwind_Restore_VFP_D_16_to_31 (struct vfpv3_regs * p);
132
 
133
/* Restore coprocessor state after phase1 unwinding.  */
134
static void
135
restore_non_core_regs (phase1_vrs * vrs)
136
{
137
  if ((vrs->demand_save_flags & DEMAND_SAVE_VFP) == 0)
138
    {
139
      if (vrs->demand_save_flags & DEMAND_SAVE_VFP_D)
140
        __gnu_Unwind_Restore_VFP_D (&vrs->vfp);
141
      else
142
        __gnu_Unwind_Restore_VFP (&vrs->vfp);
143
    }
144
 
145
  if ((vrs->demand_save_flags & DEMAND_SAVE_VFP_V3) == 0)
146
    __gnu_Unwind_Restore_VFP_D_16_to_31 (&vrs->vfp_regs_16_to_31);
147
 
148
  if ((vrs->demand_save_flags & DEMAND_SAVE_WMMXD) == 0)
149
    __gnu_Unwind_Restore_WMMXD (&vrs->wmmxd);
150
  if ((vrs->demand_save_flags & DEMAND_SAVE_WMMXC) == 0)
151
    __gnu_Unwind_Restore_WMMXC (&vrs->wmmxc);
152
}
153
 
154
#include "unwind-arm-common.inc"
155
 
156
/* ABI defined personality routines.  */
157
extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0 (_Unwind_State,
158
    _Unwind_Control_Block *, _Unwind_Context *);// __attribute__((weak));
159
extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1 (_Unwind_State,
160
    _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak));
161
extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2 (_Unwind_State,
162
    _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak));
163
 
164
/* ABI defined routine to store a virtual register to memory.  */
165
 
166
_Unwind_VRS_Result _Unwind_VRS_Get (_Unwind_Context *context,
167
                                    _Unwind_VRS_RegClass regclass,
168
                                    _uw regno,
169
                                    _Unwind_VRS_DataRepresentation representation,
170
                                    void *valuep)
171
{
172
  phase1_vrs *vrs = (phase1_vrs *) context;
173
 
174
  switch (regclass)
175
    {
176
    case _UVRSC_CORE:
177
      if (representation != _UVRSD_UINT32
178
          || regno > 15)
179
        return _UVRSR_FAILED;
180
      *(_uw *) valuep = vrs->core.r[regno];
181
      return _UVRSR_OK;
182
 
183
    case _UVRSC_VFP:
184
    case _UVRSC_FPA:
185
    case _UVRSC_WMMXD:
186
    case _UVRSC_WMMXC:
187
      return _UVRSR_NOT_IMPLEMENTED;
188
 
189
    default:
190
      return _UVRSR_FAILED;
191
    }
192
}
193
 
194
 
195
/* ABI defined function to load a virtual register from memory.  */
196
 
197
_Unwind_VRS_Result _Unwind_VRS_Set (_Unwind_Context *context,
198
                                    _Unwind_VRS_RegClass regclass,
199
                                    _uw regno,
200
                                    _Unwind_VRS_DataRepresentation representation,
201
                                    void *valuep)
202
{
203
  phase1_vrs *vrs = (phase1_vrs *) context;
204
 
205
  switch (regclass)
206
    {
207
    case _UVRSC_CORE:
208
      if (representation != _UVRSD_UINT32
209
          || regno > 15)
210
        return _UVRSR_FAILED;
211
 
212
      vrs->core.r[regno] = *(_uw *) valuep;
213
      return _UVRSR_OK;
214
 
215
    case _UVRSC_VFP:
216
    case _UVRSC_FPA:
217
    case _UVRSC_WMMXD:
218
    case _UVRSC_WMMXC:
219
      return _UVRSR_NOT_IMPLEMENTED;
220
 
221
    default:
222
      return _UVRSR_FAILED;
223
    }
224
}
225
 
226
 
227
/* ABI defined function to pop registers off the stack.  */
228
 
229
_Unwind_VRS_Result _Unwind_VRS_Pop (_Unwind_Context *context,
230
                                    _Unwind_VRS_RegClass regclass,
231
                                    _uw discriminator,
232
                                    _Unwind_VRS_DataRepresentation representation)
233
{
234
  phase1_vrs *vrs = (phase1_vrs *) context;
235
 
236
  switch (regclass)
237
    {
238
    case _UVRSC_CORE:
239
      {
240
        _uw *ptr;
241
        _uw mask;
242
        int i;
243
 
244
        if (representation != _UVRSD_UINT32)
245
          return _UVRSR_FAILED;
246
 
247
        mask = discriminator & 0xffff;
248
        ptr = (_uw *) vrs->core.r[R_SP];
249
        /* Pop the requested registers.  */
250
        for (i = 0; i < 16; i++)
251
          {
252
            if (mask & (1 << i))
253
              vrs->core.r[i] = *(ptr++);
254
          }
255
        /* Writeback the stack pointer value if it wasn't restored.  */
256
        if ((mask & (1 << R_SP)) == 0)
257
          vrs->core.r[R_SP] = (_uw) ptr;
258
      }
259
      return _UVRSR_OK;
260
 
261
    case _UVRSC_VFP:
262
      {
263
        _uw start = discriminator >> 16;
264
        _uw count = discriminator & 0xffff;
265
        struct vfp_regs tmp;
266
        struct vfpv3_regs tmp_16_to_31;
267
        int tmp_count;
268
        _uw *sp;
269
        _uw *dest;
270
        int num_vfpv3_regs = 0;
271
 
272
        /* We use an approximation here by bounding _UVRSD_DOUBLE
273
           register numbers at 32 always, since we can't detect if
274
           VFPv3 isn't present (in such a case the upper limit is 16).  */
275
        if ((representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
276
            || start + count > (representation == _UVRSD_VFPX ? 16 : 32)
277
            || (representation == _UVRSD_VFPX && start >= 16))
278
          return _UVRSR_FAILED;
279
 
280
        /* Check if we're being asked to pop VFPv3-only registers
281
           (numbers 16 through 31).  */
282
        if (start >= 16)
283
          num_vfpv3_regs = count;
284
        else if (start + count > 16)
285
          num_vfpv3_regs = start + count - 16;
286
 
287
        if (num_vfpv3_regs && representation != _UVRSD_DOUBLE)
288
          return _UVRSR_FAILED;
289
 
290
        /* Demand-save coprocessor registers for stage1.  */
291
        if (start < 16 && (vrs->demand_save_flags & DEMAND_SAVE_VFP))
292
          {
293
            vrs->demand_save_flags &= ~DEMAND_SAVE_VFP;
294
 
295
            if (representation == _UVRSD_DOUBLE)
296
              {
297
                /* Save in FLDMD/FSTMD format.  */
298
                vrs->demand_save_flags |= DEMAND_SAVE_VFP_D;
299
                __gnu_Unwind_Save_VFP_D (&vrs->vfp);
300
              }
301
            else
302
              {
303
                /* Save in FLDMX/FSTMX format.  */
304
                vrs->demand_save_flags &= ~DEMAND_SAVE_VFP_D;
305
                __gnu_Unwind_Save_VFP (&vrs->vfp);
306
              }
307
          }
308
 
309
        if (num_vfpv3_regs > 0
310
            && (vrs->demand_save_flags & DEMAND_SAVE_VFP_V3))
311
          {
312
            vrs->demand_save_flags &= ~DEMAND_SAVE_VFP_V3;
313
            __gnu_Unwind_Save_VFP_D_16_to_31 (&vrs->vfp_regs_16_to_31);
314
          }
315
 
316
        /* Restore the registers from the stack.  Do this by saving the
317
           current VFP registers to a memory area, moving the in-memory
318
           values into that area, and restoring from the whole area.
319
           For _UVRSD_VFPX we assume FSTMX standard format 1.  */
320
        if (representation == _UVRSD_VFPX)
321
          __gnu_Unwind_Save_VFP (&tmp);
322
        else
323
          {
324
            /* Save registers 0 .. 15 if required.  */
325
            if (start < 16)
326
              __gnu_Unwind_Save_VFP_D (&tmp);
327
 
328
            /* Save VFPv3 registers 16 .. 31 if required.  */
329
            if (num_vfpv3_regs)
330
              __gnu_Unwind_Save_VFP_D_16_to_31 (&tmp_16_to_31);
331
          }
332
 
333
        /* Work out how many registers below register 16 need popping.  */
334
        tmp_count = num_vfpv3_regs > 0 ? 16 - start : count;
335
 
336
        /* Copy registers below 16, if needed.
337
           The stack address is only guaranteed to be word aligned, so
338
           we can't use doubleword copies.  */
339
        sp = (_uw *) vrs->core.r[R_SP];
340
        if (tmp_count > 0)
341
          {
342
            tmp_count *= 2;
343
            dest = (_uw *) &tmp.d[start];
344
            while (tmp_count--)
345
              *(dest++) = *(sp++);
346
          }
347
 
348
        /* Copy VFPv3 registers numbered >= 16, if needed.  */
349
        if (num_vfpv3_regs > 0)
350
          {
351
            /* num_vfpv3_regs is needed below, so copy it.  */
352
            int tmp_count_2 = num_vfpv3_regs * 2;
353
            int vfpv3_start = start < 16 ? 16 : start;
354
 
355
            dest = (_uw *) &tmp_16_to_31.d[vfpv3_start - 16];
356
            while (tmp_count_2--)
357
              *(dest++) = *(sp++);
358
          }
359
 
360
        /* Skip the format word space if using FLDMX/FSTMX format.  */
361
        if (representation == _UVRSD_VFPX)
362
          sp++;
363
 
364
        /* Set the new stack pointer.  */
365
        vrs->core.r[R_SP] = (_uw) sp;
366
 
367
        /* Reload the registers.  */
368
        if (representation == _UVRSD_VFPX)
369
          __gnu_Unwind_Restore_VFP (&tmp);
370
        else
371
          {
372
            /* Restore registers 0 .. 15 if required.  */
373
            if (start < 16)
374
              __gnu_Unwind_Restore_VFP_D (&tmp);
375
 
376
            /* Restore VFPv3 registers 16 .. 31 if required.  */
377
            if (num_vfpv3_regs > 0)
378
              __gnu_Unwind_Restore_VFP_D_16_to_31 (&tmp_16_to_31);
379
          }
380
      }
381
      return _UVRSR_OK;
382
 
383
    case _UVRSC_FPA:
384
      return _UVRSR_NOT_IMPLEMENTED;
385
 
386
    case _UVRSC_WMMXD:
387
      {
388
        _uw start = discriminator >> 16;
389
        _uw count = discriminator & 0xffff;
390
        struct wmmxd_regs tmp;
391
        _uw *sp;
392
        _uw *dest;
393
 
394
        if ((representation != _UVRSD_UINT64) || start + count > 16)
395
          return _UVRSR_FAILED;
396
 
397
        if (vrs->demand_save_flags & DEMAND_SAVE_WMMXD)
398
          {
399
            /* Demand-save resisters for stage1.  */
400
            vrs->demand_save_flags &= ~DEMAND_SAVE_WMMXD;
401
            __gnu_Unwind_Save_WMMXD (&vrs->wmmxd);
402
          }
403
 
404
        /* Restore the registers from the stack.  Do this by saving the
405
           current WMMXD registers to a memory area, moving the in-memory
406
           values into that area, and restoring from the whole area.  */
407
        __gnu_Unwind_Save_WMMXD (&tmp);
408
 
409
        /* The stack address is only guaranteed to be word aligned, so
410
           we can't use doubleword copies.  */
411
        sp = (_uw *) vrs->core.r[R_SP];
412
        dest = (_uw *) &tmp.wd[start];
413
        count *= 2;
414
        while (count--)
415
          *(dest++) = *(sp++);
416
 
417
        /* Set the new stack pointer.  */
418
        vrs->core.r[R_SP] = (_uw) sp;
419
 
420
        /* Reload the registers.  */
421
        __gnu_Unwind_Restore_WMMXD (&tmp);
422
      }
423
      return _UVRSR_OK;
424
 
425
    case _UVRSC_WMMXC:
426
      {
427
        int i;
428
        struct wmmxc_regs tmp;
429
        _uw *sp;
430
 
431
        if ((representation != _UVRSD_UINT32) || discriminator > 16)
432
          return _UVRSR_FAILED;
433
 
434
        if (vrs->demand_save_flags & DEMAND_SAVE_WMMXC)
435
          {
436
            /* Demand-save resisters for stage1.  */
437
            vrs->demand_save_flags &= ~DEMAND_SAVE_WMMXC;
438
            __gnu_Unwind_Save_WMMXC (&vrs->wmmxc);
439
          }
440
 
441
        /* Restore the registers from the stack.  Do this by saving the
442
           current WMMXC registers to a memory area, moving the in-memory
443
           values into that area, and restoring from the whole area.  */
444
        __gnu_Unwind_Save_WMMXC (&tmp);
445
 
446
        sp = (_uw *) vrs->core.r[R_SP];
447
        for (i = 0; i < 4; i++)
448
          if (discriminator & (1 << i))
449
            tmp.wc[i] = *(sp++);
450
 
451
        /* Set the new stack pointer.  */
452
        vrs->core.r[R_SP] = (_uw) sp;
453
 
454
        /* Reload the registers.  */
455
        __gnu_Unwind_Restore_WMMXC (&tmp);
456
      }
457
      return _UVRSR_OK;
458
 
459
    default:
460
      return _UVRSR_FAILED;
461
    }
462
}
463
 
464
 
465
/* Core unwinding functions.  */
466
 
467
/* Calculate the address encoded by a 31-bit self-relative offset at address
468
   P.  */
469
static inline _uw
470
selfrel_offset31 (const _uw *p)
471
{
472
  _uw offset;
473
 
474
  offset = *p;
475
  /* Sign extend to 32 bits.  */
476
  if (offset & (1 << 30))
477
    offset |= 1u << 31;
478
  else
479
    offset &= ~(1u << 31);
480
 
481
  return offset + (_uw) p;
482
}
483
 
484
static _uw
485
__gnu_unwind_get_pr_addr (int idx)
486
{
487
  switch (idx)
488
    {
489
    case 0:
490
      return (_uw) &__aeabi_unwind_cpp_pr0;
491
 
492
    case 1:
493
      return (_uw) &__aeabi_unwind_cpp_pr1;
494
 
495
    case 2:
496
      return (_uw) &__aeabi_unwind_cpp_pr2;
497
 
498
    default:
499
      return 0;
500
    }
501
}
502
 
503
/* ABI defined personality routine entry points.  */
504
 
505
_Unwind_Reason_Code
506
__aeabi_unwind_cpp_pr0 (_Unwind_State state,
507
                        _Unwind_Control_Block *ucbp,
508
                        _Unwind_Context *context)
509
{
510
  return __gnu_unwind_pr_common (state, ucbp, context, 0);
511
}
512
 
513
_Unwind_Reason_Code
514
__aeabi_unwind_cpp_pr1 (_Unwind_State state,
515
                        _Unwind_Control_Block *ucbp,
516
                        _Unwind_Context *context)
517
{
518
  return __gnu_unwind_pr_common (state, ucbp, context, 1);
519
}
520
 
521
_Unwind_Reason_Code
522
__aeabi_unwind_cpp_pr2 (_Unwind_State state,
523
                        _Unwind_Control_Block *ucbp,
524
                        _Unwind_Context *context)
525
{
526
  return __gnu_unwind_pr_common (state, ucbp, context, 2);
527
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.