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}