Coverage Report

Created: 2026-02-14 07:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.76/src/capture.rs
Line
Count
Source
1
#![allow(clippy::from_over_into)]
2
3
#[cfg(feature = "serde")]
4
use crate::resolve;
5
use crate::PrintFmt;
6
use crate::{resolve_frame, trace, BacktraceFmt, Symbol, SymbolName};
7
use core::ffi::c_void;
8
use std::fmt;
9
use std::path::{Path, PathBuf};
10
use std::prelude::v1::*;
11
12
#[cfg(feature = "serde")]
13
use 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))]
29
pub struct Backtrace {
30
    // Frames here are listed from top-to-bottom of the stack
31
    frames: Box<[BacktraceFrame]>,
32
}
33
34
#[derive(Clone, Copy)]
35
struct TracePtr(*mut c_void);
36
/// SAFETY: These pointers are always valid within a process and are not used for mutation.
37
unsafe impl Send for TracePtr {}
38
/// SAFETY: These pointers are always valid within a process and are not used for mutation.
39
unsafe impl Sync for TracePtr {}
40
41
impl TracePtr {
42
0
    fn into_void(self) -> *mut c_void {
43
0
        self.0
44
0
    }
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")]
52
impl<'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")]
119
impl 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
129
0
fn _assert_send_sync() {
130
0
    fn _assert<T: Send + Sync>() {}
131
0
    _assert::<Backtrace>();
132
0
}
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)]
144
pub struct BacktraceFrame {
145
    frame: Frame,
146
    symbols: Option<Box<[BacktraceSymbol]>>,
147
}
148
149
#[derive(Clone)]
150
enum 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
160
impl Frame {
161
2.95k
    fn ip(&self) -> *mut c_void {
162
2.95k
        match *self {
163
2.95k
            Frame::Raw(ref f) => f.ip(),
164
            #[cfg(feature = "serde")]
165
            Frame::Deserialized { ip, .. } => ip.into_void(),
166
        }
167
2.95k
    }
168
169
0
    fn symbol_address(&self) -> *mut c_void {
170
0
        match *self {
171
0
            Frame::Raw(ref f) => f.symbol_address(),
172
            #[cfg(feature = "serde")]
173
            Frame::Deserialized { symbol_address, .. } => symbol_address.into_void(),
174
        }
175
0
    }
176
177
0
    fn module_base_address(&self) -> Option<*mut c_void> {
178
0
        match *self {
179
0
            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
0
    }
187
188
    /// Resolve all addresses in the frame to their symbolic names.
189
0
    fn resolve_symbols(&self) -> Box<[BacktraceSymbol]> {
190
0
        let mut symbols = Vec::new();
191
0
        let sym = |symbol: &Symbol| {
192
0
            symbols.push(BacktraceSymbol {
193
0
                name: symbol.name().map(|m| m.as_bytes().into()),
194
0
                addr: symbol.addr().map(TracePtr),
195
0
                filename: symbol.filename().map(|m| m.to_owned()),
196
0
                lineno: symbol.lineno(),
197
0
                colno: symbol.colno(),
198
            });
199
0
        };
200
0
        match *self {
201
0
            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
0
        symbols.into_boxed_slice()
208
0
    }
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))]
222
pub 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
230
impl 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
0
    pub fn new() -> Backtrace {
259
0
        let mut bt = Self::create(Self::new as usize);
260
0
        bt.resolve();
261
0
        bt
262
0
    }
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
188
    pub fn new_unresolved() -> Backtrace {
289
188
        Self::create(Self::new_unresolved as usize)
290
188
    }
291
292
188
    fn create(ip: usize) -> Backtrace {
293
188
        let mut frames = Vec::new();
294
2.95k
        trace(|frame| {
295
2.95k
            frames.push(BacktraceFrame {
296
2.95k
                frame: Frame::Raw(frame.clone()),
297
2.95k
                symbols: None,
298
2.95k
            });
299
300
            // clear inner frames, and start with call site.
301
2.95k
            if frame.symbol_address() as usize == ip {
302
0
                frames.clear();
303
2.95k
            }
304
305
2.95k
            true
306
2.95k
        });
307
188
        frames.shrink_to_fit();
308
309
188
        Backtrace {
310
188
            frames: frames.into_boxed_slice(),
311
188
        }
312
188
    }
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
188
    pub fn frames(&self) -> &[BacktraceFrame] {
325
188
        self.frames.as_ref()
326
188
    }
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
0
    pub fn resolve(&mut self) {
339
0
        self.frames.iter_mut().for_each(BacktraceFrame::resolve);
340
0
    }
