1 // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
14 use sys
::backtrace
::BacktraceContext
;
15 use sys_common
::backtrace
::Frame
;
21 frames
: &'a
mut [Frame
],
25 struct UnwindError(uw
::_Unwind_Reason_Code
);
27 impl Error
for UnwindError
{
28 fn description(&self) -> &'
static str {
29 "unexpected return value while unwinding"
33 impl ::fmt
::Display
for UnwindError
{
34 fn fmt(&self, f
: &mut ::fmt
::Formatter
) -> ::fmt
::Result
{
35 write
!(f
, "{}: {:?}", self.description(), self.0)
39 #[inline(never)] // if we know this is a function call, we can skip it when
41 pub fn unwind_backtrace(frames
: &mut [Frame
])
42 -> io
::Result
<(usize, BacktraceContext
)>
44 let mut cx
= Context
{
48 let result_unwind
= unsafe {
49 uw
::_Unwind_Backtrace(trace_fn
,
50 &mut cx
as *mut Context
53 // See libunwind:src/unwind/Backtrace.c for the return values.
54 // No, there is no doc.
56 // These return codes seem to be benign and need to be ignored for backtraces
57 // to show up properly on all tested platforms.
58 uw
::_URC_END_OF_STACK
| uw
::_URC_FATAL_PHASE1_ERROR
| uw
::_URC_FAILURE
=> {
59 Ok((cx
.idx
, BacktraceContext
))
62 Err(io
::Error
::new(io
::ErrorKind
::Other
,
63 UnwindError(result_unwind
)))
68 extern fn trace_fn(ctx
: *mut uw
::_Unwind_Context
,
69 arg
: *mut libc
::c_void
) -> uw
::_Unwind_Reason_Code
{
70 let cx
= unsafe { &mut *(arg as *mut Context) }
;
71 let mut ip_before_insn
= 0;
73 uw
::_Unwind_GetIPInfo(ctx
, &mut ip_before_insn
) as *mut libc
::c_void
75 if !ip
.is_null() && ip_before_insn
== 0 {
76 // this is a non-signaling frame, so `ip` refers to the address
77 // after the calling instruction. account for that.
78 ip
= (ip
as usize - 1) as *mut _
;
81 // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
82 // it appears to work fine without it, so we only use
83 // FindEnclosingFunction on non-osx platforms. In doing so, we get a
84 // slightly more accurate stack trace in the process.
86 // This is often because panic involves the last instruction of a
87 // function being "call std::rt::begin_unwind", with no ret
88 // instructions after it. This means that the return instruction
89 // pointer points *outside* of the calling function, and by
90 // unwinding it we go back to the original function.
91 let symaddr
= if cfg
!(target_os
= "macos") || cfg
!(target_os
= "ios") {
94 unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
97 if cx
.idx
< cx
.frames
.len() {
98 cx
.frames
[cx
.idx
] = Frame
{
99 symbol_addr
: symaddr
as *mut u8,
100 exact_position
: ip
as *mut u8,