#![cfg_attr(not(feature = "std"), no_std)]
extern crate plain;
#[cfg_attr(feature = "std", macro_use)]
extern crate scroll;
#[cfg_attr(feature = "std", macro_use)]
#[cfg(feature = "std")] extern crate log;
#[cfg(feature = "std")]
extern crate core;
#[cfg(feature = "std")]
pub mod error;
pub mod strtab;
macro_rules! if_std {
($($i:item)*) => ($(
#[cfg(feature = "std")]
$i
)*)
}
pub mod container {
use scroll;
pub use scroll::Endian as Endian;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Container {
Little,
Big,
}
impl Container {
pub fn is_big(&self) -> bool {
*self == Container::Big
}
}
#[cfg(not(target_pointer_width = "64"))]
pub const CONTAINER: Container = Container::Little;
#[cfg(target_pointer_width = "64")]
pub const CONTAINER: Container = Container::Big;
impl Default for Container {
#[inline]
fn default() -> Self {
CONTAINER
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Ctx {
pub container: Container,
pub le: scroll::Endian,
}
impl Ctx {
pub fn is_big(&self) -> bool {
self.container.is_big()
}
pub fn is_little_endian(&self) -> bool {
self.le.is_little()
}
pub fn new (container: Container, le: scroll::Endian) -> Self {
Ctx { container: container, le: le }
}
pub fn size(&self) -> usize {
match self.container {
Container::Little => 4,
Container::Big => 8,
}
}
}
impl From<Container> for Ctx {
fn from(container: Container) -> Self {
Ctx { container: container, le: scroll::Endian::default() }
}
}
impl From<scroll::Endian> for Ctx {
fn from(le: scroll::Endian) -> Self {
Ctx { container: CONTAINER, le: le }
}
}
impl Default for Ctx {
#[inline]
fn default() -> Self {
Ctx { container: Container::default(), le: scroll::Endian::default() }
}
}
}
if_std! {
#[derive(Debug, Default)]
pub struct HintData {
pub is_lsb: bool,
pub is_64: Option<bool>,
}
#[derive(Debug)]
pub enum Hint {
Elf(HintData),
Mach(HintData),
MachFat(usize),
PE,
Archive,
Unknown(u64),
}
#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
pub fn peek_bytes(bytes: &[u8; 16]) -> error::Result<Hint> {
use scroll::{Pread, BE};
if &bytes[0..elf::header::SELFMAG] == elf::header::ELFMAG {
let class = bytes[elf::header::EI_CLASS];
let is_lsb = bytes[elf::header::EI_DATA] == elf::header::ELFDATA2LSB;
let is_64 =
if class == elf::header::ELFCLASS64 {
Some (true)
} else if class == elf::header::ELFCLASS32 {
Some (false)
} else { None };
Ok(Hint::Elf(HintData { is_lsb: is_lsb, is_64: is_64 }))
} else if &bytes[0..archive::SIZEOF_MAGIC] == archive::MAGIC {
Ok(Hint::Archive)
} else if (&bytes[0..2]).pread::<u16>(0)? == pe::header::DOS_MAGIC {
Ok(Hint::PE)
} else {
use mach::{fat, header};
let magic = mach::peek(bytes, 0)?;
match magic {
fat::FAT_MAGIC => {
let narchitectures = bytes.pread_with::<u32>(4, BE)? as usize;
Ok(Hint::MachFat(narchitectures))
},
header::MH_CIGAM_64 | header::MH_CIGAM | header::MH_MAGIC_64 | header::MH_MAGIC => {
let is_lsb = magic == header::MH_CIGAM || magic == header::MH_CIGAM_64;
let is_64 = magic == header::MH_MAGIC_64 || magic == header::MH_CIGAM_64;
Ok(Hint::Mach(HintData { is_lsb: is_lsb, is_64: Some(is_64) }))
},
_ => Ok(Hint::Unknown(bytes.pread::<u64>(0)?))
}
}
}
#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
pub fn peek<R: ::std::io::Read + ::std::io::Seek>(fd: &mut R) -> error::Result<Hint> {
use std::io::SeekFrom;
let mut bytes = [0u8; 16];
fd.seek(SeekFrom::Start(0))?;
fd.read_exact(&mut bytes)?;
fd.seek(SeekFrom::Start(0))?;
peek_bytes(&bytes)
}
}
#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
#[derive(Debug)]
pub enum Object<'a> {
Elf(elf::Elf<'a>),
PE(pe::PE<'a>),
Mach(mach::Mach<'a>),
Archive(archive::Archive<'a>),
Unknown(u64),
}
#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
impl<'a> Object<'a> {
pub fn parse(bytes: &[u8]) -> error::Result<Object> {
use std::io::Cursor;
match peek(&mut Cursor::new(&bytes))? {
Hint::Elf(_) => Ok(Object::Elf(elf::Elf::parse(bytes)?)),
Hint::Mach(_) | Hint::MachFat(_) => Ok(Object::Mach(mach::Mach::parse(bytes)?)),
Hint::Archive => Ok(Object::Archive(archive::Archive::parse(bytes)?)),
Hint::PE => Ok(Object::PE(pe::PE::parse(bytes)?)),
Hint::Unknown(magic) => Ok(Object::Unknown(magic))
}
}
}
#[cfg(any(feature = "elf64", feature = "elf32"))]
#[macro_use]
pub mod elf;
#[cfg(feature = "elf32")]
pub mod elf32 {
pub use elf::header::header32 as header;
pub use elf::program_header::program_header32 as program_header;
pub use elf::section_header::section_header32 as section_header;
pub use elf::dyn::dyn32 as dyn;
pub use elf::sym::sym32 as sym;
pub use elf::reloc::reloc32 as reloc;
pub use elf::note::Nhdr32 as Note;
pub mod gnu_hash {
elf_gnu_hash_impl!(u32);
}
}
#[cfg(feature = "elf64")]
pub mod elf64 {
pub use elf::header::header64 as header;
pub use elf::program_header::program_header64 as program_header;
pub use elf::section_header::section_header64 as section_header;
pub use elf::dyn::dyn64 as dyn;
pub use elf::sym::sym64 as sym;
pub use elf::reloc::reloc64 as reloc;
pub use elf::note::Nhdr64 as Note;
pub mod gnu_hash {
elf_gnu_hash_impl!(u64);
}
}
#[cfg(all(feature = "mach32", feature = "mach64", feature = "endian_fd"))]
pub mod mach;
#[cfg(all(feature = "pe32", feature = "pe64", feature = "endian_fd"))]
pub mod pe;
#[cfg(all(feature = "archive", feature = "std"))]
pub mod archive;