Skip to content

Commit c0b280f

Browse files
committed
Load backtrace-related functions only once
.. and pass them around in BacktraceContext.
1 parent 3245a47 commit c0b280f

File tree

3 files changed

+77
-41
lines changed

3 files changed

+77
-41
lines changed

Diff for: src/libstd/sys/windows/backtrace/mod.rs

+25-20
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ mod printing;
4747
pub mod gnu;
4848

4949
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
50+
use self::printing::{load_printing_fns_ex, load_printing_fns_64};
5051

5152
pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
5253
let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
@@ -55,29 +56,31 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
5556
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
5657
let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
5758

58-
// enum for holding the StackWalk function. Different from StackWalkVariant
59-
// below, since there's no need to pass the function itself into
60-
// the BacktraceContext
61-
enum sw_fn_local {
62-
SWExFn(StackWalkExFn),
63-
SW64Fn(StackWalk64Fn),
64-
}
59+
6560
// StackWalkEx might not be present and we'll fall back to StackWalk64
66-
let (StackWalkFn, variant) =
67-
sym!(dbghelp, "StackWalkEx", StackWalkExFn)
68-
.map(|f| (sw_fn_local::SWExFn(f), StackWalkVariant::StackWalkEx))
69-
.or_else(|_|
70-
sym!(dbghelp, "StackWalk64", StackWalk64Fn)
71-
.map(|f| (sw_fn_local::SW64Fn(f), StackWalkVariant::StackWalk64))
72-
)?;
61+
let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) {
62+
Ok(StackWalkEx) =>
63+
StackWalkVariant::StackWalkEx(
64+
StackWalkEx,
65+
load_printing_fns_ex(&dbghelp)?,
66+
),
67+
Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) {
68+
Ok(StackWalk64) =>
69+
StackWalkVariant::StackWalk64(
70+
StackWalk64,
71+
load_printing_fns_64(&dbghelp)?,
72+
),
73+
Err(..) => return Err(e),
74+
},
75+
};
7376

7477
// Allocate necessary structures for doing the stack walk
7578
let process = unsafe { c::GetCurrentProcess() };
7679

7780
let backtrace_context = BacktraceContext {
7881
handle: process,
7982
SymCleanup,
80-
StackWalkVariant: variant,
83+
StackWalkVariant: sw_var,
8184
dbghelp,
8285
};
8386

@@ -88,9 +91,9 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
8891
}
8992

9093
// And now that we're done with all the setup, do the stack walking!
91-
match StackWalkFn {
92-
sw_fn_local::SWExFn(f) => set_frames_ex(f, frames, backtrace_context, process),
93-
sw_fn_local::SW64Fn(f) => set_frames_64(f, frames, backtrace_context, process),
94+
match backtrace_context.StackWalkVariant {
95+
StackWalkVariant::StackWalkEx(f, _) => set_frames_ex(f, frames, backtrace_context, process),
96+
StackWalkVariant::StackWalk64(f, _) => set_frames_64(f, frames, backtrace_context, process),
9497
}
9598
}
9699

@@ -259,17 +262,19 @@ fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD {
259262
}
260263

261264
enum StackWalkVariant {
262-
StackWalkEx,
263-
StackWalk64,
265+
StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
266+
StackWalk64(StackWalk64Fn, printing::PrintingFns64),
264267
}
265268

266269

267270
pub struct BacktraceContext {
268271
handle: c::HANDLE,
269272
SymCleanup: SymCleanupFn,
270273
// Only used in printing for msvc and not gnu
274+
// The gnu version is effectively a ZST dummy.
271275
#[allow(dead_code)]
272276
StackWalkVariant: StackWalkVariant,
277+
// keeping DynamycLibrary loaded until its functions no longer needed
273278
#[allow(dead_code)]
274279
dbghelp: DynamicLibrary,
275280
}

Diff for: src/libstd/sys/windows/backtrace/printing/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ mod printing;
1515
#[cfg(target_env = "gnu")]
1616
mod printing {
1717
pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
18+
19+
// dummy functions to mirror those present in msvc version.
20+
use sys::dynamic_lib::DynamicLibrary;
21+
use io;
22+
pub struct PrintingFnsEx {}
23+
pub struct PrintingFns64 {}
24+
pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
25+
Ok(PrintingFnsEx{})
26+
}
27+
pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result<PrintingFns64> {
28+
Ok(PrintingFns64{})
29+
}
1830
}
1931

