From bd8b31ced7514ef7ec0b5d798f9eed6867e1e431 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Fri, 8 May 2020 11:52:50 -0400 Subject: [PATCH] WIP: support no_std --- src/lib.rs | 3 +++ src/symbolize/gimli.rs | 48 ++++++++++++++++++++++-------------------- src/symbolize/mod.rs | 48 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9490312a0..012141121 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,6 +73,9 @@ #[macro_use] extern crate std; +#[cfg(not(feature = "std"))] +extern crate alloc; + pub use crate::backtrace::{trace_unsynchronized, Frame}; mod backtrace; diff --git a/src/symbolize/gimli.rs b/src/symbolize/gimli.rs index c1f4be50e..bb3262b0b 100644 --- a/src/symbolize/gimli.rs +++ b/src/symbolize/gimli.rs @@ -7,22 +7,23 @@ use self::gimli::read::EndianSlice; use self::gimli::LittleEndian as Endian; use crate::symbolize::dladdr; -use crate::symbolize::ResolveWhat; +use crate::symbolize::{ResolveWhat, StdFeatures}; use crate::types::BytesOrWideString; use crate::SymbolName; use addr2line::gimli; use core::convert::TryFrom; use core::mem; +use core::ops::Deref; use core::u32; use findshlibs::{self, Segment, SharedLibrary}; use libc::c_void; -use memmap::Mmap; -use std::env; -use std::ffi::OsString; -use std::fs::File; -use std::path::Path; + +#[cfg(feature = "std")] use std::prelude::v1::*; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + const MAPPINGS_CACHE_SIZE: usize = 4; struct Context<'a> { @@ -33,7 +34,7 @@ struct Context<'a> { struct Mapping { // 'static lifetime is a lie to hack around lack of support for self-referential structs. cx: Context<'static>, - _map: Mmap, + _map: Box>, } fn cx<'data>(object: Object<'data>) -> Option> { @@ -61,7 +62,7 @@ fn cx<'data>(object: Object<'data>) -> Option> { Some(Context { dwarf, object }) } -fn assert_lifetimes<'a>(_: &'a Mmap, _: &Context<'a>) {} +fn assert_lifetimes<'a, M: Deref>(_: &'a M, _: &Context<'a>) {} macro_rules! mk { (Mapping { $map:expr, $inner:expr }) => {{ @@ -75,12 +76,6 @@ macro_rules! mk { }}; } -fn mmap(path: &Path) -> Option { - let file = File::open(path).ok()?; - // TODO: not completely safe, see https://github.com/danburkert/memmap-rs/issues/25 - unsafe { Mmap::map(&file).ok() } -} - cfg_if::cfg_if! { if #[cfg(windows)] { use std::cmp; @@ -286,8 +281,10 @@ cfg_if::cfg_if! { impl Mapping { #[cfg(not(target_os = "macos"))] - fn new(path: &Path) -> Option { - let map = mmap(path)?; + fn new(path: &S::Path) -> Option + where S: StdFeatures, + { + let map = S::mmap(path)?; let cx = cx(Object::parse(&map)?)?; Some(mk!(Mapping { map, cx })) } @@ -296,10 +293,10 @@ impl Mapping { // different implementation of the function here. On OSX we need to go // probing the filesystem for a bunch of files. #[cfg(target_os = "macos")] - fn new(path: &Path) -> Option { + fn new(path: &S::Path) -> Option> { // First up we need to load the unique UUID which is stored in the macho // header of the file we're reading, specified at `path`. - let map = mmap(path)?; + let map = S::mmap(path)?; let macho = MachO::parse(&map, 0).ok()?; let uuid = find_uuid(&macho)?; @@ -331,7 +328,7 @@ impl Mapping { let inner = cx(Object::parse(macho)?)?; return Some(mk!(Mapping { map, inner })); - fn load_dsym(dir: &Path, uuid: &[u8; 16]) -> Option { + fn load_dsym(dir: &M::Path, uuid: &[u8; 16]) -> Option { for entry in dir.read_dir().ok()? { let entry = entry.ok()?; let map = mmap(&entry.path())?; @@ -381,7 +378,7 @@ struct Cache { } struct Library { - name: OsString, + name: Vec, segments: Vec, bias: findshlibs::Bias, } @@ -481,7 +478,9 @@ impl Cache { .next() } - fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<&'a Context<'a>> { + fn mapping_for_lib<'a, S>(&'a mut self, lib: usize) -> Option<&'a Context<'a>> + where S: StdFeatures, + { let idx = self.mappings.iter().position(|(idx, _)| *idx == lib); // Invariant: after this conditional completes without early returning @@ -501,7 +500,7 @@ impl Cache { let path = match self.libraries.get(lib) { Some(lib) => &lib.name, None => { - storage = env::current_exe().ok()?.into(); + storage = S::current_exe()?.into(); &storage } }; @@ -521,7 +520,9 @@ impl Cache { } } -pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) { +pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) + where S: StdFeatures, +{ let addr = what.address_or_ip(); let mut cb = DladdrFallback { cb, @@ -648,6 +649,7 @@ impl Symbol<'_> { } } + #[cfg(feature = "std")] pub fn filename(&self) -> Option<&Path> { match self { Symbol::Dladdr(s) => return s.filename(), diff --git a/src/symbolize/mod.rs b/src/symbolize/mod.rs index 7f8919bc8..82084dd91 100644 --- a/src/symbolize/mod.rs +++ b/src/symbolize/mod.rs @@ -10,6 +10,8 @@ cfg_if::cfg_if! { use crate::backtrace::Frame; use crate::types::BytesOrWideString; use core::ffi::c_void; +use core::borrow::Borrow; +use core::ops::Deref; use rustc_demangle::{try_demangle, Demangle}; /// Resolve an address to a symbol, passing the symbol to the specified @@ -60,7 +62,7 @@ use rustc_demangle::{try_demangle, Demangle}; #[cfg(feature = "std")] pub fn resolve(addr: *mut c_void, cb: F) { let _guard = crate::lock::lock(); - unsafe { resolve_unsynchronized(addr, cb) } + unsafe { resolve_unsynchronized::(addr, cb) } } /// Resolve a previously capture frame to a symbol, passing the symbol to the @@ -102,7 +104,7 @@ pub fn resolve(addr: *mut c_void, cb: F) { #[cfg(feature = "std")] pub fn resolve_frame(frame: &Frame, cb: F) { let _guard = crate::lock::lock(); - unsafe { resolve_frame_unsynchronized(frame, cb) } + unsafe { resolve_frame_unsynchronized::(frame, cb) } } pub enum ResolveWhat<'a> { @@ -155,11 +157,12 @@ fn adjust_ip(a: *mut c_void) -> *mut c_void { /// # Panics /// /// See information on `resolve` for caveats on `cb` panicking. -pub unsafe fn resolve_unsynchronized(addr: *mut c_void, mut cb: F) +pub unsafe fn resolve_unsynchronized(addr: *mut c_void, mut cb: F) where F: FnMut(&Symbol), + S: StdFeatures, { - resolve_imp(ResolveWhat::Address(addr), &mut cb) + resolve_imp::(ResolveWhat::Address(addr), &mut cb) } /// Same as `resolve_frame`, only unsafe as it's unsynchronized. @@ -171,11 +174,43 @@ where /// # Panics /// /// See information on `resolve_frame` for caveats on `cb` panicking. -pub unsafe fn resolve_frame_unsynchronized(frame: &Frame, mut cb: F) +pub unsafe fn resolve_frame_unsynchronized(frame: &Frame, mut cb: F) where F: FnMut(&Symbol), + S: StdFeatures, { - resolve_imp(ResolveWhat::Frame(frame), &mut cb) + resolve_imp::(ResolveWhat::Frame(frame), &mut cb) +} + +pub trait PathLike { +} + +pub trait StdFeatures { + type Path: PathLike; + type PathBuf: Borrow; + type Mmap: Deref; + fn mmap(path: &Self::Path) -> Option; + fn current_exe() -> Option; +} + + +#[cfg(feature = "std")] +struct Std; + +#[cfg(feature = "std")] +impl StdFeatures for Std { + type Path = std::path::Path; + type PathBuf = std::path::PathBuf; + type Mmap = memmap::Mmap; + fn map(path: &Self::Path) -> Option { + use std::fs::File; + let file = File::open(path).ok()?; + // TODO: not completely safe, see https://github.com/danburkert/memmap-rs/issues/25 + unsafe { Mmap::map(&file).ok() } + } + fn current_exe() -> Option { + std::env::current_exe().ok() + } } /// A trait representing the resolution of a symbol in a file. @@ -464,7 +499,6 @@ cfg_if::cfg_if! { use self::dbghelp::Symbol as SymbolImp; unsafe fn clear_symbol_cache_imp() {} } else if #[cfg(all( - feature = "std", feature = "gimli-symbolize", any( target_os = "linux",