pub mod gnu;
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+use self::printing::{load_printing_fns_ex, load_printing_fns_64};
pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
- // enum for holding the StackWalk function. Different from StackWalkVariant
- // below, since there's no need to pass the function itself into
- // the BacktraceContext
- enum sw_fn_local {
- SWExFn(StackWalkExFn),
- SW64Fn(StackWalk64Fn),
- }
+
// StackWalkEx might not be present and we'll fall back to StackWalk64
- let (StackWalkFn, variant) =
- sym!(dbghelp, "StackWalkEx", StackWalkExFn)
- .map(|f| (sw_fn_local::SWExFn(f), StackWalkVariant::StackWalkEx))
- .or_else(|_|
- sym!(dbghelp, "StackWalk64", StackWalk64Fn)
- .map(|f| (sw_fn_local::SW64Fn(f), StackWalkVariant::StackWalk64))
- )?;
+ let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) {
+ Ok(StackWalkEx) =>
+ StackWalkVariant::StackWalkEx(
+ StackWalkEx,
+ load_printing_fns_ex(&dbghelp)?,
+ ),
+ Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) {
+ Ok(StackWalk64) =>
+ StackWalkVariant::StackWalk64(
+ StackWalk64,
+ load_printing_fns_64(&dbghelp)?,
+ ),
+ Err(..) => return Err(e),
+ },
+ };
// Allocate necessary structures for doing the stack walk
let process = unsafe { c::GetCurrentProcess() };
let backtrace_context = BacktraceContext {
handle: process,
SymCleanup,
- StackWalkVariant: variant,
+ StackWalkVariant: sw_var,
dbghelp,
};
}
// And now that we're done with all the setup, do the stack walking!
- match StackWalkFn {
- sw_fn_local::SWExFn(f) => set_frames_ex(f, frames, backtrace_context, process),
- sw_fn_local::SW64Fn(f) => set_frames_64(f, frames, backtrace_context, process),
+ match backtrace_context.StackWalkVariant {
+ StackWalkVariant::StackWalkEx(f, _) => set_frames_ex(f, frames, backtrace_context, process),
+ StackWalkVariant::StackWalk64(f, _) => set_frames_64(f, frames, backtrace_context, process),
}
}
}
enum StackWalkVariant {
- StackWalkEx,
- StackWalk64,
+ StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
+ StackWalk64(StackWalk64Fn, printing::PrintingFns64),
}
handle: c::HANDLE,
SymCleanup: SymCleanupFn,
// Only used in printing for msvc and not gnu
+ // The gnu version is effectively a ZST dummy.
#[allow(dead_code)]
StackWalkVariant: StackWalkVariant,
+ // keeping DynamycLibrary loaded until its functions no longer needed
#[allow(dead_code)]
dbghelp: DynamicLibrary,
}
use sys::backtrace::BacktraceContext;
use sys::backtrace::StackWalkVariant;
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)
+pub struct PrintingFnsEx {
+ resolve_symname: SymFromInlineContextFn,
+ sym_get_line: SymGetLineFromInlineContextFn,
+}
+pub struct PrintingFns64 {
+ resolve_symname: SymFromAddrFn,
+ sym_get_line: SymGetLineFromAddr64Fn,
+}
+
+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)?,
+ })
+}
+pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result<PrintingFns64> {
+ Ok(PrintingFns64{
+ resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?,
+ sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64",
+ SymGetLineFromAddr64Fn)?,
+ })
+}
+
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(
F: FnOnce(Option<&str>) -> io::Result<()>,
{
match context.StackWalkVariant {
- StackWalkVariant::StackWalkEx => {
- let SymFromInlineContext =
- sym!(&context.dbghelp, "SymFromInlineContext",SymFromInlineContextFn)?;
- resolve_symname_from_inline_context(SymFromInlineContext, frame, callback, context)
+ StackWalkVariant::StackWalkEx(_, ref fns) => {
+ resolve_symname_from_inline_context(fns.resolve_symname, frame, callback, context)
},
- StackWalkVariant::StackWalk64 => {
- let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
- resolve_symname_from_addr(SymFromAddr, frame, callback, context)
+ StackWalkVariant::StackWalk64(_, ref fns) => {
+ resolve_symname_from_addr(fns.resolve_symname, frame, callback, context)
}
}
}
F: FnMut(&[u8], u32) -> io::Result<()>,
{
match context.StackWalkVariant {
- StackWalkVariant::StackWalkEx => {
- let SymGetLineFromInlineContext =
- sym!(&context.dbghelp, "SymGetLineFromInlineContext",
- SymGetLineFromInlineContextFn)?;
- foreach_symbol_fileline_ex(SymGetLineFromInlineContext,
- frame, f, context)
- },
- StackWalkVariant::StackWalk64 => {
- let SymGetLineFromAddr64 =
- sym!(&context.dbghelp, "SymGetLineFromAddr64",
- SymGetLineFromAddr64Fn)?;
- foreach_symbol_fileline_64(SymGetLineFromAddr64,
- frame, f, context)
- }
+ 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),
}
}