about summary refs log tree commit diff
path: root/src/libstd/sys/windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/sys/windows')
-rw-r--r--src/libstd/sys/windows/backtrace/backtrace_gnu.rs (renamed from src/libstd/sys/windows/backtrace_gnu.rs)0
-rw-r--r--src/libstd/sys/windows/backtrace/mod.rs (renamed from src/libstd/sys/windows/backtrace.rs)151
-rw-r--r--src/libstd/sys/windows/backtrace/printing/mod.rs (renamed from src/libstd/sys/windows/printing/gnu.rs)22
-rw-r--r--src/libstd/sys/windows/backtrace/printing/msvc.rs83
-rw-r--r--src/libstd/sys/windows/printing/msvc.rs73
5 files changed, 163 insertions, 166 deletions
diff --git a/src/libstd/sys/windows/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs
index f0d29dd4178..f0d29dd4178 100644
--- a/src/libstd/sys/windows/backtrace_gnu.rs
+++ b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs
diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace/mod.rs
index 94aaf439f3d..3c3fd8d3e4a 100644
--- a/src/libstd/sys/windows/backtrace.rs
+++ b/src/libstd/sys/windows/backtrace/mod.rs
@@ -24,37 +24,87 @@
 
 #![allow(deprecated)] // dynamic_lib
 
-use io::prelude::*;
-
 use io;
 use libc::c_void;
 use mem;
 use ptr;
 use sys::c;
 use sys::dynamic_lib::DynamicLibrary;
-use sys::mutex::Mutex;
+use sys_common::backtrace::Frame;
 
 macro_rules! sym {
     ($lib:expr, $e:expr, $t:ident) => (
-        match $lib.symbol($e) {
-            Ok(f) => $crate::mem::transmute::<usize, $t>(f),
-            Err(..) => return Ok(())
-        }
+        $lib.symbol($e).map(|f| unsafe {
+            $crate::mem::transmute::<usize, $t>(f)
+        })
     )
 }
 
-#[cfg(target_env = "msvc")]
-#[path = "printing/msvc.rs"]
-mod printing;
-
-#[cfg(target_env = "gnu")]
-#[path = "printing/gnu.rs"]
 mod printing;
 
 #[cfg(target_env = "gnu")]
 #[path = "backtrace_gnu.rs"]
 pub mod gnu;
 
+pub use self::printing::{resolve_symname, foreach_symbol_fileline};
+
+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 StackWalk64 = 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::STACKFRAME64 = unsafe { mem::zeroed() };
+    let image = init_frame(&mut frame, &context);
+
+    let backtrace_context = BacktraceContext {
+        handle: process,
+        SymCleanup: SymCleanup,
+        dbghelp: 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))
+    }
+
+    // And now that we're done with all the setup, do the stack walking!
+    // 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 c_void,
+                exact_position: (addr - 1) as *const c_void,
+            };
+            i += 1;
+        }
+    }
+
+    Ok((i, backtrace_context))
+}
+
 type SymInitializeFn =
     unsafe extern "system" fn(c::HANDLE, *mut c_void,
                               c::BOOL) -> c::BOOL;
@@ -68,8 +118,8 @@ type StackWalk64Fn =
                               *mut c_void, *mut c_void) -> c::BOOL;
 
 #[cfg(target_arch = "x86")]
