]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/redox/backtrace/tracing.rs
New upstream version 1.33.0+dfsg1
[rustc.git] / src / libstd / sys / redox / backtrace / tracing.rs
CommitLineData
3b2f2976
XL
1use error::Error;
2use io;
3use libc;
4use sys::backtrace::BacktraceContext;
5use sys_common::backtrace::Frame;
6
7use unwind as uw;
8
9struct Context<'a> {
10 idx: usize,
11 frames: &'a mut [Frame],
12}
13
14#[derive(Debug)]
15struct UnwindError(uw::_Unwind_Reason_Code);
16
17impl Error for UnwindError {
18 fn description(&self) -> &'static str {
19 "unexpected return value while unwinding"
20 }
21}
22
23impl ::fmt::Display for UnwindError {
24 fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
25 write!(f, "{}: {:?}", self.description(), self.0)
26 }
27}
28
29#[inline(never)] // if we know this is a function call, we can skip it when
30 // tracing
31pub fn unwind_backtrace(frames: &mut [Frame])
32 -> io::Result<(usize, BacktraceContext)>
33{
34 let mut cx = Context {
35 idx: 0,
36 frames: frames,
37 };
38 let result_unwind = unsafe {
39 uw::_Unwind_Backtrace(trace_fn,
40 &mut cx as *mut Context
41 as *mut libc::c_void)
42 };
43 // See libunwind:src/unwind/Backtrace.c for the return values.
44 // No, there is no doc.
45 match result_unwind {
46 // These return codes seem to be benign and need to be ignored for backtraces
47 // to show up properly on all tested platforms.
48 uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
49 Ok((cx.idx, BacktraceContext))
50 }
51 _ => {
52 Err(io::Error::new(io::ErrorKind::Other,
53 UnwindError(result_unwind)))
54 }
55 }
56}
57
58extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
59 arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
60 let cx = unsafe { &mut *(arg as *mut Context) };
b7449926
XL
61 if cx.idx >= cx.frames.len() {
62 return uw::_URC_NORMAL_STOP;
63 }
64
3b2f2976
XL
65 let mut ip_before_insn = 0;
66 let mut ip = unsafe {
67 uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
68 };
69 if !ip.is_null() && ip_before_insn == 0 {
70 // this is a non-signaling frame, so `ip` refers to the address
71 // after the calling instruction. account for that.
72 ip = (ip as usize - 1) as *mut _;
73 }
74
75 // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
76 // it appears to work fine without it, so we only use
77 // FindEnclosingFunction on non-osx platforms. In doing so, we get a
78 // slightly more accurate stack trace in the process.
79 //
80 // This is often because panic involves the last instruction of a
81 // function being "call std::rt::begin_unwind", with no ret
82 // instructions after it. This means that the return instruction
83 // pointer points *outside* of the calling function, and by
84 // unwinding it we go back to the original function.
85 let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
86 ip
87 } else {
88 unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
89 };
90
b7449926
XL
91 cx.frames[cx.idx] = Frame {
92 symbol_addr: symaddr as *mut u8,
93 exact_position: ip as *mut u8,
94 inline_context: 0,
95 };
96 cx.idx += 1;
3b2f2976
XL
97
98 uw::_URC_NO_REASON
99}