1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | // |
8 | // Implements C++ ABI Exception Handling Level 1 as documented at: |
9 | // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html |
10 | // using libunwind |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | // ARM EHABI does not specify _Unwind_{Get,Set}{GR,IP}(). Thus, we are |
15 | // defining inline functions to delegate the function calls to |
16 | // _Unwind_VRS_{Get,Set}(). However, some applications might declare the |
17 | // function protetype directly (instead of including <unwind.h>), thus we need |
18 | // to export these functions from libunwind.so as well. |
19 | #define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 1 |
20 | |
21 | #include <inttypes.h> |
22 | #include <stdint.h> |
23 | #include <stdbool.h> |
24 | #include <stdlib.h> |
25 | #include <stdio.h> |
26 | #include <string.h> |
27 | |
28 | #include "config.h" |
29 | #include "libunwind.h" |
30 | #include "libunwind_ext.h" |
31 | #include "shadow_stack_unwind.h" |
32 | #include "unwind.h" |
33 | |
34 | #if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ |
35 | !defined(__wasm__) |
36 | |
37 | #ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND |
38 | |
39 | // When shadow stack is enabled, a separate stack containing only return |
40 | // addresses would be maintained. On function return, the return address would |
41 | // be compared to the popped address from shadow stack to ensure the return |
42 | // target is not tempered with. When unwinding, we're skipping the normal return |
43 | // procedure for multiple frames and thus need to pop the return addresses of |
44 | // the skipped frames from shadow stack to avoid triggering an exception (using |
45 | // `_LIBUNWIND_POP_SHSTK_SSP()`). Also, some architectures, like the x86-family |
46 | // CET, push the return adddresses onto shadow stack with common call |
47 | // instructions, so for these architectures, normal function calls should be |
48 | // avoided when invoking the `jumpto()` function. To do this, we use inline |
49 | // assemblies to "goto" the `jumpto()` for these architectures. |
50 | #if !defined(_LIBUNWIND_USE_CET) && !defined(_LIBUNWIND_USE_GCS) |
51 | #define __unw_phase2_resume(cursor, fn) \ |
52 | do { \ |
53 | (void)fn; \ |
54 | __unw_resume((cursor)); \ |
55 | } while (0) |
56 | #elif defined(_LIBUNWIND_TARGET_I386) |
57 | #define __shstk_step_size (4) |
58 | #define __unw_phase2_resume(cursor, fn) \ |
59 | do { \ |
60 | _LIBUNWIND_POP_SHSTK_SSP((fn)); \ |
61 | void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \ |
62 | void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \ |
63 | __asm__ volatile("push %%edi\n\t" \ |
64 | "sub $4, %%esp\n\t" \ |
65 | "jmp *%%edx\n\t" ::"D"(shstkRegContext), \ |
66 | "d"(shstkJumpAddress)); \ |
67 | } while (0) |
68 | #elif defined(_LIBUNWIND_TARGET_X86_64) |
69 | #define __shstk_step_size (8) |
70 | #define __unw_phase2_resume(cursor, fn) \ |
71 | do { \ |
72 | _LIBUNWIND_POP_SHSTK_SSP((fn)); \ |
73 | void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \ |
74 | void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \ |
75 | __asm__ volatile("jmpq *%%rdx\n\t" ::"D"(shstkRegContext), \ |
76 | "d"(shstkJumpAddress)); \ |
77 | } while (0) |
78 | #elif defined(_LIBUNWIND_TARGET_AARCH64) |
79 | #define __shstk_step_size (8) |
80 | #define __unw_phase2_resume(cursor, fn) \ |
81 | do { \ |
82 | _LIBUNWIND_POP_SHSTK_SSP((fn)); \ |
83 | void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \ |
84 | void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \ |
85 | __asm__ volatile("mov x0, %0\n\t" \ |
86 | "br %1\n\t" \ |
87 | : \ |
88 | : "r"(shstkRegContext), "r"(shstkJumpAddress) \ |
89 | : "x0"); \ |
90 | } while (0) |
91 | #endif |
92 | |
93 | static _Unwind_Reason_Code |
94 | unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { |
95 | __unw_init_local(cursor, uc); |
96 | |
97 | // Walk each frame looking for a place to stop. |
98 | while (true) { |
99 | // Ask libunwind to get next frame (skip over first which is |
100 | // _Unwind_RaiseException). |
101 | int stepResult = __unw_step(cursor); |
102 | if (stepResult == 0) { |
103 | _LIBUNWIND_TRACE_UNWINDING( |
104 | "unwind_phase1(ex_obj=%p): __unw_step() reached " |
105 | "bottom => _URC_END_OF_STACK" , |
106 | (void *)exception_object); |
107 | return _URC_END_OF_STACK; |
108 | } else if (stepResult < 0) { |
109 | _LIBUNWIND_TRACE_UNWINDING( |
110 | "unwind_phase1(ex_obj=%p): __unw_step failed => " |
111 | "_URC_FATAL_PHASE1_ERROR" , |
112 | (void *)exception_object); |
113 | return _URC_FATAL_PHASE1_ERROR; |
114 | } |
115 | |
116 | // See if frame has code to run (has personality routine). |
117 | unw_proc_info_t frameInfo; |
118 | unw_word_t sp; |
119 | if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { |
120 | _LIBUNWIND_TRACE_UNWINDING( |
121 | "unwind_phase1(ex_obj=%p): __unw_get_proc_info " |
122 | "failed => _URC_FATAL_PHASE1_ERROR" , |
123 | (void *)exception_object); |
124 | return _URC_FATAL_PHASE1_ERROR; |
125 | } |
126 | |
127 | #ifndef NDEBUG |
128 | // When tracing, print state information. |
129 | if (_LIBUNWIND_TRACING_UNWINDING) { |
130 | char functionBuf[512]; |
131 | const char *functionName = functionBuf; |
132 | unw_word_t offset; |
133 | if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), |
134 | &offset) != UNW_ESUCCESS) || |
135 | (frameInfo.start_ip + offset > frameInfo.end_ip)) |
136 | functionName = ".anonymous." ; |
137 | unw_word_t pc; |
138 | __unw_get_reg(cursor, UNW_REG_IP, &pc); |
139 | _LIBUNWIND_TRACE_UNWINDING( |
140 | "unwind_phase1(ex_obj=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR |
141 | ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "" , |
142 | (void *)exception_object, pc, frameInfo.start_ip, functionName, |
143 | frameInfo.lsda, frameInfo.handler); |
144 | } |
145 | #endif |
146 | |
147 | // If there is a personality routine, ask it if it will want to stop at |
148 | // this frame. |
149 | if (frameInfo.handler != 0) { |
150 | _Unwind_Personality_Fn p = |
151 | (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler); |
152 | _LIBUNWIND_TRACE_UNWINDING( |
153 | "unwind_phase1(ex_obj=%p): calling personality function %p" , |
154 | (void *)exception_object, (void *)(uintptr_t)p); |
155 | _Unwind_Reason_Code personalityResult = |
156 | (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class, |
157 | exception_object, (struct _Unwind_Context *)(cursor)); |
158 | switch (personalityResult) { |
159 | case _URC_HANDLER_FOUND: |
160 | // found a catch clause or locals that need destructing in this frame |
161 | // stop search and remember stack pointer at the frame |
162 | __unw_get_reg(cursor, UNW_REG_SP, &sp); |
163 | exception_object->private_2 = (uintptr_t)sp; |
164 | _LIBUNWIND_TRACE_UNWINDING( |
165 | "unwind_phase1(ex_obj=%p): _URC_HANDLER_FOUND" , |
166 | (void *)exception_object); |
167 | return _URC_NO_REASON; |
168 | |
169 | case _URC_CONTINUE_UNWIND: |
170 | _LIBUNWIND_TRACE_UNWINDING( |
171 | "unwind_phase1(ex_obj=%p): _URC_CONTINUE_UNWIND" , |
172 | (void *)exception_object); |
173 | // continue unwinding |
174 | break; |
175 | |
176 | default: |
177 | // something went wrong |
178 | _LIBUNWIND_TRACE_UNWINDING( |
179 | "unwind_phase1(ex_obj=%p): _URC_FATAL_PHASE1_ERROR" , |
180 | (void *)exception_object); |
181 | return _URC_FATAL_PHASE1_ERROR; |
182 | } |
183 | } |
184 | } |
185 | return _URC_NO_REASON; |
186 | } |
187 | extern int __unw_step_stage2(unw_cursor_t *); |
188 | |
189 | #if defined(_LIBUNWIND_USE_GCS) |
190 | // Enable the GCS target feature to permit gcspop instructions to be used. |
191 | __attribute__((target("gcs" ))) |
192 | #endif |
193 | static _Unwind_Reason_Code |
194 | unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { |
195 | __unw_init_local(cursor, uc); |
196 | |
197 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p)" , |
198 | (void *)exception_object); |
199 | |
200 | // uc is initialized by __unw_getcontext in the parent frame. The first stack |
201 | // frame walked is unwind_phase2. |
202 | unsigned framesWalked = 1; |
203 | #if defined(_LIBUNWIND_USE_CET) |
204 | unsigned long shadowStackTop = _get_ssp(); |
205 | #elif defined(_LIBUNWIND_USE_GCS) |
206 | unsigned long shadowStackTop = 0; |
207 | if (__chkfeat(_CHKFEAT_GCS)) |
208 | shadowStackTop = (unsigned long)__gcspr(); |
209 | #endif |
210 | // Walk each frame until we reach where search phase said to stop. |
211 | while (true) { |
212 | |
213 | // Ask libunwind to get next frame (skip over first which is |
214 | // _Unwind_RaiseException). |
215 | int stepResult = __unw_step_stage2(cursor); |
216 | if (stepResult == 0) { |
217 | _LIBUNWIND_TRACE_UNWINDING( |
218 | "unwind_phase2(ex_obj=%p): __unw_step_stage2() reached " |
219 | "bottom => _URC_END_OF_STACK" , |
220 | (void *)exception_object); |
221 | return _URC_END_OF_STACK; |
222 | } else if (stepResult < 0) { |
223 | _LIBUNWIND_TRACE_UNWINDING( |
224 | "unwind_phase2(ex_obj=%p): __unw_step_stage2 failed => " |
225 | "_URC_FATAL_PHASE1_ERROR" , |
226 | (void *)exception_object); |
227 | return _URC_FATAL_PHASE2_ERROR; |
228 | } |
229 | |
230 | // Get info about this frame. |
231 | unw_word_t sp; |
232 | unw_proc_info_t frameInfo; |
233 | __unw_get_reg(cursor, UNW_REG_SP, &sp); |
234 | if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { |
235 | _LIBUNWIND_TRACE_UNWINDING( |
236 | "unwind_phase2(ex_obj=%p): __unw_get_proc_info " |
237 | "failed => _URC_FATAL_PHASE1_ERROR" , |
238 | (void *)exception_object); |
239 | return _URC_FATAL_PHASE2_ERROR; |
240 | } |
241 | |
242 | #ifndef NDEBUG |
243 | // When tracing, print state information. |
244 | if (_LIBUNWIND_TRACING_UNWINDING) { |
245 | char functionBuf[512]; |
246 | const char *functionName = functionBuf; |
247 | unw_word_t offset; |
248 | if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), |
249 | &offset) != UNW_ESUCCESS) || |
250 | (frameInfo.start_ip + offset > frameInfo.end_ip)) |
251 | functionName = ".anonymous." ; |
252 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p): start_ip=0x%" PRIxPTR |
253 | ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR |
254 | ", personality=0x%" PRIxPTR, |
255 | (void *)exception_object, frameInfo.start_ip, |
256 | functionName, sp, frameInfo.lsda, |
257 | frameInfo.handler); |
258 | } |
259 | #endif |
260 | |
261 | // In shadow stack enabled environment, we check return address stored in normal |
262 | // stack against return address stored in shadow stack, if the 2 addresses don't |
263 | // match, it means return address in normal stack has been corrupted, we return |
264 | // _URC_FATAL_PHASE2_ERROR. |
265 | #if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS) |
266 | if (shadowStackTop != 0) { |
267 | unw_word_t retInNormalStack; |
268 | __unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack); |
269 | unsigned long retInShadowStack = |
270 | *(unsigned long *)(shadowStackTop + __shstk_step_size * framesWalked); |
271 | if (retInNormalStack != retInShadowStack) |
272 | return _URC_FATAL_PHASE2_ERROR; |
273 | } |
274 | #endif |
275 | ++framesWalked; |
276 | // If there is a personality routine, tell it we are unwinding. |
277 | if (frameInfo.handler != 0) { |
278 | _Unwind_Personality_Fn p = |
279 | (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler); |
280 | _Unwind_Action action = _UA_CLEANUP_PHASE; |
281 | if (sp == exception_object->private_2) { |
282 | // Tell personality this was the frame it marked in phase 1. |
283 | action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); |
284 | } |
285 | _Unwind_Reason_Code personalityResult = |
286 | (*p)(1, action, exception_object->exception_class, exception_object, |
287 | (struct _Unwind_Context *)(cursor)); |
288 | switch (personalityResult) { |
289 | case _URC_CONTINUE_UNWIND: |
290 | // Continue unwinding |
291 | _LIBUNWIND_TRACE_UNWINDING( |
292 | "unwind_phase2(ex_obj=%p): _URC_CONTINUE_UNWIND" , |
293 | (void *)exception_object); |
294 | if (sp == exception_object->private_2) { |
295 | // Phase 1 said we would stop at this frame, but we did not... |
296 | _LIBUNWIND_ABORT("during phase1 personality function said it would " |
297 | "stop here, but now in phase2 it did not stop here" ); |
298 | } |
299 | break; |
300 | case _URC_INSTALL_CONTEXT: |
301 | _LIBUNWIND_TRACE_UNWINDING( |
302 | "unwind_phase2(ex_obj=%p): _URC_INSTALL_CONTEXT" , |
303 | (void *)exception_object); |
304 | // Personality routine says to transfer control to landing pad. |
305 | // We may get control back if landing pad calls _Unwind_Resume(). |
306 | if (_LIBUNWIND_TRACING_UNWINDING) { |
307 | unw_word_t pc; |
308 | __unw_get_reg(cursor, UNW_REG_IP, &pc); |
309 | __unw_get_reg(cursor, UNW_REG_SP, &sp); |
310 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p): re-entering " |
311 | "user code with ip=0x%" PRIxPTR |
312 | ", sp=0x%" PRIxPTR, |
313 | (void *)exception_object, pc, sp); |
314 | } |
315 | |
316 | __unw_phase2_resume(cursor, framesWalked); |
317 | // __unw_phase2_resume() only returns if there was an error. |
318 | return _URC_FATAL_PHASE2_ERROR; |
319 | default: |
320 | // Personality routine returned an unknown result code. |
321 | _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d" , |
322 | personalityResult); |
323 | return _URC_FATAL_PHASE2_ERROR; |
324 | } |
325 | } |
326 | } |
327 | |
328 | // Clean up phase did not resume at the frame that the search phase |
329 | // said it would... |
330 | return _URC_FATAL_PHASE2_ERROR; |
331 | } |
332 | |
333 | #if defined(_LIBUNWIND_USE_GCS) |
334 | // Enable the GCS target feature to permit gcspop instructions to be used. |
335 | __attribute__((target("gcs" ))) |
336 | #endif |
337 | static _Unwind_Reason_Code |
338 | unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, |
339 | _Unwind_Exception *exception_object, |
340 | _Unwind_Stop_Fn stop, void *stop_parameter) { |
341 | __unw_init_local(cursor, uc); |
342 | |
343 | // uc is initialized by __unw_getcontext in the parent frame. The first stack |
344 | // frame walked is unwind_phase2_forced. |
345 | unsigned framesWalked = 1; |
346 | // Walk each frame until we reach where search phase said to stop |
347 | while (__unw_step_stage2(cursor) > 0) { |
348 | |
349 | // Update info about this frame. |
350 | unw_proc_info_t frameInfo; |
351 | if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { |
352 | _LIBUNWIND_TRACE_UNWINDING( |
353 | "unwind_phase2_forced(ex_obj=%p): __unw_get_proc_info " |
354 | "failed => _URC_END_OF_STACK" , |
355 | (void *)exception_object); |
356 | return _URC_FATAL_PHASE2_ERROR; |
357 | } |
358 | |
359 | #ifndef NDEBUG |
360 | // When tracing, print state information. |
361 | if (_LIBUNWIND_TRACING_UNWINDING) { |
362 | char functionBuf[512]; |
363 | const char *functionName = functionBuf; |
364 | unw_word_t offset; |
365 | if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), |
366 | &offset) != UNW_ESUCCESS) || |
367 | (frameInfo.start_ip + offset > frameInfo.end_ip)) |
368 | functionName = ".anonymous." ; |
369 | _LIBUNWIND_TRACE_UNWINDING( |
370 | "unwind_phase2_forced(ex_obj=%p): start_ip=0x%" PRIxPTR |
371 | ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, |
372 | (void *)exception_object, frameInfo.start_ip, functionName, |
373 | frameInfo.lsda, frameInfo.handler); |
374 | } |
375 | #endif |
376 | |
377 | // Call stop function at each frame. |
378 | _Unwind_Action action = |
379 | (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); |
380 | _Unwind_Reason_Code stopResult = |
381 | (*stop)(1, action, exception_object->exception_class, exception_object, |
382 | (struct _Unwind_Context *)(cursor), stop_parameter); |
383 | _LIBUNWIND_TRACE_UNWINDING( |
384 | "unwind_phase2_forced(ex_obj=%p): stop function returned %d" , |
385 | (void *)exception_object, stopResult); |
386 | if (stopResult != _URC_NO_REASON) { |
387 | _LIBUNWIND_TRACE_UNWINDING( |
388 | "unwind_phase2_forced(ex_obj=%p): stopped by stop function" , |
389 | (void *)exception_object); |
390 | return _URC_FATAL_PHASE2_ERROR; |
391 | } |
392 | |
393 | ++framesWalked; |
394 | // If there is a personality routine, tell it we are unwinding. |
395 | if (frameInfo.handler != 0) { |
396 | _Unwind_Personality_Fn p = |
397 | (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler); |
398 | _LIBUNWIND_TRACE_UNWINDING( |
399 | "unwind_phase2_forced(ex_obj=%p): calling personality function %p" , |
400 | (void *)exception_object, (void *)(uintptr_t)p); |
401 | _Unwind_Reason_Code personalityResult = |
402 | (*p)(1, action, exception_object->exception_class, exception_object, |
403 | (struct _Unwind_Context *)(cursor)); |
404 | switch (personalityResult) { |
405 | case _URC_CONTINUE_UNWIND: |
406 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): " |
407 | "personality returned " |
408 | "_URC_CONTINUE_UNWIND" , |
409 | (void *)exception_object); |
410 | // Destructors called, continue unwinding |
411 | break; |
412 | case _URC_INSTALL_CONTEXT: |
413 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): " |
414 | "personality returned " |
415 | "_URC_INSTALL_CONTEXT" , |
416 | (void *)exception_object); |
417 | // We may get control back if landing pad calls _Unwind_Resume(). |
418 | __unw_phase2_resume(cursor, framesWalked); |
419 | break; |
420 | default: |
421 | // Personality routine returned an unknown result code. |
422 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): " |
423 | "personality returned %d, " |
424 | "_URC_FATAL_PHASE2_ERROR" , |
425 | (void *)exception_object, personalityResult); |
426 | return _URC_FATAL_PHASE2_ERROR; |
427 | } |
428 | } |
429 | } |
430 | |
431 | // Call stop function one last time and tell it we've reached the end |
432 | // of the stack. |
433 | _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): calling stop " |
434 | "function with _UA_END_OF_STACK" , |
435 | (void *)exception_object); |
436 | _Unwind_Action lastAction = |
437 | (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); |
438 | (*stop)(1, lastAction, exception_object->exception_class, exception_object, |
439 | (struct _Unwind_Context *)(cursor), stop_parameter); |
440 | |
441 | // Clean up phase did not resume at the frame that the search phase said it |
442 | // would. |
443 | return _URC_FATAL_PHASE2_ERROR; |
444 | } |
445 | |
446 | |
447 | /// Called by __cxa_throw. Only returns if there is a fatal error. |
448 | _LIBUNWIND_EXPORT _Unwind_Reason_Code |
449 | _Unwind_RaiseException(_Unwind_Exception *exception_object) { |
450 | _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)" , |
451 | (void *)exception_object); |
452 | unw_context_t uc; |
453 | unw_cursor_t cursor; |
454 | __unw_getcontext(&uc); |
455 | |
456 | // Mark that this is a non-forced unwind, so _Unwind_Resume() |
457 | // can do the right thing. |
458 | exception_object->private_1 = 0; |
459 | exception_object->private_2 = 0; |
460 | |
461 | // phase 1: the search phase |
462 | _Unwind_Reason_Code phase1 = unwind_phase1(uc: &uc, cursor: &cursor, exception_object); |
463 | if (phase1 != _URC_NO_REASON) |
464 | return phase1; |
465 | |
466 | // phase 2: the clean up phase |
467 | return unwind_phase2(uc: &uc, cursor: &cursor, exception_object); |
468 | } |
469 | |
470 | |
471 | |
472 | /// When _Unwind_RaiseException() is in phase2, it hands control |
473 | /// to the personality function at each frame. The personality |
474 | /// may force a jump to a landing pad in that function, the landing |
475 | /// pad code may then call _Unwind_Resume() to continue with the |
476 | /// unwinding. Note: the call to _Unwind_Resume() is from compiler |
477 | /// generated user code. All other _Unwind_* routines are called |
478 | /// by the C++ runtime __cxa_* routines. |
479 | /// |
480 | /// Note: re-throwing an exception (as opposed to continuing the unwind) |
481 | /// is implemented by having the code call __cxa_rethrow() which |
482 | /// in turn calls _Unwind_Resume_or_Rethrow(). |
483 | _LIBUNWIND_EXPORT void |
484 | _Unwind_Resume(_Unwind_Exception *exception_object) { |
485 | _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)" , (void *)exception_object); |
486 | unw_context_t uc; |
487 | unw_cursor_t cursor; |
488 | __unw_getcontext(&uc); |
489 | |
490 | if (exception_object->private_1 != 0) |
491 | unwind_phase2_forced(uc: &uc, cursor: &cursor, exception_object, |
492 | stop: (_Unwind_Stop_Fn) exception_object->private_1, |
493 | stop_parameter: (void *)exception_object->private_2); |
494 | else |
495 | unwind_phase2(uc: &uc, cursor: &cursor, exception_object); |
496 | |
497 | // Clients assume _Unwind_Resume() does not return, so all we can do is abort. |
498 | _LIBUNWIND_ABORT("_Unwind_Resume() can't return" ); |
499 | } |
500 | |
501 | |
502 | |
503 | /// Not used by C++. |
504 | /// Unwinds stack, calling "stop" function at each frame. |
505 | /// Could be used to implement longjmp(). |
506 | _LIBUNWIND_EXPORT _Unwind_Reason_Code |
507 | _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, |
508 | _Unwind_Stop_Fn stop, void *stop_parameter) { |
509 | _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)" , |
510 | (void *)exception_object, (void *)(uintptr_t)stop); |
511 | unw_context_t uc; |
512 | unw_cursor_t cursor; |
513 | __unw_getcontext(&uc); |
514 | |
515 | // Mark that this is a forced unwind, so _Unwind_Resume() can do |
516 | // the right thing. |
517 | exception_object->private_1 = (uintptr_t) stop; |
518 | exception_object->private_2 = (uintptr_t) stop_parameter; |
519 | |
520 | // do it |
521 | return unwind_phase2_forced(uc: &uc, cursor: &cursor, exception_object, stop, stop_parameter); |
522 | } |
523 | |
524 | |
525 | /// Called by personality handler during phase 2 to get LSDA for current frame. |
526 | _LIBUNWIND_EXPORT uintptr_t |
527 | _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { |
528 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
529 | unw_proc_info_t frameInfo; |
530 | uintptr_t result = 0; |
531 | if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) |
532 | result = (uintptr_t)frameInfo.lsda; |
533 | _LIBUNWIND_TRACE_API( |
534 | "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, |
535 | (void *)context, result); |
536 | #if !defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) |
537 | if (result != 0) { |
538 | if (*((uint8_t *)result) != 0xFF) |
539 | _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF" , |
540 | result); |
541 | } |
542 | #endif |
543 | return result; |
544 | } |
545 | |
546 | |
547 | /// Called by personality handler during phase 2 to find the start of the |
548 | /// function. |
549 | _LIBUNWIND_EXPORT uintptr_t |
550 | _Unwind_GetRegionStart(struct _Unwind_Context *context) { |
551 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
552 | unw_proc_info_t frameInfo; |
553 | uintptr_t result = 0; |
554 | if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) |
555 | result = (uintptr_t)frameInfo.start_ip; |
556 | _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, |
557 | (void *)context, result); |
558 | return result; |
559 | } |
560 | |
561 | #endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND |
562 | |
563 | /// Called by personality handler during phase 2 if a foreign exception |
564 | // is caught. |
565 | _LIBUNWIND_EXPORT void |
566 | _Unwind_DeleteException(_Unwind_Exception *exception_object) { |
567 | _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)" , |
568 | (void *)exception_object); |
569 | if (exception_object->exception_cleanup != NULL) |
570 | (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, |
571 | exception_object); |
572 | } |
573 | |
574 | /// Called by personality handler during phase 2 to get register values. |
575 | _LIBUNWIND_EXPORT uintptr_t |
576 | _Unwind_GetGR(struct _Unwind_Context *context, int index) { |
577 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
578 | unw_word_t result; |
579 | __unw_get_reg(cursor, index, &result); |
580 | _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR, |
581 | (void *)context, index, result); |
582 | return (uintptr_t)result; |
583 | } |
584 | |
585 | /// Called by personality handler during phase 2 to alter register values. |
586 | _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, |
587 | uintptr_t value) { |
588 | _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR |
589 | ")" , |
590 | (void *)context, index, value); |
591 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
592 | __unw_set_reg(cursor, index, value); |
593 | } |
594 | |
595 | /// Called by personality handler during phase 2 to get instruction pointer. |
596 | _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { |
597 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
598 | unw_word_t result; |
599 | __unw_get_reg(cursor, UNW_REG_IP, &result); |
600 | _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR, |
601 | (void *)context, result); |
602 | return (uintptr_t)result; |
603 | } |
604 | |
605 | /// Called by personality handler during phase 2 to alter instruction pointer, |
606 | /// such as setting where the landing pad is, so _Unwind_Resume() will |
607 | /// start executing in the landing pad. |
608 | _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, |
609 | uintptr_t value) { |
610 | _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")" , |
611 | (void *)context, value); |
612 | unw_cursor_t *cursor = (unw_cursor_t *)context; |
613 | __unw_set_reg(cursor, UNW_REG_IP, value); |
614 | } |
615 | |
616 | #endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) |
617 | |