//! ELF executables use alloc::string::String; use goblin::elf::section_header::SHT_SYMTAB; #[cfg(target_arch = "x86")] pub use goblin::elf32::{header, program_header, section_header, sym}; #[cfg(any( target_arch = "aarch64", target_arch = "riscv64", target_arch = "x86_64" ))] pub use goblin::elf64::{header, program_header, section_header, sym}; /// An ELF executable pub struct Elf<'a> { pub data: &'a [u8], header: &'a header::Header } impl<'a> Elf<'a> { /// Create a ELF executable from data pub fn from(data: &'a [u8]) -> Result<Elf<'a>, String> { if data.len() < header::SIZEOF_EHDR { Err(format!("Elf: Not enough data: {} < {}", data.len(), header::SIZEOF_EHDR)) } else if &data[..header::SELFMAG] != header::ELFMAG { Err(format!("Elf: Invalid magic: {:?} != {:?}", &data[..header::SELFMAG], header::ELFMAG)) } else if data.get(header::EI_CLASS) != Some(&header::ELFCLASS) { Err(format!("Elf: Invalid architecture: {:?} != {:?}", data.get(header::EI_CLASS), header::ELFCLASS)) } else { Ok(Elf { data, header: unsafe { &*(data.as_ptr() as usize as *const header::Header) } }) } } pub fn sections(&'a self) -> ElfSections<'a> { ElfSections { data: self.data, header: self.header, i: 0 } } pub fn segments(&'a self) -> ElfSegments<'a> { ElfSegments { data: self.data, header: self.header, i: 0 } } pub fn symbols(&'a self) -> Option<ElfSymbols<'a>> { let mut symtab_opt = None; for section in self.sections() { if section.sh_type == SHT_SYMTAB { symtab_opt = Some(section); break; } } if let Some(symtab) = symtab_opt { Some(ElfSymbols { data: self.data, symtab, i: 0 }) } else { None } } /// Get the entry field of the header pub fn entry(&self) -> usize { self.header.e_entry as usize } /// Get the program header offset pub fn program_headers(&self) -> usize { self.header.e_phoff as usize } pub fn program_header_count(&self) -> usize { self.header.e_phnum as usize } pub fn program_headers_size(&self) -> usize { self.header.e_phentsize as usize } } pub struct ElfSections<'a> { data: &'a [u8], header: &'a header::Header, i: usize } impl<'a> Iterator for ElfSections<'a> { type Item = &'a section_header::SectionHeader; fn next(&mut self) -> Option<Self::Item> { if self.i < self.header.e_shnum as usize { let item = unsafe { &* (( self.data.as_ptr() as usize + self.header.e_shoff as usize + self.i * self.header.e_shentsize as usize ) as *const section_header::SectionHeader) }; self.i += 1; Some(item) } else { None } } } pub struct ElfSegments<'a> { data: &'a [u8], header: &'a header::Header, i: usize } impl<'a> Iterator for ElfSegments<'a> { type Item = &'a program_header::ProgramHeader; fn next(&mut self) -> Option<Self::Item> { if self.i < self.header.e_phnum as usize { let item = unsafe { &* (( self.data.as_ptr() as usize + self.header.e_phoff as usize + self.i * self.header.e_phentsize as usize ) as *const program_header::ProgramHeader) }; self.i += 1; Some(item) } else { None } } } pub struct ElfSymbols<'a> { data: &'a [u8], symtab: &'a section_header::SectionHeader, i: usize } impl<'a> Iterator for ElfSymbols<'a> { type Item = &'a sym::Sym; fn next(&mut self) -> Option<Self::Item> { if self.i < (self.symtab.sh_size as usize) / sym::SIZEOF_SYM { let item = unsafe { &* (( self.data.as_ptr() as usize + self.symtab.sh_offset as usize + self.i * sym::SIZEOF_SYM ) as *const sym::Sym) }; self.i += 1; Some(item) } else { None } } }