-
Notifications
You must be signed in to change notification settings - Fork 29
/
symbolication.rs
executable file
·173 lines (154 loc) · 5.62 KB
/
symbolication.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
use winapi::um::winnt::{HANDLE, WCHAR};
use winapi::um::errhandlingapi::GetLastError;
use winapi::shared::minwindef::{TRUE, BOOL, DWORD, MAX_PATH};
use winapi::shared::guiddef::GUID;
use winapi::shared::basetsd::DWORD64;
use winapi::um::dbghelp::{SymInitializeW, SymCleanup,
SymFromAddrW, SymGetLineFromAddrW64, MAX_SYM_NAME, SYMBOL_INFOW, IMAGEHLP_LINEW64};
use std::os::windows::ffi::{OsStringExt};
use super::super::Error;
use super::super::StackFrame;
use libc::wcslen;
pub struct Symbolicator {
pub handle: HANDLE
}
impl Symbolicator {
pub fn new(handle: HANDLE) -> Result<Symbolicator, Error> {
unsafe {
if SymInitializeW(handle, std::ptr::null_mut(), TRUE) == 0 {
return Err(Error::from(std::io::Error::last_os_error()));
};
Ok(Symbolicator{handle})
}
}
pub fn reload(&mut self) -> Result<(), Error> {
info!("reloading symbol module list");
unsafe { SymRefreshModuleList(self.handle); }
Ok(())
}
pub fn symbolicate(&self, addr: u64, line_info: bool, callback: &mut dyn FnMut(&StackFrame)) -> Result<(), Error> {
let function = unsafe { self.symbol_function(addr) };
let module = match unsafe { self.symbol_module (addr) } {
Ok(module) => module,
Err(Error::NoBinaryForAddress(_)) => {
unsafe {
SymRefreshModuleList(self.handle);
self.symbol_module(addr).unwrap_or_else(|_| "?".to_owned())
}
},
Err(_) => "?".to_owned()
};
let mut line = None;
let mut filename = None;
if line_info {
if let Some((f, l)) = unsafe { self.symbol_filename(addr) } {
line = Some(l);
filename = Some(f);
}
}
callback(&StackFrame{function, filename, line, module, addr});
Ok(())
}
// returns the corresponding function name for an address
pub unsafe fn symbol_function(&self, addr: u64) -> Option<String> {
let mut buffer = std::mem::zeroed::<SymbolBuffer>();
let symbol_info = &mut *(buffer.buffer.as_mut_ptr() as *mut SYMBOL_INFOW);
symbol_info.MaxNameLen = MAX_SYM_NAME as u32;
// there must be a way to get this
symbol_info.SizeOfStruct = 88;
let mut displacement = 0;
let ret = SymFromAddrW(self.handle, addr, &mut displacement, symbol_info);
if ret != TRUE {
return None;
}
let length = std::cmp::min(symbol_info.NameLen as usize, symbol_info.MaxNameLen as usize - 1);
let symbol = std::slice::from_raw_parts(symbol_info.Name.as_ptr() as *const u16, length);
let symbol = std::ffi::OsString::from_wide(symbol);
Some(symbol.to_string_lossy().to_owned().to_string())
}
// get the corresponding filename/linke
pub unsafe fn symbol_filename(&self, addr: u64) -> Option<(String, u64)> {
let mut displacement = 0;
let mut info = std::mem::zeroed::<IMAGEHLP_LINEW64>();
info.SizeOfStruct = std::mem::size_of_val(&info) as u32;
if SymGetLineFromAddrW64(self.handle, addr, &mut displacement, &mut info) != TRUE {
return None;
}
let filename = std::slice::from_raw_parts(info.FileName, wcslen(info.FileName));
let filename = std::ffi::OsString::from_wide(filename);
Some((filename.to_string_lossy().to_owned().to_string(), info.LineNumber.into()))
}
// get the corresponding module name
pub unsafe fn symbol_module(&self, addr: u64) -> Result<String, Error> {
let mut info = std::mem::zeroed::<IMAGEHLP_MODULEW64>();
info.SizeOfStruct = std::mem::size_of_val(&info) as u32;
if SymGetModuleInfoW64(self.handle, addr, &mut info) != TRUE {
if GetLastError() == 126 {
return Err(Error::NoBinaryForAddress(addr));
}
return Err(Error::IOError(std::io::Error::last_os_error()));
}
let filename = info.LoadedImageName.as_ptr();
let filename = std::slice::from_raw_parts(filename, wcslen(filename));
let filename = std::ffi::OsString::from_wide(filename);
Ok(filename.to_string_lossy().to_owned().to_string())
}
}
impl Drop for Symbolicator {
fn drop(&mut self) {
unsafe { SymCleanup(self.handle); }
}
}
#[repr(C, align(8))]
struct SymbolBuffer {
buffer: [u8; std::mem::size_of::<SYMBOL_INFOW>() + MAX_SYM_NAME * 2]
}
// missing from winapi-rs =(
#[allow(dead_code)]
#[repr(C)]
pub enum SYM_TYPE {
SymNone,
SymCoff,
SymCv,
SymPdb,
SymExport,
SymDeferred,
SymSym,
SymDia,
SymVirtual,
NumSymTypes,
}
#[allow(non_snake_case)]
#[repr(C)]
pub struct IMAGEHLP_MODULEW64 {
pub SizeOfStruct: DWORD,
pub BaseOfImage: DWORD64,
pub ImageSize: DWORD,
pub TimeDateStamp: DWORD,
pub CheckSum: DWORD,
pub NumSyms: DWORD,
pub SymType: SYM_TYPE,
pub ModuleName: [WCHAR; 32],
pub ImageName: [WCHAR; 256],
pub LoadedImageName: [WCHAR; 256],
pub LoadedPdbName: [WCHAR; 256],
pub CVSig: DWORD,
pub CVData: [WCHAR; MAX_PATH * 3],
pub PdbSig: DWORD,
pub PdbSig70: GUID,
pub PdbAge: DWORD,
pub PdbUnmatched: BOOL,
pub DbgUnmatched: BOOL,
pub LineNumbers: BOOL,
pub GlobalSymbols: BOOL,
pub TypeInfo: BOOL,
pub SourceIndexed: BOOL,
pub Publics: BOOL,
pub MachineType: DWORD,
pub Reserved: DWORD,
}
#[link(name="dbghelp")]
extern "system" {
fn SymGetModuleInfoW64(process: HANDLE, addr: u64, info: *mut IMAGEHLP_MODULEW64) -> BOOL;
fn SymRefreshModuleList(process: HANDLE) -> BOOL;
}