From 0fad1b1cd8e6577590108c653e4818685e0f7b03 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 3 Aug 2017 21:12:15 -0700 Subject: [PATCH 1/3] Update libbacktrace config.sub from http://git.savannah.gnu.org/cgit/config.git This is needed for it to compile on Redox. --- src/libbacktrace/config.sub | 47 +++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/libbacktrace/config.sub b/src/libbacktrace/config.sub index da6d1b6826a28..40ea5dfe1152f 100644 --- a/src/libbacktrace/config.sub +++ b/src/libbacktrace/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2016 Free Software Foundation, Inc. +# Copyright 1992-2017 Free Software Foundation, Inc. -timestamp='2016-01-01' +timestamp='2017-04-02' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -67,7 +67,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2016 Free Software Foundation, Inc. +Copyright 1992-2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -117,7 +117,7 @@ case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` @@ -263,7 +263,7 @@ case $basic_machine in | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ - | i370 | i860 | i960 | ia64 \ + | i370 | i860 | i960 | ia16 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ @@ -301,6 +301,7 @@ case $basic_machine in | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ @@ -314,6 +315,7 @@ case $basic_machine in | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ + | wasm32 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) @@ -387,7 +389,7 @@ case $basic_machine in | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ - | i*86-* | i860-* | i960-* | ia64-* \ + | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ @@ -428,6 +430,7 @@ case $basic_machine in | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ | pyramid-* \ | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ @@ -444,6 +447,7 @@ case $basic_machine in | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ + | wasm32-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ @@ -643,6 +647,14 @@ case $basic_machine in basic_machine=m68k-bull os=-sysv3 ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; ebmon29k) basic_machine=a29k-amd os=-ebmon @@ -938,6 +950,9 @@ case $basic_machine in nsr-tandem) basic_machine=nsr-tandem ;; + nsx-tandem) + basic_machine=nsx-tandem + ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf @@ -1022,7 +1037,7 @@ case $basic_machine in ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppcle | powerpclittle | ppc-le | powerpc-little) + ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) @@ -1032,7 +1047,7 @@ case $basic_machine in ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) + ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) @@ -1233,6 +1248,9 @@ case $basic_machine in basic_machine=a29k-wrs os=-vxworks ;; + wasm32) + basic_machine=wasm32-unknown + ;; w65*) basic_machine=w65-wdc os=-none @@ -1382,14 +1400,14 @@ case $os in | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* | -cegcc* \ + | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ @@ -1399,7 +1417,7 @@ case $os in | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ - | -onefs* | -tirtos*) + | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1531,6 +1549,8 @@ case $os in ;; -nacl*) ;; + -ios) + ;; -none) ;; *) @@ -1626,6 +1646,9 @@ case $basic_machine in sparc-* | *-sun) os=-sunos4.1.1 ;; + pru-*) + os=-elf + ;; *-be) os=-beos ;; From 2fd4663feeec050379c91393474d3ecfd198b2b4 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 3 Aug 2017 21:13:44 -0700 Subject: [PATCH 2/3] Make backtraces work on Redox, copying Unix implementation --- src/libstd/build.rs | 2 +- src/libstd/sys/redox/backtrace.rs | 32 ----- src/libstd/sys/redox/backtrace/mod.rs | 116 ++++++++++++++++++ .../sys/redox/backtrace/printing/dladdr.rs | 53 ++++++++ .../sys/redox/backtrace/printing/mod.rs | 22 ++++ .../redox/backtrace/tracing/backtrace_fn.rs | 48 ++++++++ .../sys/redox/backtrace/tracing/gcc_s.rs | 106 ++++++++++++++++ src/libstd/sys/redox/backtrace/tracing/mod.rs | 18 +++ src/libunwind/build.rs | 2 + 9 files changed, 366 insertions(+), 33 deletions(-) delete mode 100644 src/libstd/sys/redox/backtrace.rs create mode 100644 src/libstd/sys/redox/backtrace/mod.rs create mode 100644 src/libstd/sys/redox/backtrace/printing/dladdr.rs create mode 100644 src/libstd/sys/redox/backtrace/printing/mod.rs create mode 100644 src/libstd/sys/redox/backtrace/tracing/backtrace_fn.rs create mode 100644 src/libstd/sys/redox/backtrace/tracing/gcc_s.rs create mode 100644 src/libstd/sys/redox/backtrace/tracing/mod.rs diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 0b5c2db171d65..ab304f4c9652a 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -21,7 +21,7 @@ fn main() { let target = env::var("TARGET").expect("TARGET was not set"); let host = env::var("HOST").expect("HOST was not set"); if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") && - !target.contains("emscripten") && !target.contains("fuchsia") && !target.contains("redox") { + !target.contains("emscripten") && !target.contains("fuchsia") { let _ = build_libbacktrace(&host, &target); } diff --git a/src/libstd/sys/redox/backtrace.rs b/src/libstd/sys/redox/backtrace.rs deleted file mode 100644 index 6cafe3e69bac1..0000000000000 --- a/src/libstd/sys/redox/backtrace.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys_common::backtrace::Frame; - -pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; -pub struct BacktraceContext; - -#[inline(never)] -pub fn unwind_backtrace(_frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - Ok((0, BacktraceContext)) -} - -pub mod gnu { - use io; - use fs; - use libc::c_char; - - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) - } -} diff --git a/src/libstd/sys/redox/backtrace/mod.rs b/src/libstd/sys/redox/backtrace/mod.rs new file mode 100644 index 0000000000000..2171494c49938 --- /dev/null +++ b/src/libstd/sys/redox/backtrace/mod.rs @@ -0,0 +1,116 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// 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(any(target_os = "macos", target_os = "ios", target_os = "emscripten")))] +pub mod gnu { + use io; + use fs; + use libc::c_char; + use vec::Vec; + use ffi::OsStr; + use os::unix::ffi::OsStrExt; + use io::Read; + + 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/dladdr.rs b/src/libstd/sys/redox/backtrace/printing/dladdr.rs new file mode 100644 index 0000000000000..05a071a797838 --- /dev/null +++ b/src/libstd/sys/redox/backtrace/printing/dladdr.rs @@ -0,0 +1,53 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use intrinsics; +use ffi::CStr; +use libc; +use sys::backtrace::BacktraceContext; +use 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, &mut info) == 0 { + None + } else { + CStr::from_ptr(info.dli_sname).to_str().ok() + }; + callback(symname) + } +} + +pub fn foreach_symbol_fileline(_symbol_addr: Frame, + _f: F, + _: &BacktraceContext) -> io::Result + 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/redox/backtrace/printing/mod.rs b/src/libstd/sys/redox/backtrace/printing/mod.rs new file mode 100644 index 0000000000000..1ae82e0110016 --- /dev/null +++ b/src/libstd/sys/redox/backtrace/printing/mod.rs @@ -0,0 +1,22 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::imp::{foreach_symbol_fileline, resolve_symname}; + +#[cfg(any(target_os = "macos", target_os = "ios", + target_os = "emscripten"))] +#[path = "dladdr.rs"] +mod imp; + +#[cfg(not(any(target_os = "macos", target_os = "ios", + target_os = "emscripten")))] +mod imp { + pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; +} diff --git a/src/libstd/sys/redox/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/redox/backtrace/tracing/backtrace_fn.rs new file mode 100644 index 0000000000000..ecd32aa9462a9 --- /dev/null +++ b/src/libstd/sys/redox/backtrace/tracing/backtrace_fn.rs @@ -0,0 +1,48 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// As always - 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 io; +use libc; +use sys::backtrace::BacktraceContext; +use 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, + symbol_addr: *from, + }; + } + 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/redox/backtrace/tracing/gcc_s.rs b/src/libstd/sys/redox/backtrace/tracing/gcc_s.rs new file mode 100644 index 0000000000000..cfeabaddda985 --- /dev/null +++ b/src/libstd/sys/redox/backtrace/tracing/gcc_s.rs @@ -0,0 +1,106 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use error::Error; +use io; +use libc; +use sys::backtrace::BacktraceContext; +use 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) }; + 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) } + }; + + 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/redox/backtrace/tracing/mod.rs b/src/libstd/sys/redox/backtrace/tracing/mod.rs new file mode 100644 index 0000000000000..c9c8e260d2f63 --- /dev/null +++ b/src/libstd/sys/redox/backtrace/tracing/mod.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +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/libunwind/build.rs b/src/libunwind/build.rs index be9aa6c5d40ba..cb8cb90e9ca7a 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -41,5 +41,7 @@ fn main() { println!("cargo:rustc-link-lib=unwind"); } else if target.contains("haiku") { println!("cargo:rustc-link-lib=gcc_s"); + } else if target.contains("redox") { + println!("cargo:rustc-link-lib=gcc"); } } From 9d67d5a71dafe105167acf0e8b960f5aa118652b Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 3 Aug 2017 22:49:46 -0700 Subject: [PATCH 3/3] Simplify Redox backtrace/ to not include non-Redox implementations --- src/libstd/sys/redox/backtrace/mod.rs | 76 +------------------ .../backtrace/{tracing/mod.rs => printing.rs} | 11 +-- .../sys/redox/backtrace/printing/dladdr.rs | 53 ------------- .../sys/redox/backtrace/printing/mod.rs | 22 ------ .../{tracing/gcc_s.rs => tracing.rs} | 0 .../redox/backtrace/tracing/backtrace_fn.rs | 48 ------------ 6 files changed, 3 insertions(+), 207 deletions(-) rename src/libstd/sys/redox/backtrace/{tracing/mod.rs => printing.rs} (60%) delete mode 100644 src/libstd/sys/redox/backtrace/printing/dladdr.rs delete mode 100644 src/libstd/sys/redox/backtrace/printing/mod.rs rename src/libstd/sys/redox/backtrace/{tracing/gcc_s.rs => tracing.rs} (100%) delete mode 100644 src/libstd/sys/redox/backtrace/tracing/backtrace_fn.rs diff --git a/src/libstd/sys/redox/backtrace/mod.rs b/src/libstd/sys/redox/backtrace/mod.rs index 2171494c49938..40b957d847b0f 100644 --- a/src/libstd/sys/redox/backtrace/mod.rs +++ b/src/libstd/sys/redox/backtrace/mod.rs @@ -8,80 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/// 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. +/// 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}; @@ -91,7 +18,6 @@ mod tracing; // symbol resolvers: mod printing; -#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "emscripten")))] pub mod gnu { use io; use fs; diff --git a/src/libstd/sys/redox/backtrace/tracing/mod.rs b/src/libstd/sys/redox/backtrace/printing.rs similarity index 60% rename from src/libstd/sys/redox/backtrace/tracing/mod.rs rename to src/libstd/sys/redox/backtrace/printing.rs index c9c8e260d2f63..3e937dbe623e7 100644 --- a/src/libstd/sys/redox/backtrace/tracing/mod.rs +++ b/src/libstd/sys/redox/backtrace/printing.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,11 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -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; +pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; diff --git a/src/libstd/sys/redox/backtrace/printing/dladdr.rs b/src/libstd/sys/redox/backtrace/printing/dladdr.rs deleted file mode 100644 index 05a071a797838..0000000000000 --- a/src/libstd/sys/redox/backtrace/printing/dladdr.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use intrinsics; -use ffi::CStr; -use libc; -use sys::backtrace::BacktraceContext; -use 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, &mut info) == 0 { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -pub fn foreach_symbol_fileline(_symbol_addr: Frame, - _f: F, - _: &BacktraceContext) -> io::Result - 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/redox/backtrace/printing/mod.rs b/src/libstd/sys/redox/backtrace/printing/mod.rs deleted file mode 100644 index 1ae82e0110016..0000000000000 --- a/src/libstd/sys/redox/backtrace/printing/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::imp::{foreach_symbol_fileline, resolve_symname}; - -#[cfg(any(target_os = "macos", target_os = "ios", - target_os = "emscripten"))] -#[path = "dladdr.rs"] -mod imp; - -#[cfg(not(any(target_os = "macos", target_os = "ios", - target_os = "emscripten")))] -mod imp { - pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; -} diff --git a/src/libstd/sys/redox/backtrace/tracing/gcc_s.rs b/src/libstd/sys/redox/backtrace/tracing.rs similarity index 100% rename from src/libstd/sys/redox/backtrace/tracing/gcc_s.rs rename to src/libstd/sys/redox/backtrace/tracing.rs diff --git a/src/libstd/sys/redox/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/redox/backtrace/tracing/backtrace_fn.rs deleted file mode 100644 index ecd32aa9462a9..0000000000000 --- a/src/libstd/sys/redox/backtrace/tracing/backtrace_fn.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// As always - 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 io; -use libc; -use sys::backtrace::BacktraceContext; -use 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, - symbol_addr: *from, - }; - } - Ok((nb_frames as usize, BacktraceContext)) -} - -extern { - fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; -}