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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [c6x/] [pr-support.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
/* C6X ABI compliant unwinding routines
2
   Copyright (C) 2011 Free Software Foundation, Inc.
3
 
4
   This file is free software; you can redistribute it and/or modify it
5
   under the terms of the GNU General Public License as published by the
6
   Free Software Foundation; either version 3, or (at your option) any
7
   later version.
8
 
9
   This file is distributed in the hope that it will be useful, but
10
   WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
   General Public License for more details.
13
 
14
   Under Section 7 of GPL version 3, you are granted additional
15
   permissions described in the GCC Runtime Library Exception, version
16
   3.1, as published by the Free Software Foundation.
17
 
18
   You should have received a copy of the GNU General Public License and
19
   a copy of the GCC Runtime Library Exception along with this program;
20
   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
21
   <http://www.gnu.org/licenses/>.  */
22
 
23
#include "unwind.h"
24
 
25
/* We add a prototype for abort here to avoid creating a dependency on
26
   target headers.  */
27
extern void abort (void);
28
 
29
typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
30
 
31
/* Misc constants.  */
32
#define R_A0 0
33
#define R_A1 1
34
#define R_A2 2
35
#define R_A3 3
36
#define R_A4 4
37
#define R_A5 5
38
#define R_A6 6
39
#define R_A7 7
40
#define R_A8 8
41
#define R_A9 9
42
#define R_A10 10
43
#define R_A11 11
44
#define R_A12 12
45
#define R_A13 13
46
#define R_A14 14
47
#define R_A15 15
48
#define R_B0 16
49
#define R_B1 17
50
#define R_B2 18
51
#define R_B3 19
52
#define R_B4 20
53
#define R_B5 21
54
#define R_B6 22
55
#define R_B7 23
56
#define R_B8 24
57
#define R_B9 25
58
#define R_B10 26
59
#define R_B11 27
60
#define R_B12 28
61
#define R_B13 29
62
#define R_B14 30
63
#define R_B15 31
64
 
65
#define R_SP R_B15
66
#define R_PC 33
67
 
68
#define uint32_highbit (((_uw) 1) << 31)
69
 
70
void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
71
 
72
/* Unwind descriptors.  */
73
 
74
typedef struct
75
{
76
  _uw16 length;
77
  _uw16 offset;
78
} EHT16;
79
 
80
typedef struct
81
{
82
  _uw length;
83
  _uw offset;
84
} EHT32;
85
 
86
/* Calculate the address encoded by a 31-bit self-relative offset at address
87
   P.  Copy of routine in unwind-arm.c.  */
88
 
89
static inline _uw
90
selfrel_offset31 (const _uw *p)
91
{
92
  _uw offset;
93
 
94
  offset = *p;
95
  /* Sign extend to 32 bits.  */
96
  if (offset & (1 << 30))
97
    offset |= 1u << 31;
98
 
99
  return offset + (_uw) p;
100
}
101
 
102
 
103
/* Personality routine helper functions.  */
104
 
105
#define CODE_FINISH (0xe7)
106
 
107
/* Return the next byte of unwinding information, or CODE_FINISH if there is
108
   no data remaining.  */
109
static inline _uw8
110
next_unwind_byte (__gnu_unwind_state * uws)
111
{
112
  _uw8 b;
113
 
114
  if (uws->bytes_left == 0)
115
    {
116
      /* Load another word */
117
      if (uws->words_left == 0)
118
        return CODE_FINISH; /* Nothing left.  */
119
      uws->words_left--;
120
      uws->data = *(uws->next++);
121
      uws->bytes_left = 3;
122
    }
123
  else
124
    uws->bytes_left--;
125
 
126
  /* Extract the most significant byte.  */
127
  b = (uws->data >> 24) & 0xff;
128
  uws->data <<= 8;
129
  return b;
130
}
131
 
132
static void
133
unwind_restore_pair (_Unwind_Context * context, int reg, _uw *ptr)
134
{
135
#ifdef _BIG_ENDIAN
136
  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32, ptr + 1);
137
  _Unwind_VRS_Set (context, _UVRSC_CORE, reg + 1, _UVRSD_UINT32, ptr);
138
#else
139
  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32, ptr);
