      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119

    // 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 <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.

    /// 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 io;
        use fs;
        use libc::c_char;

        #[cfg(not(any(target_os = "macos", target_os = "ios")))]
        pub fn get_executable_filename() -> io::Result<(Vec<c_char>, 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<c_char>, fs::File)> {
            use env;
            use 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;

# Help

## Keyboard Shortcuts

?
  Show this help dialog
S
  Focus the search field
⇤
  Move up in search results
⇥
  Move down in search results
⏎
  Go to active search result
+
  Collapse/expand all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)