]> git.proxmox.com Git - rustc.git/blame - vendor/backtrace/src/symbolize/mod.rs
New upstream version 1.36.0+dfsg1
[rustc.git] / vendor / backtrace / src / symbolize / mod.rs
CommitLineData
0731742a
XL
1use core::{fmt, str};
2
3cfg_if! {
4 if #[cfg(feature = "std")] {
5 use std::path::Path;
6 use std::prelude::v1::*;
7 }
8}
9
10use types::{BytesOrWideString, c_void};
041b39d2 11use rustc_demangle::{try_demangle, Demangle};
7cac9316
XL
12
13/// Resolve an address to a symbol, passing the symbol to the specified
14/// closure.
15///
16/// This function will look up the given address in areas such as the local
17/// symbol table, dynamic symbol table, or DWARF debug info (depending on the
18/// activated implementation) to find symbols to yield.
19///
20/// The closure may not be called if resolution could not be performed, and it
21/// also may be called more than once in the case of inlined functions.
22///
23/// Symbols yielded represent the execution at the specified `addr`, returning
ea8adc8c 24/// file/line pairs for that address (if available).
7cac9316 25///
0731742a
XL
26/// # Required features
27///
28/// This function requires the `std` feature of the `backtrace` crate to be
29/// enabled, and the `std` feature is enabled by default.
30///
7cac9316
XL
31/// # Example
32///
33/// ```
34/// extern crate backtrace;
35///
36/// fn main() {
37/// backtrace::trace(|frame| {
38/// let ip = frame.ip();
39///
40/// backtrace::resolve(ip, |symbol| {
41/// // ...
42/// });
43///
44/// false // only look at the top frame
45/// });
46/// }
47/// ```
0731742a
XL
48#[cfg(feature = "std")]
49pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, cb: F) {
50 let _guard = ::lock::lock();
51 unsafe { resolve_unsynchronized(addr, cb) }
52}
53
54/// Same as `resolve`, only unsafe as it's unsynchronized.
55///
56/// This function does not have synchronization guarentees but is available when
57/// the `std` feature of this crate isn't compiled in. See the `resolve`
58/// function for more documentation and examples.
59pub unsafe fn resolve_unsynchronized<F>(addr: *mut c_void, mut cb: F)
60 where F: FnMut(&Symbol)
61{
62 resolve_imp(addr as *mut _, &mut cb)
7cac9316
XL
63}
64
0731742a 65
7cac9316
XL
66/// A trait representing the resolution of a symbol in a file.
67///
68/// This trait is yielded as a trait object to the closure given to the
69/// `backtrace::resolve` function, and it is virtually dispatched as it's
70/// unknown which implementation is behind it.
71///
ea8adc8c 72/// A symbol can give contextual information about a function, for example the
7cac9316
XL
73/// name, filename, line number, precise address, etc. Not all information is
74/// always available in a symbol, however, so all methods return an `Option`.
75pub struct Symbol {
76 inner: SymbolImp,
77}
78
79impl Symbol {
80 /// Returns the name of this function.
81 ///
82 /// The returned structure can be used to query various properties about the
83 /// symbol name:
84 ///
85 /// * The `Display` implementation will print out the demangled symbol.
86 /// * The raw `str` value of the symbol can be accessed (if it's valid
87 /// utf-8).
88 /// * The raw bytes for the symbol name can be accessed.
89 pub fn name(&self) -> Option<SymbolName> {
90 self.inner.name()
91 }
92
93 /// Returns the starting address of this function.
94 pub fn addr(&self) -> Option<*mut c_void> {
0731742a 95 self.inner.addr().map(|p| p as *mut _)
7cac9316
XL
96 }
97
0731742a
XL
98 /// Returns the raw filename as a slice. This is mainly useful for `no_std`
99 /// environments.
100 pub fn filename_raw(&self) -> Option<BytesOrWideString> {
101 self.inner.filename_raw()
7cac9316
XL
102 }
103
0731742a 104
7cac9316
XL
105 /// Returns the line number for where this symbol is currently executing.
106 ///
107 /// This return value is typically `Some` if `filename` returns `Some`, and
108 /// is consequently subject to similar caveats.
109 pub fn lineno(&self) -> Option<u32> {
110 self.inner.lineno()
111 }
0731742a
XL
112
113 /// Returns the file name where this function was defined.
114 ///
115 /// This is currently only available when libbacktrace is being used (e.g.
116 /// unix platforms other than OSX) and when a binary is compiled with
117 /// debuginfo. If neither of these conditions is met then this will likely
118 /// return `None`.
119 ///
120 /// This function requires the `std` feature to be enabled for this crate.
121 #[cfg(feature = "std")]
122 pub fn filename(&self) -> Option<&Path> {
123 #[cfg(not(windows))]
124 {
125 use std::ffi::OsStr;
126 use std::os::unix::ffi::OsStrExt;
127
128 match self.filename_raw() {
129 Some(BytesOrWideString::Bytes(slice)) => {
130 Some(Path::new(OsStr::from_bytes(slice)))
131 }
132 None => None,
133 _ => unreachable!(),
134 }
135 }
136 #[cfg(windows)]
137 {
138 self.inner.filename().map(Path::new)
139 }
140 }
7cac9316
XL
141}
142
143impl fmt::Debug for Symbol {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 let mut d = f.debug_struct("Symbol");
146 if let Some(name) = self.name() {
147 d.field("name", &name);
148 }
149 if let Some(addr) = self.addr() {
150 d.field("addr", &addr);
151 }
0731742a
XL
152
153 #[cfg(feature = "std")] {
154 if let Some(filename) = self.filename() {
155 d.field("filename", &filename);
156 }
7cac9316 157 }
0731742a 158
7cac9316
XL
159 if let Some(lineno) = self.lineno() {
160 d.field("lineno", &lineno);
161 }
162 d.finish()
163 }
164}
165
041b39d2
XL
166cfg_if! {
167 if #[cfg(feature = "cpp_demangle")] {
168 // Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust
169 // failed.
170 struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>);
171
172 impl<'a> OptionCppSymbol<'a> {
173 fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> {
174 OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok())
175 }
176
177 fn none() -> OptionCppSymbol<'a> {
178 OptionCppSymbol(None)
179 }
180 }
181 } else {
0731742a
XL
182 use core::marker::PhantomData;
183
041b39d2
XL
184 // Make sure to keep this zero-sized, so that the `cpp_demangle` feature
185 // has no cost when disabled.
186 struct OptionCppSymbol<'a>(PhantomData<&'a ()>);
187
188 impl<'a> OptionCppSymbol<'a> {
189 fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> {
190 OptionCppSymbol(PhantomData)
191 }
192
193 fn none() -> OptionCppSymbol<'a> {
194 OptionCppSymbol(PhantomData)
195 }
196 }
197 }
198}
199
7cac9316
XL
200/// A wrapper around a symbol name to provide ergonomic accessors to the
201/// demangled name, the raw bytes, the raw string, etc.
041b39d2
XL
202// Allow dead code for when the `cpp_demangle` feature is not enabled.
203#[allow(dead_code)]
7cac9316
XL
204pub struct SymbolName<'a> {
205 bytes: &'a [u8],
206 demangled: Option<Demangle<'a>>,
041b39d2 207 cpp_demangled: OptionCppSymbol<'a>,
7cac9316
XL
208}
209
210impl<'a> SymbolName<'a> {
211 /// Creates a new symbol name from the raw underlying bytes.
212 pub fn new(bytes: &'a [u8]) -> SymbolName<'a> {
041b39d2
XL
213 let str_bytes = str::from_utf8(bytes).ok();
214 let demangled = str_bytes.and_then(|s| try_demangle(s).ok());
215
216 let cpp = if demangled.is_none() {
217 OptionCppSymbol::parse(bytes)
218 } else {
219 OptionCppSymbol::none()
220 };
221
7cac9316
XL
222 SymbolName {
223 bytes: bytes,
224 demangled: demangled,
041b39d2 225 cpp_demangled: cpp,
7cac9316
XL
226 }
227 }
228
041b39d2 229 /// Returns the raw symbol name as a `str` if the symbols is valid utf-8.
7cac9316 230 pub fn as_str(&self) -> Option<&'a str> {
041b39d2
XL
231 self.demangled
232 .as_ref()
233 .map(|s| s.as_str())
234 .or_else(|| {
235 str::from_utf8(self.bytes).ok()
236 })
7cac9316
XL
237 }
238
239 /// Returns the raw symbol name as a list of bytes
240 pub fn as_bytes(&self) -> &'a [u8] {
241 self.bytes
242 }
243}
244
0731742a
XL
245fn format_symbol_name(fmt: fn(&str, &mut fmt::Formatter) -> fmt::Result,
246 mut bytes: &[u8],
247 f: &mut fmt::Formatter)
248 -> fmt::Result
249{
250 while bytes.len() > 0 {
251 match str::from_utf8(bytes) {
252 Ok(name) => {
253 fmt(name, f)?;
254 break
255 }
256 Err(err) => {
257 fmt("\u{FFFD}", f)?;
258
259 match err.error_len() {
260 Some(len) => bytes = &bytes[err.valid_up_to() + len..],
261 None => break,
262 }
263 }
264 }
265 }
266 Ok(())
267}
268
041b39d2
XL
269cfg_if! {
270 if #[cfg(feature = "cpp_demangle")] {
271 impl<'a> fmt::Display for SymbolName<'a> {
272 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
273 if let Some(ref s) = self.demangled {
274 s.fmt(f)
275 } else if let Some(ref cpp) = self.cpp_demangled.0 {
276 cpp.fmt(f)
277 } else {
0731742a 278 format_symbol_name(fmt::Display::fmt, self.bytes, f)
041b39d2
XL
279 }
280 }
281 }
282 } else {
283 impl<'a> fmt::Display for SymbolName<'a> {
284 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285 if let Some(ref s) = self.demangled {
286 s.fmt(f)
287 } else {
0731742a 288 format_symbol_name(fmt::Display::fmt, self.bytes, f)
041b39d2
XL
289 }
290 }
7cac9316
XL
291 }
292 }
293}
294
041b39d2 295cfg_if! {
0731742a 296 if #[cfg(all(feature = "std", feature = "cpp_demangle"))] {
041b39d2
XL
297 impl<'a> fmt::Debug for SymbolName<'a> {
298 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
299 use std::fmt::Write;
300
301 if let Some(ref s) = self.demangled {
302 return s.fmt(f)
303 }
304
305 // This may to print if the demangled symbol isn't actually
306 // valid, so handle the error here gracefully by not propagating
307 // it outwards.
308 if let Some(ref cpp) = self.cpp_demangled.0 {
309 let mut s = String::new();
310 if write!(s, "{}", cpp).is_ok() {
311 return s.fmt(f)
312 }
313 }
314
0731742a 315 format_symbol_name(fmt::Debug::fmt, self.bytes, f)
041b39d2
XL
316 }
317 }
318 } else {
319 impl<'a> fmt::Debug for SymbolName<'a> {
320 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
321 if let Some(ref s) = self.demangled {
322 s.fmt(f)
323 } else {
0731742a 324 format_symbol_name(fmt::Debug::fmt, self.bytes, f)
041b39d2
XL
325 }
326 }
7cac9316
XL
327 }
328 }
329}
330
331cfg_if! {
332 if #[cfg(all(windows, feature = "dbghelp"))] {
333 mod dbghelp;
334 use self::dbghelp::resolve as resolve_imp;
335 use self::dbghelp::Symbol as SymbolImp;
0731742a
XL
336 } else if #[cfg(all(feature = "std",
337 feature = "gimli-symbolize",
ea8adc8c
XL
338 unix,
339 target_os = "linux"))] {
340 mod gimli;
341 use self::gimli::resolve as resolve_imp;
342 use self::gimli::Symbol as SymbolImp;
7cac9316
XL
343 } else if #[cfg(all(feature = "libbacktrace",
344 unix,
abe05a73 345 not(target_os = "fuchsia"),
7cac9316 346 not(target_os = "emscripten"),
041b39d2
XL
347 not(target_os = "macos"),
348 not(target_os = "ios")))] {
7cac9316
XL
349 mod libbacktrace;
350 use self::libbacktrace::resolve as resolve_imp;
351 use self::libbacktrace::Symbol as SymbolImp;
83c7162d
XL
352
353 // Note that we only enable coresymbolication on iOS when debug assertions
354 // are enabled because it's helpful in debug mode but it looks like apps get
355 // rejected from the app store if they use this API, see #92 for more info
7cac9316 356 } else if #[cfg(all(feature = "coresymbolication",
041b39d2 357 any(target_os = "macos",
83c7162d 358 all(target_os = "ios", debug_assertions))))] {
7cac9316
XL
359 mod coresymbolication;
360 use self::coresymbolication::resolve as resolve_imp;
361 use self::coresymbolication::Symbol as SymbolImp;
362 } else if #[cfg(all(unix,
363 not(target_os = "emscripten"),
364 feature = "dladdr"))] {
365 mod dladdr;
366 use self::dladdr::resolve as resolve_imp;
367 use self::dladdr::Symbol as SymbolImp;
368 } else {
369 mod noop;
370 use self::noop::resolve as resolve_imp;
371 use self::noop::Symbol as SymbolImp;
372 }
373}