Make msvc symbol extraction/printing functions generic.
This commit is contained in:
parent
a0b15012a1
commit
9d426ac387
1 changed files with 137 additions and 103 deletions
|
|
@ -18,7 +18,6 @@ use sys::c;
|
|||
use sys::dynamic_lib::DynamicLibrary;
|
||||
use sys_common::backtrace::Frame;
|
||||
|
||||
|
||||
// Structs holding printing functions and loaders for them
|
||||
// Two versions depending on whether dbghelp.dll has StackWalkEx or not
|
||||
// (the former being in newer Windows versions, the older being in Win7 and before)
|
||||
|
|
@ -32,23 +31,29 @@ pub struct PrintingFns64 {
|
|||
}
|
||||
|
||||
pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
|
||||
Ok(PrintingFnsEx{
|
||||
resolve_symname: sym!(dbghelp, "SymFromInlineContext",
|
||||
SymFromInlineContextFn)?,
|
||||
sym_get_line: sym!(dbghelp, "SymGetLineFromInlineContext",
|
||||
SymGetLineFromInlineContextFn)?,
|
||||
Ok(PrintingFnsEx {
|
||||
resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?,
|
||||
sym_get_line: sym!(
|
||||
dbghelp,
|
||||
"SymGetLineFromInlineContext",
|
||||
SymGetLineFromInlineContextFn
|
||||
)?,
|
||||
})
|
||||
}
|
||||
pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result<PrintingFns64> {
|
||||
Ok(PrintingFns64{
|
||||
Ok(PrintingFns64 {
|
||||
resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?,
|
||||
sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64",
|
||||
SymGetLineFromAddr64Fn)?,
|
||||
sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?,
|
||||
})
|
||||
}
|
||||
|
||||
type SymFromAddrFn =
|
||||
unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
|
||||
type SymFromInlineContextFn =
|
||||
unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
|
||||
|
||||
type SymGetLineFromAddr64Fn =
|
||||
unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
|
||||
type SymGetLineFromInlineContextFn = unsafe extern "system" fn(
|
||||
c::HANDLE,
|
||||
u64,
|
||||
|
|
@ -58,11 +63,6 @@ type SymGetLineFromInlineContextFn = unsafe extern "system" fn(
|
|||
*mut c::IMAGEHLP_LINE64,
|
||||
) -> c::BOOL;
|
||||
|
||||
type SymFromAddrFn =
|
||||
unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
|
||||
type SymGetLineFromAddr64Fn =
|
||||
unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
|
||||
|
||||
/// Converts a pointer to symbol to its string value.
|
||||
pub fn resolve_symname<F>(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()>
|
||||
where
|
||||
|
|
@ -70,61 +70,23 @@ where
|
|||
{
|
||||
match context.StackWalkVariant {
|
||||
StackWalkVariant::StackWalkEx(_, ref fns) => {
|
||||
resolve_symname_from_inline_context(fns.resolve_symname, frame, callback, context)
|
||||
},
|
||||
resolve_symname_internal(fns.resolve_symname, frame, callback, context)
|
||||
}
|
||||
StackWalkVariant::StackWalk64(_, ref fns) => {
|
||||
resolve_symname_from_addr(fns.resolve_symname, frame, callback, context)
|
||||
resolve_symname_internal(fns.resolve_symname, frame, callback, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_symname_from_inline_context<F>(
|
||||
SymFromInlineContext: SymFromInlineContextFn,
|
||||
frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()>
|
||||
where
|
||||
F: FnOnce(Option<&str>) -> io::Result<()>,
|
||||
{
|
||||
unsafe {
|
||||
let mut info: c::SYMBOL_INFO = mem::zeroed();
|
||||
info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
|
||||
// the struct size in C. the value is different to
|
||||
// `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
|
||||
// due to struct alignment.
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_symname_from_addr<F>(
|
||||
SymFromAddr: SymFromAddrFn,
|
||||
frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()>
|
||||
fn resolve_symname_internal<F, R>(
|
||||
symbol_resolver: R,
|
||||
frame: Frame,
|
||||
callback: F,
|
||||
context: &BacktraceContext,
|
||||
) -> io::Result<()>
|
||||
where
|
||||
F: FnOnce(Option<&str>) -> io::Result<()>,
|
||||
R: SymbolResolver,
|
||||
{
|
||||
unsafe {
|
||||
let mut info: c::SYMBOL_INFO = mem::zeroed();
|
||||
|
|
@ -134,15 +96,22 @@ where
|
|||
// due to struct alignment.
|
||||
info.SizeOfStruct = 88;
|
||||
|
||||
let mut displacement = 0u64;
|
||||
let ret = SymFromAddr(
|
||||
let ret = symbol_resolver.resolve_symbol(
|
||||
context.handle,
|
||||
frame.symbol_addr as u64,
|
||||
&mut displacement,
|
||||
frame.inline_context,
|
||||
&mut info,
|
||||
);
|
||||
|
||||
let symname = if ret == c::TRUE {
|
||||
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 {
|
||||
|
|
@ -152,76 +121,141 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
trait SymbolResolver {
|
||||
fn resolve_symbol(
|
||||
&self,
|
||||
process: c::HANDLE,
|
||||
symbol_address: u64,
|
||||
inline_context: c::ULONG,
|
||||
info: *mut c::SYMBOL_INFO,
|
||||
) -> c::BOOL;
|
||||
}
|
||||
|
||||
impl SymbolResolver for SymFromAddrFn {
|
||||
fn resolve_symbol(
|
||||
&self,
|
||||
process: c::HANDLE,
|
||||
symbol_address: u64,
|
||||
_inline_context: c::ULONG,
|
||||
info: *mut c::SYMBOL_INFO,
|
||||
) -> c::BOOL {
|
||||
unsafe {
|
||||
let mut displacement = 0u64;
|
||||
self(process, symbol_address, &mut displacement, info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SymbolResolver for SymFromInlineContextFn {
|
||||
fn resolve_symbol(
|
||||
&self,
|
||||
process: c::HANDLE,
|
||||
symbol_address: u64,
|
||||
inline_context: c::ULONG,
|
||||
info: *mut c::SYMBOL_INFO,
|
||||
) -> c::BOOL {
|
||||
unsafe {
|
||||
let mut displacement = 0u64;
|
||||
self(
|
||||
process,
|
||||
symbol_address,
|
||||
inline_context,
|
||||
&mut displacement,
|
||||
info,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn foreach_symbol_fileline<F>(
|
||||
frame: Frame,
|
||||
f: F,
|
||||
callback: F,
|
||||
context: &BacktraceContext,
|
||||
) -> io::Result<bool>
|
||||
where
|
||||
F: FnMut(&[u8], u32) -> io::Result<()>,
|
||||
{
|
||||
match context.StackWalkVariant {
|
||||
StackWalkVariant::StackWalkEx(_, ref fns) =>
|
||||
foreach_symbol_fileline_ex(fns.sym_get_line, frame, f, context),
|
||||
StackWalkVariant::StackWalk64(_, ref fns) =>
|
||||
foreach_symbol_fileline_64(fns.sym_get_line, frame, f, context),
|
||||
StackWalkVariant::StackWalkEx(_, ref fns) => {
|
||||
foreach_symbol_fileline_iternal(fns.sym_get_line, frame, callback, context)
|
||||
}
|
||||
StackWalkVariant::StackWalk64(_, ref fns) => {
|
||||
foreach_symbol_fileline_iternal(fns.sym_get_line, frame, callback, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn foreach_symbol_fileline_ex<F>(
|
||||
SymGetLineFromInlineContext: SymGetLineFromInlineContextFn,
|
||||
fn foreach_symbol_fileline_iternal<F, G>(
|
||||
line_getter: G,
|
||||
frame: Frame,
|
||||
mut f: F,
|
||||
mut callback: F,
|
||||
context: &BacktraceContext,
|
||||
) -> io::Result<bool>
|
||||
where
|
||||
F: FnMut(&[u8], u32) -> io::Result<()>,
|
||||
G: LineGetter,
|
||||
{
|
||||
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(
|
||||
let ret = line_getter.get_line(
|
||||
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)?;
|
||||
callback(name, line.LineNumber as u32)?;
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn foreach_symbol_fileline_64<F>(
|
||||
SymGetLineFromAddr64: SymGetLineFromAddr64Fn,
|
||||
frame: Frame,
|
||||
mut f: F,
|
||||
context: &BacktraceContext,
|
||||
) -> io::Result<bool>
|
||||
where
|
||||
F: FnMut(&[u8], u32) -> io::Result<()>,
|
||||
{
|
||||
unsafe {
|
||||
let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
|
||||
line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
|
||||
trait LineGetter {
|
||||
fn get_line(
|
||||
&self,
|
||||
process: c::HANDLE,
|
||||
frame_address: u64,
|
||||
inline_context: c::ULONG,
|
||||
line: *mut c::IMAGEHLP_LINE64,
|
||||
) -> c::BOOL;
|
||||
}
|
||||
|
||||
let mut displacement = 0u32;
|
||||
let ret = SymGetLineFromAddr64(
|
||||
context.handle,
|
||||
frame.exact_position as u64,
|
||||
&mut displacement,
|
||||
&mut line,
|
||||
);
|
||||
if ret == c::TRUE {
|
||||
let name = CStr::from_ptr(line.Filename).to_bytes();
|
||||
f(name, line.LineNumber as u32)?;
|
||||
impl LineGetter for SymGetLineFromAddr64Fn {
|
||||
fn get_line(
|
||||
&self,
|
||||
process: c::HANDLE,
|
||||
frame_address: u64,
|
||||
_inline_context: c::ULONG,
|
||||
line: *mut c::IMAGEHLP_LINE64,
|
||||
) -> c::BOOL {
|
||||
unsafe {
|
||||
let mut displacement = 0u32;
|
||||
self(process, frame_address, &mut displacement, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LineGetter for SymGetLineFromInlineContextFn {
|
||||
fn get_line(
|
||||
&self,
|
||||
process: c::HANDLE,
|
||||
frame_address: u64,
|
||||
inline_context: c::ULONG,
|
||||
line: *mut c::IMAGEHLP_LINE64,
|
||||
) -> c::BOOL {
|
||||
unsafe {
|
||||
let mut displacement = 0u32;
|
||||
self(
|
||||
process,
|
||||
frame_address,
|
||||
inline_context,
|
||||
0,
|
||||
&mut displacement,
|
||||
line,
|
||||
)
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue