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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [config/] [xtensa/] [unwind-dw2-xtensa.c] - Blame information for rev 826

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 282 jeremybenn
/* DWARF2 exception handling and frame unwinding for Xtensa.
2
   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3
   2007, 2008, 2009
4
   Free Software Foundation, Inc.
5
 
6
   This file is part of GCC.
7
 
8
   GCC is free software; you can redistribute it and/or modify it
9
   under the terms of the GNU General Public License as published by
10
   the Free Software Foundation; either version 3, or (at your option)
11
   any later version.
12
 
13
   GCC is distributed in the hope that it will be useful, but WITHOUT
14
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16
   License for more details.
17
 
18
   Under Section 7 of GPL version 3, you are granted additional
19
   permissions described in the GCC Runtime Library Exception, version
20
   3.1, as published by the Free Software Foundation.
21
 
22
   You should have received a copy of the GNU General Public License and
23
   a copy of the GCC Runtime Library Exception along with this program;
24
   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
25
   <http://www.gnu.org/licenses/>.  */
26
 
27
#include "tconfig.h"
28
#include "tsystem.h"
29
#include "coretypes.h"
30
#include "tm.h"
31
#include "dwarf2.h"
32
#include "unwind.h"
33
#ifdef __USING_SJLJ_EXCEPTIONS__
34
# define NO_SIZE_OF_ENCODED_VALUE
35
#endif
36
#include "unwind-pe.h"
37
#include "unwind-dw2-fde.h"
38
#include "unwind-dw2-xtensa.h"
39
 
40
#ifndef __USING_SJLJ_EXCEPTIONS__
41
 
42
/* The standard CIE and FDE structures work fine for Xtensa but the
43
   variable-size register window save areas are not a good fit for the rest
44
   of the standard DWARF unwinding mechanism.  Nor is that mechanism
45
   necessary, since the register save areas are always in fixed locations
46
   in each stack frame.  This file is a stripped down and customized version
47
   of the standard DWARF unwinding code.  It needs to be customized to have
48
   builtin logic for finding the save areas and also to track the stack
49
   pointer value (besides the CFA) while unwinding since the primary save
50
   area is located below the stack pointer.  It is stripped down to reduce
51
   code size and ease the maintenance burden of tracking changes in the
52
   standard version of the code.  */
53
 
54
#ifndef DWARF_REG_TO_UNWIND_COLUMN
55
#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
56
#endif
57
 
58
#define XTENSA_RA_FIELD_MASK 0x3FFFFFFF
59
 
60
/* This is the register and unwind state for a particular frame.  This
61
   provides the information necessary to unwind up past a frame and return
62
   to its caller.  */
63
struct _Unwind_Context
64
{
65
  /* Track register window save areas of 4 registers each, instead of
66
     keeping separate addresses for the individual registers.  */
67
  _Unwind_Word *reg[4];
68
 
69
  void *cfa;
70
  void *sp;
71
  void *ra;
72
 
73
  /* Cache the 2 high bits to replace the window size in return addresses.  */
74
  _Unwind_Word ra_high_bits;
75
 
76
  void *lsda;
77
  struct dwarf_eh_bases bases;
78
  /* Signal frame context.  */
79
#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
80
  _Unwind_Word flags;
81
  /* 0 for now, can be increased when further fields are added to
82
     struct _Unwind_Context.  */
83
  _Unwind_Word version;
84
};
85
 
86
 
87
/* Read unaligned data from the instruction buffer.  */
88
 
89
union unaligned
90
{
91
  void *p;
92
} __attribute__ ((packed));
93
 
94
static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *);
95
static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *,
96
                                               _Unwind_FrameState *);
97
 
98
static inline void *
99
read_pointer (const void *p) { const union unaligned *up = p; return up->p; }
100
 
101
static inline _Unwind_Word
102
_Unwind_IsSignalFrame (struct _Unwind_Context *context)
103
{
104
  return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0;
105
}
106
 
107
static inline void
108
_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val)
109
{
110
  if (val)
111
    context->flags |= SIGNAL_FRAME_BIT;
112
  else
113
    context->flags &= ~SIGNAL_FRAME_BIT;
114
}
115
 
116
/* Get the value of register INDEX as saved in CONTEXT.  */
117
 
118
inline _Unwind_Word
119
_Unwind_GetGR (struct _Unwind_Context *context, int index)
120
{
121
  _Unwind_Word *ptr;
122
 
123
  index = DWARF_REG_TO_UNWIND_COLUMN (index);
124
  ptr = context->reg[index >> 2] + (index & 3);
125
 
126
  return *ptr;
127
}
128
 
129
/* Get the value of the CFA as saved in CONTEXT.  */
130
 
131
_Unwind_Word
132
_Unwind_GetCFA (struct _Unwind_Context *context)
133
{
134
  return (_Unwind_Ptr) context->cfa;
135
}
136
 
