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