use std::fmt;
#[cfg(not(feature = "cpp_demangle"))]
use std::marker::PhantomData;
use std::os::raw::c_void;
use std::path::Path;
use std::str;
use rustc_demangle::{try_demangle, Demangle};
pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, mut cb: F) {
resolve_imp(addr, &mut cb)
}
pub struct Symbol {
inner: SymbolImp,
}
impl Symbol {
pub fn name(&self) -> Option<SymbolName> {
self.inner.name()
}
pub fn addr(&self) -> Option<*mut c_void> {
self.inner.addr()
}
pub fn filename(&self) -> Option<&Path> {
self.inner.filename()
}
pub fn lineno(&self) -> Option<u32> {
self.inner.lineno()
}
}
impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut d = f.debug_struct("Symbol");
if let Some(name) = self.name() {
d.field("name", &name);
}
if let Some(addr) = self.addr() {
d.field("addr", &addr);
}
if let Some(filename) = self.filename() {
d.field("filename", &filename);
}
if let Some(lineno) = self.lineno() {
d.field("lineno", &lineno);
}
d.finish()
}
}
cfg_if! {
if #[cfg(feature = "cpp_demangle")] {
struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>);
impl<'a> OptionCppSymbol<'a> {
fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> {
OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok())
}
fn none() -> OptionCppSymbol<'a> {
OptionCppSymbol(None)
}
}
} else {
struct OptionCppSymbol<'a>(PhantomData<&'a ()>);
impl<'a> OptionCppSymbol<'a> {
fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> {
OptionCppSymbol(PhantomData)
}
fn none() -> OptionCppSymbol<'a> {
OptionCppSymbol(PhantomData)
}
}
}
}
#[allow(dead_code)]
pub struct SymbolName<'a> {
bytes: &'a [u8],
demangled: Option<Demangle<'a>>,
cpp_demangled: OptionCppSymbol<'a>,
}
impl<'a> SymbolName<'a> {
pub fn new(bytes: &'a [u8]) -> SymbolName<'a> {
let str_bytes = str::from_utf8(bytes).ok();
let demangled = str_bytes.and_then(|s| try_demangle(s).ok());
let cpp = if demangled.is_none() {
OptionCppSymbol::parse(bytes)
} else {
OptionCppSymbol::none()
};
SymbolName {
bytes: bytes,
demangled: demangled,
cpp_demangled: cpp,
}
}
pub fn as_str(&self) -> Option<&'a str> {
self.demangled
.as_ref()
.map(|s| s.as_str())
.or_else(|| {
str::from_utf8(self.bytes).ok()
})
}
pub fn as_bytes(&self) -> &'a [u8] {
self.bytes
}
}
cfg_if! {
if #[cfg(feature = "cpp_demangle")] {
impl<'a> fmt::Display for SymbolName<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref s) = self.demangled {
s.fmt(f)
} else if let Some(ref cpp) = self.cpp_demangled.0 {
cpp.fmt(f)
} else {
String::from_utf8_lossy(self.bytes).fmt(f)
}
}
}
} else {
impl<'a> fmt::Display for SymbolName<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref s) = self.demangled {
s.fmt(f)
} else {
String::from_utf8_lossy(self.bytes).fmt(f)
}
}
}
}
}
cfg_if! {
if #[cfg(feature = "cpp_demangle")] {
impl<'a> fmt::Debug for SymbolName<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::fmt::Write;
if let Some(ref s) = self.demangled {
return s.fmt(f)
}
if let Some(ref cpp) = self.cpp_demangled.0 {
let mut s = String::new();
if write!(s, "{}", cpp).is_ok() {
return s.fmt(f)
}
}
String::from_utf8_lossy(self.bytes).fmt(f)
}
}
} else {
impl<'a> fmt::Debug for SymbolName<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref s) = self.demangled {
s.fmt(f)
} else {
String::from_utf8_lossy(self.bytes).fmt(f)
}
}
}
}
}
cfg_if! {
if #[cfg(all(windows, feature = "dbghelp"))] {
mod dbghelp;
use self::dbghelp::resolve as resolve_imp;
use self::dbghelp::Symbol as SymbolImp;
} else if #[cfg(all(feature = "gimli-symbolize",
unix,
target_os = "linux"))] {
mod gimli;
use self::gimli::resolve as resolve_imp;
use self::gimli::Symbol as SymbolImp;
} else if #[cfg(all(feature = "libbacktrace",
unix,
not(target_os = "fuchsia"),
not(target_os = "emscripten"),
not(target_os = "macos"),
not(target_os = "ios")))] {
mod libbacktrace;
use self::libbacktrace::resolve as resolve_imp;
use self::libbacktrace::Symbol as SymbolImp;
} else if #[cfg(all(feature = "coresymbolication",
any(target_os = "macos",
all(target_os = "ios", debug_assertions))))] {
mod coresymbolication;
use self::coresymbolication::resolve as resolve_imp;
use self::coresymbolication::Symbol as SymbolImp;
} else if #[cfg(all(unix,
not(target_os = "emscripten"),
feature = "dladdr"))] {
mod dladdr;
use self::dladdr::resolve as resolve_imp;
use self::dladdr::Symbol as SymbolImp;
} else {
mod noop;
use self::noop::resolve as resolve_imp;
use self::noop::Symbol as SymbolImp;
}
}