Skip to content

Commit

Permalink
Make msvc symbol extraction/printing functions generic.
Browse files Browse the repository at this point in the history
  • Loading branch information
moxian committed Jun 28, 2018
1 parent a0b1501 commit 9d426ac
Showing 1 changed file with 137 additions and 103 deletions.
240 changes: 137 additions & 103 deletions src/libstd/sys/windows/backtrace/printing/msvc.rs
Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -58,73 +63,30 @@ 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
F: FnOnce(Option<&str>) -> io::Result<()>,
{
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();
Expand All @@ -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 {
Expand All @@ -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)
}
}

0 comments on commit 9d426ac

Please sign in to comment.