2032
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
33+
pub use self::printing::{load_printing_fns_ex, load_printing_fns_64,
34+
PrintingFnsEx, PrintingFns64};

Diff for: src/libstd/sys/windows/backtrace/printing/msvc.rs

+38-21
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,38 @@ use mem;
1515
use sys::backtrace::BacktraceContext;
1616
use sys::backtrace::StackWalkVariant;
1717
use sys::c;
18+
use sys::dynamic_lib::DynamicLibrary;
1819
use sys_common::backtrace::Frame;
1920

21+
22+
// Structs holding printing functions and loaders for them
23+
// Two versions depending on whether dbghelp.dll has StackWalkEx or not
24+
// (the former being in newer Windows versions, the older being in Win7 and before)
25+
pub struct PrintingFnsEx {
26+
resolve_symname: SymFromInlineContextFn,
27+
sym_get_line: SymGetLineFromInlineContextFn,
28+
}
29+
pub struct PrintingFns64 {
30+
resolve_symname: SymFromAddrFn,
31+
sym_get_line: SymGetLineFromAddr64Fn,
32+
}
33+
34+
pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
35+
Ok(PrintingFnsEx{
36+
resolve_symname: sym!(dbghelp, "SymFromInlineContext",
37+
SymFromInlineContextFn)?,
38+
sym_get_line: sym!(dbghelp, "SymGetLineFromInlineContext",
39+
SymGetLineFromInlineContextFn)?,
40+
})
41+
}
42+
pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result<PrintingFns64> {
43+
Ok(PrintingFns64{
44+
resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?,
45+
sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64",
46+
SymGetLineFromAddr64Fn)?,
47+
})
48+
}
49+
2050
type SymFromInlineContextFn =
2151
unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
2252
type SymGetLineFromInlineContextFn = unsafe extern "system" fn(
@@ -39,14 +69,11 @@ where
3969
F: FnOnce(Option<&str>) -> io::Result<()>,
4070
{
4171
match context.StackWalkVariant {
42-
StackWalkVariant::StackWalkEx => {
43-
let SymFromInlineContext =
44-
sym!(&context.dbghelp, "SymFromInlineContext",SymFromInlineContextFn)?;
45-
resolve_symname_from_inline_context(SymFromInlineContext, frame, callback, context)
72+
StackWalkVariant::StackWalkEx(_, ref fns) => {
73+
resolve_symname_from_inline_context(fns.resolve_symname, frame, callback, context)
4674
},
47-
StackWalkVariant::StackWalk64 => {
48-
let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
49-
resolve_symname_from_addr(SymFromAddr, frame, callback, context)
75+
StackWalkVariant::StackWalk64(_, ref fns) => {
76+
resolve_symname_from_addr(fns.resolve_symname, frame, callback, context)
5077
}
5178
}
5279
}
@@ -134,20 +161,10 @@ where
134161
F: FnMut(&[u8], u32) -> io::Result<()>,
135162
{
136163
match context.StackWalkVariant {
137-
StackWalkVariant::StackWalkEx => {
138-
let SymGetLineFromInlineContext =
139-
sym!(&context.dbghelp, "SymGetLineFromInlineContext",
140-
SymGetLineFromInlineContextFn)?;
141-
foreach_symbol_fileline_ex(SymGetLineFromInlineContext,
142-
frame, f, context)
143-
},
144-
StackWalkVariant::StackWalk64 => {
145-
let SymGetLineFromAddr64 =
146-
sym!(&context.dbghelp, "SymGetLineFromAddr64",
147-
SymGetLineFromAddr64Fn)?;
148-
foreach_symbol_fileline_64(SymGetLineFromAddr64,
149-
frame, f, context)
150-
}
164+
StackWalkVariant::StackWalkEx(_, ref fns) =>
165+
foreach_symbol_fileline_ex(fns.sym_get_line, frame, f, context),
166+
StackWalkVariant::StackWalk64(_, ref fns) =>
167+
foreach_symbol_fileline_64(fns.sym_get_line, frame, f, context),
151168
}
152169
}
153170

0 commit comments

Comments
 (0)