backtrace/backtrace/
libunwind.rs1use core::ffi::c_void;
19use core::ptr::addr_of_mut;
20
21pub enum Frame {
22 Raw(*mut uw::_Unwind_Context),
23 Cloned {
24 ip: *mut c_void,
25 sp: *mut c_void,
26 symbol_address: *mut c_void,
27 },
28}
29
30unsafe impl Send for Frame {}
35unsafe impl Sync for Frame {}
36
37impl Frame {
38 pub fn ip(&self) -> *mut c_void {
39 let ctx = match *self {
40 Frame::Raw(ctx) => ctx,
41 Frame::Cloned { ip, .. } => return ip,
42 };
43 #[allow(unused_mut)]
44 let mut ip = unsafe { uw::_Unwind_GetIP(ctx) as *mut c_void };
45
46 #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))]
50 {
51 let image_base = super::sgx_image_base::get_image_base();
52 ip = usize::wrapping_sub(ip as usize, image_base as _) as _;
53 }
54 ip
55 }
56
57 pub fn sp(&self) -> *mut c_void {
58 match *self {
59 Frame::Raw(ctx) => unsafe { uw::get_sp(ctx) as *mut c_void },
60 Frame::Cloned { sp, .. } => sp,
61 }
62 }
63
64 pub fn symbol_address(&self) -> *mut c_void {
65 if let Frame::Cloned { symbol_address, .. } = *self {
66 return symbol_address;
67 }
68
69 if cfg!(target_vendor = "apple") {
81 self.ip()
82 } else {
83 unsafe { uw::_Unwind_FindEnclosingFunction(self.ip()) }
84 }
85 }
86
87 pub fn module_base_address(&self) -> Option<*mut c_void> {
88 None
89 }
90}
91
92impl Clone for Frame {
93 fn clone(&self) -> Frame {
94 Frame::Cloned {
95 ip: self.ip(),
96 sp: self.sp(),
97 symbol_address: self.symbol_address(),
98 }
99 }
100}
101
102struct Bomb {
103 enabled: bool,
104}
105
106impl Drop for Bomb {
107 fn drop(&mut self) {
108 if self.enabled {
109 panic!("cannot panic during the backtrace function");
110 }
111 }
112}
113
114#[inline(always)]
115pub unsafe fn trace(mut cb: &mut dyn FnMut(&super::Frame) -> bool) {
116 unsafe {
117 uw::_Unwind_Backtrace(trace_fn, addr_of_mut!(cb).cast());
118 }
119
120 extern "C" fn trace_fn(
121 ctx: *mut uw::_Unwind_Context,
122 arg: *mut c_void,
123 ) -> uw::_Unwind_Reason_Code {
124 let cb = unsafe { &mut *arg.cast::<&mut dyn FnMut(&super::Frame) -> bool>() };
125 let cx = super::Frame {
126 inner: Frame::Raw(ctx),
127 };
128
129 let mut bomb = Bomb { enabled: true };
130 let keep_going = cb(&cx);
131 bomb.enabled = false;
132
133 if keep_going {
134 uw::_URC_NO_REASON
135 } else {
136 uw::_URC_FAILURE
137 }
138 }
139}
140
141#[allow(non_camel_case_types)]
147#[allow(non_snake_case)]
148#[allow(dead_code)]
149mod uw {
150 pub use self::_Unwind_Reason_Code::*;
151
152 use core::ffi::c_void;
153
154 #[repr(C)]
155 pub enum _Unwind_Reason_Code {
156 _URC_NO_REASON = 0,
157 _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
158 _URC_FATAL_PHASE2_ERROR = 2,
159 _URC_FATAL_PHASE1_ERROR = 3,
160 _URC_NORMAL_STOP = 4,
161 _URC_END_OF_STACK = 5,
162 _URC_HANDLER_FOUND = 6,
163 _URC_INSTALL_CONTEXT = 7,
164 _URC_CONTINUE_UNWIND = 8,
165 _URC_FAILURE = 9, }
167
168 pub enum _Unwind_Context {}
169
170 pub type _Unwind_Trace_Fn =
171 extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
172
173 unsafe extern "C" {
174 pub fn _Unwind_Backtrace(
175 trace: _Unwind_Trace_Fn,
176 trace_argument: *mut c_void,
177 ) -> _Unwind_Reason_Code;
178 }
179
180 cfg_if::cfg_if! {
181 if #[cfg(all(
183 not(all(target_os = "android", target_arch = "arm")),
184 not(all(target_os = "freebsd", target_arch = "arm")),
185 not(all(target_os = "linux", target_arch = "arm")),
186 not(all(target_os = "horizon", target_arch = "arm")),
187 not(all(target_os = "rtems", target_arch = "arm")),
188 not(all(target_os = "vita", target_arch = "arm")),
189 not(all(target_os = "nuttx", target_arch = "arm")),
190 ))] {
191 unsafe extern "C" {
192 pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t;
193 pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
194
195 #[cfg(not(all(target_os = "linux", target_arch = "s390x")))]
196 #[link_name = "_Unwind_GetCFA"]
202 pub fn get_sp(ctx: *mut _Unwind_Context) -> libc::uintptr_t;
203
204 }
205
206 #[cfg(all(target_os = "linux", target_arch = "s390x"))]
210 pub unsafe fn get_sp(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
211 unsafe extern "C" {
212 pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, index: libc::c_int) -> libc::uintptr_t;
213 }
214 unsafe { _Unwind_GetGR(ctx, 15) }
215 }
216 } else {
217 use core::ptr::addr_of_mut;
218
219 #[repr(C)]
227 enum _Unwind_VRS_Result {
228 _UVRSR_OK = 0,
229 _UVRSR_NOT_IMPLEMENTED = 1,
230 _UVRSR_FAILED = 2,
231 }
232 #[repr(C)]
233 enum _Unwind_VRS_RegClass {
234 _UVRSC_CORE = 0,
235 _UVRSC_VFP = 1,
236 _UVRSC_FPA = 2,
237 _UVRSC_WMMXD = 3,
238 _UVRSC_WMMXC = 4,
239 }
240 #[repr(C)]
241 enum _Unwind_VRS_DataRepresentation {
242 _UVRSD_UINT32 = 0,
243 _UVRSD_VFPX = 1,
244 _UVRSD_FPAX = 2,
245 _UVRSD_UINT64 = 3,
246 _UVRSD_FLOAT = 4,
247 _UVRSD_DOUBLE = 5,
248 }
249
250 type _Unwind_Word = libc::c_uint;
251 unsafe extern "C" {
252 fn _Unwind_VRS_Get(
253 ctx: *mut _Unwind_Context,
254 klass: _Unwind_VRS_RegClass,
255 word: _Unwind_Word,
256 repr: _Unwind_VRS_DataRepresentation,
257 data: *mut c_void,
258 ) -> _Unwind_VRS_Result;
259 }
260
261 pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
262 let mut val: _Unwind_Word = 0;
263 let ptr = addr_of_mut!(val);
264 unsafe {
265 let _ = _Unwind_VRS_Get(
266 ctx,
267 _Unwind_VRS_RegClass::_UVRSC_CORE,
268 15,
269 _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
270 ptr.cast::<c_void>(),
271 );
272 }
273 (val & !1) as libc::uintptr_t
274 }
275
276 const SP: _Unwind_Word = 13;
278
279 pub unsafe fn get_sp(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
280 let mut val: _Unwind_Word = 0;
281 let ptr = addr_of_mut!(val);
282 unsafe {
283 let _ = _Unwind_VRS_Get(
284 ctx,
285 _Unwind_VRS_RegClass::_UVRSC_CORE,
286 SP,
287 _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
288 ptr.cast::<c_void>(),
289 );
290 }
291 val as libc::uintptr_t
292 }
293
294 pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
297 pc
298 }
299 }
300 }
301}