From d39c66bf4ff2b49957edadf10afcc4050c3fc60b Mon Sep 17 00:00:00 2001 From: moxian Date: Tue, 8 May 2018 06:19:55 +0000 Subject: [PATCH 1/6] Add a fallback for stacktrace printing for older Windows versions. PR #47252 switched stack inspection functions of dbghelp.dll to their newer alternatives that also capture inlined context. Unfortunately, said new alternatives are not present in older dbghelp.dll versions. In particular Windows 7 at the time of writing has dbghelp.dll version 6.1.7601 from 2010, that lacks StackWalkEx and friends. Fixes #50138 --- src/libstd/sys/windows/backtrace/mod.rs | 170 +++++++++--- .../sys/windows/backtrace/printing/msvc.rs | 253 +++++++++++++----- src/libstd/sys/windows/c.rs | 16 ++ 3 files changed, 331 insertions(+), 108 deletions(-) diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 82498ad4d5820..8e879e0f49e86 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -48,24 +48,21 @@ pub mod gnu; pub use self::printing::{resolve_symname, foreach_symbol_fileline}; -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")?; // Fetch the symbols necessary from dbghelp.dll let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - let StackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn)?; + // StackWalkEx might not be present and we'll fall back to StackWalk64 + let ResStackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn); + let ResStackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn); // Allocate necessary structures for doing the stack walk let process = unsafe { c::GetCurrentProcess() }; let thread = unsafe { c::GetCurrentThread() }; let mut context: c::CONTEXT = unsafe { mem::zeroed() }; unsafe { c::RtlCaptureContext(&mut context) }; - let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; - frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; - let image = init_frame(&mut frame, &context); let backtrace_context = BacktraceContext { handle: process, @@ -76,49 +73,139 @@ pub fn unwind_backtrace(frames: &mut [Frame]) // Initialize this process's symbols let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) }; if ret != c::TRUE { - return Ok((0, backtrace_context)) + return Ok((0, backtrace_context)); } // And now that we're done with all the setup, do the stack walking! - let mut i = 0; - unsafe { - while i < frames.len() && - StackWalkEx(image, process, thread, &mut frame, &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0) == c::TRUE - { - let addr = (frame.AddrPC.Offset - 1) as *const u8; - - frames[i] = Frame { - symbol_addr: addr, - exact_position: addr, - inline_context: frame.InlineFrameContext, - }; - i += 1; + match (ResStackWalkEx, ResStackWalk64) { + (Ok(StackWalkEx), _) => { + let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; + frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; + let image = init_frame_ex(&mut frame, &context); + + let mut i = 0; + unsafe { + while i < frames.len() + && StackWalkEx( + image, + process, + thread, + &mut frame, + &mut context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ) == c::TRUE + { + let addr = (frame.AddrPC.Offset - 1) as *const u8; + + frames[i] = Frame { + symbol_addr: addr, + exact_position: addr, + inline_context: frame.InlineFrameContext, + }; + i += 1; + } + } + + Ok((i, backtrace_context)) } + (_, Ok(StackWalk64)) => { + let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; + let image = init_frame_64(&mut frame, &context); + + // Start from -1 to avoid printing this stack frame, which will + // always be exactly the same. + let mut i = 0; + unsafe { + while i < frames.len() + && StackWalk64( + image, + process, + thread, + &mut frame, + &mut context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) == c::TRUE + { + let addr = frame.AddrPC.Offset; + if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0 + { + break; + } + + frames[i] = Frame { + symbol_addr: (addr - 1) as *const u8, + exact_position: (addr - 1) as *const u8, + inline_context: 0, + }; + i += 1; + } + } + + Ok((i, backtrace_context)) + } + (Err(e), _) => Err(e), } - - Ok((i, backtrace_context)) } -type SymInitializeFn = - unsafe extern "system" fn(c::HANDLE, *mut c_void, - c::BOOL) -> c::BOOL; -type SymCleanupFn = - unsafe extern "system" fn(c::HANDLE) -> c::BOOL; +type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; +type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL; + +type StackWalkExFn = unsafe extern "system" fn( + c::DWORD, + c::HANDLE, + c::HANDLE, + *mut c::STACKFRAME_EX, + *mut c::CONTEXT, + *mut c_void, + *mut c_void, + *mut c_void, + *mut c_void, + c::DWORD, +) -> c::BOOL; + +type StackWalk64Fn = unsafe extern "system" fn( + c::DWORD, + c::HANDLE, + c::HANDLE, + *mut c::STACKFRAME64, + *mut c::CONTEXT, + *mut c_void, + *mut c_void, + *mut c_void, + *mut c_void, +) -> c::BOOL; -type StackWalkExFn = - unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE, - *mut c::STACKFRAME_EX, *mut c::CONTEXT, - *mut c_void, *mut c_void, - *mut c_void, *mut c_void, c::DWORD) -> c::BOOL; +#[cfg(target_arch = "x86")] +fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { + frame.AddrPC.Offset = ctx.Eip as u64; + frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + frame.AddrStack.Offset = ctx.Esp as u64; + frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + frame.AddrFrame.Offset = ctx.Ebp as u64; + frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_I386 +} + +#[cfg(target_arch = "x86_64")] +fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { + frame.AddrPC.Offset = ctx.Rip as u64; + frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + frame.AddrStack.Offset = ctx.Rsp as u64; + frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + frame.AddrFrame.Offset = ctx.Rbp as u64; + frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_AMD64 +} #[cfg(target_arch = "x86")] -fn init_frame(frame: &mut c::STACKFRAME_EX, - ctx: &c::CONTEXT) -> c::DWORD { +fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { frame.AddrPC.Offset = ctx.Eip as u64; frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; frame.AddrStack.Offset = ctx.Esp as u64; @@ -129,8 +216,7 @@ fn init_frame(frame: &mut c::STACKFRAME_EX, } #[cfg(target_arch = "x86_64")] -fn init_frame(frame: &mut c::STACKFRAME_EX, - ctx: &c::CONTEXT) -> c::DWORD { +fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { frame.AddrPC.Offset = ctx.Rip as u64; frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; frame.AddrStack.Offset = ctx.Rsp as u64; diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 967df1c8a2de9..e26d95a4f9d0a 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -10,88 +10,209 @@ use ffi::CStr; use io; -use libc::{c_ulong, c_char}; +use libc::{c_char, c_ulong}; use mem; -use sys::c; use sys::backtrace::BacktraceContext; +use sys::c; use sys_common::backtrace::Frame; 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(c::HANDLE, u64, c::ULONG, - u64, *mut c::DWORD, *mut c::IMAGEHLP_LINE64) -> c::BOOL; + unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *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 SymGetLineFromInlineContextFn = unsafe extern "system" fn( + c::HANDLE, + u64, + c::ULONG, + u64, + *mut c::DWORD, + *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(frame: Frame, - callback: F, - context: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> +pub fn resolve_symname(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> +where + F: FnOnce(Option<&str>) -> io::Result<()>, { - let SymFromInlineContext = sym!(&context.dbghelp, - "SymFromInlineContext", - SymFromInlineContextFn)?; + match ( + sym!( + &context.dbghelp, + "SymFromInlineContext", + SymFromInlineContextFn + ), + sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn), + ) { + (Ok(SymFromInlineContext), _) => 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::() - MAX_SYM_NAME + 1` (== 81) + // due to struct alignment. + info.SizeOfStruct = 88; - 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::() - 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) +{ + match ( + sym!( + &context.dbghelp, + "SymFromInlineContext", + SymFromInlineContextFn + ), + sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn), + ) { + (Ok(SymFromInlineContext), _) => 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::() - 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 + 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 { - 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) + None + }; + callback(symname) + }, + (_, Ok(SymFromAddr)) => unsafe { + } else { + None + }; + callback(symname) + }, + (_, Ok(SymFromAddr)) => 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::() - MAX_SYM_NAME + 1` (== 81) + // due to struct alignment. + info.SizeOfStruct = 88; + + let mut displacement = 0u64; + let ret = SymFromAddr( + context.handle, + frame.symbol_addr as u64, + &mut displacement, + &mut info, + ); + + let symname = if ret == c::TRUE { + let ptr = info.Name.as_ptr() as *const c_char; + CStr::from_ptr(ptr).to_str().ok() + } else { + None + }; + callback(symname) + }, + (Err(e), _) => Err(e), } } -pub fn foreach_symbol_fileline(frame: Frame, - mut f: F, - context: &BacktraceContext) - -> io::Result - where F: FnMut(&[u8], u32) -> io::Result<()> +pub fn foreach_symbol_fileline( + frame: Frame, + mut f: F, + context: &BacktraceContext, +) -> io::Result +where + F: FnMut(&[u8], u32) -> io::Result<()>, { - let SymGetLineFromInlineContext = sym!(&context.dbghelp, - "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn)?; + match ( + sym!( + &context.dbghelp, + "SymGetLineFromInlineContext", + SymGetLineFromInlineContextFn + ), + sym!( + &context.dbghelp, + "SymGetLineFromAddr64", + SymGetLineFromAddr64Fn + ), + ) { + (Ok(SymGetLineFromInlineContext), _) => unsafe { + let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); + line.SizeOfStruct = ::mem::size_of::() as u32; - unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = ::mem::size_of::() as u32; + let mut displacement = 0u32; + let ret = SymGetLineFromInlineContext( + 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)?; + } + Ok(false) + }, + (_, Ok(SymGetLineFromAddr64)) => unsafe { + let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); + line.SizeOfStruct = ::mem::size_of::() as u32; - let mut displacement = 0u32; - let ret = SymGetLineFromInlineContext(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)?; - } - Ok(false) + 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)?; + } + Ok(false) + }, + (Err(e), _) => Err(e), } } diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 6d929f21365cf..30aba2f400f2f 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -635,6 +635,22 @@ pub struct STACKFRAME_EX { pub InlineFrameContext: DWORD, } +#[repr(C)] +#[cfg(feature = "backtrace")] +pub struct STACKFRAME64 { + pub AddrPC: ADDRESS64, + pub AddrReturn: ADDRESS64, + pub AddrFrame: ADDRESS64, + pub AddrStack: ADDRESS64, + pub AddrBStore: ADDRESS64, + pub FuncTableEntry: *mut c_void, + pub Params: [u64; 4], + pub Far: BOOL, + pub Virtual: BOOL, + pub Reserved: [u64; 3], + pub KdHelp: KDHELP64, +} + #[repr(C)] #[cfg(feature = "backtrace")] pub struct KDHELP64 { From 3245a475ab92b5ab77cf69e336279420c86a83eb Mon Sep 17 00:00:00 2001 From: moxian Date: Sun, 13 May 2018 04:38:43 +0000 Subject: [PATCH 2/6] Split separate stackwalk variants into their own functions .. rather than having them be one giant match statement. --- src/libstd/sys/windows/backtrace/mod.rs | 194 ++++++++------ .../sys/windows/backtrace/printing/msvc.rs | 248 +++++++++--------- 2 files changed, 238 insertions(+), 204 deletions(-) diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 8e879e0f49e86..884ec4e9fade4 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -46,7 +46,7 @@ mod printing; #[path = "backtrace_gnu.rs"] pub mod gnu; -pub use self::printing::{resolve_symname, foreach_symbol_fileline}; +pub use self::printing::{foreach_symbol_fileline, resolve_symname}; pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { let dbghelp = DynamicLibrary::open("dbghelp.dll")?; @@ -54,19 +54,30 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon // Fetch the symbols necessary from 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 ResStackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn); - let ResStackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn); + 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)) + )?; // Allocate necessary structures for doing the stack walk let process = unsafe { c::GetCurrentProcess() }; - let thread = unsafe { c::GetCurrentThread() }; - let mut context: c::CONTEXT = unsafe { mem::zeroed() }; - unsafe { c::RtlCaptureContext(&mut context) }; let backtrace_context = BacktraceContext { handle: process, SymCleanup, + StackWalkVariant: variant, dbghelp, }; @@ -77,81 +88,102 @@ 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! - match (ResStackWalkEx, ResStackWalk64) { - (Ok(StackWalkEx), _) => { - let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; - frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; - let image = init_frame_ex(&mut frame, &context); - - let mut i = 0; - unsafe { - while i < frames.len() - && StackWalkEx( - image, - process, - thread, - &mut frame, - &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0, - ) == c::TRUE - { - let addr = (frame.AddrPC.Offset - 1) as *const u8; - - frames[i] = Frame { - symbol_addr: addr, - exact_position: addr, - inline_context: frame.InlineFrameContext, - }; - i += 1; - } - } + 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), + } +} - Ok((i, backtrace_context)) +fn set_frames_ex( + StackWalkEx: StackWalkExFn, + frames: &mut [Frame], + backtrace_context: BacktraceContext, + process: c::HANDLE, +) -> io::Result<(usize, BacktraceContext)> { + let thread = unsafe { c::GetCurrentProcess() }; + let mut context: c::CONTEXT = unsafe { mem::zeroed() }; + unsafe { c::RtlCaptureContext(&mut context) }; + + let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; + frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; + let image = init_frame_ex(&mut frame, &context); + + let mut i = 0; + unsafe { + while i < frames.len() + && StackWalkEx( + image, + process, + thread, + &mut frame, + &mut context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ) == c::TRUE + { + let addr = (frame.AddrPC.Offset - 1) as *const u8; + + frames[i] = Frame { + symbol_addr: addr, + exact_position: addr, + inline_context: frame.InlineFrameContext, + }; + i += 1; } - (_, Ok(StackWalk64)) => { - let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; - let image = init_frame_64(&mut frame, &context); - - // Start from -1 to avoid printing this stack frame, which will - // always be exactly the same. - let mut i = 0; - unsafe { - while i < frames.len() - && StackWalk64( - image, - process, - thread, - &mut frame, - &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ) == c::TRUE - { - let addr = frame.AddrPC.Offset; - if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0 - { - break; - } - - frames[i] = Frame { - symbol_addr: (addr - 1) as *const u8, - exact_position: (addr - 1) as *const u8, - inline_context: 0, - }; - i += 1; - } + } + + Ok((i, backtrace_context)) +} + +fn set_frames_64( + StackWalk64: StackWalk64Fn, + frames: &mut [Frame], + backtrace_context: BacktraceContext, + process: c::HANDLE, +) -> io::Result<(usize, BacktraceContext)> { + let thread = unsafe { c::GetCurrentProcess() }; + let mut context: c::CONTEXT = unsafe { mem::zeroed() }; + unsafe { c::RtlCaptureContext(&mut context) }; + + let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; + let image = init_frame_64(&mut frame, &context); + + // Start from -1 to avoid printing this stack frame, which will + // always be exactly the same. + let mut i = 0; + unsafe { + while i < frames.len() + && StackWalk64( + image, + process, + thread, + &mut frame, + &mut context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) == c::TRUE + { + let addr = frame.AddrPC.Offset; + if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0 + { + break; } - Ok((i, backtrace_context)) + frames[i] = Frame { + symbol_addr: (addr - 1) as *const u8, + exact_position: (addr - 1) as *const u8, + inline_context: 0, + }; + i += 1; } - (Err(e), _) => Err(e), } + + Ok((i, backtrace_context)) } type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; @@ -226,16 +258,26 @@ fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { c::IMAGE_FILE_MACHINE_AMD64 } +enum StackWalkVariant { + StackWalkEx, + StackWalk64, +} + + pub struct BacktraceContext { handle: c::HANDLE, SymCleanup: SymCleanupFn, // Only used in printing for msvc and not gnu #[allow(dead_code)] + StackWalkVariant: StackWalkVariant, + #[allow(dead_code)] dbghelp: DynamicLibrary, } impl Drop for BacktraceContext { fn drop(&mut self) { - unsafe { (self.SymCleanup)(self.handle); } + unsafe { + (self.SymCleanup)(self.handle); + } } } diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index e26d95a4f9d0a..9d7accb7ad77a 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -13,11 +13,10 @@ use io; use libc::{c_char, c_ulong}; use mem; use sys::backtrace::BacktraceContext; +use sys::backtrace::StackWalkVariant; use sys::c; use sys_common::backtrace::Frame; -type SymFromInlineContextFn = - unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *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 SymGetLineFromInlineContextFn = unsafe extern "system" fn( @@ -39,57 +38,26 @@ pub fn resolve_symname(frame: Frame, callback: F, context: &BacktraceContext) where F: FnOnce(Option<&str>) -> io::Result<()>, { - match ( - sym!( - &context.dbghelp, - "SymFromInlineContext", - SymFromInlineContextFn - ), - sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn), - ) { - (Ok(SymFromInlineContext), _) => 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::() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; + match context.StackWalkVariant { + StackWalkVariant::StackWalkEx => { + let SymFromInlineContext = + sym!(&context.dbghelp, "SymFromInlineContext",SymFromInlineContextFn)?; + resolve_symname_from_inline_context(SymFromInlineContext, frame, callback, context) + }, + StackWalkVariant::StackWalk64 => { + let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?; + resolve_symname_from_addr(SymFromAddr, frame, callback, context) + } + } +} - 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_inline_context( + SymFromInlineContext: SymFromInlineContextFn, + frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> +where + F: FnOnce(Option<&str>) -> io::Result<()>, { - match ( - sym!( - &context.dbghelp, - "SymFromInlineContext", - SymFromInlineContextFn - ), - sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn), - ) { - (Ok(SymFromInlineContext), _) => unsafe { + 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 @@ -122,42 +90,69 @@ where None }; callback(symname) - }, - (_, Ok(SymFromAddr)) => unsafe { - } else { - None - }; - callback(symname) - }, - (_, Ok(SymFromAddr)) => 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::() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; + } +} - let mut displacement = 0u64; - let ret = SymFromAddr( - context.handle, - frame.symbol_addr as u64, - &mut displacement, - &mut info, - ); +fn resolve_symname_from_addr( + SymFromAddr: SymFromAddrFn, + 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::() - MAX_SYM_NAME + 1` (== 81) + // due to struct alignment. + info.SizeOfStruct = 88; - let symname = if ret == c::TRUE { - let ptr = info.Name.as_ptr() as *const c_char; - CStr::from_ptr(ptr).to_str().ok() - } else { - None - }; - callback(symname) - }, - (Err(e), _) => Err(e), + let mut displacement = 0u64; + let ret = SymFromAddr( + context.handle, + frame.symbol_addr as u64, + &mut displacement, + &mut info, + ); + + let symname = if ret == c::TRUE { + let ptr = info.Name.as_ptr() as *const c_char; + CStr::from_ptr(ptr).to_str().ok() + } else { + None + }; + callback(symname) } } pub fn foreach_symbol_fileline( + frame: Frame, + f: F, + context: &BacktraceContext, +) -> io::Result +where + 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) + } + } +} + +fn foreach_symbol_fileline_ex( + SymGetLineFromInlineContext: SymGetLineFromInlineContextFn, frame: Frame, mut f: F, context: &BacktraceContext, @@ -165,54 +160,51 @@ pub fn foreach_symbol_fileline( where F: FnMut(&[u8], u32) -> io::Result<()>, { - match ( - sym!( - &context.dbghelp, - "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn - ), - sym!( - &context.dbghelp, - "SymGetLineFromAddr64", - SymGetLineFromAddr64Fn - ), - ) { - (Ok(SymGetLineFromInlineContext), _) => unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = ::mem::size_of::() as u32; + unsafe { + let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); + line.SizeOfStruct = ::mem::size_of::() as u32; - let mut displacement = 0u32; - let ret = SymGetLineFromInlineContext( - 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)?; - } - Ok(false) - }, - (_, Ok(SymGetLineFromAddr64)) => unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = ::mem::size_of::() as u32; + let mut displacement = 0u32; + let ret = SymGetLineFromInlineContext( + 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)?; + } + Ok(false) + } +} - 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)?; - } - Ok(false) - }, - (Err(e), _) => Err(e), +fn foreach_symbol_fileline_64( + SymGetLineFromAddr64: SymGetLineFromAddr64Fn, + frame: Frame, + mut f: F, + context: &BacktraceContext, +) -> io::Result +where + F: FnMut(&[u8], u32) -> io::Result<()>, +{ + unsafe { + let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); + line.SizeOfStruct = ::mem::size_of::() as u32; + + 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)?; + } + Ok(false) } } From c0b280f5f594fc6ff34ddcf35aa26cc46a073808 Mon Sep 17 00:00:00 2001 From: moxian Date: Sun, 13 May 2018 08:41:24 +0000 Subject: [PATCH 3/6] Load backtrace-related functions only once .. and pass them around in BacktraceContext. --- src/libstd/sys/windows/backtrace/mod.rs | 45 +++++++------- .../sys/windows/backtrace/printing/mod.rs | 14 +++++ .../sys/windows/backtrace/printing/msvc.rs | 59 ++++++++++++------- 3 files changed, 77 insertions(+), 41 deletions(-) diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 884ec4e9fade4..23bb4ab6dfe91 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -47,6 +47,7 @@ mod printing; 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")?; @@ -55,21 +56,23 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon 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() }; @@ -77,7 +80,7 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon let backtrace_context = BacktraceContext { handle: process, SymCleanup, - StackWalkVariant: variant, + StackWalkVariant: sw_var, 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! - 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), } } @@ -259,8 +262,8 @@ fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { } enum StackWalkVariant { - StackWalkEx, - StackWalk64, + StackWalkEx(StackWalkExFn, printing::PrintingFnsEx), + StackWalk64(StackWalk64Fn, printing::PrintingFns64), } @@ -268,8 +271,10 @@ pub struct BacktraceContext { 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, } diff --git a/src/libstd/sys/windows/backtrace/printing/mod.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs index 3e566f6e2bd5c..251d5028aeaa6 100644 --- a/src/libstd/sys/windows/backtrace/printing/mod.rs +++ b/src/libstd/sys/windows/backtrace/printing/mod.rs @@ -15,6 +15,20 @@ mod printing; #[cfg(target_env = "gnu")] mod printing { 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 { + Ok(PrintingFnsEx{}) + } + pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result { + Ok(PrintingFns64{}) + } } pub use self::printing::{foreach_symbol_fileline, resolve_symname}; +pub use self::printing::{load_printing_fns_ex, load_printing_fns_64, + PrintingFnsEx, PrintingFns64}; diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 9d7accb7ad77a..9cfc2c3d3525e 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -15,8 +15,38 @@ use mem; 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 { + 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 { + 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( @@ -39,14 +69,11 @@ where 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) } } } @@ -134,20 +161,10 @@ where 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), } } From a0b15012a17594566311ea490eda243b6bd9d92b Mon Sep 17 00:00:00 2001 From: moxian Date: Fri, 18 May 2018 11:38:50 +0000 Subject: [PATCH 4/6] Make stackwalking generic instead of matching on enum variants. --- src/libstd/sys/windows/backtrace/mod.rs | 280 +++++++++++++----------- 1 file changed, 147 insertions(+), 133 deletions(-) diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 23bb4ab6dfe91..7ef4e203571b2 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -47,7 +47,7 @@ mod printing; pub mod gnu; pub use self::printing::{foreach_symbol_fileline, resolve_symname}; -use self::printing::{load_printing_fns_ex, load_printing_fns_64}; +use self::printing::{load_printing_fns_64, load_printing_fns_ex}; pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { let dbghelp = DynamicLibrary::open("dbghelp.dll")?; @@ -56,20 +56,15 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - // StackWalkEx might not be present and we'll fall back to StackWalk64 let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) { - Ok(StackWalkEx) => - StackWalkVariant::StackWalkEx( - StackWalkEx, - load_printing_fns_ex(&dbghelp)?, - ), + 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)?, - ), + Ok(StackWalk64) => { + StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?) + } Err(..) => return Err(e), }, }; @@ -92,101 +87,38 @@ 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! 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), - } -} - -fn set_frames_ex( - StackWalkEx: StackWalkExFn, - frames: &mut [Frame], - backtrace_context: BacktraceContext, - process: c::HANDLE, -) -> io::Result<(usize, BacktraceContext)> { - let thread = unsafe { c::GetCurrentProcess() }; - let mut context: c::CONTEXT = unsafe { mem::zeroed() }; - unsafe { c::RtlCaptureContext(&mut context) }; - - let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; - frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; - let image = init_frame_ex(&mut frame, &context); + StackWalkVariant::StackWalkEx(StackWalkEx, _) => { + set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context)) + } - let mut i = 0; - unsafe { - while i < frames.len() - && StackWalkEx( - image, - process, - thread, - &mut frame, - &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0, - ) == c::TRUE - { - let addr = (frame.AddrPC.Offset - 1) as *const u8; - - frames[i] = Frame { - symbol_addr: addr, - exact_position: addr, - inline_context: frame.InlineFrameContext, - }; - i += 1; + StackWalkVariant::StackWalk64(StackWalk64, _) => { + set_frames(StackWalk64, frames).map(|i| (i, backtrace_context)) } } - - Ok((i, backtrace_context)) } -fn set_frames_64( - StackWalk64: StackWalk64Fn, - frames: &mut [Frame], - backtrace_context: BacktraceContext, - process: c::HANDLE, -) -> io::Result<(usize, BacktraceContext)> { +fn set_frames(StackWalk: W, frames: &mut [Frame]) -> io::Result { + let process = unsafe { c::GetCurrentProcess() }; let thread = unsafe { c::GetCurrentProcess() }; let mut context: c::CONTEXT = unsafe { mem::zeroed() }; unsafe { c::RtlCaptureContext(&mut context) }; + let mut frame = W::Item::new(); + let image = frame.init(&context); - let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; - let image = init_frame_64(&mut frame, &context); - - // Start from -1 to avoid printing this stack frame, which will - // always be exactly the same. let mut i = 0; - unsafe { - while i < frames.len() - && StackWalk64( - image, - process, - thread, - &mut frame, - &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ) == c::TRUE - { - let addr = frame.AddrPC.Offset; - if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0 - { - break; - } - - frames[i] = Frame { - symbol_addr: (addr - 1) as *const u8, - exact_position: (addr - 1) as *const u8, - inline_context: 0, - }; - i += 1; - } + while i < frames.len() + && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE + { + let addr = frame.get_addr(); + frames[i] = Frame { + symbol_addr: addr, + exact_position: addr, + inline_context: 0, + }; + + i += 1 } - - Ok((i, backtrace_context)) + Ok(i) } type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; @@ -217,48 +149,131 @@ type StackWalk64Fn = unsafe extern "system" fn( *mut c_void, ) -> c::BOOL; -#[cfg(target_arch = "x86")] -fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Eip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Esp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Ebp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 +trait StackWalker { + type Item: StackFrame; + + fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL; } -#[cfg(target_arch = "x86_64")] -fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Rip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Rsp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Rbp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 +impl StackWalker for StackWalkExFn { + type Item = c::STACKFRAME_EX; + fn walk( + &self, + image: c::DWORD, + process: c::HANDLE, + thread: c::HANDLE, + frame: &mut Self::Item, + context: &mut c::CONTEXT, + ) -> c::BOOL { + unsafe { + self( + image, + process, + thread, + frame, + context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ) + } + } +} + +impl StackWalker for StackWalk64Fn { + type Item = c::STACKFRAME64; + fn walk( + &self, + image: c::DWORD, + process: c::HANDLE, + thread: c::HANDLE, + frame: &mut Self::Item, + context: &mut c::CONTEXT, + ) -> c::BOOL { + unsafe { + self( + image, + process, + thread, + frame, + context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) + } + } +} + +trait StackFrame { + fn new() -> Self; + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD; + fn get_addr(&self) -> *const u8; } -#[cfg(target_arch = "x86")] -fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Eip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Esp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Ebp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 +impl StackFrame for c::STACKFRAME_EX { + fn new() -> c::STACKFRAME_EX { + unsafe { mem::zeroed() } + } + + #[cfg(target_arch = "x86")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Eip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Esp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Ebp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_I386 + } + #[cfg(target_arch = "x86_64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Rip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Rsp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Rbp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_AMD64 + } + + fn get_addr(&self) -> *const u8 { + (self.AddrPC.Offset - 1) as *const u8 + } } -#[cfg(target_arch = "x86_64")] -fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Rip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Rsp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Rbp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 +impl StackFrame for c::STACKFRAME64 { + fn new() -> c::STACKFRAME64 { + unsafe { mem::zeroed() } + } + + #[cfg(target_arch = "x86")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Eip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Esp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Ebp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_I386 + } + #[cfg(target_arch = "x86_64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Rip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Rsp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Rbp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_AMD64 + } + + fn get_addr(&self) -> *const u8 { + (self.AddrPC.Offset - 1) as *const u8 + } } enum StackWalkVariant { @@ -266,7 +281,6 @@ enum StackWalkVariant { StackWalk64(StackWalk64Fn, printing::PrintingFns64), } - pub struct BacktraceContext { handle: c::HANDLE, SymCleanup: SymCleanupFn, From 9d426ac387f2d42c998349c76ac1c2aea044e0ec Mon Sep 17 00:00:00 2001 From: moxian Date: Fri, 18 May 2018 12:33:23 +0000 Subject: [PATCH 5/6] Make msvc symbol extraction/printing functions generic. --- .../sys/windows/backtrace/printing/msvc.rs | 240 ++++++++++-------- 1 file changed, 137 insertions(+), 103 deletions(-) diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 9cfc2c3d3525e..d8f0a4d820898 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -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 { - 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 { - 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(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( - 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::() - 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( - SymFromAddr: SymFromAddrFn, - frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> +fn resolve_symname_internal( + 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( frame: Frame, - f: F, + callback: F, context: &BacktraceContext, ) -> io::Result 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( - SymGetLineFromInlineContext: SymGetLineFromInlineContextFn, +fn foreach_symbol_fileline_iternal( + line_getter: G, frame: Frame, - mut f: F, + mut callback: F, context: &BacktraceContext, ) -> io::Result where F: FnMut(&[u8], u32) -> io::Result<()>, + G: LineGetter, { unsafe { let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); line.SizeOfStruct = ::mem::size_of::() 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( - SymGetLineFromAddr64: SymGetLineFromAddr64Fn, - frame: Frame, - mut f: F, - context: &BacktraceContext, -) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, -{ - unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = ::mem::size_of::() 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) } } From be7f619870085121bdd7911aa882c35e70aedb8a Mon Sep 17 00:00:00 2001 From: moxian Date: Mon, 4 Jun 2018 11:00:12 +0000 Subject: [PATCH 6/6] Change traits to bare FnMut where possible. --- .../sys/windows/backtrace/printing/msvc.rs | 178 +++++++----------- 1 file changed, 67 insertions(+), 111 deletions(-) diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index d8f0a4d820898..c8b946bf13ad1 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -69,24 +69,48 @@ where F: FnOnce(Option<&str>) -> io::Result<()>, { match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => { - resolve_symname_internal(fns.resolve_symname, frame, callback, context) - } - StackWalkVariant::StackWalk64(_, ref fns) => { - resolve_symname_internal(fns.resolve_symname, frame, callback, context) - } + StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal( + |process: c::HANDLE, + symbol_address: u64, + inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO| unsafe { + let mut displacement = 0u64; + (fns.resolve_symname)( + process, + symbol_address, + inline_context, + &mut displacement, + info, + ) + }, + frame, + callback, + context, + ), + StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal( + |process: c::HANDLE, + symbol_address: u64, + _inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO| unsafe { + let mut displacement = 0u64; + (fns.resolve_symname)(process, symbol_address, &mut displacement, info) + }, + frame, + callback, + context, + ), } } fn resolve_symname_internal( - symbol_resolver: R, + mut symbol_resolver: R, frame: Frame, callback: F, context: &BacktraceContext, ) -> io::Result<()> where F: FnOnce(Option<&str>) -> io::Result<()>, - R: SymbolResolver, + R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL, { unsafe { let mut info: c::SYMBOL_INFO = mem::zeroed(); @@ -96,7 +120,7 @@ where // due to struct alignment. info.SizeOfStruct = 88; - let ret = symbol_resolver.resolve_symbol( + let ret = symbol_resolver( context.handle, frame.symbol_addr as u64, frame.inline_context, @@ -121,52 +145,6 @@ 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( frame: Frame, callback: F, @@ -176,30 +154,55 @@ where F: FnMut(&[u8], u32) -> io::Result<()>, { match context.StackWalkVariant { - 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) - } + StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal( + |process: c::HANDLE, + frame_address: u64, + inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64| unsafe { + let mut displacement = 0u32; + (fns.sym_get_line)( + process, + frame_address, + inline_context, + 0, + &mut displacement, + line, + ) + }, + frame, + callback, + context, + ), + StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal( + |process: c::HANDLE, + frame_address: u64, + _inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64| unsafe { + let mut displacement = 0u32; + (fns.sym_get_line)(process, frame_address, &mut displacement, line) + }, + frame, + callback, + context, + ), } } fn foreach_symbol_fileline_iternal( - line_getter: G, + mut line_getter: G, frame: Frame, mut callback: F, context: &BacktraceContext, ) -> io::Result where F: FnMut(&[u8], u32) -> io::Result<()>, - G: LineGetter, + G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL, { unsafe { let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); line.SizeOfStruct = ::mem::size_of::() as u32; - let ret = line_getter.get_line( + let ret = line_getter( context.handle, frame.exact_position as u64, frame.inline_context, @@ -212,50 +215,3 @@ where Ok(false) } } - -trait LineGetter { - fn get_line( - &self, - process: c::HANDLE, - frame_address: u64, - inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64, - ) -> c::BOOL; -} - -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, - ) - } - } -}