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
use ffi::CStr;
use io;
use libc::{c_ulong, c_char};
use mem;
use sys::c;
use sys::backtrace::BacktraceContext;
use sys_common::backtrace::Frame;
type SymFromInlineContextFn =
unsafe extern "system" fn(c::HANDLE, u64, c::ULONG,
*mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
type SymGetLineFromInlineContextFn =
unsafe extern "system" fn(c::HANDLE, u64, c::ULONG,
u64, *mut c::DWORD, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
pub fn resolve_symname<F>(frame: Frame,
callback: F,
context: &BacktraceContext) -> io::Result<()>
where F: FnOnce(Option<&str>) -> io::Result<()>
{
let SymFromInlineContext = sym!(&context.dbghelp,
"SymFromInlineContext",
SymFromInlineContextFn)?;
unsafe {
let mut info: c::SYMBOL_INFO = mem::zeroed();
info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
info.SizeOfStruct = 88;
let mut displacement = 0u64;
let ret = SymFromInlineContext(context.handle,
frame.symbol_addr as u64,
frame.inline_context,
&mut displacement,
&mut info);
let valid_range = if ret == c::TRUE &&
frame.symbol_addr as usize >= info.Address as usize {
if info.Size != 0 {
(frame.symbol_addr as usize) < info.Address as usize + info.Size as usize
} else {
true
}
} else {
false
};
let symname = if valid_range {
let ptr = info.Name.as_ptr() as *const c_char;
CStr::from_ptr(ptr).to_str().ok()
} else {
None
};
callback(symname)
}
}
pub fn foreach_symbol_fileline<F>(frame: Frame,
mut f: F,
context: &BacktraceContext)
-> io::Result<bool>
where F: FnMut(&[u8], u32) -> io::Result<()>
{
let SymGetLineFromInlineContext = sym!(&context.dbghelp,
"SymGetLineFromInlineContext",
SymGetLineFromInlineContextFn)?;
unsafe {
let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
let mut displacement = 0u32;
let ret = SymGetLineFromInlineContext(context.handle,
frame.exact_position as u64,
frame.inline_context,
0,
&mut displacement,
&mut line);
if ret == c::TRUE {
let name = CStr::from_ptr(line.Filename).to_bytes();
f(name, line.LineNumber as u32)?;
}
Ok(false)
}
}