140
  _Unwind_VRS_Set (context, _UVRSC_CORE, reg + 1, _UVRSD_UINT32, ptr + 1);
141
#endif
142
}
143
 
144
static const int
145
unwind_frame_regs[13] =
146
{
147
  R_A15, R_B15, R_B14, R_B13, R_B12, R_B11, R_B10, R_B3,
148
  R_A14, R_A13, R_A12, R_A11, R_A10
149
};
150
 
151
static void
152
pop_compact_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
153
{
154
  int size;
155
  _uw test;
156
  int i, regno, nregs;
157
 
158
  size = 0;
159
  nregs = __builtin_popcount (mask);
160
  for (i = 0; i < 13; i++)
161
    {
162
      test = 1 << i;
163
      if ((mask & test) == 0)
164
        continue;
165
 
166
      regno = unwind_frame_regs[12 - i];
167
 
168
      if (i < 12 && nregs > 2
169
          && (mask & (test << 1)) != 0
170
          && unwind_frame_regs[11 - i] == regno + 1
171
          && (regno & 1) == 0)
172
        {
173
          i++;
174
          nregs--;
175
        }
176
 
177
      nregs--;
178
      size += 2;
179
    }
180
 
181
  if (!inc_sp)
182
    ptr -= size;
183
 
184
  /* SP points just past the end of the stack.  */
185
  ptr += 2;
186
  nregs = __builtin_popcount (mask);
187
  for (i = 0; i < 13; i++)
188
    {
189
      test = 1 << i;
190
      if ((mask & test) == 0)
191
        continue;
192
 
193
      regno = unwind_frame_regs[12 - i];
194
 
195
      if (i < 12 && nregs > 2
196
          && (mask & (test << 1)) != 0
197
          && unwind_frame_regs[11 - i] == regno + 1
198
          && (regno & 1) == 0)
199
        {
200
          /* Register pair.  */
201
          unwind_restore_pair (context, regno, ptr);
202
          i++;
203
          nregs--;
204
        }
205
      else
206
        {
207
          /* Single register with padding.  */
208
          _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, ptr);
209
        }
210
 
211
      nregs--;
212
      ptr += 2;
213
    }
214
 
215
  ptr -= 2;
216
  if ((mask & (1 << 11)) == 0)
217
    _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
218
}
219
 
220
static void
221
pop_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
222
{
223
  int i;
224
  int regno;
225
  int nregs;
226
 
227
  nregs = __builtin_popcount (mask);
228
 
229
  if (!inc_sp)
230
    ptr -= nregs;
231
  else if (nregs & 1)
232
    ptr++;
233
 
234
  ptr++;
235
  for (i = 0; i < 13; i++)
236
    {
237
      if ((mask & (1 << i)) == 0)
238
        continue;
239
      regno = unwind_frame_regs[12 - i];
240
      if (i < 12 && unwind_frame_regs[11 - i] == (regno + 1)
241
          && (mask & (1 << (i + 1))) != 0
242
          && (((_uw)ptr) & 4) == 0
243
          && (regno & 1) == 0)
244
        {
245
          unwind_restore_pair (context, regno, ptr);
246
          i++;
247
          ptr += 2;
248
        }
249
      else
250
        {
251
          _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32,
252
                           ptr);
253
          ptr++;
254
        }
255
    }
256
 
257
  ptr--;
258
  if ((mask & (1 << 11)) == 0)
259
    _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
260
}
261
 
