|
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 */ |