137
/* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
138
 
139
inline void
140
_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
141
{
142
  _Unwind_Word *ptr;
143
 
144
  index = DWARF_REG_TO_UNWIND_COLUMN (index);
145
  ptr = context->reg[index >> 2] + (index & 3);
146
 
147
  *ptr = val;
148
}
149
 
150
/* Retrieve the return address for CONTEXT.  */
151
 
152
inline _Unwind_Ptr
153
_Unwind_GetIP (struct _Unwind_Context *context)
154
{
155
  return (_Unwind_Ptr) context->ra;
156
}
157
 
158
/* Retrieve the return address and flag whether that IP is before
159
   or after first not yet fully executed instruction.  */
160
 
161
inline _Unwind_Ptr
162
_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
163
{
164
  *ip_before_insn = _Unwind_IsSignalFrame (context);
165
  return (_Unwind_Ptr) context->ra;
166
}
167
 
168
/* Overwrite the return address for CONTEXT with VAL.  */
169
 
170
inline void
171
_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
172
{
173
  context->ra = (void *) val;
174
}
175
 
176
void *
177
_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
178
{
179
  return context->lsda;
180
}
181
 
182
_Unwind_Ptr
183
_Unwind_GetRegionStart (struct _Unwind_Context *context)
184
{
185
  return (_Unwind_Ptr) context->bases.func;
186
}
187
 
188
void *
189
_Unwind_FindEnclosingFunction (void *pc)
190
{
191
  struct dwarf_eh_bases bases;
192
  const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases);
193
  if (fde)
194
    return bases.func;
195
  else
196
    return NULL;
197
}
198
 
199
_Unwind_Ptr
200
_Unwind_GetDataRelBase (struct _Unwind_Context *context)
201
{
202
  return (_Unwind_Ptr) context->bases.dbase;
203
}
204
 
205
_Unwind_Ptr
206
_Unwind_GetTextRelBase (struct _Unwind_Context *context)
207
{
208
  return (_Unwind_Ptr) context->bases.tbase;
209
}
210
 
211
#ifdef MD_UNWIND_SUPPORT
212
#include MD_UNWIND_SUPPORT
213
#endif
214
 
215
/* Extract any interesting information from the CIE for the translation
216
   unit F belongs to.  Return a pointer to the byte after the augmentation,
217
   or NULL if we encountered an undecipherable augmentation.  */
218
 
219
static const unsigned char *
220
extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
221
                  _Unwind_FrameState *fs)
222
{
223
  const unsigned char *aug = cie->augmentation;
224
  const unsigned char *p = aug + strlen ((const char *)aug) + 1;
225
  const unsigned char *ret = NULL;
226
  _uleb128_t utmp;
227
  _sleb128_t stmp;
228
 
229
  /* g++ v2 "eh" has pointer immediately following augmentation string,
230
     so it must be handled first.  */
231
  if (aug[0] == 'e' && aug[1] == 'h')
232
    {
233
      fs->eh_ptr = read_pointer (p);
234
      p += sizeof (void *);
235
      aug += 2;
236
    }
237
 
238
  /* Immediately following the augmentation are the code and
239
     data alignment and return address column.  */
240
  p = read_uleb128 (p, &utmp);
241
  p = read_sleb128 (p, &stmp);
242
  if (cie->version == 1)
243
    fs->retaddr_column = *p++;
244
  else
245
    {
246
      p = read_uleb128 (p, &utmp);
247
      fs->retaddr_column = (_Unwind_Word)utmp;
248
    }
249
  fs->lsda_encoding = DW_EH_PE_omit;
250
 
251
  /* If the augmentation starts with 'z', then a uleb128 immediately
252
     follows containing the length of the augmentation field following
253
     the size.  */
254
  if (*aug == 'z')
255
    {
256
      p = read_uleb128 (p, &utmp);
257
      ret = p + utmp;
258
 
259
      fs->saw_z = 1;
260
      ++aug;
261
    }
262
 
263
  /* Iterate over recognized augmentation subsequences.  */
264
  while (*aug != '\0')
265
    {
266
      /* "L" indicates a byte showing how the LSDA pointer is encoded.  */
267
      if (aug[0] == 'L')
268
        {
269
          fs->lsda_encoding = *p++;
270
          aug += 1;
271
        }
272
 
273
      /* "R" indicates a byte indicating how FDE addresses are encoded.  */
274
      else if (aug[0] == 'R')
275
        {
276
          fs->fde_encoding = *p++;
277
          aug += 1;
278
        }
279
 
280
      /* "P" indicates a personality routine in the CIE augmentation.  */
281
      else if (aug[0] == 'P')
282
        {
283
          _Unwind_Ptr personality;
284
 
285
          p = read_encoded_value (context, *p, p + 1, &personality);
286
          fs->personality = (_Unwind_Personality_Fn) personality;
287
          aug += 1;
288
        }
289
 
290
      /* "S" indicates a signal frame.  */
291
      else if (aug[0] == 'S')
292
        {
293
          fs->signal_frame = 1;
294
          aug += 1;
295
        }
296
 
297
      /* Otherwise we have an unknown augmentation string.
298
         Bail unless we saw a 'z' prefix.  */
299
      else
300
        return ret;
301
    }
302
 
303
  return ret ? ret : p;
304
}
305
 
