88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- /// Backtrace support built on libgcc with some extra OS-specific support
12- ///
13- /// Some methods of getting a backtrace:
14- ///
15- /// * The backtrace() functions on unix. It turns out this doesn't work very
16- /// well for green threads on macOS, and the address to symbol portion of it
17- /// suffers problems that are described below.
18- ///
19- /// * Using libunwind. This is more difficult than it sounds because libunwind
20- /// isn't installed everywhere by default. It's also a bit of a hefty library,
21- /// so possibly not the best option. When testing, libunwind was excellent at
22- /// getting both accurate backtraces and accurate symbols across platforms.
23- /// This route was not chosen in favor of the next option, however.
24- ///
25- /// * We're already using libgcc_s for exceptions in rust (triggering thread
26- /// unwinding and running destructors on the stack), and it turns out that it
27- /// conveniently comes with a function that also gives us a backtrace. All of
28- /// these functions look like _Unwind_*, but it's not quite the full
29- /// repertoire of the libunwind API. Due to it already being in use, this was
30- /// the chosen route of getting a backtrace.
31- ///
32- /// After choosing libgcc_s for backtraces, the sad part is that it will only
33- /// give us a stack trace of instruction pointers. Thankfully these instruction
34- /// pointers are accurate (they work for green and native threads), but it's
35- /// then up to us again to figure out how to translate these addresses to
36- /// symbols. As with before, we have a few options. Before, that, a little bit
37- /// of an interlude about symbols. This is my very limited knowledge about
38- /// symbol tables, and this information is likely slightly wrong, but the
39- /// general idea should be correct.
40- ///
41- /// When talking about symbols, it's helpful to know a few things about where
42- /// symbols are located. Some symbols are located in the dynamic symbol table
43- /// of the executable which in theory means that they're available for dynamic
44- /// linking and lookup. Other symbols end up only in the local symbol table of
45- /// the file. This loosely corresponds to pub and priv functions in Rust.
46- ///
47- /// Armed with this knowledge, we know that our solution for address to symbol
48- /// translation will need to consult both the local and dynamic symbol tables.
49- /// With that in mind, here's our options of translating an address to
50- /// a symbol.
51- ///
52- /// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
53- /// behind the scenes to translate, and this is why backtrace() was not used.
54- /// Conveniently, this method works fantastically on macOS. It appears dladdr()
55- /// uses magic to consult the local symbol table, or we're putting everything
56- /// in the dynamic symbol table anyway. Regardless, for macOS, this is the
57- /// method used for translation. It's provided by the system and easy to do.o
58- ///
59- /// Sadly, all other systems have a dladdr() implementation that does not
60- /// consult the local symbol table. This means that most functions are blank
61- /// because they don't have symbols. This means that we need another solution.
62- ///
63- /// * Use unw_get_proc_name(). This is part of the libunwind api (not the
64- /// libgcc_s version of the libunwind api), but involves taking a dependency
65- /// to libunwind. We may pursue this route in the future if we bundle
66- /// libunwind, but libunwind was unwieldy enough that it was not chosen at
67- /// this time to provide this functionality.
68- ///
69- /// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
70- /// semi-reasonable solution. The stdlib already knows how to spawn processes,
71- /// so in theory it could invoke readelf, parse the output, and consult the
72- /// local/dynamic symbol tables from there. This ended up not getting chosen
73- /// due to the craziness of the idea plus the advent of the next option.
74- ///
75- /// * Use `libbacktrace`. It turns out that this is a small library bundled in
76- /// the gcc repository which provides backtrace and symbol translation
77- /// functionality. All we really need from it is the backtrace functionality,
78- /// and we only really need this on everything that's not macOS, so this is the
79- /// chosen route for now.
80- ///
81- /// In summary, the current situation uses libgcc_s to get a trace of stack
82- /// pointers, and we use dladdr() or libbacktrace to translate these addresses
83- /// to symbols. This is a bit of a hokey implementation as-is, but it works for
84- /// all unix platforms we support right now, so it at least gets the job done.
11+ /// See sys/unix/backtrace/mod.rs for an explanation of the method used here.
8512
8613pub use self :: tracing:: unwind_backtrace;
8714pub use self :: printing:: { foreach_symbol_fileline, resolve_symname} ;
@@ -91,7 +18,6 @@ mod tracing;
9118// symbol resolvers:
9219mod printing;
9320
94- #[ cfg( not( any( target_os = "macos" , target_os = "ios" , target_os = "emscripten" ) ) ) ]
9521pub mod gnu {
9622 use io;
9723 use fs;
0 commit comments