From d50e4cc0640e54a64d0f7ccb05a77fd4a2fe0741 Mon Sep 17 00:00:00 2001 From: Yamakaky Date: Sun, 4 Dec 2016 16:38:27 -0500 Subject: Improve backtrace formating while panicking. - `RUST_BACKTRACE=full` prints all the informations (old behaviour) - `RUST_BACKTRACE=(0|no)` disables the backtrace. - `RUST_BACKTRACE=` (including `1`) shows a simplified backtrace, without the function addresses and with cleaned filenames and symbols. Also removes some unneded frames at the beginning and the end. Fixes #37783. PR is #38165. --- src/libstd/sys/windows/backtrace.rs | 163 ---------------------- src/libstd/sys/windows/backtrace/backtrace_gnu.rs | 62 ++++++++ src/libstd/sys/windows/backtrace/mod.rs | 156 +++++++++++++++++++++ src/libstd/sys/windows/backtrace/printing/mod.rs | 20 +++ src/libstd/sys/windows/backtrace/printing/msvc.rs | 83 +++++++++++ src/libstd/sys/windows/backtrace_gnu.rs | 62 -------- src/libstd/sys/windows/printing/gnu.rs | 26 ---- src/libstd/sys/windows/printing/msvc.rs | 73 ---------- 8 files changed, 321 insertions(+), 324 deletions(-) delete mode 100644 src/libstd/sys/windows/backtrace.rs create mode 100644 src/libstd/sys/windows/backtrace/backtrace_gnu.rs create mode 100644 src/libstd/sys/windows/backtrace/mod.rs create mode 100644 src/libstd/sys/windows/backtrace/printing/mod.rs create mode 100644 src/libstd/sys/windows/backtrace/printing/msvc.rs delete mode 100644 src/libstd/sys/windows/backtrace_gnu.rs delete mode 100644 src/libstd/sys/windows/printing/gnu.rs delete mode 100644 src/libstd/sys/windows/printing/msvc.rs (limited to 'src/libstd/sys/windows') diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs deleted file mode 100644 index 94aaf439f3d..00000000000 --- a/src/libstd/sys/windows/backtrace.rs +++ /dev/null @@ -1,163 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! As always, windows has something very different than unix, we mainly want -//! to avoid having to depend too much on libunwind for windows. -//! -//! If you google around, you'll find a fair bit of references to built-in -//! functions to get backtraces on windows. It turns out that most of these are -//! in an external library called dbghelp. I was unable to find this library -//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent -//! of it. -//! -//! You'll also find that there's a function called CaptureStackBackTrace -//! mentioned frequently (which is also easy to use), but sadly I didn't have a -//! copy of that function in my mingw install (maybe it was broken?). Instead, -//! this takes the route of using StackWalk64 in order to walk the stack. - -#![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; - -macro_rules! sym { - ($lib:expr, $e:expr, $t:ident) => ( - match $lib.symbol($e) { - Ok(f) => $crate::mem::transmute::(f), - Err(..) => return Ok(()) - } - ) -} - -#[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; - -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 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; - -#[cfg(target_arch = "x86")] -pub 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; - 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")] -pub 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; - 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 -} - -struct Cleanup { - handle: c::HANDLE, - SymCleanup: SymCleanupFn, -} - -impl Drop for Cleanup { - 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/backtrace/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs new file mode 100644 index 00000000000..f0d29dd4178 --- /dev/null +++ b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs @@ -0,0 +1,62 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use sys::c; +use libc::c_char; +use path::PathBuf; +use fs::{OpenOptions, File}; +use sys::ext::fs::OpenOptionsExt; +use sys::handle::Handle; +use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte}; + +fn query_full_process_image_name() -> io::Result { + unsafe { + let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION, + c::FALSE, + c::GetCurrentProcessId())); + fill_utf16_buf(|buf, mut sz| { + if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 { + 0 + } else { + sz + } + }, os2path) + } +} + +fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> { + // We query the current image name, open the file without FILE_SHARE_DELETE so it + // can't be moved and then get the current image name again. If the names are the + // same than we have successfully locked the file + let image_name1 = query_full_process_image_name()?; + let file = OpenOptions::new() + .read(true) + .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE) + .open(&image_name1)?; + let image_name2 = query_full_process_image_name()?; + + if image_name1 != image_name2 { + return Err(io::Error::new(io::ErrorKind::Other, + "executable moved while trying to lock it")); + } + + Ok((image_name1, file)) +} + +// Get the executable filename for libbacktrace +// This returns the path in the ANSI code page and a File which should remain open +// for as long as the path should remain valid +pub fn get_executable_filename() -> io::Result<(Vec, File)> { + let (executable, file) = lock_and_get_executable_filename()?; + let u16_executable = to_u16s(executable.into_os_string())?; + Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS, + &u16_executable, true)?, file)) +} diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs new file mode 100644 index 00000000000..3c3fd8d3e4a --- /dev/null +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -0,0 +1,156 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! As always, windows has something very different than unix, we mainly want +//! to avoid having to depend too much on libunwind for windows. +//! +//! If you google around, you'll find a fair bit of references to built-in +//! functions to get backtraces on windows. It turns out that most of these are +//! in an external library called dbghelp. I was unable to find this library +//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent +//! of it. +//! +//! You'll also find that there's a function called CaptureStackBackTrace +//! mentioned frequently (which is also easy to use), but sadly I didn't have a +//! copy of that function in my mingw install (maybe it was broken?). Instead, +//! this takes the route of using StackWalk64 in order to walk the stack. + +#![allow(deprecated)] // dynamic_lib + +use io; +use libc::c_void; +use mem; +use ptr; +use sys::c; +use sys::dynamic_lib::DynamicLibrary; +use sys_common::backtrace::Frame; + +macro_rules! sym { + ($lib:expr, $e:expr, $t:ident) => ( + $lib.symbol($e).map(|f| unsafe { + $crate::mem::transmute::(f) + }) + ) +} + +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; +type SymCleanupFn = + unsafe extern "system" fn(c::HANDLE) -> 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; + +#[cfg(target_arch = "x86")] +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; + 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(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 +} + +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 BacktraceContext { + fn drop(&mut self) { + unsafe { (self.SymCleanup)(self.handle); } + } +} diff --git a/src/libstd/sys/windows/backtrace/printing/mod.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs new file mode 100644 index 00000000000..3e566f6e2bd --- /dev/null +++ b/src/libstd/sys/windows/backtrace/printing/mod.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(target_env = "msvc")] +#[path = "msvc.rs"] +mod printing; + +#[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 or the MIT license +// , 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(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::() - 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(frame: Frame, + mut f: F, + context: &BacktraceContext) + -> io::Result + 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::() 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/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace_gnu.rs deleted file mode 100644 index f0d29dd4178..00000000000 --- a/src/libstd/sys/windows/backtrace_gnu.rs +++ /dev/null @@ -1,62 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys::c; -use libc::c_char; -use path::PathBuf; -use fs::{OpenOptions, File}; -use sys::ext::fs::OpenOptionsExt; -use sys::handle::Handle; -use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte}; - -fn query_full_process_image_name() -> io::Result { - unsafe { - let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION, - c::FALSE, - c::GetCurrentProcessId())); - fill_utf16_buf(|buf, mut sz| { - if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 { - 0 - } else { - sz - } - }, os2path) - } -} - -fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> { - // We query the current image name, open the file without FILE_SHARE_DELETE so it - // can't be moved and then get the current image name again. If the names are the - // same than we have successfully locked the file - let image_name1 = query_full_process_image_name()?; - let file = OpenOptions::new() - .read(true) - .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE) - .open(&image_name1)?; - let image_name2 = query_full_process_image_name()?; - - if image_name1 != image_name2 { - return Err(io::Error::new(io::ErrorKind::Other, - "executable moved while trying to lock it")); - } - - Ok((image_name1, file)) -} - -// Get the executable filename for libbacktrace -// This returns the path in the ANSI code page and a File which should remain open -// for as long as the path should remain valid -pub fn get_executable_filename() -> io::Result<(Vec, File)> { - let (executable, file) = lock_and_get_executable_filename()?; - let u16_executable = to_u16s(executable.into_os_string())?; - Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS, - &u16_executable, true)?, file)) -} diff --git a/src/libstd/sys/windows/printing/gnu.rs b/src/libstd/sys/windows/printing/gnu.rs deleted file mode 100644 index be2d5273c07..00000000000 --- a/src/libstd/sys/windows/printing/gnu.rs +++ /dev/null @@ -1,26 +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 or the MIT license -// , at your -// 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; - -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) -} 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 or the MIT license -// , 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::() - 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::() 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(()) - } - } -} -- cgit 1.4.1-3-g733a5