Update contrib.
1 /* unwind_pr.c - ARM-defined model personality routines
3 * Copyright 2002-2003 ARM Limited.
8 1. Subject to the provisions of clause 2, ARM hereby grants to LICENSEE a
9 perpetual, non-exclusive, nontransferable, royalty free, worldwide licence
10 to use this Example Implementation of Exception Handling solely for the
11 purpose of developing, having developed, manufacturing, having
12 manufactured, offering to sell, selling, supplying or otherwise
13 distributing products which comply with the Exception Handling ABI for the
14 ARM Architecture specification. All other rights are reserved to ARM or its
17 2. THIS EXAMPLE IMPLEMENTATION OF EXCEPTION HANDLING IS PROVIDED "AS IS"
18 WITH NO WARRANTIES EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED
19 TO ANY WARRANTY OF SATISFACTORY QUALITY, MERCHANTABILITY, NONINFRINGEMENT
20 OR FITNESS FOR A PARTICULAR PURPOSE.
23 * RCS $Revision: 1.20 $
24 * Checkin $Date: 2003/11/10 17:13:37 $
25 * Revising $Author: achapman $
30 #include "unwind_env.h"
31 /* Language-independent unwinder declarations: */
34 /* Define PR_DIAGNOSTICS for printed diagnostics from the personality routine */
37 extern int printf(const char *, ...);
42 extern _Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
43 _Unwind_Control_Block *ucbp,
44 _Unwind_Context *context,
47 /* Personality routines - external entry points.
48 * pr0: short unwind description, 16 bit EHT offsets.
49 * pr1: long unwind description, 16 bit EHT offsets.
50 * pr2: long unwind description, 32 bit EHT offsets.
54 _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(_Unwind_State state,
55 _Unwind_Control_Block *ucbp,
56 _Unwind_Context *context) {
57 return __ARM_unwind_cpp_prcommon(state, ucbp, context, 0);
62 _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(_Unwind_State state,
63 _Unwind_Control_Block *ucbp,
64 _Unwind_Context *context) {
65 return __ARM_unwind_cpp_prcommon(state, ucbp, context, 1);
70 _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(_Unwind_State state,
71 _Unwind_Control_Block *ucbp,
72 _Unwind_Context *context) {
73 return __ARM_unwind_cpp_prcommon(state, ucbp, context, 2);
77 /* The rest of the file deals with the common routine */
81 /* C++ exceptions ABI required here:
82 * Declare protocol routines called by the personality routine.
83 * These are weak references so that referencing them here is
84 * insufficient to pull them into the image - they will only be
85 * included if application code uses a __cxa routine.
88 typedef unsigned char bool;
89 static const bool false = 0;
90 static const bool true = !false;
92 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
94 WEAKDECL void __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
95 WEAKDECL bool __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
96 WEAKDECL bool __cxa_type_match(_Unwind_Control_Block *ucbp,
97 const type_info *rttip,
98 void **matched_object);
101 /* ----- Address manipulation: ----- */
103 /* The following helper function is never called and is present simply
104 * for ease of packaging. The constant word within is used by
105 * ER_RO_offset_to_addr to compute the RO segment base.
106 * The zero word named W is relocated relative to the base B of the
107 * segment which includes it, hence B is recoverable at runtime by
111 extern const uint32_t __ARM_unwind_cpp_ROSegBase_SelfOffset;
113 __asm void __ARM_unwind_cpp_basehelper(void)
115 export __ARM_unwind_cpp_ROSegBase_SelfOffset;
116 R_ARM_ROSEGREL32 EQU 39
117 __ARM_unwind_cpp_ROSegBase_SelfOffset;
119 __RELOC R_ARM_ROSEGREL32,__ARM_unwind_cpp_ROSegBase_SelfOffset;
122 #define ER_RO_SegBase ((uint32_t)&__ARM_unwind_cpp_ROSegBase_SelfOffset - \
123 __ARM_unwind_cpp_ROSegBase_SelfOffset)
125 /* And now the function used to convert segment-relative offsets
126 * to absolute addresses.
129 static __inline uint32_t ER_RO_offset_to_addr(uint32_t offset)
131 return offset + ER_RO_SegBase;
135 /* --------- VRS manipulation: --------- */
141 static __inline uint32_t core_get(_Unwind_Context *context, uint32_t regno)
144 /* This call is required to never fail if given a valid regno */
145 _Unwind_VRS_Get(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
149 static __inline void core_set(_Unwind_Context *context, uint32_t regno, uint32_t newval)
151 /* This call is required to never fail if given a valid regno */
152 _Unwind_VRS_Set(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &newval);
155 static __inline uint32_t count_to_mask(uint32_t count) {
156 return (1 << count) - 1;
159 /* --------- Support for unwind instruction stream: --------- */
161 #define CODE_FINISH (0xb0)
163 typedef struct uwdata {
164 uint32_t unwind_word; /* current word of unwind description */
165 uint32_t *unwind_word_pointer; /* ptr to next word */
166 uint8_t unwind_word_bytes_remaining; /* count of bytes left in current word */
167 uint8_t unwind_words_remaining; /* count of words left, at ptr onwards */
170 static __inline uint8_t next_unwind_byte(uwdata *u) {
172 if (u->unwind_word_bytes_remaining == 0) { /* Load another word */
173 if (u->unwind_words_remaining == 0) return CODE_FINISH; /* nothing left - yield NOP */
174 u->unwind_words_remaining--;
175 u->unwind_word = *(u->unwind_word_pointer++);
176 u->unwind_word_bytes_remaining = 4;
179 u->unwind_word_bytes_remaining--;
180 ub = (u->unwind_word & 0xff000000) >> 24;
181 u->unwind_word <<= 8;
186 /* --------- Personality routines: --------- */
188 /* The C++ Standard is silent on what is supposed to happen if an internal
189 * inconsistency occurs during unwinding. In our design, we return to the
190 * caller with _URC_FAILURE. During phase 1 this causes a return from the
191 * language-independent unwinder to its caller (__cxa_throw or __cxa_rethrow)
192 * which will then call terminate(). If an error occurs during phase 2, the
193 * caller will call abort().
196 /* Types to assist with reading EHT's */
208 typedef uint32_t landingpad_t;
211 landingpad_t landingpad;
215 landingpad_t landingpad;
216 uint32_t rtti_offset;
220 uint32_t rtti_count; /* table count (possibly 0) */
221 uint32_t (rtti_offsets[1]); /* variable length table, possibly followed by landing pad */
228 /* Requirement imposed by C++ semantics module - match object in slot 0: */
229 #define BARRIER_HANDLEROBJECT (0)
230 /* Requirement imposed by C++ semantics module - function exception spec info */
231 #define BARRIER_FNSPECCOUNT (1)
232 #define BARRIER_FNSPECBASE (2)
233 #define BARRIER_FNSPECSTRIDE (3)
234 #define BARRIER_FNSPECARRAY (4)
235 /* Private use for us between phase 1 & 2: */
236 #define BARRIER_EHTP (1)
238 #define SAVE_PROPAGATION_BARRIER(UCB_PTR,VSP,EHTP,HANDLEROBJECT) \
239 (UCB_PTR)->barrier_cache.sp = (VSP); \
240 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_EHTP] = (uint32_t)(EHTP); \
241 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_HANDLEROBJECT] = (uint32_t)(HANDLEROBJECT);
243 #define CHECK_FOR_PROPAGATION_BARRIER(UCB_PTR,VSP,EHTP) \
244 ((UCB_PTR)->barrier_cache.sp == (VSP) && \
245 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_EHTP] == (uint32_t)(EHTP))
248 /* Cleanup cache: We only use one field */
249 #define CLEANUP_EHTP (0)
252 /* Special catch rtti values */
253 #define CATCH_ALL (0xffffffff)
254 #define CATCH_ALL_AND_TERMINATE (0xfffffffe)
257 /* Common personality routine: receives pr index as an argument.
259 * Note this implementation contains no explicit check against attempting to
260 * unwind off the top of the stack. Instead it relies (in cooperation with
261 * the language-independent unwinder) on there being a propagation barrier
262 * somewhere on the stack, perhaps the caller to main being not
263 * unwindable. An alternative would be to check for the stack pointer
264 * addressing a stack limit symbol.
267 _Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
268 _Unwind_Control_Block *ucbp,
269 _Unwind_Context *context,
272 _Unwind_EHT_Header *eht_startp; /* EHT start pointer */
273 uint8_t *ehtp; /* EHT pointer, incremented as required */
274 /* Flag for fnspec violations in which the frame should be unwound before calling unexpected() */
275 bool phase2_call_unexpected_after_unwind;
276 /* Flag for whether we have loaded r15 (pc) with a return address while executing
277 * unwind instructions.
278 * Set this on any write to r15 while executing the unwind instructions.
280 bool wrote_pc = false;
281 /* Flag for whether we loaded r15 from r14 while executing the unwind instructions */
282 bool wrote_pc_from_lr = false;
285 /* Mark all as well and extract the EHT pointer */
287 eht_startp = ucbp->pr_cache.ehtp;
289 #ifdef PR_DIAGNOSTICS
290 printf("PR entered: state=%d, r15=0x%x, fnstart=0x%x\n",
291 state, core_get(context, R_PC), ucbp->pr_cache.fnstart);
294 /* What are we supposed to do? */
296 if (state != _US_VIRTUAL_UNWIND_FRAME &&
297 state != _US_UNWIND_FRAME_STARTING &&
298 state != _US_UNWIND_FRAME_RESUME) {
299 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_UNSPECIFIED);
303 phase2_call_unexpected_after_unwind = false;
305 /* Traverse the current EHT, if there is one.
306 * The required behaviours are:
307 * _US_VIRTUAL_UNWIND_FRAME: search for a propagation barrier in this frame.
308 * otherwise look for the propagation barrier we found in phase 1,
309 * performing cleanups on the way. In this case if state will be one of:
310 * _US_UNWIND_FRAME_STARTING first time with this frame
311 * _US_UNWIND_FRAME_RESUME not first time, we are part-way through the EHT.
314 if ((ucbp->pr_cache.additional & 1) == 0) { /* EHT inline in index table? */
315 /* No: thus there is a real EHT */
317 if (state == _US_UNWIND_FRAME_RESUME) {
318 /* Recover saved pointer to next EHT entry */
319 ehtp = (uint8_t *)ucbp->cleanup_cache.bitpattern[CLEANUP_EHTP];
320 #ifdef PR_DIAGNOSTICS
321 printf("PR EHT recovered pointer 0x%x\n", (int)ehtp);
324 /* Point at the first EHT entry.
325 * For pr0, the unwind description is entirely within the header word.
326 * For pr1 & pr2, an unwind description extension word count is
327 * held in bits 16-23 of the header word.
329 uint32_t unwind_extension_word_count = (idx == 0 ? 0 : ((*eht_startp) >> 16) & 0xff);
330 ehtp = (uint8_t *)(eht_startp + 1 + unwind_extension_word_count);
332 #ifdef PR_DIAGNOSTICS
333 printf("PR EHT first entry at 0x%x\n", (int)ehtp);
341 /* Extract 32 bit length and offset */
346 length = ((EHT32 *)ehtp)->length;
347 if (length == 0) break; /* end of table */
348 offset = ((EHT32 *)ehtp)->offset;
349 ehtp += sizeof(EHT32);
352 length = ((EHT16 *)ehtp)->length;
353 if (length == 0) break; /* end of table */
354 offset = ((EHT16 *)ehtp)->offset;
355 ehtp += sizeof(EHT16);
358 #ifdef PR_DIAGNOSTICS
359 printf("PR Got entry at 0x%x code=%d, length=0x%x, offset=0x%x\n",
360 (int)(ehtp-4), ((offset & 1) << 1) | (length & 1),
361 length & ~1, offset & ~1);
364 /* Dispatch on the kind of entry */
365 switch (((offset & 1) << 1) | (length & 1)) {
366 case 0: /* cleanup */
367 if (state == _US_VIRTUAL_UNWIND_FRAME) {
368 /* Not a propagation barrier - skip */
370 /* Phase 2: call the cleanup if the return address is in range */
372 uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset;
373 uint32_t rtn_addr = core_get(context, R_PC);
374 if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
375 /* It is in range. */
376 landingpad_t landingpad = ((EHT_cleanup_tail *)ehtp)->landingpad;
377 ehtp += sizeof(EHT_cleanup_tail);
378 /* Dump state into the ECO so we resume correctly after the cleanup. */
379 /* We simply save the address of the next EHT entry. */
380 ucbp->cleanup_cache.bitpattern[CLEANUP_EHTP] = (uint32_t)ehtp;
381 if (!__cxa_begin_cleanup(ucbp)) {
382 /* Should be impossible, using ARM's library */
383 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_UNSPECIFIED);
386 /* Set up the VRS to enter the landing pad. */
387 padaddress = ER_RO_offset_to_addr(landingpad);
388 core_set(context, R_PC, padaddress);
389 #ifdef PR_DIAGNOSTICS
390 printf("PR Got cleanup in range, cleanup addr=0x%x\n", core_get(context, R_PC));
391 printf("PR Saving EHT pointer 0x%x\n", (int)ehtp);
393 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, padaddress);
394 /* Exit requesting upload the VRS to the real machine. */
395 return _URC_INSTALL_CONTEXT;
398 /* Phase 1, or phase 2 and not in range */
399 ehtp += sizeof(EHT_cleanup_tail);
403 if (state == _US_VIRTUAL_UNWIND_FRAME) {
404 /* In range, and with a matching type? */
405 uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset;
406 uint32_t rtn_addr = core_get(context, R_PC);
407 void *matched_object;
408 length -= 1; /* length had low bit set - clear it */
409 if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
411 uint32_t rtti_val = ((EHT_catch_tail *)ehtp)->rtti_offset;
412 if (rtti_val == CATCH_ALL_AND_TERMINATE) {
413 /* Always matches and causes propagation failure in phase 1 */
414 #ifdef PR_DIAGNOSTICS
415 printf("PR Got CATCH_ALL_AND_TERMINATE in phase 1\n");
417 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
420 if ((rtti_val == CATCH_ALL && ((matched_object = ucbp + 1),1)) ||
421 __cxa_type_match(ucbp,
422 (type_info *)(rtti_val = ER_RO_offset_to_addr(rtti_val)),
424 /* In range and matches.
425 * Record the propagation barrier details for ease of detection in phase 2.
426 * We save a pointer to the middle of the handler entry -
427 * this is fine, so long as we are consistent about it.
429 #ifdef PR_DIAGNOSTICS
430 printf("PR Got barrier in phase 1\n");
431 printf("PR Matched object address 0x%8.8x\n", matched_object);
433 SAVE_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp, matched_object);
434 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND,
435 ER_RO_offset_to_addr(((EHT_catch_tail *)ehtp)->landingpad));
436 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_CPP_TYPEINFO, rtti_val);
437 return _URC_HANDLER_FOUND;
440 /* Not in range or no type match - fall thru to carry on scanning the table */
442 /* Else this is phase 2: have we encountered the saved barrier? */
443 if (CHECK_FOR_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp)) {
445 * Set up the VRS to enter the landing pad,
446 * and upload the VRS to the real machine.
448 landingpad_t landingpad;
450 #ifdef PR_DIAGNOSTICS
451 printf("PR Got catch barrier in phase 2\n");
453 landingpad = ((EHT_catch_tail *)ehtp)->landingpad;
454 padaddress = ER_RO_offset_to_addr(landingpad);
455 core_set(context, R_PC, padaddress);
456 core_set(context, 0, (uint32_t)ucbp);
457 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, padaddress);
458 /* Exit requesting upload the VRS to the real machine. */
459 return _URC_INSTALL_CONTEXT;
462 /* Else carry on scanning the table */
463 ehtp += sizeof(EHT_catch_tail);
466 case 2: /* function exception specification (fnspec) */
468 uint32_t counter_word = ((EHT_fnspec_tail *)ehtp)->rtti_count;
469 uint32_t rtti_count = counter_word & 0x7fffffff; /* Extract offset count */
470 if (state == _US_VIRTUAL_UNWIND_FRAME) {
472 /* In range? Offset had low bit set - clear it */
473 uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset - 1;
474 uint32_t rtn_addr = core_get(context, R_PC);
475 if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
476 /* See if any type matches */
477 uint32_t *rttipp = &((EHT_fnspec_tail *)ehtp)->rtti_offsets[0];
479 for (i = 0; i < rtti_count; i++) {
480 void *matched_object;
481 if (__cxa_type_match(ucbp,
482 (type_info *)ER_RO_offset_to_addr(*rttipp),
484 #ifdef PR_DIAGNOSTICS
485 printf("PR Fnspec matched in phase 1\n");
492 if (i == rtti_count) { /* NB case rtti_count==0 forces no match [for throw()] */
493 /* No match - fnspec violation is a propagation barrier */
494 #ifdef PR_DIAGNOSTICS
495 printf("PR Got fnspec barrier in phase 1\n");
497 SAVE_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp, 0); /* save ptr to the count of types */
498 /* Even if this is a fnspec with a landing pad, we always end up in
499 * __cxa_call_unexpected so tell the debugger thats where we're going
501 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND, &__cxa_call_unexpected);
502 return _URC_HANDLER_FOUND;
504 } /* if (in range...) */
506 /* Fall out of the 'if' to continue table scanning */
509 /* Else this is phase 2: have we encountered the saved barrier? */
510 if (CHECK_FOR_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp)) {
511 /* Yes we have. Fill in the UCB barrier_cache for entry to __cxa_call_unexpected */
512 uint32_t *p = (uint32_t *)ehtp; /* ptr to rtti count */
513 ucbp->barrier_cache.bitpattern[BARRIER_FNSPECCOUNT] = rtti_count;
514 ucbp->barrier_cache.bitpattern[BARRIER_FNSPECBASE] = ER_RO_offset_to_addr(0); /* base address */
515 ucbp->barrier_cache.bitpattern[BARRIER_FNSPECSTRIDE] = 4; /* stride */
516 ucbp->barrier_cache.bitpattern[BARRIER_FNSPECARRAY] = (uint32_t)(p + 1); /* address of rtti offset list */
518 /* If this is a fnspec with an attached landing pad, we must enter
519 * the pad immediately. Otherwise we need to unwind the frame before
520 * calling __cxa_call_unexpected() so set a flag to make this happen.
522 if (counter_word == rtti_count)
523 phase2_call_unexpected_after_unwind = true; /* no pad, enter later */
525 landingpad_t landingpad;
527 #ifdef PR_DIAGNOSTICS
528 printf("PR Got fnspec barrier in phase 2 (immediate entry)\n");
530 ehtp += (sizeof(((EHT_fnspec_tail *)ehtp)->rtti_count) +
531 sizeof(uint32_t) * rtti_count); /* point at pad offset */
532 landingpad = *(landingpad_t *)ehtp;
533 padaddress = ER_RO_offset_to_addr(landingpad);
534 core_set(context, 0, (uint32_t)ucbp);
535 core_set(context, R_PC, padaddress);
536 /* Even if this is a fnspec with a landing pad, in phase 1 we said we'd
537 * end up in __cxa_call_unexpected so show the same thing now
539 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, &__cxa_call_unexpected);
540 return _URC_INSTALL_CONTEXT;
542 } /* endif (barrier match) */
543 } /* endif (which phase) */
545 /* Advance to the next item, remembering to skip the landing pad if present */
546 ehtp += (sizeof(((EHT_fnspec_tail *)ehtp)->rtti_count) +
547 sizeof(uint32_t) * rtti_count +
548 (counter_word == rtti_count ? 0 : sizeof(landingpad_t)));
551 case 3: /* unallocated */
552 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT);
558 #ifdef PR_DIAGNOSTICS
559 printf("PR Reached end of EHT\n");
562 } /* if out-of-line EHT */
565 /* Do a virtual unwind of this frame - load the first unwind bytes then loop.
566 * Loop exit is by executing opcode CODE_FINISH.
569 ud.unwind_word = *(uint32_t *)eht_startp; /* first word */
570 ud.unwind_word_pointer = (uint32_t *)eht_startp + 1; /* ptr to extension words, if any */
571 if (idx == 0) { /* short description */
572 ud.unwind_words_remaining = 0; /* no further words */
573 ud.unwind_word <<= 8; /* 3 explicit unwind bytes in this word */
574 ud.unwind_word_bytes_remaining = 3;
575 } else { /* long description: extension word count in bits 16-23 */
576 ud.unwind_words_remaining = ((ud.unwind_word) >> 16) & 0xff;
577 ud.unwind_word <<= 16; /* 2 explicit unwind bytes in this word */
578 ud.unwind_word_bytes_remaining = 2;
581 #ifdef PR_DIAGNOSTICS
582 /* debug_print_vrs(context); */
586 uint8_t ub = next_unwind_byte(&ud);
588 #ifdef PR_DIAGNOSTICS
589 printf("PR Unwind byte 0x%x\n", ub);
592 /* decode and execute the current byte ... */
594 if (ub == CODE_FINISH) { /* finished unwinding */
597 _Unwind_VRS_Get(context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, &lr);
598 core_set(context, R_PC, lr);
599 wrote_pc_from_lr = true;
601 #ifdef PR_DIAGNOSTICS
604 _Unwind_VRS_Get(context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &nextpc);
605 printf("PR Next PC is 0x%x\n", nextpc);
610 if (ub <= 0x3f) { /* 00nnnnnn: vsp += (nnnnnn << 2) + 4 */
611 uint32_t increment = ((ub & 0x3f) << 2) + 4;
612 core_set(context, R_SP, core_get(context, R_SP) + increment);
615 if (ub <= 0x7f) { /* 01xxxxxx: vsp -= (xxxxxx << 2) + 4 */
616 uint32_t decrement = ((ub & 0x3f) << 2) + 4;
617 core_set(context, R_SP, core_get(context, R_SP) - decrement);
620 if (ub <= 0x8f) { /* 100000000 00000000: refuse, 1000rrrr rrrrrrrr: pop integer regs */
621 uint32_t mask = (ub & 0xf) << 12;
622 ub = next_unwind_byte(&ud);
624 if (mask == 0) { /* 10000000 00000000 refuse to unwind */
625 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
628 if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
629 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
632 if (mask & (1 << R_PC)) wrote_pc = true;
635 if (ub <= 0x9f) { /* 1001nnnn: vsp = r[nnnn] if not 13,15 */
636 uint8_t regno = ub & 0xf;
637 if (regno == 13 || regno == R_PC) { /* reserved */
638 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
641 core_set(context, R_SP, core_get(context, regno));
644 if (ub <= 0xaf) { /* 1010xnnn: pop r4-r[4+nnn], +r14 if x */
645 uint32_t mask = count_to_mask((ub & 0x7) + 1) << 4;
646 if (ub & 0x8) mask |= (1 << R_LR);
647 if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
648 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
654 /* if (ub == 0xb0) is CODE_FINISH, handled earlier */
655 if (ub == 0xb1) { /* 10110001 0000iiii pop integer regs, others reserved */
656 uint32_t mask = next_unwind_byte(&ud);
657 if (mask == 0 || mask > 0xf) { /* reserved */
658 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
661 if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
662 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
667 if (ub == 0xb2) { /* 10110010 uleb128 : vsp += (uleb128 << 2) + 0x204 */
672 ub = next_unwind_byte(&ud);
673 u |= (ub & 0x7f) << n;
674 if ((ub & 0x80) == 0) break;
677 core_set(context, R_SP, core_get(context, R_SP) + (u << 2) + 0x204);
680 if (ub == 0xb3) { /* 10110011: pop vfp */
681 uint32_t discriminator = next_unwind_byte(&ud);
682 discriminator = ((discriminator & 0xf0) << 12) | ((discriminator & 0x0f) + 1);
683 if (_Unwind_VRS_Pop(context, _UVRSC_VFP, discriminator, _UVRSD_VFPX) != _UVRSR_OK) {
684 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
689 { /* 101101nn: pop fpa */
690 uint32_t discriminator = 0x40000 | ((ub & 0x3) + 1);
691 if (_Unwind_VRS_Pop(context, _UVRSC_FPA, discriminator, _UVRSD_FPAX) != _UVRSR_OK) {
692 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
697 } /* if (ub <= 0xb7) ... */
698 if (ub <= 0xbf) { /* 10111nnn: pop vfp */
699 uint32_t discriminator = 0x80000 | ((ub & 0x7) + 1);
700 if (_Unwind_VRS_Pop(context, _UVRSC_VFP, discriminator, _UVRSD_VFPX) != _UVRSR_OK) {
701 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
707 if (ub == 0xc7) { /* 11000111: WMMX C regs */
708 uint32_t mask = next_unwind_byte(&ud);
709 if (mask == 0 || mask > 0xf) { /* reserved */
710 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
713 if (_Unwind_VRS_Pop(context, _UVRSC_WMMXC, mask, _UVRSD_UINT32) != _UVRSR_OK) {
714 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
718 } else if (ub == 0xc6) { /* 11000110: WMMX D regs */
719 uint32_t discriminator = next_unwind_byte(&ud);
720 discriminator = ((discriminator & 0xf0) << 4) | ((discriminator & 0x0f) + 1);
721 if (_Unwind_VRS_Pop(context, _UVRSC_WMMXD, discriminator, _UVRSD_UINT64) != _UVRSR_OK) {
722 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
727 /* 11000nnn (nnn != 6, 7): WMMX D regs */
728 uint32_t discriminator = 0xa00 | ((ub & 0x7) + 1);
729 if (_Unwind_VRS_Pop(context, _UVRSC_WMMXD, discriminator, _UVRSD_UINT64) != _UVRSR_OK) {
730 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
735 } /* if (ub <= 0xc7) ... */
736 if (ub == 0xc8) { /* 11001000: pop fpa */
737 uint32_t discriminator = next_unwind_byte(&ud);
738 discriminator = ((discriminator & 0x70) << 12) | ((discriminator & 0x03) + 1);
739 if (_Unwind_VRS_Pop(context, _UVRSC_FPA, discriminator, _UVRSD_FPAX) != _UVRSR_OK) {
740 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
745 /* and in fact everything else is currently reserved or spare */
746 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
750 #ifdef PR_DIAGNOSTICS
751 /* debug_print_vrs(context); */
754 /* The VRS has now been updated to reflect the virtual unwind.
755 * If we are dealing with an unmatched fnspec, pop intervening frames
756 * and call unexpected(). Else return to our caller with an
757 * indication to continue unwinding.
760 if (phase2_call_unexpected_after_unwind) {
761 /* Set up the VRS to enter __cxa_call_unexpected,
762 * and upload the VRS to the real machine.
763 * The barrier_cache was initialised earlier.
765 #ifdef PR_DIAGNOSTICS
766 printf("PR Got fnspec barrier in phase 2 (unwinding completed)\n");
768 core_set(context, 0, (uint32_t)ucbp);
769 if (!wrote_pc_from_lr) {
771 /* Move the return address to lr to simulate a call */
772 _Unwind_VRS_Get(context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &pc);
773 core_set(context, R_LR, pc);
775 core_set(context, R_PC, (uint32_t)&__cxa_call_unexpected);
776 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, &__cxa_call_unexpected);
777 return _URC_INSTALL_CONTEXT;
780 /* Else continue with next frame */
781 return _URC_CONTINUE_UNWIND;
785 /* end ifdef prcommon_c */