#![warn(missing_docs)]
#[macro_use]
mod macros;
mod array;
mod dynamic;
mod header;
mod modinfo;
mod note;
mod relocation;
mod section;
mod segment;
mod strings;
mod symbols;
mod types;
mod utils;
pub use array::*;
pub use dynamic::*;
use header::*;
pub use modinfo::*;
pub use note::*;
pub use relocation::*;
pub use section::ElfSectionAccessTrait;
use section::*;
pub use segment::ElfSegmentAccessTrait;
use segment::*;
use std::io;
pub use strings::*;
pub use symbols::*;
pub use types::*;
pub use utils::ElfioReadSeek;
pub struct Elfio {
header: Box<dyn ElfHeaderTrait>,
converter: utils::Converter,
sections: Vec<Box<dyn ElfSectionTrait>>,
segments: Vec<Box<dyn ElfSegmentTrait>>,
}
impl Elfio {
pub fn new() -> Self {
Elfio {
converter: utils::Converter { is_needed: false },
header: Box::new(ElfHeader::<Elf64Addr, Elf64Off>::new()),
sections: Vec::new(),
segments: Vec::new(),
}
}
pub fn new_(encoding: u8, endianess: u8) -> Self {
Elfio {
converter: if (endianess == constant::ELFDATA2LSB && cfg!(target_endian = "little"))
|| endianess == constant::ELFDATA2MSB && cfg!(target_endian = "big")
{
utils::Converter { is_needed: false }
} else {
utils::Converter { is_needed: true }
},
header: if encoding == constant::ELFCLASS64 {
Box::new(ElfHeader::<Elf64Addr, Elf64Off>::new())
} else {
Box::new(ElfHeader::<Elf32Addr, Elf32Off>::new())
},
sections: Vec::new(),
segments: Vec::new(),
}
}
pub fn get_converter(&self) -> &utils::Converter {
&self.converter
}
pub fn load(&mut self, reader: &mut (dyn ElfioReadSeek)) -> io::Result<()> {
let mut e_ident: [u8; constant::EI_NIDENT] = [0; constant::EI_NIDENT];
reader.read_exact(&mut e_ident)?;
reader.seek(io::SeekFrom::Start(0))?;
if e_ident[constant::EI_MAG0] != constant::ELFMAG0
|| e_ident[constant::EI_MAG1] != constant::ELFMAG1
|| e_ident[constant::EI_MAG2] != constant::ELFMAG2
|| e_ident[constant::EI_MAG3] != constant::ELFMAG3
{
return Err(io::Error::new(
io::ErrorKind::Other,
"File signature doesn't conform ELF file",
));
}
if e_ident[constant::EI_CLASS] != constant::ELFCLASS64
&& e_ident[constant::EI_CLASS] != constant::ELFCLASS32
{
return Err(io::Error::new(
io::ErrorKind::Other,
"Unknown ELF class value",
));
}
if e_ident[constant::EI_DATA] != constant::ELFDATA2LSB
&& e_ident[constant::EI_DATA] != constant::ELFDATA2MSB
{
return Err(io::Error::new(
io::ErrorKind::Other,
"Unknown ELF file endianess",
));
}
if e_ident[constant::EI_CLASS] == constant::ELFCLASS64 {
self.header = Box::new(ElfHeader::<Elf64Addr, Elf64Off>::new());
} else {
self.header = Box::new(ElfHeader::<Elf32Addr, Elf32Off>::new());
}
if (cfg!(target_endian = "little") && (e_ident[constant::EI_DATA] == constant::ELFDATA2LSB))
|| (cfg!(target_endian = "big")
&& (e_ident[constant::EI_DATA] == constant::ELFDATA2MSB))
{
self.converter.is_needed = false;
} else {
self.converter.is_needed = true;
}
self.header.set_converter(&self.converter);
match self.header.load(reader) {
Ok(_) => (),
Err(e) => return Err(e),
};
self.load_sections(reader)?;
self.load_segments(reader)?;
Ok(())
}
pub fn get_sections(&self) -> &Vec<Box<dyn ElfSectionTrait>> {
&self.sections
}
pub fn get_segments(&self) -> &Vec<Box<dyn ElfSegmentTrait>> {
&self.segments
}
pub fn get_section_by_name(&self, section_name: &str) -> Option<&dyn ElfSectionTrait> {
for section in &self.sections {
if section.get_name() == section_name {
return Some(&**section);
}
}
None
}
pub fn get_section_by_index(&self, index: ElfHalf) -> Option<&dyn ElfSectionTrait> {
let index = index as usize;
if index < self.sections.len() {
return Some(&*self.sections[index]);
}
None
}
fn load_sections(&mut self, reader: &mut (dyn ElfioReadSeek)) -> io::Result<()> {
let entry_size = self.header.get_section_entry_size() as Elf64Off;
let num = self.header.get_sections_num() as Elf64Off;
let offset = self.header.get_sections_offset();
for i in 0..num {
let mut section = self.create_section();
reader.seek(io::SeekFrom::Start(i * entry_size + offset))?;
section.load(reader)?;
self.sections.push(section);
}
let shstrndx = self.get_section_name_str_index();
if shstrndx != constant::SHN_UNDEF {
for i in 1..num {
let pos = self.sections[i as usize].get_name_string_offset();
let acc = StringSectionAccessor::new(self, &*self.sections[shstrndx as usize]);
let name = acc.get_string(pos);
self.sections[i as usize].set_name(&name);
}
}
Ok(())
}
fn create_section(&self) -> Box<dyn ElfSectionTrait> {
let section: Box<dyn ElfSectionTrait> = if self.header.get_class() == constant::ELFCLASS64 {
Box::new(ElfSection::<Elf64Addr, Elf64Off, ElfXword>::new(
&self.converter,
))
} else {
Box::new(ElfSection::<Elf32Addr, Elf32Off, ElfWord>::new(
&self.converter,
))
};
section
}
fn load_segments(&mut self, reader: &mut (dyn ElfioReadSeek)) -> io::Result<()> {
let entry_size = self.header.get_segment_entry_size() as Elf64Off;
let num = self.header.get_segments_num() as Elf64Off;
let offset = self.header.get_segments_offset();
for i in 0..num {
let mut segment = self.create_segment();
reader.seek(io::SeekFrom::Start(i * entry_size + offset))?;
segment.load(reader)?;
self.segments.push(segment);
}
Ok(())
}
fn create_segment(&self) -> Box<dyn ElfSegmentTrait> {
let segment: Box<dyn ElfSegmentTrait> = if self.header.get_class() == constant::ELFCLASS64 {
Box::new(ElfSegment::<Elf64Addr, Elf64Off, ElfXword>::new(
&self.converter,
self.header.get_class(),
))
} else {
Box::new(ElfSegment::<Elf32Addr, Elf32Off, ElfWord>::new(
&self.converter,
self.header.get_class(),
))
};
segment
}
ELFIO_HEADER_ACCESS_GET!(u8, class);
ELFIO_HEADER_ACCESS_GET!(u8, elf_version);
ELFIO_HEADER_ACCESS_GET!(u8, encoding);
ELFIO_HEADER_ACCESS_GET!(ElfHalf, header_size);
ELFIO_HEADER_ACCESS_GET!(ElfHalf, section_entry_size);
ELFIO_HEADER_ACCESS_GET!(ElfHalf, segment_entry_size);
ELFIO_HEADER_ACCESS_GET_SET!(ElfWord, version);
ELFIO_HEADER_ACCESS_GET_SET!(u8, os_abi);
ELFIO_HEADER_ACCESS_GET_SET!(u8, abi_version);
ELFIO_HEADER_ACCESS_GET_SET!(ElfHalf, type);
ELFIO_HEADER_ACCESS_GET_SET!(ElfHalf, machine);
ELFIO_HEADER_ACCESS_GET_SET!(ElfWord, flags);
ELFIO_HEADER_ACCESS_GET_SET!(Elf64Addr, entry);
ELFIO_HEADER_ACCESS_GET_SET!(ElfHalf, sections_num);
ELFIO_HEADER_ACCESS_GET_SET!(Elf64Off, sections_offset);
ELFIO_HEADER_ACCESS_GET_SET!(ElfHalf, segments_num);
ELFIO_HEADER_ACCESS_GET_SET!(Elf64Off, segments_offset);
ELFIO_HEADER_ACCESS_GET_SET!(ElfHalf, section_name_str_index);
}
impl std::fmt::Debug for Elfio {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Elfio")
.finish()
}
}
impl Default for Elfio {
fn default() -> Self {
Self::new()
}
}