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