Skip to content

Commit

Permalink
WIP: support no_std
Browse files Browse the repository at this point in the history
  • Loading branch information
luser committed May 8, 2020
1 parent b5cc5b1 commit bd8b31c
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 30 deletions.
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
48 changes: 25 additions & 23 deletions src/symbolize/gimli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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<Deref<Target=[u8]>>,
}

fn cx<'data>(object: Object<'data>) -> Option<Context<'data>> {
Expand Down Expand Up @@ -61,7 +62,7 @@ fn cx<'data>(object: Object<'data>) -> Option<Context<'data>> {
Some(Context { dwarf, object })
}

fn assert_lifetimes<'a>(_: &'a Mmap, _: &Context<'a>) {}
fn assert_lifetimes<'a, M: Deref<Target=[u8]>>(_: &'a M, _: &Context<'a>) {}

macro_rules! mk {
(Mapping { $map:expr, $inner:expr }) => {{
Expand All @@ -75,12 +76,6 @@ macro_rules! mk {
}};
}

fn mmap(path: &Path) -> Option<Mmap> {
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;
Expand Down Expand Up @@ -286,8 +281,10 @@ cfg_if::cfg_if! {

impl Mapping {
#[cfg(not(target_os = "macos"))]
fn new(path: &Path) -> Option<Mapping> {
let map = mmap(path)?;
fn new<S>(path: &S::Path) -> Option<Mapping>
where S: StdFeatures,
{
let map = S::mmap(path)?;
let cx = cx(Object::parse(&map)?)?;
Some(mk!(Mapping { map, cx }))
}
Expand All @@ -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<Mapping> {
fn new(path: &S::Path) -> Option<Mapping<S>> {
// 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)?;

Expand Down Expand Up @@ -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<Mapping> {
fn load_dsym(dir: &M::Path, uuid: &[u8; 16]) -> Option<Mapping> {
for entry in dir.read_dir().ok()? {
let entry = entry.ok()?;
let map = mmap(&entry.path())?;
Expand Down Expand Up @@ -381,7 +378,7 @@ struct Cache {
}

struct Library {
name: OsString,
name: Vec<u8>,
segments: Vec<LibrarySegment>,
bias: findshlibs::Bias,
}
Expand Down Expand Up @@ -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
Expand All @@ -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
}
};
Expand All @@ -521,7 +520,9 @@ impl Cache {
}
}

pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
pub unsafe fn resolve<S>(what: ResolveWhat, cb: &mut FnMut(&super::Symbol))
where S: StdFeatures,
{
let addr = what.address_or_ip();
let mut cb = DladdrFallback {
cb,
Expand Down Expand Up @@ -648,6 +649,7 @@ impl Symbol<'_> {
}
}

#[cfg(feature = "std")]
pub fn filename(&self) -> Option<&Path> {
match self {
Symbol::Dladdr(s) => return s.filename(),
Expand Down
48 changes: 41 additions & 7 deletions src/symbolize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -60,7 +62,7 @@ use rustc_demangle::{try_demangle, Demangle};
#[cfg(feature = "std")]
pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, cb: F) {
let _guard = crate::lock::lock();
unsafe { resolve_unsynchronized(addr, cb) }
unsafe { resolve_unsynchronized::<F, Std>(addr, cb) }
}

/// Resolve a previously capture frame to a symbol, passing the symbol to the
Expand Down Expand Up @@ -102,7 +104,7 @@ pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, cb: F) {
#[cfg(feature = "std")]
pub fn resolve_frame<F: FnMut(&Symbol)>(frame: &Frame, cb: F) {
let _guard = crate::lock::lock();
unsafe { resolve_frame_unsynchronized(frame, cb) }
unsafe { resolve_frame_unsynchronized::<F, Std>(frame, cb) }
}

pub enum ResolveWhat<'a> {
Expand Down Expand Up @@ -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<F>(addr: *mut c_void, mut cb: F)
pub unsafe fn resolve_unsynchronized<F, S>(addr: *mut c_void, mut cb: F)
where
F: FnMut(&Symbol),
S: StdFeatures,
{
resolve_imp(ResolveWhat::Address(addr), &mut cb)
resolve_imp::<S>(ResolveWhat::Address(addr), &mut cb)
}

/// Same as `resolve_frame`, only unsafe as it's unsynchronized.
Expand All @@ -171,11 +174,43 @@ where
/// # Panics
///
/// See information on `resolve_frame` for caveats on `cb` panicking.
pub unsafe fn resolve_frame_unsynchronized<F>(frame: &Frame, mut cb: F)
pub unsafe fn resolve_frame_unsynchronized<F, S>(frame: &Frame, mut cb: F)
where
F: FnMut(&Symbol),
S: StdFeatures,
{
resolve_imp(ResolveWhat::Frame(frame), &mut cb)
resolve_imp::<S>(ResolveWhat::Frame(frame), &mut cb)
}

pub trait PathLike {
}

pub trait StdFeatures {
type Path: PathLike;
type PathBuf: Borrow<Self::Path>;
type Mmap: Deref<Target=[u8]>;
fn mmap(path: &Self::Path) -> Option<Self::Mmap>;
fn current_exe() -> Option<Self::PathBuf>;
}


#[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<Self::Mmap> {
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<Self::PathBuf> {
std::env::current_exe().ok()
}
}

/// A trait representing the resolution of a symbol in a file.
Expand Down Expand Up @@ -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",
Expand Down

0 comments on commit bd8b31c

Please sign in to comment.