Load backtrace-related functions only once
.. and pass them around in BacktraceContext.
This commit is contained in:
@@ -47,6 +47,7 @@ mod printing;
|
|||||||
pub mod gnu;
|
pub mod gnu;
|
||||||
|
|
||||||
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
|
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)> {
|
pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
|
||||||
let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
|
let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
|
||||||
@@ -55,21 +56,23 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
|
|||||||
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
|
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
|
||||||
let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
|
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
|
// StackWalkEx might not be present and we'll fall back to StackWalk64
|
||||||
let (StackWalkFn, variant) =
|
let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) {
|
||||||
sym!(dbghelp, "StackWalkEx", StackWalkExFn)
|
Ok(StackWalkEx) =>
|
||||||
.map(|f| (sw_fn_local::SWExFn(f), StackWalkVariant::StackWalkEx))
|
StackWalkVariant::StackWalkEx(
|
||||||
.or_else(|_|
|
StackWalkEx,
|
||||||
sym!(dbghelp, "StackWalk64", StackWalk64Fn)
|
load_printing_fns_ex(&dbghelp)?,
|
||||||
.map(|f| (sw_fn_local::SW64Fn(f), StackWalkVariant::StackWalk64))
|
),
|
||||||
)?;
|
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
|
// Allocate necessary structures for doing the stack walk
|
||||||
let process = unsafe { c::GetCurrentProcess() };
|
let process = unsafe { c::GetCurrentProcess() };
|
||||||
@@ -77,7 +80,7 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
|
|||||||
let backtrace_context = BacktraceContext {
|
let backtrace_context = BacktraceContext {
|
||||||
handle: process,
|
handle: process,
|
||||||
SymCleanup,
|
SymCleanup,
|
||||||
StackWalkVariant: variant,
|
StackWalkVariant: sw_var,
|
||||||
dbghelp,
|
dbghelp,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,9 +91,9 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
// And now that we're done with all the setup, do the stack walking!
|
// And now that we're done with all the setup, do the stack walking!
|
||||||
match StackWalkFn {
|
match backtrace_context.StackWalkVariant {
|
||||||
sw_fn_local::SWExFn(f) => set_frames_ex(f, frames, backtrace_context, process),
|
StackWalkVariant::StackWalkEx(f, _) => set_frames_ex(f, frames, backtrace_context, process),
|
||||||
sw_fn_local::SW64Fn(f) => set_frames_64(f, frames, backtrace_context, process),
|
StackWalkVariant::StackWalk64(f, _) => set_frames_64(f, frames, backtrace_context, process),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,8 +262,8 @@ fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum StackWalkVariant {
|
enum StackWalkVariant {
|
||||||
StackWalkEx,
|
StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
|
||||||
StackWalk64,
|
StackWalk64(StackWalk64Fn, printing::PrintingFns64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -268,8 +271,10 @@ pub struct BacktraceContext {
|
|||||||
handle: c::HANDLE,
|
handle: c::HANDLE,
|
||||||
SymCleanup: SymCleanupFn,
|
SymCleanup: SymCleanupFn,
|
||||||
// Only used in printing for msvc and not gnu
|
// Only used in printing for msvc and not gnu
|
||||||
|
// The gnu version is effectively a ZST dummy.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
StackWalkVariant: StackWalkVariant,
|
StackWalkVariant: StackWalkVariant,
|
||||||
|
// keeping DynamycLibrary loaded until its functions no longer needed
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
dbghelp: DynamicLibrary,
|
dbghelp: DynamicLibrary,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,20 @@ mod printing;
|
|||||||
#[cfg(target_env = "gnu")]
|
#[cfg(target_env = "gnu")]
|
||||||
mod printing {
|
mod printing {
|
||||||
pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
|
pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
|
||||||
|
|
||||||
|
// dummy functions to mirror those present in msvc version.
|
||||||
|
use sys::dynamic_lib::DynamicLibrary;
|
||||||
|
use io;
|
||||||
|
pub struct PrintingFnsEx {}
|
||||||
|
pub struct PrintingFns64 {}
|
||||||
|
pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
|
||||||
|
Ok(PrintingFnsEx{})
|
||||||
|
}
|
||||||
|
pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result<PrintingFns64> {
|
||||||
|
Ok(PrintingFns64{})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
|
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
|
||||||
|
pub use self::printing::{load_printing_fns_ex, load_printing_fns_64,
|
||||||
|
PrintingFnsEx, PrintingFns64};
|
||||||
|
|||||||
@@ -15,8 +15,38 @@ use mem;
|
|||||||
use sys::backtrace::BacktraceContext;
|
use sys::backtrace::BacktraceContext;
|
||||||
use sys::backtrace::StackWalkVariant;
|
use sys::backtrace::StackWalkVariant;
|
||||||
use sys::c;
|
use sys::c;
|
||||||
|
use sys::dynamic_lib::DynamicLibrary;
|
||||||
use sys_common::backtrace::Frame;
|
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 =
|
type SymFromInlineContextFn =
|
||||||
unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
|
unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
|
||||||
type SymGetLineFromInlineContextFn = unsafe extern "system" fn(
|
type SymGetLineFromInlineContextFn = unsafe extern "system" fn(
|
||||||
@@ -39,14 +69,11 @@ where
|
|||||||
F: FnOnce(Option<&str>) -> io::Result<()>,
|
F: FnOnce(Option<&str>) -> io::Result<()>,
|
||||||
{
|
{
|
||||||
match context.StackWalkVariant {
|
match context.StackWalkVariant {
|
||||||
StackWalkVariant::StackWalkEx => {
|
StackWalkVariant::StackWalkEx(_, ref fns) => {
|
||||||
let SymFromInlineContext =
|
resolve_symname_from_inline_context(fns.resolve_symname, frame, callback, context)
|
||||||
sym!(&context.dbghelp, "SymFromInlineContext",SymFromInlineContextFn)?;
|
|
||||||
resolve_symname_from_inline_context(SymFromInlineContext, frame, callback, context)
|
|
||||||
},
|
},
|
||||||
StackWalkVariant::StackWalk64 => {
|
StackWalkVariant::StackWalk64(_, ref fns) => {
|
||||||
let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
|
resolve_symname_from_addr(fns.resolve_symname, frame, callback, context)
|
||||||
resolve_symname_from_addr(SymFromAddr, frame, callback, context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,20 +161,10 @@ where
|
|||||||
F: FnMut(&[u8], u32) -> io::Result<()>,
|
F: FnMut(&[u8], u32) -> io::Result<()>,
|
||||||
{
|
{
|
||||||
match context.StackWalkVariant {
|
match context.StackWalkVariant {
|
||||||
StackWalkVariant::StackWalkEx => {
|
StackWalkVariant::StackWalkEx(_, ref fns) =>
|
||||||
let SymGetLineFromInlineContext =
|
foreach_symbol_fileline_ex(fns.sym_get_line, frame, f, context),
|
||||||
sym!(&context.dbghelp, "SymGetLineFromInlineContext",
|
StackWalkVariant::StackWalk64(_, ref fns) =>
|
||||||
SymGetLineFromInlineContextFn)?;
|
foreach_symbol_fileline_64(fns.sym_get_line, frame, f, context),
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user