aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sys/windows/backtrace/mod.rs
diff options
context:
space:
mode:
authorFenrirWolf <[email protected]>2018-08-19 18:01:18 -0600
committerGitHub <[email protected]>2018-08-19 18:01:18 -0600
commit15cb3c1e91842a68a8e50e1e1a42aefab13cc25e (patch)
treea514fde042ff2a504a03305bfe0894ff8cd8d47e /ctr-std/src/sys/windows/backtrace/mod.rs
parentUpdate for latest nightly 2018-06-09 (#70) (diff)
parentUpdate for nightly-2018-08-18 (diff)
downloadctru-rs-15cb3c1e91842a68a8e50e1e1a42aefab13cc25e.tar.xz
ctru-rs-15cb3c1e91842a68a8e50e1e1a42aefab13cc25e.zip
Merge pull request #73 from FenrirWolf/update-2018-08-18
Update for nightly-2018-08-18
Diffstat (limited to 'ctr-std/src/sys/windows/backtrace/mod.rs')
-rw-r--r--ctr-std/src/sys/windows/backtrace/mod.rs297
1 files changed, 234 insertions, 63 deletions
diff --git a/ctr-std/src/sys/windows/backtrace/mod.rs b/ctr-std/src/sys/windows/backtrace/mod.rs
index 82498ad..f64cae8 100644
--- a/ctr-std/src/sys/windows/backtrace/mod.rs
+++ b/ctr-std/src/sys/windows/backtrace/mod.rs
@@ -46,110 +46,281 @@ 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};
+use self::printing::{load_printing_fns_64, load_printing_fns_ex};
-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 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() };
- 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,
SymCleanup,
+ StackWalkVariant: sw_var,
dbghelp,
};
// 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!
+ match backtrace_context.StackWalkVariant {
+ StackWalkVariant::StackWalkEx(StackWalkEx, _) => {
+ set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context))
+ }
+
+ StackWalkVariant::StackWalk64(StackWalk64, _) => {
+ set_frames(StackWalk64, frames).map(|i| (i, backtrace_context))
+ }
+ }
+}
+
+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 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;
+ 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)
+}
+
+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;
+
+trait StackWalker {
+ type Item: StackFrame;
+
+ fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL;
+}
+
+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;
+}
+
+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
+ }
+
+ #[cfg(target_arch = "aarch64")]
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+ self.AddrPC.Offset = ctx.Pc as u64;
+ self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrStack.Offset = ctx.Sp as u64;
+ self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrFrame.Offset = ctx.Fp as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_ARM64
+ }
- Ok((i, backtrace_context))
+ fn get_addr(&self) -> *const u8 {
+ (self.AddrPC.Offset - 1) as *const u8
+ }
}
-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;
-
-#[cfg(target_arch = "x86")]
-fn init_frame(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
+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
+ }
+
+ #[cfg(target_arch = "aarch64")]
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+ self.AddrPC.Offset = ctx.Pc as u64;
+ self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrStack.Offset = ctx.Sp as u64;
+ self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrFrame.Offset = ctx.Fp as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_ARM64
+ }
+
+ fn get_addr(&self) -> *const u8 {
+ (self.AddrPC.Offset - 1) as *const u8
+ }
}
-#[cfg(target_arch = "x86_64")]
-fn init_frame(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
+enum StackWalkVariant {
+ StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
+ StackWalk64(StackWalk64Fn, printing::PrintingFns64),
}
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,
}
impl Drop for BacktraceContext {
fn drop(&mut self) {
- unsafe { (self.SymCleanup)(self.handle); }
+ unsafe {
+ (self.SymCleanup)(self.handle);
+ }
}
}