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