/rust/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/symbolize/mod.rs
Line | Count | Source |
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 | 0 | pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, cb: F) { |
62 | 0 | let _guard = crate::lock::lock(); |
63 | 0 | unsafe { resolve_unsynchronized(addr, cb) } |
64 | 0 | } |
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 | 0 | pub fn resolve_frame<F: FnMut(&Symbol)>(frame: &Frame, cb: F) { |
104 | 0 | let _guard = crate::lock::lock(); |
105 | 0 | unsafe { resolve_frame_unsynchronized(frame, cb) } |
106 | 0 | } Unexecuted instantiation: backtrace::symbolize::resolve_frame::<<pprof::frames::Frames as core::convert::From<pprof::frames::UnresolvedFrames>>::from::{closure#0}>Unexecuted instantiation: backtrace::symbolize::resolve_frame::<<backtrace::capture::Frame>::resolve_symbols::{closure#0}> |
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 | 0 | fn address_or_ip(&self) -> *mut c_void { |
116 | 0 | match self { |
117 | 0 | ResolveWhat::Address(a) => adjust_ip(*a), |
118 | 0 | ResolveWhat::Frame(f) => adjust_ip(f.ip()), |
119 | | } |
120 | 0 | } |
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 | 0 | fn adjust_ip(a: *mut c_void) -> *mut c_void { |
142 | 0 | if a.is_null() { |
143 | 0 | a |
144 | | } else { |
145 | 0 | (a as usize - 1) as *mut c_void |
146 | | } |
147 | 0 | } |
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 | 0 | pub unsafe fn resolve_unsynchronized<F>(addr: *mut c_void, mut cb: F) |
159 | 0 | where |
160 | 0 | F: FnMut(&Symbol), |
161 | | { |
162 | 0 | imp::resolve(ResolveWhat::Address(addr), &mut cb) |
163 | 0 | } |
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 | 0 | pub unsafe fn resolve_frame_unsynchronized<F>(frame: &Frame, mut cb: F) |
175 | 0 | where |
176 | 0 | F: FnMut(&Symbol), |
177 | | { |
178 | 0 | imp::resolve(ResolveWhat::Frame(frame), &mut cb) |
179 | 0 | } Unexecuted instantiation: backtrace::symbolize::resolve_frame_unsynchronized::<<pprof::frames::Frames as core::convert::From<pprof::frames::UnresolvedFrames>>::from::{closure#0}>Unexecuted instantiation: backtrace::symbolize::resolve_frame_unsynchronized::<<backtrace::capture::Frame>::resolve_symbols::{closure#0}> |
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 | 0 | pub fn name(&self) -> Option<SymbolName<'_>> { |
208 | 0 | self.inner.name() |
209 | 0 | } |
210 | | |
211 | | /// Returns the starting address of this function. |
212 | 0 | pub fn addr(&self) -> Option<*mut c_void> { |
213 | 0 | self.inner.addr() |
214 | 0 | } |
215 | | |
216 | | /// Returns the raw filename as a slice. This is mainly useful for `no_std` |
217 | | /// environments. |
218 | 0 | pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> { |
219 | 0 | self.inner.filename_raw() |
220 | 0 | } |
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 | 0 | pub fn colno(&self) -> Option<u32> { |
227 | 0 | self.inner.colno() |
228 | 0 | } |
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 | 0 | pub fn lineno(&self) -> Option<u32> { |
235 | 0 | self.inner.lineno() |
236 | 0 | } |
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 | 0 | pub fn filename(&self) -> Option<&Path> { |
252 | 0 | self.inner.filename() |
253 | 0 | } |
254 | | } |
255 | | |
256 | | impl fmt::Debug for Symbol { |
257 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
258 | 0 | let mut d = f.debug_struct("Symbol"); |
259 | 0 | if let Some(name) = self.name() { |
260 | 0 | d.field("name", &name); |
261 | 0 | } |
262 | 0 | if let Some(addr) = self.addr() { |
263 | 0 | d.field("addr", &addr); |
264 | 0 | } |
265 | | |
266 | | #[cfg(feature = "std")] |
267 | | { |
268 | 0 | if let Some(filename) = self.filename() { |
269 | 0 | d.field("filename", &filename); |
270 | 0 | } |
271 | | } |
272 | | |
273 | 0 | if let Some(lineno) = self.lineno() { |
274 | 0 | d.field("lineno", &lineno); |
275 | 0 | } |
276 | 0 | d.finish() |
277 | 0 | } |
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 | | } |
296 | | } |
297 | | |
298 | | /// A wrapper around a symbol name to provide ergonomic accessors to the |
299 | | /// demangled name, the raw bytes, the raw string, etc. |
300 | | pub struct SymbolName<'a> { |
301 | | bytes: &'a [u8], |
302 | | demangled: Option<Demangle<'a>>, |
303 | | #[cfg(feature = "cpp_demangle")] |
304 | | cpp_demangled: OptionCppSymbol<'a>, |
305 | | } |
306 | | |
307 | | impl<'a> SymbolName<'a> { |
308 | | /// Creates a new symbol name from the raw underlying bytes. |
309 | 0 | pub fn new(bytes: &'a [u8]) -> SymbolName<'a> { |
310 | 0 | let str_bytes = str::from_utf8(bytes).ok(); |
311 | 0 | let demangled = str_bytes.and_then(|s| try_demangle(s).ok()); |
312 | | |
313 | | #[cfg(feature = "cpp_demangle")] |
314 | | let cpp = if demangled.is_none() { |
315 | | OptionCppSymbol::parse(bytes) |
316 | | } else { |
317 | | OptionCppSymbol::none() |
318 | | }; |
319 | | |
320 | 0 | SymbolName { |
321 | 0 | bytes, |
322 | 0 | demangled, |
323 | 0 | #[cfg(feature = "cpp_demangle")] |
324 | 0 | cpp_demangled: cpp, |
325 | 0 | } |
326 | 0 | } |
327 | | |
328 | | /// Returns the raw (mangled) symbol name as a `str` if the symbol is valid utf-8. |
329 | | /// |
330 | | /// Use the `Display` implementation if you want the demangled version. |
331 | 0 | pub fn as_str(&self) -> Option<&'a str> { |
332 | 0 | self.demangled |
333 | 0 | .as_ref() |
334 | 0 | .map(|s| s.as_str()) |
335 | 0 | .or_else(|| str::from_utf8(self.bytes).ok()) |
336 | 0 | } |
337 | | |
338 | | /// Returns the raw symbol name as a list of bytes |
339 | 0 | pub fn as_bytes(&self) -> &'a [u8] { |
340 | 0 | self.bytes |
341 | 0 | } |
342 | | } |
343 | | |
344 | 0 | fn format_symbol_name( |
345 | 0 | fmt: fn(&str, &mut fmt::Formatter<'_>) -> fmt::Result, |
346 | 0 | mut bytes: &[u8], |
347 | 0 | f: &mut fmt::Formatter<'_>, |
348 | 0 | ) -> fmt::Result { |
349 | 0 | while bytes.len() > 0 { |
350 | 0 | match str::from_utf8(bytes) { |
351 | 0 | Ok(name) => { |
352 | 0 | fmt(name, f)?; |
353 | 0 | break; |
354 | | } |
355 | 0 | Err(err) => { |
356 | 0 | fmt("\u{FFFD}", f)?; |
357 | | |
358 | 0 | match err.error_len() { |
359 | 0 | Some(len) => bytes = &bytes[err.valid_up_to() + len..], |
360 | 0 | None => break, |
361 | | } |
362 | | } |
363 | | } |
364 | | } |
365 | 0 | Ok(()) |
366 | 0 | } |
367 | | |
368 | | impl<'a> fmt::Display for SymbolName<'a> { |
369 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
370 | 0 | if let Some(ref s) = self.demangled { |
371 | 0 | return s.fmt(f); |
372 | 0 | } |
373 | | |
374 | | #[cfg(feature = "cpp_demangle")] |
375 | | { |
376 | | if let Some(ref cpp) = self.cpp_demangled.0 { |
377 | | return cpp.fmt(f); |
378 | | } |
379 | | } |
380 | | |
381 | 0 | format_symbol_name(fmt::Display::fmt, self.bytes, f) |
382 | 0 | } |
383 | | } |
384 | | |
385 | | impl<'a> fmt::Debug for SymbolName<'a> { |
386 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
387 | 0 | if let Some(ref s) = self.demangled { |
388 | 0 | return s.fmt(f); |
389 | 0 | } |
390 | | |
391 | | #[cfg(all(feature = "std", feature = "cpp_demangle"))] |
392 | | { |
393 | | use std::fmt::Write; |
394 | | |
395 | | // This may to print if the demangled symbol isn't actually |
396 | | // valid, so handle the error here gracefully by not propagating |
397 | | // it outwards. |
398 | | if let Some(ref cpp) = self.cpp_demangled.0 { |
399 | | let mut s = String::new(); |
400 | | if write!(s, "{cpp}").is_ok() { |
401 | | return s.fmt(f); |
402 | | } |
403 | | } |
404 | | } |
405 | | |
406 | 0 | format_symbol_name(fmt::Debug::fmt, self.bytes, f) |
407 | 0 | } |
408 | | } |
409 | | |
410 | | /// Attempt to reclaim that cached memory used to symbolicate addresses. |
411 | | /// |
412 | | /// This method will attempt to release any global data structures that have |
413 | | /// otherwise been cached globally or in the thread which typically represent |
414 | | /// parsed DWARF information or similar. |
415 | | /// |
416 | | /// # Caveats |
417 | | /// |
418 | | /// While this function is always available it doesn't actually do anything on |
419 | | /// most implementations. Libraries like dbghelp or libbacktrace do not provide |
420 | | /// facilities to deallocate state and manage the allocated memory. For now the |
421 | | /// `std` feature of this crate is the only feature where this |
422 | | /// function has any effect. |
423 | | #[cfg(feature = "std")] |
424 | 0 | pub fn clear_symbol_cache() { |
425 | 0 | let _guard = crate::lock::lock(); |
426 | 0 | unsafe { |
427 | 0 | imp::clear_symbol_cache(); |
428 | 0 | } |
429 | 0 | } |
430 | | |
431 | | cfg_if::cfg_if! { |
432 | | if #[cfg(miri)] { |
433 | | mod miri; |
434 | | use miri as imp; |
435 | | } else if #[cfg(all(windows, target_env = "msvc", not(target_vendor = "uwp")))] { |
436 | | mod dbghelp; |
437 | | use dbghelp as imp; |
438 | | } else if #[cfg(all( |
439 | | any(unix, all(windows, target_env = "gnu")), |
440 | | not(target_vendor = "uwp"), |
441 | | not(target_os = "emscripten"), |
442 | | any(not(backtrace_in_libstd), feature = "backtrace"), |
443 | | ))] { |
444 | | mod gimli; |
445 | | use gimli as imp; |
446 | | } else { |
447 | | mod noop; |
448 | | use noop as imp; |
449 | | } |
450 | | } |