1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use io;
use io::prelude::*;
use libc;
use mem;
use sys_common::mutex::Mutex;
use super::super::printing::print;
use unwind as uw;
#[inline(never)]
pub fn write(w: &mut Write) -> io::Result<()> {
struct Context<'a> {
idx: isize,
writer: &'a mut (Write+'a),
last_error: Option<io::Error>,
}
static LOCK: Mutex = Mutex::new();
unsafe {
LOCK.lock();
writeln!(w, "stack backtrace:")?;
let mut cx = Context { writer: w, last_error: None, idx: 0 };
let ret = match {
uw::_Unwind_Backtrace(trace_fn,
&mut cx as *mut Context as *mut libc::c_void)
} {
uw::_URC_NO_REASON => {
match cx.last_error {
Some(err) => Err(err),
None => Ok(())
}
}
_ => Ok(()),
};
LOCK.unlock();
return ret
}
extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
let cx: &mut Context = unsafe { mem::transmute(arg) };
let mut ip_before_insn = 0;
let mut ip = unsafe {
uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
};
if !ip.is_null() && ip_before_insn == 0 {
ip = (ip as usize - 1) as *mut _;
}
let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
ip
} else {
unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
};
cx.idx += 1;
if cx.idx <= 0 { return uw::_URC_NO_REASON }
if cx.idx > 100 {
match write!(cx.writer, " ... <frames omitted>\n") {
Ok(()) => {}
Err(e) => { cx.last_error = Some(e); }
}
return uw::_URC_FAILURE
}
if cx.last_error.is_some() { return uw::_URC_FAILURE }
match print(cx.writer, cx.idx, ip, symaddr) {
Ok(()) => {}
Err(e) => { cx.last_error = Some(e); }
}
uw::_URC_NO_REASON
}
}