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