]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgcc/config/c6x/pr-support.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / c6x / pr-support.c
1 /* C6X ABI compliant unwinding routines
2 Copyright (C) 2011-2021 Free Software Foundation, Inc.
3
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.
8
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.
13
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.
17
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/>. */
22
23 #include "unwind.h"
24
25 /* We add a prototype for abort here to avoid creating a dependency on
26 target headers. */
27 extern void abort (void);
28
29 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
30
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
64
65 #define R_SP R_B15
66 #define R_PC 33
67
68 #define uint32_highbit (((_uw) 1) << 31)
69
70 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
71
72 /* Unwind descriptors. */
73
74 typedef struct
75 {
76 _uw16 length;
77 _uw16 offset;
78 } EHT16;
79
80 typedef struct
81 {
82 _uw length;
83 _uw offset;
84 } EHT32;
85
86 /* Calculate the address encoded by a 31-bit self-relative offset at address
87 P. Copy of routine in unwind-arm.c. */
88
89 static inline _uw
90 selfrel_offset31 (const _uw *p)
91 {
92 _uw offset;
93
94 offset = *p;
95 /* Sign extend to 32 bits. */
96 if (offset & (1 << 30))
97 offset |= 1u << 31;
98
99 return offset + (_uw) p;
100 }
101
102
103 /* Personality routine helper functions. */
104
105 #define CODE_FINISH (0xe7)
106
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)
111 {
112 _uw8 b;
113
114 if (uws->bytes_left == 0)
115 {
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;
122 }
123 else
124 uws->bytes_left--;
125
126 /* Extract the most significant byte. */
127 b = (uws->data >> 24) & 0xff;
128 uws->data <<= 8;
129 return b;
130 }
131
132 static void
133 unwind_restore_pair (_Unwind_Context * context, int reg, _uw *ptr)
134 {
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
142 }
143
144 static const int
145 unwind_frame_regs[13] =
146 {
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
149 };
150
151 static void
152 pop_compact_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
153 {
154 int size;
155 _uw test;
156 int i, regno, nregs;
157
158 size = 0;
159 nregs = __builtin_popcount (mask);
160 for (i = 0; i < 13; i++)
161 {
162 test = 1 << i;
163 if ((mask & test) == 0)
164 continue;
165
166 regno = unwind_frame_regs[12 - i];
167
168 if (i < 12 && nregs > 2
169 && (mask & (test << 1)) != 0
170 && unwind_frame_regs[11 - i] == regno + 1
171 && (regno & 1) == 0)
172 {
173 i++;
174 nregs--;
175 }
176
177 nregs--;
178 size += 2;
179 }
180
181 if (!inc_sp)
182 ptr -= size;
183
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++)
188 {
189 test = 1 << i;
190 if ((mask & test) == 0)
191 continue;
192
193 regno = unwind_frame_regs[12 - i];
194
195 if (i < 12 && nregs > 2
196 && (mask & (test << 1)) != 0
197 && unwind_frame_regs[11 - i] == regno + 1
198 && (regno & 1) == 0)
199 {
200 /* Register pair. */
201 unwind_restore_pair (context, regno, ptr);
202 i++;
203 nregs--;
204 }
205 else
206 {
207 /* Single register with padding. */
208 _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, ptr);
209 }
210
211 nregs--;
212 ptr += 2;
213 }
214
215 ptr -= 2;
216 if ((mask & (1 << 11)) == 0)
217 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
218 }
219
220 static void
221 pop_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
222 {
223 int i;
224 int regno;
225 int nregs;
226
227 nregs = __builtin_popcount (mask);
228
229 if (!inc_sp)
230 ptr -= nregs;
231 else if (nregs & 1)
232 ptr++;
233
234 ptr++;
235 for (i = 0; i < 13; i++)
236 {
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)
244 {
245 unwind_restore_pair (context, regno, ptr);
246 i++;
247 ptr += 2;
248 }
249 else
250 {
251 _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32,
252 ptr);
253 ptr++;
254 }
255 }
256
257 ptr--;
258 if ((mask & (1 << 11)) == 0)
259 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
260 }
261
262 /* Unwind a 24-bit encoded frame. */
263 _Unwind_Reason_Code
264 __gnu_unwind_24bit (_Unwind_Context * context, _uw data, int compact)
265 {
266 _uw offset;
267 _uw mask;
268 _uw *ptr;
269 _uw tmp;
270 int ret_reg = unwind_frame_regs[data & 0xf];
271
272 if (ret_reg != R_B3)
273 {
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);
277 }
278
279 mask = (data >> 4) & 0x1fff;
280
281 offset = (data >> 17) & 0x7f;
282 if (offset == 0x7f)
283 _Unwind_VRS_Get (context, _UVRSC_CORE, R_A15, _UVRSD_UINT32, &ptr);
284 else
285 {
286 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
287 ptr += offset * 2;
288 }
289
290
291 if (compact)
292 pop_compact_frame (context, mask, ptr, offset != 0x7f);
293 else
294 pop_frame (context, mask, ptr, offset != 0x7f);
295
296 _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &tmp);
297 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &tmp);
298
299 return _URC_OK;
300 }
301
302 static void
303 unwind_pop_rts (_Unwind_Context * context)
304 {
305 _uw *ptr;
306
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. */
327 }
328
329 /* Execute the unwinding instructions described by UWS. */
330 _Unwind_Reason_Code
331 __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
332 {
333 _uw op;
334 int inc_sp;
335 _uw reg;
336 _uw *ptr;
337
338 inc_sp = 1;
339 for (;;)
340 {
341 op = next_unwind_byte (uws);
342 if (op == CODE_FINISH)
343 {
344 /* Drop out of the loop. */
345 break;
346 }
347 if ((op & 0xc0) == 0)
348 {
349 /* sp += (imm6 << 3) + 8. */
350 _uw offset;
351
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;
357 }
358
359 if (op == 0xd2)
360 {
361 /* vsp = vsp + 0x204 + (uleb128 << 2). */
362 int shift;
363
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)
368 {
369 reg += ((op & 0x7f) << shift);
370 shift += 7;
371 op = next_unwind_byte (uws);
372 }
373 reg += ((op & 0x7f) << shift) + 0x408;
374 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
375 continue;
376 }
377
378 if ((op & 0xe0) == 0x80)
379 {
380 /* POP bitmask */
381 _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
382
383 if (mask == 0)
384 {
385 /* CANTUNWIND */
386 return _URC_FAILURE;
387 }
388
389 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
390 pop_frame (context, mask, ptr, inc_sp);
391 continue;
392 }
393
394 if ((op & 0xe0) == 0xa0)
395 {
396 /* POP bitmask (compact) */
397 _uw mask = ((op & 0x1f) << 8) | next_unwind_byte (uws);
398
399 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
400 pop_compact_frame (context, mask, ptr, inc_sp);
401 continue;
402 }
403
404 if ((op & 0xf0) == 0xc0)
405 {
406 /* POP registers */
407 int nregs = op & 0xf;
408
409 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &ptr);
410 while (nregs > 0)
411 {
412 op = next_unwind_byte (uws);
413 if ((op >> 4) != 0xf)
414 {
415 reg = unwind_frame_regs[op >> 4];
416 _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
417 ptr);
418 nregs--;
419 }
420 ptr--;
421 if ((op & 0xf) != 0xf)
422 {
423 reg = unwind_frame_regs[op & 0xf];
424 _Unwind_VRS_Set (context, _UVRSC_CORE, reg, _UVRSD_UINT32,
425 ptr);
426 nregs--;
427 }
428 ptr--;
429 }
430
431 continue;
432 }
433
434 if (op == 0xd0)
435 {
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;
441 }
442
443 if (op == 0xd1)
444 {
445 /* __cx6abi_pop_rts */
446 unwind_pop_rts (context);
447 break;
448 }
449
450 if ((op & 0xf0) == 0xe0)
451 {
452 /* B3 = reg. RETURN case already handled above. */
453 int regno = unwind_frame_regs[op & 0xf];
454
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;
458 }
459
460 /* Reserved. */
461 return _URC_FAILURE;
462 }
463
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;
468 }
469
470
471 /* Execute the unwinding instructions associated with a frame. UCBP and
472 CONTEXT are the current exception object and virtual CPU state
473 respectively. */
474
475 _Unwind_Reason_Code
476 __gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
477 {
478 _uw *ptr;
479 __gnu_unwind_state uws;
480
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;
489
490 return __gnu_unwind_execute (context, &uws);
491 }
492
493 /* Data segment base pointer corresponding to the function catching
494 the exception. */
495
496 _Unwind_Ptr
497 _Unwind_GetDataRelBase (_Unwind_Context *context)
498 {
499 return _Unwind_GetGR (context, R_B14);
500 }
501
502 /* This should never be used. */
503
504 _Unwind_Ptr
505 _Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
506 {
507 abort ();
508 }
509
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)
514 {
515 _Unwind_Control_Block *ucbp;
516
517 ucbp = (_Unwind_Control_Block *) _Unwind_GetGR (context, UNWIND_POINTER_REG);
518 return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
519 }
520
521 void *
522 _Unwind_GetLanguageSpecificData (_Unwind_Context *context)
523 {
524 _Unwind_Control_Block *ucbp;
525 _uw *ptr;
526
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;
533
534 return ptr;
535 }