Update contrib.
1 /* unwind_pr.c - ARM-defined model personality routines
3 * Copyright 2002-2005 ARM Limited. All rights reserved.
5 * Your rights to use this code are set out in the accompanying licence
6 * text file LICENCE.txt (ARM contract number LEC-ELA-00080 v1.0).
9 /* Portions copyright Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). */
12 * RCS $Revision: 92986 $
13 * Checkin $Date: 2005-10-13 15:56:12 +0100 (Thu, 13 Oct 2005) $
14 * Revising $Author: achapman $
19 #include "unwind_env.h"
20 /* Language-independent unwinder declarations: */
23 /* Define PR_DIAGNOSTICS for printed diagnostics from the personality routine */
26 /* Symbian specific support */
27 #include "symbian_support.h"
32 extern int printf(const char *, ...);
38 extern _Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
39 _Unwind_Control_Block *ucbp,
40 _Unwind_Context *context,
43 /* Personality routines - external entry points.
44 * pr0: short unwind description, 16 bit EHT offsets.
45 * pr1: long unwind description, 16 bit EHT offsets.
46 * pr2: long unwind description, 32 bit EHT offsets.
50 _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(_Unwind_State state,
51 _Unwind_Control_Block *ucbp,
52 _Unwind_Context *context) {
53 return __ARM_unwind_cpp_prcommon(state, ucbp, context, 0);
58 EXPORT_C _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(_Unwind_State state,
59 _Unwind_Control_Block *ucbp,
60 _Unwind_Context *context) {
61 return __ARM_unwind_cpp_prcommon(state, ucbp, context, 1);
66 EXPORT_C _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(_Unwind_State state,
67 _Unwind_Control_Block *ucbp,
68 _Unwind_Context *context) {
69 return __ARM_unwind_cpp_prcommon(state, ucbp, context, 2);
73 /* The rest of the file deals with the common routine */
77 /* C++ exceptions ABI required here:
78 * Declare protocol routines called by the personality routine.
79 * These are weak references so that referencing them here is
80 * insufficient to pull them into the image - they will only be
81 * included if application code uses a __cxa routine.
84 typedef unsigned char bool;
85 static const bool false = 0;
86 static const bool true = !false;
88 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
90 IMPORT_C WEAKDECL void __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
91 IMPORT_C WEAKDECL bool __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
95 ctm_succeeded_with_ptr_to_base = 2
96 } __cxa_type_match_result;
97 IMPORT_C WEAKDECL __cxa_type_match_result __cxa_type_match(_Unwind_Control_Block *ucbp,
98 const type_info *rttip,
99 bool is_reference_type,
100 void **matched_object);
102 /* ----- Helper routines, private ----- */
104 /* R_ARM_PREL31 is a place-relative 31-bit signed relocation. The
105 * routine takes the address of a location that was relocated by
106 * R_ARM_PREL31, and returns an absolute address.
108 static FORCEINLINE uint32_t __ARM_resolve_prel31(void *p)
110 return (uint32_t)((((*(int32_t *)p) << 1) >> 1) + (int32_t)p);
113 /* --------- VRS manipulation: --------- */
119 static FORCEINLINE uint32_t core_get(_Unwind_Context *context, uint32_t regno)
122 /* This call is required to never fail if given a valid regno */
123 _Unwind_VRS_Get(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
127 static FORCEINLINE void core_set(_Unwind_Context *context, uint32_t regno, uint32_t newval)
129 /* This call is required to never fail if given a valid regno */
130 _Unwind_VRS_Set(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &newval);
133 static FORCEINLINE uint32_t count_to_mask(uint32_t count) {
134 return (1 << count) - 1;
137 /* --------- Support for unwind instruction stream: --------- */
139 #define CODE_FINISH (0xb0)
141 typedef struct uwdata {
142 uint32_t unwind_word; /* current word of unwind description */
143 uint32_t *unwind_word_pointer; /* ptr to next word */
144 uint8_t unwind_word_bytes_remaining; /* count of bytes left in current word */
145 uint8_t unwind_words_remaining; /* count of words left, at ptr onwards */
148 static INLINE uint8_t next_unwind_byte(uwdata *u) {
150 if (u->unwind_word_bytes_remaining == 0) { /* Load another word */
151 if (u->unwind_words_remaining == 0) return CODE_FINISH; /* nothing left - yield NOP */
152 u->unwind_words_remaining--;
153 u->unwind_word = *(u->unwind_word_pointer++);
154 u->unwind_word_bytes_remaining = 4;
157 u->unwind_word_bytes_remaining--;
158 ub = (u->unwind_word & 0xff000000) >> 24;
159 u->unwind_word <<= 8;
164 /* --------- Personality routines: --------- */
166 /* The C++ Standard is silent on what is supposed to happen if an internal
167 * inconsistency occurs during unwinding. In our design, we return to the
168 * caller with _URC_FAILURE. During phase 1 this causes a return from the
169 * language-independent unwinder to its caller (__cxa_throw or __cxa_rethrow)
170 * which will then call terminate(). If an error occurs during phase 2, the
171 * caller will call abort().
174 /* Types to assist with reading EHT's */
186 typedef uint32_t landingpad_t;
189 landingpad_t landingpad;
193 landingpad_t landingpad;
198 uint32_t rtti_count; /* table count (possibly 0) */
199 uint32_t (rtti_refs[1]); /* variable length table, possibly followed by landing pad */
206 /* Requirement imposed by C++ semantics module - pointer to match object in slot 0: */
207 #define BARRIER_HANDLEROBJECT (0)
208 /* Requirement imposed by C++ semantics module - function exception spec info */
209 #define BARRIER_FNSPECCOUNT (1)
210 #define BARRIER_FNSPECBASE (2)
211 #define BARRIER_FNSPECSTRIDE (3)
212 #define BARRIER_FNSPECARRAY (4)
213 /* Private use for us until catch handler entry complete: */
214 #define BARRIER_TEMPORARYMATCHOBJECT (1)
215 /* Private use for us between phase 1 & 2: */
216 #define BARRIER_EHTP (2)
218 #define SAVE_CATCH_PROPAGATION_BARRIER(UCB_PTR,VSP,EHTP,HANDLEROBJECT) \
219 (UCB_PTR)->barrier_cache.sp = (VSP); \
220 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_EHTP] = (uint32_t)(EHTP); \
221 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_HANDLEROBJECT] = (uint32_t)(HANDLEROBJECT);
223 #define SAVE_CATCH_OF_BASEPTR_PROPAGATION_BARRIER(UCB_PTR,VSP,EHTP,HANDLEROBJECT) \
224 (UCB_PTR)->barrier_cache.sp = (VSP); \
225 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_EHTP] = (uint32_t)(EHTP); \
226 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_TEMPORARYMATCHOBJECT] = (uint32_t)(HANDLEROBJECT); \
227 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_HANDLEROBJECT] = (uint32_t)&((UCB_PTR)->barrier_cache.bitpattern[BARRIER_TEMPORARYMATCHOBJECT]);
229 #define SAVE_FNSPEC_PROPAGATION_BARRIER(UCB_PTR,VSP,EHTP) \
230 (UCB_PTR)->barrier_cache.sp = (VSP); \
231 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_EHTP] = (uint32_t)(EHTP); \
232 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_HANDLEROBJECT] = (uint32_t)0;
234 #define CHECK_FOR_PROPAGATION_BARRIER(UCB_PTR,VSP,EHTP) \
235 ((UCB_PTR)->barrier_cache.sp == (VSP) && \
236 (UCB_PTR)->barrier_cache.bitpattern[BARRIER_EHTP] == (uint32_t)(EHTP))
239 /* Cleanup cache: We only use one field */
240 #define CLEANUP_EHTP (0)
243 /* Special catch rtti values */
244 #define CATCH_ALL (0xffffffff)
245 #define CATCH_ALL_AND_TERMINATE (0xfffffffe)
246 /* Landing pad bit for catching a reference type */
247 #define CATCH_REFERENCE (0x80000000)
250 /* Common personality routine: receives pr index as an argument.
252 * Note this implementation contains no explicit check against attempting to
253 * unwind off the top of the stack. Instead it relies (in cooperation with
254 * the language-independent unwinder) on there being a propagation barrier
255 * somewhere on the stack, perhaps the caller to main being not
256 * unwindable. An alternative would be to check for the stack pointer
257 * addressing a stack limit symbol.
260 _Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
261 _Unwind_Control_Block *ucbp,
262 _Unwind_Context *context,
265 _Unwind_EHT_Header *eht_startp; /* EHT start pointer */
266 uint8_t *ehtp; /* EHT pointer, incremented as required */
267 /* Flag for fnspec violations in which the frame should be unwound before calling unexpected() */
268 bool phase2_call_unexpected_after_unwind;
269 /* Flag for whether we have loaded r15 (pc) with a return address while executing
270 * unwind instructions.
271 * Set this on any write to r15 while executing the unwind instructions.
273 bool wrote_pc = false;
274 /* Flag for whether we have loaded r14 (lr) with a return address while executing
275 * unwind instructions.
276 * Set this on any write to r14 while executing the unwind instructions.
278 bool wrote_lr = false;
279 /* Flag for whether we loaded r15 from r14 while executing the unwind instructions */
280 bool wrote_pc_from_lr = false;
283 /* Are we version 2 of the EHABI ? */
284 bool ehabiv2 = EHABI_V2(ucbp);
286 /* Mark all as well and extract the EHT pointer */
288 eht_startp = ucbp->pr_cache.ehtp;
290 #ifdef PR_DIAGNOSTICS
291 printf("PR entered: state=%d, r15=0x%x, fnstart=0x%x\n",
292 state, core_get(context, R_PC), ucbp->pr_cache.fnstart);
295 /* What are we supposed to do? */
297 if (state != _US_VIRTUAL_UNWIND_FRAME &&
298 state != _US_UNWIND_FRAME_STARTING &&
299 state != _US_UNWIND_FRAME_RESUME) {
300 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_UNSPECIFIED);
304 phase2_call_unexpected_after_unwind = false;
306 /* Traverse the current EHT, if there is one.
307 * The required behaviours are:
308 * _US_VIRTUAL_UNWIND_FRAME: search for a propagation barrier in this frame.
309 * otherwise look for the propagation barrier we found in phase 1,
310 * performing cleanups on the way. In this case if state will be one of:
311 * _US_UNWIND_FRAME_STARTING first time with this frame
312 * _US_UNWIND_FRAME_RESUME not first time, we are part-way through the EHT.
315 if ((ucbp->pr_cache.additional & 1) == 0) { /* EHT inline in index table? */
316 /* No: thus there is a real EHT */
318 if (state == _US_UNWIND_FRAME_RESUME) {
319 /* Recover saved pointer to next EHT entry */
320 ehtp = (uint8_t *)ucbp->cleanup_cache.bitpattern[CLEANUP_EHTP];
321 #ifdef PR_DIAGNOSTICS
322 printf("PR EHT recovered pointer 0x%x\n", (int)ehtp);
325 /* Point at the first EHT entry.
326 * For pr0, the unwind description is entirely within the header word.
327 * For pr1 & pr2, an unwind description extension word count is
328 * held in bits 16-23 of the header word.
330 uint32_t unwind_extension_word_count = (idx == 0 ? 0 : ((*eht_startp) >> 16) & 0xff);
331 ehtp = (uint8_t *)(eht_startp + 1 + unwind_extension_word_count);
333 #ifdef PR_DIAGNOSTICS
334 printf("PR EHT first entry at 0x%x\n", (int)ehtp);
342 /* Extract 32 bit length and offset */
347 length = ((EHT32 *)ehtp)->length;
348 if (length == 0) break; /* end of table */
349 offset = ((EHT32 *)ehtp)->offset;
350 ehtp += sizeof(EHT32);
353 length = ((EHT16 *)ehtp)->length;
354 if (length == 0) break; /* end of table */
355 offset = ((EHT16 *)ehtp)->offset;
356 ehtp += sizeof(EHT16);
359 #ifdef PR_DIAGNOSTICS
360 printf("PR Got entry at 0x%x code=%d, length=0x%x, offset=0x%x\n",
361 (int)(ehtp-4), ((offset & 1) << 1) | (length & 1),
362 length & ~1, offset & ~1);
365 /* Dispatch on the kind of entry */
366 switch (((offset & 1) << 1) | (length & 1)) {
367 case 0: /* cleanup */
368 if (state == _US_VIRTUAL_UNWIND_FRAME) {
369 /* Not a propagation barrier - skip */
371 /* Phase 2: call the cleanup if the return address is in range */
373 uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset;
374 uint32_t rtn_addr = core_get(context, R_PC);
375 if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
376 /* It is in range. */
377 /* We need both of these to support v1 and v2 */
378 landingpad_t *landingpadp = &((EHT_cleanup_tail *)ehtp)->landingpad;
379 landingpad_t landingpad = *landingpadp;
380 ehtp += sizeof(EHT_cleanup_tail);
381 /* Dump state into the ECO so we resume correctly after the cleanup. */
382 /* We simply save the address of the next EHT entry. */
383 ucbp->cleanup_cache.bitpattern[CLEANUP_EHTP] = (uint32_t)ehtp;
384 if (!__cxa_begin_cleanup(ucbp)) {
385 /* Should be impossible, using ARM's library */
386 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_UNSPECIFIED);
389 /* Set up the VRS to enter the landing pad. */
390 padaddress = ehabiv2 ?
391 __ARM_resolve_prel31(landingpadp) :
392 ER_RO_OFFSET_TO_ADDR(landingpad,ucbp);
393 core_set(context, R_PC, padaddress);
394 #ifdef PR_DIAGNOSTICS
395 printf("PR Got cleanup in range, cleanup addr=0x%x\n", core_get(context, R_PC));
396 printf("PR Saving EHT pointer 0x%x\n", (int)ehtp);
398 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, padaddress);
399 /* Exit requesting upload the VRS to the real machine. */
400 return _URC_INSTALL_CONTEXT;
403 /* Phase 1, or phase 2 and not in range */
404 ehtp += sizeof(EHT_cleanup_tail);
408 if (state == _US_VIRTUAL_UNWIND_FRAME) {
409 /* In range, and with a matching type? */
410 uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset;
411 uint32_t rtn_addr = core_get(context, R_PC);
412 void *matched_object;
413 length -= 1; /* length had low bit set - clear it */
414 if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
416 __cxa_type_match_result matched_result;
417 uint32_t *rtti_ref = &((EHT_catch_tail *)ehtp)->rtti_ref;
418 uint32_t rtti_val = *rtti_ref;
419 if (rtti_val == CATCH_ALL_AND_TERMINATE) {
420 /* Always matches and causes propagation failure in phase 1 */
421 #ifdef PR_DIAGNOSTICS
422 printf("PR Got CATCH_ALL_AND_TERMINATE in phase 1\n");
424 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
426 } else if (rtti_val == CATCH_ALL) {
427 matched_object = ucbp + 1;
428 matched_result = ctm_succeeded;
430 bool is_reference_type = ((uint32_t)(((EHT_catch_tail *)ehtp)->landingpad) & CATCH_REFERENCE)
433 (uint32_t)__ARM_resolve_target2((void *)rtti_ref) :
434 (uint32_t)ER_RO_OFFSET_TO_ADDR(rtti_val, ucbp);
435 matched_result =__cxa_type_match(ucbp,
436 (type_info *)rtti_val,
440 if (matched_result != ctm_failed) {
441 /* In range and matches.
442 * Record the propagation barrier details for ease of detection in phase 2.
443 * We save a pointer to the middle of the handler entry -
444 * this is fine, so long as we are consistent about it.
446 #ifdef PR_DIAGNOSTICS
447 printf("PR Got barrier in phase 1, result %d\n", (int)matched_result);
448 printf("PR Matched object address 0x%8.8x\n", matched_object);
450 if (matched_result == ctm_succeeded_with_ptr_to_base) {
451 SAVE_CATCH_OF_BASEPTR_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP),
452 ehtp, matched_object);
455 SAVE_CATCH_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP),
456 ehtp, matched_object);
458 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND,
460 __ARM_resolve_prel31(&((EHT_catch_tail *)ehtp)->landingpad) :
461 ER_RO_OFFSET_TO_ADDR(((EHT_catch_tail *)ehtp)->landingpad, ucbp)));
462 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_CPP_TYPEINFO, rtti_val);
463 return _URC_HANDLER_FOUND;
466 /* Not in range or no type match - fall thru to carry on scanning the table */
468 /* Else this is phase 2: have we encountered the saved barrier? */
469 if (CHECK_FOR_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp)) {
471 * Set up the VRS to enter the landing pad,
472 * and upload the VRS to the real machine.
474 landingpad_t *landingpadp = &((EHT_catch_tail *)ehtp)->landingpad;
475 landingpad_t landingpad = *landingpadp;
476 uint32_t padaddress = ehabiv2 ?
477 __ARM_resolve_prel31(landingpadp) :
478 ER_RO_OFFSET_TO_ADDR(landingpad, ucbp);
479 #ifdef PR_DIAGNOSTICS
480 printf("PR Got catch barrier in phase 2\n");
482 core_set(context, R_PC, padaddress);
483 core_set(context, 0, (uint32_t)ucbp);
484 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, padaddress);
485 /* Exit requesting upload the VRS to the real machine. */
486 return _URC_INSTALL_CONTEXT;
489 /* Else carry on scanning the table */
490 ehtp += sizeof(EHT_catch_tail);
493 case 2: /* function exception specification (fnspec) */
495 uint32_t counter_word = ((EHT_fnspec_tail *)ehtp)->rtti_count;
496 uint32_t rtti_count = counter_word & 0x7fffffff; /* Extract offset count */
497 if (state == _US_VIRTUAL_UNWIND_FRAME) {
499 /* In range? Offset had low bit set - clear it */
500 uint32_t rangestartaddr = ucbp->pr_cache.fnstart + offset - 1;
501 uint32_t rtn_addr = core_get(context, R_PC);
502 if (rangestartaddr <= rtn_addr && rtn_addr < rangestartaddr + length) {
503 /* See if any type matches */
504 uint32_t *rttipp = &((EHT_fnspec_tail *)ehtp)->rtti_refs[0];
506 for (i = 0; i < rtti_count; i++) {
507 void *matched_object;
510 artti = (type_info *)__ARM_resolve_target2(rttipp);
512 artti = (type_info *)ER_RO_OFFSET_TO_ADDR(*rttipp, ucbp);
513 if (__cxa_type_match(ucbp, artti, false, &matched_object)) {
514 #ifdef PR_DIAGNOSTICS
515 printf("PR Fnspec matched in phase 1\n");
522 if (i == rtti_count) { /* NB case rtti_count==0 forces no match [for throw()] */
523 /* No match - fnspec violation is a propagation barrier */
524 #ifdef PR_DIAGNOSTICS
525 printf("PR Got fnspec barrier in phase 1\n");
527 SAVE_FNSPEC_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp); /* save ptr to the count of types */
528 /* Even if this is a fnspec with a landing pad, we always end up in
529 * __cxa_call_unexpected so tell the debugger thats where we're going
531 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND, &__cxa_call_unexpected);
532 return _URC_HANDLER_FOUND;
534 } /* if (in range...) */
536 /* Fall out of the 'if' to continue table scanning */
539 /* Else this is phase 2: have we encountered the saved barrier? */
540 if (CHECK_FOR_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP), ehtp)) {
541 /* Yes we have. Fill in the UCB barrier_cache for entry to __cxa_call_unexpected */
542 uint32_t *p = (uint32_t *)ehtp; /* ptr to rtti count */
543 ucbp->barrier_cache.bitpattern[BARRIER_FNSPECCOUNT] = rtti_count;
544 ucbp->barrier_cache.bitpattern[BARRIER_FNSPECBASE] = ehabiv2 ? 0 :ER_RO_OFFSET_TO_ADDR(0, ucbp);
545 ucbp->barrier_cache.bitpattern[BARRIER_FNSPECSTRIDE] = 4; /* stride */
546 ucbp->barrier_cache.bitpattern[BARRIER_FNSPECARRAY] = (uint32_t)(p + 1); /* address of rtti offset list */
548 /* If this is a fnspec with an attached landing pad, we must enter
549 * the pad immediately. Otherwise we need to unwind the frame before
550 * calling __cxa_call_unexpected() so set a flag to make this happen.
552 if (counter_word == rtti_count)
553 phase2_call_unexpected_after_unwind = true; /* no pad, enter later */
555 landingpad_t *landingpadp;
556 landingpad_t landingpad;
558 #ifdef PR_DIAGNOSTICS
559 printf("PR Got fnspec barrier in phase 2 (immediate entry)\n");
561 ehtp += (sizeof(((EHT_fnspec_tail *)ehtp)->rtti_count) +
562 sizeof(uint32_t) * rtti_count); /* point at pad offset */
563 landingpadp = (landingpad_t *)ehtp;
564 landingpad = *(landingpad_t *)ehtp;
565 padaddress = ehabiv2 ?
566 __ARM_resolve_prel31(landingpadp) :
567 ER_RO_OFFSET_TO_ADDR(landingpad, ucbp);
568 core_set(context, 0, (uint32_t)ucbp);
569 core_set(context, R_PC, padaddress);
570 /* Even if this is a fnspec with a landing pad, in phase 1 we said we'd
571 * end up in __cxa_call_unexpected so show the same thing now
573 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, &__cxa_call_unexpected);
574 return _URC_INSTALL_CONTEXT;
576 } /* endif (barrier match) */
577 } /* endif (which phase) */
579 /* Advance to the next item, remembering to skip the landing pad if present */
580 ehtp += (sizeof(((EHT_fnspec_tail *)ehtp)->rtti_count) +
581 sizeof(uint32_t) * rtti_count +
582 (counter_word == rtti_count ? 0 : sizeof(landingpad_t)));
585 case 3: /* unallocated */
586 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT);
592 #ifdef PR_DIAGNOSTICS
593 printf("PR Reached end of EHT\n");
596 } /* if out-of-line EHT */
599 /* Do a virtual unwind of this frame - load the first unwind bytes then loop.
600 * Loop exit is by executing opcode CODE_FINISH.
603 ud.unwind_word = *(uint32_t *)eht_startp; /* first word */
604 ud.unwind_word_pointer = (uint32_t *)eht_startp + 1; /* ptr to extension words, if any */
605 if (idx == 0) { /* short description */
606 ud.unwind_words_remaining = 0; /* no further words */
607 ud.unwind_word <<= 8; /* 3 explicit unwind bytes in this word */
608 ud.unwind_word_bytes_remaining = 3;
609 } else { /* long description: extension word count in bits 16-23 */
610 ud.unwind_words_remaining = ((ud.unwind_word) >> 16) & 0xff;
611 ud.unwind_word <<= 16; /* 2 explicit unwind bytes in this word */
612 ud.unwind_word_bytes_remaining = 2;
615 #ifdef PR_DIAGNOSTICS
616 /* debug_print_vrs(context); */
620 uint8_t ub = next_unwind_byte(&ud);
622 #ifdef PR_DIAGNOSTICS
623 printf("PR Unwind byte 0x%x\n", ub);
626 /* decode and execute the current byte ... */
628 if (ub == CODE_FINISH) { /* finished unwinding */
632 /* If neither pc nor lr was written, the saved return address was
633 * not restored. This indicates broken unwind instructions.
635 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT);
638 _Unwind_VRS_Get(context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, &lr);
639 core_set(context, R_PC, lr);
640 wrote_pc_from_lr = true;
642 #ifdef PR_DIAGNOSTICS
645 _Unwind_VRS_Get(context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &nextpc);
646 printf("PR Next PC is 0x%x\n", nextpc);
651 if (ub <= 0x3f) { /* 00nnnnnn: vsp += (nnnnnn << 2) + 4 */
652 uint32_t increment = ((ub & 0x3f) << 2) + 4;
653 core_set(context, R_SP, core_get(context, R_SP) + increment);
656 if (ub <= 0x7f) { /* 01xxxxxx: vsp -= (xxxxxx << 2) + 4 */
657 uint32_t decrement = ((ub & 0x3f) << 2) + 4;
658 core_set(context, R_SP, core_get(context, R_SP) - decrement);
661 if (ub <= 0x8f) { /* 100000000 00000000: refuse, 1000rrrr rrrrrrrr: pop integer regs */
662 uint32_t mask = (ub & 0xf) << 12;
663 ub = next_unwind_byte(&ud);
665 if (mask == 0) { /* 10000000 00000000 refuse to unwind */
666 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
669 if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
670 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
673 if (mask & (1 << R_PC)) wrote_pc = true;
674 if (mask & (1 << R_LR)) wrote_lr = true;
677 if (ub <= 0x9f) { /* 1001nnnn: vsp = r[nnnn] if not 13,15 */
678 uint8_t regno = ub & 0xf;
679 if (regno == 13 || regno == R_PC) { /* reserved */
680 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
683 core_set(context, R_SP, core_get(context, regno));
686 if (ub <= 0xaf) { /* 1010xnnn: pop r4-r[4+nnn], +r14 if x */
687 uint32_t mask = count_to_mask((ub & 0x7) + 1) << 4;
692 if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
693 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
699 /* if (ub == 0xb0) is CODE_FINISH, handled earlier */
700 if (ub == 0xb1) { /* 10110001 0000iiii pop integer regs, others reserved */
701 uint32_t mask = next_unwind_byte(&ud);
702 if (mask == 0 || mask > 0xf) { /* reserved */
703 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
706 if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
707 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
712 if (ub == 0xb2) { /* 10110010 uleb128 : vsp += (uleb128 << 2) + 0x204 */
717 ub = next_unwind_byte(&ud);
718 u |= (ub & 0x7f) << n;
719 if ((ub & 0x80) == 0) break;
722 core_set(context, R_SP, core_get(context, R_SP) + (u << 2) + 0x204);
725 if (ub == 0xb3) { /* 10110011: pop vfp from FSTMFDX */
726 uint32_t discriminator = next_unwind_byte(&ud);
727 discriminator = ((discriminator & 0xf0) << 12) | ((discriminator & 0x0f) + 1);
728 if (_Unwind_VRS_Pop(context, _UVRSC_VFP, discriminator, _UVRSD_VFPX) != _UVRSR_OK) {
729 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
734 { /* 101101nn: was pop fpa, now spare */
735 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
738 } /* if (ub <= 0xb7) ... */
739 if (ub <= 0xbf) { /* 10111nnn: pop vfp from FSTMFDX */
740 uint32_t discriminator = 0x80000 | ((ub & 0x7) + 1);
741 if (_Unwind_VRS_Pop(context, _UVRSC_VFP, discriminator, _UVRSD_VFPX) != _UVRSR_OK) {
742 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
748 if (ub == 0xc7) { /* 11000111: WMMX C regs */
749 uint32_t mask = next_unwind_byte(&ud);
750 if (mask == 0 || mask > 0xf) { /* reserved */
751 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
754 if (_Unwind_VRS_Pop(context, _UVRSC_WMMXC, mask, _UVRSD_UINT32) != _UVRSR_OK) {
755 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
759 } else if (ub == 0xc6) { /* 11000110: WMMX D regs */
760 uint32_t discriminator = next_unwind_byte(&ud);
761 discriminator = ((discriminator & 0xf0) << 12) | ((discriminator & 0x0f) + 1);
762 if (_Unwind_VRS_Pop(context, _UVRSC_WMMXD, discriminator, _UVRSD_UINT64) != _UVRSR_OK) {
763 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
768 /* 11000nnn (nnn != 6, 7): WMMX D regs */
769 uint32_t discriminator = 0xa0000 | ((ub & 0x7) + 1);
770 if (_Unwind_VRS_Pop(context, _UVRSC_WMMXD, discriminator, _UVRSD_UINT64) != _UVRSR_OK) {
771 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
776 } /* if (ub <= 0xc7) ... */
777 if (ub == 0xc8 || /* 11001000 sssscccc: pop VFP hi regs from FSTMFDD */
778 ub == 0xc9) { /* 11001001 sssscccc: pop VFP from FSTMFDD */
779 uint32_t discriminator = next_unwind_byte(&ud);
780 discriminator = ((discriminator & 0xf0) << 12) | ((discriminator & 0x0f) + 1);
781 if (ub == 0xc8) discriminator += 16 << 16;
782 if (_Unwind_VRS_Pop(context, _UVRSC_VFP, discriminator, _UVRSD_DOUBLE) != _UVRSR_OK) {
783 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
788 if (ub <= 0xcf) { /* spare */
789 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
792 if (ub <= 0xd7) { /* 11010nnn: pop VFP from FSTMFDD */
793 uint32_t discriminator = 0x80000 | ((ub & 0x7) + 1);
794 if (_Unwind_VRS_Pop(context, _UVRSC_VFP, discriminator, _UVRSD_DOUBLE) != _UVRSR_OK) {
795 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
800 /* and in fact everything else is currently reserved or spare */
801 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
805 #ifdef PR_DIAGNOSTICS
806 /* debug_print_vrs(context); */
809 /* The VRS has now been updated to reflect the virtual unwind.
810 * If we are dealing with an unmatched fnspec, pop intervening frames
811 * and call unexpected(). Else return to our caller with an
812 * indication to continue unwinding.
815 if (phase2_call_unexpected_after_unwind) {
816 /* Set up the VRS to enter __cxa_call_unexpected,
817 * and upload the VRS to the real machine.
818 * The barrier_cache was initialised earlier.
820 #ifdef PR_DIAGNOSTICS
821 printf("PR Got fnspec barrier in phase 2 (unwinding completed)\n");
823 core_set(context, 0, (uint32_t)ucbp);
824 if (!wrote_pc_from_lr) {
826 /* Move the return address to lr to simulate a call */
827 _Unwind_VRS_Get(context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &pc);
828 core_set(context, R_LR, pc);
830 core_set(context, R_PC, (uint32_t)&__cxa_call_unexpected);
831 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, &__cxa_call_unexpected);
832 return _URC_INSTALL_CONTEXT;
835 /* Else continue with next frame */
836 return _URC_CONTINUE_UNWIND;
840 /* end ifdef prcommon_c */