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