4 use sys_common::backtrace::Frame;
6 use sys::sgx::abi::mem::image_base;
8 pub struct BacktraceContext;
12 frames: &'a mut [Frame],
16 struct UnwindError(uw::_Unwind_Reason_Code);
18 impl Error for UnwindError {
19 fn description(&self) -> &'static str {
20 "unexpected return value while unwinding"
24 impl ::fmt::Display for UnwindError {
25 fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
26 write!(f, "{}: {:?}", self.description(), self.0)
30 #[inline(never)] // this function call can be skipped it when tracing.
31 pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
32 let mut cx = Context { idx: 0, frames };
34 unsafe { uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context as *mut libc::c_void) };
35 // See libunwind:src/unwind/Backtrace.c for the return values.
36 // No, there is no doc.
37 let res = match result_unwind {
38 // These return codes seem to be benign and need to be ignored for backtraces
39 // to show up properly on all tested platforms.
40 uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
41 Ok((cx.idx, BacktraceContext))
43 _ => Err(io::Error::new(
45 UnwindError(result_unwind),
51 extern "C" fn trace_fn(
52 ctx: *mut uw::_Unwind_Context,
53 arg: *mut libc::c_void,
54 ) -> uw::_Unwind_Reason_Code {
55 let cx = unsafe { &mut *(arg as *mut Context) };
56 if cx.idx >= cx.frames.len() {
57 return uw::_URC_NORMAL_STOP;
60 let mut ip_before_insn = 0;
61 let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void };
62 if !ip.is_null() && ip_before_insn == 0 {
63 // this is a non-signaling frame, so `ip` refers to the address
64 // after the calling instruction. account for that.
65 ip = (ip as usize - 1) as *mut _;
68 let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) };
69 cx.frames[cx.idx] = Frame {
70 symbol_addr: symaddr as *mut u8,
71 exact_position: ip as *mut u8,
79 // To reduce TCB size in Sgx enclave, we do not want to implement resolve_symname functionality.
80 // Rather, we print the offset of the address here, which could be later mapped to correct function.
81 pub fn resolve_symname<F>(frame: Frame,
83 _: &BacktraceContext) -> io::Result<()>
84 where F: FnOnce(Option<&str>) -> io::Result<()>
86 callback(Some(&format!("0x{:x}",
87 (frame.symbol_addr.wrapping_offset_from(image_base() as _)))))
90 pub fn foreach_symbol_fileline<F>(_: Frame,
92 _: &BacktraceContext) -> io::Result<bool>
93 where F: FnMut(&[u8], u32) -> io::Result<()>