]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/backtrace.rs
Don't default on std crate when manipulating browser history
[rust.git] / src / libstd / sys / sgx / backtrace.rs
1 use io;
2 use error::Error;
3 use libc;
4 use sys_common::backtrace::Frame;
5 use unwind as uw;
6 use sys::sgx::abi::mem::image_base;
7
8 pub struct BacktraceContext;
9
10 struct Context<'a> {
11     idx: usize,
12     frames: &'a mut [Frame],
13 }
14
15 #[derive(Debug)]
16 struct UnwindError(uw::_Unwind_Reason_Code);
17
18 impl Error for UnwindError {
19     fn description(&self) -> &'static str {
20         "unexpected return value while unwinding"
21     }
22 }
23
24 impl ::fmt::Display for UnwindError {
25     fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
26         write!(f, "{}: {:?}", self.description(), self.0)
27     }
28 }
29
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 };
33     let result_unwind =
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))
42         }
43         _ => Err(io::Error::new(
44             io::ErrorKind::Other,
45             UnwindError(result_unwind),
46         )),
47     };
48     res
49 }
50
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;
58     }
59
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 _;
66     }
67
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,
72         inline_context: 0,
73     };
74     cx.idx += 1;
75
76     uw::_URC_NO_REASON
77 }
78
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,
82                           callback: F,
83                           _: &BacktraceContext) -> io::Result<()>
84     where F: FnOnce(Option<&str>) -> io::Result<()>
85 {
86     callback(Some(&format!("0x{:x}",
87             (frame.symbol_addr.wrapping_offset_from(image_base() as _)))))
88 }
89
90 pub fn foreach_symbol_fileline<F>(_: Frame,
91                                   _: F,
92                                   _: &BacktraceContext) -> io::Result<bool>
93     where F: FnMut(&[u8], u32) -> io::Result<()>
94 {
95     Ok(false)
96 }