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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [xtensa/] [unwind-dw2-xtensa.c] - Blame information for rev 747

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

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

powered by: WebSVN 2.1.0

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