|
1 /* unwinder.c |
|
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 /* Language-independent unwinder implementation */ |
|
18 |
|
19 /* This source file is compiled automatically by ARM's make system into |
|
20 * multiple object files. The source regions constituting object file |
|
21 * xxx.o are delimited by ifdef xxx_c / endif directives. |
|
22 * |
|
23 * The source regions currently marked are: |
|
24 * unwinder_c |
|
25 * unwind_activity_c |
|
26 */ |
|
27 |
|
28 #ifndef __EPOC32__ |
|
29 #include <stddef.h> |
|
30 #include <stdlib.h> |
|
31 #else |
|
32 #include <e32def.h> |
|
33 #endif |
|
34 /* Environment: */ |
|
35 #include "unwind_env.h" |
|
36 /* Language-independent unwinder declarations: */ |
|
37 #include "unwinder.h" |
|
38 |
|
39 #ifdef __EPOC32__ |
|
40 /* Symbian specific support */ |
|
41 #include "symbian_support.h" |
|
42 #endif |
|
43 |
|
44 /* Define UNWIND_ACTIVITY_DIAGNOSTICS for printed information from _Unwind_Activity */ |
|
45 /* Define VRS_DIAGNOSTICS for printed diagnostics about VRS operations */ |
|
46 |
|
47 #if defined(VRS_DIAGNOSTICS) || defined(UNWIND_ACTIVITY_DIAGNOSTICS) |
|
48 #ifndef __EPOC32__ |
|
49 extern int printf(const char *, ...); |
|
50 #endif |
|
51 #endif |
|
52 |
|
53 #ifdef SUPPORT_NESTED_EXCEPTIONS |
|
54 extern _Unwind_Control_Block *AllocSavedUCB(); |
|
55 extern void FreeSavedUCB(_Unwind_Control_Block *context); |
|
56 #endif |
|
57 |
|
58 #ifdef unwinder_c |
|
59 |
|
60 /* ========================= ========================= */ |
|
61 /* ========================= Virtual register set ========================= */ |
|
62 /* ========================= ========================= */ |
|
63 |
|
64 /* The approach taken by this implementation is to use the real machine |
|
65 * registers to hold all but the values of core (integer) |
|
66 * registers. Consequently the implementation must use only the core |
|
67 * registers except when manipulating the virtual register set. Non-core |
|
68 * registers are saved only on first use, so the single implementation can |
|
69 * cope with execution on processors which lack certain registers. The |
|
70 * registers as they were at the start of the propagation must be preserved |
|
71 * over phase 1 so that the machine state is correct at the start of phase |
|
72 * 2. This requires a copy to be taken (which can be stack allocated). During |
|
73 * a stack unwind (phase 1 or phase 2), the "current" virtual register set is |
|
74 * implemented as core register values held in a data structure, and non-core |
|
75 * register values held in the registers themselves. To ensure that all |
|
76 * original register values are available at the beginning of phase 2, the |
|
77 * core registers are saved in a second structure at the start of phase 1 and |
|
78 * the non-core registers are demand-saved into another part of the data |
|
79 * structure that holds the current core registers during the phase 1 stack |
|
80 * unwind. |
|
81 */ |
|
82 /* Extent to which the access routines are implemented: |
|
83 * _Unwind_VRS_Get and _Unwind_VRS_Set implement only access to the core registers. |
|
84 * _Unwind_VRS_Pop implements only popping of core and vfp registers. |
|
85 * There is no support here for the Intel WMMX registers, but space is nevertheless |
|
86 * reserved in the virtual register set structure to indicate whether demand-saving |
|
87 * of those registers is required (as they are unsupported, it never is). The space |
|
88 * costs nothing as it is required for alignment. |
|
89 * The level of supported functionality is compliant with the requirements of the |
|
90 * Exceptions ABI. |
|
91 */ |
|
92 |
|
93 typedef unsigned char bool; |
|
94 struct core_s { uint32_t r[16]; }; /* core integer regs */ |
|
95 struct vfp_s { uint64_t d[32]; }; /* VFP registers saved in FSTMD format */ |
|
96 |
|
97 /* Phase 1 virtual register set includes demand-save areas */ |
|
98 /* The phase 2 virtual register set must be a prefix of the phase 1 set */ |
|
99 typedef struct phase1_virtual_register_set_s { |
|
100 /* demand_save flag == 1 means save the registers in the demand-save area */ |
|
101 bool demand_save_vfp_low; |
|
102 bool demand_save_vfp_high; |
|
103 bool demand_save_wmmxd; |
|
104 bool demand_save_wmmxc; |
|
105 struct core_s core; /* current core registers */ |
|
106 struct vfp_s vfp; /* demand-saved vfp registers */ |
|
107 } phase1_virtual_register_set; |
|
108 |
|
109 /* Phase 2 virtual register set has no demand-save areas */ |
|
110 /* The phase 2 virtual register set must be a prefix of the phase 1 set */ |
|
111 /* The assembly fragments for _Unwind_RaiseException and _Unwind_Resume create |
|
112 * a phase2_virtual_register_set_s by hand so be careful. |
|
113 */ |
|
114 typedef struct phase2_virtual_register_set_s { |
|
115 /* demand_save flag == 1 means save the registers in the demand-save area */ |
|
116 /* Always 0 in phase 2 */ |
|
117 bool demand_save_vfp_low; |
|
118 bool demand_save_vfp_high; |
|
119 bool demand_save_wmmxd; |
|
120 bool demand_save_wmmxc; |
|
121 struct core_s core; /* current core registers */ |
|
122 } phase2_virtual_register_set; |
|
123 |
|
124 /* -- Helper macros for the embedded assembly */ |
|
125 |
|
126 #if defined(__TARGET_ARCH_5T) || defined(__TARGET_ARCH_5TXM) || \ |
|
127 defined(__TARGET_ARCH_5TE) || defined(__TARGET_ARCH_6) || \ |
|
128 defined(__TARGET_ARCH_6T2) || defined(__TARGET_ARCH_7_A) /* || ... */ |
|
129 #define ARCH_5T_OR_LATER 1 |
|
130 #else |
|
131 #define ARCH_5T_OR_LATER 0 |
|
132 #endif |
|
133 |
|
134 #if defined(__APCS_INTERWORK) && !ARCH_5T_OR_LATER |
|
135 #define OLD_STYLE_INTERWORKING 1 |
|
136 #else |
|
137 #define OLD_STYLE_INTERWORKING 0 |
|
138 #endif |
|
139 |
|
140 #if defined(__TARGET_ARCH_4T) || defined(__TARGET_ARCH_4TXM) || ARCH_5T_OR_LATER |
|
141 #define HAVE_BX 1 |
|
142 #else |
|
143 #define HAVE_BX 0 |
|
144 #endif |
|
145 |
|
146 #if defined(__TARGET_ARCH_THUMBNAIL) |
|
147 #define THUMBNAIL 1 |
|
148 #else |
|
149 #define THUMBNAIL 0 |
|
150 #endif |
|
151 |
|
152 #if HAVE_BX |
|
153 #define RET_LR bx lr |
|
154 #else |
|
155 #define RET_LR mov pc,lr |
|
156 #endif |
|
157 |
|
158 /* ----- Routines: ----- */ |
|
159 |
|
160 /* ----- Helper routines, private ----- */ |
|
161 |
|
162 /* R_ARM_PREL31 is a place-relative 31-bit signed relocation. The |
|
163 * routine takes the address of a location that was relocated by |
|
164 * R_ARM_PREL31, and returns an absolute address. |
|
165 */ |
|
166 static FORCEINLINE uint32_t __ARM_resolve_prel31(void *p) |
|
167 { |
|
168 return (uint32_t)((((*(int32_t *)p) << 1) >> 1) + (int32_t)p); |
|
169 } |
|
170 |
|
171 /* ----- Helper routines, private but external ----- */ |
|
172 |
|
173 /* Note '%0' refers to local label '0' */ |
|
174 #if defined(__thumb) |
|
175 #define MAYBE_SWITCH_TO_ARM_STATE SWITCH_TO_ARM_STATE |
|
176 #define MAYBE_CODE16 code16 |
|
177 #else |
|
178 #define MAYBE_SWITCH_TO_ARM_STATE /* nothing */ |
|
179 #define MAYBE_CODE16 /* nothing */ |
|
180 #endif |
|
181 __asm void __ARM_Unwind_VRS_VFPpreserve_low(void *vfpp) |
|
182 { |
|
183 vfp_d0 CN 0; |
|
184 /* Preserve the low vfp registers in the passed memory */ |
|
185 #if defined(__thumb) |
|
186 macro; |
|
187 SWITCH_TO_ARM_STATE; |
|
188 1 |
|
189 align 4; |
|
190 2 |
|
191 assert (%2 - %1) = 0; |
|
192 bx pc; |
|
193 nop; |
|
194 code32; |
|
195 mend; |
|
196 #endif |
|
197 |
|
198 MAYBE_SWITCH_TO_ARM_STATE; |
|
199 stc p11,vfp_d0,[r0],{0x20}; /* 0xec800b20 FSTMIAD r0,{d0-d15} */ |
|
200 RET_LR; |
|
201 MAYBE_CODE16; |
|
202 } |
|
203 |
|
204 __asm void __ARM_Unwind_VRS_VFPpreserve_high(void *vfpp) |
|
205 { |
|
206 vfp_d16 CN 0; /* =16 when used with stcl */ |
|
207 /* Preserve the high vfp registers in the passed memory */ |
|
208 MAYBE_SWITCH_TO_ARM_STATE; |
|
209 stcl p11,vfp_d16,[r0],{0x20}; /* 0xecc00b20 FSTMIAD r0,{d16-d31} */ |
|
210 RET_LR; |
|
211 MAYBE_CODE16; |
|
212 } |
|
213 |
|
214 __asm void __ARM_Unwind_VRS_VFPrestore_low(void *vfpp) |
|
215 { |
|
216 /* Restore the low vfp registers from the passed memory */ |
|
217 vfp_d0 CN 0; |
|
218 MAYBE_SWITCH_TO_ARM_STATE; |
|
219 ldc p11,vfp_d0,[r0],{0x20}; /* 0xec900b20 FLDMIAD r0,{d0-d15} */ |
|
220 RET_LR; |
|
221 MAYBE_CODE16; |
|
222 } |
|
223 |
|
224 __asm void __ARM_Unwind_VRS_VFPrestore_high(void *vfpp) |
|
225 { |
|
226 /* Restore the high vfp registers from the passed memory */ |
|
227 vfp_d16 CN 0; /* =16 when used with ldcl */ |
|
228 MAYBE_SWITCH_TO_ARM_STATE; |
|
229 ldcl p11,vfp_d16,[r0],{0x20}; /* 0xecd00b20 FLDMIAD r0,{d16-d31} */ |
|
230 RET_LR; |
|
231 MAYBE_CODE16; |
|
232 } |
|
233 |
|
234 |
|
235 __asm NORETURNDECL void __ARM_Unwind_VRS_corerestore(void *corep) |
|
236 { |
|
237 /* We rely here on corep pointing to a location in the stack, |
|
238 * as we briefly assign it to sp. This allows us to safely do |
|
239 * ldmia's which restore sp (if we use a different base register, |
|
240 * the updated sp may be used by the handler of any data abort |
|
241 * that occurs during the ldmia, and the stack gets overwritten). |
|
242 * By hypothesis this is preserve8 but the load of sp means the |
|
243 * assembler can't infer that. |
|
244 */ |
|
245 #if THUMBNAIL |
|
246 preserve8; |
|
247 mov.w r13, r0; |
|
248 ldmia.w r13!,{r0-r12}; |
|
249 ldr.w r14, [r13, #4] /* lr */ |
|
250 ldr.w r12, [r13, #4*2] /* pc */ |
|
251 ldr.w r13, [r13, #0] /* sp */ |
|
252 bx r12 |
|
253 |
|
254 #else |
|
255 preserve8; |
|
256 MAYBE_SWITCH_TO_ARM_STATE; |
|
257 #if OLD_STYLE_INTERWORKING |
|
258 mov r13, r0; |
|
259 ldmia r13!,{r0-r12}; |
|
260 ldr r12,[r13, #4*2]; /* pc */ |
|
261 ldmia r13,{r13-r14}; |
|
262 bx r12; |
|
263 #else |
|
264 |
|
265 #if __ARMCC_VERSION < 300000 |
|
266 mov r13, r0; |
|
267 ldmia r13,{r0-r15}; |
|
268 #else |
|
269 mov r14, r0; |
|
270 ldmia r14!, {r0-r12}; |
|
271 ldr r13, [r14], #4; |
|
272 ldmia r14, {r14,r15}; |
|
273 #endif |
|
274 |
|
275 #endif |
|
276 MAYBE_CODE16; |
|
277 #endif |
|
278 } |
|
279 |
|
280 |
|
281 /* ----- Development support ----- */ |
|
282 |
|
283 #ifdef VRS_DIAGNOSTICS |
|
284 static void debug_print_vrs_vfp(uint32_t base, uint64_t *lp) |
|
285 { |
|
286 int c = 0; |
|
287 int i; |
|
288 for (i = 0; i < 16; i++) { |
|
289 printf("D%-2d 0x%16.16llx ", i + base, *lp); |
|
290 lp++; |
|
291 if (c++ == 1) { |
|
292 c = 0; |
|
293 printf("\n"); |
|
294 } |
|
295 } |
|
296 } |
|
297 |
|
298 |
|
299 static void debug_print_vrs(_Unwind_Context *context) |
|
300 { |
|
301 phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context; |
|
302 int i; |
|
303 int c; |
|
304 printf("------------------------------------------------------------------------\n"); |
|
305 c = 0; |
|
306 for (i = 0; i < 16; i++) { |
|
307 printf("r%-2d 0x%8.8x ", i, vrsp->core.r[i]); |
|
308 if (c++ == 3) { |
|
309 c = 0; |
|
310 printf("\n"); |
|
311 } |
|
312 } |
|
313 |
|
314 printf("-----\n"); |
|
315 if (vrsp->demand_save_vfp_low == 1) |
|
316 printf("VFP low registers not saved\n"); |
|
317 else |
|
318 debug_print_vrs_vfp(0, &vrsp->vfp.d[0]); |
|
319 printf("-----\n"); |
|
320 if (vrsp->demand_save_vfp_high == 1) |
|
321 printf("VFP high registers not saved\n"); |
|
322 else |
|
323 debug_print_vrs_vfp(16, &vrsp->vfp.d[16]); |
|
324 printf("------------------------------------------------------------------------\n"); |
|
325 } |
|
326 #endif |
|
327 |
|
328 |
|
329 /* ----- Public routines ----- */ |
|
330 |
|
331 EXPORT_C _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context, |
|
332 _Unwind_VRS_RegClass regclass, |
|
333 uint32_t regno, |
|
334 _Unwind_VRS_DataRepresentation representation, |
|
335 void *valuep) |
|
336 { |
|
337 phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context; |
|
338 switch (regclass) { |
|
339 case _UVRSC_CORE: |
|
340 { |
|
341 if (representation != _UVRSD_UINT32 || regno > 15) |
|
342 return _UVRSR_FAILED; |
|
343 vrsp->core.r[regno] = *(uint32_t *)valuep; |
|
344 return _UVRSR_OK; |
|
345 } |
|
346 case _UVRSC_VFP: |
|
347 case _UVRSC_WMMXD: |
|
348 case _UVRSC_WMMXC: |
|
349 return _UVRSR_NOT_IMPLEMENTED; |
|
350 default: |
|
351 break; |
|
352 } |
|
353 return _UVRSR_FAILED; |
|
354 } |
|
355 |
|
356 |
|
357 EXPORT_C _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context, |
|
358 _Unwind_VRS_RegClass regclass, |
|
359 uint32_t regno, |
|
360 _Unwind_VRS_DataRepresentation representation, |
|
361 void *valuep) |
|
362 { |
|
363 phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context; |
|
364 switch (regclass) { |
|
365 case _UVRSC_CORE: |
|
366 { |
|
367 if (representation != _UVRSD_UINT32 || regno > 15) |
|
368 return _UVRSR_FAILED; |
|
369 *(uint32_t *)valuep = vrsp->core.r[regno]; |
|
370 return _UVRSR_OK; |
|
371 } |
|
372 case _UVRSC_VFP: |
|
373 case _UVRSC_WMMXD: |
|
374 case _UVRSC_WMMXC: |
|
375 return _UVRSR_NOT_IMPLEMENTED; |
|
376 default: |
|
377 break; |
|
378 } |
|
379 return _UVRSR_FAILED; |
|
380 } |
|
381 |
|
382 |
|
383 #define R_SP 13 |
|
384 |
|
385 EXPORT_C _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *context, |
|
386 _Unwind_VRS_RegClass regclass, |
|
387 uint32_t descriminator, |
|
388 _Unwind_VRS_DataRepresentation representation) |
|
389 { |
|
390 phase1_virtual_register_set *vrsp = (phase1_virtual_register_set *)context; |
|
391 switch (regclass) { |
|
392 case _UVRSC_CORE: |
|
393 { |
|
394 /* If SP is included in the mask, the loaded value is used in preference to |
|
395 * the writeback value, but only on completion of the loading. |
|
396 */ |
|
397 uint32_t mask, *vsp, *rp, sp_loaded; |
|
398 if (representation != _UVRSD_UINT32) |
|
399 return _UVRSR_FAILED; |
|
400 vsp = (uint32_t *)vrsp->core.r[R_SP]; |
|
401 rp = (uint32_t *)&vrsp->core; |
|
402 mask = descriminator & 0xffff; |
|
403 sp_loaded = mask & (1 << R_SP); |
|
404 while (mask != 0) { |
|
405 if (mask & 1) { |
|
406 #ifdef VRS_DIAGNOSTICS |
|
407 printf("VRS Pop r%d\n", rp - &vrsp->core.r[0]); |
|
408 #endif |
|
409 *rp = *vsp++; |
|
410 } |
|
411 rp++; |
|
412 mask >>= 1; |
|
413 } |
|
414 if (!sp_loaded) |
|
415 vrsp->core.r[R_SP] = (uint32_t)vsp; |
|
416 return _UVRSR_OK; |
|
417 } |
|
418 case _UVRSC_VFP: |
|
419 { |
|
420 uint32_t start = descriminator >> 16; |
|
421 uint32_t count = descriminator & 0xffff; |
|
422 bool some_low = start < 16; |
|
423 bool some_high = start + count > 16; |
|
424 if ((representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) || |
|
425 (representation == _UVRSD_VFPX && some_high) || |
|
426 (representation == _UVRSD_DOUBLE && start + count > 32)) |
|
427 return _UVRSR_FAILED; |
|
428 if (some_low && vrsp->demand_save_vfp_low == 1) { /* Demand-save over phase 1 */ |
|
429 vrsp->demand_save_vfp_low = 0; |
|
430 __ARM_Unwind_VRS_VFPpreserve_low(&vrsp->vfp.d[0]); |
|
431 } |
|
432 if (some_high && vrsp->demand_save_vfp_high == 1) { /* Demand-save over phase 1 */ |
|
433 vrsp->demand_save_vfp_high = 0; |
|
434 __ARM_Unwind_VRS_VFPpreserve_high(&vrsp->vfp.d[16]); |
|
435 } |
|
436 /* Now recover from the stack into the real machine registers. |
|
437 * Note for _UVRSD_VFPX we assume FSTMX standard format 1. |
|
438 * Do this by saving the current VFP registers to a memory area, |
|
439 * moving the in-memory values into that area, and |
|
440 * restoring from the whole area. |
|
441 * Must be careful as the 64-bit values saved by FSTMX might be |
|
442 * only 32-bit aligned. |
|
443 */ |
|
444 { |
|
445 struct unaligned_vfp_reg_s { uint32_t w1; uint32_t w2; }; |
|
446 struct unaligned_vfp_reg_s *vsp; |
|
447 struct vfp_s temp_vfp; |
|
448 if (some_low) |
|
449 __ARM_Unwind_VRS_VFPpreserve_low(&temp_vfp.d[0]); |
|
450 if (some_high) |
|
451 __ARM_Unwind_VRS_VFPpreserve_high(&temp_vfp.d[16]); |
|
452 vsp = (struct unaligned_vfp_reg_s *)vrsp->core.r[R_SP]; |
|
453 while (count--) { |
|
454 struct unaligned_vfp_reg_s *v = |
|
455 (struct unaligned_vfp_reg_s *)&temp_vfp.d[start++]; |
|
456 *v = *vsp++; |
|
457 #ifdef VRS_DIAGNOSTICS |
|
458 printf("VRS Pop D%d = 0x%llx\n", start - 1, temp_vfp.d[start - 1]); |
|
459 #endif |
|
460 } |
|
461 vrsp->core.r[R_SP] = (uint32_t)((uint32_t *)vsp + |
|
462 (representation == _UVRSD_VFPX ? |
|
463 1 : /* +1 to skip the format word */ |
|
464 0)); |
|
465 if (some_low) |
|
466 __ARM_Unwind_VRS_VFPrestore_low(&temp_vfp.d[0]); |
|
467 if (some_high) |
|
468 __ARM_Unwind_VRS_VFPrestore_high(&temp_vfp.d[16]); |
|
469 } |
|
470 return _UVRSR_OK; |
|
471 } |
|
472 case _UVRSC_WMMXD: |
|
473 case _UVRSC_WMMXC: |
|
474 return _UVRSR_NOT_IMPLEMENTED; |
|
475 default: |
|
476 break; |
|
477 } |
|
478 return _UVRSR_FAILED; |
|
479 } |
|
480 |
|
481 |
|
482 |
|
483 /* ========================= ========================= */ |
|
484 /* ========================= The unwinder ========================= */ |
|
485 /* ========================= ========================= */ |
|
486 |
|
487 |
|
488 /* This implementation uses the UCB unwinder_cache as follows: |
|
489 * reserved1 is documented in the EABI as requiring initialisation to 0. |
|
490 * It is used to manage nested simultaneous propagation. If the value is 0, |
|
491 * the UCB is participating in no propagations. If the value is 1, the UCB |
|
492 * is participating in one propagation. Otherwise the value is a pointer to |
|
493 * a structure holding saved UCB state from the next propagation out. |
|
494 * The structure used is simply a mallocated UCB. |
|
495 * reserved2 is used to preserve the call-site address over calls to a |
|
496 * personality routine and cleanup. |
|
497 * reserved3 is used to cache the PR address. |
|
498 * reserved4 is used by the Symbian implementation to cache the ROM exeception |
|
499 * search table |
|
500 * reserved5 is used by the symbian implementation to cache the |
|
501 * TExceptionDescriptor for the executable of the 'current' frame |
|
502 */ |
|
503 |
|
504 #define NESTED_CONTEXT unwinder_cache.reserved1 |
|
505 #define SAVED_CALLSITE_ADDR unwinder_cache.reserved2 |
|
506 #define PR_ADDR unwinder_cache.reserved3 |
|
507 |
|
508 /* Index table entry: */ |
|
509 |
|
510 #ifndef __EPOC32__ // Symbian OS defines this in symbian_support.h |
|
511 typedef struct __EIT_entry { |
|
512 uint32_t fnoffset; /* Place-relative */ |
|
513 uint32_t content; |
|
514 } __EIT_entry; |
|
515 #endif |
|
516 |
|
517 /* Private defines etc: */ |
|
518 |
|
519 static const uint32_t EXIDX_CANTUNWIND = 1; |
|
520 static const uint32_t uint32_highbit = 0x80000000; |
|
521 |
|
522 /* ARM C++ personality routines: */ |
|
523 |
|
524 typedef _Unwind_Reason_Code (*personality_routine)(_Unwind_State, |
|
525 _Unwind_Control_Block *, |
|
526 _Unwind_Context *); |
|
527 |
|
528 WEAKDECL _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *, |
|
529 _Unwind_Context *context); |
|
530 IMPORT_C WEAKDECL _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *, |
|
531 _Unwind_Context *context); |
|
532 IMPORT_C WEAKDECL _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *, |
|
533 _Unwind_Context *context); |
|
534 |
|
535 |
|
536 /* Various image symbols: */ |
|
537 |
|
538 struct ExceptionTableInfo { |
|
539 uint32_t EIT_base; |
|
540 uint32_t EIT_limit; |
|
541 }; |
|
542 |
|
543 #ifndef __EPOC32__ |
|
544 /* We define __ARM_ETInfo to allow access to some linker-generated |
|
545 names that are not legal C identifiers. __ARM_ETInfo is extern only |
|
546 because of scope limitations of the embedded assembler */ |
|
547 extern const struct ExceptionTableInfo __ARM_ETInfo; |
|
548 #define EIT_base \ |
|
549 ((const __EIT_entry *)(__ARM_ETInfo.EIT_base + (const char *)&__ARM_ETInfo)) |
|
550 #define EIT_limit \ |
|
551 ((const __EIT_entry *)(__ARM_ETInfo.EIT_limit + (const char *)&__ARM_ETInfo)) |
|
552 |
|
553 #endif |
|
554 |
|
555 |
|
556 /* ----- Index table processing ----- */ |
|
557 |
|
558 /* find_and_expand_eit_entry is a support function used in both phases to set |
|
559 * ucb.pr_cache and internal cache. |
|
560 * Call with a pointer to the ucb and the return address to look up. |
|
561 * |
|
562 * The table is contained in the half-open interval |
|
563 * [EIT_base, EIT_limit) and is an ordered array of __EIT_entrys. |
|
564 * Perform a binary search via C library routine bsearch. |
|
565 * The table contains only function start addresses (encoded as offsets), so |
|
566 * we need to special-case the end table entry in the comparison function, |
|
567 * which we do by assuming the function it describes extends to end of memory. |
|
568 * This causes us problems indirectly in that we would like to fault as |
|
569 * many attempts as possible to look up an invalid return address. There are |
|
570 * several ways an invalid return address can be obtained from a broken |
|
571 * program, such as someone corrupting the stack or broken unwind instructions |
|
572 * recovered the wrong value. It is plausible that many bad return addresses |
|
573 * will be either small integers or will point into the heap or stack, hence |
|
574 * it's desirable to get the length of that final function roughly right. |
|
575 * Here we make no attempt to do it. Code exclusively for use in toolchains |
|
576 * which define a suitable limit symbol could make use of that symbol. |
|
577 * Alternatively (QoI) a smart linker could augment the index table with a |
|
578 * dummy EXIDX_CANTUNWIND entry pointing just past the last real function. |
|
579 */ |
|
580 |
|
581 #ifndef __EPOC32__ |
|
582 static int EIT_comparator(const void *ck, const void *ce) |
|
583 { |
|
584 uint32_t return_address = *(const uint32_t *)ck; |
|
585 const __EIT_entry *eitp = (const __EIT_entry *)ce; |
|
586 const __EIT_entry *next_eitp = eitp + 1; |
|
587 uint32_t next_fn; |
|
588 if (next_eitp != EIT_limit) |
|
589 next_fn = __ARM_resolve_prel31((void *)&next_eitp->fnoffset); |
|
590 else |
|
591 next_fn = 0xffffffffU; |
|
592 if (return_address < __ARM_resolve_prel31((void *)&eitp->fnoffset)) return -1; |
|
593 if (return_address >= next_fn) return 1; |
|
594 return 0; |
|
595 } |
|
596 #endif |
|
597 |
|
598 |
|
599 static _Unwind_Reason_Code find_and_expand_eit_entry_V2(_Unwind_Control_Block *ucbp, |
|
600 uint32_t return_address) |
|
601 { |
|
602 /* Search the index table for an entry containing the specified return |
|
603 * address. Subtract the 2 from the return address, as the index table |
|
604 * contains function start addresses (a trailing noreturn BL would |
|
605 * appear to return to the first address of the next function (perhaps |
|
606 * +1 if Thumb); a leading BL would appear to return to function start |
|
607 * + instruction size (perhaps +1 if Thumb)). |
|
608 */ |
|
609 |
|
610 #ifndef __EPOC32__ |
|
611 const __EIT_entry *base = EIT_base; |
|
612 size_t nelems = EIT_limit - EIT_base; |
|
613 __EIT_entry *eitp; |
|
614 |
|
615 return_address -= 2; |
|
616 |
|
617 eitp = (__EIT_entry *) bsearch(&return_address, base, nelems, |
|
618 sizeof(__EIT_entry), EIT_comparator); |
|
619 #else |
|
620 const __EIT_entry *base = EIT_base(ucbp); |
|
621 size_t nelems = EIT_limit(ucbp) - base; |
|
622 __EIT_entry *eitp; |
|
623 |
|
624 return_address -= 2; |
|
625 |
|
626 // This must succeed on SymbianOS or else an error will have occured already. |
|
627 eitp = SearchEITV2(return_address, base, nelems); |
|
628 #endif |
|
629 |
|
630 if (eitp == NULL) { |
|
631 /* The return address we have was not found in the EIT. |
|
632 * This breaks the scan and we have to indicate failure. |
|
633 */ |
|
634 ucbp->PR_ADDR = NULL; |
|
635 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_UNWINDER_LOOKUPFAILED); |
|
636 return _URC_FAILURE; |
|
637 } |
|
638 |
|
639 /* Cache the function offset */ |
|
640 |
|
641 ucbp->pr_cache.fnstart = __ARM_resolve_prel31((void *)&eitp->fnoffset); |
|
642 |
|
643 /* Can this frame be unwound at all? */ |
|
644 |
|
645 if (eitp->content == EXIDX_CANTUNWIND) { |
|
646 ucbp->PR_ADDR = NULL; |
|
647 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND); |
|
648 return _URC_FAILURE; |
|
649 } |
|
650 |
|
651 /* Obtain the address of the "real" __EHT_Header word */ |
|
652 |
|
653 if (eitp->content & uint32_highbit) { |
|
654 /* It is immediate data */ |
|
655 ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content; |
|
656 ucbp->pr_cache.additional = 1; |
|
657 } else { |
|
658 /* The content field is a 31-bit place-relative offset to an _Unwind_EHT_Entry structure */ |
|
659 ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)__ARM_resolve_prel31((void *)&eitp->content); |
|
660 ucbp->pr_cache.additional = 0; |
|
661 } |
|
662 |
|
663 /* Discover the personality routine address */ |
|
664 |
|
665 if (*(uint32_t *)(ucbp->pr_cache.ehtp) & uint32_highbit) { |
|
666 /* It is immediate data - compute matching pr */ |
|
667 uint32_t idx = ((*(uint32_t *)(ucbp->pr_cache.ehtp)) >> 24) & 0xf; |
|
668 if (idx == 0) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr0; |
|
669 else if (idx == 1) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr1; |
|
670 else if (idx == 2) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr2; |
|
671 else { /* Failed */ |
|
672 ucbp->PR_ADDR = NULL; |
|
673 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT); |
|
674 return _URC_FAILURE; |
|
675 } |
|
676 } else { |
|
677 /* It's a place-relative offset to pr */ |
|
678 ucbp->PR_ADDR = __ARM_resolve_prel31((void *)(ucbp->pr_cache.ehtp)); |
|
679 } |
|
680 return _URC_OK; |
|
681 } |
|
682 |
|
683 static _Unwind_Reason_Code find_and_expand_eit_entry_V1(_Unwind_Control_Block *ucbp, |
|
684 uint32_t return_address) |
|
685 { |
|
686 /* Search the index table for an entry containing the specified return |
|
687 * address. The EIT contains function offsets relative to the base of the |
|
688 * execute region so adjust the return address accordingly. |
|
689 */ |
|
690 |
|
691 #ifndef __EPOC32__ |
|
692 uint32_t return_address_offset = ADDR_TO_ER_RO_OFFSET(return_address, ucbp); |
|
693 const __EIT_entry *base = EIT_base; |
|
694 size_t nelems = EIT_limit - EIT_base; |
|
695 |
|
696 const __EIT_entry *eitp = |
|
697 (const __EIT_entry *) bsearch(&return_address_offset, base, nelems, |
|
698 sizeof(__EIT_entry), EIT_comparator); |
|
699 if (eitp == NULL) { |
|
700 /* The return address we have was not found in the EIT. |
|
701 * This breaks the scan and we have to indicate failure. |
|
702 */ |
|
703 ucbp->PR_ADDR = NULL; |
|
704 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_UNWINDER_LOOKUPFAILED); |
|
705 return _URC_FAILURE; |
|
706 } |
|
707 #else |
|
708 /* Shouldn't we subtract 2 from here just like in the V2 lookup? |
|
709 */ |
|
710 uint32_t return_address_offset = ADDR_TO_ER_RO_OFFSET(return_address, ucbp); |
|
711 const __EIT_entry *base = EIT_base(ucbp); |
|
712 size_t nelems = EIT_limit(ucbp) - base; |
|
713 |
|
714 // This must succeed or else an error will have occured already. |
|
715 const __EIT_entry *eitp = SearchEITV1(return_address_offset, base, nelems); |
|
716 |
|
717 #endif |
|
718 |
|
719 |
|
720 /* Cache the function offset */ |
|
721 |
|
722 ucbp->pr_cache.fnstart = ER_RO_OFFSET_TO_ADDR(eitp->fnoffset, ucbp); |
|
723 |
|
724 /* Can this frame be unwound at all? */ |
|
725 |
|
726 if (eitp->content == EXIDX_CANTUNWIND) { |
|
727 ucbp->PR_ADDR = NULL; |
|
728 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_NOUNWIND); |
|
729 return _URC_FAILURE; |
|
730 } |
|
731 |
|
732 /* Obtain the address of the "real" __EHT_Header word */ |
|
733 if (eitp->content & uint32_highbit) { |
|
734 /* It is immediate data */ |
|
735 ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content; |
|
736 ucbp->pr_cache.additional = 1; |
|
737 } else { |
|
738 /* The content field is a segment relative offset to an _Unwind_EHT_Entry structure */ |
|
739 ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)ER_RO_OFFSET_TO_ADDR(eitp->content, ucbp); |
|
740 ucbp->pr_cache.additional = 0; |
|
741 } |
|
742 |
|
743 /* Discover the personality routine address */ |
|
744 |
|
745 if (*(uint32_t *)(ucbp->pr_cache.ehtp) & uint32_highbit) { |
|
746 /* It is immediate data - compute matching pr */ |
|
747 uint32_t idx = ((*(uint32_t *)(ucbp->pr_cache.ehtp)) >> 24) & 0xf; |
|
748 |
|
749 if (idx == 0) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr0; |
|
750 else if (idx == 1) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr1; |
|
751 else if (idx == 2) ucbp->PR_ADDR = (uint32_t)&__aeabi_unwind_cpp_pr2; |
|
752 else { /* Failed */ |
|
753 ucbp->PR_ADDR = NULL; |
|
754 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_TABLECORRUPT); |
|
755 return _URC_FAILURE; |
|
756 } |
|
757 } else { |
|
758 /* Execute region offset to PR */ |
|
759 ucbp->PR_ADDR = ER_RO_OFFSET_TO_ADDR(*(uint32_t *)(ucbp->pr_cache.ehtp), ucbp); |
|
760 |
|
761 } |
|
762 return _URC_OK; |
|
763 } |
|
764 |
|
765 static _Unwind_Reason_Code find_and_expand_eit_entry(_Unwind_Control_Block *ucbp, |
|
766 uint32_t return_address) |
|
767 { |
|
768 ValidateExceptionDescriptor(return_address, ucbp); |
|
769 if (EHABI_V2(ucbp)) |
|
770 return find_and_expand_eit_entry_V2(ucbp, return_address); |
|
771 else |
|
772 return find_and_expand_eit_entry_V1(ucbp, return_address); |
|
773 } |
|
774 |
|
775 |
|
776 /* ----- Unwinding: ----- */ |
|
777 |
|
778 /* Fwd decl */ |
|
779 static NORETURNDECL void unwind_next_frame(_Unwind_Control_Block *ucbp, phase2_virtual_register_set *vrsp); |
|
780 |
|
781 /* Helper fn: If the demand_save flag in a phase1_virtual_register_set was |
|
782 * zeroed, the registers were demand-saved. This function restores from |
|
783 * the save area. |
|
784 */ |
|
785 static FORCEINLINE void restore_non_core_regs(phase1_virtual_register_set *vrsp) |
|
786 { |
|
787 if (vrsp->demand_save_vfp_low == 0) |
|
788 __ARM_Unwind_VRS_VFPrestore_low(&vrsp->vfp.d[0]); |
|
789 if (vrsp->demand_save_vfp_high == 0) |
|
790 __ARM_Unwind_VRS_VFPrestore_high(&vrsp->vfp.d[16]); |
|
791 } |
|
792 |
|
793 /* _Unwind_RaiseException is the external entry point to begin unwinding */ |
|
794 __asm _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp) |
|
795 { |
|
796 extern __ARM_Unwind_RaiseException; |
|
797 |
|
798 #if THUMBNAIL |
|
799 |
|
800 /* Create a phase2_virtual_register_set on the stack */ |
|
801 /* Save the core registers, carefully writing the original sp value */ |
|
802 /* Note we account for the pc but do not actually write it's value here */ |
|
803 str.w r14,[sp, #-8]!; |
|
804 add.w r14, r13, #8; |
|
805 str.w r14,[sp, #-4]! /* pushed 3 words => 3 words */ |
|
806 stmfd.w sp!,{r0-r12}; /* pushed 13 words => 16 words */ |
|
807 /* Write zeroes for the demand_save bytes so no saving occurs in phase 2 */ |
|
808 mov.w r1,#0; |
|
809 str.w r1,[sp,#-4]!; /* pushed 1 word => 17 words */ |
|
810 mov.w r1,sp; |
|
811 sub.w sp,sp,#4; /* preserve 8 byte alignment => 18 words */ |
|
812 |
|
813 /* Now pass to C (with r0 still valid) to do the real work. |
|
814 * r0 = ucbp, r1 = phase2_virtual_register_set. |
|
815 * If we get control back, pop the stack and return preserving r0. |
|
816 */ |
|
817 |
|
818 /* on arch 5T and later the linker will fix 'bl' => 'blx' as |
|
819 needed */ |
|
820 bl.w __ARM_Unwind_RaiseException; |
|
821 ldr.w r14,[sp,#16*4]; |
|
822 add.w sp,sp,#18*4; |
|
823 bx lr; |
|
824 |
|
825 #else |
|
826 |
|
827 MAYBE_SWITCH_TO_ARM_STATE; |
|
828 |
|
829 /* Create a phase2_virtual_register_set on the stack */ |
|
830 /* Save the core registers, carefully writing the original sp value */ |
|
831 #if __ARMCC_VERSION < 300000 |
|
832 stmfd sp!,{r13-r15}; /* pushed 3 words => 3 words */ |
|
833 #else |
|
834 stmdb r13, {r14,r15}; |
|
835 str r13, [r13,#-3*4]; |
|
836 sub r13, r13, #3*4; |
|
837 #endif |
|
838 stmfd sp!,{r0-r12}; /* pushed 13 words => 16 words */ |
|
839 /* Write zeroes for the demand_save bytes so no saving occurs in phase 2 */ |
|
840 mov r1,#0; |
|
841 str r1,[sp,#-4]!; /* pushed 1 word => 17 words */ |
|
842 mov r1,sp; |
|
843 sub sp,sp,#4; /* preserve 8 byte alignment => 18 words */ |
|
844 |
|
845 /* Now pass to C (with r0 still valid) to do the real work. |
|
846 * r0 = ucbp, r1 = phase2_virtual_register_set. |
|
847 * If we get control back, pop the stack and return preserving r0. |
|
848 */ |
|
849 |
|
850 #if OLD_STYLE_INTERWORKING |
|
851 ldr r2,Unwind_RaiseException_Offset; |
|
852 add r2,r2,pc; |
|
853 mov lr,pc; |
|
854 Offset_Base |
|
855 bx r2; |
|
856 #else |
|
857 /* on arch 5T and later the linker will fix 'bl' => 'blx' as |
|
858 needed */ |
|
859 bl __ARM_Unwind_RaiseException; |
|
860 #endif |
|
861 ldr r14,[sp,#16*4]; |
|
862 add sp,sp,#18*4; |
|
863 RET_LR; |
|
864 #if OLD_STYLE_INTERWORKING |
|
865 Unwind_RaiseException_Offset dcd __ARM_Unwind_RaiseException - Offset_Base; |
|
866 #endif |
|
867 MAYBE_CODE16; |
|
868 |
|
869 #endif |
|
870 |
|
871 #ifndef __EPOC32__ |
|
872 /* Alternate symbol names for difficult symbols. |
|
873 * It is possible no functions included in the image require |
|
874 * a handler table. Therefore make only a weak reference to |
|
875 * the handler table base symbol, which may be absent. |
|
876 */ |
|
877 align 4 |
|
878 extern |.ARM.exidx$$Base|; |
|
879 extern |.ARM.exidx$$Limit|; |
|
880 extern |.ARM.extab$$Base| WEAKASMDECL; |
|
881 export __ARM_ETInfo; |
|
882 /* these are offsets for /ropi */ |
|
883 __ARM_ETInfo /* layout must match struct ExceptionTableInfo */ |
|
884 eit_base dcd |.ARM.exidx$$Base| - __ARM_ETInfo; /* index table base */ |
|
885 eit_limit dcd |.ARM.exidx$$Limit| - __ARM_ETInfo; /* index table limit */ |
|
886 #endif |
|
887 } |
|
888 |
|
889 |
|
890 /* __ARM_Unwind_RaiseException performs phase 1 unwinding */ |
|
891 |
|
892 _Unwind_Reason_Code __ARM_Unwind_RaiseException(_Unwind_Control_Block *ucbp, |
|
893 phase2_virtual_register_set *entry_VRSp) |
|
894 { |
|
895 phase1_virtual_register_set phase1_VRS; |
|
896 |
|
897 /* Is this a nested simultaneous propagation? |
|
898 * (see comments with _Unwind_Complete) |
|
899 */ |
|
900 if (ucbp->NESTED_CONTEXT == 0) { |
|
901 /* No - this is only propagation */ |
|
902 ucbp->NESTED_CONTEXT = 1; |
|
903 } else { |
|
904 #ifdef SUPPORT_NESTED_EXCEPTIONS |
|
905 /* Yes - cache the state elsewhere and restore it when the propagation ends */ |
|
906 /* This representation wastes space and uses malloc; do better? |
|
907 * On the other hand will it ever be used in practice? |
|
908 */ |
|
909 _Unwind_Control_Block *saved_ucbp = AllocSavedUCB(); |
|
910 if (ucbp == NULL) { |
|
911 DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_UNWINDER_BUFFERFAILED); |
|
912 return _URC_FAILURE; |
|
913 } |
|
914 saved_ucbp->unwinder_cache = ucbp->unwinder_cache; |
|
915 saved_ucbp->barrier_cache = ucbp->barrier_cache; |
|
916 saved_ucbp->cleanup_cache = ucbp->cleanup_cache; |
|
917 ucbp->NESTED_CONTEXT = (uint32_t)saved_ucbp; |
|
918 #else |
|
919 abort(); |
|
920 #endif |
|
921 } |
|
922 |
|
923 /* entry_VRSp contains the core registers as they were when |
|
924 * _Unwind_RaiseException was called. Copy the call-site address to r15 |
|
925 * then copy all the registers to phase1_VRS for the phase 1 stack scan. |
|
926 */ |
|
927 |
|
928 entry_VRSp->core.r[15] = entry_VRSp->core.r[14]; |
|
929 phase1_VRS.core = entry_VRSp->core; |
|
930 |
|
931 /* For phase 1 only ensure non-core registers are saved before use. |
|
932 * If WMMX registers are supported, initialise their flags here and |
|
933 * take appropriate action elsewhere. |
|
934 */ |
|
935 |
|
936 phase1_VRS.demand_save_vfp_low = 1; |
|
937 phase1_VRS.demand_save_vfp_high = 1; |
|
938 #ifdef __EPOC32__ |
|
939 /* Set up Symbian specific caches in the _Unwind_Control_Block's |
|
940 unwinder_cache. |
|
941 */ |
|
942 InitialiseSymbianSpecificUnwinderCache(phase1_VRS.core.r[15], ucbp); |
|
943 #endif |
|
944 |
|
945 |
|
946 /* Now perform a virtual unwind until a propagation barrier is met, or |
|
947 * until something goes wrong. If something does go wrong, we ought (I |
|
948 * suppose) to restore registers we may have destroyed. |
|
949 */ |
|
950 |
|
951 while (1) { |
|
952 |
|
953 _Unwind_Reason_Code pr_result; |
|
954 |
|
955 /* Search the index table for the required entry. Cache the index table |
|
956 * pointer, and obtain and cache the addresses of the "real" __EHT_Header |
|
957 * word and the personality routine. |
|
958 */ |
|
959 |
|
960 if (find_and_expand_eit_entry(ucbp, phase1_VRS.core.r[15]) != _URC_OK) { |
|
961 restore_non_core_regs(&phase1_VRS); |
|
962 /* Debugger bottleneck fn called during lookup */ |
|
963 return _URC_FAILURE; |
|
964 } |
|
965 |
|
966 /* Call the pr to decide what to do */ |
|
967 |
|
968 pr_result = ((personality_routine)ucbp->PR_ADDR)(_US_VIRTUAL_UNWIND_FRAME, |
|
969 ucbp, |
|
970 (_Unwind_Context *)&phase1_VRS); |
|
971 |
|
972 if (pr_result == _URC_HANDLER_FOUND) break; |
|
973 if (pr_result == _URC_CONTINUE_UNWIND) continue; |
|
974 |
|
975 /* If we get here some sort of failure has occurred in the |
|
976 * pr and probably the pr returned _URC_FAILURE |
|
977 */ |
|
978 restore_non_core_regs(&phase1_VRS); |
|
979 return _URC_FAILURE; |
|
980 } |
|
981 |
|
982 /* Propagation barrier located... restore entry register state of non-core regs */ |
|
983 |
|
984 restore_non_core_regs(&phase1_VRS); |
|
985 |
|
986 /* Initiate real unwinding */ |
|
987 unwind_next_frame(ucbp, entry_VRSp); |
|
988 /* Unreached, but keep compiler quiet: */ |
|
989 return _URC_FAILURE; |
|
990 } |
|
991 |
|
992 |
|
993 /* unwind_next_frame performs phase 2 unwinding */ |
|
994 |
|
995 static NORETURNDECL void unwind_next_frame(_Unwind_Control_Block *ucbp, phase2_virtual_register_set *vrsp) |
|
996 { |
|
997 while (1) { |
|
998 |
|
999 _Unwind_Reason_Code pr_result; |
|
1000 |
|
1001 /* Search the index table for the required entry. Cache the index table |
|
1002 * pointer, and obtain and cache the addresses of the "real" __EHT_Header |
|
1003 * word and the personality routine. |
|
1004 */ |
|
1005 |
|
1006 if (find_and_expand_eit_entry(ucbp, vrsp->core.r[15]) != _URC_OK) |
|
1007 abort(); |
|
1008 |
|
1009 /* Save the call-site address and call the pr to do whatever it |
|
1010 * wants to do on this new frame. |
|
1011 */ |
|
1012 |
|
1013 ucbp->SAVED_CALLSITE_ADDR = vrsp->core.r[15]; |
|
1014 pr_result = ((personality_routine)ucbp->PR_ADDR)(_US_UNWIND_FRAME_STARTING, ucbp, |
|
1015 (_Unwind_Context *)vrsp); |
|
1016 |
|
1017 if (pr_result == _URC_INSTALL_CONTEXT) { |
|
1018 /* Upload the registers */ |
|
1019 __ARM_Unwind_VRS_corerestore(&vrsp->core); |
|
1020 } else if (pr_result == _URC_CONTINUE_UNWIND) |
|
1021 continue; |
|
1022 else |
|
1023 abort(); |
|
1024 } |
|
1025 } |
|
1026 |
|
1027 |
|
1028 /* _Unwind_Resume is the external entry point called after a cleanup |
|
1029 * to resume unwinding. It tail-calls a helper function, |
|
1030 * __ARM_Unwind_Resume, which never returns. |
|
1031 */ |
|
1032 __asm NORETURNDECL void _Unwind_Resume(_Unwind_Control_Block *ucbp) |
|
1033 { |
|
1034 extern __ARM_Unwind_Resume; |
|
1035 |
|
1036 #if THUMBNAIL |
|
1037 |
|
1038 /* Create a phase2_virtual_register_set on the stack */ |
|
1039 /* Save the core registers, carefully writing the original sp value */ |
|
1040 /* Note we account for the pc but do not actually write it's value here */ |
|
1041 str.w r14,[sp, #-8]!; |
|
1042 add.w r14, r13, #8; |
|
1043 str.w r14,[sp, #-4]! /* pushed 3 words => 3 words */ |
|
1044 stmfd.w sp!,{r0-r12}; /* pushed 13 words => 16 words */ |
|
1045 /* Write zeroes for the demand_save bytes so no saving occurs in phase 2 */ |
|
1046 mov.w r1,#0; |
|
1047 str.w r1,[sp,#-4]!; /* pushed 1 word => 17 words */ |
|
1048 mov.w r1,sp; |
|
1049 sub.w sp,sp,#4; /* preserve 8 byte alignment => 18 words */ |
|
1050 |
|
1051 /* Now pass to C (with r0 still valid) to do the real work. |
|
1052 * r0 = ucbp, r1 = phase2_virtual_register_set. |
|
1053 * This call never returns. |
|
1054 */ |
|
1055 |
|
1056 mov pc,r2 |
|
1057 |
|
1058 #else |
|
1059 |
|
1060 MAYBE_SWITCH_TO_ARM_STATE; |
|
1061 |
|
1062 /* Create a phase2_virtual_register_set on the stack */ |
|
1063 /* Save the core registers, carefully writing the original sp value */ |
|
1064 |
|
1065 #if __ARMCC_VERSION < 300000 |
|
1066 stmfd sp!,{r13-r15}; /* pushed 3 words => 3 words */ |
|
1067 #else |
|
1068 stmdb r13, {r14,r15}; |
|
1069 str r13, [r13,#-3*4]; |
|
1070 sub r13, r13, #3*4; |
|
1071 #endif |
|
1072 |
|
1073 stmfd sp!,{r0-r12}; /* pushed 13 words => 16 words */ |
|
1074 /* Write zeroes for the demand_save bytes so no saving occurs in phase 2 */ |
|
1075 mov r1,#0; |
|
1076 str r1,[sp,#-4]!; /* pushed 1 word => 17 words */ |
|
1077 mov r1,sp; |
|
1078 sub sp,sp,#4; /* preserve 8 byte alignment => 18 words */ |
|
1079 |
|
1080 /* Now pass to C (with r0 still valid) to do the real work. |
|
1081 * r0 = ucbp, r1 = phase2_virtual_register_set. |
|
1082 * This call never returns. |
|
1083 */ |
|
1084 |
|
1085 #ifdef __APCS_INTERWORK |
|
1086 ldr r2,Unwind_Resume_Offset; |
|
1087 add r2,r2,pc; |
|
1088 bx r2; |
|
1089 Unwind_Resume_Offset dcd __ARM_Unwind_Resume - .; |
|
1090 #else |
|
1091 b __ARM_Unwind_Resume; |
|
1092 #endif |
|
1093 MAYBE_CODE16; |
|
1094 |
|
1095 #endif |
|
1096 } |
|
1097 |
|
1098 |
|
1099 /* Helper function for _Unwind_Resume */ |
|
1100 |
|
1101 NORETURNDECL void __ARM_Unwind_Resume(_Unwind_Control_Block *ucbp, |
|
1102 phase2_virtual_register_set *entry_VRSp) |
|
1103 { |
|
1104 _Unwind_Reason_Code pr_result; |
|
1105 |
|
1106 /* Recover saved state */ |
|
1107 |
|
1108 entry_VRSp->core.r[15] = ucbp->SAVED_CALLSITE_ADDR; |
|
1109 |
|
1110 /* Call the cached PR and dispatch */ |
|
1111 |
|
1112 pr_result = ((personality_routine)ucbp->PR_ADDR)(_US_UNWIND_FRAME_RESUME, ucbp, |
|
1113 (_Unwind_Context *)entry_VRSp); |
|
1114 |
|
1115 if (pr_result == _URC_INSTALL_CONTEXT) { |
|
1116 /* Upload the registers */ |
|
1117 __ARM_Unwind_VRS_corerestore(&entry_VRSp->core); |
|
1118 } else if (pr_result == _URC_CONTINUE_UNWIND) |
|
1119 unwind_next_frame(ucbp, entry_VRSp); |
|
1120 else |
|
1121 abort(); |
|
1122 } |
|
1123 |
|
1124 |
|
1125 /* _Unwind_Complete is called at the end of a propagation. |
|
1126 * If we support multiple simultaneous propagations, restore the cached state |
|
1127 * of the previous propagation here. |
|
1128 */ |
|
1129 |
|
1130 void _Unwind_Complete(_Unwind_Control_Block *ucbp) |
|
1131 { |
|
1132 _Unwind_Control_Block *context = (_Unwind_Control_Block *)ucbp->NESTED_CONTEXT; |
|
1133 if ((uint32_t)context == 0) abort(); /* should be impossible */ |
|
1134 if ((uint32_t)context == 1) { |
|
1135 /* This was the only ongoing propagation of this object */ |
|
1136 ucbp->NESTED_CONTEXT--; |
|
1137 return; |
|
1138 } |
|
1139 #ifdef SUPPORT_NESTED_EXCEPTIONS |
|
1140 /* Otherwise we copy the state back from the cache structure pointed to |
|
1141 * by ucbp->NESTED_CONTEXT. |
|
1142 */ |
|
1143 /* This first one updates ucbp->NESTED_CONTEXT */ |
|
1144 ucbp->unwinder_cache = context->unwinder_cache; |
|
1145 ucbp->barrier_cache = context->barrier_cache; |
|
1146 ucbp->cleanup_cache = context->cleanup_cache; |
|
1147 FreeSavedUCB(context); |
|
1148 #else |
|
1149 abort(); |
|
1150 #endif |
|
1151 } |
|
1152 |
|
1153 /* _Unwind_DeleteException can be used to invoke the exception_cleanup |
|
1154 * function after catching a foreign exception. |
|
1155 */ |
|
1156 |
|
1157 void _Unwind_DeleteException(_Unwind_Control_Block *ucbp) |
|
1158 { |
|
1159 if (ucbp->exception_cleanup != NULL) |
|
1160 (ucbp->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, ucbp); |
|
1161 } |
|
1162 |
|
1163 #endif /* unwinder_c */ |
|
1164 #ifdef unwind_activity_c |
|
1165 |
|
1166 /* Runtime debug "bottleneck function": */ |
|
1167 /* (not in the current Exceptions EABI document) */ |
|
1168 |
|
1169 void _Unwind_Activity(_Unwind_Control_Block *ucbp, uint32_t reason, uint32_t arg) |
|
1170 { |
|
1171 #ifdef UNWIND_ACTIVITY_DIAGNOSTICS |
|
1172 uint32_t who = reason >> 24; |
|
1173 uint32_t activity = reason & 0xffffff; |
|
1174 printf("_Unwind_Activity: UCB=0x%8.8x Reason=(", (uint32_t)ucbp); |
|
1175 switch (who) { |
|
1176 case _UASUBSYS_UNWINDER: |
|
1177 printf("unw,"); |
|
1178 if (activity >= 0x80) |
|
1179 printf("%x) Arg=0x%8.8x\n", activity, arg); |
|
1180 break; |
|
1181 case _UASUBSYS_CPP: |
|
1182 printf("C++,"); |
|
1183 if (activity >= 0x80) { |
|
1184 if (activity == _UAACT_CPP_TYPEINFO) |
|
1185 printf("typeinfo) Typeinfo=0x%8.8x\n", arg); |
|
1186 else |
|
1187 printf("%x) Arg=0x%8.8x\n", activity, arg); |
|
1188 } |
|
1189 break; |
|
1190 default: |
|
1191 printf("???,"); |
|
1192 if (activity >= 0x80) |
|
1193 printf("%x) Arg=0x%8.8x\n", activity, arg); |
|
1194 break; |
|
1195 } |
|
1196 if (activity < 0x80) { |
|
1197 switch (activity) { |
|
1198 case _UAACT_STARTING: |
|
1199 printf("starting) Typeinfo=0x%8.8x\n", arg); |
|
1200 break; |
|
1201 case _UAACT_ENDING: |
|
1202 printf("ending) Cause=%d\n", arg); |
|
1203 break; |
|
1204 case _UAACT_BARRIERFOUND: |
|
1205 printf("barrierfound) Pad=0x%8.8x\n", arg); |
|
1206 break; |
|
1207 case _UAACT_PADENTRY: |
|
1208 printf("padentry) Pad=0x%8.8x\n", arg); |
|
1209 break; |
|
1210 default: |
|
1211 printf("%x) Arg=0x%8.8x\n", activity, arg); |
|
1212 break; |
|
1213 } |
|
1214 } |
|
1215 #endif |
|
1216 } |
|
1217 |
|
1218 #endif /* unwind_activity_c */ |