0
|
1 |
/* unwind_pr.c - ARM-defined model personality routines
|
|
2 |
*
|
|
3 |
* Copyright 2002-2005 ARM Limited. All rights reserved.
|
|
4 |
*
|
|
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).
|
|
7 |
*/
|
|
8 |
|
|
9 |
/* Portions copyright Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). */
|
|
10 |
|
|
11 |
/*
|
|
12 |
* RCS $Revision: 92986 $
|
|
13 |
* Checkin $Date: 2005-10-13 15:56:12 +0100 (Thu, 13 Oct 2005) $
|
|
14 |
* Revising $Author: achapman $
|
|
15 |
*/
|
|
16 |
|
|
17 |
#include <cstdlib>
|
|
18 |
/* Environment: */
|
|
19 |
#include "unwind_env.h"
|
|
20 |
/* Language-independent unwinder declarations: */
|
|
21 |
#include "unwinder.h"
|
|
22 |
|
|
23 |
/* Define PR_DIAGNOSTICS for printed diagnostics from the personality routine */
|
|
24 |
|
|
25 |
#ifdef __EPOC32__
|
|
26 |
/* Symbian specific support */
|
|
27 |
#include "symbian_support.h"
|
|
28 |
#endif
|
|
29 |
|
|
30 |
#ifdef PR_DIAGNOSTICS
|
|
31 |
#ifndef __EPOC32__
|
|
32 |
extern int printf(const char *, ...);
|
|
33 |
#endif
|
|
34 |
#endif
|
|
35 |
|
|
36 |
|
|
37 |
/* Forward decl: */
|
|
38 |
extern _Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
|
|
39 |
_Unwind_Control_Block *ucbp,
|
|
40 |
_Unwind_Context *context,
|
|
41 |
uint32_t idx);
|
|
42 |
|
|
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.
|
|
47 |
*/
|
|
48 |
|
|
49 |
#ifdef pr0_c
|
|
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);
|
|
54 |
}
|
|
55 |
#endif
|
|
56 |
|
|
57 |
#ifdef pr1_c
|
|
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);
|
|
62 |
}
|
|
63 |
#endif
|
|
64 |
|
|
65 |
#ifdef pr2_c
|
|
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);
|
|
70 |
}
|
|
71 |
#endif
|
|
72 |
|
|
73 |
/* The rest of the file deals with the common routine */
|
|
74 |
|
|
75 |
#ifdef prcommon_c
|
|
76 |
|
|
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.
|
|
82 |
*/
|
|
83 |
|
|
84 |
typedef unsigned char bool;
|
|
85 |
static const bool false = 0;
|
|
86 |
static const bool true = !false;
|
|
87 |
|
|
88 |
typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
|
|
89 |
|
|
90 |
IMPORT_C WEAKDECL void __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
|
|
91 |
IMPORT_C WEAKDECL bool __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
|
|
92 |
typedef enum {
|
|
93 |
ctm_failed = 0,
|
|
94 |
ctm_succeeded = 1,
|
|
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);
|
|
101 |
|
|
102 |
/* ----- Helper routines, private ----- */
|
|
103 |
|
|
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.
|
|
107 |
*/
|
|
108 |
static FORCEINLINE uint32_t __ARM_resolve_prel31(void *p)
|
|
109 |
{
|
|
110 |
return (uint32_t)((((*(int32_t *)p) << 1) >> 1) + (int32_t)p);
|
|
111 |
}
|
|
112 |
|
|
113 |
/* --------- VRS manipulation: --------- */
|
|
114 |
|
|
115 |
#define R_SP 13
|
|
116 |
#define R_LR 14
|
|
117 |
#define R_PC 15
|
|
118 |
|
|
119 |
static FORCEINLINE uint32_t core_get(_Unwind_Context *context, uint32_t regno)
|
|
120 |
{
|
|
121 |
uint32_t val;
|
|
122 |
/* This call is required to never fail if given a valid regno */
|
|
123 |
_Unwind_VRS_Get(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
|
|
124 |
return val;
|
|
125 |
}
|
|
126 |
|
|
127 |
static FORCEINLINE void core_set(_Unwind_Context *context, uint32_t regno, uint32_t newval)
|
|
128 |
{
|
|
129 |
/* This call is required to never fail if given a valid regno */
|
|
130 |
_Unwind_VRS_Set(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &newval);
|
|
131 |
}
|
|
132 |
|
|
133 |
static FORCEINLINE uint32_t count_to_mask(uint32_t count) {
|
|
134 |
return (1 << count) - 1;
|
|
135 |
}
|
|
136 |
|
|
137 |
/* --------- Support for unwind instruction stream: --------- */
|
|
138 |
|
|
139 |
#define CODE_FINISH (0xb0)
|
|
140 |
|
|
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 */
|
|
146 |
} uwdata;
|
|
147 |
|
|
148 |
static INLINE uint8_t next_unwind_byte(uwdata *u) {
|
|
149 |
uint8_t ub;
|
|
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;
|
|
155 |
}
|
|
156 |
|
|
157 |
u->unwind_word_bytes_remaining--;
|
|
158 |
ub = (u->unwind_word & 0xff000000) >> 24;
|
|
159 |
u->unwind_word <<= 8;
|
|
160 |
return ub;
|
|
161 |
}
|
|
162 |
|
|
163 |
|
|
164 |
/* --------- Personality routines: --------- */
|
|
165 |
|
|
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().
|
|
172 |
*/
|
|
173 |
|
|
174 |
/* Types to assist with reading EHT's */
|
|
175 |
|
|
176 |
typedef struct {
|
|
177 |
uint16_t length;
|
|
178 |
uint16_t offset;
|
|
179 |
} EHT16;
|
|
180 |
|
|
181 |
typedef struct {
|
|
182 |
uint32_t length;
|
|
183 |
uint32_t offset;
|
|
184 |
} EHT32;
|
|
185 |
|
|
186 |
typedef uint32_t landingpad_t;
|
|
187 |
|
|
188 |
typedef struct {
|
|
189 |
landingpad_t landingpad;
|
|
190 |
} EHT_cleanup_tail;
|
|
191 |
|
|
192 |
typedef struct {
|
|
193 |
landingpad_t landingpad;
|
|
194 |
uint32_t rtti_ref;
|
|
195 |
} EHT_catch_tail;
|
|
196 |
|
|
197 |
typedef struct {
|
|
198 |
uint32_t rtti_count; /* table count (possibly 0) */
|
|
199 |
uint32_t (rtti_refs[1]); /* variable length table, possibly followed by landing pad */
|
|
200 |
} EHT_fnspec_tail;
|
|
201 |
|
|
202 |
|
|
203 |
/* Macros: */
|
|
204 |
|
|
205 |
/* Barrier cache: */
|
|
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)
|
|
217 |
|
|
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);
|
|
222 |
|
|
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]);
|
|
228 |
|
|
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;
|
|
233 |
|
|
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))
|
|
237 |
|
|
238 |
|
|
239 |
/* Cleanup cache: We only use one field */
|
|
240 |
#define CLEANUP_EHTP (0)
|
|
241 |
|
|
242 |
|
|
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)
|
|
248 |
|
|
249 |
|
|
250 |
/* Common personality routine: receives pr index as an argument.
|
|
251 |
*
|
|
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.
|
|
258 |
*/
|
|
259 |
|
|
260 |
_Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
|
|
261 |
_Unwind_Control_Block *ucbp,
|
|
262 |
_Unwind_Context *context,
|
|
263 |
uint32_t idx)
|
|
264 |
{
|
|
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.
|
|
272 |
*/
|
|
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.
|
|
277 |
*/
|
|
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;
|
|
281 |
uwdata ud;
|
|
282 |
|
|
283 |
/* Are we version 2 of the EHABI ? */
|
|
284 |
bool ehabiv2 = EHABI_V2(ucbp);
|
|
285 |
|
|
286 |
/* Mark all as well and extract the EHT pointer */
|
|
287 |
|
|
288 |
eht_startp = ucbp->pr_cache.ehtp;
|
|
289 |
|
|
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);
|
|
293 |
#endif
|
|
294 |
|
|
295 |
/* What are we supposed to do? */
|
|
296 |
|
|
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);
|
|
301 |
return _URC_FAILURE;
|
|
302 |
}
|
|
303 |
|
|
304 |
phase2_call_unexpected_after_unwind = false;
|
|
305 |
|
|
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.
|
|
313 |
*/
|
|
314 |
|
|
315 |
if ((ucbp->pr_cache.additional & 1) == 0) { /* EHT inline in index table? */
|
|
316 |
/* No: thus there is a real EHT */
|
|
317 |
|
|
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);
|
|
323 |
#endif
|
|
324 |
} else {
|
|
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.
|
|
329 |
*/
|
|
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);
|
|
332 |
|
|
333 |
#ifdef PR_DIAGNOSTICS
|
|
334 |
printf("PR EHT first entry at 0x%x\n", (int)ehtp);
|
|
335 |
#endif
|
|
336 |
}
|
|
337 |
|
|
338 |
/* scan ... */
|
|
339 |
|
|
340 |
while (1) {
|
|
341 |
|
|
342 |
/* Extract 32 bit length and offset */
|
|
343 |
uint32_t length;
|
|
344 |
uint32_t offset;
|
|
345 |
if (idx == 2) {
|
|
346 |
/* 32 bit offsets */
|
|
347 |
length = ((EHT32 *)ehtp)->length;
|
|
348 |
if (length == 0) break; /* end of table */
|
|
349 |
offset = ((EHT32 *)ehtp)->offset;
|
|
350 |
ehtp += sizeof(EHT32);
|
|
351 |
} else {
|
|
352 |
/* 16 bit offsets */
|
|
353 |
length = ((EHT16 *)ehtp)->length;
|
|
354 |
if (length == 0) break; /* end of table */
|
|
355 |
offset = ((EHT16 *)ehtp)->offset;
|
|
356 |
ehtp += sizeof(EHT16);
|
|
357 |
}
|
|
358 |
|
|
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);
|
|
363 |
#endif
|
|
364 |
|
|
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 */
|
|
370 |
} else {
|
|
371 |
/* Phase 2: call the cleanup if the return address is in range */
|
|
372 |
uint32_t padaddress;
|
|
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);
|
|
387 |
return _URC_FAILURE;
|
|
388 |
}
|
|
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);
|
|
397 |
#endif
|
|
398 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, padaddress);
|
|
399 |
/* Exit requesting upload the VRS to the real machine. */
|
|
400 |
return _URC_INSTALL_CONTEXT;
|
|
401 |
}
|
|
402 |
}
|
|
403 |
/* Phase 1, or phase 2 and not in range */
|
|
404 |
ehtp += sizeof(EHT_cleanup_tail);
|
|
405 |
break;
|
|
406 |
case 1: /* catch */
|
|
407 |
{
|
|
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) {
|
|
415 |
/* In range */
|
|
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");
|
|
423 |
#endif
|
|
424 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
|
|
425 |
return _URC_FAILURE;
|
|
426 |
} else if (rtti_val == CATCH_ALL) {
|
|
427 |
matched_object = ucbp + 1;
|
|
428 |
matched_result = ctm_succeeded;
|
|
429 |
} else {
|
|
430 |
bool is_reference_type = ((uint32_t)(((EHT_catch_tail *)ehtp)->landingpad) & CATCH_REFERENCE)
|
|
431 |
== CATCH_REFERENCE;
|
|
432 |
rtti_val = ehabiv2 ?
|
|
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,
|
|
437 |
is_reference_type,
|
|
438 |
&matched_object);
|
|
439 |
}
|
|
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.
|
|
445 |
*/
|
|
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);
|
|
449 |
#endif
|
|
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);
|
|
453 |
|
|
454 |
} else {
|
|
455 |
SAVE_CATCH_PROPAGATION_BARRIER(ucbp, core_get(context, R_SP),
|
|
456 |
ehtp, matched_object);
|
|
457 |
}
|
|
458 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND,
|
|
459 |
(ehabiv2 ?
|
|
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;
|
|
464 |
}
|
|
465 |
}
|
|
466 |
/* Not in range or no type match - fall thru to carry on scanning the table */
|
|
467 |
} else {
|
|
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)) {
|
|
470 |
/* Yes we have.
|
|
471 |
* Set up the VRS to enter the landing pad,
|
|
472 |
* and upload the VRS to the real machine.
|
|
473 |
*/
|
|
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");
|
|
481 |
#endif
|
|
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;
|
|
487 |
}
|
|
488 |
}
|
|
489 |
/* Else carry on scanning the table */
|
|
490 |
ehtp += sizeof(EHT_catch_tail);
|
|
491 |
break;
|
|
492 |
}
|
|
493 |
case 2: /* function exception specification (fnspec) */
|
|
494 |
{
|
|
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) {
|
|
498 |
/* Phase 1 */
|
|
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];
|
|
505 |
uint32_t i;
|
|
506 |
for (i = 0; i < rtti_count; i++) {
|
|
507 |
void *matched_object;
|
|
508 |
type_info * artti;
|
|
509 |
if (ehabiv2)
|
|
510 |
artti = (type_info *)__ARM_resolve_target2(rttipp);
|
|
511 |
else
|
|
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");
|
|
516 |
#endif
|
|
517 |
break;
|
|
518 |
}
|
|
519 |
rttipp++;
|
|
520 |
}
|
|
521 |
|
|
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");
|
|
526 |
#endif
|
|
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
|
|
530 |
*/
|
|
531 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND, &__cxa_call_unexpected);
|
|
532 |
return _URC_HANDLER_FOUND;
|
|
533 |
}
|
|
534 |
} /* if (in range...) */
|
|
535 |
|
|
536 |
/* Fall out of the 'if' to continue table scanning */
|
|
537 |
|
|
538 |
} else {
|
|
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 */
|
|
547 |
|
|
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.
|
|
551 |
*/
|
|
552 |
if (counter_word == rtti_count)
|
|
553 |
phase2_call_unexpected_after_unwind = true; /* no pad, enter later */
|
|
554 |
else { /* pad */
|
|
555 |
landingpad_t *landingpadp;
|
|
556 |
landingpad_t landingpad;
|
|
557 |
uint32_t padaddress;
|
|
558 |
#ifdef PR_DIAGNOSTICS
|
|
559 |
printf("PR Got fnspec barrier in phase 2 (immediate entry)\n");
|
|
560 |
#endif
|
|
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
|
|
572 |
*/
|
|
573 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, &__cxa_call_unexpected);
|
|
574 |
return _URC_INSTALL_CONTEXT;
|
|
575 |
}
|
|
576 |
} /* endif (barrier match) */
|
|
577 |
} /* endif (which phase) */
|
|
578 |
|
|
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)));
|
|
583 |
break;
|
|
584 |
}
|
|
585 |
case 3: /* unallocated */
|
|
586 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT);
|
|
587 |
return _URC_FAILURE;
|
|
588 |
} /* switch */
|
|
589 |
|
|
590 |
} /* while (1) */
|
|
591 |
|
|
592 |
#ifdef PR_DIAGNOSTICS
|
|
593 |
printf("PR Reached end of EHT\n");
|
|
594 |
#endif
|
|
595 |
|
|
596 |
} /* if out-of-line EHT */
|
|
597 |
|
|
598 |
|
|
599 |
/* Do a virtual unwind of this frame - load the first unwind bytes then loop.
|
|
600 |
* Loop exit is by executing opcode CODE_FINISH.
|
|
601 |
*/
|
|
602 |
|
|
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;
|
|
613 |
}
|
|
614 |
|
|
615 |
#ifdef PR_DIAGNOSTICS
|
|
616 |
/* debug_print_vrs(context); */
|
|
617 |
#endif
|
|
618 |
|
|
619 |
while (1) {
|
|
620 |
uint8_t ub = next_unwind_byte(&ud);
|
|
621 |
|
|
622 |
#ifdef PR_DIAGNOSTICS
|
|
623 |
printf("PR Unwind byte 0x%x\n", ub);
|
|
624 |
#endif
|
|
625 |
|
|
626 |
/* decode and execute the current byte ... */
|
|
627 |
|
|
628 |
if (ub == CODE_FINISH) { /* finished unwinding */
|
|
629 |
if (!wrote_pc) {
|
|
630 |
uint32_t lr;
|
|
631 |
if (!wrote_lr) {
|
|
632 |
/* If neither pc nor lr was written, the saved return address was
|
|
633 |
* not restored. This indicates broken unwind instructions.
|
|
634 |
*/
|
|
635 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT);
|
|
636 |
return _URC_FAILURE;
|
|
637 |
}
|
|
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;
|
|
641 |
}
|
|
642 |
#ifdef PR_DIAGNOSTICS
|
|
643 |
{
|
|
644 |
uint32_t nextpc;
|
|
645 |
_Unwind_VRS_Get(context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &nextpc);
|
|
646 |
printf("PR Next PC is 0x%x\n", nextpc);
|
|
647 |
}
|
|
648 |
#endif
|
|
649 |
break;
|
|
650 |
}
|
|
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);
|
|
654 |
continue;
|
|
655 |
}
|
|
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);
|
|
659 |
continue;
|
|
660 |
}
|
|
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);
|
|
664 |
mask |= ub << 4;
|
|
665 |
if (mask == 0) { /* 10000000 00000000 refuse to unwind */
|
|
666 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
|
|
667 |
return _URC_FAILURE;
|
|
668 |
}
|
|
669 |
if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
|
|
670 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
|
|
671 |
return _URC_FAILURE;
|
|
672 |
}
|
|
673 |
if (mask & (1 << R_PC)) wrote_pc = true;
|
|
674 |
if (mask & (1 << R_LR)) wrote_lr = true;
|
|
675 |
continue;
|
|
676 |
}
|
|
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);
|
|
681 |
return _URC_FAILURE;
|
|
682 |
}
|
|
683 |
core_set(context, R_SP, core_get(context, regno));
|
|
684 |
continue;
|
|
685 |
}
|
|
686 |
if (ub <= 0xaf) { /* 1010xnnn: pop r4-r[4+nnn], +r14 if x */
|
|
687 |
uint32_t mask = count_to_mask((ub & 0x7) + 1) << 4;
|
|
688 |
if (ub & 0x8) {
|
|
689 |
mask |= (1 << R_LR);
|
|
690 |
wrote_lr = true;
|
|
691 |
}
|
|
692 |
if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
|
|
693 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
|
|
694 |
return _URC_FAILURE;
|
|
695 |
}
|
|
696 |
continue;
|
|
697 |
}
|
|
698 |
if (ub <= 0xb7) {
|
|
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);
|
|
704 |
return _URC_FAILURE;
|
|
705 |
}
|
|
706 |
if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
|
|
707 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
|
|
708 |
return _URC_FAILURE;
|
|
709 |
}
|
|
710 |
continue;
|
|
711 |
}
|
|
712 |
if (ub == 0xb2) { /* 10110010 uleb128 : vsp += (uleb128 << 2) + 0x204 */
|
|
713 |
uint32_t u = 0;
|
|
714 |
uint32_t n = 0;
|
|
715 |
/* decode */
|
|
716 |
while (1) {
|
|
717 |
ub = next_unwind_byte(&ud);
|
|
718 |
u |= (ub & 0x7f) << n;
|
|
719 |
if ((ub & 0x80) == 0) break;
|
|
720 |
n += 7;
|
|
721 |
}
|
|
722 |
core_set(context, R_SP, core_get(context, R_SP) + (u << 2) + 0x204);
|
|
723 |
continue;
|
|
724 |
}
|
|
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);
|
|
730 |
return _URC_FAILURE;
|
|
731 |
}
|
|
732 |
continue;
|
|
733 |
}
|
|
734 |
{ /* 101101nn: was pop fpa, now spare */
|
|
735 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
|
|
736 |
return _URC_FAILURE;
|
|
737 |
}
|
|
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);
|
|
743 |
return _URC_FAILURE;
|
|
744 |
}
|
|
745 |
continue;
|
|
746 |
}
|
|
747 |
if (ub <= 0xc7) {
|
|
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);
|
|
752 |
return _URC_FAILURE;
|
|
753 |
}
|
|
754 |
if (_Unwind_VRS_Pop(context, _UVRSC_WMMXC, mask, _UVRSD_UINT32) != _UVRSR_OK) {
|
|
755 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
|
|
756 |
return _URC_FAILURE;
|
|
757 |
}
|
|
758 |
continue;
|
|
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);
|
|
764 |
return _URC_FAILURE;
|
|
765 |
}
|
|
766 |
continue;
|
|
767 |
} else {
|
|
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);
|
|
772 |
return _URC_FAILURE;
|
|
773 |
}
|
|
774 |
continue;
|
|
775 |
}
|
|
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);
|
|
784 |
return _URC_FAILURE;
|
|
785 |
}
|
|
786 |
continue;
|
|
787 |
}
|
|
788 |
if (ub <= 0xcf) { /* spare */
|
|
789 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
|
|
790 |
return _URC_FAILURE;
|
|
791 |
}
|
|
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);
|
|
796 |
return _URC_FAILURE;
|
|
797 |
}
|
|
798 |
continue;
|
|
799 |
}
|
|
800 |
/* and in fact everything else is currently reserved or spare */
|
|
801 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
|
|
802 |
return _URC_FAILURE;
|
|
803 |
}
|
|
804 |
|
|
805 |
#ifdef PR_DIAGNOSTICS
|
|
806 |
/* debug_print_vrs(context); */
|
|
807 |
#endif
|
|
808 |
|
|
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.
|
|
813 |
*/
|
|
814 |
|
|
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.
|
|
819 |
*/
|
|
820 |
#ifdef PR_DIAGNOSTICS
|
|
821 |
printf("PR Got fnspec barrier in phase 2 (unwinding completed)\n");
|
|
822 |
#endif
|
|
823 |
core_set(context, 0, (uint32_t)ucbp);
|
|
824 |
if (!wrote_pc_from_lr) {
|
|
825 |
uint32_t pc;
|
|
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);
|
|
829 |
}
|
|
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;
|
|
833 |
}
|
|
834 |
|
|
835 |
/* Else continue with next frame */
|
|
836 |
return _URC_CONTINUE_UNWIND;
|
|
837 |
}
|
|
838 |
|
|
839 |
#endif
|
|
840 |
/* end ifdef prcommon_c */
|