262
/* Unwind a 24-bit encoded frame.  */
263
_Unwind_Reason_Code
264
__gnu_unwind_24bit (_Unwind_Context * context, _uw data, int compact)
265
{
266
  _uw offset;
267
  _uw mask;
268
  _uw *ptr;
269
  _uw tmp;
270
  int ret_reg = unwind_frame_regs[data & 0xf];
271
 
272
  if (ret_reg != R_B3)
273
    {
274
      _Unwind_VRS_Get (context, _UVRSC_CORE, unwind_frame_regs[data & 0xf],
275
                       _UVRSD_UINT32, &tmp);
276
      _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &tmp);
277
    }
278
 
279
  mask = (data >> 4) & 0x1fff;
280
 
281
  offset = (data >> 17) & 0x7f;
282
  if (offset == 0x7f)
283
    _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &ptr);
284
  else
285
    {
286
      _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
287
      ptr += offset * 2;
288
    }
289
 
290
 
291
  if (compact)
292
    pop_compact_frame (context, mask, ptr, offset != 0x7f);
293
  else
294
    pop_frame (context, mask, ptr, offset != 0x7f);
295
 
296
  _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &tmp);
297
  _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &tmp);
298
 
299
  return _URC_OK;
300
}
301
 
302
static void
303
unwind_pop_rts (_Unwind_Context * context)
304
{
305
  _uw *ptr;
306
 
307
  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
308
#ifdef _BIG_ENDIAN
309
  _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ptr + 1);
310
#else
311
  _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ptr + 2);
312
#endif
313
  ptr += 3;
314
  unwind_restore_pair (context, R_A10, ptr);
315
  ptr += 2;
316
  unwind_restore_pair (context, R_B10, ptr);
317
  ptr += 2;
318
  unwind_restore_pair (context, R_A12, ptr);
319
  ptr += 2;
320
  unwind_restore_pair (context, R_B12, ptr);
321
  ptr += 2;
322
  unwind_restore_pair (context, R_A14, ptr);
323
  ptr += 2;
324
  _Unwind_VRS_Set (context, _UVRSC_CORE, R_B14, _UVRSD_UINT32, ptr);
325
  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
326
  /* PC will be set by implicit RETURN opcode.  */
327
}
328
 
329
/* Execute the unwinding instructions described by UWS.  */
330
_Unwind_Reason_Code
331
__gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
332
{
333
  _uw op;
334
  int inc_sp;
335
  _uw reg;
336
  _uw *ptr;
337
 
338
  inc_sp = 1;
339
  for (;;)
340
    {
341
      op = next_unwind_byte (uws);
342
      if (op == CODE_FINISH)
343
        {
344
          /* Drop out of the loop.  */
345
          break;
346
        }
347
      if ((op & 0xc0) == 0)
348
        {
349
          /* sp += (imm6 << 3) + 8.  */
350
          _uw offset;
351
 
352
          offset = ((op & 0x3f) << 3) + 8;
353
          _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
354
          reg += offset;
355
          _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
356
          continue;
357
        }
358
 
359
      if (op == 0xd2)
360
        {
361
          /* vsp = vsp + 0x204 + (uleb128 << 2).  */
362
          int shift;
363
 
364
          _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
365
          op = next_unwind_byte (uws);
366
          shift = 3;
367
          while (op & 0x80)
368
            {
369
              reg += ((op & 0x7f) << shift);
370
              shift += 7;
371
              op = next_unwind_byte (uws);
372
            }
373
          reg += ((op & 0x7f) << shift) + 0x408;
374
          _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
375
          continue;
376
        }
377
 
378
      if ((op & 0xe0) == 0x80)
379
        {
380
          /* POP bitmask */
381
          _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
382
 
383
          if (mask == 0)
384
            {
385
              /* CANTUNWIND */
386
              return _URC_FAILURE;
387
            }
388
 
389
          _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
390
          pop_frame (context, mask, ptr, inc_sp);
391
          continue;
392
        }
393
 
394
      if ((op & 0xe0) == 0xa0)
395
        {
396
          /* POP bitmask (compact) */
397
          _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
398
 
399
          _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
400
          pop_compact_frame (context, mask, ptr, inc_sp);
401
          continue;
402
        }
403
 
404
      if ((op & 0xf0) == 0xc0)
405
        {
406
          /* POP registers */
407
          int nregs = op & 0xf;
408
 
409
          _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
410
          while (nregs > 0)
411
            {
412
              op = next_unwind_byte (uws);
413
              if ((op >> 4) != 0xf)
414
                {
415
                  reg = unwind_frame_regs[op >> 4];
416
                  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
417
                                   ptr);
418
                  nregs--;
419
                }
420
              ptr--;
421
              if ((op & 0xf) != 0xf)
422
                {
423
                  reg = unwind_frame_regs[op & 0xf];
424
                  _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
425
                                   ptr);
426
                  nregs--;
427
                }
428
              ptr--;
429
            }
430
 
431
          continue;
432
        }
