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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [arm/] [pr-support.c] - Blame information for rev 758

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
/* We add a prototype for abort here to avoid creating a dependency on
27
   target headers.  */
28
extern void abort (void);
29
 
30
typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
31
 
32
/* Misc constants.  */
33
#define R_IP    12
34
#define R_SP    13
35
#define R_LR    14
36
#define R_PC    15
37
 
38
#define uint32_highbit (((_uw) 1) << 31)
39
 
40
void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
41
 
42
/* Unwind descriptors.  */
43
 
44
typedef struct
45
{
46
  _uw16 length;
47
  _uw16 offset;
48
} EHT16;
49
 
50
typedef struct
51
{
52
  _uw length;
53
  _uw offset;
54
} EHT32;
55
 
56
/* Calculate the address encoded by a 31-bit self-relative offset at address
57
   P.  Copy of routine in unwind-arm.c.  */
58
 
59
static inline _uw
60
selfrel_offset31 (const _uw *p)
61
{
62
  _uw offset;
63
 
64
  offset = *p;
65
  /* Sign extend to 32 bits.  */
66
  if (offset & (1 << 30))
67
    offset |= 1u << 31;
68
 
69
  return offset + (_uw) p;
70
}
71
 
72
 
73
/* Personality routine helper functions.  */
74
 
75
#define CODE_FINISH (0xb0)
76
 
77
/* Return the next byte of unwinding information, or CODE_FINISH if there is
78
   no data remaining.  */
79
static inline _uw8
80
next_unwind_byte (__gnu_unwind_state * uws)
81
{
82
  _uw8 b;
83
 
84
  if (uws->bytes_left == 0)
85
    {
86
      /* Load another word */
87
      if (uws->words_left == 0)
88
        return CODE_FINISH; /* Nothing left.  */
89
      uws->words_left--;
90
      uws->data = *(uws->next++);
91
      uws->bytes_left = 3;
92
    }
93
  else
94
    uws->bytes_left--;
95
 
96
  /* Extract the most significant byte.  */
97
  b = (uws->data >> 24) & 0xff;
98
  uws->data <<= 8;
99
  return b;
100
}
101
 
102
/* Execute the unwinding instructions described by UWS.  */
103
_Unwind_Reason_Code
104
__gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
105
{
106
  _uw op;
107
  int set_pc;
108
  _uw reg;
109
 
110
  set_pc = 0;
111
  for (;;)
112
    {
113
      op = next_unwind_byte (uws);
114
      if (op == CODE_FINISH)
115
        {
116
          /* If we haven't already set pc then copy it from lr.  */
117
          if (!set_pc)
118
            {
119
              _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
120
                               &reg);
121
              _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
122
                               &reg);
123
              set_pc = 1;
124
            }
125
          /* Drop out of the loop.  */
126
          break;
127
        }
128
      if ((op & 0x80) == 0)
129
        {
130
          /* vsp = vsp +- (imm6 << 2 + 4).  */
131
          _uw offset;
132
 
133
          offset = ((op & 0x3f) << 2) + 4;
134
          _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
135
          if (op & 0x40)
136
            reg -= offset;
137
          else
138
            reg += offset;
139
          _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
140
          continue;
141
        }
142
 
143
      if ((op & 0xf0) == 0x80)
144
        {
145
          op = (op << 8) | next_unwind_byte (uws);
146
          if (op == 0x8000)
147
            {
148
              /* Refuse to unwind.  */
149
              return _URC_FAILURE;
150
            }
151
          /* Pop r4-r15 under mask.  */
152
          op = (op << 4) & 0xfff0;
153
          if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
154
              != _UVRSR_OK)
155
            return _URC_FAILURE;
156
          if (op & (1 << R_PC))
157
            set_pc = 1;
158
          continue;
159
        }
160
      if ((op & 0xf0) == 0x90)
161
        {
162
          op &= 0xf;
163
          if (op == 13 || op == 15)
164
            /* Reserved.  */
165
            return _URC_FAILURE;
166
          /* vsp = r[nnnn].  */
167
          _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
168
          _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
169
          continue;
170
        }
171
      if ((op & 0xf0) == 0xa0)
172
        {
173
          /* Pop r4-r[4+nnn], [lr].  */
174
          _uw mask;
175
 
176
          mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
177
          if (op & 8)
178
            mask |= (1 << R_LR);
179
          if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32)
180
              != _UVRSR_OK)
181
            return _URC_FAILURE;
182
          continue;
183
        }
184
      if ((op & 0xf0) == 0xb0)
185
        {
186
          /* op == 0xb0 already handled.  */
187
          if (op == 0xb1)
188
            {
189
              op = next_unwind_byte (uws);
190
              if (op == 0 || ((op & 0xf0) != 0))
191
                /* Spare.  */
192
                return _URC_FAILURE;
193
              /* Pop r0-r4 under mask.  */
194
              if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
195
                  != _UVRSR_OK)
196
                return _URC_FAILURE;
197
              continue;
198
            }
199
          if (op == 0xb2)
200
            {
201
              /* vsp = vsp + 0x204 + (uleb128 << 2).  */
202
              int shift;
203
 
204
              _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
205
                               &reg);
206
              op = next_unwind_byte (uws);
207
              shift = 2;
208
              while (op & 0x80)
209
                {
210
                  reg += ((op & 0x7f) << shift);
211
                  shift += 7;
212
                  op = next_unwind_byte (uws);
213
                }
214
              reg += ((op & 0x7f) << shift) + 0x204;
215
              _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
216
                               &reg);
217
              continue;
218
            }
219
          if (op == 0xb3)
