backtrace/
capture.rs

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