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}