1 use std::prelude::v1::*;
2 use std::fmt;
3 use std::path::{Path, PathBuf};
4 
5 use {trace, resolve, SymbolName};
6 use types::c_void;
7 
8 /// Representation of an owned and self-contained backtrace.
9 ///
10 /// This structure can be used to capture a backtrace at various points in a
11 /// program and later used to inspect what the backtrace was at that time.
12 ///
13 /// `Backtrace` supports pretty-printing of backtraces through its `Debug`
14 /// implementation.
15 #[derive(Clone)]
16 #[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
17 #[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))]
18 pub struct Backtrace {
19     // Frames here are listed from top-to-bottom of the stack
20     frames: Vec<BacktraceFrame>,
21     // The index we believe is the actual start of the backtrace, omitting
22     // frames like `Backtrace::new` and `backtrace::trace`.
23     actual_start_index: usize,
24 }
25 
26 /// Captured version of a frame in a backtrace.
27 ///
28 /// This type is returned as a list from `Backtrace::frames` and represents one
29 /// stack frame in a captured backtrace.
30 #[derive(Clone)]
31 #[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
32 #[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))]
33 pub struct BacktraceFrame {
34     ip: usize,
35     symbol_address: usize,
36     symbols: Option<Vec<BacktraceSymbol>>,
37 }
38 
39 /// Captured version of a symbol in a backtrace.
40 ///
41 /// This type is returned as a list from `BacktraceFrame::symbols` and
42 /// represents the metadata for a symbol in a backtrace.
43 #[derive(Clone)]
44 #[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
45 #[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))]
46 pub struct BacktraceSymbol {
47     name: Option<Vec<u8>>,
48     addr: Option<usize>,
49     filename: Option<PathBuf>,
50     lineno: Option<u32>,
51 }
52 
53 impl Backtrace {
54     /// Captures a backtrace at the callsite of this function, returning an
55     /// owned representation.
56     ///
57     /// This function is useful for representing a backtrace as an object in
58     /// Rust. This returned value can be sent across threads and printed
59     /// elsewhere, and the purpose of this value is to be entirely self
60     /// contained.
61     ///
62     /// # Examples
63     ///
64     /// ```
65     /// use backtrace::Backtrace;
66     ///
67     /// let current_backtrace = Backtrace::new();
68     /// ```
69     #[inline(never)] // want to make sure there's a frame here to remove
new() -> Backtrace70     pub fn new() -> Backtrace {
71         let mut bt = Self::create(Self::new as usize);
72         bt.resolve();
73         bt
74     }
75 
76     /// Similar to `new` except that this does not resolve any symbols, this
77     /// simply captures the backtrace as a list of addresses.
78     ///
79     /// At a later time the `resolve` function can be called to resolve this
80     /// backtrace's symbols into readable names. This function exists because
81     /// the resolution process can sometimes take a significant amount of time
82     /// whereas any one backtrace may only be rarely printed.
83     ///
84     /// # Examples
85     ///
86     /// ```
87     /// use backtrace::Backtrace;
88     ///
89     /// let mut current_backtrace = Backtrace::new_unresolved();
90     /// println!("{:?}", current_backtrace); // no symbol names
91     /// current_backtrace.resolve();
92     /// println!("{:?}", current_backtrace); // symbol names now present
93     /// ```
94     #[inline(never)] // want to make sure there's a frame here to remove
new_unresolved() -> Backtrace95     pub fn new_unresolved() -> Backtrace {
96         Self::create(Self::new_unresolved as usize)
97     }
98 
create(ip: usize) -> Backtrace99     fn create(ip: usize) -> Backtrace {
100         let ip_lo = ip;
101         let ip_hi = ip + 128;
102 
103         let mut frames = Vec::new();
104         let mut actual_start_index = None;
105         trace(|frame| {
106             let ip = frame.ip() as usize;
107             frames.push(BacktraceFrame {
108                 ip,
109                 symbol_address: frame.symbol_address() as usize,
110                 symbols: None,
111             });
112 
113             if cfg!(not(all(target_os = "windows", target_arch = "x86"))) &&
114                 ip >= ip_lo &&
115                 ip <= ip_hi &&
116                 actual_start_index.is_none()
117             {
118                 actual_start_index = Some(frames.len());
119             }
120             true
121         });
122 
123         Backtrace {
124             frames,
125             actual_start_index: actual_start_index.unwrap_or(0),
126         }
127     }
128 
129     /// Returns the frames from when this backtrace was captured.
130     ///
131     /// The first entry of this slice is likely the function `Backtrace::new`,
132     /// and the last frame is likely something about how this thread or the main
133     /// function started.
frames(&self) -> &[BacktraceFrame]134     pub fn frames(&self) -> &[BacktraceFrame] {
135         &self.frames[self.actual_start_index..]
136     }
137 
138     /// If this backtrace was created from `new_unresolved` then this function
139     /// will resolve all addresses in the backtrace to their symbolic names.
140     ///
141     /// If this backtrace has been previously resolved or was created through
142     /// `new`, this function does nothing.
resolve(&mut self)143     pub fn resolve(&mut self) {
144         for frame in self.frames.iter_mut().filter(|f| f.symbols.is_none()) {
145             let mut symbols = Vec::new();
146             resolve(frame.ip as *mut _, |symbol| {
147                 symbols.push(BacktraceSymbol {
148                     name: symbol.name().map(|m| m.as_bytes().to_vec()),
149                     addr: symbol.addr().map(|a| a as usize),
150                     filename: symbol.filename().map(|m| m.to_owned()),
151                     lineno: symbol.lineno(),
152                 });
153             });
154             frame.symbols = Some(symbols);
155         }
156     }
157 }
158 
159 impl From<Vec<BacktraceFrame>> for Backtrace {
from(frames: Vec<BacktraceFrame>) -> Self160     fn from(frames: Vec<BacktraceFrame>) -> Self {
161         Backtrace {
162             frames,
163             actual_start_index: 0,
164         }
165     }
166 }
167 
168 impl Into<Vec<BacktraceFrame>> for Backtrace {
into(self) -> Vec<BacktraceFrame>169     fn into(self) -> Vec<BacktraceFrame> {
170         self.frames
171     }
172 }
173 
174 impl BacktraceFrame {
175     /// Same as `Frame::ip`
ip(&self) -> *mut c_void176     pub fn ip(&self) -> *mut c_void {
177         self.ip as *mut c_void
178     }
179 
180     /// Same as `Frame::symbol_address`
symbol_address(&self) -> *mut c_void181     pub fn symbol_address(&self) -> *mut c_void {
182         self.symbol_address as *mut c_void
183     }
184 
185     /// Returns the list of symbols that this frame corresponds to.
186     ///
187     /// Normally there is only one symbol per frame, but sometimes if a number
188     /// of functions are inlined into one frame then multiple symbols will be
189     /// returned. The first symbol listed is the "innermost function", whereas
190     /// the last symbol is the outermost (last caller).
191     ///
192     /// Note that if this frame came from an unresolved backtrace then this will
193     /// return an empty list.
symbols(&self) -> &[BacktraceSymbol]194     pub fn symbols(&self) -> &[BacktraceSymbol] {
195         self.symbols.as_ref().map(|s| &s[..]).unwrap_or(&[])
196     }
197 }
198 
199 impl BacktraceSymbol {
200     /// Same as `Symbol::name`
name(&self) -> Option<SymbolName>201     pub fn name(&self) -> Option<SymbolName> {
202         self.name.as_ref().map(|s| SymbolName::new(s))
203     }
204 
205     /// Same as `Symbol::addr`
addr(&self) -> Option<*mut c_void>206     pub fn addr(&self) -> Option<*mut c_void> {
207         self.addr.map(|s| s as *mut c_void)
208     }
209 
210     /// Same as `Symbol::filename`
filename(&self) -> Option<&Path>211     pub fn filename(&self) -> Option<&Path> {
212         self.filename.as_ref().map(|p| &**p)
213     }
214 
215     /// Same as `Symbol::lineno`
lineno(&self) -> Option<u32>216     pub fn lineno(&self) -> Option<u32> {
217         self.lineno
218     }
219 }
220 
221 impl fmt::Debug for Backtrace {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result222     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
223         write!(fmt, "stack backtrace:")?;
224 
225         let iter = if fmt.alternate() {
226             self.frames.iter()
227         } else {
228             self.frames[self.actual_start_index..].iter()
229         };
230 
231         for (idx, frame) in iter.enumerate() {
232             // To reduce TCB size in Sgx enclave, we do not want to implement symbol resolution functionality.
233             // Rather, we can print the offset of the address here, which could be later mapped to
234             // correct function.
235             let ip: *mut c_void;
236             #[cfg(target_env = "sgx")]
237             {
238                 ip = usize::wrapping_sub(
239                     frame.ip() as _,
240                     std::os::fortanix_sgx::mem::image_base() as _,
241                 ) as _;
242             }
243             #[cfg(not(target_env = "sgx"))]
244             {
245                 ip = frame.ip();
246             }
247 
248             write!(fmt, "\n{:4}: ", idx)?;
249 
250             let symbols = match frame.symbols {
251                 Some(ref s) => s,
252                 None => {
253                     write!(fmt, "<unresolved> ({:?})", ip)?;
254                     continue
255                 }
256             };
257             if symbols.len() == 0 {
258                 write!(fmt, "<no info> ({:?})", ip)?;
259                 continue;
260             }
261 
262             for (idx, symbol) in symbols.iter().enumerate() {
263                 if idx != 0 {
264                     write!(fmt, "\n      ")?;
265                 }
266 
267                 if let Some(name) = symbol.name() {
268                     write!(fmt, "{}", name)?;
269                 } else {
270                     write!(fmt, "<unknown>")?;
271                 }
272 
273                 if idx == 0 {
274                     write!(fmt, " ({:?})", ip)?;
275                 }
276 
277                 if let (Some(file), Some(line)) = (symbol.filename(), symbol.lineno()) {
278                     write!(fmt, "\n             at {}:{}", file.display(), line)?;
279                 }
280             }
281         }
282 
283         Ok(())
284     }
285 }
286 
287 impl Default for Backtrace {
default() -> Backtrace288     fn default() -> Backtrace {
289         Backtrace::new()
290     }
291 }
292