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