OSDN Git Service

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