diff options
| author | Yamakaky <yamakaky@yamaworld.fr> | 2016-12-04 16:38:27 -0500 |
|---|---|---|
| committer | Yamakaky <yamakaky@yamaworld.fr> | 2017-02-15 14:24:37 -0500 |
| commit | d50e4cc0640e54a64d0f7ccb05a77fd4a2fe0741 (patch) | |
| tree | 2c403c3c5fb8e02b5d5bbe493eec5375c47fd137 /src/libstd/sys | |
| parent | e0044bd3896456afb346d06e91a97ac515930ccf (diff) | |
| download | rust-d50e4cc0640e54a64d0f7ccb05a77fd4a2fe0741.tar.gz rust-d50e4cc0640e54a64d0f7ccb05a77fd4a2fe0741.zip | |
Improve backtrace formating while panicking.
- `RUST_BACKTRACE=full` prints all the informations (old behaviour) - `RUST_BACKTRACE=(0|no)` disables the backtrace. - `RUST_BACKTRACE=<everything else>` (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.
Diffstat (limited to 'src/libstd/sys')
| -rw-r--r-- | src/libstd/sys/redox/backtrace.rs | 11 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/mod.rs | 5 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/printing/dladdr.rs | 62 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/printing/mod.rs | 7 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs | 51 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/tracing/gcc_s.rs | 159 | ||||
| -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/unix/backtrace/printing/gnu.rs) | 11 | ||||
| -rw-r--r-- | src/libstd/sys/windows/backtrace/printing/msvc.rs | 83 | ||||
| -rw-r--r-- | src/libstd/sys/windows/printing/gnu.rs | 26 | ||||
| -rw-r--r-- | src/libstd/sys/windows/printing/msvc.rs | 73 |
12 files changed, 317 insertions, 322 deletions
diff --git a/src/libstd/sys/redox/backtrace.rs b/src/libstd/sys/redox/backtrace.rs index 6f53841502a..961148fb6b4 100644 --- a/src/libstd/sys/redox/backtrace.rs +++ b/src/libstd/sys/redox/backtrace.rs @@ -10,9 +10,14 @@ use libc; use io; -use sys_common::backtrace::output; +use sys_common::backtrace::Frame; + +pub use sys_common::gnu::libbacktrace::*; +pub struct BacktraceContext; #[inline(never)] -pub fn write(w: &mut io::Write) -> io::Result<()> { - output(w, 0, 0 as *mut libc::c_void, None) +pub fn unwind_backtrace(frames: &mut [Frame]) + -> io::Result<(usize, BacktraceContext)> +{ + Ok((0, BacktraceContext)) } diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs index 1eef89bf66f..29d4012dcdf 100644 --- a/src/libstd/sys/unix/backtrace/mod.rs +++ b/src/libstd/sys/unix/backtrace/mod.rs @@ -83,7 +83,8 @@ /// to symbols. This is a bit of a hokey implementation as-is, but it works for /// all unix platforms we support right now, so it at least gets the job done. -pub use self::tracing::write; +pub use self::tracing::unwind_backtrace; +pub use self::printing::{foreach_symbol_fileline, resolve_symname}; // tracing impls: mod tracing; @@ -100,3 +101,5 @@ pub mod gnu { Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) } } + +pub struct BacktraceContext; diff --git a/src/libstd/sys/unix/backtrace/printing/dladdr.rs b/src/libstd/sys/unix/backtrace/printing/dladdr.rs index d9b759dc673..05a071a7978 100644 --- a/src/libstd/sys/unix/backtrace/printing/dladdr.rs +++ b/src/libstd/sys/unix/backtrace/printing/dladdr.rs @@ -9,33 +9,45 @@ // except according to those terms. use io; -use io::prelude::*; +use intrinsics; +use ffi::CStr; use libc; +use sys::backtrace::BacktraceContext; +use sys_common::backtrace::Frame; -pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, - _symaddr: *mut libc::c_void) -> io::Result<()> { - use sys_common::backtrace::{output}; - use intrinsics; - use ffi::CStr; - - #[repr(C)] - struct Dl_info { - dli_fname: *const libc::c_char, - dli_fbase: *mut libc::c_void, - dli_sname: *const libc::c_char, - dli_saddr: *mut libc::c_void, - } - extern { - fn dladdr(addr: *const libc::c_void, - info: *mut Dl_info) -> libc::c_int; +pub fn resolve_symname<F>(frame: Frame, + callback: F, + _: &BacktraceContext) -> io::Result<()> + where F: FnOnce(Option<&str>) -> io::Result<()> +{ + unsafe { + let mut info: Dl_info = intrinsics::init(); + let symname = if dladdr(frame.exact_position, &mut info) == 0 { + None + } else { + CStr::from_ptr(info.dli_sname).to_str().ok() + }; + callback(symname) } +} - let mut info: Dl_info = unsafe { intrinsics::init() }; - if unsafe { dladdr(addr, &mut info) == 0 } { - output(w, idx,addr, None) - } else { - output(w, idx, addr, Some(unsafe { - CStr::from_ptr(info.dli_sname).to_bytes() - })) - } +pub fn foreach_symbol_fileline<F>(_symbol_addr: Frame, + _f: F, + _: &BacktraceContext) -> io::Result<bool> + where F: FnMut(&[u8], libc::c_int) -> io::Result<()> +{ + Ok(false) +} + +#[repr(C)] +struct Dl_info { + dli_fname: *const libc::c_char, + dli_fbase: *mut libc::c_void, + dli_sname: *const libc::c_char, + dli_saddr: *mut libc::c_void, +} + +extern { + fn dladdr(addr: *const libc::c_void, + info: *mut Dl_info) -> libc::c_int; } diff --git a/src/libstd/sys/unix/backtrace/printing/mod.rs b/src/libstd/sys/unix/backtrace/printing/mod.rs index 02e53854727..1ae82e01100 100644 --- a/src/libstd/sys/unix/backtrace/printing/mod.rs +++ b/src/libstd/sys/unix/backtrace/printing/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::imp::print; +pub use self::imp::{foreach_symbol_fileline, resolve_symname}; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))] @@ -17,5 +17,6 @@ mod imp; #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "emscripten")))] -#[path = "gnu.rs"] -mod imp; +mod imp { + pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; +} diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs index ca2e70b5003..fd46b8b9cf0 100644 --- a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs +++ b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs @@ -18,39 +18,32 @@ /// simple to use it should be used only on iOS devices as the only viable /// option. -use io::prelude::*; use io; use libc; use mem; -use sys::mutex::Mutex; +use sys::backtrace::BacktraceContext; +use sys_common::backtrace::Frame; -use super::super::printing::print; - -#[inline(never)] -pub fn write(w: &mut Write) -> io::Result<()> { - extern { - fn backtrace(buf: *mut *mut libc::c_void, - sz: libc::c_int) -> libc::c_int; +#[inline(never)] // if we know this is a function call, we can skip it when + // tracing +pub fn unwind_backtrace(frames: &mut [Frame]) + -> io::Result<(usize, BacktraceContext)> +{ + const FRAME_LEN: usize = 100; + assert!(FRAME_LEN >= frames.len()); + let mut raw_frames = [::std::ptr::null_mut(); FRAME_LEN]; + let nb_frames = unsafe { + backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int) + } as usize; + for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) { + *to = Frame { + exact_position: *from, + symbol_addr: *from, + }; } + Ok((nb_frames as usize, BacktraceContext)) +} - // while it doesn't requires lock for work as everything is - // local, it still displays much nicer backtraces when a - // couple of threads panic simultaneously - static LOCK: Mutex = Mutex::new(); - unsafe { - LOCK.lock(); - - writeln!(w, "stack backtrace:")?; - // 100 lines should be enough - const SIZE: usize = 100; - let mut buf: [*mut libc::c_void; SIZE] = mem::zeroed(); - let cnt = backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize; - - // skipping the first one as it is write itself - for i in 1..cnt { - print(w, i as isize, buf[i], buf[i])? - } - LOCK.unlock(); - } - Ok(()) +extern { + fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; } diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs index c1b45620ab0..8691fe55e7c 100644 --- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs +++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs @@ -8,102 +8,97 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use error::Error; use io; -use io::prelude::*; use libc; -use mem; -use sys_common::mutex::Mutex; +use sys::backtrace::BacktraceContext; +use sys_common::backtrace::Frame; -use super::super::printing::print; use unwind as uw; -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn write(w: &mut Write) -> io::Result<()> { - struct Context<'a> { - idx: isize, - writer: &'a mut (Write+'a), - last_error: Option<io::Error>, - } +struct Context<'a> { + idx: usize, + frames: &'a mut [Frame], +} - // When using libbacktrace, we use some necessary global state, so we - // need to prevent more than one thread from entering this block. This - // is semi-reasonable in terms of printing anyway, and we know that all - // I/O done here is blocking I/O, not green I/O, so we don't have to - // worry about this being a native vs green mutex. - static LOCK: Mutex = Mutex::new(); - unsafe { - LOCK.lock(); +#[derive(Debug)] +struct UnwindError(uw::_Unwind_Reason_Code); - writeln!(w, "stack backtrace:")?; +impl Error for UnwindError { + fn description(&self) -> &'static str { + "unexpected return value while unwinding" + } +} - let mut cx = Context { writer: w, last_error: None, idx: 0 }; - let ret = match { - uw::_Unwind_Backtrace(trace_fn, - &mut cx as *mut Context as *mut libc::c_void) - } { - uw::_URC_NO_REASON => { - match cx.last_error { - Some(err) => Err(err), - None => Ok(()) - } - } - _ => Ok(()), - }; - LOCK.unlock(); - return ret +impl ::fmt::Display for UnwindError { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + write!(f, "{}: {:?}", self.description(), self.0) } +} - extern fn trace_fn(ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { - let cx: &mut Context = unsafe { mem::transmute(arg) }; - let mut ip_before_insn = 0; - let mut ip = unsafe { - uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void - }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; +#[inline(never)] // if we know this is a function call, we can skip it when + // tracing +pub fn unwind_backtrace(frames: &mut [Frame]) + -> io::Result<(usize, BacktraceContext)> +{ + let mut cx = Context { + idx: 0, + frames: frames, + }; + let result_unwind = unsafe { + uw::_Unwind_Backtrace(trace_fn, + &mut cx as *mut Context + as *mut libc::c_void) + }; + // See libunwind:src/unwind/Backtrace.c for the return values. + // No, there is no doc. + match result_unwind { + uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR => { + Ok((cx.idx, BacktraceContext)) } - - // dladdr() on osx gets whiny when we use FindEnclosingFunction, and - // it appears to work fine without it, so we only use - // FindEnclosingFunction on non-osx platforms. In doing so, we get a - // slightly more accurate stack trace in the process. - // - // This is often because panic involves the last instruction of a - // function being "call std::rt::begin_unwind", with no ret - // instructions after it. This means that the return instruction - // pointer points *outside* of the calling function, and by - // unwinding it we go back to the original function. - let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { - ip - } else { - unsafe { uw::_Unwind_FindEnclosingFunction(ip) } - }; - - // Don't print out the first few frames (they're not user frames) - cx.idx += 1; - if cx.idx <= 0 { return uw::_URC_NO_REASON } - // Don't print ginormous backtraces - if cx.idx > 100 { - match write!(cx.writer, " ... <frames omitted>\n") { - Ok(()) => {} - Err(e) => { cx.last_error = Some(e); } - } - return uw::_URC_FAILURE + _ => { + Err(io::Error::new(io::ErrorKind::Other, + UnwindError(result_unwind))) } + } +} - // Once we hit an error, stop trying to print more frames - if cx.last_error.is_some() { return uw::_URC_FAILURE } +extern fn trace_fn(ctx: *mut uw::_Unwind_Context, + arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { + let cx = unsafe { &mut *(arg as *mut Context) }; + let mut ip_before_insn = 0; + let mut ip = unsafe { + uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void + }; + if !ip.is_null() && ip_before_insn == 0 { + // this is a non-signaling frame, so `ip` refers to the address + // after the calling instruction. account for that. + ip = (ip as usize - 1) as *mut _; + } - match print(cx.writer, cx.idx, ip, symaddr) { - Ok(()) => {} - Err(e) => { cx.last_error = Some(e); } - } + // dladdr() on osx gets whiny when we use FindEnclosingFunction, and + // it appears to work fine without it, so we only use + // FindEnclosingFunction on non-osx platforms. In doing so, we get a + // slightly more accurate stack trace in the process. + // + // This is often because panic involves the last instruction of a + // function being "call std::rt::begin_unwind", with no ret + // instructions after it. This means that the return instruction + // pointer points *outside* of the calling function, and by + // unwinding it we go back to the original function. + let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { + ip + } else { + unsafe { uw::_Unwind_FindEnclosingFunction(ip) } + }; - // keep going - uw::_URC_NO_REASON + if cx.idx < cx.frames.len() { + cx.frames[cx.idx] = Frame { + symbol_addr: symaddr, + exact_position: ip, + }; + cx.idx += 1; } + + uw::_URC_NO_REASON } 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/unix/backtrace/printing/gnu.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs index fb06fbedaf5..3e566f6e2bd 100644 --- a/src/libstd/sys/unix/backtrace/printing/gnu.rs +++ b/src/libstd/sys/windows/backtrace/printing/mod.rs @@ -8,4 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use sys_common::gnu::libbacktrace::print; +#[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 <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/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 <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 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 <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(()) - } - } -} |
