Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sections in segment: merge from master #24

Open
wants to merge 23 commits into
base: sections-in-segment
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e23d90d
Add a function on `SharedLibrary` to go from an AVMA to an SVMA
fitzgen Aug 21, 2017
4e6635a
Bump to version 0.3.3
fitzgen Aug 21, 2017
e280560
Merge pull request #9 from fitzgen/shlib-avma-to-svma
fitzgen Aug 22, 2017
9fcb636
Clean up panic propagation in linux implementation
sfackler Nov 11, 2017
ef48e02
Merge pull request #10 from sfackler/simplify-unwind
fitzgen Nov 12, 2017
44e1a3e
Update dependencies
fitzgen Nov 12, 2017
d6fb611
Merge pull request #11 from gimli-rs/update-deps
fitzgen Nov 12, 2017
9adf2a2
Updte links to point to gimli-rs/findshlibs instead of fitzgen/findsh…
fitzgen Nov 12, 2017
7f80964
Merge pull request #12 from fitzgen/update-links-for-gimli-rs-org
fitzgen Nov 13, 2017
3d6f6d2
Fixed deprecated usage of tyvar_behind_raw_pointer
mitsuhiko Apr 10, 2018
9d83263
Added support for fetching IDs from a shared library
mitsuhiko Apr 10, 2018
1175448
Do not implement defaults for id()
mitsuhiko Apr 10, 2018
319b897
Added a default implementation for unsupported platforms. Fixes #14
mitsuhiko Apr 10, 2018
2deb38a
Moved a method to the right trait implementation
mitsuhiko Apr 10, 2018
d8bf4cb
Merge pull request #13 from getsentry/feature/ids
fitzgen Apr 10, 2018
79ca0f5
Merge branch 'master' into feature/unsupported
mitsuhiko Apr 10, 2018
e75edf5
Made some methods unreachable! and documented fallback behavior
mitsuhiko Apr 10, 2018
b47a834
Merge pull request #15 from getsentry/feature/unsupported
fitzgen Apr 10, 2018
c9c2cbf
Run `cargo fmt`
fitzgen Apr 13, 2018
df036c6
Update dependencies to their latest versions
fitzgen Apr 13, 2018
910a946
Merge pull request #17 from fitzgen/refmt-and-update-deps
fitzgen Apr 13, 2018
0c91beb
Bump to version 0.4.0
fitzgen Apr 16, 2018
81d9a38
Merged from master to bring branch up to date. No new changes.
gilescope Aug 5, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@ keywords = ["dyld", "dylib", "shared", "library", "dl_iterate_phdr"]
license = "Apache-2.0/MIT"
name = "findshlibs"
readme = "./README.md"
repository = "https://github.com/fitzgen/findshlibs"
version = "0.3.2"
repository = "https://github.com/gimli-rs/findshlibs"
version = "0.4.0"

[badges.coveralls]
repository = "fitzgen/findshlibs"
repository = "gimli-rs/findshlibs"

[badges.travis-ci]
repository = "fitzgen/findshlibs"
repository = "gimli-rs/findshlibs"

[build-dependencies.bindgen]
default-features = false
version = "0.29.0"
version = "0.36.0"

[dependencies]
cfg-if = "0.1.0"
lazy_static = "0.2.2"
cfg-if = "0.1.2"
lazy_static = "1.0.0"

[features]
nightly = []
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `findshlibs`

