1 use core::{fmt, str};
2 
3 cfg_if::cfg_if! {
4     if #[cfg(feature = "std")] {
5         use std::path::Path;
6         use std::prelude::v1::*;
7     }
8 }
9 
10 use crate::backtrace::Frame;
11 use crate::types::BytesOrWideString;
12 use core::ffi::c_void;
13 use rustc_demangle::{try_demangle, Demangle};
14 
15 /// Resolve an address to a symbol, passing the symbol to the specified
16 /// closure.
17 ///
18 /// This function will look up the given address in areas such as the local
19 /// symbol table, dynamic symbol table, or DWARF debug info (depending on the
20 /// activated implementation) to find symbols to yield.
21 ///
22 /// The closure may not be called if resolution could not be performed, and it
23 /// also may be called more than once in the case of inlined functions.
24 ///
25 /// Symbols yielded represent the execution at the specified `addr`, returning
26 /// file/line pairs for that address (if available).
27 ///
28 /// Note that if you have a `Frame` then it's recommended to use the
29 /// `resolve_frame` function instead of this one.
30 ///
31 /// # Required features
32 ///
33 /// This function requires the `std` feature of the `backtrace` crate to be
34 /// enabled, and the `std` feature is enabled by default.
35 ///
36 /// # Panics
37 ///
38 /// This function strives to never panic, but if the `cb` provided panics then
39 /// some platforms will force a double panic to abort the process. Some
40 /// platforms use a C library which internally uses callbacks which cannot be
41 /// unwound through, so panicking from `cb` may trigger a process abort.
42 ///
43 /// # Example
44 ///
45 /// ```
46 /// extern crate backtrace;
47 ///
48 /// fn main() {
49 ///     backtrace::trace(|frame| {
50 ///         let ip = frame.ip();
51 ///
52 ///         backtrace::resolve(ip, |symbol| {
53 ///             // ...
54 ///         });
55 ///
56 ///         false // only look at the top frame
57 ///     });
58 /// }
59 /// ```
60 #[cfg(feature = "std")]
resolve<F: FnMut(&Symbol)>(addr: *mut c_void, cb: F)61 pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, cb: F) {
62     let _guard = crate::lock::lock();
63     unsafe { resolve_unsynchronized(addr, cb) }
64 }
65 
66 /// Resolve a previously capture frame to a symbol, passing the symbol to the
67 /// specified closure.
68 ///
69 /// This functin performs the same function as `resolve` except that it takes a
70 /// `Frame` as an argument instead of an address. This can allow some platform
71 /// implementations of backtracing to provide more accurate symbol information
72 /// or information about inline frames for example. It's recommended to use this
73 /// if you can.
74 ///
75 /// # Required features
76 ///
77 /// This function requires the `std` feature of the `backtrace` crate to be
78 /// enabled, and the `std` feature is enabled by default.
79 ///
80 /// # Panics
81 ///
82 /// This function strives to never panic, but if the `cb` provided panics then
83 /// some platforms will force a double panic to abort the process. Some
84 /// platforms use a C library which internally uses callbacks which cannot be
85 /// unwound through, so panicking from `cb` may trigger a process abort.
86 ///
87 /// # Example
88 ///
89 /// ```
90 /// extern crate backtrace;
91 ///
92 /// fn main() {
93 ///     backtrace::trace(|frame| {
94 ///         backtrace::resolve_frame(frame, |symbol| {
95 ///             // ...
96 ///         });
97 ///
98 ///         false // only look at the top frame
99 ///     });
100 /// }
101 /// ```
102 #[cfg(feature = "std")]
resolve_frame<F: FnMut(&Symbol)>(frame: &Frame, cb: F)103 pub fn resolve_frame<F: FnMut(&Symbol)>(frame: &Frame, cb: F) {
104     let _guard = crate::lock::lock();
105     unsafe { resolve_frame_unsynchronized(frame, cb) }
106 }
107 
108 pub enum ResolveWhat<'a> {
109     Address(*mut c_void),
110     Frame(&'a Frame),
111 }
112 
113 impl<'a> ResolveWhat<'a> {
114     #[allow(dead_code)]
address_or_ip(&self) -> *mut c_void115     fn address_or_ip(&self) -> *mut c_void {
116         match self {
117             ResolveWhat::Address(a) => adjust_ip(*a),
118             ResolveWhat::Frame(f) => adjust_ip(f.ip()),
119         }
120     }
121 }
122 
123 // IP values from stack frames are typically (always?) the instruction
124 // *after* the call that's the actual stack trace. Symbolizing this on
125 // causes the filename/line number to be one ahead and perhaps into
126 // the void if it's near the end of the function.
127 //
128 // This appears to basically always be the case on all platforms, so we always
129 // subtract one from a resolved ip to resolve it to the previous call
130 // instruction instead of the instruction being returned to.
131 //
132 // Ideally we would not do this. Ideally we would require callers of the
133 // `resolve` APIs here to manually do the -1 and account that they want location
134 // information for the *previous* instruction, not the current. Ideally we'd
135 // also expose on `Frame` if we are indeed the address of the next instruction
136 // or the current.
137 //
138 // For now though this is a pretty niche concern so we just internally always
139 // subtract one. Consumers should keep working and getting pretty good results,
140 // so we should be good enough.
adjust_ip(a: *mut c_void) -> *mut c_void141 fn adjust_ip(a: *mut c_void) -> *mut c_void {
142     if a.is_null() {
143         a
144     } else {
145         (a as usize - 1) as *mut c_void
146     }
147 }
148 
149 /// Same as `resolve`, only unsafe as it's unsynchronized.
150 ///
151 /// This function does not have synchronization guarentees but is available when
152 /// the `std` feature of this crate isn't compiled in. See the `resolve`
153 /// function for more documentation and examples.
154 ///
155 /// # Panics
156 ///
157 /// See information on `resolve` for caveats on `cb` panicking.
resolve_unsynchronized<F>(addr: *mut c_void, mut cb: F) where F: FnMut(&Symbol),158 pub unsafe fn resolve_unsynchronized<F>(addr: *mut c_void, mut cb: F)
159 where
160     F: FnMut(&Symbol),
161 {
162     resolve_imp(ResolveWhat::Address(addr), &mut cb)
163 }
164 
165 /// Same as `resolve_frame`, only unsafe as it's unsynchronized.
166 ///
167 /// This function does not have synchronization guarentees but is available
168 /// when the `std` feature of this crate isn't compiled in. See the
169 /// `resolve_frame` function for more documentation and examples.
170 ///
171 /// # Panics
172 ///
173 /// See information on `resolve_frame` for caveats on `cb` panicking.
resolve_frame_unsynchronized<F>(frame: &Frame, mut cb: F) where F: FnMut(&Symbol),174 pub unsafe fn resolve_frame_unsynchronized<F>(frame: &Frame, mut cb: F)
175 where
176     F: FnMut(&Symbol),
177 {
178     resolve_imp(ResolveWhat::Frame(frame), &mut cb)
179 }
180 
181 /// A trait representing the resolution of a symbol in a file.
182 ///
183 /// This trait is yielded as a trait object to the closure given to the
184 /// `backtrace::resolve` function, and it is virtually dispatched as it's
185 /// unknown which implementation is behind it.
186 ///
187 /// A symbol can give contextual information about a function, for example the
188 /// name, filename, line number, precise address, etc. Not all information is
189 /// always available in a symbol, however, so all methods return an `Option`.
190 pub struct Symbol {
191     // TODO: this lifetime bound needs to be persisted eventually to `Symbol`,
192     // but that's currently a breaking change. For now this is safe since
193     // `Symbol` is only ever handed out by reference and can't be cloned.
194     inner: SymbolImp<'static>,
195 }
196 
197 impl Symbol {
198     /// Returns the name of this function.
199     ///
200     /// The returned structure can be used to query various properties about the
201     /// symbol name:
202     ///
203     /// * The `Display` implementation will print out the demangled symbol.
204     /// * The raw `str` value of the symbol can be accessed (if it's valid
205     ///   utf-8).
206     /// * The raw bytes for the symbol name can be accessed.
name(&self) -> Option<SymbolName>207     pub fn name(&self) -> Option<SymbolName> {
208         self.inner.name()
209     }
210 
211     /// Returns the starting address of this function.
addr(&self) -> Option<*mut c_void>212     pub fn addr(&self) -> Option<*mut c_void> {
213         self.inner.addr().map(|p| p as *mut _)
214     }
215 
216     /// Returns the raw filename as a slice. This is mainly useful for `no_std`
217     /// environments.
filename_raw(&self) -> Option<BytesOrWideString>218     pub fn filename_raw(&self) -> Option<BytesOrWideString> {
219         self.inner.filename_raw()
220     }
221 
222     /// Returns the line number for where this symbol is currently executing.
223     ///
224     /// This return value is typically `Some` if `filename` returns `Some`, and
225     /// is consequently subject to similar caveats.
lineno(&self) -> Option<u32>226     pub fn lineno(&self) -> Option<u32> {
227         self.inner.lineno()
228     }
229 
230     /// Returns the file name where this function was defined.
231     ///
232     /// This is currently only available when libbacktrace is being used (e.g.
233     /// unix platforms other than OSX) and when a binary is compiled with
234     /// debuginfo. If neither of these conditions is met then this will likely
235     /// return `None`.
236     ///
237     /// # Required features
238     ///
239     /// This function requires the `std` feature of the `backtrace` crate to be
240     /// enabled, and the `std` feature is enabled by default.
241     #[cfg(feature = "std")]
242     #[allow(unreachable_code)]
filename(&self) -> Option<&Path>243     pub fn filename(&self) -> Option<&Path> {
244         self.inner.filename()
245     }
246 }
247 
248 impl fmt::Debug for Symbol {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result249     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250         let mut d = f.debug_struct("Symbol");
251         if let Some(name) = self.name() {
252             d.field("name", &name);
253         }
254         if let Some(addr) = self.addr() {
255             d.field("addr", &addr);
256         }
257 
258         #[cfg(feature = "std")]
259         {
260             if let Some(filename) = self.filename() {
261                 d.field("filename", &filename);
262             }
263         }
264 
265         if let Some(lineno) = self.lineno() {
266             d.field("lineno", &lineno);
267         }
268         d.finish()
269     }
270 }
271 
272 cfg_if::cfg_if! {
273     if #[cfg(feature = "cpp_demangle")] {
274         // Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust
275         // failed.
276         struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>);
277 
278         impl<'a> OptionCppSymbol<'a> {
279             fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> {
280                 OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok())
281             }
282 
283             fn none() -> OptionCppSymbol<'a> {
284                 OptionCppSymbol(None)
285             }
286         }
287     } else {
288         use core::marker::PhantomData;
289 
290         // Make sure to keep this zero-sized, so that the `cpp_demangle` feature
291         // has no cost when disabled.
292         struct OptionCppSymbol<'a>(PhantomData<&'a ()>);
293 
294         impl<'a> OptionCppSymbol<'a> {
295             fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> {
296                 OptionCppSymbol(PhantomData)
297             }
298 
299             fn none() -> OptionCppSymbol<'a> {
300                 OptionCppSymbol(PhantomData)
301             }
302         }
303     }
304 }
305 
306 /// A wrapper around a symbol name to provide ergonomic accessors to the
307 /// demangled name, the raw bytes, the raw string, etc.
308 // Allow dead code for when the `cpp_demangle` feature is not enabled.
309 #[allow(dead_code)]
310 pub struct SymbolName<'a> {
311     bytes: &'a [u8],
312     demangled: Option<Demangle<'a>>,
313     cpp_demangled: OptionCppSymbol<'a>,
314 }
315 
316 impl<'a> SymbolName<'a> {
317     /// Creates a new symbol name from the raw underlying bytes.
new(bytes: &'a [u8]) -> SymbolName<'a>318     pub fn new(bytes: &'a [u8]) -> SymbolName<'a> {
319         let str_bytes = str::from_utf8(bytes).ok();
320         let demangled = str_bytes.and_then(|s| try_demangle(s).ok());
321 
322         let cpp = if demangled.is_none() {
323             OptionCppSymbol::parse(bytes)
324         } else {
325             OptionCppSymbol::none()
326         };
327 
328         SymbolName {
329             bytes: bytes,
330             demangled: demangled,
331             cpp_demangled: cpp,
332         }
333     }
334 
335     /// Returns the raw (mangled) symbol name as a `str` if the symbol is valid utf-8.
336     ///
337     /// Use the `Display` implementation if you want the demangled version.
as_str(&self) -> Option<&'a str>338     pub fn as_str(&self) -> Option<&'a str> {
339         self.demangled
340             .as_ref()
341             .map(|s| s.as_str())
342             .or_else(|| str::from_utf8(self.bytes).ok())
343     }
344 
345     /// Returns the raw symbol name as a list of bytes
as_bytes(&self) -> &'a [u8]346     pub fn as_bytes(&self) -> &'a [u8] {
347         self.bytes
348     }
349 }
350 
format_symbol_name( fmt: fn(&str, &mut fmt::Formatter) -> fmt::Result, mut bytes: &[u8], f: &mut fmt::Formatter, ) -> fmt::Result351 fn format_symbol_name(
352     fmt: fn(&str, &mut fmt::Formatter) -> fmt::Result,
353     mut bytes: &[u8],
354     f: &mut fmt::Formatter,
355 ) -> fmt::Result {
356     while bytes.len() > 0 {
357         match str::from_utf8(bytes) {
358             Ok(name) => {
359                 fmt(name, f)?;
360                 break;
361             }
362             Err(err) => {
363                 fmt("\u{FFFD}", f)?;
364 
365                 match err.error_len() {
366                     Some(len) => bytes = &bytes[err.valid_up_to() + len..],
367                     None => break,
368                 }
369             }
370         }
371     }
372     Ok(())
373 }
374 
375 cfg_if::cfg_if! {
376     if #[cfg(feature = "cpp_demangle")] {
377         impl<'a> fmt::Display for SymbolName<'a> {
378             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
379                 if let Some(ref s) = self.demangled {
380                     s.fmt(f)
381                 } else if let Some(ref cpp) = self.cpp_demangled.0 {
382                     cpp.fmt(f)
383                 } else {
384                     format_symbol_name(fmt::Display::fmt, self.bytes, f)
385                 }
386             }
387         }
388     } else {
389         impl<'a> fmt::Display for SymbolName<'a> {
390             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
391                 if let Some(ref s) = self.demangled {
392                     s.fmt(f)
393                 } else {
394                     format_symbol_name(fmt::Display::fmt, self.bytes, f)
395                 }
396             }
397         }
398     }
399 }
400 
401 cfg_if::cfg_if! {
402     if #[cfg(all(feature = "std", feature = "cpp_demangle"))] {
403         impl<'a> fmt::Debug for SymbolName<'a> {
404             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
405                 use std::fmt::Write;
406 
407                 if let Some(ref s) = self.demangled {
408                     return s.fmt(f)
409                 }
410 
411                 // This may to print if the demangled symbol isn't actually
412                 // valid, so handle the error here gracefully by not propagating
413                 // it outwards.
414                 if let Some(ref cpp) = self.cpp_demangled.0 {
415                     let mut s = String::new();
416                     if write!(s, "{}", cpp).is_ok() {
417                         return s.fmt(f)
418                     }
419                 }
420 
421                 format_symbol_name(fmt::Debug::fmt, self.bytes, f)
422             }
423         }
424     } else {
425         impl<'a> fmt::Debug for SymbolName<'a> {
426             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
427                 if let Some(ref s) = self.demangled {
428                     s.fmt(f)
429                 } else {
430                     format_symbol_name(fmt::Debug::fmt, self.bytes, f)
431                 }
432             }
433         }
434     }
435 }
436 
437 /// Attempt to reclaim that cached memory used to symbolicate addresses.
438 ///
439 /// This method will attempt to release any global data structures that have
440 /// otherwise been cached globally or in the thread which typically represent
441 /// parsed DWARF information or similar.
442 ///
443 /// # Caveats
444 ///
445 /// While this function is always available it doesn't actually do anything on
446 /// most implementations. Libraries like dbghelp or libbacktrace do not provide
447 /// facilities to deallocate state and manage the allocated memory. For now the
448 /// `gimli-symbolize` feature of this crate is the only feature where this
449 /// function has any effect.
450 #[cfg(feature = "std")]
clear_symbol_cache()451 pub fn clear_symbol_cache() {
452     let _guard = crate::lock::lock();
453     unsafe {
454         clear_symbol_cache_imp();
455     }
456 }
457 
458 mod dladdr;
459 
460 cfg_if::cfg_if! {
461     if #[cfg(all(windows, target_env = "msvc", feature = "dbghelp", not(target_vendor = "uwp")))] {
462         mod dbghelp;
463         use self::dbghelp::resolve as resolve_imp;
464         use self::dbghelp::Symbol as SymbolImp;
465         unsafe fn clear_symbol_cache_imp() {}
466     } else if #[cfg(all(
467         feature = "std",
468         feature = "gimli-symbolize",
469         any(
470             target_os = "linux",
471             target_os = "macos",
472             windows,
473         ),
474     ))] {
475         mod gimli;
476         use self::gimli::resolve as resolve_imp;
477         use self::gimli::Symbol as SymbolImp;
478         use self::gimli::clear_symbol_cache as clear_symbol_cache_imp;
479     // Note that we only enable coresymbolication on iOS when debug assertions
480     // are enabled because it's helpful in debug mode but it looks like apps get
481     // rejected from the app store if they use this API, see #92 for more info
482     } else if #[cfg(all(feature = "coresymbolication",
483                         any(target_os = "macos",
484                             all(target_os = "ios", debug_assertions))))] {
485         mod coresymbolication;
486         use self::coresymbolication::resolve as resolve_imp;
487         use self::coresymbolication::Symbol as SymbolImp;
488         unsafe fn clear_symbol_cache_imp() {}
489     } else if #[cfg(all(feature = "libbacktrace",
490                         any(unix, all(windows, not(target_vendor = "uwp"), target_env = "gnu")),
491                         not(target_os = "fuchsia"),
492                         not(target_os = "emscripten")))] {
493         mod libbacktrace;
494         use self::libbacktrace::resolve as resolve_imp;
495         use self::libbacktrace::Symbol as SymbolImp;
496         unsafe fn clear_symbol_cache_imp() {}
497     } else if #[cfg(all(unix,
498                         not(target_os = "emscripten"),
499                         not(target_os = "fuchsia"),
500                         feature = "dladdr"))] {
501         mod dladdr_resolve;
502         use self::dladdr_resolve::resolve as resolve_imp;
503         use self::dladdr_resolve::Symbol as SymbolImp;
504         unsafe fn clear_symbol_cache_imp() {}
505     } else {
506         mod noop;
507         use self::noop::resolve as resolve_imp;
508         use self::noop::Symbol as SymbolImp;
509         #[allow(unused)]
510         unsafe fn clear_symbol_cache_imp() {}
511     }
512 }
513