use crate::{resolve, resolve_frame, trace, Symbol, SymbolName};
use std::ffi::c_void;
use std::fmt;
use std::path::{Path, PathBuf};
use std::prelude::v1::*;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
#[derive(Clone)]
#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct Backtrace {
frames: Vec<BacktraceFrame>,
actual_start_index: usize,
}
fn _assert_send_sync() {
fn _assert<T: Send + Sync>() {}
_assert::<Backtrace>();
}
#[derive(Clone)]
pub struct BacktraceFrame {
frame: Frame,
symbols: Option<Vec<BacktraceSymbol>>,
}
#[derive(Clone)]
enum Frame {
Raw(crate::Frame),
#[allow(dead_code)]
Deserialized {
ip: usize,
symbol_address: usize,
},
}
impl Frame {
fn ip(&self) -> *mut c_void {
match *self {
Frame::Raw(ref f) => f.ip(),
Frame::Deserialized { ip, .. } => ip as *mut c_void,
}
}
fn symbol_address(&self) -> *mut c_void {
match *self {
Frame::Raw(ref f) => f.symbol_address(),
Frame::Deserialized { symbol_address, .. } => symbol_address as *mut c_void,
}
}
}
#[derive(Clone)]
#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct BacktraceSymbol {
name: Option<Vec<u8>>,
addr: Option<usize>,
filename: Option<PathBuf>,
lineno: Option<u32>,
}
impl Backtrace {
#[inline(never)] pub fn new() -> Backtrace {
let mut bt = Self::create(Self::new as usize);
bt.resolve();
bt
}
#[inline(never)] pub fn new_unresolved() -> Backtrace {
Self::create(Self::new_unresolved as usize)
}
fn create(ip: usize) -> Backtrace {
let mut frames = Vec::new();
let mut actual_start_index = None;
trace(|frame| {
frames.push(BacktraceFrame {
frame: Frame::Raw(frame.clone()),
symbols: None,
});
if frame.symbol_address() as usize == ip && actual_start_index.is_none() {
actual_start_index = Some(frames.len());
}
true
});
Backtrace {
frames,
actual_start_index: actual_start_index.unwrap_or(0),
}
}
pub fn frames(&self) -> &[BacktraceFrame] {
&self.frames[self.actual_start_index..]
}
pub fn resolve(&mut self) {
for frame in self.frames.iter_mut().filter(|f| f.symbols.is_none()) {
let mut symbols = Vec::new();
{
let sym = |symbol: &Symbol| {
symbols.push(BacktraceSymbol {
name: symbol.name().map(|m| m.as_bytes().to_vec()),
addr: symbol.addr().map(|a| a as usize),
filename: symbol.filename().map(|m| m.to_owned()),
lineno: symbol.lineno(),
});
};
match frame.frame {
Frame::Raw(ref f) => resolve_frame(f, sym),
Frame::Deserialized { ip, .. } => {
resolve(ip as *mut c_void, sym);
}
}
}
frame.symbols = Some(symbols);
}
}
}
impl From<Vec<BacktraceFrame>> for Backtrace {
fn from(frames: Vec<BacktraceFrame>) -> Self {
Backtrace {
frames,
actual_start_index: 0,
}
}
}
impl Into<Vec<BacktraceFrame>> for Backtrace {
fn into(self) -> Vec<BacktraceFrame> {
self.frames
}
}
impl BacktraceFrame {
pub fn ip(&self) -> *mut c_void {
self.frame.ip() as *mut c_void
}
pub fn symbol_address(&self) -> *mut c_void {
self.frame.symbol_address() as *mut c_void
}
pub fn symbols(&self) -> &[BacktraceSymbol] {
self.symbols.as_ref().map(|s| &s[..]).unwrap_or(&[])
}
}
impl BacktraceSymbol {
pub fn name(&self) -> Option<SymbolName> {
self.name.as_ref().map(|s| SymbolName::new(s))
}
pub fn addr(&self) -> Option<*mut c_void> {
self.addr.map(|s| s as *mut c_void)
}
pub fn filename(&self) -> Option<&Path> {
self.filename.as_ref().map(|p| &**p)
}
pub fn lineno(&self) -> Option<u32> {
self.lineno
}
}
impl fmt::Debug for Backtrace {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "stack backtrace:")?;
let iter = if fmt.alternate() {
self.frames.iter()
} else {
self.frames[self.actual_start_index..].iter()
};
for (idx, frame) in iter.enumerate() {
let ip: *mut c_void;
#[cfg(target_env = "sgx")]
{
ip = usize::wrapping_sub(
frame.ip() as _,
std::os::fortanix_sgx::mem::image_base() as _,
) as _;
}
#[cfg(not(target_env = "sgx"))]
{
ip = frame.ip();
}
write!(fmt, "\n{:4}: ", idx)?;
let symbols = match frame.symbols {
Some(ref s) => s,
None => {
write!(fmt, "<unresolved> ({:?})", ip)?;
continue;
}
};
if symbols.len() == 0 {
write!(fmt, "<no info> ({:?})", ip)?;
continue;
}
for (idx, symbol) in symbols.iter().enumerate() {
if idx != 0 {
write!(fmt, "\n ")?;
}
if let Some(name) = symbol.name() {
write!(fmt, "{}", name)?;
} else {
write!(fmt, "<unknown>")?;
}
if idx == 0 {
write!(fmt, " ({:?})", ip)?;
}
if let (Some(file), Some(line)) = (symbol.filename(), symbol.lineno()) {
write!(fmt, "\n at {}:{}", file.display(), line)?;
}
}
}
Ok(())
}
}
impl Default for Backtrace {
fn default() -> Backtrace {
Backtrace::new()
}
}
impl fmt::Debug for BacktraceFrame {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("BacktraceFrame")
.field("ip", &self.ip())
.field("symbol_address", &self.symbol_address())
.finish()
}
}
impl fmt::Debug for BacktraceSymbol {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("BacktraceSymbol")
.field("name", &self.name())
.field("addr", &self.addr())
.field("filename", &self.filename())
.field("lineno", &self.lineno())
.finish()
}
}
#[cfg(feature = "serialize-rustc")]
mod rustc_serialize_impls {
use super::*;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
#[derive(RustcEncodable, RustcDecodable)]
struct SerializedFrame {
ip: usize,
symbol_address: usize,
symbols: Option<Vec<BacktraceSymbol>>,
}
impl Decodable for BacktraceFrame {
fn decode<D>(d: &mut D) -> Result<Self, D::Error>
where
D: Decoder,
{
let frame: SerializedFrame = SerializedFrame::decode(d)?;
Ok(BacktraceFrame {
frame: Frame::Deserialized {
ip: frame.ip,
symbol_address: frame.symbol_address,
},
symbols: frame.symbols,
})
}
}
impl Encodable for BacktraceFrame {
fn encode<E>(&self, e: &mut E) -> Result<(), E::Error>
where
E: Encoder,
{
let BacktraceFrame { frame, symbols } = self;
SerializedFrame {
ip: frame.ip() as usize,
symbol_address: frame.symbol_address() as usize,
symbols: symbols.clone(),
}
.encode(e)
}
}
}
#[cfg(feature = "serde")]
mod serde_impls {
extern crate serde;
use self::serde::de::Deserializer;
use self::serde::ser::Serializer;
use self::serde::{Deserialize, Serialize};
use super::*;
#[derive(Serialize, Deserialize)]
struct SerializedFrame {
ip: usize,
symbol_address: usize,
symbols: Option<Vec<BacktraceSymbol>>,
}
impl Serialize for BacktraceFrame {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let BacktraceFrame { frame, symbols } = self;
SerializedFrame {
ip: frame.ip() as usize,
symbol_address: frame.symbol_address() as usize,
symbols: symbols.clone(),
}
.serialize(s)
}
}
impl<'a> Deserialize<'a> for BacktraceFrame {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
let frame: SerializedFrame = SerializedFrame::deserialize(d)?;
Ok(BacktraceFrame {
frame: Frame::Deserialized {
ip: frame.ip,
symbol_address: frame.symbol_address,
},
symbols: frame.symbols,
})
}
}
}