220
            {
221
              /* Pop VFP registers with fldmx.  */
222
              op = next_unwind_byte (uws);
223
              op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
224
              if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
225
                  != _UVRSR_OK)
226
                return _URC_FAILURE;
227
              continue;
228
            }
229
          if ((op & 0xfc) == 0xb4)
230
            {
231
              /* Pop FPA E[4]-E[4+nn].  */
232
              op = 0x40000 | ((op & 3) + 1);
233
              if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
234
                  != _UVRSR_OK)
235
                return _URC_FAILURE;
236
              continue;
237
            }
238
          /* op & 0xf8 == 0xb8.  */
239
          /* Pop VFP D[8]-D[8+nnn] with fldmx.  */
240
          op = 0x80000 | ((op & 7) + 1);
241
          if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
242
              != _UVRSR_OK)
243
            return _URC_FAILURE;
244
          continue;
245
        }
246
      if ((op & 0xf0) == 0xc0)
247
        {
248
          if (op == 0xc6)
249
            {
250
              /* Pop iWMMXt D registers.  */
251
              op = next_unwind_byte (uws);
252
              op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
253
              if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
254
                  != _UVRSR_OK)
255
                return _URC_FAILURE;
256
              continue;
257
            }
258
          if (op == 0xc7)
259
            {
260
              op = next_unwind_byte (uws);
261
              if (op == 0 || (op & 0xf0) != 0)
262
                /* Spare.  */
263
                return _URC_FAILURE;
264
              /* Pop iWMMXt wCGR{3,2,1,0} under mask.  */
265
              if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
266
                  != _UVRSR_OK)
267
                return _URC_FAILURE;
268
              continue;
269
            }
270
          if ((op & 0xf8) == 0xc0)
271
            {
272
              /* Pop iWMMXt wR[10]-wR[10+nnn].  */
273
              op = 0xa0000 | ((op & 0xf) + 1);
274
              if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
275
                  != _UVRSR_OK)
276
                return _URC_FAILURE;
277
              continue;
278
            }
279
          if (op == 0xc8)
280
            {
281
#ifndef __VFP_FP__
282
              /* Pop FPA registers.  */
283
              op = next_unwind_byte (uws);
284
              op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
285
              if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
286
                  != _UVRSR_OK)
287
                return _URC_FAILURE;
288
              continue;
289
#else
290
              /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm.  */
291
              op = next_unwind_byte (uws);
292
              op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
293
              if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
294
                  != _UVRSR_OK)
295
                return _URC_FAILURE;
296
              continue;
297
#endif
298
            }
299
          if (op == 0xc9)
300
            {
301
              /* Pop VFP registers with fldmd.  */
302
              op = next_unwind_byte (uws);
303
              op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
304
              if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
305
                  != _UVRSR_OK)
306
                return _URC_FAILURE;
307
              continue;
308
            }
309
          /* Spare.  */
310
          return _URC_FAILURE;
311
        }
312
      if ((op & 0xf8) == 0xd0)
313
        {
314
          /* Pop VFP D[8]-D[8+nnn] with fldmd.  */
315
          op = 0x80000 | ((op & 7) + 1);
316
          if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
317
              != _UVRSR_OK)
318
            return _URC_FAILURE;
319
          continue;
320
        }
321
      /* Spare.  */
322
      return _URC_FAILURE;
323
    }
324
  return _URC_OK;
325
}
326
 
327
 
328
/* Execute the unwinding instructions associated with a frame.  UCBP and
329
   CONTEXT are the current exception object and virtual CPU state
330
   respectively.  */
331
 
332
_Unwind_Reason_Code
333
__gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
334
{
335
  _uw *ptr;
336
  __gnu_unwind_state uws;
337
 
338
  ptr = (_uw *) ucbp->pr_cache.ehtp;
339
  /* Skip over the personality routine address.  */
340
  ptr++;
341
  /* Setup the unwinder state.  */
342
  uws.data = (*ptr) << 8;
343
  uws.next = ptr + 1;
344
  uws.bytes_left = 3;
345
  uws.words_left = ((*ptr) >> 24) & 0xff;
346
 
347
  return __gnu_unwind_execute (context, &uws);
348
}
349
 
350
/* Get the _Unwind_Control_Block from an _Unwind_Context.  */
351
 
352
static inline _Unwind_Control_Block *
353
unwind_UCB_from_context (_Unwind_Context * context)
354
{
355
  return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
356
}
357
 
358
/* Get the start address of the function being unwound.  */
359
 
360
_Unwind_Ptr
361
_Unwind_GetRegionStart (_Unwind_Context * context)
362
{
363
  _Unwind_Control_Block *ucbp;
364
 
365
  ucbp = unwind_UCB_from_context (context);
366
  return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
367
}
368
 
369
/* Find the Language specific exception data.  */
370
 
371
void *
372
_Unwind_GetLanguageSpecificData (_Unwind_Context * context)
373
{
374
  _Unwind_Control_Block *ucbp;
375
  _uw *ptr;
376
 
377
  /* Get a pointer to the exception table entry.  */
378
  ucbp = unwind_UCB_from_context (context);
379
  ptr = (_uw *) ucbp->pr_cache.ehtp;
380
  /* Skip the personality routine address.  */
381
  ptr++;
382
  /* Skip the unwind opcodes.  */
383
  ptr += (((*ptr) >> 24) & 0xff) + 1;
384
 
385
  return ptr;
386
}
387
 
388
 
389
/* These two should never be used.  */
390
 
391
_Unwind_Ptr
392
_Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused)))
393
{
394
  abort ();
395
}
396
 
397
_Unwind_Ptr
398
_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
399
{
400
  abort ();
401
}

powered by: WebSVN 2.1.0

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