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