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