8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
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.
85
12
86
13
pub use self :: tracing:: unwind_backtrace;
87
14
pub use self :: printing:: { foreach_symbol_fileline, resolve_symname} ;
@@ -91,7 +18,6 @@ mod tracing;
91
18
// symbol resolvers:
92
19
mod printing;
93
20
94
- #[ cfg( not( any( target_os = "macos" , target_os = "ios" , target_os = "emscripten" ) ) ) ]
95
21
pub mod gnu {
96
22
use io;
97
23
use fs;
0 commit comments