diff --git a/Cargo.lock b/Cargo.lock index 39ea2fbdf27..ebb27fafdb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,16 +105,23 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "autocfg" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "backtrace" -version = "0.3.11" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-std-workspace-core 1.0.0", ] [[package]] @@ -335,8 +342,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-std-workspace-core 1.0.0", +] [[package]] name = "chalk-engine" @@ -562,7 +573,7 @@ name = "crc32fast" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -598,7 +609,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -612,7 +623,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -624,7 +635,7 @@ name = "crossbeam-utils" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -632,7 +643,7 @@ name = "crossbeam-utils" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -814,7 +825,7 @@ name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -822,7 +833,7 @@ name = "error-chain" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -837,7 +848,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -862,7 +873,7 @@ name = "filetime" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1356,7 +1367,7 @@ name = "log" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1642,7 +1653,7 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1711,7 +1722,7 @@ version = "0.10.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1767,7 +1778,7 @@ name = "packed_simd" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2351,7 +2362,7 @@ name = "rustc" version = "0.0.0" dependencies = [ "arena 0.0.0", - "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2409,7 +2420,7 @@ name = "rustc-ap-rustc_data_structures" version = "407.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2481,7 +2492,7 @@ name = "rustc-ap-syntax_pos" version = "407.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-arena 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-rustc_data_structures 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-serialize 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2708,7 +2719,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3291,7 +3302,7 @@ name = "socket2" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3307,7 +3318,7 @@ name = "std" version = "0.0.0" dependencies = [ "alloc 0.0.0", - "backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", @@ -3319,7 +3330,6 @@ dependencies = [ "panic_unwind 0.0.0", "profiler_builtins 0.0.0", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_asan 0.0.0", "rustc_lsan 0.0.0", "rustc_msan 0.0.0", @@ -3462,7 +3472,7 @@ name = "syntax_pos" version = "0.0.0" dependencies = [ "arena 0.0.0", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", "rustc_macros 0.1.0", "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3486,7 +3496,7 @@ name = "tempfile" version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4091,7 +4101,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "18b65ea1161bfb2dd6da6fade5edd4dbd08fba85012123dd333d2fd1b90b2782" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "1c50b4cb6d852a8567d98bb11c03f91ccec4dfbd88778bc1b92789c624081283" "checksum backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "6ea90dd7b012b3d1a2cb6bec16670a0db2c95d4e931e84f4047e0460c1b34c8d" "checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a" "checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf" @@ -4109,7 +4120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010" "checksum cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "585784cac9b05c93a53b17a0b24a5cdd1dfdda5256f030e089b549d2390cc720" "checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "89431bba4e6b7092fb5fcd00a6f6ca596c55cc26b2f1e6dcdd08a1f4933f66b2" "checksum chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17ec698a6f053a23bfbe646d9f2fde4b02abc19125595270a99e6f44ae0bdd1a" "checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index c4c1170e539..d22dc9a71a4 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -23,8 +23,18 @@ compiler_builtins = { version = "0.1.15" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } hashbrown = { version = "0.3.0", features = ['rustc-dep-of-std'] } -rustc-demangle = { version = "0.1.10", features = ['rustc-dep-of-std'] } -backtrace-sys = { version = "0.1.24", features = ["rustc-dep-of-std"], optional = true } + +[dependencies.backtrace] +version = "0.3.25" +default-features = false # don't use coresymbolication on OSX +features = [ + "rustc-dep-of-std", # enable build support for integrating into libstd + "dbghelp", # backtrace/symbolize on MSVC + "libbacktrace", # symbolize on most platforms + "libunwind", # backtrace on most platforms + "dladdr", # symbolize on platforms w/o libbacktrace +] +optional = true [dev-dependencies] rand = "0.6.1" @@ -51,7 +61,6 @@ cc = "1.0" [features] default = ["std_detect_file_io", "std_detect_dlsym_getauxval"] -backtrace = ["backtrace-sys"] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] compiler-builtins-c = ["alloc/compiler-builtins-c"] diff --git a/src/libstd/sys/cloudabi/backtrace.rs b/src/libstd/sys/cloudabi/backtrace.rs deleted file mode 100644 index 17719a29b6e..00000000000 --- a/src/libstd/sys/cloudabi/backtrace.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::error::Error; -use crate::ffi::CStr; -use crate::fmt; -use crate::intrinsics; -use crate::io; -use crate::sys_common::backtrace::Frame; - -use unwind as uw; - -pub struct BacktraceContext; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[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 }; - 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 { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => Err(io::Error::new( - io::ErrorKind::Other, - UnwindError(result_unwind), - )), - } -} - -extern "C" 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<'_>) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - 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 _; - } - - let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) }; - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} - -pub fn foreach_symbol_fileline(_: Frame, _: F, _: &BacktraceContext) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, -{ - // No way to obtain this information on CloudABI. - Ok(false) -} - -pub fn resolve_symname(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 as *mut _, &mut info) == 0 || info.dli_sname.is_null() { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -#[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 "C" { - fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; -} diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs index 3f8e67a7af8..c3b8bbd0426 100644 --- a/src/libstd/sys/cloudabi/mod.rs +++ b/src/libstd/sys/cloudabi/mod.rs @@ -4,8 +4,6 @@ #[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; #[path = "../unix/cmath.rs"] pub mod cmath; pub mod condvar; diff --git a/src/libstd/sys/redox/backtrace/mod.rs b/src/libstd/sys/redox/backtrace/mod.rs deleted file mode 100644 index 8ea2783580a..00000000000 --- a/src/libstd/sys/redox/backtrace/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -/// See sys/unix/backtrace/mod.rs for an explanation of the method used here. - -pub use self::tracing::unwind_backtrace; -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; - -// tracing impls: -mod tracing; -// symbol resolvers: -mod printing; - -pub mod gnu { - use crate::io; - use crate::fs; - use crate::vec::Vec; - use crate::ffi::OsStr; - use crate::os::unix::ffi::OsStrExt; - use crate::io::Read; - use libc::c_char; - - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - let mut exefile = fs::File::open("sys:exe")?; - let mut exename = Vec::new(); - exefile.read_to_end(&mut exename)?; - if exename.last() == Some(&b'\n') { - exename.pop(); - } - let file = fs::File::open(OsStr::from_bytes(&exename))?; - Ok((exename.into_iter().map(|c| c as c_char).collect(), file)) - } -} - -pub struct BacktraceContext; diff --git a/src/libstd/sys/redox/backtrace/printing.rs b/src/libstd/sys/redox/backtrace/printing.rs deleted file mode 100644 index 489eed4562d..00000000000 --- a/src/libstd/sys/redox/backtrace/printing.rs +++ /dev/null @@ -1 +0,0 @@ -pub use crate::sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; diff --git a/src/libstd/sys/redox/backtrace/tracing.rs b/src/libstd/sys/redox/backtrace/tracing.rs deleted file mode 100644 index 13f34338fd3..00000000000 --- a/src/libstd/sys/redox/backtrace/tracing.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::error::Error; -use crate::fmt; -use crate::io; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -use unwind as uw; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[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 { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => { - Err(io::Error::new(io::ErrorKind::Other, - UnwindError(result_unwind))) - } - } -} - -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<'_>) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - 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 _; - } - - // 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) } - }; - - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index 0e8ed8e303d..354184f8af6 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -8,8 +8,6 @@ #[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; pub mod cmath; pub mod condvar; pub mod env; diff --git a/src/libstd/sys/sgx/backtrace.rs b/src/libstd/sys/sgx/backtrace.rs deleted file mode 100644 index 326737a2418..00000000000 --- a/src/libstd/sys/sgx/backtrace.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::io; -use crate::error::Error; -use crate::fmt; -use crate::sys_common::backtrace::Frame; -use crate::sys::sgx::abi::mem::image_base; - -use unwind as uw; - -pub struct BacktraceContext; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // this function call can be skipped it when tracing. -pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { - let mut cx = Context { idx: 0, 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. - let res = match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => Err(io::Error::new( - io::ErrorKind::Other, - UnwindError(result_unwind), - )), - }; - res -} - -extern "C" 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<'_>) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - 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 _; - } - - let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) }; - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} - -// To reduce TCB size in Sgx enclave, we do not want to implement resolve_symname functionality. -// Rather, we print the offset of the address here, which could be later mapped to correct function. -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - callback(Some(&format!("0x{:x}", - (frame.symbol_addr.wrapping_offset_from(image_base() as _))))) -} - -pub fn foreach_symbol_fileline(_: Frame, - _: F, - _: &BacktraceContext) -> io::Result - where F: FnMut(&[u8], u32) -> io::Result<()> -{ - Ok(false) -} diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index a99a534f41e..01f5536ed7a 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -12,8 +12,6 @@ pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; pub mod cmath; pub mod condvar; pub mod env; diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs deleted file mode 100644 index 0887e5a4df9..00000000000 --- a/src/libstd/sys/unix/backtrace/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -/// Backtrace support built on libgcc with some extra OS-specific support -/// -/// Some methods of getting a backtrace: -/// -/// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on macOS, and the address to symbol portion of it -/// suffers problems that are described below. -/// -/// * Using libunwind. This is more difficult than it sounds because libunwind -/// isn't installed everywhere by default. It's also a bit of a hefty library, -/// so possibly not the best option. When testing, libunwind was excellent at -/// getting both accurate backtraces and accurate symbols across platforms. -/// This route was not chosen in favor of the next option, however. -/// -/// * We're already using libgcc_s for exceptions in rust (triggering thread -/// unwinding and running destructors on the stack), and it turns out that it -/// conveniently comes with a function that also gives us a backtrace. All of -/// these functions look like _Unwind_*, but it's not quite the full -/// repertoire of the libunwind API. Due to it already being in use, this was -/// the chosen route of getting a backtrace. -/// -/// After choosing libgcc_s for backtraces, the sad part is that it will only -/// give us a stack trace of instruction pointers. Thankfully these instruction -/// pointers are accurate (they work for green and native threads), but it's -/// then up to us again to figure out how to translate these addresses to -/// symbols. As with before, we have a few options. Before, that, a little bit -/// of an interlude about symbols. This is my very limited knowledge about -/// symbol tables, and this information is likely slightly wrong, but the -/// general idea should be correct. -/// -/// When talking about symbols, it's helpful to know a few things about where -/// symbols are located. Some symbols are located in the dynamic symbol table -/// of the executable which in theory means that they're available for dynamic -/// linking and lookup. Other symbols end up only in the local symbol table of -/// the file. This loosely corresponds to pub and priv functions in Rust. -/// -/// Armed with this knowledge, we know that our solution for address to symbol -/// translation will need to consult both the local and dynamic symbol tables. -/// With that in mind, here's our options of translating an address to -/// a symbol. -/// -/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() -/// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on macOS. It appears dladdr() -/// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for macOS, this is the -/// method used for translation. It's provided by the system and easy to do.o -/// -/// Sadly, all other systems have a dladdr() implementation that does not -/// consult the local symbol table. This means that most functions are blank -/// because they don't have symbols. This means that we need another solution. -/// -/// * Use unw_get_proc_name(). This is part of the libunwind api (not the -/// libgcc_s version of the libunwind api), but involves taking a dependency -/// to libunwind. We may pursue this route in the future if we bundle -/// libunwind, but libunwind was unwieldy enough that it was not chosen at -/// this time to provide this functionality. -/// -/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a -/// semi-reasonable solution. The stdlib already knows how to spawn processes, -/// so in theory it could invoke readelf, parse the output, and consult the -/// local/dynamic symbol tables from there. This ended up not getting chosen -/// due to the craziness of the idea plus the advent of the next option. -/// -/// * Use `libbacktrace`. It turns out that this is a small library bundled in -/// the gcc repository which provides backtrace and symbol translation -/// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not macOS, so this is the -/// chosen route for now. -/// -/// In summary, the current situation uses libgcc_s to get a trace of stack -/// pointers, and we use dladdr() or libbacktrace to translate these addresses -/// 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::unwind_backtrace; -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; - -// tracing impls: -mod tracing; -// symbol resolvers: -mod printing; - -#[cfg(not(target_os = "emscripten"))] -pub mod gnu { - use crate::io; - use crate::fs; - - use libc::c_char; - - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - use crate::env; - use crate::os::unix::ffi::OsStrExt; - - let filename = env::current_exe()?; - let file = fs::File::open(&filename)?; - let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter() - .map(|&x| x as c_char).collect(); - filename_cstr.push(0); // Null terminate - Ok((filename_cstr, file)) - } -} - -pub struct BacktraceContext; diff --git a/src/libstd/sys/unix/backtrace/printing/dladdr.rs b/src/libstd/sys/unix/backtrace/printing/dladdr.rs deleted file mode 100644 index cf3bda640e9..00000000000 --- a/src/libstd/sys/unix/backtrace/printing/dladdr.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::io; -use crate::intrinsics; -use crate::ffi::CStr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -pub fn resolve_symname(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 as *mut _, &mut info) == 0 || - info.dli_sname.is_null() { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -#[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 deleted file mode 100644 index d090caede43..00000000000 --- a/src/libstd/sys/unix/backtrace/printing/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -mod dladdr; - -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; -use crate::io; - -#[cfg(target_os = "emscripten")] -pub use self::dladdr::resolve_symname; - -#[cfg(target_os = "emscripten")] -pub fn foreach_symbol_fileline(_: Frame, _: F, _: &BacktraceContext) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()> -{ - Ok(false) -} - -#[cfg(not(target_os = "emscripten"))] -pub use crate::sys_common::gnu::libbacktrace::foreach_symbol_fileline; - -#[cfg(not(target_os = "emscripten"))] -pub fn resolve_symname(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()> -{ - crate::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| { - if symname.is_some() { - callback(symname) - } else { - dladdr::resolve_symname(frame, callback, bc) - } - }, bc) -} diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs deleted file mode 100644 index a628d107ad6..00000000000 --- a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// As always - iOS on arm uses SjLj exceptions and -/// _Unwind_Backtrace is even not available there. Still, -/// backtraces could be extracted using a backtrace function, -/// which thanks god is public -/// -/// As mentioned in a huge comment block in `super::super`, backtrace -/// doesn't play well with green threads, so while it is extremely nice and -/// simple to use it should be used only on iOS devices as the only viable -/// option. - -use crate::io; -use crate::ptr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -#[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 = [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 as *mut u8, - symbol_addr: *from as *mut u8, - inline_context: 0, - }; - } - Ok((nb_frames as usize, BacktraceContext)) -} - -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 deleted file mode 100644 index e6379132baf..00000000000 --- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::error::Error; -use crate::fmt; -use crate::io; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -use unwind as uw; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[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, - }; - 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 { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => { - Err(io::Error::new(io::ErrorKind::Other, - UnwindError(result_unwind))) - } - } -} - -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<'_>) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - 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 _; - } - - // 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) } - }; - - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} diff --git a/src/libstd/sys/unix/backtrace/tracing/mod.rs b/src/libstd/sys/unix/backtrace/tracing/mod.rs deleted file mode 100644 index 11863e64545..00000000000 --- a/src/libstd/sys/unix/backtrace/tracing/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub use self::imp::*; - -#[cfg(not(all(target_os = "ios", target_arch = "arm")))] -#[path = "gcc_s.rs"] -mod imp; -#[cfg(all(target_os = "ios", target_arch = "arm"))] -#[path = "backtrace_fn.rs"] -mod imp; diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index c2b264ff8de..821623db272 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -27,8 +27,6 @@ pub mod alloc; pub mod args; pub mod android; -#[cfg(feature = "backtrace")] -pub mod backtrace; pub mod cmath; pub mod condvar; pub mod env; diff --git a/src/libstd/sys/wasi/backtrace.rs b/src/libstd/sys/wasi/backtrace.rs deleted file mode 100644 index 7d56b298997..00000000000 --- a/src/libstd/sys/wasi/backtrace.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::io; -use crate::sys::unsupported; -use crate::sys_common::backtrace::Frame; - -pub struct BacktraceContext; - -pub fn unwind_backtrace(_frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - unsupported() -} - -pub fn resolve_symname(_frame: Frame, - _callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - unsupported() -} - -pub fn foreach_symbol_fileline(_: Frame, - _: F, - _: &BacktraceContext) -> io::Result - where F: FnMut(&[u8], u32) -> io::Result<()> -{ - unsupported() -} diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs index a9bb0151d05..e22434439f5 100644 --- a/src/libstd/sys/wasi/mod.rs +++ b/src/libstd/sys/wasi/mod.rs @@ -21,8 +21,6 @@ pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; #[path = "../wasm/cmath.rs"] pub mod cmath; #[path = "../wasm/condvar.rs"] diff --git a/src/libstd/sys/wasm/backtrace.rs b/src/libstd/sys/wasm/backtrace.rs deleted file mode 100644 index 7d56b298997..00000000000 --- a/src/libstd/sys/wasm/backtrace.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::io; -use crate::sys::unsupported; -use crate::sys_common::backtrace::Frame; - -pub struct BacktraceContext; - -pub fn unwind_backtrace(_frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - unsupported() -} - -pub fn resolve_symname(_frame: Frame, - _callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - unsupported() -} - -pub fn foreach_symbol_fileline(_: Frame, - _: F, - _: &BacktraceContext) -> io::Result - where F: FnMut(&[u8], u32) -> io::Result<()> -{ - unsupported() -} diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index 670d07de1d1..9ea8bd16538 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -23,8 +23,6 @@ pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; pub mod cmath; pub mod env; pub mod fs; diff --git a/src/libstd/sys/windows/backtrace/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs deleted file mode 100644 index 7ac1f8122f7..00000000000 --- a/src/libstd/sys/windows/backtrace/backtrace_gnu.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::io; -use crate::sys::c; -use crate::path::PathBuf; -use crate::fs::{OpenOptions, File}; -use crate::sys::ext::fs::OpenOptionsExt; -use crate::sys::handle::Handle; - -use libc::c_char; -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 deleted file mode 100644 index c5b0cc87210..00000000000 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ /dev/null @@ -1,355 +0,0 @@ -//! 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 crate::io; -use crate::mem; -use crate::ptr; -use crate::sys::c; -use crate::sys::dynamic_lib::DynamicLibrary; -use crate::sys_common::backtrace::Frame; - -use libc::c_void; - -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::{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)> { - 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)?; - - // 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 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)); - } - - // 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(StackWalk: W, frames: &mut [Frame]) -> io::Result { - 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; - 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: frame.get_inline_context(), - }; - - 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; - fn get_inline_context(&self) -> u32; -} - -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 = "arm")] - 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.R11 as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_ARMNT - } - - #[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 - } - - fn get_inline_context(&self) -> u32 { - self.InlineFrameContext - } -} - -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 = "arm")] - 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.R11 as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_ARMNT - } - - #[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 - } - - fn get_inline_context(&self) -> u32 { - 0 - } -} - -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); - } - } -} diff --git a/src/libstd/sys/windows/backtrace/printing/mod.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs deleted file mode 100644 index 9497d51ac17..00000000000 --- a/src/libstd/sys/windows/backtrace/printing/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -#[cfg(target_env = "msvc")] -#[path = "msvc.rs"] -mod printing; - -#[cfg(target_env = "gnu")] -mod printing { - pub use crate::sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; - - // dummy functions to mirror those present in msvc version. - use crate::sys::dynamic_lib::DynamicLibrary; - use crate::io; - pub struct PrintingFnsEx {} - pub struct PrintingFns64 {} - pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result { - Ok(PrintingFnsEx{}) - } - pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result { - Ok(PrintingFns64{}) - } -} - -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; -pub use self::printing::{load_printing_fns_ex, load_printing_fns_64, - PrintingFnsEx, PrintingFns64}; diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs deleted file mode 100644 index 13a1512d0eb..00000000000 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ /dev/null @@ -1,208 +0,0 @@ -use crate::ffi::CStr; -use crate::io; -use crate::mem; -use crate::sys::backtrace::BacktraceContext; -use crate::sys::backtrace::StackWalkVariant; -use crate::sys::c; -use crate::sys::dynamic_lib::DynamicLibrary; -use crate::sys_common::backtrace::Frame; - -use libc::{c_char, c_ulong}; - -// Structs holding printing functions and loaders for them -// Two versions depending on whether dbghelp.dll has StackWalkEx or not -// (the former being in newer Windows versions, the older being in Win7 and before) -pub struct PrintingFnsEx { - resolve_symname: SymFromInlineContextFn, - sym_get_line: SymGetLineFromInlineContextFn, -} -pub struct PrintingFns64 { - resolve_symname: SymFromAddrFn, - sym_get_line: SymGetLineFromAddr64Fn, -} - -pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result { - Ok(PrintingFnsEx { - resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?, - sym_get_line: sym!( - dbghelp, - "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn - )?, - }) -} -pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result { - Ok(PrintingFns64 { - resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?, - sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?, - }) -} - -type SymFromAddrFn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; -type SymFromInlineContextFn = - unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *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; -type SymGetLineFromInlineContextFn = unsafe extern "system" fn( - c::HANDLE, - u64, - c::ULONG, - u64, - *mut c::DWORD, - *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<()>, -{ - match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal( - |process: c::HANDLE, - symbol_address: u64, - inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO| unsafe { - let mut displacement = 0u64; - (fns.resolve_symname)( - process, - symbol_address, - inline_context, - &mut displacement, - info, - ) - }, - frame, - callback, - context, - ), - StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal( - |process: c::HANDLE, - symbol_address: u64, - _inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO| unsafe { - let mut displacement = 0u64; - (fns.resolve_symname)(process, symbol_address, &mut displacement, info) - }, - frame, - callback, - context, - ), - } -} - -fn resolve_symname_internal( - mut symbol_resolver: R, - frame: Frame, - callback: F, - context: &BacktraceContext, -) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()>, - R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL, -{ - 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 ret = symbol_resolver( - context.handle, - frame.symbol_addr as u64, - frame.inline_context, - &mut info, - ); - let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { - if info.Size != 0 { - (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize - } else { - true - } - } else { - false - }; - let symname = if valid_range { - 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, - callback: F, - context: &BacktraceContext, -) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, -{ - match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal( - |process: c::HANDLE, - frame_address: u64, - inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64| unsafe { - let mut displacement = 0u32; - (fns.sym_get_line)( - process, - frame_address, - inline_context, - 0, - &mut displacement, - line, - ) - }, - frame, - callback, - context, - ), - StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal( - |process: c::HANDLE, - frame_address: u64, - _inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64| unsafe { - let mut displacement = 0u32; - (fns.sym_get_line)(process, frame_address, &mut displacement, line) - }, - frame, - callback, - context, - ), - } -} - -fn foreach_symbol_fileline_iternal( - mut line_getter: G, - frame: Frame, - mut callback: F, - context: &BacktraceContext, -) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, - G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL, -{ - unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = mem::size_of::() as u32; - - let ret = line_getter( - context.handle, - frame.exact_position as u64, - frame.inline_context, - &mut line, - ); - if ret == c::TRUE { - let name = CStr::from_ptr(line.Filename).to_bytes(); - callback(name, line.LineNumber as u32)?; - } - Ok(false) - } -} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 518eccf754c..6ad338660c3 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -5,8 +5,6 @@ #![unstable(issue = "0", feature = "windows_c")] use crate::os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort, c_char}; -#[cfg(target_arch = "x86_64")] -use crate::os::raw::c_ulonglong; use crate::ptr; use libc::{wchar_t, size_t, c_void}; @@ -33,10 +31,6 @@ pub type CHAR = c_char; pub type ULONG_PTR = usize; pub type ULONG = c_ulong; -#[cfg(target_arch = "x86_64")] -pub type ULONGLONG = u64; -#[cfg(target_arch = "x86_64")] -pub type DWORDLONG = ULONGLONG; pub type LPBOOL = *mut BOOL; pub type LPBYTE = *mut BYTE; @@ -108,11 +102,6 @@ pub const FIONBIO: c_ulong = 0x8004667e; -#[cfg(target_arch = "arm")] -const ARM_MAX_BREAKPOINTS: usize = 8; -#[cfg(target_arch = "arm")] -const ARM_MAX_WATCHPOINTS: usize = 1; - #[repr(C)] #[derive(Copy)] pub struct WIN32_FIND_DATAW { @@ -270,22 +259,6 @@ pub struct ipv6_mreq { pub const WAIT_TIMEOUT: DWORD = 258; pub const WAIT_FAILED: DWORD = 0xFFFFFFFF; -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub const MAX_SYM_NAME: usize = 2000; -#[cfg(target_arch = "x86")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c; -#[cfg(target_arch = "x86_64")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664; -#[cfg(target_arch = "aarch64")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64; -#[cfg(target_arch = "arm")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_ARMNT: DWORD = 0x01c4; - pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; @@ -580,41 +553,6 @@ pub struct OVERLAPPED { pub hEvent: HANDLE, } -#[repr(C)] -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub struct SYMBOL_INFO { - pub SizeOfStruct: c_ulong, - pub TypeIndex: c_ulong, - pub Reserved: [u64; 2], - pub Index: c_ulong, - pub Size: c_ulong, - pub ModBase: u64, - pub Flags: c_ulong, - pub Value: u64, - pub Address: u64, - pub Register: c_ulong, - pub Scope: c_ulong, - pub Tag: c_ulong, - pub NameLen: c_ulong, - pub MaxNameLen: c_ulong, - // note that windows has this as 1, but it basically just means that - // the name is inline at the end of the struct. For us, we just bump - // the struct size up to MAX_SYM_NAME. - pub Name: [c_char; MAX_SYM_NAME], -} - -#[repr(C)] -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub struct IMAGEHLP_LINE64 { - pub SizeOfStruct: u32, - pub Key: *const c_void, - pub LineNumber: u32, - pub Filename: *const c_char, - pub Address: u64, -} - #[repr(C)] #[allow(dead_code)] // we only use some variants pub enum ADDRESS_MODE { @@ -624,280 +562,8 @@ pub enum ADDRESS_MODE { AddrModeFlat, } -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct ADDRESS64 { - pub Offset: u64, - pub Segment: u16, - pub Mode: ADDRESS_MODE, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct STACKFRAME_EX { - pub AddrPC: ADDRESS64, - pub AddrReturn: ADDRESS64, - pub AddrFrame: ADDRESS64, - pub AddrStack: ADDRESS64, - pub AddrBStore: ADDRESS64, - pub FuncTableEntry: *mut c_void, - pub Params: [u64; 4], - pub Far: BOOL, - pub Virtual: BOOL, - pub Reserved: [u64; 3], - pub KdHelp: KDHELP64, - pub StackFrameSize: DWORD, - pub InlineFrameContext: DWORD, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct STACKFRAME64 { - pub AddrPC: ADDRESS64, - pub AddrReturn: ADDRESS64, - pub AddrFrame: ADDRESS64, - pub AddrStack: ADDRESS64, - pub AddrBStore: ADDRESS64, - pub FuncTableEntry: *mut c_void, - pub Params: [u64; 4], - pub Far: BOOL, - pub Virtual: BOOL, - pub Reserved: [u64; 3], - pub KdHelp: KDHELP64, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct KDHELP64 { - pub Thread: u64, - pub ThCallbackStack: DWORD, - pub ThCallbackBStore: DWORD, - pub NextCallback: DWORD, - pub FramePointer: DWORD, - pub KiCallUserMode: u64, - pub KeUserCallbackDispatcher: u64, - pub SystemRangeStart: u64, - pub KiUserExceptionDispatcher: u64, - pub StackBase: u64, - pub StackLimit: u64, - pub Reserved: [u64; 5], -} - -#[cfg(target_arch = "x86")] -#[repr(C)] -pub struct CONTEXT { - pub ContextFlags: DWORD, - pub Dr0: DWORD, - pub Dr1: DWORD, - pub Dr2: DWORD, - pub Dr3: DWORD, - pub Dr6: DWORD, - pub Dr7: DWORD, - pub FloatSave: FLOATING_SAVE_AREA, - pub SegGs: DWORD, - pub SegFs: DWORD, - pub SegEs: DWORD, - pub SegDs: DWORD, - pub Edi: DWORD, - pub Esi: DWORD, - pub Ebx: DWORD, - pub Edx: DWORD, - pub Ecx: DWORD, - pub Eax: DWORD, - pub Ebp: DWORD, - pub Eip: DWORD, - pub SegCs: DWORD, - pub EFlags: DWORD, - pub Esp: DWORD, - pub SegSs: DWORD, - pub ExtendedRegisters: [u8; 512], -} - -#[cfg(target_arch = "x86")] -#[repr(C)] -pub struct FLOATING_SAVE_AREA { - pub ControlWord: DWORD, - pub StatusWord: DWORD, - pub TagWord: DWORD, - pub ErrorOffset: DWORD, - pub ErrorSelector: DWORD, - pub DataOffset: DWORD, - pub DataSelector: DWORD, - pub RegisterArea: [u8; 80], - pub Cr0NpxState: DWORD, -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct CONTEXT { - pub P1Home: DWORDLONG, - pub P2Home: DWORDLONG, - pub P3Home: DWORDLONG, - pub P4Home: DWORDLONG, - pub P5Home: DWORDLONG, - pub P6Home: DWORDLONG, - - pub ContextFlags: DWORD, - pub MxCsr: DWORD, - - pub SegCs: WORD, - pub SegDs: WORD, - pub SegEs: WORD, - pub SegFs: WORD, - pub SegGs: WORD, - pub SegSs: WORD, - pub EFlags: DWORD, - - pub Dr0: DWORDLONG, - pub Dr1: DWORDLONG, - pub Dr2: DWORDLONG, - pub Dr3: DWORDLONG, - pub Dr6: DWORDLONG, - pub Dr7: DWORDLONG, - - pub Rax: DWORDLONG, - pub Rcx: DWORDLONG, - pub Rdx: DWORDLONG, - pub Rbx: DWORDLONG, - pub Rsp: DWORDLONG, - pub Rbp: DWORDLONG, - pub Rsi: DWORDLONG, - pub Rdi: DWORDLONG, - pub R8: DWORDLONG, - pub R9: DWORDLONG, - pub R10: DWORDLONG, - pub R11: DWORDLONG, - pub R12: DWORDLONG, - pub R13: DWORDLONG, - pub R14: DWORDLONG, - pub R15: DWORDLONG, - - pub Rip: DWORDLONG, - - pub FltSave: FLOATING_SAVE_AREA, - - pub VectorRegister: [M128A; 26], - pub VectorControl: DWORDLONG, - - pub DebugControl: DWORDLONG, - pub LastBranchToRip: DWORDLONG, - pub LastBranchFromRip: DWORDLONG, - pub LastExceptionToRip: DWORDLONG, - pub LastExceptionFromRip: DWORDLONG, -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct M128A { - pub Low: c_ulonglong, - pub High: c_longlong -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct FLOATING_SAVE_AREA { - _Dummy: [u8; 512] // FIXME: Fill this out -} - -#[cfg(target_arch = "arm")] -#[repr(C)] -pub struct CONTEXT { - pub ContextFlags: ULONG, - pub R0: ULONG, - pub R1: ULONG, - pub R2: ULONG, - pub R3: ULONG, - pub R4: ULONG, - pub R5: ULONG, - pub R6: ULONG, - pub R7: ULONG, - pub R8: ULONG, - pub R9: ULONG, - pub R10: ULONG, - pub R11: ULONG, - pub R12: ULONG, - pub Sp: ULONG, - pub Lr: ULONG, - pub Pc: ULONG, - pub Cpsr: ULONG, - pub Fpscr: ULONG, - pub Padding: ULONG, - pub D: [u64; 32], - pub Bvr: [ULONG; ARM_MAX_BREAKPOINTS], - pub Bcr: [ULONG; ARM_MAX_BREAKPOINTS], - pub Wvr: [ULONG; ARM_MAX_WATCHPOINTS], - pub Wcr: [ULONG; ARM_MAX_WATCHPOINTS], - pub Padding2: [ULONG; 2] -} - -// FIXME(#43348): This structure is used for backtrace only, and a fake -// definition is provided here only to allow rustdoc to pass type-check. This -// will not appear in the final documentation. This should be also defined for -// other architectures supported by Windows such as ARM, and for historical -// interest, maybe MIPS and PowerPC as well. -#[cfg(all(rustdoc, not(any(target_arch = "x86_64", target_arch = "x86", - target_arch = "aarch64", target_arch = "arm"))))] pub enum CONTEXT {} -#[cfg(target_arch = "aarch64")] -pub const ARM64_MAX_BREAKPOINTS: usize = 8; - -#[cfg(target_arch = "aarch64")] -pub const ARM64_MAX_WATCHPOINTS: usize = 2; - -#[cfg(target_arch = "aarch64")] -#[repr(C)] -pub struct ARM64_NT_NEON128 { - pub D: [f64; 2], -} - -#[cfg(target_arch = "aarch64")] -#[repr(C, align(16))] -pub struct CONTEXT { - pub ContextFlags: DWORD, - pub Cpsr: DWORD, - pub X0: u64, - pub X1: u64, - pub X2: u64, - pub X3: u64, - pub X4: u64, - pub X5: u64, - pub X6: u64, - pub X7: u64, - pub X8: u64, - pub X9: u64, - pub X10: u64, - pub X11: u64, - pub X12: u64, - pub X13: u64, - pub X14: u64, - pub X15: u64, - pub X16: u64, - pub X17: u64, - pub X18: u64, - pub X19: u64, - pub X20: u64, - pub X21: u64, - pub X22: u64, - pub X23: u64, - pub X24: u64, - pub X25: u64, - pub X26: u64, - pub X27: u64, - pub X28: u64, - pub Fp: u64, - pub Lr: u64, - pub Sp: u64, - pub Pc: u64, - pub V: [ARM64_NT_NEON128; 32], - pub Fpcr: DWORD, - pub Fpsr: DWORD, - pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS], - pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS], - pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS], - pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS], -} - #[repr(C)] pub struct SOCKADDR_STORAGE_LH { pub ss_family: ADDRESS_FAMILY, @@ -1220,8 +886,6 @@ pub fn FindFirstFileW(fileName: LPCWSTR, pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL; pub fn FindClose(findFile: HANDLE) -> BOOL; - #[cfg(feature = "backtrace")] - pub fn RtlCaptureContext(ctx: *mut CONTEXT); pub fn getsockopt(s: SOCKET, level: c_int, optname: c_int, @@ -1252,10 +916,6 @@ pub fn getaddrinfo(node: *const c_char, service: *const c_char, res: *mut *mut ADDRINFOA) -> c_int; pub fn freeaddrinfo(res: *mut ADDRINFOA); - #[cfg(feature = "backtrace")] - pub fn LoadLibraryW(name: LPCWSTR) -> HMODULE; - #[cfg(feature = "backtrace")] - pub fn FreeLibrary(handle: HMODULE) -> BOOL; pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void; pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; @@ -1361,34 +1021,3 @@ pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN { panic!("rwlocks not available") } } - -#[cfg(all(target_env = "gnu", feature = "backtrace"))] -mod gnu { - use super::*; - - pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400; - - pub const CP_ACP: UINT = 0; - - pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400; - - extern "system" { - pub fn OpenProcess(dwDesiredAccess: DWORD, - bInheritHandle: BOOL, - dwProcessId: DWORD) -> HANDLE; - } - - compat_fn! { - kernel32: - - pub fn QueryFullProcessImageNameW(_hProcess: HANDLE, - _dwFlags: DWORD, - _lpExeName: LPWSTR, - _lpdwSize: LPDWORD) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - } -} - -#[cfg(all(target_env = "gnu", feature = "backtrace"))] -pub use self::gnu::*; diff --git a/src/libstd/sys/windows/dynamic_lib.rs b/src/libstd/sys/windows/dynamic_lib.rs deleted file mode 100644 index b9d5105cb73..00000000000 --- a/src/libstd/sys/windows/dynamic_lib.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::os::windows::prelude::*; - -use crate::ffi::{CString, OsStr}; -use crate::io; -use crate::sys::c; - -pub struct DynamicLibrary { - handle: c::HMODULE, -} - -impl DynamicLibrary { - pub fn open(filename: &str) -> io::Result { - let filename = OsStr::new(filename) - .encode_wide() - .chain(Some(0)) - .collect::>(); - let result = unsafe { - c::LoadLibraryW(filename.as_ptr()) - }; - if result.is_null() { - Err(io::Error::last_os_error()) - } else { - Ok(DynamicLibrary { handle: result }) - } - } - - pub fn symbol(&self, symbol: &str) -> io::Result { - let symbol = CString::new(symbol)?; - unsafe { - match c::GetProcAddress(self.handle, symbol.as_ptr()) as usize { - 0 => Err(io::Error::last_os_error()), - n => Ok(n), - } - } - } -} - -impl Drop for DynamicLibrary { - fn drop(&mut self) { - unsafe { - c::FreeLibrary(self.handle); - } - } -} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 1425254a2e1..1cb55539129 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -14,13 +14,9 @@ pub mod alloc; pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; pub mod c; pub mod cmath; pub mod condvar; -#[cfg(feature = "backtrace")] -pub mod dynamic_lib; pub mod env; pub mod ext; pub mod fast_thread_local; diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 8d8d8169b43..a01b31e948b 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -2,40 +2,17 @@ /// supported platforms. use crate::env; -use crate::io::prelude::*; use crate::io; +use crate::io::prelude::*; +use crate::mem; use crate::path::{self, Path}; use crate::ptr; -use crate::str; use crate::sync::atomic::{self, Ordering}; use crate::sys::mutex::Mutex; -use rustc_demangle::demangle; +use backtrace::{BytesOrWideString, Frame, Symbol}; -pub use crate::sys::backtrace::{ - unwind_backtrace, - resolve_symname, - foreach_symbol_fileline, - BacktraceContext -}; - -#[cfg(target_pointer_width = "64")] -pub const HEX_WIDTH: usize = 18; - -#[cfg(target_pointer_width = "32")] -pub const HEX_WIDTH: usize = 10; - -/// Represents an item in the backtrace list. See `unwind_backtrace` for how -/// it is created. -#[derive(Debug, Copy, Clone)] -pub struct Frame { - /// Exact address of the call that failed. - pub exact_position: *const u8, - /// Address of the enclosing function. - pub symbol_addr: *const u8, - /// Which inlined function is this frame referring to - pub inline_context: u32, -} +pub const HEX_WIDTH: usize = 2 + 2 * mem::size_of::(); /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; @@ -49,7 +26,7 @@ pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { // test mode immediately return here to optimize away any references to the // libbacktrace symbols if cfg!(test) { - return Ok(()) + return Ok(()); } // Use a lock to prevent mixed output in multithreading context. @@ -63,75 +40,39 @@ pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { } fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { - let mut frames = [Frame { - exact_position: ptr::null(), - symbol_addr: ptr::null(), - inline_context: 0, - }; MAX_NB_FRAMES]; - let (nb_frames, context) = unwind_backtrace(&mut frames)?; - let (skipped_before, skipped_after) = - filter_frames(&frames[..nb_frames], format, &context); - if skipped_before + skipped_after > 0 { - writeln!(w, "note: Some details are omitted, \ - run with `RUST_BACKTRACE=full` for a verbose backtrace.")?; - } writeln!(w, "stack backtrace:")?; - let filtered_frames = &frames[..nb_frames - skipped_after]; - for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() { - resolve_symname(*frame, |symname| { - output(w, index, *frame, symname, format) - }, &context)?; - let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| { - output_fileline(w, file, line, format) - }, &context)?; - if has_more_filenames { - w.write_all(b" <... and possibly more>")?; - } + let mut printer = Printer::new(format, w); + unsafe { + backtrace::trace_unsynchronized(|frame| { + let mut hit = false; + backtrace::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; + printer.output(frame, Some(symbol)); + }); + if !hit { + printer.output(frame, None); + } + !printer.done + }); + } + if printer.skipped { + writeln!( + w, + "note: Some details are omitted, \ + run with `RUST_BACKTRACE=full` for a verbose backtrace." + )?; } - Ok(()) } -/// Returns a number of frames to remove at the beginning and at the end of the -/// backtrace, according to the backtrace format. -fn filter_frames(frames: &[Frame], - format: PrintFormat, - context: &BacktraceContext) -> (usize, usize) -{ - if format == PrintFormat::Full { - return (0, 0); - } - - let skipped_before = 0; - - let skipped_after = frames.len() - frames.iter().position(|frame| { - let mut is_marker = false; - let _ = resolve_symname(*frame, |symname| { - if let Some(mangled_symbol_name) = symname { - // Use grep to find the concerned functions - if mangled_symbol_name.contains("__rust_begin_short_backtrace") { - is_marker = true; - } - } - Ok(()) - }, context); - is_marker - }).unwrap_or(frames.len()); - - if skipped_before + skipped_after >= frames.len() { - // Avoid showing completely empty backtraces - return (0, 0); - } - - (skipped_before, skipped_after) -} - - /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. #[inline(never)] pub fn __rust_begin_short_backtrace(f: F) -> T - where F: FnOnce() -> T, F: Send, T: Send +where + F: FnOnce() -> T, + F: Send, + T: Send, { f() } @@ -156,7 +97,7 @@ pub fn log_enabled() -> Option { _ => return Some(PrintFormat::Full), } - let val = env::var_os("RUST_BACKTRACE").and_then(|x| + let val = env::var_os("RUST_BACKTRACE").and_then(|x| { if &x == "0" { None } else if &x == "full" { @@ -164,80 +105,141 @@ pub fn log_enabled() -> Option { } else { Some(PrintFormat::Short) } + }); + ENABLED.store( + match val { + Some(v) => v as isize, + None => 1, + }, + Ordering::SeqCst, ); - ENABLED.store(match val { - Some(v) => v as isize, - None => 1, - }, Ordering::SeqCst); val } -/// Prints the symbol of the backtrace frame. -/// -/// These output functions should now be used everywhere to ensure consistency. -/// You may want to also use `output_fileline`. -fn output(w: &mut dyn Write, idx: usize, frame: Frame, - s: Option<&str>, format: PrintFormat) -> io::Result<()> { - // Remove the `17: 0x0 - ` line. - if format == PrintFormat::Short && frame.exact_position == ptr::null() { - return Ok(()); - } - match format { - PrintFormat::Full => write!(w, - " {:2}: {:2$?} - ", - idx, - frame.exact_position, - HEX_WIDTH)?, - PrintFormat::Short => write!(w, " {:2}: ", idx)?, - } - match s { - Some(string) => { - let symbol = demangle(string); - match format { - PrintFormat::Full => write!(w, "{}", symbol)?, - // strip the trailing hash if short mode - PrintFormat::Short => write!(w, "{:#}", symbol)?, - } - } - None => w.write_all(b"")?, - } - w.write_all(b"\n") +struct Printer<'a, 'b> { + format: PrintFormat, + done: bool, + skipped: bool, + idx: usize, + out: &'a mut (dyn Write + 'b), } -/// Prints the filename and line number of the backtrace frame. -/// -/// See also `output`. -#[allow(dead_code)] -fn output_fileline(w: &mut dyn Write, - file: &[u8], - line: u32, - format: PrintFormat) -> io::Result<()> { - // prior line: " ##: {:2$} - func" - w.write_all(b"")?; - match format { - PrintFormat::Full => write!(w, - " {:1$}", - "", - HEX_WIDTH)?, - PrintFormat::Short => write!(w, " ")?, +impl<'a, 'b> Printer<'a, 'b> { + fn new(format: PrintFormat, out: &'a mut (dyn Write + 'b)) -> Printer<'a, 'b> { + Printer { format, done: false, skipped: false, idx: 0, out } } - let file = str::from_utf8(file).unwrap_or(""); - let file_path = Path::new(file); - let mut already_printed = false; - if format == PrintFormat::Short && file_path.is_absolute() { - if let Ok(cwd) = env::current_dir() { - if let Ok(stripped) = file_path.strip_prefix(&cwd) { - if let Some(s) = stripped.to_str() { - write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; - already_printed = true; + /// Prints the symbol of the backtrace frame. + /// + /// These output functions should now be used everywhere to ensure consistency. + /// You may want to also use `output_fileline`. + fn output(&mut self, frame: &Frame, symbol: Option<&Symbol>) { + if self.idx > MAX_NB_FRAMES { + self.done = true; + self.skipped = true; + return; + } + if self._output(frame, symbol).is_err() { + self.done = true; + } + self.idx += 1; + } + + fn _output(&mut self, frame: &Frame, symbol: Option<&Symbol>) -> io::Result<()> { + if self.format == PrintFormat::Short { + if let Some(sym) = symbol.and_then(|s| s.name()).and_then(|s| s.as_str()) { + if sym.contains("__rust_begin_short_backtrace") { + self.skipped = true; + self.done = true; + return Ok(()); + } + } + + // Remove the `17: 0x0 - ` line. + if self.format == PrintFormat::Short && frame.ip() == ptr::null_mut() { + self.skipped = true; + return Ok(()); + } + } + + match self.format { + PrintFormat::Full => { + write!(self.out, " {:2}: {:2$?} - ", self.idx, frame.ip(), HEX_WIDTH)? + } + PrintFormat::Short => write!(self.out, " {:2}: ", self.idx)?, + } + + match symbol.and_then(|s| s.name()) { + Some(symbol) => { + match self.format { + PrintFormat::Full => write!(self.out, "{}", symbol)?, + // strip the trailing hash if short mode + PrintFormat::Short => write!(self.out, "{:#}", symbol)?, + } + } + None => self.out.write_all(b"")?, + } + self.out.write_all(b"\n")?; + if let Some(sym) = symbol { + self.output_fileline(sym)?; + } + Ok(()) + } + + /// Prints the filename and line number of the backtrace frame. + /// + /// See also `output`. + fn output_fileline(&mut self, symbol: &Symbol) -> io::Result<()> { + #[cfg(windows)] + let path_buf; + let file = match symbol.filename_raw() { + #[cfg(unix)] + Some(BytesOrWideString::Bytes(bytes)) => { + use crate::os::unix::prelude::*; + Path::new(crate::ffi::OsStr::from_bytes(bytes)) + } + #[cfg(not(unix))] + Some(BytesOrWideString::Bytes(bytes)) => { + Path::new(crate::str::from_utf8(bytes).unwrap_or("")) + } + #[cfg(windows)] + Some(BytesOrWideString::Wide(wide)) => { + use crate::os::windows::prelude::*; + path_buf = crate::ffi::OsString::from_wide(wide); + Path::new(&path_buf) + } + #[cfg(not(windows))] + Some(BytesOrWideString::Wide(_wide)) => { + Path::new("") + } + None => return Ok(()), + }; + let line = match symbol.lineno() { + Some(line) => line, + None => return Ok(()), + }; + // prior line: " ##: {:2$} - func" + self.out.write_all(b"")?; + match self.format { + PrintFormat::Full => write!(self.out, " {:1$}", "", HEX_WIDTH)?, + PrintFormat::Short => write!(self.out, " ")?, + } + + let mut already_printed = false; + if self.format == PrintFormat::Short && file.is_absolute() { + if let Ok(cwd) = env::current_dir() { + if let Ok(stripped) = file.strip_prefix(&cwd) { + if let Some(s) = stripped.to_str() { + write!(self.out, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; + already_printed = true; + } } } } - } - if !already_printed { - write!(w, " at {}:{}", file, line)?; - } + if !already_printed { + write!(self.out, " at {}:{}", file.display(), line)?; + } - w.write_all(b"\n") + self.out.write_all(b"\n") + } } diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs deleted file mode 100644 index 6cd050242dd..00000000000 --- a/src/libstd/sys_common/gnu/libbacktrace.rs +++ /dev/null @@ -1,175 +0,0 @@ -use backtrace_sys::backtrace_state; - -use crate::ffi::CStr; -use crate::io; -use crate::mem; -use crate::ptr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -pub fn foreach_symbol_fileline(frame: Frame, - mut f: F, - _: &BacktraceContext) -> io::Result -where F: FnMut(&[u8], u32) -> io::Result<()> -{ - // pcinfo may return an arbitrary number of file:line pairs, - // in the order of stack trace (i.e., inlined calls first). - // in order to avoid allocation, we stack-allocate a fixed size of entries. - const FILELINE_SIZE: usize = 32; - let mut fileline_buf = [(ptr::null(), !0); FILELINE_SIZE]; - let ret; - let fileline_count = { - let state = unsafe { init_state() }; - if state.is_null() { - return Err(io::Error::new( - io::ErrorKind::Other, - "failed to allocate libbacktrace state") - ) - } - let mut fileline_win: &mut [FileLine] = &mut fileline_buf; - let fileline_addr = &mut fileline_win as *mut &mut [FileLine]; - ret = unsafe { - backtrace_sys::backtrace_pcinfo( - state, - frame.exact_position as libc::uintptr_t, - pcinfo_cb, - error_cb, - fileline_addr as *mut libc::c_void, - ) - }; - FILELINE_SIZE - fileline_win.len() - }; - if ret == 0 { - for &(file, line) in &fileline_buf[..fileline_count] { - if file.is_null() { continue; } // just to be sure - let file = unsafe { CStr::from_ptr(file).to_bytes() }; - f(file, line)?; - } - Ok(fileline_count == FILELINE_SIZE) - } else { - Ok(false) - } -} - -/// Converts a pointer to symbol to its string value. -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - let symname = { - let state = unsafe { init_state() }; - if state.is_null() { - return Err(io::Error::new( - io::ErrorKind::Other, - "failed to allocate libbacktrace state") - ) - } - let mut data: *const libc::c_char = ptr::null(); - let data_addr = &mut data as *mut *const libc::c_char; - let ret = unsafe { - backtrace_sys::backtrace_syminfo( - state, - frame.symbol_addr as libc::uintptr_t, - syminfo_cb, - error_cb, - data_addr as *mut libc::c_void, - ) - }; - if ret == 0 || data.is_null() { - None - } else { - unsafe { - CStr::from_ptr(data).to_str().ok() - } - } - }; - callback(symname) -} - -//////////////////////////////////////////////////////////////////////// -// helper callbacks -//////////////////////////////////////////////////////////////////////// - -type FileLine = (*const libc::c_char, u32); - -extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char, - _errnum: libc::c_int) { - // do nothing for now -} -extern fn syminfo_cb(data: *mut libc::c_void, - _pc: libc::uintptr_t, - symname: *const libc::c_char, - _symval: libc::uintptr_t, - _symsize: libc::uintptr_t) { - let slot = data as *mut *const libc::c_char; - unsafe { *slot = symname; } -} -extern fn pcinfo_cb(data: *mut libc::c_void, - _pc: libc::uintptr_t, - filename: *const libc::c_char, - lineno: libc::c_int, - _function: *const libc::c_char) -> libc::c_int { - if !filename.is_null() { - let slot = data as *mut &mut [FileLine]; - let buffer = unsafe {ptr::read(slot)}; - - // if the buffer is not full, add file:line to the buffer - // and adjust the buffer for next possible calls to pcinfo_cb. - if !buffer.is_empty() { - buffer[0] = (filename, lineno as u32); - unsafe { ptr::write(slot, &mut buffer[1..]); } - } - } - - 0 -} - -// The libbacktrace API supports creating a state, but it does not -// support destroying a state. I personally take this to mean that a -// state is meant to be created and then live forever. -// -// I would love to register an at_exit() handler which cleans up this -// state, but libbacktrace provides no way to do so. -// -// With these constraints, this function has a statically cached state -// that is calculated the first time this is requested. Remember that -// backtracing all happens serially (one global lock). -// -// Things don't work so well on not-Linux since libbacktrace can't track -// down that executable this is. We at one point used env::current_exe but -// it turns out that there are some serious security issues with that -// approach. -// -// Specifically, on certain platforms like BSDs, a malicious actor can cause -// an arbitrary file to be placed at the path returned by current_exe. -// libbacktrace does not behave defensively in the presence of ill-formed -// DWARF information, and has been demonstrated to segfault in at least one -// case. There is no evidence at the moment to suggest that a more carefully -// constructed file can't cause arbitrary code execution. As a result of all -// of this, we don't hint libbacktrace with the path to the current process. -unsafe fn init_state() -> *mut backtrace_state { - static mut STATE: *mut backtrace_state = ptr::null_mut(); - if !STATE.is_null() { return STATE } - - let filename = match crate::sys::backtrace::gnu::get_executable_filename() { - Ok((filename, file)) => { - // filename is purposely leaked here since libbacktrace requires - // it to stay allocated permanently, file is also leaked so that - // the file stays locked - let filename_ptr = filename.as_ptr(); - mem::forget(filename); - mem::forget(file); - filename_ptr - }, - Err(_) => ptr::null(), - }; - - STATE = backtrace_sys::backtrace_create_state( - filename, - 0, - error_cb, - ptr::null_mut(), - ); - STATE -} diff --git a/src/libstd/sys_common/gnu/mod.rs b/src/libstd/sys_common/gnu/mod.rs deleted file mode 100644 index d6959697f2a..00000000000 --- a/src/libstd/sys_common/gnu/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -pub mod libbacktrace; diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 78e15994264..c4daedefd8e 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -77,12 +77,6 @@ macro_rules! rtunwrap { } } -#[cfg(feature = "backtrace")] -#[cfg(any(all(unix, not(target_os = "emscripten")), - all(windows, target_env = "gnu"), - target_os = "redox"))] -pub mod gnu; - // common error constructors /// A trait for viewing representations from std types diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 290c4481c00..18d682640db 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -38,6 +38,7 @@ features = [ "objbase", "profileapi", "processenv", + "processthreadsapi", "psapi", "schannel", "securitybaseapi", diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index edef26e6b02..ad3ac986c94 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -64,6 +64,7 @@ Crate("aho-corasick"), Crate("arrayvec"), Crate("atty"), + Crate("autocfg"), Crate("backtrace"), Crate("backtrace-sys"), Crate("bitflags"), diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index b725fbe3d74..837be69f7ca 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -61,6 +61,7 @@ "src/libstd/net/test.rs", "src/libstd/sys_common/mod.rs", "src/libstd/sys_common/net.rs", + "src/libstd/sys_common/backtrace.rs", "src/libterm", // Not sure how to make this crate portable, but test crate needs it. "src/libtest", // Probably should defer to unstable `std::sys` APIs. "src/libstd/sync/mpsc", // some tests are only run on non-emscripten