Mercurial > hg > CbC > CbC_gcc
comparison gcc/config/xtensa/unwind-dw2-xtensa.c @ 0:a06113de4d67
first commit
author | kent <kent@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2009 14:47:48 +0900 |
parents | |
children | 77e2b8dfacca |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a06113de4d67 |
---|---|
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, 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 | |
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 */ |