433
 
434
      if (op == 0xd0)
435
        {
436
          /* MV FP, SP */
437
          inc_sp = 0;
438
          _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &reg);
439
          _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
440
          continue;
441
        }
442
 
443
      if (op == 0xd1)
444
        {
445
          /* __cx6abi_pop_rts */
446
          unwind_pop_rts (context);
447
          break;
448
        }
449
 
450
      if ((op & 0xf0) == 0xe0)
451
        {
452
          /* B3 = reg.  RETURN case alreadh handled above.  */
453
          int regno = unwind_frame_regs[op & 0xf];
454
 
455
          _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &reg);
456
          _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &reg);
457
          continue;
458
        }
459
 
460
      /* Reserved.  */
461
      return _URC_FAILURE;
462
    }
463
 
464
  /* Implicit RETURN.  */
465
  _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &reg);
466
  _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &reg);
467
  return _URC_OK;
468
}
469
 
470
 
471
/* Execute the unwinding instructions associated with a frame.  UCBP and
472
   CONTEXT are the current exception object and virtual CPU state
473
   respectively.  */
474
 
475
_Unwind_Reason_Code
476
__gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
477
{
478
  _uw *ptr;
479
  __gnu_unwind_state uws;
480
 
481
  ptr = (_uw *) ucbp->pr_cache.ehtp;
482
  /* Skip over the personality routine address.  */
483
  ptr++;
484
  /* Setup the unwinder state.  */
485
  uws.data = (*ptr) << 8;
486
  uws.next = ptr + 1;
487
  uws.bytes_left = 3;
488
  uws.words_left = ((*ptr) >> 24) & 0xff;
489
 
490
  return __gnu_unwind_execute (context, &uws);
491
}
492
 
493
/* Data segment base pointer corresponding to the function catching
494
   the exception.  */
495
 
496
_Unwind_Ptr
497
_Unwind_GetDataRelBase (_Unwind_Context *context)
498
{
499
  return _Unwind_GetGR (context, R_B14);
500
}
501
 
502
/* This should never be used.  */
503
 
504
_Unwind_Ptr
505
_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
506
{
507
  abort ();
508
}
509
 
510
/* Only used by gcc personality routines, so can rely on a value they hid
511
   there earlier.  */
512
_Unwind_Ptr
513
_Unwind_GetRegionStart (_Unwind_Context *context)
514
{
515
  _Unwind_Control_Block *ucbp;
516
 
517
  ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
518
  return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
519
}
520
 
521
void *
522
_Unwind_GetLanguageSpecificData (_Unwind_Context *context)
523
{
524
  _Unwind_Control_Block *ucbp;
525
  _uw *ptr;
526
 
527
  ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
528
  ptr = (_uw *) ucbp->pr_cache.ehtp;
529
  /* Skip the personality routine address.  */
530
  ptr++;
531
  /* Skip the unwind opcodes.  */
532
  ptr += (((*ptr) >> 24) & 0xff) + 1;
533
 
534
  return ptr;
535
}

powered by: WebSVN 2.1.0

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