1 //! Support for capturing a stack backtrace of an OS thread 2 //! 3 //! This module contains the support necessary to capture a stack backtrace of a 4 //! running OS thread from the OS thread itself. The `Backtrace` type supports 5 //! capturing a stack trace via the `Backtrace::capture` and 6 //! `Backtrace::force_capture` functions. 7 //! 8 //! A backtrace is typically quite handy to attach to errors (e.g. types 9 //! implementing `std::error::Error`) to get a causal chain of where an error 10 //! was generated. 11 //! 12 //! ## Accuracy 13 //! 14 //! Backtraces are attempted to be as accurate as possible, but no guarantees 15 //! are provided about the exact accuracy of a backtrace. Instruction pointers, 16 //! symbol names, filenames, line numbers, etc, may all be incorrect when 17 //! reported. Accuracy is attempted on a best-effort basis, however, any bug 18 //! reports are always welcome to indicate areas of improvement! 19 //! 20 //! For most platforms a backtrace with a filename/line number requires that 21 //! programs be compiled with debug information. Without debug information 22 //! filenames/line numbers will not be reported. 23 //! 24 //! ## Platform support 25 //! 26 //! Not all platforms that std compiles for support capturing backtraces. Some 27 //! platforms simply do nothing when capturing a backtrace. To check whether the 28 //! platform supports capturing backtraces you can consult the `BacktraceStatus` 29 //! enum as a result of `Backtrace::status`. 30 //! 31 //! Like above with accuracy platform support is done on a best effort basis. 32 //! Sometimes libraries might not be available at runtime or something may go 33 //! wrong which would cause a backtrace to not be captured. Please feel free to 34 //! report issues with platforms where a backtrace cannot be captured though! 35 //! 36 //! ## Environment Variables 37 //! 38 //! The `Backtrace::capture` function might not actually capture a backtrace by 39 //! default. Its behavior is governed by two environment variables: 40 //! 41 //! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture` 42 //! will never capture a backtrace. Any other value set will enable 43 //! `Backtrace::capture`. 44 //! 45 //! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable 46 //! is consulted with the same rules of `RUST_LIB_BACKTRACE`. 47 //! 48 //! * If neither of the above env vars are set, then `Backtrace::capture` will 49 //! be disabled. 50 //! 51 //! Capturing a backtrace can be a quite expensive runtime operation, so the 52 //! environment variables allow either forcibly disabling this runtime 53 //! performance hit or allow selectively enabling it in some programs. 54 //! 55 //! Note that the `Backtrace::force_capture` function can be used to ignore 56 //! these environment variables. Also note that the state of environment 57 //! variables is cached once the first backtrace is created, so altering 58 //! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change 59 //! how backtraces are captured. 60 61 // NB: A note on resolution of a backtrace: 62 // 63 // Backtraces primarily happen in two steps, one is where we actually capture 64 // the stack backtrace, giving us a list of instruction pointers corresponding 65 // to stack frames. Next we take these instruction pointers and, one-by-one, 66 // turn them into a human readable name (like `main`). 67 // 68 // The first phase can be somewhat expensive (walking the stack), especially 69 // on MSVC where debug information is consulted to return inline frames each as 70 // their own frame. The second phase, however, is almost always extremely 71 // expensive (on the order of milliseconds sometimes) when it's consulting debug 72 // information. 73 // 74 // We attempt to amortize this cost as much as possible by delaying resolution 75 // of an address to a human readable name for as long as possible. When 76 // `Backtrace::create` is called to capture a backtrace it doesn't actually 77 // perform any symbol resolution, but rather we lazily resolve symbols only just 78 // before they're needed for printing. This way we can make capturing a 79 // backtrace and throwing it away much cheaper, but actually printing a 80 // backtrace is still basically the same cost. 81 // 82 // This strategy comes at the cost of some synchronization required inside of a 83 // `Backtrace`, but that's a relatively small price to pay relative to capturing 84 // a backtrace or actually symbolizing it. 85 86 //use crate::std::backtrace_rs::{self, BytesOrWideString}; 87 #![allow(dead_code)] 88 use crate::std::env; 89 use crate::std::ffi::c_void; 90 use crate::std::fmt; 91 use crate::std::panic::UnwindSafe; 92 use crate::std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; 93 use crate::std::sync::LazyLock; 94 //use crate::std::sys_common::backtrace::{lock, output_filename}; 95 use crate::std::vec::Vec; 96 97 /// A captured OS thread stack backtrace. 98 /// 99 /// This type represents a stack backtrace for an OS thread captured at a 100 /// previous point in time. In some instances the `Backtrace` type may 101 /// internally be empty due to configuration. For more information see 102 /// `Backtrace::capture`. 103 #[must_use] 104 pub struct Backtrace { 105 inner: Inner, 106 } 107 108 /// The current status of a backtrace, indicating whether it was captured or 109 /// whether it is empty for some other reason. 110 #[non_exhaustive] 111 #[derive(Debug, PartialEq, Eq)] 112 pub enum BacktraceStatus { 113 /// Capturing a backtrace is not supported, likely because it's not 114 /// implemented for the current platform. 115 Unsupported, 116 /// Capturing a backtrace has been disabled through either the 117 /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables. 118 Disabled, 119 /// A backtrace has been captured and the `Backtrace` should print 120 /// reasonable information when rendered. 121 Captured, 122 } 123 124 enum Inner { 125 Unsupported, 126 Disabled, 127 Captured(LazyLock<Capture, LazyResolve>), 128 } 129 130 struct Capture { 131 actual_start: usize, 132 frames: Vec<BacktraceFrame>, 133 } 134 135 fn _assert_send_sync() { 136 fn _assert<T: Send + Sync>() {} 137 _assert::<Backtrace>(); 138 } 139 140 /// A single frame of a backtrace. 141 pub struct BacktraceFrame { 142 frame: RawFrame, 143 symbols: Vec<BacktraceSymbol>, 144 } 145 146 #[derive(Debug)] 147 enum RawFrame { 148 //Actual(backtrace_rs::Frame), 149 #[cfg(test)] 150 Fake, 151 } 152 153 struct BacktraceSymbol { 154 name: Option<Vec<u8>>, 155 filename: Option<BytesOrWide>, 156 lineno: Option<u32>, 157 colno: Option<u32>, 158 } 159 160 enum BytesOrWide { 161 Bytes(Vec<u8>), 162 Wide(Vec<u16>), 163 } 164 165 impl fmt::Debug for Backtrace { 166 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 167 let capture = match &self.inner { 168 Inner::Unsupported => return fmt.write_str("<unsupported>"), 169 Inner::Disabled => return fmt.write_str("<disabled>"), 170 Inner::Captured(c) => &**c, 171 }; 172 173 let frames = &capture.frames[capture.actual_start..]; 174 175 write!(fmt, "Backtrace ")?; 176 177 let mut dbg = fmt.debug_list(); 178 179 for frame in frames { 180 if frame.frame.ip().is_null() { 181 continue; 182 } 183 184 dbg.entries(&frame.symbols); 185 } 186 187 dbg.finish() 188 } 189 } 190 191 impl fmt::Debug for BacktraceFrame { 192 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 193 let mut dbg = fmt.debug_list(); 194 dbg.entries(&self.symbols); 195 dbg.finish() 196 } 197 } 198 199 impl fmt::Debug for BacktraceSymbol { 200 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 201 // FIXME: improve formatting: https://github.com/rust-lang/rust/issues/65280 202 // FIXME: Also, include column numbers into the debug format as Display already has them. 203 // Until there are stable per-frame accessors, the format shouldn't be changed: 204 // https://github.com/rust-lang/rust/issues/65280#issuecomment-638966585 205 write!(fmt, "{{ ")?; 206 207 //TODO:不支持backtrace 208 write!(fmt, "fn: <unknown>")?; 209 // if let Some(fn_name) = self.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)) { 210 // write!(fmt, "fn: \"{:#}\"", fn_name)?; 211 // } else { 212 // write!(fmt, "fn: <unknown>")?; 213 // } 214 215 if let Some(fname) = self.filename.as_ref() { 216 write!(fmt, ", file: \"{:?}\"", fname)?; 217 } 218 219 if let Some(line) = self.lineno { 220 write!(fmt, ", line: {:?}", line)?; 221 } 222 223 write!(fmt, " }}") 224 } 225 } 226 227 impl fmt::Debug for BytesOrWide { 228 fn fmt(&self, _fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 229 // output_filename( 230 // fmt, 231 // match self { 232 // BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), 233 // BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), 234 // }, 235 // backtrace_rs::PrintFmt::Short, 236 // crate::std::env::current_dir().as_ref().ok(), 237 // ) 238 Ok(()) 239 } 240 } 241 242 impl Backtrace { 243 /// Returns whether backtrace captures are enabled through environment 244 /// variables. 245 fn enabled() -> bool { 246 // Cache the result of reading the environment variables to make 247 // backtrace captures speedy, because otherwise reading environment 248 // variables every time can be somewhat slow. 249 static ENABLED: AtomicUsize = AtomicUsize::new(0); 250 match ENABLED.load(Relaxed) { 251 0 => {} 252 1 => return false, 253 _ => return true, 254 } 255 let enabled = match env::var("RUST_LIB_BACKTRACE") { 256 Ok(s) => s != "0", 257 Err(_) => match env::var("RUST_BACKTRACE") { 258 Ok(s) => s != "0", 259 Err(_) => false, 260 }, 261 }; 262 ENABLED.store(enabled as usize + 1, Relaxed); 263 enabled 264 } 265 266 /// Capture a stack backtrace of the current thread. 267 /// 268 /// This function will capture a stack backtrace of the current OS thread of 269 /// execution, returning a `Backtrace` type which can be later used to print 270 /// the entire stack trace or render it to a string. 271 /// 272 /// This function will be a noop if the `RUST_BACKTRACE` or 273 /// `RUST_LIB_BACKTRACE` backtrace variables are both not set. If either 274 /// environment variable is set and enabled then this function will actually 275 /// capture a backtrace. Capturing a backtrace can be both memory intensive 276 /// and slow, so these environment variables allow liberally using 277 /// `Backtrace::capture` and only incurring a slowdown when the environment 278 /// variables are set. 279 /// 280 /// To forcibly capture a backtrace regardless of environment variables, use 281 /// the `Backtrace::force_capture` function. 282 #[inline(never)] // want to make sure there's a frame here to remove 283 pub fn capture() -> Backtrace { 284 if !Backtrace::enabled() { 285 return Backtrace { 286 inner: Inner::Disabled, 287 }; 288 } 289 Backtrace::create(Backtrace::capture as usize) 290 } 291 292 /// Forcibly captures a full backtrace, regardless of environment variable 293 /// configuration. 294 /// 295 /// This function behaves the same as `capture` except that it ignores the 296 /// values of the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment 297 /// variables, always capturing a backtrace. 298 /// 299 /// Note that capturing a backtrace can be an expensive operation on some 300 /// platforms, so this should be used with caution in performance-sensitive 301 /// parts of code. 302 #[inline(never)] // want to make sure there's a frame here to remove 303 pub fn force_capture() -> Backtrace { 304 Backtrace::create(Backtrace::force_capture as usize) 305 } 306 307 /// Forcibly captures a disabled backtrace, regardless of environment 308 /// variable configuration. 309 pub const fn disabled() -> Backtrace { 310 Backtrace { 311 inner: Inner::Disabled, 312 } 313 } 314 315 // Capture a backtrace which start just before the function addressed by 316 // `ip` 317 fn create(_ip: usize) -> Backtrace { 318 // let _lock = lock(); 319 // let mut frames = Vec::new(); 320 // let mut actual_start = None; 321 // unsafe { 322 // backtrace_rs::trace_unsynchronized(|frame| { 323 // frames.push(BacktraceFrame { 324 // frame: RawFrame::Actual(frame.clone()), 325 // symbols: Vec::new(), 326 // }); 327 // if frame.symbol_address().addr() == ip && actual_start.is_none() { 328 // actual_start = Some(frames.len()); 329 // } 330 // true 331 // }); 332 // } 333 334 // If no frames came out assume that this is an unsupported platform 335 // since `backtrace` doesn't provide a way of learning this right now, 336 // and this should be a good enough approximation. 337 // let inner = if frames.is_empty() { 338 // Inner::Unsupported 339 // } else { 340 // Inner::Captured(LazyLock::new(lazy_resolve(Capture { 341 // actual_start: actual_start.unwrap_or(0), 342 // frames, 343 // }))) 344 // }; 345 346 Backtrace { 347 inner: Inner::Unsupported, 348 } 349 } 350 351 /// Returns the status of this backtrace, indicating whether this backtrace 352 /// request was unsupported, disabled, or a stack trace was actually 353 /// captured. 354 #[must_use] 355 pub fn status(&self) -> BacktraceStatus { 356 match self.inner { 357 Inner::Unsupported => BacktraceStatus::Unsupported, 358 Inner::Disabled => BacktraceStatus::Disabled, 359 Inner::Captured(_) => BacktraceStatus::Captured, 360 } 361 } 362 } 363 364 impl<'a> Backtrace { 365 /// Returns an iterator over the backtrace frames. 366 #[must_use] 367 pub fn frames(&'a self) -> &'a [BacktraceFrame] { 368 if let Inner::Captured(c) = &self.inner { 369 &c.frames 370 } else { 371 &[] 372 } 373 } 374 } 375 376 impl fmt::Display for Backtrace { 377 fn fmt(&self, _fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 378 // let capture = match &self.inner { 379 // Inner::Unsupported => return fmt.write_str("unsupported backtrace"), 380 // Inner::Disabled => return fmt.write_str("disabled backtrace"), 381 // Inner::Captured(c) => &**c, 382 // }; 383 384 // let full = fmt.alternate(); 385 // let (frames, style) = if full { 386 // (&capture.frames[..], backtrace_rs::PrintFmt::Full) 387 // } else { 388 // (&capture.frames[capture.actual_start..], backtrace_rs::PrintFmt::Short) 389 // }; 390 391 // // When printing paths we try to strip the cwd if it exists, otherwise 392 // // we just print the path as-is. Note that we also only do this for the 393 // // short format, because if it's full we presumably want to print 394 // // everything. 395 // let cwd = crate::std::env::current_dir(); 396 // let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| { 397 // output_filename(fmt, path, style, cwd.as_ref().ok()) 398 // }; 399 400 // let mut f = backtrace_rs::BacktraceFmt::new(fmt, style, &mut print_path); 401 // f.add_context()?; 402 // for frame in frames { 403 // if frame.symbols.is_empty() { 404 // f.frame().print_raw(frame.frame.ip(), None, None, None)?; 405 // } else { 406 // for symbol in frame.symbols.iter() { 407 // f.frame().print_raw_with_column( 408 // frame.frame.ip(), 409 // symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)), 410 // symbol.filename.as_ref().map(|b| match b { 411 // BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), 412 // BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), 413 // }), 414 // symbol.lineno, 415 // symbol.colno, 416 // )?; 417 // } 418 // } 419 // } 420 // f.finish()?; 421 Ok(()) 422 } 423 } 424 425 type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe; 426 427 fn lazy_resolve(capture: Capture) -> LazyResolve { 428 move || { 429 // Use the global backtrace lock to synchronize this as it's a 430 // requirement of the `backtrace` crate, and then actually resolve 431 // everything. 432 // let _lock = lock(); 433 // for frame in capture.frames.iter_mut() { 434 // let symbols = &mut frame.symbols; 435 // let frame = match &frame.frame { 436 // RawFrame::Actual(frame) => frame, 437 // #[cfg(test)] 438 // RawFrame::Fake => unimplemented!(), 439 // }; 440 // unsafe { 441 // backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { 442 // symbols.push(BacktraceSymbol { 443 // name: symbol.name().map(|m| m.as_bytes().to_vec()), 444 // filename: symbol.filename_raw().map(|b| match b { 445 // BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()), 446 // BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()), 447 // }), 448 // lineno: symbol.lineno(), 449 // colno: symbol.colno(), 450 // }); 451 // }); 452 // } 453 // } 454 455 capture 456 } 457 } 458 459 impl RawFrame { 460 fn ip(&self) -> *mut c_void { 461 match self { 462 //RawFrame::Actual(frame) => frame.ip(), 463 #[cfg(test)] 464 RawFrame::Fake => crate::std::ptr::invalid_mut(1), 465 _ => todo!(), 466 } 467 } 468 } 469