306
/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for
307
   its caller and decode it into FS.  This function also sets the
308
   lsda member of CONTEXT, as it is really information
309
   about the caller's frame.  */
310
 
311
static _Unwind_Reason_Code
312
uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
313
{
314
  const struct dwarf_fde *fde;
315
  const struct dwarf_cie *cie;
316
  const unsigned char *aug;
317
  int window_size;
318
  _Unwind_Word *ra_ptr;
319
 
320
  memset (fs, 0, sizeof (*fs));
321
  context->lsda = 0;
322
 
323
  fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1,
324
                          &context->bases);
325
  if (fde == NULL)
326
    {
327
#ifdef MD_FALLBACK_FRAME_STATE_FOR
328
      _Unwind_Reason_Code reason;
329
      /* Couldn't find frame unwind info for this function.  Try a
330
         target-specific fallback mechanism.  This will necessarily
331
         not provide a personality routine or LSDA.  */
332
      reason = MD_FALLBACK_FRAME_STATE_FOR (context, fs);
333
      if (reason != _URC_END_OF_STACK)
334
        return reason;
335
#endif
336
      /* The frame was not recognized and handled by the fallback function,
337
         but it is not really the end of the stack.  Fall through here and
338
         unwind it anyway.  */
339
    }
340
  else
341
    {
342
      cie = get_cie (fde);
343
      if (extract_cie_info (cie, context, fs) == NULL)
344
        /* CIE contained unknown augmentation.  */
345
        return _URC_FATAL_PHASE1_ERROR;
346
 
347
      /* Locate augmentation for the fde.  */
348
      aug = (const unsigned char *) fde + sizeof (*fde);
349
      aug += 2 * size_of_encoded_value (fs->fde_encoding);
350
      if (fs->saw_z)
351
        {
352
          _uleb128_t i;
353
          aug = read_uleb128 (aug, &i);
354
        }
355
      if (fs->lsda_encoding != DW_EH_PE_omit)
356
        {
357
          _Unwind_Ptr lsda;
358
 
359
          aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda);
360
          context->lsda = (void *) lsda;
361
        }
362
    }
363
 
364
  /* Check for the end of the stack.  This needs to be checked after
365
     the MD_FALLBACK_FRAME_STATE_FOR check for signal frames because
366
     the contents of context->reg[0] are undefined at a signal frame,
367
     and register a0 may appear to be zero.  (The return address in
368
     context->ra comes from register a4 or a8).  */
369
  ra_ptr = context->reg[0];
370
  if (ra_ptr && *ra_ptr == 0)
371
    return _URC_END_OF_STACK;
372
 
373
  /* Find the window size from the high bits of the return address.  */
374
  if (ra_ptr)
375
    window_size = (*ra_ptr >> 30) * 4;
376
  else
377
    window_size = 8;
378
 
379
  fs->retaddr_column = window_size;
380
 
381
  return _URC_NO_REASON;
382
}
383
 
384
static void
385
uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
386
{
387
  struct _Unwind_Context orig_context = *context;
388
  _Unwind_Word *sp, *cfa, *next_cfa;
389
  int i;
390
 
391
  if (fs->signal_regs)
392
    {
393
      cfa = (_Unwind_Word *) fs->signal_regs[1];
394
      next_cfa = (_Unwind_Word *) cfa[-3];
395
 
396
      for (i = 0; i < 4; i++)
397
        context->reg[i] = fs->signal_regs + (i << 2);
398
    }
399
  else
400
    {
401
      int window_size = fs->retaddr_column >> 2;
402
 
403
      sp = (_Unwind_Word *) orig_context.sp;
404
      cfa = (_Unwind_Word *) orig_context.cfa;
405
      next_cfa = (_Unwind_Word *) cfa[-3];
406
 
407
      /* Registers a0-a3 are in the save area below sp.  */
408
      context->reg[0] = sp - 4;
409
 
410
      /* Find the extra save area below next_cfa.  */
411
      for (i = 1; i < window_size; i++)
412
        context->reg[i] = next_cfa - 4 * (1 + window_size - i);
413
 
414
      /* Remaining registers rotate from previous save areas.  */
415
      for (i = window_size; i < 4; i++)
416
        context->reg[i] = orig_context.reg[i - window_size];
417
    }
418
 
419
  context->sp = cfa;
420
  context->cfa = next_cfa;
421
 
422
  _Unwind_SetSignalFrame (context, fs->signal_frame);
423
}
424
 
