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