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