0
|
1 |
/* unwind_pr.c - ARM-defined model personality routines
|
|
2 |
*
|
|
3 |
* Copyright 2002-2003 ARM Limited.
|
|
4 |
*/
|
|
5 |
/*
|
|
6 |
Licence
|
|
7 |
|
|
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
|
|
15 |
licensors.
|
|
16 |
|
|
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.
|
|
21 |
*/
|
|
22 |
/*
|
|
23 |
* RCS $Revision: 1.20 $
|
|
24 |
* Checkin $Date: 2003/11/10 17:13:37 $
|
|
25 |
* Revising $Author: achapman $
|
|
26 |
*/
|
|
27 |
|
|
28 |
#include <cstdlib>
|
|
29 |
/* Environment: */
|
|
30 |
#include "unwind_env.h"
|
|
31 |
/* Language-independent unwinder declarations: */
|
|
32 |
#include "unwinder.h"
|
|
33 |
|
|
34 |
/* Define PR_DIAGNOSTICS for printed diagnostics from the personality routine */
|
|
35 |
|
|
36 |
#ifdef PR_DIAGNOSTICS
|
|
37 |
extern int printf(const char *, ...);
|
|
38 |
#endif
|
|
39 |
|
|
40 |
|
|
41 |
/* Forward decl: */
|
|
42 |
extern _Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
|
|
43 |
_Unwind_Control_Block *ucbp,
|
|
44 |
_Unwind_Context *context,
|
|
45 |
uint32_t idx);
|
|
46 |
|
|
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.
|
|
51 |
*/
|
|
52 |
|
|
53 |
#ifdef pr0_c
|
|
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);
|
|
58 |
}
|
|
59 |
#endif
|
|
60 |
|
|
61 |
#ifdef pr1_c
|
|
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);
|
|
66 |
}
|
|
67 |
#endif
|
|
68 |
|
|
69 |
#ifdef pr2_c
|
|
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);
|
|
74 |
}
|
|
75 |
#endif
|
|
76 |
|
|
77 |
/* The rest of the file deals with the common routine */
|
|
78 |
|
|
79 |
#ifdef prcommon_c
|
|
80 |
|
|
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.
|
|
86 |
*/
|
|
87 |
|
|
88 |
typedef unsigned char bool;
|
|
89 |
static const bool false = 0;
|
|
90 |
static const bool true = !false;
|
|
91 |
|
|
92 |
typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
|
|
93 |
|
|
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);
|
|
99 |
|
|
100 |
|
|
101 |
/* ----- Address manipulation: ----- */
|
|
102 |
|
|
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
|
|
108 |
* computing &W - W.
|
|
109 |
*/
|
|
110 |
|
|
111 |
extern const uint32_t __ARM_unwind_cpp_ROSegBase_SelfOffset;
|
|
112 |
|
|
113 |
__asm void __ARM_unwind_cpp_basehelper(void)
|
|
114 |
{
|
|
115 |
export __ARM_unwind_cpp_ROSegBase_SelfOffset;
|
|
116 |
R_ARM_ROSEGREL32 EQU 39
|
|
117 |
__ARM_unwind_cpp_ROSegBase_SelfOffset;
|
|
118 |
dcd 0;
|
|
119 |
__RELOC R_ARM_ROSEGREL32,__ARM_unwind_cpp_ROSegBase_SelfOffset;
|
|
120 |
}
|
|
121 |
|
|
122 |
#define ER_RO_SegBase ((uint32_t)&__ARM_unwind_cpp_ROSegBase_SelfOffset - \
|
|
123 |
__ARM_unwind_cpp_ROSegBase_SelfOffset)
|
|
124 |
|
|
125 |
/* And now the function used to convert segment-relative offsets
|
|
126 |
* to absolute addresses.
|
|
127 |
*/
|
|
128 |
|
|
129 |
static __inline uint32_t ER_RO_offset_to_addr(uint32_t offset)
|
|
130 |
{
|
|
131 |
return offset + ER_RO_SegBase;
|
|
132 |
}
|
|
133 |
|
|
134 |
|
|
135 |
/* --------- VRS manipulation: --------- */
|
|
136 |
|
|
137 |
#define R_SP 13
|
|
138 |
#define R_LR 14
|
|
139 |
#define R_PC 15
|
|
140 |
|
|
141 |
static __inline uint32_t core_get(_Unwind_Context *context, uint32_t regno)
|
|
142 |
{
|
|
143 |
uint32_t val;
|
|
144 |
/* This call is required to never fail if given a valid regno */
|
|
145 |
_Unwind_VRS_Get(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
|
|
146 |
return val;
|
|
147 |
}
|
|
148 |
|
|
149 |
static __inline void core_set(_Unwind_Context *context, uint32_t regno, uint32_t newval)
|
|
150 |
{
|
|
151 |
/* This call is required to never fail if given a valid regno */
|
|
152 |
_Unwind_VRS_Set(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &newval);
|
|
153 |
}
|
|
154 |
|
|
155 |
static __inline uint32_t count_to_mask(uint32_t count) {
|
|
156 |
return (1 << count) - 1;
|
|
157 |
}
|
|
158 |
|
|
159 |
/* --------- Support for unwind instruction stream: --------- */
|
|
160 |
|
|
161 |
#define CODE_FINISH (0xb0)
|
|
162 |
|
|
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 */
|
|
168 |
} uwdata;
|
|
169 |
|
|
170 |
static __inline uint8_t next_unwind_byte(uwdata *u) {
|
|
171 |
uint8_t ub;
|
|
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;
|
|
177 |
}
|
|
178 |
|
|
179 |
u->unwind_word_bytes_remaining--;
|
|
180 |
ub = (u->unwind_word & 0xff000000) >> 24;
|
|
181 |
u->unwind_word <<= 8;
|
|
182 |
return ub;
|
|
183 |
}
|
|
184 |
|
|
185 |
|
|
186 |
/* --------- Personality routines: --------- */
|
|
187 |
|
|
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().
|
|
194 |
*/
|
|
195 |
|
|
196 |
/* Types to assist with reading EHT's */
|
|
197 |
|
|
198 |
typedef struct {
|
|
199 |
uint16_t length;
|
|
200 |
uint16_t offset;
|
|
201 |
} EHT16;
|
|
202 |
|
|
203 |
typedef struct {
|
|
204 |
uint32_t length;
|
|
205 |
uint32_t offset;
|
|
206 |
} EHT32;
|
|
207 |
|
|
208 |
typedef uint32_t landingpad_t;
|
|
209 |
|
|
210 |
typedef struct {
|
|
211 |
landingpad_t landingpad;
|
|
212 |
} EHT_cleanup_tail;
|
|
213 |
|
|
214 |
typedef struct {
|
|
215 |
landingpad_t landingpad;
|
|
216 |
uint32_t rtti_offset;
|
|
217 |
} EHT_catch_tail;
|
|
218 |
|
|
219 |
typedef struct {
|
|
220 |
uint32_t rtti_count; /* table count (possibly 0) */
|
|
221 |
uint32_t (rtti_offsets[1]); /* variable length table, possibly followed by landing pad */
|
|
222 |
} EHT_fnspec_tail;
|
|
223 |
|
|
224 |
|
|
225 |
/* Macros: */
|
|
226 |
|
|
227 |
/* Barrier cache: */
|
|
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)
|
|
237 |
|
|
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);
|
|
242 |
|
|
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))
|
|
246 |
|
|
247 |
|
|
248 |
/* Cleanup cache: We only use one field */
|
|
249 |
#define CLEANUP_EHTP (0)
|
|
250 |
|
|
251 |
|
|
252 |
/* Special catch rtti values */
|
|
253 |
#define CATCH_ALL (0xffffffff)
|
|
254 |
#define CATCH_ALL_AND_TERMINATE (0xfffffffe)
|
|
255 |
|
|
256 |
|
|
257 |
/* Common personality routine: receives pr index as an argument.
|
|
258 |
*
|
|
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.
|
|
265 |
*/
|
|
266 |
|
|
267 |
_Unwind_Reason_Code __ARM_unwind_cpp_prcommon(_Unwind_State state,
|
|
268 |
_Unwind_Control_Block *ucbp,
|
|
269 |
_Unwind_Context *context,
|
|
270 |
uint32_t idx)
|
|
271 |
{
|
|
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.
|
|
279 |
*/
|
|
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;
|
|
283 |
uwdata ud;
|
|
284 |
|
|
285 |
/* Mark all as well and extract the EHT pointer */
|
|
286 |
|
|
287 |
eht_startp = ucbp->pr_cache.ehtp;
|
|
288 |
|
|
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);
|
|
292 |
#endif
|
|
293 |
|
|
294 |
/* What are we supposed to do? */
|
|
295 |
|
|
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);
|
|
300 |
return _URC_FAILURE;
|
|
301 |
}
|
|
302 |
|
|
303 |
phase2_call_unexpected_after_unwind = false;
|
|
304 |
|
|
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.
|
|
312 |
*/
|
|
313 |
|
|
314 |
if ((ucbp->pr_cache.additional & 1) == 0) { /* EHT inline in index table? */
|
|
315 |
/* No: thus there is a real EHT */
|
|
316 |
|
|
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);
|
|
322 |
#endif
|
|
323 |
} else {
|
|
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.
|
|
328 |
*/
|
|
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);
|
|
331 |
|
|
332 |
#ifdef PR_DIAGNOSTICS
|
|
333 |
printf("PR EHT first entry at 0x%x\n", (int)ehtp);
|
|
334 |
#endif
|
|
335 |
}
|
|
336 |
|
|
337 |
/* scan ... */
|
|
338 |
|
|
339 |
while (1) {
|
|
340 |
|
|
341 |
/* Extract 32 bit length and offset */
|
|
342 |
uint32_t length;
|
|
343 |
uint32_t offset;
|
|
344 |
if (idx == 2) {
|
|
345 |
/* 32 bit offsets */
|
|
346 |
length = ((EHT32 *)ehtp)->length;
|
|
347 |
if (length == 0) break; /* end of table */
|
|
348 |
offset = ((EHT32 *)ehtp)->offset;
|
|
349 |
ehtp += sizeof(EHT32);
|
|
350 |
} else {
|
|
351 |
/* 16 bit offsets */
|
|
352 |
length = ((EHT16 *)ehtp)->length;
|
|
353 |
if (length == 0) break; /* end of table */
|
|
354 |
offset = ((EHT16 *)ehtp)->offset;
|
|
355 |
ehtp += sizeof(EHT16);
|
|
356 |
}
|
|
357 |
|
|
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);
|
|
362 |
#endif
|
|
363 |
|
|
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 */
|
|
369 |
} else {
|
|
370 |
/* Phase 2: call the cleanup if the return address is in range */
|
|
371 |
uint32_t padaddress;
|
|
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);
|
|
384 |
return _URC_FAILURE;
|
|
385 |
}
|
|
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);
|
|
392 |
#endif
|
|
393 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, padaddress);
|
|
394 |
/* Exit requesting upload the VRS to the real machine. */
|
|
395 |
return _URC_INSTALL_CONTEXT;
|
|
396 |
}
|
|
397 |
}
|
|
398 |
/* Phase 1, or phase 2 and not in range */
|
|
399 |
ehtp += sizeof(EHT_cleanup_tail);
|
|
400 |
break;
|
|
401 |
case 1: /* catch */
|
|
402 |
{
|
|
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) {
|
|
410 |
/* In range */
|
|
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");
|
|
416 |
#endif
|
|
417 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
|
|
418 |
return _URC_FAILURE;
|
|
419 |
}
|
|
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)),
|
|
423 |
&matched_object)) {
|
|
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.
|
|
428 |
*/
|
|
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);
|
|
432 |
#endif
|
|
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;
|
|
438 |
}
|
|
439 |
}
|
|
440 |
/* Not in range or no type match - fall thru to carry on scanning the table */
|
|
441 |
} else {
|
|
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)) {
|
|
444 |
/* Yes we have.
|
|
445 |
* Set up the VRS to enter the landing pad,
|
|
446 |
* and upload the VRS to the real machine.
|
|
447 |
*/
|
|
448 |
landingpad_t landingpad;
|
|
449 |
uint32_t padaddress;
|
|
450 |
#ifdef PR_DIAGNOSTICS
|
|
451 |
printf("PR Got catch barrier in phase 2\n");
|
|
452 |
#endif
|
|
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;
|
|
460 |
}
|
|
461 |
}
|
|
462 |
/* Else carry on scanning the table */
|
|
463 |
ehtp += sizeof(EHT_catch_tail);
|
|
464 |
break;
|
|
465 |
}
|
|
466 |
case 2: /* function exception specification (fnspec) */
|
|
467 |
{
|
|
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) {
|
|
471 |
/* Phase 1 */
|
|
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];
|
|
478 |
uint32_t i;
|
|
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),
|
|
483 |
&matched_object)) {
|
|
484 |
#ifdef PR_DIAGNOSTICS
|
|
485 |
printf("PR Fnspec matched in phase 1\n");
|
|
486 |
#endif
|
|
487 |
break;
|
|
488 |
}
|
|
489 |
rttipp++;
|
|
490 |
}
|
|
491 |
|
|
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");
|
|
496 |
#endif
|
|
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
|
|
500 |
*/
|
|
501 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_BARRIERFOUND, &__cxa_call_unexpected);
|
|
502 |
return _URC_HANDLER_FOUND;
|
|
503 |
}
|
|
504 |
} /* if (in range...) */
|
|
505 |
|
|
506 |
/* Fall out of the 'if' to continue table scanning */
|
|
507 |
|
|
508 |
} else {
|
|
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 */
|
|
517 |
|
|
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.
|
|
521 |
*/
|
|
522 |
if (counter_word == rtti_count)
|
|
523 |
phase2_call_unexpected_after_unwind = true; /* no pad, enter later */
|
|
524 |
else { /* pad */
|
|
525 |
landingpad_t landingpad;
|
|
526 |
uint32_t padaddress;
|
|
527 |
#ifdef PR_DIAGNOSTICS
|
|
528 |
printf("PR Got fnspec barrier in phase 2 (immediate entry)\n");
|
|
529 |
#endif
|
|
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
|
|
538 |
*/
|
|
539 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_PADENTRY, &__cxa_call_unexpected);
|
|
540 |
return _URC_INSTALL_CONTEXT;
|
|
541 |
}
|
|
542 |
} /* endif (barrier match) */
|
|
543 |
} /* endif (which phase) */
|
|
544 |
|
|
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)));
|
|
549 |
break;
|
|
550 |
}
|
|
551 |
case 3: /* unallocated */
|
|
552 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT);
|
|
553 |
return _URC_FAILURE;
|
|
554 |
} /* switch */
|
|
555 |
|
|
556 |
} /* while (1) */
|
|
557 |
|
|
558 |
#ifdef PR_DIAGNOSTICS
|
|
559 |
printf("PR Reached end of EHT\n");
|
|
560 |
#endif
|
|
561 |
|
|
562 |
} /* if out-of-line EHT */
|
|
563 |
|
|
564 |
|
|
565 |
/* Do a virtual unwind of this frame - load the first unwind bytes then loop.
|
|
566 |
* Loop exit is by executing opcode CODE_FINISH.
|
|
567 |
*/
|
|
568 |
|
|
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;
|
|
579 |
}
|
|
580 |
|
|
581 |
#ifdef PR_DIAGNOSTICS
|
|
582 |
/* debug_print_vrs(context); */
|
|
583 |
#endif
|
|
584 |
|
|
585 |
while (1) {
|
|
586 |
uint8_t ub = next_unwind_byte(&ud);
|
|
587 |
|
|
588 |
#ifdef PR_DIAGNOSTICS
|
|
589 |
printf("PR Unwind byte 0x%x\n", ub);
|
|
590 |
#endif
|
|
591 |
|
|
592 |
/* decode and execute the current byte ... */
|
|
593 |
|
|
594 |
if (ub == CODE_FINISH) { /* finished unwinding */
|
|
595 |
if (!wrote_pc) {
|
|
596 |
uint32_t lr;
|
|
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;
|
|
600 |
}
|
|
601 |
#ifdef PR_DIAGNOSTICS
|
|
602 |
{
|
|
603 |
uint32_t nextpc;
|
|
604 |
_Unwind_VRS_Get(context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &nextpc);
|
|
605 |
printf("PR Next PC is 0x%x\n", nextpc);
|
|
606 |
}
|
|
607 |
#endif
|
|
608 |
break;
|
|
609 |
}
|
|
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);
|
|
613 |
continue;
|
|
614 |
}
|
|
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);
|
|
618 |
continue;
|
|
619 |
}
|
|
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);
|
|
623 |
mask |= ub << 4;
|
|
624 |
if (mask == 0) { /* 10000000 00000000 refuse to unwind */
|
|
625 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND);
|
|
626 |
return _URC_FAILURE;
|
|
627 |
}
|
|
628 |
if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
|
|
629 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
|
|
630 |
return _URC_FAILURE;
|
|
631 |
}
|
|
632 |
if (mask & (1 << R_PC)) wrote_pc = true;
|
|
633 |
continue;
|
|
634 |
}
|
|
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);
|
|
639 |
return _URC_FAILURE;
|
|
640 |
}
|
|
641 |
core_set(context, R_SP, core_get(context, regno));
|
|
642 |
continue;
|
|
643 |
}
|
|
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);
|
|
649 |
return _URC_FAILURE;
|
|
650 |
}
|
|
651 |
continue;
|
|
652 |
}
|
|
653 |
if (ub <= 0xb7) {
|
|
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);
|
|
659 |
return _URC_FAILURE;
|
|
660 |
}
|
|
661 |
if (_Unwind_VRS_Pop(context, _UVRSC_CORE, mask, _UVRSD_UINT32) != _UVRSR_OK) {
|
|
662 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
|
|
663 |
return _URC_FAILURE;
|
|
664 |
}
|
|
665 |
continue;
|
|
666 |
}
|
|
667 |
if (ub == 0xb2) { /* 10110010 uleb128 : vsp += (uleb128 << 2) + 0x204 */
|
|
668 |
uint32_t u = 0;
|
|
669 |
uint32_t n = 0;
|
|
670 |
/* decode */
|
|
671 |
while (1) {
|
|
672 |
ub = next_unwind_byte(&ud);
|
|
673 |
u |= (ub & 0x7f) << n;
|
|
674 |
if ((ub & 0x80) == 0) break;
|
|
675 |
n += 7;
|
|
676 |
}
|
|
677 |
core_set(context, R_SP, core_get(context, R_SP) + (u << 2) + 0x204);
|
|
678 |
continue;
|
|
679 |
}
|
|
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);
|
|
685 |
return _URC_FAILURE;
|
|
686 |
}
|
|
687 |
continue;
|
|
688 |
}
|
|
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);
|
|
693 |
return _URC_FAILURE;
|
|
694 |
}
|
|
695 |
continue;
|
|
696 |
}
|
|
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);
|
|
702 |
return _URC_FAILURE;
|
|
703 |
}
|
|
704 |
continue;
|
|
705 |
}
|
|
706 |
if (ub <= 0xc7) {
|
|
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);
|
|
711 |
return _URC_FAILURE;
|
|
712 |
}
|
|
713 |
if (_Unwind_VRS_Pop(context, _UVRSC_WMMXC, mask, _UVRSD_UINT32) != _UVRSR_OK) {
|
|
714 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_VRSFAILED);
|
|
715 |
return _URC_FAILURE;
|
|
716 |
}
|
|
717 |
continue;
|
|
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);
|
|
723 |
return _URC_FAILURE;
|
|
724 |
}
|
|
725 |
continue;
|
|
726 |
} else {
|
|
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);
|
|
731 |
return _URC_FAILURE;
|
|
732 |
}
|
|
733 |
continue;
|
|
734 |
}
|
|
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);
|
|
741 |
return _URC_FAILURE;
|
|
742 |
}
|
|
743 |
continue;
|
|
744 |
}
|
|
745 |
/* and in fact everything else is currently reserved or spare */
|
|
746 |
DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_CPP, _UAACT_ENDING, _UAARG_ENDING_CPP_BADOPCODE);
|
|
747 |
return _URC_FAILURE;
|
|
748 |
}
|
|
749 |
|
|
750 |
#ifdef PR_DIAGNOSTICS
|
|
751 |
/* debug_print_vrs(context); */
|
|
752 |
#endif
|
|
753 |
|
|
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.
|
|
758 |
*/
|
|
759 |
|
|
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.
|
|
764 |
*/
|
|
765 |
#ifdef PR_DIAGNOSTICS
|
|
766 |
printf("PR Got fnspec barrier in phase 2 (unwinding completed)\n");
|
|
767 |
#endif
|
|
768 |
core_set(context, 0, (uint32_t)ucbp);
|
|
769 |
if (!wrote_pc_from_lr) {
|
|
770 |
uint32_t pc;
|
|
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);
|
|
774 |
}
|
|
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;
|
|
778 |
}
|
|
779 |
|
|
780 |
/* Else continue with next frame */
|
|
781 |
return _URC_CONTINUE_UNWIND;
|
|
782 |
}
|
|
783 |
|
|
784 |
#endif
|
|
785 |
/* end ifdef prcommon_c */
|