-pub fn init_frame(frame: &mut c::STACKFRAME64,
-                  ctx: &c::CONTEXT) -> c::DWORD {
+fn init_frame(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;
@@ -80,8 +130,8 @@ pub fn init_frame(frame: &mut c::STACKFRAME64,
 }
 
 #[cfg(target_arch = "x86_64")]
-pub fn init_frame(frame: &mut c::STACKFRAME64,
-                  ctx: &c::CONTEXT) -> c::DWORD {
+fn init_frame(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;
@@ -91,73 +141,16 @@ pub fn init_frame(frame: &mut c::STACKFRAME64,
     c::IMAGE_FILE_MACHINE_AMD64
 }
 
-struct Cleanup {
+pub struct BacktraceContext {
     handle: c::HANDLE,
     SymCleanup: SymCleanupFn,
+    // Only used in printing for msvc and not gnu
+    #[allow(dead_code)]
+    dbghelp: DynamicLibrary,
 }
 
-impl Drop for Cleanup {
+impl Drop for BacktraceContext {
     fn drop(&mut self) {
         unsafe { (self.SymCleanup)(self.handle); }
     }
 }
-
-pub fn write(w: &mut Write) -> io::Result<()> {
-    // According to windows documentation, all dbghelp functions are
-    // single-threaded.
-    static LOCK: Mutex = Mutex::new();
-    unsafe {
-        LOCK.lock();
-        let res = _write(w);
-        LOCK.unlock();
-        return res
-    }
-}
-
-unsafe fn _write(w: &mut Write) -> io::Result<()> {
-    let dbghelp = match DynamicLibrary::open("dbghelp.dll") {
-        Ok(lib) => lib,
-        Err(..) => return Ok(()),
-    };
-
-    // Fetch the symbols necessary from dbghelp.dll
-    let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn);
-    let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn);
-    let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn);
-
-    // Allocate necessary structures for doing the stack walk
-    let process = c::GetCurrentProcess();
-    let thread = c::GetCurrentThread();
-    let mut context: c::CONTEXT = mem::zeroed();
-    c::RtlCaptureContext(&mut context);
-    let mut frame: c::STACKFRAME64 = mem::zeroed();
-    let image = init_frame(&mut frame, &context);
-
-    // Initialize this process's symbols
-    let ret = SymInitialize(process, ptr::null_mut(), c::TRUE);
-    if ret != c::TRUE { return Ok(()) }
-    let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
-
-    // And now that we're done with all the setup, do the stack walking!
-    // Start from -1 to avoid printing this stack frame, which will
-    // always be exactly the same.
-    let mut i = -1;
-    write!(w, "stack backtrace:\n")?;
-    while 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 }
-
-        i += 1;
-
-        if i >= 0 {
-            printing::print(w, i, addr - 1, process, &dbghelp)?;
-        }
-    }
-
-    Ok(())
-}
diff --git a/src/libstd/sys/windows/printing/gnu.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs
index be2d5273c07..3e566f6e2bd 100644
--- a/src/libstd/sys/windows/printing/gnu.rs
+++ b/src/libstd/sys/windows/backtrace/printing/mod.rs
@@ -8,19 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use io::prelude::*;
-use io;
-use libc::c_void;
-use sys::c;
-use sys::dynamic_lib::DynamicLibrary;
-use sys_common::gnu::libbacktrace;
+#[cfg(target_env = "msvc")]
+#[path = "msvc.rs"]
+mod printing;
 
-pub fn print(w: &mut Write,
-             i: isize,
-             addr: u64,
-             _process: c::HANDLE,
-             _dbghelp: &DynamicLibrary)
-              -> io::Result<()> {
-    let addr = addr as usize as *mut c_void;
-    libbacktrace::print(w, i, addr, addr)
+#[cfg(target_env = "gnu")]
+mod printing {
+    pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
 }
+
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs
new file mode 100644
index 00000000000..3107d784324
--- /dev/null
+++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs
@@ -0,0 +1,83 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ffi::CStr;
+use io;
+use libc::{c_ulong, c_int, c_char};
+use mem;
+use sys::c;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
+
+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<F>(frame: Frame,
+                          callback: F,
+                          context: &BacktraceContext) -> io::Result<()>
+    where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
+
+    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);
+
+        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,
+                                  mut f: F,
+                                  context: &BacktraceContext)
+    -> io::Result<bool>
+    where F: FnMut(&[u8], c_int) -> io::Result<()>
+{
+    let SymGetLineFromAddr64 = sym!(&context.dbghelp,
+                                    "SymGetLineFromAddr64",
+                                    SymGetLineFromAddr64Fn)?;
+
+    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 c_int)?;
+        }
+        Ok(false)
+    }
+}
diff --git a/src/libstd/sys/windows/printing/msvc.rs b/src/libstd/sys/windows/printing/msvc.rs
deleted file mode 100644
index 9c29ac4082a..00000000000
--- a/src/libstd/sys/windows/printing/msvc.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use ffi::CStr;
-use io::prelude::*;
-use io;
-use libc::{c_ulong, c_int, c_char, c_void};
-use mem;
-use sys::c;
-use sys::dynamic_lib::DynamicLibrary;
-use sys_common::backtrace::{output, output_fileline};
-
-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;
-
-pub fn print(w: &mut Write,
-             i: isize,
-             addr: u64,
-             process: c::HANDLE,
-             dbghelp: &DynamicLibrary)
-              -> io::Result<()> {
-    unsafe {
-        let SymFromAddr = sym!(dbghelp, "SymFromAddr", SymFromAddrFn);
-        let SymGetLineFromAddr64 = sym!(dbghelp,
-                                        "SymGetLineFromAddr64",
-                                        SymGetLineFromAddr64Fn);
-
-        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(process, addr, &mut displacement, &mut info);
-
-        let name = if ret == c::TRUE {
-            let ptr = info.Name.as_ptr() as *const c_char;
-            Some(CStr::from_ptr(ptr).to_bytes())
-        } else {
-            None
-        };
-
-        output(w, i, addr as usize as *mut c_void, name)?;
-
-        // Now find out the filename and line number
-        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(process, addr, &mut displacement, &mut line);
-        if ret == c::TRUE {
-            output_fileline(w,
-                            CStr::from_ptr(line.Filename).to_bytes(),
-                            line.LineNumber as c_int,
-                            false)
-        } else {
-            Ok(())
-        }
-    }
-}