* builtins.def (BUILT_IN_SETJMP): Revert latest change.
[official-gcc.git] / libgcc / config / c6x / pr-support.c
blobf1ab7ad2f7d68f336d6549e215e6452f9f5f6563
1 /* C6X ABI compliant unwinding routines
2 Copyright (C) 2011-2017 Free Software Foundation, Inc.
4 This file is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3, or (at your option) any
7 later version.
9 This file is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 Under Section 7 of GPL version 3, you are granted additional
15 permissions described in the GCC Runtime Library Exception, version
16 3.1, as published by the Free Software Foundation.
18 You should have received a copy of the GNU General Public License and
19 a copy of the GCC Runtime Library Exception along with this program;
20 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
21 <http://www.gnu.org/licenses/>. */
23 #include "unwind.h"
25 /* We add a prototype for abort here to avoid creating a dependency on
26 target headers. */
27 extern void abort (void);
29 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
31 /* Misc constants. */
32 #define R_A0 0
33 #define R_A1 1
34 #define R_A2 2
35 #define R_A3 3
36 #define R_A4 4
37 #define R_A5 5
38 #define R_A6 6
39 #define R_A7 7
40 #define R_A8 8
41 #define R_A9 9
42 #define R_A10 10
43 #define R_A11 11
44 #define R_A12 12
45 #define R_A13 13
46 #define R_A14 14
47 #define R_A15 15
48 #define R_B0 16
49 #define R_B1 17
50 #define R_B2 18
51 #define R_B3 19
52 #define R_B4 20
53 #define R_B5 21
54 #define R_B6 22
55 #define R_B7 23
56 #define R_B8 24
57 #define R_B9 25
58 #define R_B10 26
59 #define R_B11 27
60 #define R_B12 28
61 #define R_B13 29
62 #define R_B14 30
63 #define R_B15 31
65 #define R_SP R_B15
66 #define R_PC 33
68 #define uint32_highbit (((_uw) 1) << 31)
70 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
72 /* Unwind descriptors. */
74 typedef struct
76 _uw16 length;
77 _uw16 offset;
78 } EHT16;
80 typedef struct
82 _uw length;
83 _uw offset;
84 } EHT32;
86 /* Calculate the address encoded by a 31-bit self-relative offset at address
87 P. Copy of routine in unwind-arm.c. */
89 static inline _uw
90 selfrel_offset31 (const _uw *p)
92 _uw offset;
94 offset = *p;
95 /* Sign extend to 32 bits. */
96 if (offset & (1 << 30))
97 offset |= 1u << 31;
99 return offset + (_uw) p;
103 /* Personality routine helper functions. */
105 #define CODE_FINISH (0xe7)
107 /* Return the next byte of unwinding information, or CODE_FINISH if there is
108 no data remaining. */
109 static inline _uw8
110 next_unwind_byte (__gnu_unwind_state * uws)
112 _uw8 b;
114 if (uws->bytes_left == 0)
116 /* Load another word */
117 if (uws->words_left == 0)
118 return CODE_FINISH; /* Nothing left. */
119 uws->words_left--;
120 uws->data = *(uws->next++);
121 uws->bytes_left = 3;
123 else
124 uws->bytes_left--;
126 /* Extract the most significant byte. */
127 b = (uws->data >> 24) & 0xff;
128 uws->data <<= 8;
129 return b;
132 static void
133 unwind_restore_pair (_Unwind_Context * context, int reg, _uw *ptr)
135 #ifdef _BIG_ENDIAN
136 _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32, ptr + 1);
137 _Unwind_VRS_Set (context, _UVRSC_CORE, reg + 1, _UVRSD_UINT32, ptr);
138 #else
139 _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32, ptr);
140 _Unwind_VRS_Set (context, _UVRSC_CORE, reg + 1, _UVRSD_UINT32, ptr + 1);
141 #endif
144 static const int
145 unwind_frame_regs[13] =
147 R_A15, R_B15, R_B14, R_B13, R_B12, R_B11, R_B10, R_B3,
148 R_A14, R_A13, R_A12, R_A11, R_A10
151 static void
152 pop_compact_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
154 int size;
155 _uw test;
156 int i, regno, nregs;
158 size = 0;
159 nregs = __builtin_popcount (mask);
160 for (i = 0; i < 13; i++)
162 test = 1 << i;
163 if ((mask & test) == 0)
164 continue;
166 regno = unwind_frame_regs[12 - i];
168 if (i < 12 && nregs > 2
169 && (mask & (test << 1)) != 0
170 && unwind_frame_regs[11 - i] == regno + 1
171 && (regno & 1) == 0)
173 i++;
174 nregs--;
177 nregs--;
178 size += 2;
181 if (!inc_sp)
182 ptr -= size;
184 /* SP points just past the end of the stack. */
185 ptr += 2;
186 nregs = __builtin_popcount (mask);
187 for (i = 0; i < 13; i++)
189 test = 1 << i;
190 if ((mask & test) == 0)
191 continue;
193 regno = unwind_frame_regs[12 - i];
195 if (i < 12 && nregs > 2
196 && (mask & (test << 1)) != 0
197 && unwind_frame_regs[11 - i] == regno + 1
198 && (regno & 1) == 0)
200 /* Register pair. */
201 unwind_restore_pair (context, regno, ptr);
202 i++;
203 nregs--;
205 else
207 /* Single register with padding. */
208 _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, ptr);
211 nregs--;
212 ptr += 2;
215 ptr -= 2;
216 if ((mask & (1 << 11)) == 0)
217 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
220 static void
221 pop_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
223 int i;
224 int regno;
225 int nregs;
227 nregs = __builtin_popcount (mask);
229 if (!inc_sp)
230 ptr -= nregs;
231 else if (nregs & 1)
232 ptr++;
234 ptr++;
235 for (i = 0; i < 13; i++)
237 if ((mask & (1 << i)) == 0)
238 continue;
239 regno = unwind_frame_regs[12 - i];
240 if (i < 12 && unwind_frame_regs[11 - i] == (regno + 1)
241 && (mask & (1 << (i + 1))) != 0
242 && (((_uw)ptr) & 4) == 0
243 && (regno & 1) == 0)
245 unwind_restore_pair (context, regno, ptr);
246 i++;
247 ptr += 2;
249 else
251 _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32,
252 ptr);
253 ptr++;
257 ptr--;
258 if ((mask & (1 << 11)) == 0)
259 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
262 /* Unwind a 24-bit encoded frame. */
263 _Unwind_Reason_Code
264 __gnu_unwind_24bit (_Unwind_Context * context, _uw data, int compact)
266 _uw offset;
267 _uw mask;
268 _uw *ptr;
269 _uw tmp;
270 int ret_reg = unwind_frame_regs[data & 0xf];
272 if (ret_reg != R_B3)
274 _Unwind_VRS_Get (context, _UVRSC_CORE, unwind_frame_regs[data & 0xf],
275 _UVRSD_UINT32, &tmp);
276 _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &tmp);
279 mask = (data >> 4) & 0x1fff;
281 offset = (data >> 17) & 0x7f;
282 if (offset == 0x7f)
283 _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &ptr);
284 else
286 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
287 ptr += offset * 2;
291 if (compact)
292 pop_compact_frame (context, mask, ptr, offset != 0x7f);
293 else
294 pop_frame (context, mask, ptr, offset != 0x7f);
296 _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &tmp);
297 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &tmp);
299 return _URC_OK;
302 static void
303 unwind_pop_rts (_Unwind_Context * context)
305 _uw *ptr;
307 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
308 #ifdef _BIG_ENDIAN
309 _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ptr + 1);
310 #else
311 _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, ptr + 2);
312 #endif
313 ptr += 3;
314 unwind_restore_pair (context, R_A10, ptr);
315 ptr += 2;
316 unwind_restore_pair (context, R_B10, ptr);
317 ptr += 2;
318 unwind_restore_pair (context, R_A12, ptr);
319 ptr += 2;
320 unwind_restore_pair (context, R_B12, ptr);
321 ptr += 2;
322 unwind_restore_pair (context, R_A14, ptr);
323 ptr += 2;
324 _Unwind_VRS_Set (context, _UVRSC_CORE, R_B14, _UVRSD_UINT32, ptr);
325 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
326 /* PC will be set by implicit RETURN opcode. */
329 /* Execute the unwinding instructions described by UWS. */
330 _Unwind_Reason_Code
331 __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
333 _uw op;
334 int inc_sp;
335 _uw reg;
336 _uw *ptr;
338 inc_sp = 1;
339 for (;;)
341 op = next_unwind_byte (uws);
342 if (op == CODE_FINISH)
344 /* Drop out of the loop. */
345 break;
347 if ((op & 0xc0) == 0)
349 /* sp += (imm6 << 3) + 8. */
350 _uw offset;
352 offset = ((op & 0x3f) << 3) + 8;
353 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
354 reg += offset;
355 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
356 continue;
359 if (op == 0xd2)
361 /* vsp = vsp + 0x204 + (uleb128 << 2). */
362 int shift;
364 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
365 op = next_unwind_byte (uws);
366 shift = 3;
367 while (op & 0x80)
369 reg += ((op & 0x7f) << shift);
370 shift += 7;
371 op = next_unwind_byte (uws);
373 reg += ((op & 0x7f) << shift) + 0x408;
374 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
375 continue;
378 if ((op & 0xe0) == 0x80)
380 /* POP bitmask */
381 _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
383 if (mask == 0)
385 /* CANTUNWIND */
386 return _URC_FAILURE;
389 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
390 pop_frame (context, mask, ptr, inc_sp);
391 continue;
394 if ((op & 0xe0) == 0xa0)
396 /* POP bitmask (compact) */
397 _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
399 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
400 pop_compact_frame (context, mask, ptr, inc_sp);
401 continue;
404 if ((op & 0xf0) == 0xc0)
406 /* POP registers */
407 int nregs = op & 0xf;
409 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
410 while (nregs > 0)
412 op = next_unwind_byte (uws);
413 if ((op >> 4) != 0xf)
415 reg = unwind_frame_regs[op >> 4];
416 _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
417 ptr);
418 nregs--;
420 ptr--;
421 if ((op & 0xf) != 0xf)
423 reg = unwind_frame_regs[op & 0xf];
424 _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
425 ptr);
426 nregs--;
428 ptr--;
431 continue;
434 if (op == 0xd0)
436 /* MV FP, SP */
437 inc_sp = 0;
438 _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &reg);
439 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
440 continue;
443 if (op == 0xd1)
445 /* __cx6abi_pop_rts */
446 unwind_pop_rts (context);
447 break;
450 if ((op & 0xf0) == 0xe0)
452 /* B3 = reg. RETURN case already handled above. */
453 int regno = unwind_frame_regs[op & 0xf];
455 _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &reg);
456 _Unwind_VRS_Set (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &reg);
457 continue;
460 /* Reserved. */
461 return _URC_FAILURE;
464 /* Implicit RETURN. */
465 _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &reg);
466 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &reg);
467 return _URC_OK;
471 /* Execute the unwinding instructions associated with a frame. UCBP and
472 CONTEXT are the current exception object and virtual CPU state
473 respectively. */
475 _Unwind_Reason_Code
476 __gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
478 _uw *ptr;
479 __gnu_unwind_state uws;
481 ptr = (_uw *) ucbp->pr_cache.ehtp;
482 /* Skip over the personality routine address. */
483 ptr++;
484 /* Setup the unwinder state. */
485 uws.data = (*ptr) << 8;
486 uws.next = ptr + 1;
487 uws.bytes_left = 3;
488 uws.words_left = ((*ptr) >> 24) & 0xff;
490 return __gnu_unwind_execute (context, &uws);
493 /* Data segment base pointer corresponding to the function catching
494 the exception. */
496 _Unwind_Ptr
497 _Unwind_GetDataRelBase (_Unwind_Context *context)
499 return _Unwind_GetGR (context, R_B14);
502 /* This should never be used. */
504 _Unwind_Ptr
505 _Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
507 abort ();
510 /* Only used by gcc personality routines, so can rely on a value they hid
511 there earlier. */
512 _Unwind_Ptr
513 _Unwind_GetRegionStart (_Unwind_Context *context)
515 _Unwind_Control_Block *ucbp;
517 ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
518 return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
521 void *
522 _Unwind_GetLanguageSpecificData (_Unwind_Context *context)
524 _Unwind_Control_Block *ucbp;
525 _uw *ptr;
527 ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
528 ptr = (_uw *) ucbp->pr_cache.ehtp;
529 /* Skip the personality routine address. */
530 ptr++;
531 /* Skip the unwind opcodes. */
532 ptr += (((*ptr) >> 24) & 0xff) + 1;
534 return ptr;