include!("constants_header.rs");
pub trait ElfHeader {
fn e_ident(&self) -> [u8; SIZEOF_IDENT];
fn e_type(&self) -> u16;
fn e_machine(&self) -> u16;
fn e_version(&self) -> u32;
fn e_entry(&self) -> u64;
fn e_phoff(&self) -> u64;
fn e_shoff(&self) -> u64;
fn e_flags(&self) -> u32;
fn e_ehsize(&self) -> u16;
fn e_phentsize(&self) -> u16;
fn e_phnum(&self) -> u16;
fn e_shentsize(&self) -> u16;
fn e_shnum(&self) -> u16;
fn e_shstrndx(&self) -> u16;
}
macro_rules! elf_header {
($size:ident) => {
use core::fmt;
#[repr(C)]
#[derive(Clone, Copy, Default, PartialEq)]
pub struct Header {
pub e_ident: [u8; SIZEOF_IDENT],
pub e_type: u16,
pub e_machine: u16,
pub e_version: u32,
pub e_entry: $size,
pub e_phoff: $size,
pub e_shoff: $size,
pub e_flags: u32,
pub e_ehsize: u16,
pub e_phentsize: u16,
pub e_phnum: u16,
pub e_shentsize: u16,
pub e_shnum: u16,
pub e_shstrndx: u16,
}
impl Header {
pub fn from_bytes(bytes: &[u8; SIZEOF_EHDR]) -> &Header {
let header: &Header = unsafe { ::core::mem::transmute(bytes) };
header
}
}
impl fmt::Debug for Header {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"e_ident: {:?} e_type: {} e_machine: 0x{:x} e_version: 0x{:x} e_entry: 0x{:x} \
e_phoff: 0x{:x} e_shoff: 0x{:x} e_flags: {:x} e_ehsize: {} e_phentsize: {} \
e_phnum: {} e_shentsize: {} e_shnum: {} e_shstrndx: {}",
self.e_ident,
et_to_str(self.e_type),
self.e_machine,
self.e_version,
self.e_entry,
self.e_phoff,
self.e_shoff,
self.e_flags,
self.e_ehsize,
self.e_phentsize,
self.e_phnum,
self.e_shentsize,
self.e_shnum,
self.e_shstrndx)
}
}
}
}
pub const ET_NONE: u16 = 0;
pub const ET_REL: u16 = 1;
pub const ET_EXEC: u16 = 2;
pub const ET_DYN: u16 = 3;
pub const ET_CORE: u16 = 4;
pub const ET_NUM: u16 = 5;
pub const ELFMAG: &'static [u8; 4] = b"\x7FELF";
pub const SELFMAG: usize = 4;
pub const EI_CLASS: usize = 4;
pub const ELFCLASSNONE: u8 = 0;
pub const ELFCLASS32: u8 = 1;
pub const ELFCLASS64: u8 = 2;
pub const ELFCLASSNUM: u8 = 3;
pub const EI_DATA: usize = 5;
pub const ELFDATANONE: u8 = 0;
pub const ELFDATA2LSB: u8 = 1;
pub const ELFDATA2MSB: u8 = 2;
pub const SIZEOF_IDENT: usize = 16;
#[inline]
pub fn class_to_str(et: u8) -> &'static str {
match et {
ELFCLASSNONE => "NONE",
ELFCLASS32 => "ELF32",
ELFCLASS64 => "ELF64",
_ => "UNKNOWN_CLASS",
}
}
#[inline]
pub fn et_to_str(et: u16) -> &'static str {
match et {
ET_NONE => "NONE",
ET_REL => "REL",
ET_EXEC => "EXEC",
ET_DYN => "DYN",
ET_CORE => "CORE",
ET_NUM => "NUM",
_ => "UNKNOWN_ET",
}
}
#[cfg(feature = "std")]
pub use self::impure::*;
#[cfg(feature = "std")]
mod impure {
use super::*;
use scroll::{self, Pread};
use elf::error::*;
pub fn peek<S: scroll::Pread>(buffer: &S) -> Result<(u8, bool)> {
let ident: &[u8] = buffer.pread_slice(0, SIZEOF_IDENT)?;
if &ident[0..SELFMAG] != ELFMAG {
let magic: u64 = ident.pread_with(0, scroll::LE)?;
return Err(Error::BadMagic(magic).into());
}
let class = ident[EI_CLASS];
let is_lsb = ident[EI_DATA] == ELFDATA2LSB;
Ok((class, is_lsb))
}
}
macro_rules! elf_header_impure_impl {
($size:expr) => {
#[cfg(feature = "std")]
pub use self::impure::*;
#[cfg(feature = "std")]
mod impure {
use super::*;
use elf::error::*;
use elf::error;
use scroll::{self, ctx};
use std::fs::File;
use std::io::{Read};
use core::result;
impl ElfHeader for Header {
fn e_ident(&self) -> [u8; SIZEOF_IDENT] {
self.e_ident
}
fn e_type(&self) -> u16 {
self.e_type
}
fn e_machine(&self) -> u16 {
self.e_machine
}
fn e_version(&self) -> u32 {
self.e_version
}
fn e_entry(&self) -> u64 {
self.e_entry as u64
}
fn e_phoff(&self) -> u64 {
self.e_phoff as u64
}
fn e_shoff(&self) -> u64 {
self.e_shoff as u64
}
fn e_flags(&self) -> u32 {
self.e_flags
}
fn e_ehsize(&self) -> u16 {
self.e_ehsize
}
fn e_phentsize(&self) -> u16 {
self.e_phentsize
}
fn e_phnum(&self) -> u16 {
self.e_phnum
}
fn e_shentsize(&self) -> u16 {
self.e_shentsize
}
fn e_shnum(&self) -> u16 {
self.e_shnum
}
fn e_shstrndx(&self) -> u16 {
self.e_shstrndx
}
}
impl<'a> ctx::TryFromCtx<'a> for Header {
type Error = error::Error;
fn try_from_ctx(buffer: &'a [u8], (mut offset, _): (usize, scroll::Endian)) -> result::Result<Self, Self::Error> {
use scroll::Gread;
let mut elf_header = Header::default();
let mut offset = &mut offset;
buffer.gread_inout(offset, &mut elf_header.e_ident)?;
let endianness =
match elf_header.e_ident[EI_DATA] {
ELFDATA2LSB => scroll::LE,
ELFDATA2MSB => scroll::BE,
d => return Err(Error::Malformed(format!("invalid ELF endianness DATA type {:x}", d)).into()),
};
elf_header.e_type = buffer.gread_with(offset, endianness)?;
elf_header.e_machine = buffer.gread_with(offset, endianness)?;
elf_header.e_version = buffer.gread_with(offset, endianness)?;
elf_header.e_entry = buffer.gread_with(offset, endianness)?;
elf_header.e_phoff = buffer.gread_with(offset, endianness)?;
elf_header.e_shoff = buffer.gread_with(offset, endianness)?;
elf_header.e_flags = buffer.gread_with(offset, endianness)?;
elf_header.e_ehsize = buffer.gread_with(offset, endianness)?;
elf_header.e_phentsize = buffer.gread_with(offset, endianness)?;
elf_header.e_phnum = buffer.gread_with(offset, endianness)?;
elf_header.e_shentsize = buffer.gread_with(offset, endianness)?;
elf_header.e_shnum = buffer.gread_with(offset, endianness)?;
elf_header.e_shstrndx = buffer.gread_with(offset, endianness)?;
Ok(elf_header)
}
}
impl ctx::TryIntoCtx for Header {
type Error = scroll::Error;
fn try_into_ctx(self, mut bytes: &mut [u8], (mut offset, _endianness): (usize, scroll::Endian)) -> result::Result<(), Self::Error> {
use scroll::{Gwrite};
let mut offset = &mut offset;
let endianness =
match self.e_ident[EI_DATA] {
ELFDATA2LSB => scroll::LE,
ELFDATA2MSB => scroll::BE,
d => return Err(scroll::Error::BadInput(format!("invalid ELF endianness DATA type {:x}", d)).into()),
};
for i in 0..self.e_ident.len() {
bytes.gwrite(self.e_ident[i], offset)?;
}
bytes.gwrite_with(self.e_type , offset, endianness)?;
bytes.gwrite_with(self.e_machine , offset, endianness)?;
bytes.gwrite_with(self.e_version , offset, endianness)?;
bytes.gwrite_with(self.e_entry , offset, endianness)?;
bytes.gwrite_with(self.e_phoff , offset, endianness)?;
bytes.gwrite_with(self.e_shoff , offset, endianness)?;
bytes.gwrite_with(self.e_flags , offset, endianness)?;
bytes.gwrite_with(self.e_ehsize , offset, endianness)?;
bytes.gwrite_with(self.e_phentsize , offset, endianness)?;
bytes.gwrite_with(self.e_phnum , offset, endianness)?;
bytes.gwrite_with(self.e_shentsize , offset, endianness)?;
bytes.gwrite_with(self.e_shnum , offset, endianness)?;
bytes.gwrite_with(self.e_shstrndx , offset, endianness)
}
}
impl Header {
pub fn from_fd(buffer: &mut File) -> Result<Header> {
let mut elf_header = [0; $size];
buffer.read(&mut elf_header)?;
Ok(*Header::from_bytes(&elf_header))
}
#[cfg(feature = "endian_fd")]
pub fn parse<S: scroll::Gread>(buffer: &S) -> Result<Header> {
let mut elf_header = Header::default();
let mut offset = &mut 0;
for i in 0..SIZEOF_IDENT {
elf_header.e_ident[i] = buffer.gread(&mut offset)?;
}
let endianness =
match elf_header.e_ident[EI_DATA] {
ELFDATA2LSB => scroll::LE,
ELFDATA2MSB => scroll::BE,
d => return Err(Error::Malformed(format!("invalid ELF DATA type {:x}", d)).into()),
};
elf_header.e_type = buffer.gread_with(offset, endianness)?;
elf_header.e_machine = buffer.gread_with(offset, endianness)?;
elf_header.e_version = buffer.gread_with(offset, endianness)?;
elf_header.e_entry = buffer.gread_with(offset, endianness)?;
elf_header.e_phoff = buffer.gread_with(offset, endianness)?;
elf_header.e_shoff = buffer.gread_with(offset, endianness)?;
elf_header.e_flags = buffer.gread_with(offset, endianness)?;
elf_header.e_ehsize = buffer.gread_with(offset, endianness)?;
elf_header.e_phentsize = buffer.gread_with(offset, endianness)?;
elf_header.e_phnum = buffer.gread_with(offset, endianness)?;
elf_header.e_shentsize = buffer.gread_with(offset, endianness)?;
elf_header.e_shnum = buffer.gread_with(offset, endianness)?;
elf_header.e_shstrndx = buffer.gread_with(offset, endianness)?;
Ok(elf_header)
}
}
}
};
}
macro_rules! elf_header_test {
($class:expr) => {
#[cfg(test)]
mod test {
extern crate scroll;
use scroll::{Pwrite, Pread};
use super::*;
use scroll::Buffer;
#[test]
fn test_peek () {
let v = vec![0x7f, 0x45, 0x4c, 0x46, $class, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x70, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8c];
let header = Buffer::new(v);
match peek(&header) {
Err(_) => assert!(false),
Ok((class, is_lsb)) => {
assert_eq!(true, is_lsb);
assert_eq!(class, $class)
}
}
}
#[test]
fn header_read_write () {
let crt1: Vec<u8> =
if $class == ELFCLASS64 {
include!("../../../etc/crt1.rs")
} else {
include!("../../../etc/crt132.rs")
};
let header: Header = crt1.pread(0).unwrap();
assert_eq!(header.e_type, ET_REL);
println!("header: {:?}", &header);
let mut bytes = [0u8; SIZEOF_EHDR];
bytes.pwrite(header, 0).unwrap();
let header2: Header = bytes.pread(0).unwrap();
assert_eq!(header, header2);
}
}
}
}