341
}
342
343
impl From<Vec<BacktraceFrame>> for Backtrace {
344
0
    fn from(frames: Vec<BacktraceFrame>) -> Self {
345
0
        Backtrace {
346
0
            frames: frames.into_boxed_slice(),
347
0
        }
348
0
    }
349
}
350
351
impl From<crate::Frame> for BacktraceFrame {
352
0
    fn from(frame: crate::Frame) -> Self {
353
0
        BacktraceFrame {
354
0
            frame: Frame::Raw(frame),
355
0
            symbols: None,
356
0
        }
357
0
    }
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
363
impl Into<Vec<BacktraceFrame>> for Backtrace {
364
0
    fn into(self) -> Vec<BacktraceFrame> {
365
0
        self.frames.into_vec()
366
0
    }
367
}
368
369
impl 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
2.95k
    pub fn ip(&self) -> *mut c_void {
377
2.95k
        self.frame.ip()
378
2.95k
    }
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
0
    pub fn symbol_address(&self) -> *mut c_void {
387
0
        self.frame.symbol_address()
388
0
    }
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
0
    pub fn module_base_address(&self) -> Option<*mut c_void> {
397
0
        self.frame.module_base_address()
398
0
    }
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
0
    pub fn symbols(&self) -> &[BacktraceSymbol] {
415
0
        self.symbols.as_ref().map(|s| &s[..]).unwrap_or(&[])
416
0
    }
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
0
    pub fn resolve(&mut self) {
427
0
        if self.symbols.is_none() {
428
0
            self.symbols = Some(self.frame.resolve_symbols());
429
0
        }
430
0
    }
431
}
432
433
impl 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
0
    pub fn name(&self) -> Option<SymbolName<'_>> {
441
0
        self.name.as_ref().map(|s| SymbolName::new(s))
442
0
    }
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
0
    pub fn addr(&self) -> Option<*mut c_void> {
451
0
        self.addr.map(|s| s.into_void())
452
0
    }
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
0
    pub fn filename(&self) -> Option<&Path> {
461
0
        self.filename.as_deref()
462
0
    }
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
0
    pub fn lineno(&self) -> Option<u32> {
471
0
        self.lineno
472
0
    }
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
0
    pub fn colno(&self) -> Option<u32> {
481
0
        self.colno
482
0
    }
483
}
484
485
impl fmt::Debug for Backtrace {
486
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
487
0
        let style = if fmt.alternate() {
488
0
            PrintFmt::Full
489
        } else {
490
0
            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
0
        let cwd = std::env::current_dir();
498
0
        let mut print_path =
499
0
            move |fmt: &mut fmt::Formatter<'_>, path: crate::BytesOrWideString<'_>| {
500
0
                let path = path.into_path_buf();
501
0
                if style != PrintFmt::Full {
502
0
                    if let Ok(cwd) = &cwd {
503
0
                        if let Ok(suffix) = path.strip_prefix(cwd) {
504
0
                            return fmt::Display::fmt(&suffix.display(), fmt);
505
0
                        }
506
0
                    }
507
0
                }
508
0
                fmt::Display::fmt(&path.display(), fmt)
509
0
            };
510
511
0
        let mut f = BacktraceFmt::new(fmt, style, &mut print_path);
512
0
        f.add_context()?;
513
0
        for frame in &self.frames {
514
0
            f.frame().backtrace_frame(frame)?;
515
        }
516
0
        f.finish()?;
517
0
        Ok(())
518
0
    }
519
}
520
521
impl Default for Backtrace {
522
0
    fn default() -> Backtrace {
523
0
        Backtrace::new()
524
0
    }
525
}
526
527
impl fmt::Debug for BacktraceFrame {
528
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
529
0
        fmt.debug_struct("BacktraceFrame")
530
0
            .field("ip", &self.ip())
531
0
            .field("symbol_address", &self.symbol_address())
532
0
            .finish()
533
0
    }
534
}
535
536
impl fmt::Debug for BacktraceSymbol {
537
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
538
0
        fmt.debug_struct("BacktraceSymbol")
539
0
            .field("name", &self.name())
540
0
            .field("addr", &self.addr())
541
0
            .field("filename", &self.filename())
542
0
            .field("lineno", &self.lineno())
543
0
            .field("colno", &self.colno())
544
0
            .finish()
545
0
    }
546
}
547
548
#[cfg(feature = "serde")]
549
mod 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)]
598
mod 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
}