#![no_std]
pub mod sections;
pub mod segments;
pub mod traits;
#[doc(inline)]
pub use sections::Header as SectionHeader;
#[doc(inline)]
pub use segments::Header as ProgramHeader;
#[doc(inline)]
pub use traits::Source;
#[derive(Debug, Clone)]
pub enum Error<E>
where
E: core::fmt::Debug,
{
NotAnElfFile,
WrongElfFile,
Source(E),
NotEnoughSpace,
InvalidString,
}
impl<E> From<E> for Error<E>
where
E: core::fmt::Debug,
{
fn from(value: E) -> Error<E> {
Error::Source(value)
}
}
pub struct Loader<DS> {
data_source: DS,
e_entry: u32,
e_phoff: u32,
e_shoff: u32,
e_phnum: u16,
e_shnum: u16,
e_shstrndx: u16,
}
impl<DS> Loader<DS>
where
DS: Source,
{
const EM_ARM: u16 = 0x0028;
const ET_EXEC: u16 = 0x0002;
const ELF_MAGIC: u32 = 0x7F454C46;
const DESIRED_ELF_VERSION: u32 = 0x01010100;
pub fn new(data_source: DS) -> Result<Loader<DS>, Error<DS::Error>> {
let elf_header = data_source.read_u32_be(0x00)?;
if elf_header != Self::ELF_MAGIC {
return Err(Error::NotAnElfFile);
}
let class_endian_version_abi = data_source.read_u32_be(0x04)?;
if class_endian_version_abi != Self::DESIRED_ELF_VERSION {
return Err(Error::WrongElfFile);
}
let elf_type = data_source.read_u16_le(0x10)?;
if elf_type != Self::ET_EXEC {
return Err(Error::WrongElfFile);
}
let elf_machine = data_source.read_u16_le(0x12)?;
if elf_machine != Self::EM_ARM {
return Err(Error::WrongElfFile);
}
let elf_version = data_source.read_u32_le(0x14)?;
if elf_version != 1 {
return Err(Error::WrongElfFile);
}
let e_entry = data_source.read_u32_le(0x18)?;
let e_phoff = data_source.read_u32_le(0x1C)?;
let e_shoff = data_source.read_u32_le(0x20)?;
let e_phentsize = data_source.read_u16_le(0x2A)?;
if e_phentsize != ProgramHeader::SIZE_IN_BYTES {
return Err(Error::WrongElfFile);
}
let e_phnum = data_source.read_u16_le(0x2C)?;
let e_shentsize = data_source.read_u16_le(0x2E)?;
if e_shentsize != SectionHeader::SIZE_IN_BYTES {
return Err(Error::WrongElfFile);
}
let e_shnum = data_source.read_u16_le(0x30)?;
let e_shstrndx = data_source.read_u16_le(0x32)?;
let loader = Loader {
data_source,
e_entry,
e_phoff,
e_shoff,
e_phnum,
e_shnum,
e_shstrndx,
};
Ok(loader)
}
pub fn iter_section_headers(&self) -> IterSectionHeaders<DS> {
IterSectionHeaders {
parent: self,
next_section: 0,
}
}
pub fn iter_program_headers(&self) -> IterProgramHeaders<DS> {
IterProgramHeaders {
parent: self,
next_program_header: 0,
}
}
pub fn e_entry(&self) -> u32 {
self.e_entry
}
pub fn e_phoff(&self) -> u32 {
self.e_phoff
}
pub fn e_shoff(&self) -> u32 {
self.e_shoff
}
pub fn e_phnum(&self) -> u16 {
self.e_phnum
}
pub fn e_shnum(&self) -> u16 {
self.e_shnum
}
pub fn segment_start_offset(&self) -> u32 {
self.e_phoff() + u32::from(self.e_phnum()) * u32::from(ProgramHeader::SIZE_IN_BYTES)
}
}
pub struct IterSectionHeaders<'a, DS> {
parent: &'a Loader<DS>,
next_section: u16,
}
impl<'a, DS> Iterator for IterSectionHeaders<'a, DS>
where
DS: Source,
{
type Item = Result<SectionHeader, Error<DS::Error>>;
fn next(&mut self) -> Option<Self::Item> {
if self.next_section == self.parent.e_shnum {
return None;
}
let current_section = self.next_section;
self.next_section = self.next_section.wrapping_add(1);
Some(SectionHeader::new(self.parent, current_section))
}
}
pub struct IterProgramHeaders<'a, DS> {
parent: &'a Loader<DS>,
next_program_header: u16,
}
impl<'a, DS> Iterator for IterProgramHeaders<'a, DS>
where
DS: Source,
{
type Item = Result<ProgramHeader, Error<DS::Error>>;
fn next(&mut self) -> Option<Self::Item> {
if self.next_program_header == self.parent.e_phnum {
return None;
}
let current_program_header = self.next_program_header;
self.next_program_header = self.next_program_header.wrapping_add(1);
Some(ProgramHeader::new(self.parent, current_program_header))
}
}