| 1 | use crate::PrintFmt; |
| 2 | use crate::{resolve, resolve_frame, trace, BacktraceFmt, Symbol, SymbolName}; |
| 3 | use std::ffi::c_void; |
| 4 | use std::fmt; |
| 5 | use std::path::{Path, PathBuf}; |
| 6 | use std::prelude::v1::*; |
| 7 | |
| 8 | #[cfg (feature = "serde" )] |
| 9 | use serde::{Deserialize, Serialize}; |
| 10 | |
| 11 | /// Representation of an owned and self-contained backtrace. |
| 12 | /// |
| 13 | /// This structure can be used to capture a backtrace at various points in a |
| 14 | /// program and later used to inspect what the backtrace was at that time. |
| 15 | /// |
| 16 | /// `Backtrace` supports pretty-printing of backtraces through its `Debug` |
| 17 | /// implementation. |
| 18 | /// |
| 19 | /// # Required features |
| 20 | /// |
| 21 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 22 | /// enabled, and the `std` feature is enabled by default. |
| 23 | #[derive (Clone)] |
| 24 | #[cfg_attr (feature = "serialize-rustc" , derive(RustcDecodable, RustcEncodable))] |
| 25 | #[cfg_attr (feature = "serde" , derive(Deserialize, Serialize))] |
| 26 | pub struct Backtrace { |
| 27 | // Frames here are listed from top-to-bottom of the stack |
| 28 | frames: Vec<BacktraceFrame>, |
| 29 | } |
| 30 | |
| 31 | fn _assert_send_sync() { |
| 32 | fn _assert<T: Send + Sync>() {} |
| 33 | _assert::<Backtrace>(); |
| 34 | } |
| 35 | |
| 36 | /// Captured version of a frame in a backtrace. |
| 37 | /// |
| 38 | /// This type is returned as a list from `Backtrace::frames` and represents one |
| 39 | /// stack frame in a captured backtrace. |
| 40 | /// |
| 41 | /// # Required features |
| 42 | /// |
| 43 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 44 | /// enabled, and the `std` feature is enabled by default. |
| 45 | #[derive (Clone)] |
| 46 | pub struct BacktraceFrame { |
| 47 | frame: Frame, |
| 48 | symbols: Option<Vec<BacktraceSymbol>>, |
| 49 | } |
| 50 | |
| 51 | #[derive (Clone)] |
| 52 | enum Frame { |
| 53 | Raw(crate::Frame), |
| 54 | #[allow (dead_code)] |
| 55 | Deserialized { |
| 56 | ip: usize, |
| 57 | symbol_address: usize, |
| 58 | module_base_address: Option<usize>, |
| 59 | }, |
| 60 | } |
| 61 | |
| 62 | impl Frame { |
| 63 | fn ip(&self) -> *mut c_void { |
| 64 | match *self { |
| 65 | Frame::Raw(ref f) => f.ip(), |
| 66 | Frame::Deserialized { ip, .. } => ip as *mut c_void, |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | fn symbol_address(&self) -> *mut c_void { |
| 71 | match *self { |
| 72 | Frame::Raw(ref f) => f.symbol_address(), |
| 73 | Frame::Deserialized { symbol_address, .. } => symbol_address as *mut c_void, |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | fn module_base_address(&self) -> Option<*mut c_void> { |
| 78 | match *self { |
| 79 | Frame::Raw(ref f) => f.module_base_address(), |
| 80 | Frame::Deserialized { |
| 81 | module_base_address, |
| 82 | .. |
| 83 | } => module_base_address.map(|addr| addr as *mut c_void), |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | /// Resolve all addresses in the frame to their symbolic names. |
| 88 | fn resolve_symbols(&self) -> Vec<BacktraceSymbol> { |
| 89 | let mut symbols = Vec::new(); |
| 90 | let sym = |symbol: &Symbol| { |
| 91 | symbols.push(BacktraceSymbol { |
| 92 | name: symbol.name().map(|m| m.as_bytes().to_vec()), |
| 93 | addr: symbol.addr().map(|a| a as usize), |
| 94 | filename: symbol.filename().map(|m| m.to_owned()), |
| 95 | lineno: symbol.lineno(), |
| 96 | colno: symbol.colno(), |
| 97 | }); |
| 98 | }; |
| 99 | match *self { |
| 100 | Frame::Raw(ref f) => resolve_frame(f, sym), |
| 101 | Frame::Deserialized { ip, .. } => { |
| 102 | resolve(ip as *mut c_void, sym); |
| 103 | } |
| 104 | } |
| 105 | symbols |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | /// Captured version of a symbol in a backtrace. |
| 110 | /// |
| 111 | /// This type is returned as a list from `BacktraceFrame::symbols` and |
| 112 | /// represents the metadata for a symbol in a backtrace. |
| 113 | /// |
| 114 | /// # Required features |
| 115 | /// |
| 116 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 117 | /// enabled, and the `std` feature is enabled by default. |
| 118 | #[derive (Clone)] |
| 119 | #[cfg_attr (feature = "serialize-rustc" , derive(RustcDecodable, RustcEncodable))] |
| 120 | #[cfg_attr (feature = "serde" , derive(Deserialize, Serialize))] |
| 121 | pub struct BacktraceSymbol { |
| 122 | name: Option<Vec<u8>>, |
| 123 | addr: Option<usize>, |
| 124 | filename: Option<PathBuf>, |
| 125 | lineno: Option<u32>, |
| 126 | colno: Option<u32>, |
| 127 | } |
| 128 | |
| 129 | impl Backtrace { |
| 130 | /// Captures a backtrace at the callsite of this function, returning an |
| 131 | /// owned representation. |
| 132 | /// |
| 133 | /// This function is useful for representing a backtrace as an object in |
| 134 | /// Rust. This returned value can be sent across threads and printed |
| 135 | /// elsewhere, and the purpose of this value is to be entirely self |
| 136 | /// contained. |
| 137 | /// |
| 138 | /// Note that on some platforms acquiring a full backtrace and resolving it |
| 139 | /// can be extremely expensive. If the cost is too much for your application |
| 140 | /// it's recommended to instead use `Backtrace::new_unresolved()` which |
| 141 | /// avoids the symbol resolution step (which typically takes the longest) |
| 142 | /// and allows deferring that to a later date. |
| 143 | /// |
| 144 | /// # Examples |
| 145 | /// |
| 146 | /// ``` |
| 147 | /// use backtrace::Backtrace; |
| 148 | /// |
| 149 | /// let current_backtrace = Backtrace::new(); |
| 150 | /// ``` |
| 151 | /// |
| 152 | /// # Required features |
| 153 | /// |
| 154 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 155 | /// enabled, and the `std` feature is enabled by default. |
| 156 | #[inline (never)] // want to make sure there's a frame here to remove |
| 157 | pub fn new() -> Backtrace { |
| 158 | let mut bt = Self::create(Self::new as usize); |
| 159 | bt.resolve(); |
| 160 | bt |
| 161 | } |
| 162 | |
| 163 | /// Similar to `new` except that this does not resolve any symbols, this |
| 164 | /// simply captures the backtrace as a list of addresses. |
| 165 | /// |
| 166 | /// At a later time the `resolve` function can be called to resolve this |
| 167 | /// backtrace's symbols into readable names. This function exists because |
| 168 | /// the resolution process can sometimes take a significant amount of time |
| 169 | /// whereas any one backtrace may only be rarely printed. |
| 170 | /// |
| 171 | /// # Examples |
| 172 | /// |
| 173 | /// ``` |
| 174 | /// use backtrace::Backtrace; |
| 175 | /// |
| 176 | /// let mut current_backtrace = Backtrace::new_unresolved(); |
| 177 | /// println!("{current_backtrace:?}" ); // no symbol names |
| 178 | /// current_backtrace.resolve(); |
| 179 | /// println!("{current_backtrace:?}" ); // symbol names now present |
| 180 | /// ``` |
| 181 | /// |
| 182 | /// # Required features |
| 183 | /// |
| 184 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 185 | /// enabled, and the `std` feature is enabled by default. |
| 186 | #[inline (never)] // want to make sure there's a frame here to remove |
| 187 | pub fn new_unresolved() -> Backtrace { |
| 188 | Self::create(Self::new_unresolved as usize) |
| 189 | } |
| 190 | |
| 191 | fn create(ip: usize) -> Backtrace { |
| 192 | let mut frames = Vec::new(); |
| 193 | trace(|frame| { |
| 194 | frames.push(BacktraceFrame { |
| 195 | frame: Frame::Raw(frame.clone()), |
| 196 | symbols: None, |
| 197 | }); |
| 198 | |
| 199 | // clear inner frames, and start with call site. |
| 200 | if frame.symbol_address() as usize == ip { |
| 201 | frames.clear(); |
| 202 | } |
| 203 | |
| 204 | true |
| 205 | }); |
| 206 | frames.shrink_to_fit(); |
| 207 | |
| 208 | Backtrace { frames } |
| 209 | } |
| 210 | |
| 211 | /// Returns the frames from when this backtrace was captured. |
| 212 | /// |
| 213 | /// The first entry of this slice is likely the function `Backtrace::new`, |
| 214 | /// and the last frame is likely something about how this thread or the main |
| 215 | /// function started. |
| 216 | /// |
| 217 | /// # Required features |
| 218 | /// |
| 219 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 220 | /// enabled, and the `std` feature is enabled by default. |
| 221 | pub fn frames(&self) -> &[BacktraceFrame] { |
| 222 | self.frames.as_slice() |
| 223 | } |
| 224 | |
| 225 | /// If this backtrace was created from `new_unresolved` then this function |
| 226 | /// will resolve all addresses in the backtrace to their symbolic names. |
| 227 | /// |
| 228 | /// If this backtrace has been previously resolved or was created through |
| 229 | /// `new`, this function does nothing. |
| 230 | /// |
| 231 | /// # Required features |
| 232 | /// |
| 233 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 234 | /// enabled, and the `std` feature is enabled by default. |
| 235 | pub fn resolve(&mut self) { |
| 236 | self.frames.iter_mut().for_each(BacktraceFrame::resolve); |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | impl From<Vec<BacktraceFrame>> for Backtrace { |
| 241 | fn from(frames: Vec<BacktraceFrame>) -> Self { |
| 242 | Backtrace { frames } |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | impl From<crate::Frame> for BacktraceFrame { |
| 247 | fn from(frame: crate::Frame) -> Self { |
| 248 | BacktraceFrame { |
| 249 | frame: Frame::Raw(frame), |
| 250 | symbols: None, |
| 251 | } |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | // we don't want implementing `impl From<Backtrace> for Vec<BacktraceFrame>` on purpose, |
| 256 | // because "... additional directions for Vec<T> can weaken type inference ..." |
| 257 | // more information on https://github.com/rust-lang/backtrace-rs/pull/526 |
| 258 | impl Into<Vec<BacktraceFrame>> for Backtrace { |
| 259 | fn into(self) -> Vec<BacktraceFrame> { |
| 260 | self.frames |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | impl BacktraceFrame { |
| 265 | /// Same as `Frame::ip` |
| 266 | /// |
| 267 | /// # Required features |
| 268 | /// |
| 269 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 270 | /// enabled, and the `std` feature is enabled by default. |
| 271 | pub fn ip(&self) -> *mut c_void { |
| 272 | self.frame.ip() |
| 273 | } |
| 274 | |
| 275 | /// Same as `Frame::symbol_address` |
| 276 | /// |
| 277 | /// # Required features |
| 278 | /// |
| 279 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 280 | /// enabled, and the `std` feature is enabled by default. |
| 281 | pub fn symbol_address(&self) -> *mut c_void { |
| 282 | self.frame.symbol_address() |
| 283 | } |
| 284 | |
| 285 | /// Same as `Frame::module_base_address` |
| 286 | /// |
| 287 | /// # Required features |
| 288 | /// |
| 289 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 290 | /// enabled, and the `std` feature is enabled by default. |
| 291 | pub fn module_base_address(&self) -> Option<*mut c_void> { |
| 292 | self.frame.module_base_address() |
| 293 | } |
| 294 | |
| 295 | /// Returns the list of symbols that this frame corresponds to. |
| 296 | /// |
| 297 | /// Normally there is only one symbol per frame, but sometimes if a number |
| 298 | /// of functions are inlined into one frame then multiple symbols will be |
| 299 | /// returned. The first symbol listed is the "innermost function", whereas |
| 300 | /// the last symbol is the outermost (last caller). |
| 301 | /// |
| 302 | /// Note that if this frame came from an unresolved backtrace then this will |
| 303 | /// return an empty list. |
| 304 | /// |
| 305 | /// # Required features |
| 306 | /// |
| 307 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 308 | /// enabled, and the `std` feature is enabled by default. |
| 309 | pub fn symbols(&self) -> &[BacktraceSymbol] { |
| 310 | self.symbols.as_ref().map(|s| &s[..]).unwrap_or(&[]) |
| 311 | } |
| 312 | |
| 313 | /// Resolve all addresses in this frame to their symbolic names. |
| 314 | /// |
| 315 | /// If this frame has been previously resolved, this function does nothing. |
| 316 | /// |
| 317 | /// # Required features |
| 318 | /// |
| 319 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 320 | /// enabled, and the `std` feature is enabled by default. |
| 321 | pub fn resolve(&mut self) { |
| 322 | if self.symbols.is_none() { |
| 323 | self.symbols = Some(self.frame.resolve_symbols()); |
| 324 | } |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | impl BacktraceSymbol { |
| 329 | /// Same as `Symbol::name` |
| 330 | /// |
| 331 | /// # Required features |
| 332 | /// |
| 333 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 334 | /// enabled, and the `std` feature is enabled by default. |
| 335 | pub fn name(&self) -> Option<SymbolName<'_>> { |
| 336 | self.name.as_ref().map(|s| SymbolName::new(s)) |
| 337 | } |
| 338 | |
| 339 | /// Same as `Symbol::addr` |
| 340 | /// |
| 341 | /// # Required features |
| 342 | /// |
| 343 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 344 | /// enabled, and the `std` feature is enabled by default. |
| 345 | pub fn addr(&self) -> Option<*mut c_void> { |
| 346 | self.addr.map(|s| s as *mut c_void) |
| 347 | } |
| 348 | |
| 349 | /// Same as `Symbol::filename` |
| 350 | /// |
| 351 | /// # Required features |
| 352 | /// |
| 353 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 354 | /// enabled, and the `std` feature is enabled by default. |
| 355 | pub fn filename(&self) -> Option<&Path> { |
| 356 | self.filename.as_ref().map(|p| &**p) |
| 357 | } |
| 358 | |
| 359 | /// Same as `Symbol::lineno` |
| 360 | /// |
| 361 | /// # Required features |
| 362 | /// |
| 363 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 364 | /// enabled, and the `std` feature is enabled by default. |
| 365 | pub fn lineno(&self) -> Option<u32> { |
| 366 | self.lineno |
| 367 | } |
| 368 | |
| 369 | /// Same as `Symbol::colno` |
| 370 | /// |
| 371 | /// # Required features |
| 372 | /// |
| 373 | /// This function requires the `std` feature of the `backtrace` crate to be |
| 374 | /// enabled, and the `std` feature is enabled by default. |
| 375 | pub fn colno(&self) -> Option<u32> { |
| 376 | self.colno |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | impl fmt::Debug for Backtrace { |
| 381 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 382 | let style = if fmt.alternate() { |
| 383 | PrintFmt::Full |
| 384 | } else { |
| 385 | PrintFmt::Short |
| 386 | }; |
| 387 | |
| 388 | // When printing paths we try to strip the cwd if it exists, otherwise |
| 389 | // we just print the path as-is. Note that we also only do this for the |
| 390 | // short format, because if it's full we presumably want to print |
| 391 | // everything. |
| 392 | let cwd = std::env::current_dir(); |
| 393 | let mut print_path = |
| 394 | move |fmt: &mut fmt::Formatter<'_>, path: crate::BytesOrWideString<'_>| { |
| 395 | let path = path.into_path_buf(); |
| 396 | if style == PrintFmt::Full { |
| 397 | if let Ok(cwd) = &cwd { |
| 398 | if let Ok(suffix) = path.strip_prefix(cwd) { |
| 399 | return fmt::Display::fmt(&suffix.display(), fmt); |
| 400 | } |
| 401 | } |
| 402 | } |
| 403 | fmt::Display::fmt(&path.display(), fmt) |
| 404 | }; |
| 405 | |
| 406 | let mut f = BacktraceFmt::new(fmt, style, &mut print_path); |
| 407 | f.add_context()?; |
| 408 | for frame in &self.frames { |
| 409 | f.frame().backtrace_frame(frame)?; |
| 410 | } |
| 411 | f.finish()?; |
| 412 | Ok(()) |
| 413 | } |
| 414 | } |
| 415 | |
| 416 | impl Default for Backtrace { |
| 417 | fn default() -> Backtrace { |
| 418 | Backtrace::new() |
| 419 | } |
| 420 | } |
| 421 | |
| 422 | impl fmt::Debug for BacktraceFrame { |
| 423 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 424 | fmt&mut DebugStruct<'_, '_>.debug_struct("BacktraceFrame" ) |
| 425 | .field("ip" , &self.ip()) |
| 426 | .field(name:"symbol_address" , &self.symbol_address()) |
| 427 | .finish() |
| 428 | } |
| 429 | } |
| 430 | |
| 431 | impl fmt::Debug for BacktraceSymbol { |
| 432 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 433 | fmt&mut DebugStruct<'_, '_>.debug_struct("BacktraceSymbol" ) |
| 434 | .field("name" , &self.name()) |
| 435 | .field("addr" , &self.addr()) |
| 436 | .field("filename" , &self.filename()) |
| 437 | .field("lineno" , &self.lineno()) |
| 438 | .field(name:"colno" , &self.colno()) |
| 439 | .finish() |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | #[cfg (feature = "serialize-rustc" )] |
| 444 | mod rustc_serialize_impls { |
| 445 | use super::*; |
| 446 | use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; |
| 447 | |
| 448 | #[derive (RustcEncodable, RustcDecodable)] |
| 449 | struct SerializedFrame { |
| 450 | ip: usize, |
| 451 | symbol_address: usize, |
| 452 | module_base_address: Option<usize>, |
| 453 | symbols: Option<Vec<BacktraceSymbol>>, |
| 454 | } |
| 455 | |
| 456 | impl Decodable for BacktraceFrame { |
| 457 | fn decode<D>(d: &mut D) -> Result<Self, D::Error> |
| 458 | where |
| 459 | D: Decoder, |
| 460 | { |
| 461 | let frame: SerializedFrame = SerializedFrame::decode(d)?; |
| 462 | Ok(BacktraceFrame { |
| 463 | frame: Frame::Deserialized { |
| 464 | ip: frame.ip, |
| 465 | symbol_address: frame.symbol_address, |
| 466 | module_base_address: frame.module_base_address, |
| 467 | }, |
| 468 | symbols: frame.symbols, |
| 469 | }) |
| 470 | } |
| 471 | } |
| 472 | |
| 473 | impl Encodable for BacktraceFrame { |
| 474 | fn encode<E>(&self, e: &mut E) -> Result<(), E::Error> |
| 475 | where |
| 476 | E: Encoder, |
| 477 | { |
| 478 | let BacktraceFrame { frame, symbols } = self; |
| 479 | SerializedFrame { |
| 480 | ip: frame.ip() as usize, |
| 481 | symbol_address: frame.symbol_address() as usize, |
| 482 | module_base_address: frame.module_base_address().map(|addr| addr as usize), |
| 483 | symbols: symbols.clone(), |
| 484 | } |
| 485 | .encode(e) |
| 486 | } |
| 487 | } |
| 488 | } |
| 489 | |
| 490 | #[cfg (feature = "serde" )] |
| 491 | mod serde_impls { |
| 492 | use super::*; |
| 493 | use serde::de::Deserializer; |
| 494 | use serde::ser::Serializer; |
| 495 | use serde::{Deserialize, Serialize}; |
| 496 | |
| 497 | #[derive (Serialize, Deserialize)] |
| 498 | struct SerializedFrame { |
| 499 | ip: usize, |
| 500 | symbol_address: usize, |
| 501 | module_base_address: Option<usize>, |
| 502 | symbols: Option<Vec<BacktraceSymbol>>, |
| 503 | } |
| 504 | |
| 505 | impl Serialize for BacktraceFrame { |
| 506 | fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> |
| 507 | where |
| 508 | S: Serializer, |
| 509 | { |
| 510 | let BacktraceFrame { frame, symbols } = self; |
| 511 | SerializedFrame { |
| 512 | ip: frame.ip() as usize, |
| 513 | symbol_address: frame.symbol_address() as usize, |
| 514 | module_base_address: frame.module_base_address().map(|addr| addr as usize), |
| 515 | symbols: symbols.clone(), |
| 516 | } |
| 517 | .serialize(s) |
| 518 | } |
| 519 | } |
| 520 | |
| 521 | impl<'a> Deserialize<'a> for BacktraceFrame { |
| 522 | fn deserialize<D>(d: D) -> Result<Self, D::Error> |
| 523 | where |
| 524 | D: Deserializer<'a>, |
| 525 | { |
| 526 | let frame: SerializedFrame = SerializedFrame::deserialize(d)?; |
| 527 | Ok(BacktraceFrame { |
| 528 | frame: Frame::Deserialized { |
| 529 | ip: frame.ip, |
| 530 | symbol_address: frame.symbol_address, |
| 531 | module_base_address: frame.module_base_address, |
| 532 | }, |
| 533 | symbols: frame.symbols, |
| 534 | }) |
| 535 | } |
| 536 | } |
| 537 | } |
| 538 | |
| 539 | #[cfg (test)] |
| 540 | mod tests { |
| 541 | use super::*; |
| 542 | |
| 543 | #[test ] |
| 544 | fn test_frame_conversion() { |
| 545 | let mut frames = vec![]; |
| 546 | crate::trace(|frame| { |
| 547 | let converted = BacktraceFrame::from(frame.clone()); |
| 548 | frames.push(converted); |
| 549 | true |
| 550 | }); |
| 551 | |
| 552 | let mut manual = Backtrace::from(frames); |
| 553 | manual.resolve(); |
| 554 | let frames = manual.frames(); |
| 555 | |
| 556 | for frame in frames { |
| 557 | println!("{:?}" , frame.ip()); |
| 558 | println!("{:?}" , frame.symbol_address()); |
| 559 | println!("{:?}" , frame.module_base_address()); |
| 560 | println!("{:?}" , frame.symbols()); |
| 561 | } |
| 562 | } |
| 563 | } |
| 564 | |