-
Notifications
You must be signed in to change notification settings - Fork 26
/
backtrace.rs
117 lines (99 loc) · 3.33 KB
/
backtrace.rs
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
110
111
112
113
114
115
116
117
#![allow(clippy::let_unit_value)]
use std::cmp::min;
use std::mem::size_of;
use std::mem::transmute;
use std::ptr;
use blazesym::symbolize::CodeInfo;
use blazesym::symbolize::Input;
use blazesym::symbolize::Process;
use blazesym::symbolize::Source;
use blazesym::symbolize::Sym;
use blazesym::symbolize::Symbolized;
use blazesym::symbolize::Symbolizer;
use blazesym::Addr;
use blazesym::Pid;
const ADDR_WIDTH: usize = 16;
fn print_frame(name: &str, addr_info: Option<(Addr, Addr, usize)>, code_info: &Option<CodeInfo>) {
let code_info = code_info.as_ref().map(|code_info| {
let path = code_info.to_path();
let path = path.display();
match (code_info.line, code_info.column) {
(Some(line), Some(col)) => format!(" {path}:{line}:{col}"),
(Some(line), None) => format!(" {path}:{line}"),
(None, _) => format!(" {path}"),
}
});
if let Some((input_addr, addr, offset)) = addr_info {
// If we have various address information bits we have a new symbol.
println!(
"{input_addr:#0width$x}: {name} @ {addr:#x}+{offset:#x}{code_info}",
code_info = code_info.as_deref().unwrap_or(""),
width = ADDR_WIDTH
)
} else {
// Otherwise we are dealing with an inlined call.
println!(
"{:width$} {name}{code_info} [inlined]",
" ",
code_info = code_info
.map(|info| format!(" @{info}"))
.as_deref()
.unwrap_or(""),
width = ADDR_WIDTH
)
}
}
fn symbolize_current_bt() {
assert_eq!(size_of::<*mut libc::c_void>(), size_of::<Addr>());
// Retrieve up to 64 stack frames of the calling thread.
const MAX_CNT: usize = 64;
let mut bt_buf = [ptr::null_mut::<libc::c_void>(); MAX_CNT];
let bt_cnt = unsafe { libc::backtrace(bt_buf.as_mut_ptr(), MAX_CNT as _) } as usize;
let bt = &mut bt_buf[0..min(bt_cnt, MAX_CNT)];
let bt = unsafe { transmute::<&mut [*mut libc::c_void], &mut [Addr]>(bt) };
// For all but the top most address in the call stack, adjust for
// the fact that we captured the address we will return to, but not
// the one we called from.
let () = bt.iter_mut().skip(1).for_each(|addr| *addr -= 1);
// Symbolize the addresses for the current process, as that's where
// they were captured.
let src = Source::Process(Process::new(Pid::Slf));
let symbolizer = Symbolizer::new();
let syms = symbolizer.symbolize(&src, Input::AbsAddr(bt)).unwrap();
let addrs = bt;
for (input_addr, sym) in addrs.iter().copied().zip(syms) {
match sym {
Symbolized::Sym(Sym {
name,
addr,
offset,
code_info,
inlined,
..
}) => {
print_frame(&name, Some((input_addr, addr, offset)), &code_info);
for frame in inlined.iter() {
print_frame(&frame.name, None, &frame.code_info);
}
}
Symbolized::Unknown(..) => {
println!("{input_addr:#0width$x}: <no-symbol>", width = ADDR_WIDTH)
}
}
}
}
#[inline(never)]
fn f() {
g()
}
#[inline(always)]
fn g() {
h()
}
#[inline(never)]
fn h() {
symbolize_current_bt()
}
fn main() {
f();
}