backtrace/
capture.rs

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