use format::bindings::*;
use std::{
mem,
convert::{
TryFrom,
TryInto,
},
};
use nom::{IResult, IResult::*, Needed::{Size, Unknown}, *};
use failure::Error;
use error::RustepErrorKind;
use format::executable::Executable;
use num::FromPrimitive;
use enumflags::BitFlags;
#[derive(FromPrimitive, ToPrimitive, Eq, PartialEq, Clone, Copy, Debug)]
pub enum ElfType {
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
ET_CORE = 4,
ET_NUM = 5,
ET_LOOS = 65024,
ET_HIOS = 65279,
ET_LOPROC = 65280,
ET_HIPROC = 65535,
}
#[derive(FromPrimitive, ToPrimitive, Eq, PartialEq)]
pub enum SegmentType {
PT_NULL = 0,
PT_LOAD = 1,
PT_DYNAMIC = 2,
PT_INTERP = 3,
PT_NOTE = 4,
PT_SHLIB = 5,
PT_PHDR = 6,
PT_TLS = 7,
PT_NUM = 8,
PT_LOOS = 1610612736,
PT_GNU_EH_FRAME = 1685382480,
PT_GNU_STACK = 1685382481,
PT_GNU_RELRO = 1685382482,
PT_LOSUNW = 1879048186,
PT_SUNWSTACK = 1879048187,
PT_HISUNW = 1879048191,
PT_LOPROC = 1879048192,
PT_HIPROC = 2147483647,
}
#[derive(EnumFlags, Copy, Clone, Debug)]
#[repr(u64)]
pub enum SegmentFlag {
PF_X = 1,
PF_W = 2,
PF_R = 4,
PF_MASKOS = 267386880,
PF_MASKPROC = 4026531840,
}
#[derive(FromPrimitive, ToPrimitive, Eq, PartialEq)]
pub enum SectionType {
SHT_NULL = 0,
SHT_PROGBITS = 1,
SHT_SYMTAB = 2,
SHT_STRTAB = 3,
SHT_RELA = 4,
SHT_HASH = 5,
SHT_DYNAMIC = 6,
SHT_NOTE = 7,
SHT_NOBITS = 8,
SHT_REL = 9,
SHT_SHLIB = 10,
SHT_DYNSYM = 11,
SHT_INIT_ARRAY = 14,
SHT_FINI_ARRAY = 15,
SHT_PREINIT_ARRAY = 16,
SHT_GROUP = 17,
SHT_SYMTAB_SHNDX = 18,
SHT_NUM = 19,
SHT_LOOS = 1610612736,
SHT_GNU_ATTRIBUTES = 1879048181,
SHT_GNU_HASH = 1879048182,
SHT_GNU_LIBLIST = 1879048183,
SHT_CHECKSUM = 1879048184,
SHT_LOSUNW = 1879048186,
SHT_SUNW_COMDAT = 1879048187,
SHT_SUNW_syminfo = 1879048188,
SHT_GNU_verdef = 1879048189,
SHT_GNU_verneed = 1879048190,
SHT_GNU_versym = 1879048191,
SHT_LOPROC = 1879048192,
SHT_HIPROC = 2147483647,
SHT_LOUSER = 2147483648,
SHT_HIUSER = 2415919103,
}
#[derive(EnumFlags, Copy, Clone, Debug)]
#[repr(u64)]
pub enum SectionFlag {
SHF_WRITE = 1,
SHF_ALLOC = 2,
SHF_EXECINSTR = 4,
SHF_MERGE = 16,
SHF_STRINGS = 32,
SHF_INFO_LINK = 64,
SHF_LINK_ORDER = 128,
SHF_OS_NONCONFORMING = 256,
SHF_GROUP = 512,
SHF_TLS = 1024,
SHF_COMPRESSED = 2048,
SHF_MASKOS = 267386880,
}
pub trait ElfSectionHeader {
fn address(&self) -> u64;
fn offset(&self) -> u64;
fn size(&self) -> u64;
fn entry_size(&self) -> u64;
}
impl ElfSectionHeader for Elf32_Shdr {
fn address(&self) -> u64 {
self.sh_addr as u64
}
fn offset(&self) -> u64 {
self.sh_offset as u64
}
fn size(&self) -> u64 {
self.sh_size as u64
}
fn entry_size(&self) -> u64 {
self.sh_entsize as u64
}
}
impl ElfSectionHeader for Elf64_Shdr {
fn address(&self) -> u64 {
self.sh_addr
}
fn offset(&self) -> u64 {
self.sh_offset
}
fn size(&self) -> u64 {
self.sh_size
}
fn entry_size(&self) -> u64 {
self.sh_entsize
}
}
pub trait ElfSection {
fn shdr(&self) -> &ElfSectionHeader;
fn name(&self) -> &str;
fn section_type(&self) -> &SectionType;
fn flags(&self) -> BitFlags<SectionFlag>;
fn data(&self) -> &[u8];
}
pub struct ElfSection32<'a> {
shdr: Elf32_Shdr,
section_type: SectionType,
flags: BitFlags<SectionFlag>,
name: String,
data: &'a [u8],
}
pub struct ElfSection64<'a> {
shdr: Elf64_Shdr,
section_type: SectionType,
flags: BitFlags<SectionFlag>,
name: String,
data: &'a [u8],
}
impl<'a> ElfSection for ElfSection32<'a> {
fn shdr(&self) -> &ElfSectionHeader {
&self.shdr
}
fn name(&self) -> &str {
&self.name
}
fn section_type(&self) -> &SectionType {
&self.section_type
}
fn flags(&self) -> BitFlags<SectionFlag> {
self.flags
}
fn data(&self) -> &[u8] {
self.data
}
}
impl<'a> ElfSection for ElfSection64<'a> {
fn shdr(&self) -> &ElfSectionHeader {
&self.shdr
}
fn name(&self) -> &str {
&self.name
}
fn section_type(&self) -> &SectionType {
&self.section_type
}
fn flags(&self) -> BitFlags<SectionFlag> {
self.flags
}
fn data(&self) -> &[u8] {
self.data
}
}
pub trait ElfSegmentHeader {
fn offset(&self) -> u64;
fn vaddr(&self) -> u64;
fn paddr(&self) -> u64;
fn file_size(&self) -> u64;
fn mem_size(&self) -> u64;
}
impl ElfSegmentHeader for Elf32_Phdr {
fn offset(&self) -> u64 {
self.p_offset as u64
}
fn vaddr(&self) -> u64 {
self.p_vaddr as u64
}
fn paddr(&self) -> u64 {
self.p_paddr as u64
}
fn file_size(&self) -> u64 {
self.p_filesz as u64
}
fn mem_size(&self) -> u64 {
self.p_memsz as u64
}
}
impl ElfSegmentHeader for Elf64_Phdr {
fn offset(&self) -> u64 {
self.p_offset
}
fn vaddr(&self) -> u64 {
self.p_vaddr
}
fn paddr(&self) -> u64 {
self.p_paddr
}
fn file_size(&self) -> u64 {
self.p_filesz
}
fn mem_size(&self) -> u64 {
self.p_memsz
}
}
pub trait ElfSegment {
fn phdr(&self) -> &ElfSegmentHeader;
fn segment_type(&self) -> &SegmentType;
fn flags(&self) -> BitFlags<SegmentFlag>;
fn data(&self) -> &[u8];
}
pub struct ElfSegment32<'a> {
phdr: Elf32_Phdr,
segment_type: SegmentType,
flags: BitFlags<SegmentFlag>,
data: &'a [u8],
}
pub struct ElfSegment64<'a> {
phdr: Elf64_Phdr,
segment_type: SegmentType,
flags: BitFlags<SegmentFlag>,
data: &'a [u8],
}
impl<'a> ElfSegment for ElfSegment32<'a> {
fn phdr(&self) -> &ElfSegmentHeader {
&self.phdr
}
fn segment_type(&self) -> &SegmentType {
&self.segment_type
}
fn flags(&self) -> BitFlags<SegmentFlag> {
self.flags
}
fn data(&self) -> &[u8] {
self.data
}
}
impl<'a> ElfSegment for ElfSegment64<'a> {
fn phdr(&self) -> &ElfSegmentHeader {
&self.phdr
}
fn segment_type(&self) -> &SegmentType {
&self.segment_type
}
fn flags(&self) -> BitFlags<SegmentFlag> {
self.flags
}
fn data(&self) -> &[u8] {
self.data
}
}
#[derive(FromPrimitive, ToPrimitive, Eq, PartialEq)]
#[repr(u64)]
pub enum ElfMachine {
NONE = 0,
M32 = 1,
SPARC = 2,
I386 = 3,
M68K = 4,
M88K = 5,
I860 = 7,
MIPS = 8,
S370 = 9,
MIPS_RS3_LE = 10,
PARISC = 15,
VPP500 = 17,
SPARC32PLUS = 18,
I960 = 19,
PPC = 20,
PPC64 = 21,
S390 = 22,
V800 = 36,
FR20 = 37,
RH32 = 38,
RCE = 39,
ARM = 40,
ALPHA = 41,
SH = 42,
SPARCV9 = 43,
TRICORE = 44,
ARC = 45,
H8_300 = 46,
H8_300H = 47,
H8S = 48,
H8_500 = 49,
IA_64 = 50,
MIPS_X = 51,
COLDFIRE = 52,
M68HC12 = 53,
MMA = 54,
PCP = 55,
NCPU = 56,
NDR1 = 57,
STARCORE = 58,
ME16 = 59,
ST100 = 60,
TINYJ = 61,
X86_64 = 62,
PDSP = 63,
PDP10 = 64,
PDP11 = 65,
FX66 = 66,
ST9PLUS = 67,
ST7 = 68,
M68HC16 = 69,
M68HC11 = 70,
M68HC08 = 71,
M68HC05 = 72,
SVX = 73,
ST19 = 74,
VAX = 75,
CRIS = 76,
JAVELIN = 77,
FIREPATH = 78,
ZSP = 79,
MMIX = 80,
HUANY = 81,
PRISM = 82,
AVR = 83,
FR30 = 84,
D10V = 85,
D30V = 86,
V850 = 87,
M32R = 88,
MN10300 = 89,
MN10200 = 90,
PJ = 91,
OPENRISC = 92,
ARC_A5 = 93,
XTENSA = 94,
VIDEOCORE = 95,
TMM_GPP = 96,
NS32K = 97,
TPC = 98,
SNP1K = 99,
ST200 = 100,
IP2K = 101,
MAX = 102,
CR = 103,
F2MC16 = 104,
MSP430 = 105,
BLACKFIN = 106,
SE_C33 = 107,
SEP = 108,
ARCA = 109,
UNICORE = 110,
}
pub trait ElfHeader {
fn elf_type(&self) -> Result<ElfType, Error>;
fn machine(&self) -> Result<ElfMachine, Error>;
fn entry(&self) -> u64;
fn phoff(&self) -> u64;
fn shoff(&self) -> u64;
fn ehsize(&self) -> u64;
fn phentsize(&self) -> u64;
fn phnum(&self) -> u64;
fn shentsize(&self) -> u64;
fn shnum(&self) -> u64;
fn shstrndx(&self) -> u64;
}
impl ElfHeader for Elf32_Ehdr {
fn elf_type(&self) -> Result<ElfType, Error> {
Ok(FromPrimitive::from_u16(self.e_type)
.ok_or(RustepErrorKind::ElfType(self.e_type as u64))?)
}
fn machine(&self) -> Result<ElfMachine, Error> {
Ok(FromPrimitive::from_u16(self.e_machine)
.ok_or(RustepErrorKind::ElfMachine(self.e_machine as u64))?)
}
fn entry(&self) -> u64 {
self.e_entry as u64
}
fn phoff(&self) -> u64 {
self.e_phoff as u64
}
fn shoff(&self) -> u64 {
self.e_shoff as u64
}
fn ehsize(&self) -> u64 {
self.e_ehsize as u64
}
fn phentsize(&self) -> u64 {
self.e_phentsize as u64
}
fn phnum(&self) -> u64 {
self.e_phnum as u64
}
fn shentsize(&self) -> u64 {
self.e_shentsize as u64
}
fn shnum(&self) -> u64 {
self.e_shnum as u64
}
fn shstrndx(&self) -> u64 {
self.e_shstrndx as u64
}
}
impl ElfHeader for Elf64_Ehdr {
fn elf_type(&self) -> Result<ElfType, Error> {
Ok(FromPrimitive::from_u16(self.e_type)
.ok_or(RustepErrorKind::ElfType(self.e_type as u64))?)
}
fn machine(&self) -> Result<ElfMachine, Error> {
Ok(FromPrimitive::from_u16(self.e_machine)
.ok_or(RustepErrorKind::ElfMachine(self.e_machine as u64))?)
}
fn entry(&self) -> u64 {
self.e_entry as u64
}
fn phoff(&self) -> u64 {
self.e_phoff as u64
}
fn shoff(&self) -> u64 {
self.e_shoff as u64
}
fn ehsize(&self) -> u64 {
self.e_ehsize as u64
}
fn phentsize(&self) -> u64 {
self.e_phentsize as u64
}
fn phnum(&self) -> u64 {
self.e_phnum as u64
}
fn shentsize(&self) -> u64 {
self.e_shentsize as u64
}
fn shnum(&self) -> u64 {
self.e_shnum as u64
}
fn shstrndx(&self) -> u64 {
self.e_shstrndx as u64
}
}
pub trait ElfFormat {
fn header(&self) -> &ElfHeader;
fn segments(&self) -> Vec<&ElfSegment>;
fn sections(&self) -> Vec<&ElfSection>;
fn section(&self, name: &str) -> Option<&ElfSection> {
for sec in self.sections().iter() {
if sec.name() == name {
return Some(*sec)
}
}
None
}
}
pub struct Elf32<'a> {
header: Elf32_Ehdr,
elf_type: ElfType,
segments: Vec<ElfSegment32<'a>>,
sections: Vec<ElfSection32<'a>>,
}
pub struct Elf64<'a> {
header: Elf64_Ehdr,
elf_type: ElfType,
segments: Vec<ElfSegment64<'a>>,
sections: Vec<ElfSection64<'a>>,
}
impl<'a> ElfFormat for Elf32<'a> {
fn header(&self) -> &ElfHeader {
&self.header
}
fn segments(&self) -> Vec<&ElfSegment> {
let mut v = Vec::new();
for elem in self.segments.iter() {
v.push(elem as &ElfSegment);
}
v
}
fn sections(&self) -> Vec<&ElfSection> {
let mut v = Vec::new();
for elem in self.sections.iter() {
v.push(elem as &ElfSection);
}
v
}
}
impl<'a> ElfFormat for Elf64<'a> {
fn header(&self) -> &ElfHeader {
&self.header
}
fn segments(&self) -> Vec<&ElfSegment> {
let mut v = Vec::new();
for elem in self.segments.iter() {
v.push(elem as &ElfSegment);
}
v
}
fn sections(&self) -> Vec<&ElfSection> {
let mut v = Vec::new();
for elem in self.sections.iter() {
v.push(elem as &ElfSection);
}
v
}
}
impl<'a> TryFrom<&'a Executable<'a>> for &'a ElfFormat {
type Error=Error;
fn try_from(value: &'a Executable) -> Result<&'a ElfFormat, Error> {
match *value {
Executable::Elf32(ref elf) => Ok(elf as &ElfFormat),
Executable::Elf64(ref elf) => Ok(elf as &ElfFormat),
_ => Err(RustepErrorKind::NotElf)?,
}
}
}
pub fn parse_elf(input: &[u8]) -> Result<Executable, Error> {
let elf_class = nom_try!(parse_elf_class(input)) as u32;
match elf_class {
ELFCLASS32 => parse_elf32(input),
ELFCLASS64 => parse_elf64(input),
val => Err(RustepErrorKind::UnsupportedElfClass(val as u8))?,
}
}
macro_rules! define_elf_parser {
{
$func_name: ident,
$header_parser: ident,
$section_parser: ident,
$segment_parser: ident,
$section: ident,
$segment: ident,
$result: ident
} => {
pub fn $func_name(input: &[u8]) -> Result<Executable, Error> {
let hdr = nom_try!($header_parser(input));
let mut segments = Vec::new();
let mut sections = Vec::new();
let program_headers = nom_try!(preceded!(
input,
take!(hdr.e_phoff),
count!(call!($segment_parser), hdr.e_phnum as usize)
));
for p in program_headers.iter() {
let data = &input[(p.p_offset as usize)..(p.p_offset + p.p_filesz) as usize];
let segment_type = FromPrimitive::from_u32(p.p_type)
.ok_or(RustepErrorKind::SegmentType(p.p_type as u64))?;
let flags = BitFlags::from_bits(p.p_flags as u64)
.ok_or(RustepErrorKind::SegmentFlag(p.p_flags as u64))?;
let segment = $segment {
phdr: *p,
segment_type: segment_type,
flags: flags,
data: data
};
segments.push(segment);
}
let section_headers = nom_try!(preceded!(
input,
take!(hdr.e_shoff),
count!(call!($section_parser), hdr.e_shnum as usize)
));
for s in section_headers.iter() {
let data = &input[(s.sh_offset as usize) .. (s.sh_offset + s.sh_size) as usize];
let section_type = FromPrimitive::from_u32(s.sh_type)
.ok_or(RustepErrorKind::SectionType(s.sh_type as u64))?;
let flags = BitFlags::from_bits(s.sh_flags as u64)
.ok_or(RustepErrorKind::SectionFlag(s.sh_flags as u64))?;
let name = String::new();
let section = $section {
name: name,
shdr: *s,
section_type: section_type,
flags: flags,
data: data
};
sections.push(section);
}
let strtab_data = sections
.get(hdr.e_shstrndx as usize)
.map(|s| s.data);
if let Some(data) = strtab_data {
for s in sections.iter_mut() {
let name_bytes = nom_try!(take_until!(&data[s.shdr.sh_name as usize..], b"\x00" as &[u8]));
let mut new_name = String::from_utf8(name_bytes.to_vec())?;
mem::replace(&mut s.name, new_name);
}
}
let struct_ins = $result {
header: hdr,
elf_type: FromPrimitive::from_u16(hdr.e_type)
.ok_or(RustepErrorKind::ElfType(hdr.e_type as u64))?,
sections: sections,
segments: segments,
};
Ok(Executable::$result(struct_ins))
}
}
}
define_elf_parser!{
parse_elf32,
parse_elf_header32,
parse_elf_section_header32,
parse_elf_prog_header32,
ElfSection32,
ElfSegment32,
Elf32
}
define_elf_parser!{
parse_elf64,
parse_elf_header64,
parse_elf_section_header64,
parse_elf_prog_header64,
ElfSection64,
ElfSegment64,
Elf64
}
#[test]
fn test_parse_elf32() {
use std::{fs::File, io::prelude::*};
let mut file = File::open("test/test32").unwrap();
let mut buf = Vec::new();
file.read_to_end(&mut buf).unwrap();
let result = parse_elf32(&buf).unwrap();
{
let res: &ElfFormat = (&result).try_into().expect("unable to convert");
assert_eq!(res.header().elf_type().unwrap(), ElfType::ET_DYN);
}
match result {
Executable::Elf32(res) => {
let section = res.sections[1].shdr;
assert_eq!(section.sh_name, 0x1b);
assert_eq!(section.sh_type, 1);
assert_eq!(section.sh_flags, 2);
assert_eq!(section.sh_addr, 0x154);
assert_eq!(section.sh_offset, 0x154);
assert_eq!(section.sh_size, 19);
assert_eq!(section.sh_link, 0);
assert_eq!(section.sh_info, 0);
assert_eq!(section.sh_addralign, 1);
assert_eq!(section.sh_entsize, 0);
let segment = res.segments[0].phdr;
assert_eq!(segment.p_type, 6);
assert_eq!(segment.p_offset, 0x34);
assert_eq!(segment.p_vaddr, 0x34);
assert_eq!(segment.p_paddr, 0x34);
assert_eq!(segment.p_filesz, 288);
assert_eq!(segment.p_memsz, 288);
assert_eq!(segment.p_flags, 5);
assert_eq!(segment.p_align, 4);
},
_ => panic!("Wrong file format detection"),
};
}
#[test]
fn test_parse_elf() {
use std::{fs::File, io::prelude::*};
let mut file = File::open("test/test").unwrap();
let mut buf = Vec::new();
file.read_to_end(&mut buf).unwrap();
let result = parse_elf(&buf).unwrap();
{
let res: &ElfFormat = (&result).try_into().expect("unable to convert");
assert_eq!(res.header().elf_type().unwrap(), ElfType::ET_DYN);
}
match result {
Executable::Elf64(res) => {
let section = res.sections[1].shdr;
assert_eq!(section.sh_name, 0x1b);
assert_eq!(section.sh_type, 1);
assert_eq!(section.sh_flags, 2);
assert_eq!(section.sh_addr, 0x238);
assert_eq!(section.sh_offset, 0x238);
assert_eq!(section.sh_size, 28);
assert_eq!(section.sh_link, 0);
assert_eq!(section.sh_info, 0);
assert_eq!(section.sh_addralign, 1);
assert_eq!(section.sh_entsize, 0);
let segment = res.segments[0].phdr;
assert_eq!(segment.p_type, 6);
assert_eq!(segment.p_offset, 0x40);
assert_eq!(segment.p_vaddr, 0x40);
assert_eq!(segment.p_paddr, 0x40);
assert_eq!(segment.p_filesz, 504);
assert_eq!(segment.p_memsz, 504);
assert_eq!(segment.p_flags, 5);
assert_eq!(segment.p_align, 8);
assert_eq!(res.elf_type, ElfType::ET_DYN);
},
_ => panic!("Wrong file format detection"),
};
let mut file = File::open("test/test32").unwrap();
let mut buf = Vec::new();
file.read_to_end(&mut buf).unwrap();
let result = parse_elf(&buf).unwrap();
match result {
Executable::Elf32(res) => {
let section = res.sections[1].shdr;
assert_eq!(section.sh_name, 0x1b);
assert_eq!(section.sh_type, 1);
assert_eq!(section.sh_flags, 2);
assert_eq!(section.sh_addr, 0x154);
assert_eq!(section.sh_offset, 0x154);
assert_eq!(section.sh_size, 19);
assert_eq!(section.sh_link, 0);
assert_eq!(section.sh_info, 0);
assert_eq!(section.sh_addralign, 1);
assert_eq!(section.sh_entsize, 0);
let segment = res.segments[0].phdr;
assert_eq!(segment.p_type, 6);
assert_eq!(segment.p_offset, 0x34);
assert_eq!(segment.p_vaddr, 0x34);
assert_eq!(segment.p_paddr, 0x34);
assert_eq!(segment.p_filesz, 288);
assert_eq!(segment.p_memsz, 288);
assert_eq!(segment.p_flags, 5);
assert_eq!(segment.p_align, 4);
assert_eq!(res.elf_type, ElfType::ET_DYN);
},
_ => panic!("Wrong file format detection"),
};
}
#[test]
fn test_parse_elf64() {
use std::{fs::File, io::prelude::*};
let mut file = File::open("test/test").unwrap();
let mut buf = Vec::new();
file.read_to_end(&mut buf).unwrap();
let result = parse_elf64(&buf).unwrap();
{
let res: &ElfFormat = (&result).try_into().expect("unable to convert");
assert_eq!(res.header().elf_type().unwrap(), ElfType::ET_DYN);
}
match result {
Executable::Elf64(res) => {
let section = res.sections[1].shdr;
assert_eq!(section.sh_name, 0x1b);
assert_eq!(section.sh_type, 1);
assert_eq!(section.sh_flags, 2);
assert_eq!(section.sh_addr, 0x238);
assert_eq!(section.sh_offset, 0x238);
assert_eq!(section.sh_size, 28);
assert_eq!(section.sh_link, 0);
assert_eq!(section.sh_info, 0);
assert_eq!(section.sh_addralign, 1);
assert_eq!(section.sh_entsize, 0);
let segment = res.segments[0].phdr;
assert_eq!(segment.p_type, 6);
assert_eq!(segment.p_offset, 0x40);
assert_eq!(segment.p_vaddr, 0x40);
assert_eq!(segment.p_paddr, 0x40);
assert_eq!(segment.p_filesz, 504);
assert_eq!(segment.p_memsz, 504);
assert_eq!(segment.p_flags, 5);
assert_eq!(segment.p_align, 8);
},
_ => panic!("Wrong file format detection"),
}
}
#[test]
fn test_parse_elf_wrong_class() {
match parse_elf(b"\x7fELF\x05") {
Err(e) => assert_eq!(
*e.downcast_ref::<RustepErrorKind>().unwrap(),
RustepErrorKind::UnsupportedElfClass(5)
),
_ => panic!("parse elf with class 5 succeed, which cannot happen"),
}
}
named!(parse_elf_class<&[u8], u8>,
do_parse!(
tag!("\x7fELF") >> data: le_u8 >>
(data)
)
);
#[test]
fn test_parse_elf_class() {
assert_eq!(parse_elf_class(b"\x7fELF\x01"), Done(b"" as &[u8], 1));
assert_eq!(parse_elf_class(b"\x7fELF\x02"), Done(b"" as &[u8], 2));
use nom::ErrorKind;
assert_eq!(
parse_elf_class(b"FLE\x01"),
Error(error_position!(ErrorKind::Tag, b"FLE\x01" as &[u8]))
);
}
fn parse_e_ident(input: &[u8]) -> IResult<&[u8], [u8; 16]> {
let res = take!(input, 16);
let mut v = [0; 16];
if let Done(_i, val) = res {
v.clone_from_slice(val);
Done(_i, v)
} else if let Error(e) = res {
Error(e)
} else if let Incomplete(need) = res {
Incomplete(need)
} else {
unreachable!()
}
}
named!(parse_elf_header32<&[u8], Elf32_Ehdr>,
do_parse!(
e_ident: parse_e_ident >>
e_type: le_u16 >>
e_machine: le_u16 >>
e_version: le_u32 >>
e_entry: le_u32 >>
e_phoff: le_u32 >>
e_shoff: le_u32 >>
e_flags: le_u32 >>
e_ehsize: le_u16 >>
e_phentsize: le_u16 >>
e_phnum: le_u16 >>
e_shentsize: le_u16 >>
e_shnum: le_u16 >>
e_shstrndx: le_u16 >>
(Elf32_Ehdr {
e_ident: e_ident,
e_type: e_type,
e_machine: e_machine,
e_version: e_version,
e_entry: e_entry,
e_phoff: e_phoff,
e_shoff: e_shoff,
e_flags: e_flags,
e_ehsize: e_ehsize,
e_phentsize: e_phentsize,
e_phnum: e_phnum,
e_shentsize: e_shentsize,
e_shnum: e_shnum,
e_shstrndx: e_shstrndx
})
)
);
#[test]
fn test_parse_elf_header32() {
use std::{fs::File, io::prelude::*};
let file = File::open("test/test32").unwrap();
let mut buf = [0; 0x34];
let mut handle = file.take(0x34);
handle.read(&mut buf).unwrap();
let res = parse_elf_header32(&buf);
if let Done(_, hdr) = res {
assert_eq!(hdr.e_ident[0], 0x7fu8);
assert_eq!(hdr.e_ident[1], 0x45u8);
assert_eq!(hdr.e_ident[2], 0x4cu8);
assert_eq!(hdr.e_ident[3], 0x46u8);
assert_eq!(hdr.e_type, 3);
assert_eq!(hdr.e_machine, 3);
assert_eq!(hdr.e_version, 1);
assert_eq!(hdr.e_entry, 0x3e0);
assert_eq!(hdr.e_phoff, 52);
assert_eq!(hdr.e_shoff, 7372);
assert_eq!(hdr.e_flags, 0);
assert_eq!(hdr.e_ehsize, 52);
assert_eq!(hdr.e_phentsize, 32);
assert_eq!(hdr.e_phnum, 9);
assert_eq!(hdr.e_shentsize, 40);
assert_eq!(hdr.e_shnum, 31);
assert_eq!(hdr.e_shstrndx, 30);
} else if let Error(err) = res {
panic!(err.to_string());
} else if let Incomplete(need) = res {
match need {
Size(size) => panic!("Incomplete, needs size {}", size),
Unknown => panic!("Incomplete, needs size unknown"),
}
} else {
unreachable!();
}
}
named!(parse_elf_header64<&[u8], Elf64_Ehdr>,
do_parse!(
e_ident: parse_e_ident >>
e_type: le_u16 >>
e_machine: le_u16 >>
e_version: le_u32 >>
e_entry: le_u64 >>
e_phoff: le_u64 >>
e_shoff: le_u64 >>
e_flags: le_u32 >>
e_ehsize: le_u16 >>
e_phentsize: le_u16 >>
e_phnum: le_u16 >>
e_shentsize: le_u16 >>
e_shnum: le_u16 >>
e_shstrndx: le_u16 >>
(Elf64_Ehdr {
e_ident: e_ident,
e_type: e_type,
e_machine: e_machine,
e_version: e_version,
e_entry: e_entry,
e_phoff: e_phoff,
e_shoff: e_shoff,
e_flags: e_flags,
e_ehsize: e_ehsize,
e_phentsize: e_phentsize,
e_phnum: e_phnum,
e_shentsize: e_shentsize,
e_shnum: e_shnum,
e_shstrndx: e_shstrndx
})
)
);
#[test]
fn test_parse_elf_header64() {
use std::{fs::File, io::prelude::*};
let file = File::open("test/test").unwrap();
let mut buf = [0; 0x40];
let mut handle = file.take(0x40);
handle.read(&mut buf).unwrap();
let res = parse_elf_header64(&buf);
if let Done(_i, hdr) = res {
assert_eq!(hdr.e_ident[0], 0x7f);
assert_eq!(hdr.e_ident[1], 0x45);
assert_eq!(hdr.e_ident[2], 0x4c);
assert_eq!(hdr.e_ident[3], 0x46);
assert_eq!(hdr.e_type, 3);
assert_eq!(hdr.e_machine, 62);
assert_eq!(hdr.e_version, 1);
assert_eq!(hdr.e_entry, 0x540);
assert_eq!(hdr.e_phoff, 64);
assert_eq!(hdr.e_shoff, 7744);
assert_eq!(hdr.e_flags, 0);
assert_eq!(hdr.e_ehsize, 64);
assert_eq!(hdr.e_phentsize, 56);
assert_eq!(hdr.e_phnum, 9);
assert_eq!(hdr.e_shentsize, 64);
assert_eq!(hdr.e_shnum, 30);
assert_eq!(hdr.e_shstrndx, 29);
} else if let Error(err) = res {
panic!(err.to_string());
} else if let Incomplete(need) = res {
match need {
Size(size) => {
panic!("incomplete, needs size {}", size);
}
Unknown => {
panic!("incomplete file, needs size unknown");
}
}
} else {
unreachable!();
}
}
named!(parse_elf_prog_header32<&[u8], Elf32_Phdr>,
do_parse!(
p_type: le_u32 >>
p_offset: le_u32 >>
p_vaddr: le_u32 >>
p_paddr: le_u32 >>
p_filesz: le_u32 >>
p_memsz: le_u32 >>
p_flags: le_u32 >>
p_align: le_u32 >>
(Elf32_Phdr {
p_type: p_type,
p_offset: p_offset,
p_vaddr: p_vaddr,
p_paddr: p_paddr,
p_filesz: p_filesz,
p_memsz: p_memsz,
p_flags: p_flags,
p_align: p_align
})
)
);
named!(parse_elf_prog_header64<&[u8], Elf64_Phdr>,
do_parse!(
p_type: le_u32 >>
p_flags: le_u32 >>
p_offset: le_u64 >>
p_vaddr: le_u64 >>
p_paddr: le_u64 >>
p_filesz: le_u64 >>
p_memsz: le_u64 >>
p_align: le_u64 >>
(Elf64_Phdr {
p_type: p_type,
p_flags: p_flags,
p_offset: p_offset,
p_vaddr: p_vaddr,
p_paddr: p_paddr,
p_filesz: p_filesz,
p_memsz: p_memsz,
p_align: p_align,
})
)
);
named!(parse_elf_section_header32<&[u8], Elf32_Shdr>,
do_parse!(
sh_name: le_u32 >>
sh_type: le_u32 >>
sh_flags: le_u32 >>
sh_addr: le_u32 >>
sh_offset: le_u32 >>
sh_size: le_u32 >>
sh_link: le_u32 >>
sh_info: le_u32 >>
sh_addralign: le_u32 >>
sh_entsize: le_u32 >>
(Elf32_Shdr {
sh_name: sh_name,
sh_type: sh_type,
sh_flags: sh_flags,
sh_addr: sh_addr,
sh_offset: sh_offset,
sh_size: sh_size,
sh_link: sh_link,
sh_info: sh_info,
sh_addralign: sh_addralign,
sh_entsize: sh_entsize
})
)
);
named!(parse_elf_section_header64<&[u8], Elf64_Shdr>,
do_parse!(
sh_name: le_u32 >>
sh_type: le_u32 >>
sh_flags: le_u64 >>
sh_addr: le_u64 >>
sh_offset: le_u64 >>
sh_size: le_u64 >>
sh_link: le_u32 >>
sh_info: le_u32 >>
sh_addralign: le_u64 >>
sh_entsize: le_u64 >>
(Elf64_Shdr {
sh_name: sh_name,
sh_type: sh_type,
sh_flags: sh_flags,
sh_addr: sh_addr,
sh_offset: sh_offset,
sh_size: sh_size,
sh_link: sh_link,
sh_info: sh_info,
sh_addralign: sh_addralign,
sh_entsize: sh_entsize
})
)
);