]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/c6x/pr-support.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / c6x / pr-support.c
CommitLineData
1e874273 1/* C6X ABI compliant unwinding routines
7adcbafe 2 Copyright (C) 2011-2022 Free Software Foundation, Inc.
1e874273
PB
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. */
27extern void abort (void);
28
29typedef 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
70void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
71
72/* Unwind descriptors. */
73
74typedef struct
75{
76 _uw16 length;
77 _uw16 offset;
78} EHT16;
79
80typedef 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
89static inline _uw
90selfrel_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. */
109static inline _uw8
110next_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
132static void
133unwind_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
144static const int
145unwind_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
151static void
152pop_compact_frame (_Unwind_Context * context, _uw mask, _uw *ptr, int inc_sp)
153{
154 int size;
155 _uw test;
0d53e346 156 int i, regno, nregs;
1e874273
PB
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];
1e874273 167
0d53e346
BS
168 if (i < 12 && nregs > 2
169 && (mask & (test << 1)) != 0
170 && unwind_frame_regs[11 - i] == regno + 1
171 && (regno & 1) == 0)
1e874273
PB
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];
1e874273 194
0d53e346
BS
195 if (i < 12 && nregs > 2
196 && (mask & (test << 1)) != 0
197 && unwind_frame_regs[11 - i] == regno + 1
198 && (regno & 1) == 0)
1e874273
PB
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
220static void
221pop_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];
0d53e346 240 if (i < 12 && unwind_frame_regs[11 - i] == (regno + 1)
1e874273
PB
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;
5b2d9d90
BS
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 }
1e874273
PB
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
5b2d9d90 296 _Unwind_VRS_Get (context, _UVRSC_CORE, R_B3, _UVRSD_UINT32, &tmp);
1e874273
PB
297 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &tmp);
298
299 return _URC_OK;
300}
301
302static void
303unwind_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 {
5764ee3c 452 /* B3 = reg. RETURN case already handled above. */
1e874273
PB
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
521void *
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}