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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [arm/] [pr-support.c] - Blame information for rev 856

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

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

powered by: WebSVN 2.1.0

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