Simplify Redox backtrace/ to not include non-Redox implementations
This commit is contained in:
parent
2fd4663fee
commit
9d67d5a71d
@ -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;
|
||||
|
@ -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};
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use io;
|
||||
use intrinsics;
|
||||
use ffi::CStr;
|
||||
use libc;
|
||||
use sys::backtrace::BacktraceContext;
|
||||
use sys_common::backtrace::Frame;
|
||||
|
||||
pub fn resolve_symname<F>(frame: Frame,
|
||||
callback: F,
|
||||
_: &BacktraceContext) -> io::Result<()>
|
||||
where F: FnOnce(Option<&str>) -> io::Result<()>
|
||||
{
|
||||
unsafe {
|
||||
let mut info: Dl_info = intrinsics::init();
|
||||
let symname = if dladdr(frame.exact_position, &mut info) == 0 {
|
||||
None
|
||||
} else {
|
||||
CStr::from_ptr(info.dli_sname).to_str().ok()
|
||||
};
|
||||
callback(symname)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn foreach_symbol_fileline<F>(_symbol_addr: Frame,
|
||||
_f: F,
|
||||
_: &BacktraceContext) -> io::Result<bool>
|
||||
where F: FnMut(&[u8], libc::c_int) -> io::Result<()>
|
||||
{
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Dl_info {
|
||||
dli_fname: *const libc::c_char,
|
||||
dli_fbase: *mut libc::c_void,
|
||||
dli_sname: *const libc::c_char,
|
||||
dli_saddr: *mut libc::c_void,
|
||||
}
|
||||
|
||||
extern {
|
||||
fn dladdr(addr: *const libc::c_void,
|
||||
info: *mut Dl_info) -> libc::c_int;
|
||||
}
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
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};
|
||||
}
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/// 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user