| 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: LockGuard = 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: LockGuard = 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: &*mut c_void) => adjust_ip(*a), |
| 118 | ResolveWhat::Frame(f: &&Frame) => 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(what: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(what: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() |
| 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: DebugStruct<'_, '_> = f.debug_struct(name:"Symbol" ); |
| 259 | if let Some(name: SymbolName<'_>) = self.name() { |
| 260 | d.field(name:"name" , &name); |
| 261 | } |
| 262 | if let Some(addr: *mut c_void) = self.addr() { |
| 263 | d.field(name:"addr" , &addr); |
| 264 | } |
| 265 | |
| 266 | #[cfg (feature = "std" )] |
| 267 | { |
| 268 | if let Some(filename: &Path) = self.filename() { |
| 269 | d.field(name:"filename" , &filename); |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | if let Some(lineno: u32) = self.lineno() { |
| 274 | d.field(name:"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: &str) => { |
| 367 | fmt(name, f)?; |
| 368 | break; |
| 369 | } |
| 370 | Err(err: Utf8Error) => { |
| 371 | fmt(" \u{FFFD}" , f)?; |
| 372 | |
| 373 | match err.error_len() { |
| 374 | Some(len: usize) => 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: LockGuard = 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, all(windows, target_env = "gnu" )), |
| 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 | } |
| 486 | |