425
/* CONTEXT describes the unwind state for a frame, and FS describes the FDE
426
   of its caller.  Update CONTEXT to refer to the caller as well.  Note
427
   that the lsda member is not updated here, but later in
428
   uw_frame_state_for.  */
429
 
430
static void
431
uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
432
{
433
  uw_update_context_1 (context, fs);
434
 
435
  /* Compute the return address now, since the return address column
436
     can change from frame to frame.  */
437
  if (fs->signal_ra != 0)
438
    context->ra = (void *) fs->signal_ra;
439
  else
440
    context->ra = (void *) ((_Unwind_GetGR (context, fs->retaddr_column)
441
                             & XTENSA_RA_FIELD_MASK) | context->ra_high_bits);
442
}
443
 
444
static void
445
uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
446
{
447
  uw_update_context (context, fs);
448
}
449
 
450
/* Fill in CONTEXT for top-of-stack.  The only valid registers at this
451
   level will be the return address and the CFA.  */
452
 
453
#define uw_init_context(CONTEXT)                                           \
454
  do                                                                       \
455
    {                                                                      \
456
      __builtin_unwind_init ();                                            \
457
      uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (),                  \
458
                         __builtin_return_address (0));                     \
459
    }                                                                      \
460
  while (0)
461
 
462
static void __attribute__((noinline))
463
uw_init_context_1 (struct _Unwind_Context *context, void *outer_cfa,
464
                   void *outer_ra)
465
{
466
  void *ra = __builtin_return_address (0);
467
  void *cfa = __builtin_dwarf_cfa ();
468
  _Unwind_FrameState fs;
469
 
470
  memset (context, 0, sizeof (struct _Unwind_Context));
471
  context->ra = ra;
472
 
473
  memset (&fs, 0, sizeof (fs));
474
  fs.retaddr_column = 8;
475
  context->sp = cfa;
476
  context->cfa = outer_cfa;
477
  context->ra_high_bits =
478
    ((_Unwind_Word) uw_init_context_1) & ~XTENSA_RA_FIELD_MASK;
479
  uw_update_context_1 (context, &fs);
480
 
481
  context->ra = outer_ra;
482
}
483
 
484
 
485
/* Install TARGET into CURRENT so that we can return to it.  This is a
486
   macro because __builtin_eh_return must be invoked in the context of
487
   our caller.  */
488
 
489
#define uw_install_context(CURRENT, TARGET)                              \
490
  do                                                                     \
491
    {                                                                    \
492
      long offset = uw_install_context_1 ((CURRENT), (TARGET));          \
493
      void *handler = __builtin_frob_return_addr ((TARGET)->ra);         \
494
      __builtin_eh_return (offset, handler);                             \
495
    }                                                                    \
496
  while (0)
497
 
498
static long
499
uw_install_context_1 (struct _Unwind_Context *current,
500
                      struct _Unwind_Context *target)
501
{
502
  long i;
503
 
504
  /* The eh_return insn assumes a window size of 8, so don't bother copying
505
     the save areas for registers a8-a15 since they won't be reloaded.  */
506
  for (i = 0; i < 2; ++i)
507
    {
508
      void *c = current->reg[i];
509
      void *t = target->reg[i];
510
 
511
      if (t && c && t != c)
512
        memcpy (c, t, 4 * sizeof (_Unwind_Word));
513
    }
514
 
515
  return 0;
516
}
517
 
518
static inline _Unwind_Ptr
519
uw_identify_context (struct _Unwind_Context *context)
520
{
521
  return _Unwind_GetCFA (context);
522
}
523
 
524
 
525
#include "unwind.inc"
526
 
527
#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
528
alias (_Unwind_Backtrace);
529
alias (_Unwind_DeleteException);
530
alias (_Unwind_FindEnclosingFunction);
531
alias (_Unwind_ForcedUnwind);
532
alias (_Unwind_GetDataRelBase);
533
alias (_Unwind_GetTextRelBase);
534
alias (_Unwind_GetCFA);
535
alias (_Unwind_GetGR);
536
alias (_Unwind_GetIP);
537
alias (_Unwind_GetLanguageSpecificData);
538
alias (_Unwind_GetRegionStart);
539
alias (_Unwind_RaiseException);
540
alias (_Unwind_Resume);
541
alias (_Unwind_Resume_or_Rethrow);
542
alias (_Unwind_SetGR);
543
alias (_Unwind_SetIP);
544
#endif
545
 
546
#endif /* !USING_SJLJ_EXCEPTIONS */

powered by: WebSVN 2.1.0

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