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 | // 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 | |
34 | fn _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)] |
49 | pub struct BacktraceFrame { |
50 | frame: Frame, |
51 | symbols: Option<Vec<BacktraceSymbol>>, |
52 | } |
53 | |
54 | #[derive (Clone)] |
55 | enum 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 | |
65 | impl 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))] |
103 | pub 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 | |
111 | impl 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 | |
243 | impl 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 | |
252 | impl 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 | |
261 | impl Into<Vec<BacktraceFrame>> for Backtrace { |
262 | fn into(self) -> Vec<BacktraceFrame> { |
263 | self.frames |
264 | } |
265 | } |
266 | |
267 | impl 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 | |
319 | impl 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 | |
371 | impl 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 | |
408 | impl Default for Backtrace { |
409 | fn default() -> Backtrace { |
410 | Backtrace::new() |
411 | } |
412 | } |
413 | |
414 | impl fmt::Debug for BacktraceFrame { |
415 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
416 | fmt&mut DebugStruct<'_, '_>.debug_struct("BacktraceFrame" ) |
417 | .field("ip" , &self.ip()) |
418 | .field(name:"symbol_address" , &self.symbol_address()) |
419 | .finish() |
420 | } |
421 | } |
422 | |
423 | impl fmt::Debug for BacktraceSymbol { |
424 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
425 | fmt&mut DebugStruct<'_, '_>.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(name:"colno" , &self.colno()) |
431 | .finish() |
432 | } |
433 | } |
434 | |
435 | #[cfg (feature = "serialize-rustc" )] |
436 | mod 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" )] |
483 | mod 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)] |
532 | mod 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 | } |
556 | |