#![warn(missing_docs)]
use std::error::Error;
use std::fmt::{ Display, Formatter };
use std::io::{ Read, Seek, SeekFrom };
use std::collections::HashMap;
#[macro_use]
mod macros;
pub mod types;
pub mod numeric;
pub mod constants;
use crate::types::*;
pub type ParseElfResult<T> = std::result::Result<T, ParseElfError>;
#[derive(Debug)]
pub enum ParseElfError {
IoError{
inner: std::io::Error
},
#[allow(missing_docs)]
InvalidSectionType(u32),
#[allow(missing_docs)]
InvalidProgramFlags(u32),
#[allow(missing_docs)]
InvalidProgramHeader(u32),
#[allow(missing_docs)]
InvalidVersion(u32),
#[allow(missing_docs)]
InvalidMachine(u16),
#[allow(missing_docs)]
InvalidElfType(u16),
#[allow(missing_docs)]
InvalidOsAbi(u8),
#[allow(missing_docs)]
InvalidIdentVersion(u8),
#[allow(missing_docs)]
InvalidDataFormat(u8),
#[allow(missing_docs)]
InvalidDataClass(u8),
InvalidParsingDescriptor,
}
impl Error for ParseElfError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
ParseElfError::IoError{ inner } => Some(inner),
_ => None,
}
}
}
impl Display for ParseElfError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl From<std::io::Error> for ParseElfError {
fn from(err: std::io::Error) -> ParseElfError {
ParseElfError::IoError{ inner: err }
}
}
trait Parslet {
fn parse<R: Read + Seek>(reader: &mut R, descriptor: &mut Descriptor) -> ParseElfResult<Self> where Self: Sized;
}
enum Descriptor {
None,
Data{ format: DataFormat, class: DataClass },
}
impl Descriptor {
fn data_class(&self) -> ParseElfResult<DataClass> {
match self {
Descriptor::Data{ class, .. } => Ok(*class),
Descriptor::None => Err(ParseElfError::InvalidParsingDescriptor),
}
}
fn data_format(&self) -> ParseElfResult<DataFormat> {
match self {
Descriptor::Data{ format, .. } => Ok(*format),
Descriptor::None => Err(ParseElfError::InvalidParsingDescriptor)
}
}
}
#[derive(Debug)]
pub struct Elf {
header: ElfHeader,
sections: Vec<Section>,
segments: Vec<Segment>,
section_map: HashMap<String, usize>,
}
impl Elf {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> ParseElfResult<Elf> {
let file = std::fs::File::open(path)?;
let mut buf = std::io::BufReader::new(file);
Ok(Elf::parse(&mut buf)?)
}
pub fn parse<R: Read + Seek>(reader: &mut R) -> ParseElfResult<Elf> {
let mut descriptor = Descriptor::None;
let header = ElfHeader::parse(reader, &mut descriptor)?;
let sections = parse_sections(reader, &mut descriptor, &header)?;
let segments = parse_segments(reader, &mut descriptor, &header)?;
let mut section_map = HashMap::new();
associate_string_table(&mut section_map, §ions, &header);
Ok(Elf{
header,
sections,
segments,
section_map
})
}
pub fn try_get_section(&self, section_name: &str) -> Option<&Section> {
self.sections.get(*self.section_map.get(section_name)?)
}
pub fn header(&self) -> &ElfHeader {
&self.header
}
pub fn sections(&self) -> SectionIter {
SectionIter {
elf: &self,
idx: 0
}
}
pub fn segments(&self) -> SegmentIter {
SegmentIter {
elf: &self,
idx: 0
}
}
}
fn parse_sections<R: Read + Seek>(reader: &mut R, descriptor: &mut Descriptor, header: &ElfHeader) -> ParseElfResult<Vec<Section>> {
reader.seek(SeekFrom::Start(header.section_headers_offset()))?;
let mut sections = Vec::new();
for _ in 0..header.section_header_count() {
sections.push(Section::parse(reader, descriptor)?)
}
Ok(sections)
}
fn parse_segments<R: Read + Seek>(reader: &mut R, descriptor: &mut Descriptor, header: &ElfHeader) -> ParseElfResult<Vec<Segment>> {
reader.seek(SeekFrom::Start(header.program_headers_offset()))?;
let mut segments = Vec::new();
for _ in 0..header.program_header_count() {
segments.push(Segment::parse(reader, descriptor)?)
}
Ok(segments)
}
fn associate_string_table(section_map: &mut HashMap<String, usize>, sections: &[Section], header: &ElfHeader) {
if let Some(idx) = header.section_name_table_index() {
if let SectionData::Strings(table) = §ions[idx].data() {
for (i, _section) in sections.iter().enumerate() {
let name = table[i].clone();
section_map.insert(name, i);
}
}
}
}
pub struct SectionIter<'a> {
elf: &'a Elf,
idx: usize,
}
impl<'a> Iterator for SectionIter<'a> {
type Item = &'a Section;
fn next(&mut self) -> Option<Self::Item> {
let item = self.elf.sections.get(self.idx)?;
self.idx += 1;
Some(item)
}
}
pub struct SegmentIter<'a> {
elf: &'a Elf,
idx: usize,
}
impl<'a> Iterator for SegmentIter<'a> {
type Item = &'a Segment;
fn next(&mut self) -> Option<Self::Item> {
let item = self.elf.segments.get(self.idx)?;
self.idx += 1;
Some(item)
}
}
pub mod prelude {
pub use crate::numeric::*;
pub use crate::types::*;
pub use crate::Elf;
}
#[cfg(test)]
mod test {
use super::*;
fn _load_example_binary() -> Elf {
let elf = Elf::load("examples/example-binary").unwrap();
elf
}
#[test]
fn get_section_bytes() {
let elf = _load_example_binary();
let text = elf.try_get_section(".text").unwrap();
if let SectionData::Bytes(_bytes) = text.data() {
}
}
#[test]
fn section_iters() {
let elf = _load_example_binary();
for (i, s) in elf.sections().enumerate() {
match i {
0 => assert_eq!(s.header().section_type(), SectionType::Null),
2 => assert_eq!(s.header().section_type(), SectionType::ProgramData),
5 => assert_eq!(s.header().section_type(), SectionType::SymbolTable),
6 => assert_eq!(s.header().section_type(), SectionType::StringTable),
_ => continue
}
}
}
#[test]
fn segment_iters() {
let elf = _load_example_binary();
println!("{:#?}", elf);
for (i, h) in elf.segments().enumerate() {
match i {
0 => assert_eq!(h.header().program_header_type(), ProgramHeaderType::Phdr),
1 => assert_eq!(h.header().program_header_type(), ProgramHeaderType::Loadable),
2 => assert_eq!(h.header().program_header_type(), ProgramHeaderType::Loadable),
3 => assert_eq!(h.header().program_header_type(), ProgramHeaderType::GnuStack),
4 => assert_eq!(h.header().program_header_type(), ProgramHeaderType::ArmExidx),
_ => continue
}
}
}
}