]> git.proxmox.com Git - rustc.git/blob - library/backtrace/src/symbolize/mod.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / library / backtrace / src / symbolize / mod.rs
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 super::backtrace::Frame;
11 use super::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")]
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 function 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")]
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)]
115 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.
141 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 guarantees 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.
158 pub unsafe fn resolve_unsynchronized<F>(addr: *mut c_void, mut cb: F)
159 where
160 F: FnMut(&Symbol),
161 {
162 imp::resolve(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 guarantees 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.
174 pub unsafe fn resolve_frame_unsynchronized<F>(frame: &Frame, mut cb: F)
175 where
176 F: FnMut(&Symbol),
177 {
178 imp::resolve(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: imp::Symbol<'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.
207 pub fn name(&self) -> Option<SymbolName<'_>> {
208 self.inner.name()
209 }
210
211 /// Returns the starting address of this function.
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.
218 pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> {
219 self.inner.filename_raw()
220 }
221
222 /// Returns the column number for where this symbol is currently executing.
223 ///
224 /// Only gimli currently provides a value here and even then only if `filename`
225 /// returns `Some`, and so it is then consequently subject to similar caveats.
226 pub fn colno(&self) -> Option<u32> {
227 self.inner.colno()
228 }
229
230 /// Returns the line number for where this symbol is currently executing.
231 ///
232 /// This return value is typically `Some` if `filename` returns `Some`, and
233 /// is consequently subject to similar caveats.
234 pub fn lineno(&self) -> Option<u32> {
235 self.inner.lineno()
236 }
237
238 /// Returns the file name where this function was defined.
239 ///
240 /// This is currently only available when libbacktrace or gimli is being
241 /// used (e.g. unix platforms other) and when a binary is compiled with
242 /// debuginfo. If neither of these conditions is met then this will likely
243 /// return `None`.
244 ///
245 /// # Required features
246 ///
247 /// This function requires the `std` feature of the `backtrace` crate to be
248 /// enabled, and the `std` feature is enabled by default.
249 #[cfg(feature = "std")]
250 #[allow(unreachable_code)]
251 pub fn filename(&self) -> Option<&Path> {
252 self.inner.filename()
253 }
254 }
255
256 impl fmt::Debug for Symbol {
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 let mut d = f.debug_struct("Symbol");
259 if let Some(name) = self.name() {
260 d.field("name", &name);
261 }
262 if let Some(addr) = self.addr() {
263 d.field("addr", &addr);
264 }
265
266 #[cfg(feature = "std")]
267 {
268 if let Some(filename) = self.filename() {
269 d.field("filename", &filename);
270 }
271 }
272
273 if let Some(lineno) = self.lineno() {
274 d.field("lineno", &lineno);
275 }
276 d.finish()
277 }
278 }
279
280 cfg_if::cfg_if! {
281 if #[cfg(feature = "cpp_demangle")] {
282 // Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust
283 // failed.
284 struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>);
285
286 impl<'a> OptionCppSymbol<'a> {
287 fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> {
288 OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok())
289 }
290
291 fn none() -> OptionCppSymbol<'a> {
292 OptionCppSymbol(None)
293 }
294 }
295 } else {
296 use core::marker::PhantomData;
297
298 // Make sure to keep this zero-sized, so that the `cpp_demangle` feature
299 // has no cost when disabled.
300 struct OptionCppSymbol<'a>(PhantomData<&'a ()>);
301
302 impl<'a> OptionCppSymbol<'a> {
303 fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> {
304 OptionCppSymbol(PhantomData)
305 }
306
307 fn none() -> OptionCppSymbol<'a> {
308 OptionCppSymbol(PhantomData)
309 }
310 }
311 }
312 }
313
314 /// A wrapper around a symbol name to provide ergonomic accessors to the
315 /// demangled name, the raw bytes, the raw string, etc.
316 // Allow dead code for when the `cpp_demangle` feature is not enabled.
317 #[allow(dead_code)]
318 pub struct SymbolName<'a> {
319 bytes: &'a [u8],
320 demangled: Option<Demangle<'a>>,
321 cpp_demangled: OptionCppSymbol<'a>,
322 }
323
324 impl<'a> SymbolName<'a> {
325 /// Creates a new symbol name from the raw underlying bytes.
326 pub fn new(bytes: &'a [u8]) -> SymbolName<'a> {
327 let str_bytes = str::from_utf8(bytes).ok();
328 let demangled = str_bytes.and_then(|s| try_demangle(s).ok());
329
330 let cpp = if demangled.is_none() {
331 OptionCppSymbol::parse(bytes)
332 } else {
333 OptionCppSymbol::none()
334 };
335
336 SymbolName {
337 bytes: bytes,
338 demangled: demangled,
339 cpp_demangled: cpp,
340 }
341 }
342
343 /// Returns the raw (mangled) symbol name as a `str` if the symbol is valid utf-8.
344 ///
345 /// Use the `Display` implementation if you want the demangled version.
346 pub fn as_str(&self) -> Option<&'a str> {
347 self.demangled
348 .as_ref()
349 .map(|s| s.as_str())
350 .or_else(|| str::from_utf8(self.bytes).ok())
351 }
352
353 /// Returns the raw symbol name as a list of bytes
354 pub fn as_bytes(&self) -> &'a [u8] {
355 self.bytes
356 }
357 }
358
359 fn format_symbol_name(
360 fmt: fn(&str, &mut fmt::Formatter<'_>) -> fmt::Result,
361 mut bytes: &[u8],
362 f: &mut fmt::Formatter<'_>,
363 ) -> fmt::Result {
364 while bytes.len() > 0 {
365 match str::from_utf8(bytes) {
366 Ok(name) => {
367 fmt(name, f)?;
368 break;
369 }
370 Err(err) => {
371 fmt("\u{FFFD}", f)?;
372
373 match err.error_len() {
374 Some(len) => bytes = &bytes[err.valid_up_to() + len..],
375 None => break,
376 }
377 }
378 }
379 }
380 Ok(())
381 }
382
383 cfg_if::cfg_if! {
384 if #[cfg(feature = "cpp_demangle")] {
385 impl<'a> fmt::Display for SymbolName<'a> {
386 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387 if let Some(ref s) = self.demangled {
388 s.fmt(f)
389 } else if let Some(ref cpp) = self.cpp_demangled.0 {
390 cpp.fmt(f)
391 } else {
392 format_symbol_name(fmt::Display::fmt, self.bytes, f)
393 }
394 }
395 }
396 } else {
397 impl<'a> fmt::Display for SymbolName<'a> {
398 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
399 if let Some(ref s) = self.demangled {
400 s.fmt(f)
401 } else {
402 format_symbol_name(fmt::Display::fmt, self.bytes, f)
403 }
404 }
405 }
406 }
407 }
408
409 cfg_if::cfg_if! {
410 if #[cfg(all(feature = "std", feature = "cpp_demangle"))] {
411 impl<'a> fmt::Debug for SymbolName<'a> {
412 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
413 use std::fmt::Write;
414
415 if let Some(ref s) = self.demangled {
416 return s.fmt(f)
417 }
418
419 // This may to print if the demangled symbol isn't actually
420 // valid, so handle the error here gracefully by not propagating
421 // it outwards.
422 if let Some(ref cpp) = self.cpp_demangled.0 {
423 let mut s = String::new();
424 if write!(s, "{}", cpp).is_ok() {
425 return s.fmt(f)
426 }
427 }
428
429 format_symbol_name(fmt::Debug::fmt, self.bytes, f)
430 }
431 }
432 } else {
433 impl<'a> fmt::Debug for SymbolName<'a> {
434 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435 if let Some(ref s) = self.demangled {
436 s.fmt(f)
437 } else {
438 format_symbol_name(fmt::Debug::fmt, self.bytes, f)
439 }
440 }
441 }
442 }
443 }
444
445 /// Attempt to reclaim that cached memory used to symbolicate addresses.
446 ///
447 /// This method will attempt to release any global data structures that have
448 /// otherwise been cached globally or in the thread which typically represent
449 /// parsed DWARF information or similar.
450 ///
451 /// # Caveats
452 ///
453 /// While this function is always available it doesn't actually do anything on
454 /// most implementations. Libraries like dbghelp or libbacktrace do not provide
455 /// facilities to deallocate state and manage the allocated memory. For now the
456 /// `gimli-symbolize` feature of this crate is the only feature where this
457 /// function has any effect.
458 #[cfg(feature = "std")]
459 pub fn clear_symbol_cache() {
460 let _guard = crate::lock::lock();
461 unsafe {
462 imp::clear_symbol_cache();
463 }
464 }
465
466 cfg_if::cfg_if! {
467 if #[cfg(miri)] {
468 mod miri;
469 use miri as imp;
470 } else if #[cfg(all(windows, target_env = "msvc", not(target_vendor = "uwp")))] {
471 mod dbghelp;
472 use dbghelp as imp;
473 } else if #[cfg(all(
474 any(unix, windows),
475 not(target_vendor = "uwp"),
476 not(target_os = "emscripten"),
477 any(not(backtrace_in_libstd), feature = "backtrace"),
478 ))] {
479 mod gimli;
480 use gimli as imp;
481 } else {
482 mod noop;
483 use noop as imp;
484 }
485 }