[![](http://meritbadge.herokuapp.com/findshlibs) ![](https://img.shields.io/crates/d/findshlibs.png)](https://crates.io/crates/findshlibs) [![Build Status](https://travis-ci.org/fitzgen/findshlibs.png?branch=master)](https://travis-ci.org/fitzgen/findshlibs) [![Coverage Status](https://coveralls.io/repos/github/fitzgen/findshlibs/badge.svg?branch=master)](https://coveralls.io/github/fitzgen/findshlibs?branch=master)
[![](http://meritbadge.herokuapp.com/findshlibs) ![](https://img.shields.io/crates/d/findshlibs.png)](https://crates.io/crates/findshlibs) [![Build Status](https://travis-ci.org/gimli-rs/findshlibs.png?branch=master)](https://travis-ci.org/gimli-rs/findshlibs) [![Coverage Status](https://coveralls.io/repos/github/gimli-rs/findshlibs/badge.svg?branch=master)](https://coveralls.io/github/gimli-rs/findshlibs?branch=master)

Find the shared libraries loaded in the current process with a cross platform
API.
Expand Down Expand Up @@ -39,4 +39,8 @@ These are the OSes that `findshlibs` currently supports:
* Linux
* macOS

If a platform is not supported then a fallback implementation is used that
does nothing. To see if your platform does something at runtime the
`TARGET_SUPPORTED` constant can be used.

Is your OS missing here? Send us a pull request!
24 changes: 12 additions & 12 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ fn main() {
generate_linux_bindings();
} else if cfg!(target_os = "macos") {
generate_macos_bindings();
} else {
panic!("`findshlibs` does not support the target OS :(");
}
}

fn generate_linux_bindings() {
let bindings = bindgen::Builder::default()
.header("./src/linux/bindings.h")
.whitelisted_function("dl_iterate_phdr")
.whitelisted_type(r#"Elf\d*.*"#)
.whitelisted_var("PT_.*")
.whitelist_function("dl_iterate_phdr")
.whitelist_type(r#"Elf\d*.*"#)
.whitelist_var("PT_.*")
.generate()
.expect("Should generate linux FFI bindings OK");

Expand All @@ -31,13 +29,15 @@ fn generate_linux_bindings() {
fn generate_macos_bindings() {
let bindings = bindgen::Builder::default()
.header("./src/macos/bindings.h")
.whitelisted_function("_dyld_.*")
.whitelisted_type("mach_header.*")
.whitelisted_type("load_command.*")
.whitelisted_type("segment_command.*")
.whitelisted_type("section.*")
.whitelisted_var("MH_MAGIC.*")
.whitelisted_var("LC_SEGMENT.*")
.whitelist_function("_dyld_.*")
.whitelist_type("mach_header.*")
.whitelist_type("load_command.*")
.whitelist_type("uuid_command.*")
.whitelist_type("segment_command.*")
.whitelist_type("section.*")
.whitelist_var("MH_MAGIC.*")
.whitelist_var("LC_SEGMENT.*")
.whitelist_var("LC_UUID.*")
.generate()
.expect("Should generate macOS FFI bindings OK");

Expand Down
65 changes: 64 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@
//! * Linux
//! * macOS
//!
//! If a platform is not supported then a fallback implementation is used that
//! does nothing. To see if your platform does something at runtime the
//! `TARGET_SUPPORTED` constant can be used.
//!
//! Is your OS missing here? Send us a pull request!
//!
//! ## Addresses
Expand Down Expand Up @@ -108,6 +112,8 @@ use std::ffi::CStr;
use std::fmt::{self, Debug};
use std::ptr;

pub mod unsupported;

cfg_if!(
if #[cfg(target_os = "linux")] {

Expand All @@ -117,6 +123,9 @@ cfg_if!(
/// implementation for the target operating system.
pub type TargetSharedLibrary<'a> = linux::SharedLibrary<'a>;

/// An indicator if this platform is supported.
pub const TARGET_SUPPORTED: bool = true;

} else if #[cfg(target_os = "macos")] {

pub mod macos;
Expand All @@ -125,9 +134,17 @@ cfg_if!(
/// implementation for the target operating system.
pub type TargetSharedLibrary<'a> = macos::SharedLibrary<'a>;

/// An indicator if this platform is supported.
pub const TARGET_SUPPORTED: bool = true;

} else {

// No implementation for this platform :(
/// The [`SharedLibrary` trait](./trait.SharedLibrary.html)
/// implementation for the target operating system.
pub type TargetSharedLibrary<'a> = unsupported::SharedLibrary<'a>;

/// An indicator if this platform is supported.
pub const TARGET_SUPPORTED: bool = false;

}
);
Expand Down Expand Up @@ -285,6 +302,40 @@ pub trait Segment: NamedMemoryRange<<Self as Segment>::SharedLibrary> {
type EhFrame: EhFrame<Segment = Self>;
}

/// Represents an ID for a shared library.
#[derive(PartialEq, Eq, Hash)]
pub enum SharedLibraryId {
/// A UUID (used on mac)
Uuid([u8; 16]),
}

impl fmt::Display for SharedLibraryId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SharedLibraryId::Uuid(ref bytes) => {
for (idx, byte) in bytes.iter().enumerate() {
if idx == 4 || idx == 6 || idx == 8 || idx == 10 {
try!(write!(f, "-"));
}
try!(write!(f, "{:02x}", byte));
}
}
}
Ok(())
}
}

impl fmt::Debug for SharedLibraryId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SharedLibraryId::Uuid(..) => {
write!(f, "Uuid(\"{}\")", self)?;
}
}
Ok(())
}
}

/// A trait representing a shared library that is loaded in this process.
pub trait SharedLibrary: Sized + Debug {
/// The associated segment type for this shared library.
Expand All @@ -302,6 +353,9 @@ pub trait SharedLibrary: Sized + Debug {
/// Get the name of this shared library.
fn name(&self) -> &CStr;

/// Get the debug-id of this shared library if available.
fn id(&self) -> Option<SharedLibraryId>;

/// Get the bias of this shared library.
///
/// See the module documentation for details.
Expand All @@ -318,6 +372,15 @@ pub trait SharedLibrary: Sized + Debug {
/// exists.
fn eh_frame(&self) -> Option<Self::EhFrame>;

/// Given an AVMA within this shared library, convert it back to an SVMA by
/// removing this shared library's bias.
#[inline]
fn avma_to_svma(&self, address: Avma) -> Svma {
let bias = self.virtual_memory_bias();
let reverse_bias = -bias.0;
Svma(unsafe { address.0.offset(reverse_bias) })
}

/// Iterate over the shared libraries mapped into this process and invoke
/// `f` with each one.
///
Expand Down
75 changes: 26 additions & 49 deletions src/linux/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
//! Linux-specific implementation of the `SharedLibrary` trait.

use super::{Bias, IterationControl, NamedMemoryRange, Svma};
use super::{Bias, IterationControl, NamedMemoryRange, Svma, SharedLibraryId};
use super::EhFrameHdr as EhFrameHdrTrait;
use super::Segment as SegmentTrait;
use super::SharedLibrary as SharedLibraryTrait;

use std::any::Any;
use std::cell::RefCell;
use std::ffi::CStr;
use std::isize;
use std::marker::PhantomData;
use std::os::raw;
use std::panic;
use std::process;
use std::slice;

mod bindings;
Expand Down Expand Up @@ -136,13 +134,13 @@ pub struct SharedLibrary<'a> {
headers: &'a [Phdr],
}

thread_local! {
static PANIC_VALUE: RefCell<Option<Box<Any + Send + 'static>>> = RefCell::new(None);
struct IterState<F> {
f: F,
panic: Option<Box<Any + Send>>,
}

const CONTINUE: raw::c_int = 0;
const BREAK: raw::c_int = 1;
const PANIC: raw::c_int = 2;

impl<'a> SharedLibrary<'a> {
unsafe fn new(info: &'a bindings::dl_phdr_info, size: usize) -> Self {
Expand All @@ -156,46 +154,24 @@ impl<'a> SharedLibrary<'a> {

unsafe extern "C" fn callback<F, C>(info: *mut bindings::dl_phdr_info,
size: usize,
f: *mut raw::c_void)
state: *mut raw::c_void)
-> raw::c_int
where F: FnMut(&Self) -> C,
C: Into<IterationControl>
{
// XXX: We must be very careful to avoid unwinding back into C code
// here, which is UB. We attempt to shepherd the panic across the C
// frames, by stashing it in the `PANIC_VALUE` thread local, and then
// resuming the panic after we exit the `dl_iterate_phdr` call. If,
// however, we panic *again* while stashing the panic value, then we are
// left with no choice but to abort.
let state = &mut *(state as *mut IterState<F>);

match panic::catch_unwind(panic::AssertUnwindSafe(|| {
let f = f as *mut F;
let f = f.as_mut().unwrap();

let info = info.as_ref().unwrap();
let shlib = SharedLibrary::new(info, size);

f(&shlib).into()
(state.f)(&shlib).into()
})) {
Ok(IterationControl::Continue) => CONTINUE,
Ok(IterationControl::Break) => BREAK,
Err(panicked) => {
if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| {
PANIC_VALUE.with(|p| {
*p.borrow_mut() = Some(panicked);
});
})) {
// Try and print out a diagnostic message before aborting.
let _ = panic::catch_unwind(|| {
eprintln!(
"findshlibs: aborting due to double-panic when unwinding a panic \
across C frames"
);
});
process::abort();
}

PANIC
state.panic = Some(panicked);
BREAK
}
}
}
Expand All @@ -211,6 +187,11 @@ impl<'a> SharedLibraryTrait for SharedLibrary<'a> {
self.name
}

#[inline]
fn id(&self) -> Option<SharedLibraryId> {
None
}

#[inline]
fn segments(&self) -> Self::SegmentIter {
SegmentIter { inner: self.headers.iter() }
Expand Down Expand Up @@ -242,25 +223,21 @@ impl<'a> SharedLibraryTrait for SharedLibrary<'a> {
}

#[inline]
fn each<F, C>(mut f: F)
fn each<F, C>(f: F)
where F: FnMut(&Self) -> C,
C: Into<IterationControl>
{
match unsafe {
bindings::dl_iterate_phdr(Some(Self::callback::<F, C>), &mut f as *mut _ as *mut _)
} {
r if r == BREAK || r == CONTINUE => return,
r if r == PANIC => {
panic::resume_unwind(PANIC_VALUE.with(|p| {
p.borrow_mut()
.take()
.expect("dl_iterate_phdr returned PANIC, but we don't have a PANIC_VALUE")
}))
}
otherwise => unreachable!(
"dl_iterate_phdr returned some value we never return from our callback: {}",
otherwise
)
let mut state = IterState {
f: f,
panic: None,
};

unsafe {
bindings::dl_iterate_phdr(Some(Self::callback::<F, C>), &mut state as *mut _ as *mut _);
}

if let Some(panic) = state.panic {
panic::resume_unwind(panic);
}
}
}
Expand Down
Loading