#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
extern crate goblin;
use std::fmt;
use std::io::Cursor;
mod elf;
pub use elf::*;
mod macho;
pub use macho::*;
mod pe;
pub use pe::*;
mod traits;
pub use traits::*;
#[derive(Debug)]
pub struct File<'a> {
inner: FileInternal<'a>,
}
#[derive(Debug)]
enum FileInternal<'a> {
Elf(ElfFile<'a>),
MachO(MachOFile<'a>),
Pe(PeFile<'a>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Machine {
Other,
Arm,
Arm64,
X86,
#[allow(non_camel_case_types)]
X86_64,
}
#[derive(Debug)]
pub struct SegmentIterator<'a> {
inner: SegmentIteratorInternal<'a>,
}
#[derive(Debug)]
enum SegmentIteratorInternal<'a> {
Elf(ElfSegmentIterator<'a>),
MachO(MachOSegmentIterator<'a>),
Pe(PeSegmentIterator<'a>),
}
pub struct Segment<'a> {
inner: SegmentInternal<'a>,
}
#[derive(Debug)]
enum SegmentInternal<'a> {
Elf(ElfSegment<'a>),
MachO(MachOSegment<'a>),
Pe(PeSegment<'a>),
}
#[derive(Debug)]
pub struct SectionIterator<'a> {
inner: SectionIteratorInternal<'a>,
}
#[derive(Debug)]
enum SectionIteratorInternal<'a> {
Elf(ElfSectionIterator<'a>),
MachO(MachOSectionIterator<'a>),
Pe(PeSectionIterator<'a>),
}
pub struct Section<'a> {
inner: SectionInternal<'a>,
}
enum SectionInternal<'a> {
Elf(ElfSection<'a>),
MachO(MachOSection<'a>),
Pe(PeSection<'a>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionKind {
Unknown,
Text,
Data,
ReadOnlyData,
UninitializedData,
Other,
}
#[derive(Debug)]
pub struct Symbol<'a> {
kind: SymbolKind,
section: usize,
section_kind: Option<SectionKind>,
global: bool,
name: Option<&'a str>,
address: u64,
size: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolKind {
Unknown,
Text,
Data,
Section,
File,
Common,
Tls,
}
macro_rules! with_inner {
($inner:expr, $enum:ident, |$var:ident| $body:expr) => {
match $inner {
&$enum::Elf(ref $var) => { $body }
&$enum::MachO(ref $var) => { $body }
&$enum::Pe(ref $var) => { $body }
}
}
}
macro_rules! map_inner {
($inner:expr, $from:ident, $to:ident, |$var:ident| $body:expr) => {
match $inner {
&$from::Elf(ref $var) => $to::Elf($body),
&$from::MachO(ref $var) => $to::MachO($body),
&$from::Pe(ref $var) => $to::Pe($body),
}
}
}
macro_rules! next_inner {
($inner:expr, $from:ident, $to:ident) => {
match $inner {
&mut $from::Elf(ref mut iter) => iter.next().map(|x| $to::Elf(x)),
&mut $from::MachO(ref mut iter) => iter.next().map(|x| $to::MachO(x)),
&mut $from::Pe(ref mut iter) => iter.next().map(|x| $to::Pe(x)),
}
}
}
impl<'a> Object<'a> for File<'a> {
type Segment = Segment<'a>;
type SegmentIterator = SegmentIterator<'a>;
type Section = Section<'a>;
type SectionIterator = SectionIterator<'a>;
fn parse(data: &'a [u8]) -> Result<Self, &'static str> {
let mut cursor = Cursor::new(data);
let inner = match goblin::peek(&mut cursor).map_err(|_| "Could not parse file magic")? {
goblin::Hint::Elf(_) => FileInternal::Elf(ElfFile::parse(data)?),
goblin::Hint::Mach(_) => FileInternal::MachO(MachOFile::parse(data)?),
goblin::Hint::PE => FileInternal::Pe(PeFile::parse(data)?),
_ => return Err("Unknown file magic"),
};
Ok(File { inner })
}
fn machine(&self) -> Machine {
with_inner!(&self.inner, FileInternal, |x| x.machine())
}
fn segments(&'a self) -> SegmentIterator<'a> {
SegmentIterator {
inner: map_inner!(
&self.inner,
FileInternal,
SegmentIteratorInternal,
|x| x.segments()
),
}
}
fn section_data_by_name(&self, section_name: &str) -> Option<&'a [u8]> {
with_inner!(
&self.inner,
FileInternal,
|x| x.section_data_by_name(section_name)
)
}
fn sections(&'a self) -> SectionIterator<'a> {
SectionIterator {
inner: map_inner!(
&self.inner,
FileInternal,
SectionIteratorInternal,
|x| x.sections()
),
}
}
fn symbols(&self) -> Vec<Symbol<'a>> {
with_inner!(&self.inner, FileInternal, |x| x.symbols())
}
fn is_little_endian(&self) -> bool {
with_inner!(&self.inner, FileInternal, |x| x.is_little_endian())
}
}
impl<'a> Iterator for SegmentIterator<'a> {
type Item = Segment<'a>;
fn next(&mut self) -> Option<Self::Item> {
next_inner!(&mut self.inner, SegmentIteratorInternal, SegmentInternal)
.map(|inner| Segment { inner })
}
}
impl<'a> fmt::Debug for Segment<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Segment")
.field("name", &self.name().unwrap_or("<unnamed>"))
.field("address", &self.address())
.field("size", &self.data().len())
.finish()
}
}
impl<'a> ObjectSegment<'a> for Segment<'a> {
fn address(&self) -> u64 {
with_inner!(&self.inner, SegmentInternal, |x| x.address())
}
fn size(&self) -> u64 {
with_inner!(&self.inner, SegmentInternal, |x| x.size())
}
fn data(&self) -> &'a [u8] {
with_inner!(&self.inner, SegmentInternal, |x| x.data())
}
fn name(&self) -> Option<&str> {
with_inner!(&self.inner, SegmentInternal, |x| x.name())
}
}
impl<'a> Iterator for SectionIterator<'a> {
type Item = Section<'a>;
fn next(&mut self) -> Option<Self::Item> {
next_inner!(&mut self.inner, SectionIteratorInternal, SectionInternal)
.map(|inner| Section { inner })
}
}
impl<'a> fmt::Debug for Section<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Section")
.field("name", &self.name().unwrap_or("<invalid name>"))
.field("address", &self.address())
.field("size", &self.data().len())
.finish()
}
}
impl<'a> ObjectSection<'a> for Section<'a> {
fn address(&self) -> u64 {
with_inner!(&self.inner, SectionInternal, |x| x.address())
}
fn size(&self) -> u64 {
with_inner!(&self.inner, SectionInternal, |x| x.size())
}
fn data(&self) -> &'a [u8] {
with_inner!(&self.inner, SectionInternal, |x| x.data())
}
fn name(&self) -> Option<&str> {
with_inner!(&self.inner, SectionInternal, |x| x.name())
}
fn segment_name(&self) -> Option<&str> {
with_inner!(&self.inner, SectionInternal, |x| x.segment_name())
}
}
impl<'a> Symbol<'a> {
#[inline]
pub fn kind(&self) -> SymbolKind {
self.kind
}
#[inline]
pub fn section_kind(&self) -> Option<SectionKind> {
self.section_kind
}
#[inline]
pub fn is_undefined(&self) -> bool {
self.section_kind.is_none()
}
#[inline]
pub fn is_global(&self) -> bool {
self.global
}
#[inline]
pub fn is_local(&self) -> bool {
!self.global
}
#[inline]
pub fn name(&self) -> Option<&'a str> {
self.name
}
#[inline]
pub fn address(&self) -> u64 {
self.address
}
#[inline]
pub fn size(&self) -> u64 {
self.size
}
}