diff options
| author | moxian <moxian@google.com> | 2018-05-18 11:38:50 +0000 |
|---|---|---|
| committer | moxian <moxian@google.com> | 2018-06-28 21:56:58 +0000 |
| commit | a0b15012a17594566311ea490eda243b6bd9d92b (patch) | |
| tree | 2bc28470db41900192ef83d488ba8b2420fe2968 /src/libstd/sys | |
| parent | c0b280f5f594fc6ff34ddcf35aa26cc46a073808 (diff) | |
| download | rust-a0b15012a17594566311ea490eda243b6bd9d92b.tar.gz rust-a0b15012a17594566311ea490eda243b6bd9d92b.zip | |
Make stackwalking generic instead of matching on enum variants.
Diffstat (limited to 'src/libstd/sys')
| -rw-r--r-- | src/libstd/sys/windows/backtrace/mod.rs | 280 |
1 files changed, 147 insertions, 133 deletions
diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 23bb4ab6dfe..7ef4e203571 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<W: StackWalker>(StackWalk: W, frames: &mut [Frame]) -> io::Result<usize> { + 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, |
