1 //===----------------------------------------------------------------------===//
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
8 // Implements gcc extensions to the C++ ABI Exception Handling Level 1.
10 //===----------------------------------------------------------------------===//
20 #include "libunwind_ext.h"
21 #include "libunwind.h"
22 #include "Unwind-EHABI.h"
26 #include <sys/debug.h>
29 #if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
31 #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
32 #define PRIVATE_1 private_[0]
33 #elif defined(_LIBUNWIND_ARM_EHABI)
34 #define PRIVATE_1 unwinder_cache.reserved1
36 #define PRIVATE_1 private_1
39 /// Called by __cxa_rethrow().
40 _LIBUNWIND_EXPORT _Unwind_Reason_Code
41 _Unwind_Resume_or_Rethrow(_Unwind_Exception
*exception_object
) {
43 "_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR
,
44 (void *)exception_object
, (intptr_t)exception_object
->PRIVATE_1
);
46 // If this is non-forced and a stopping place was found, then this is a
48 // Call _Unwind_RaiseException() as if this was a new exception
49 if (exception_object
->PRIVATE_1
== 0) {
50 return _Unwind_RaiseException(exception_object
);
51 // Will return if there is no catch clause, so that __cxa_rethrow can call
55 // Call through to _Unwind_Resume() which distinguishes between forced and
56 // regular exceptions.
57 _Unwind_Resume(exception_object
);
58 _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()"
59 " which unexpectedly returned");
62 /// Called by personality handler during phase 2 to get base address for data
63 /// relative encodings.
64 _LIBUNWIND_EXPORT
uintptr_t
65 _Unwind_GetDataRelBase(struct _Unwind_Context
*context
) {
66 _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context
);
68 return unw_get_data_rel_base((unw_cursor_t
*)context
);
71 _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
75 /// Called by personality handler during phase 2 to get base address for text
76 /// relative encodings.
77 _LIBUNWIND_EXPORT
uintptr_t
78 _Unwind_GetTextRelBase(struct _Unwind_Context
*context
) {
80 _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context
);
81 _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
85 /// Scans unwind information to find the function that contains the
86 /// specified code address "pc".
87 _LIBUNWIND_EXPORT
void *_Unwind_FindEnclosingFunction(void *pc
) {
88 _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc
);
93 // Get the start address of the enclosing function from the function's
95 uint32_t *p
= (uint32_t *)pc
;
97 // Keep looking forward until a word of 0 is found. The traceback
98 // table starts at the following word.
101 struct tbtable
*TBTable
= (struct tbtable
*)(p
+ 1);
103 // Get the address of the traceback table extension.
104 p
= (uint32_t *)&TBTable
->tb_ext
;
106 // Skip field parminfo if it exists.
107 if (TBTable
->tb
.fixedparms
|| TBTable
->tb
.floatparms
)
110 if (TBTable
->tb
.has_tboff
)
111 // *p contains the offset from the function start to traceback table.
112 return (void *)((uintptr_t)TBTable
- *p
- sizeof(uint32_t));
115 // This is slow, but works.
116 // We create an unwind cursor then alter the IP to be pc
119 unw_proc_info_t info
;
120 __unw_getcontext(&uc
);
121 __unw_init_local(&cursor
, &uc
);
122 __unw_set_reg(&cursor
, UNW_REG_IP
, (unw_word_t
)(intptr_t)pc
);
123 if (__unw_get_proc_info(&cursor
, &info
) == UNW_ESUCCESS
)
124 return (void *)(intptr_t) info
.start_ip
;
130 /// Walk every frame and call trace function at each one. If trace function
131 /// returns anything other than _URC_NO_REASON, then walk is terminated.
132 _LIBUNWIND_EXPORT _Unwind_Reason_Code
133 _Unwind_Backtrace(_Unwind_Trace_Fn callback
, void *ref
) {
136 __unw_getcontext(&uc
);
137 __unw_init_local(&cursor
, &uc
);
139 _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)",
140 (void *)(uintptr_t)callback
);
142 #if defined(_LIBUNWIND_ARM_EHABI)
143 // Create a mock exception object for force unwinding.
144 _Unwind_Exception ex
;
145 memset(&ex
, '\0', sizeof(ex
));
146 memcpy(&ex
.exception_class
, "CLNGUNW", sizeof(ex
.exception_class
));
151 _Unwind_Reason_Code result
;
153 #if !defined(_LIBUNWIND_ARM_EHABI)
154 // ask libunwind to get next frame (skip over first frame which is
155 // _Unwind_Backtrace())
156 if (__unw_step(&cursor
) <= 0) {
157 _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached "
158 "bottom of stack, returning %d",
160 return _URC_END_OF_STACK
;
163 // Get the information for this frame.
164 unw_proc_info_t frameInfo
;
165 if (__unw_get_proc_info(&cursor
, &frameInfo
) != UNW_ESUCCESS
) {
166 return _URC_END_OF_STACK
;
169 // Update the pr_cache in the mock exception object.
170 uint32_t *unwindInfo
= (uint32_t *)frameInfo
.unwind_info
;
171 ex
.pr_cache
.fnstart
= frameInfo
.start_ip
;
172 ex
.pr_cache
.ehtp
= (_Unwind_EHT_Header
*) unwindInfo
;
173 ex
.pr_cache
.additional
= frameInfo
.flags
;
175 struct _Unwind_Context
*context
= (struct _Unwind_Context
*)&cursor
;
176 // Get and call the personality function to unwind the frame.
177 _Unwind_Personality_Fn handler
= (_Unwind_Personality_Fn
)frameInfo
.handler
;
178 if (handler
== NULL
) {
179 return _URC_END_OF_STACK
;
181 if (handler(_US_VIRTUAL_UNWIND_FRAME
| _US_FORCE_UNWIND
, &ex
, context
) !=
182 _URC_CONTINUE_UNWIND
) {
183 return _URC_END_OF_STACK
;
185 #endif // defined(_LIBUNWIND_ARM_EHABI)
188 if (_LIBUNWIND_TRACING_UNWINDING
) {
189 char functionName
[512];
190 unw_proc_info_t frame
;
192 __unw_get_proc_name(&cursor
, functionName
, 512, &offset
);
193 __unw_get_proc_info(&cursor
, &frame
);
194 _LIBUNWIND_TRACE_UNWINDING(
195 " _backtrace: start_ip=0x%" PRIxPTR
", func=%s, lsda=0x%" PRIxPTR
", context=%p",
196 frame
.start_ip
, functionName
, frame
.lsda
,
200 // call trace function with this frame
201 result
= (*callback
)((struct _Unwind_Context
*)(&cursor
), ref
);
202 if (result
!= _URC_NO_REASON
) {
203 _LIBUNWIND_TRACE_UNWINDING(
204 " _backtrace: ended because callback returned %d", result
);
211 /// Find DWARF unwind info for an address 'pc' in some function.
212 _LIBUNWIND_EXPORT
const void *_Unwind_Find_FDE(const void *pc
,
213 struct dwarf_eh_bases
*bases
) {
214 // This is slow, but works.
215 // We create an unwind cursor then alter the IP to be pc
218 unw_proc_info_t info
;
219 __unw_getcontext(&uc
);
220 __unw_init_local(&cursor
, &uc
);
221 __unw_set_reg(&cursor
, UNW_REG_IP
, (unw_word_t
)(intptr_t)pc
);
222 __unw_get_proc_info(&cursor
, &info
);
223 bases
->tbase
= (uintptr_t)info
.extra
;
224 bases
->dbase
= 0; // dbase not used on Mac OS X
225 bases
->func
= (uintptr_t)info
.start_ip
;
226 _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc
,
227 (void *)(intptr_t) info
.unwind_info
);
228 return (void *)(intptr_t) info
.unwind_info
;
231 /// Returns the CFA (call frame area, or stack pointer at start of function)
232 /// for the current context.
233 _LIBUNWIND_EXPORT
uintptr_t _Unwind_GetCFA(struct _Unwind_Context
*context
) {
234 unw_cursor_t
*cursor
= (unw_cursor_t
*)context
;
236 __unw_get_reg(cursor
, UNW_REG_SP
, &result
);
237 _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR
,
238 (void *)context
, result
);
239 return (uintptr_t)result
;
243 /// Called by personality handler during phase 2 to get instruction pointer.
244 /// ipBefore is a boolean that says if IP is already adjusted to be the call
245 /// site address. Normally IP is the return address.
246 _LIBUNWIND_EXPORT
uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context
*context
,
248 _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context
);
249 int isSignalFrame
= __unw_is_signal_frame((unw_cursor_t
*)context
);
250 // Negative means some kind of error (probably UNW_ENOINFO), but we have no
251 // good way to report that, and this maintains backward compatibility with the
252 // implementation that hard-coded zero in every case, even signal frames.
253 if (isSignalFrame
<= 0)
257 return _Unwind_GetIP(context
);
260 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
262 /// Called by programs with dynamic code generators that want
263 /// to register a dynamically generated FDE.
264 /// This function has existed on Mac OS X since 10.4, but
265 /// was broken until 10.6.
266 _LIBUNWIND_EXPORT
void __register_frame(const void *fde
) {
267 _LIBUNWIND_TRACE_API("__register_frame(%p)", fde
);
268 __unw_add_dynamic_fde((unw_word_t
)(uintptr_t)fde
);
272 /// Called by programs with dynamic code generators that want
273 /// to unregister a dynamically generated FDE.
274 /// This function has existed on Mac OS X since 10.4, but
275 /// was broken until 10.6.
276 _LIBUNWIND_EXPORT
void __deregister_frame(const void *fde
) {
277 _LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde
);
278 __unw_remove_dynamic_fde((unw_word_t
)(uintptr_t)fde
);
282 // The following register/deregister functions are gcc extensions.
283 // They have existed on Mac OS X, but have never worked because Mac OS X
284 // before 10.6 used keymgr to track known FDEs, but these functions
285 // never got updated to use keymgr.
286 // For now, we implement these as do-nothing functions to keep any existing
287 // applications working. We also add the not in 10.6 symbol so that nwe
288 // application won't be able to use them.
290 #if defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
291 _LIBUNWIND_EXPORT
void __register_frame_info_bases(const void *fde
, void *ob
,
292 void *tb
, void *db
) {
297 _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)",
299 // do nothing, this function never worked in Mac OS X
302 _LIBUNWIND_EXPORT
void __register_frame_info(const void *fde
, void *ob
) {
305 _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde
, ob
);
306 // do nothing, this function never worked in Mac OS X
309 _LIBUNWIND_EXPORT
void __register_frame_info_table_bases(const void *fde
,
316 _LIBUNWIND_TRACE_API("__register_frame_info_table_bases"
317 "(%p,%p, %p, %p)", fde
, ob
, tb
, db
);
318 // do nothing, this function never worked in Mac OS X
321 _LIBUNWIND_EXPORT
void __register_frame_info_table(const void *fde
, void *ob
) {
324 _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde
, ob
);
325 // do nothing, this function never worked in Mac OS X
328 _LIBUNWIND_EXPORT
void __register_frame_table(const void *fde
) {
330 _LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde
);
331 // do nothing, this function never worked in Mac OS X
334 _LIBUNWIND_EXPORT
void *__deregister_frame_info(const void *fde
) {
336 _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde
);
337 // do nothing, this function never worked in Mac OS X
341 _LIBUNWIND_EXPORT
void *__deregister_frame_info_bases(const void *fde
) {
343 _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde
);
344 // do nothing, this function never worked in Mac OS X
347 #endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
349 #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
351 #endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)