diff options
| author | moxian <moxian@google.com> | 2018-05-13 04:38:43 +0000 |
|---|---|---|
| committer | moxian <moxian@google.com> | 2018-06-28 21:56:48 +0000 |
| commit | 3245a475ab92b5ab77cf69e336279420c86a83eb (patch) | |
| tree | 58636f02c381d690a2ad0f99e05a3935d39b3115 | |
| parent | d39c66bf4ff2b49957edadf10afcc4050c3fc60b (diff) | |
| download | rust-3245a475ab92b5ab77cf69e336279420c86a83eb.tar.gz rust-3245a475ab92b5ab77cf69e336279420c86a83eb.zip | |
Split separate stackwalk variants into their own functions
.. rather than having them be one giant match statement.
| -rw-r--r-- | src/libstd/sys/windows/backtrace/mod.rs | 194 | ||||
| -rw-r--r-- | src/libstd/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 8e879e0f49e..884ec4e9fad 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 e26d95a4f9d..9d7accb7ad7 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -13,13 +13,12 @@ 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( c::HANDLE, u64, @@ -39,57 +38,26 @@ pub fn resolve_symname<F>(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::<SYMBOL_INFO>() - 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<F>( + 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,97 +90,121 @@ 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::<SYMBOL_INFO>() - 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<F>( + 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::<SYMBOL_INFO>() - 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<F>( frame: Frame, + f: F, + context: &BacktraceContext, +) -> io::Result<bool> +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<F>( + SymGetLineFromInlineContext: SymGetLineFromInlineContextFn, + frame: Frame, mut f: F, context: &BacktraceContext, ) -> io::Result<bool> 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::<c::IMAGEHLP_LINE64>() as u32; + 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( - 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::<c::IMAGEHLP_LINE64>() 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<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; + + 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) } } |
