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 gcc extensions to the C++ ABI Exception Handling Level 1.
9f6c50668Spatrick //
10f6c50668Spatrick //===----------------------------------------------------------------------===//
11f6c50668Spatrick
12f6c50668Spatrick #include <inttypes.h>
13f6c50668Spatrick #include <stdbool.h>
14f6c50668Spatrick #include <stdint.h>
15f6c50668Spatrick #include <stdio.h>
16f6c50668Spatrick #include <stdlib.h>
17f6c50668Spatrick #include <string.h>
18f6c50668Spatrick
19f6c50668Spatrick #include "config.h"
20f6c50668Spatrick #include "libunwind_ext.h"
21f6c50668Spatrick #include "libunwind.h"
22f6c50668Spatrick #include "Unwind-EHABI.h"
23f6c50668Spatrick #include "unwind.h"
24f6c50668Spatrick
25*0faf1914Srobert #if defined(_AIX)
26*0faf1914Srobert #include <sys/debug.h>
27*0faf1914Srobert #endif
28*0faf1914Srobert
29f6c50668Spatrick #if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
30f6c50668Spatrick
31f6c50668Spatrick #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
32*0faf1914Srobert #define PRIVATE_1 private_[0]
33*0faf1914Srobert #elif defined(_LIBUNWIND_ARM_EHABI)
34*0faf1914Srobert #define PRIVATE_1 unwinder_cache.reserved1
35*0faf1914Srobert #else
36*0faf1914Srobert #define PRIVATE_1 private_1
37f6c50668Spatrick #endif
38f6c50668Spatrick
39f6c50668Spatrick /// Called by __cxa_rethrow().
40f6c50668Spatrick _LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_Resume_or_Rethrow(_Unwind_Exception * exception_object)41f6c50668Spatrick _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
42*0faf1914Srobert _LIBUNWIND_TRACE_API(
43*0faf1914Srobert "_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR,
44*0faf1914Srobert (void *)exception_object, (intptr_t)exception_object->PRIVATE_1);
45f6c50668Spatrick
46f6c50668Spatrick // If this is non-forced and a stopping place was found, then this is a
47f6c50668Spatrick // re-throw.
48f6c50668Spatrick // Call _Unwind_RaiseException() as if this was a new exception
49*0faf1914Srobert if (exception_object->PRIVATE_1 == 0) {
50f6c50668Spatrick return _Unwind_RaiseException(exception_object);
51f6c50668Spatrick // Will return if there is no catch clause, so that __cxa_rethrow can call
52f6c50668Spatrick // std::terminate().
53f6c50668Spatrick }
54f6c50668Spatrick
55*0faf1914Srobert // Call through to _Unwind_Resume() which distinguishes between forced and
56f6c50668Spatrick // regular exceptions.
57f6c50668Spatrick _Unwind_Resume(exception_object);
58f6c50668Spatrick _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()"
59f6c50668Spatrick " which unexpectedly returned");
60f6c50668Spatrick }
61f6c50668Spatrick
62f6c50668Spatrick /// Called by personality handler during phase 2 to get base address for data
63f6c50668Spatrick /// relative encodings.
64f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t
_Unwind_GetDataRelBase(struct _Unwind_Context * context)65f6c50668Spatrick _Unwind_GetDataRelBase(struct _Unwind_Context *context) {
66f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
67*0faf1914Srobert #if defined(_AIX)
68*0faf1914Srobert return unw_get_data_rel_base((unw_cursor_t *)context);
69*0faf1914Srobert #else
70*0faf1914Srobert (void)context;
71f6c50668Spatrick _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
72*0faf1914Srobert #endif
73f6c50668Spatrick }
74f6c50668Spatrick
75f6c50668Spatrick /// Called by personality handler during phase 2 to get base address for text
76f6c50668Spatrick /// relative encodings.
77f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t
_Unwind_GetTextRelBase(struct _Unwind_Context * context)78f6c50668Spatrick _Unwind_GetTextRelBase(struct _Unwind_Context *context) {
79f6c50668Spatrick (void)context;
80f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
81f6c50668Spatrick _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
82f6c50668Spatrick }
83f6c50668Spatrick
84f6c50668Spatrick
85f6c50668Spatrick /// Scans unwind information to find the function that contains the
86f6c50668Spatrick /// specified code address "pc".
_Unwind_FindEnclosingFunction(void * pc)87f6c50668Spatrick _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
88f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc);
89*0faf1914Srobert #if defined(_AIX)
90*0faf1914Srobert if (pc == NULL)
91*0faf1914Srobert return NULL;
92*0faf1914Srobert
93*0faf1914Srobert // Get the start address of the enclosing function from the function's
94*0faf1914Srobert // traceback table.
95*0faf1914Srobert uint32_t *p = (uint32_t *)pc;
96*0faf1914Srobert
97*0faf1914Srobert // Keep looking forward until a word of 0 is found. The traceback
98*0faf1914Srobert // table starts at the following word.
99*0faf1914Srobert while (*p)
100*0faf1914Srobert ++p;
101*0faf1914Srobert struct tbtable *TBTable = (struct tbtable *)(p + 1);
102*0faf1914Srobert
103*0faf1914Srobert // Get the address of the traceback table extension.
104*0faf1914Srobert p = (uint32_t *)&TBTable->tb_ext;
105*0faf1914Srobert
106*0faf1914Srobert // Skip field parminfo if it exists.
107*0faf1914Srobert if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
108*0faf1914Srobert ++p;
109*0faf1914Srobert
110*0faf1914Srobert if (TBTable->tb.has_tboff)
111*0faf1914Srobert // *p contains the offset from the function start to traceback table.
112*0faf1914Srobert return (void *)((uintptr_t)TBTable - *p - sizeof(uint32_t));
113*0faf1914Srobert return NULL;
114*0faf1914Srobert #else
115f6c50668Spatrick // This is slow, but works.
116f6c50668Spatrick // We create an unwind cursor then alter the IP to be pc
117f6c50668Spatrick unw_cursor_t cursor;
118f6c50668Spatrick unw_context_t uc;
119f6c50668Spatrick unw_proc_info_t info;
120f6c50668Spatrick __unw_getcontext(&uc);
121f6c50668Spatrick __unw_init_local(&cursor, &uc);
122f6c50668Spatrick __unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc);
123f6c50668Spatrick if (__unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)
124f6c50668Spatrick return (void *)(intptr_t) info.start_ip;
125f6c50668Spatrick else
126f6c50668Spatrick return NULL;
127*0faf1914Srobert #endif
128f6c50668Spatrick }
129f6c50668Spatrick
130f6c50668Spatrick /// Walk every frame and call trace function at each one. If trace function
131f6c50668Spatrick /// returns anything other than _URC_NO_REASON, then walk is terminated.
132f6c50668Spatrick _LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_Backtrace(_Unwind_Trace_Fn callback,void * ref)133f6c50668Spatrick _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
134f6c50668Spatrick unw_cursor_t cursor;
135f6c50668Spatrick unw_context_t uc;
136f6c50668Spatrick __unw_getcontext(&uc);
137f6c50668Spatrick __unw_init_local(&cursor, &uc);
138f6c50668Spatrick
139f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)",
140f6c50668Spatrick (void *)(uintptr_t)callback);
141f6c50668Spatrick
142f6c50668Spatrick #if defined(_LIBUNWIND_ARM_EHABI)
143f6c50668Spatrick // Create a mock exception object for force unwinding.
144f6c50668Spatrick _Unwind_Exception ex;
145f6c50668Spatrick memset(&ex, '\0', sizeof(ex));
146*0faf1914Srobert strcpy((char *)&ex.exception_class, "CLNGUNW");
147f6c50668Spatrick #endif
148f6c50668Spatrick
149f6c50668Spatrick // walk each frame
150f6c50668Spatrick while (true) {
151f6c50668Spatrick _Unwind_Reason_Code result;
152f6c50668Spatrick
153f6c50668Spatrick #if !defined(_LIBUNWIND_ARM_EHABI)
154f6c50668Spatrick // ask libunwind to get next frame (skip over first frame which is
155f6c50668Spatrick // _Unwind_Backtrace())
156f6c50668Spatrick if (__unw_step(&cursor) <= 0) {
157f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached "
158f6c50668Spatrick "bottom of stack, returning %d",
159f6c50668Spatrick _URC_END_OF_STACK);
160f6c50668Spatrick return _URC_END_OF_STACK;
161f6c50668Spatrick }
162f6c50668Spatrick #else
163f6c50668Spatrick // Get the information for this frame.
164f6c50668Spatrick unw_proc_info_t frameInfo;
165f6c50668Spatrick if (__unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) {
166f6c50668Spatrick return _URC_END_OF_STACK;
167f6c50668Spatrick }
168f6c50668Spatrick
169f6c50668Spatrick // Update the pr_cache in the mock exception object.
170f6c50668Spatrick const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info;
171f6c50668Spatrick ex.pr_cache.fnstart = frameInfo.start_ip;
172f6c50668Spatrick ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo;
173f6c50668Spatrick ex.pr_cache.additional= frameInfo.flags;
174f6c50668Spatrick
175f6c50668Spatrick struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;
176f6c50668Spatrick // Get and call the personality function to unwind the frame.
177f6c50668Spatrick _Unwind_Personality_Fn handler = (_Unwind_Personality_Fn)frameInfo.handler;
178f6c50668Spatrick if (handler == NULL) {
179f6c50668Spatrick return _URC_END_OF_STACK;
180f6c50668Spatrick }
181f6c50668Spatrick if (handler(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) !=
182f6c50668Spatrick _URC_CONTINUE_UNWIND) {
183f6c50668Spatrick return _URC_END_OF_STACK;
184f6c50668Spatrick }
185f6c50668Spatrick #endif // defined(_LIBUNWIND_ARM_EHABI)
186f6c50668Spatrick
187f6c50668Spatrick // debugging
188f6c50668Spatrick if (_LIBUNWIND_TRACING_UNWINDING) {
189f6c50668Spatrick char functionName[512];
190f6c50668Spatrick unw_proc_info_t frame;
191f6c50668Spatrick unw_word_t offset;
192f6c50668Spatrick __unw_get_proc_name(&cursor, functionName, 512, &offset);
193f6c50668Spatrick __unw_get_proc_info(&cursor, &frame);
194f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING(
195f6c50668Spatrick " _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p",
196f6c50668Spatrick frame.start_ip, functionName, frame.lsda,
197f6c50668Spatrick (void *)&cursor);
198f6c50668Spatrick }
199f6c50668Spatrick
200f6c50668Spatrick // call trace function with this frame
201f6c50668Spatrick result = (*callback)((struct _Unwind_Context *)(&cursor), ref);
202f6c50668Spatrick if (result != _URC_NO_REASON) {
203f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING(
204f6c50668Spatrick " _backtrace: ended because callback returned %d", result);
205f6c50668Spatrick return result;
206f6c50668Spatrick }
207f6c50668Spatrick }
208f6c50668Spatrick }
209f6c50668Spatrick
210f6c50668Spatrick
211f6c50668Spatrick /// Find DWARF unwind info for an address 'pc' in some function.
_Unwind_Find_FDE(const void * pc,struct dwarf_eh_bases * bases)212f6c50668Spatrick _LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,
213f6c50668Spatrick struct dwarf_eh_bases *bases) {
214f6c50668Spatrick // This is slow, but works.
215f6c50668Spatrick // We create an unwind cursor then alter the IP to be pc
216f6c50668Spatrick unw_cursor_t cursor;
217f6c50668Spatrick unw_context_t uc;
218f6c50668Spatrick unw_proc_info_t info;
219f6c50668Spatrick __unw_getcontext(&uc);
220f6c50668Spatrick __unw_init_local(&cursor, &uc);
221f6c50668Spatrick __unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc);
222f6c50668Spatrick __unw_get_proc_info(&cursor, &info);
223f6c50668Spatrick bases->tbase = (uintptr_t)info.extra;
224f6c50668Spatrick bases->dbase = 0; // dbase not used on Mac OS X
225f6c50668Spatrick bases->func = (uintptr_t)info.start_ip;
226f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc,
227f6c50668Spatrick (void *)(intptr_t) info.unwind_info);
228f6c50668Spatrick return (void *)(intptr_t) info.unwind_info;
229f6c50668Spatrick }
230f6c50668Spatrick
231f6c50668Spatrick /// Returns the CFA (call frame area, or stack pointer at start of function)
232f6c50668Spatrick /// for the current context.
_Unwind_GetCFA(struct _Unwind_Context * context)233f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
234f6c50668Spatrick unw_cursor_t *cursor = (unw_cursor_t *)context;
235f6c50668Spatrick unw_word_t result;
236f6c50668Spatrick __unw_get_reg(cursor, UNW_REG_SP, &result);
237f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR,
238f6c50668Spatrick (void *)context, result);
239f6c50668Spatrick return (uintptr_t)result;
240f6c50668Spatrick }
241f6c50668Spatrick
242f6c50668Spatrick
243f6c50668Spatrick /// Called by personality handler during phase 2 to get instruction pointer.
244f6c50668Spatrick /// ipBefore is a boolean that says if IP is already adjusted to be the call
245f6c50668Spatrick /// site address. Normally IP is the return address.
_Unwind_GetIPInfo(struct _Unwind_Context * context,int * ipBefore)246f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
247f6c50668Spatrick int *ipBefore) {
248f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context);
249f6c50668Spatrick int isSignalFrame = __unw_is_signal_frame((unw_cursor_t *)context);
250f6c50668Spatrick // Negative means some kind of error (probably UNW_ENOINFO), but we have no
251f6c50668Spatrick // good way to report that, and this maintains backward compatibility with the
252f6c50668Spatrick // implementation that hard-coded zero in every case, even signal frames.
253f6c50668Spatrick if (isSignalFrame <= 0)
254f6c50668Spatrick *ipBefore = 0;
255f6c50668Spatrick else
256f6c50668Spatrick *ipBefore = 1;
257f6c50668Spatrick return _Unwind_GetIP(context);
258f6c50668Spatrick }
259f6c50668Spatrick
260f6c50668Spatrick #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
261f6c50668Spatrick
262f6c50668Spatrick /// Called by programs with dynamic code generators that want
263f6c50668Spatrick /// to register a dynamically generated FDE.
264f6c50668Spatrick /// This function has existed on Mac OS X since 10.4, but
265f6c50668Spatrick /// was broken until 10.6.
__register_frame(const void * fde)266f6c50668Spatrick _LIBUNWIND_EXPORT void __register_frame(const void *fde) {
267f6c50668Spatrick _LIBUNWIND_TRACE_API("__register_frame(%p)", fde);
268f6c50668Spatrick __unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde);
269f6c50668Spatrick }
270f6c50668Spatrick
271f6c50668Spatrick
272f6c50668Spatrick /// Called by programs with dynamic code generators that want
273f6c50668Spatrick /// to unregister a dynamically generated FDE.
274f6c50668Spatrick /// This function has existed on Mac OS X since 10.4, but
275f6c50668Spatrick /// was broken until 10.6.
__deregister_frame(const void * fde)276f6c50668Spatrick _LIBUNWIND_EXPORT void __deregister_frame(const void *fde) {
277f6c50668Spatrick _LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde);
278f6c50668Spatrick __unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde);
279f6c50668Spatrick }
280f6c50668Spatrick
281f6c50668Spatrick
282f6c50668Spatrick // The following register/deregister functions are gcc extensions.
283f6c50668Spatrick // They have existed on Mac OS X, but have never worked because Mac OS X
284f6c50668Spatrick // before 10.6 used keymgr to track known FDEs, but these functions
285f6c50668Spatrick // never got updated to use keymgr.
286f6c50668Spatrick // For now, we implement these as do-nothing functions to keep any existing
287f6c50668Spatrick // applications working. We also add the not in 10.6 symbol so that nwe
288f6c50668Spatrick // application won't be able to use them.
289f6c50668Spatrick
290f6c50668Spatrick #if defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
__register_frame_info_bases(const void * fde,void * ob,void * tb,void * db)291f6c50668Spatrick _LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob,
292f6c50668Spatrick void *tb, void *db) {
293f6c50668Spatrick (void)fde;
294f6c50668Spatrick (void)ob;
295f6c50668Spatrick (void)tb;
296f6c50668Spatrick (void)db;
297f6c50668Spatrick _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)",
298f6c50668Spatrick fde, ob, tb, db);
299f6c50668Spatrick // do nothing, this function never worked in Mac OS X
300f6c50668Spatrick }
301f6c50668Spatrick
__register_frame_info(const void * fde,void * ob)302f6c50668Spatrick _LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) {
303f6c50668Spatrick (void)fde;
304f6c50668Spatrick (void)ob;
305f6c50668Spatrick _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde, ob);
306f6c50668Spatrick // do nothing, this function never worked in Mac OS X
307f6c50668Spatrick }
308f6c50668Spatrick
__register_frame_info_table_bases(const void * fde,void * ob,void * tb,void * db)309f6c50668Spatrick _LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde,
310f6c50668Spatrick void *ob, void *tb,
311f6c50668Spatrick void *db) {
312f6c50668Spatrick (void)fde;
313f6c50668Spatrick (void)ob;
314f6c50668Spatrick (void)tb;
315f6c50668Spatrick (void)db;
316f6c50668Spatrick _LIBUNWIND_TRACE_API("__register_frame_info_table_bases"
317f6c50668Spatrick "(%p,%p, %p, %p)", fde, ob, tb, db);
318f6c50668Spatrick // do nothing, this function never worked in Mac OS X
319f6c50668Spatrick }
320f6c50668Spatrick
__register_frame_info_table(const void * fde,void * ob)321f6c50668Spatrick _LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) {
322f6c50668Spatrick (void)fde;
323f6c50668Spatrick (void)ob;
324f6c50668Spatrick _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde, ob);
325f6c50668Spatrick // do nothing, this function never worked in Mac OS X
326f6c50668Spatrick }
327f6c50668Spatrick
__register_frame_table(const void * fde)328f6c50668Spatrick _LIBUNWIND_EXPORT void __register_frame_table(const void *fde) {
329f6c50668Spatrick (void)fde;
330f6c50668Spatrick _LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde);
331f6c50668Spatrick // do nothing, this function never worked in Mac OS X
332f6c50668Spatrick }
333f6c50668Spatrick
__deregister_frame_info(const void * fde)334f6c50668Spatrick _LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) {
335f6c50668Spatrick (void)fde;
336f6c50668Spatrick _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde);
337f6c50668Spatrick // do nothing, this function never worked in Mac OS X
338f6c50668Spatrick return NULL;
339f6c50668Spatrick }
340f6c50668Spatrick
__deregister_frame_info_bases(const void * fde)341f6c50668Spatrick _LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) {
342f6c50668Spatrick (void)fde;
343f6c50668Spatrick _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde);
344f6c50668Spatrick // do nothing, this function never worked in Mac OS X
345f6c50668Spatrick return NULL;
346f6c50668Spatrick }
347f6c50668Spatrick #endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
348f6c50668Spatrick
349f6c50668Spatrick #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
350f6c50668Spatrick
351f6c50668Spatrick #endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
352