Skip to content

Commit

Permalink
Merge pull request #13 from getsentry/feature/ids
Browse files Browse the repository at this point in the history
Add support for fetching UUIDs from macho libs
  • Loading branch information
fitzgen authored Apr 10, 2018
2 parents 7f80964 + 2deb38a commit d8bf4cb
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 3 deletions.
2 changes: 2 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ fn generate_macos_bindings() {
.whitelist_function("_dyld_.*")
.whitelist_type("mach_header.*")
.whitelist_type("load_command.*")
.whitelist_type("uuid_command.*")
.whitelist_type("segment_command.*")
.whitelist_var("MH_MAGIC.*")
.whitelist_var("LC_SEGMENT.*")
.whitelist_var("LC_UUID.*")
.generate()
.expect("Should generate macOS FFI bindings OK");

Expand Down
37 changes: 37 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,40 @@ pub trait Segment: Sized + Debug {
}
}

/// 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 @@ -236,6 +270,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>;

/// Iterate over this shared library's segments.
fn segments(&self) -> Self::SegmentIter;

Expand Down
7 changes: 6 additions & 1 deletion src/linux/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Linux-specific implementation of the `SharedLibrary` trait.

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

Expand Down Expand Up @@ -149,6 +149,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
36 changes: 34 additions & 2 deletions src/macos/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! The MacOS implementation of the [SharedLibrary
//! trait](../trait.SharedLibrary.html).

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

Expand Down Expand Up @@ -74,6 +74,26 @@ pub struct SegmentIter<'a> {
num_commands: usize,
}

impl<'a> SegmentIter<'a> {
fn find_uuid(&self) -> Option<[u8; 16]> {
let mut num_commands = self.num_commands;
let mut commands = self.commands;

while num_commands > 0 {
num_commands -= 1;
let this_command = unsafe { commands.as_ref().unwrap() };
let command_size = this_command.cmdsize as isize;
if let bindings::LC_UUID = this_command.cmd {
let uuid_cmd = commands as *const bindings::uuid_command;
return Some(unsafe { (*uuid_cmd).uuid });
}
commands = unsafe { (commands as *const u8).offset(command_size) as *const _ };
}

None
}
}

impl<'a> Iterator for SegmentIter<'a> {
type Item = Segment<'a>;

Expand Down Expand Up @@ -141,7 +161,8 @@ impl<'a> MachHeader<'a> {
MachType::from_header_ptr(header).and_then(|ty| {
match ty {
MachType::Mach32 => header.as_ref().map(MachHeader::Header32),
MachType::Mach64 => (header as *const _).as_ref().map(MachHeader::Header64),
MachType::Mach64 => (header as *const bindings::mach_header_64)
.as_ref().map(MachHeader::Header64),
}
})
}
Expand Down Expand Up @@ -179,6 +200,10 @@ impl<'a> SharedLibraryTrait for SharedLibrary<'a> {
self.name
}

fn id(&self) -> Option<SharedLibraryId> {
self.segments().find_uuid().map(SharedLibraryId::Uuid)
}

fn segments(&self) -> Self::SegmentIter {
match self.header {
MachHeader::Header32(header) => {
Expand Down Expand Up @@ -290,6 +315,13 @@ mod tests {
});
}

#[test]
fn get_id() {
macos::SharedLibrary::each(|shlib| {
assert!(shlib.id().is_some());
});
}

#[test]
fn have_text_or_pagezero() {
macos::SharedLibrary::each(|shlib| {
Expand Down

0 comments on commit d8bf4cb

Please sign in to comment.