/// A 32-bit ELF object file. /// /// This is a file that starts with [`elf::FileHeader32`], and corresponds /// to [`crate::FileKind::Elf32`]. pubtype ElfFile32<'data, Endian = Endianness, R = &'data [u8]> =
ElfFile<'data, elf::FileHeader32<Endian>, R>; /// A 64-bit ELF object file. /// /// This is a file that starts with [`elf::FileHeader64`], and corresponds /// to [`crate::FileKind::Elf64`]. pubtype ElfFile64<'data, Endian = Endianness, R = &'data [u8]> =
ElfFile<'data, elf::FileHeader64<Endian>, R>;
/// A partially parsed ELF file. /// /// Most functionality is provided by the [`Object`] trait implementation. #[derive(Debug)] pubstruct ElfFile<'data, Elf, R = &'data [u8]> where
Elf: FileHeader,
R: ReadRef<'data>,
{ pub(super) endian: Elf::Endian, pub(super) data: R, pub(super) header: &'data Elf, pub(super) segments: &'data [Elf::ProgramHeader], pub(super) sections: SectionTable<'data, Elf, R>, pub(super) relocations: RelocationSections, pub(super) symbols: SymbolTable<'data, Elf, R>, pub(super) dynamic_symbols: SymbolTable<'data, Elf, R>,
}
impl<'data, Elf, R> ElfFile<'data, Elf, R> where
Elf: FileHeader,
R: ReadRef<'data>,
{ /// Parse the raw ELF file data. pubfn parse(data: R) -> read::Result<Self> { let header = Elf::parse(data)?; let endian = header.endian()?; let segments = header.program_headers(endian, data)?; let sections = header.sections(endian, data)?; let symbols = sections.symbols(endian, data, elf::SHT_SYMTAB)?; // TODO: get dynamic symbols from DT_SYMTAB if there are no sections let dynamic_symbols = sections.symbols(endian, data, elf::SHT_DYNSYM)?; // The API we provide requires a mapping from section to relocations, so build it now. let relocations = sections.relocation_sections(endian, symbols.section())?;
/// Returns the raw data. pubfn data(&self) -> R { self.data
}
/// Returns the raw ELF file header. #[deprecated(note = "Use `elf_header` instead")] pubfn raw_header(&self) -> &'data Elf { self.header
}
/// Returns the raw ELF segments. #[deprecated(note = "Use `elf_program_headers` instead")] pubfn raw_segments(&self) -> &'data [Elf::ProgramHeader] { self.segments
}
/// Get the raw ELF file header. pubfn elf_header(&self) -> &'data Elf { self.header
}
/// Get the raw ELF program headers. /// /// Returns an empty slice if the file has no program headers. pubfn elf_program_headers(&self) -> &'data [Elf::ProgramHeader] { self.segments
}
/// Get the ELF section table. /// /// Returns an empty section table if the file has no section headers. pubfn elf_section_table(&self) -> &SectionTable<'data, Elf, R> {
&self.sections
}
/// Get the ELF symbol table. /// /// Returns an empty symbol table if the file has no symbol table. pubfn elf_symbol_table(&self) -> &SymbolTable<'data, Elf, R> {
&self.symbols
}
/// Get the ELF dynamic symbol table. /// /// Returns an empty symbol table if the file has no dynamic symbol table. pubfn elf_dynamic_symbol_table(&self) -> &SymbolTable<'data, Elf, R> {
&self.dynamic_symbols
}
/// Get a mapping for linked relocation sections. pubfn elf_relocation_sections(&self) -> &RelocationSections {
&self.relocations
}
/// A trait for generic access to [`elf::FileHeader32`] and [`elf::FileHeader64`]. #[allow(missing_docs)] pubtrait FileHeader: Debug + Pod { // Ideally this would be a `u64: From<Word>`, but can't express that. type Word: Into<u64>; type Sword: Into<i64>; type Endian: endian::Endian; type ProgramHeader: ProgramHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>; type SectionHeader: SectionHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>; type CompressionHeader: CompressionHeader<Endian = Self::Endian, Word = Self::Word>; type NoteHeader: NoteHeader<Endian = Self::Endian>; typeDyn: Dyn<Endian = Self::Endian, Word = Self::Word>; type Sym: Sym<Endian = Self::Endian, Word = Self::Word>; type Rel: Rel<Endian = Self::Endian, Word = Self::Word>; type Rela: Rela<Endian = Self::Endian, Word = Self::Word> + From<Self::Rel>;
/// Return true if this type is a 64-bit header. /// /// This is a property of the type, not a value in the header data. fn is_type_64(&self) -> bool;
/// Return true if this type is a 64-bit header. /// /// This is a property of the type, not a value in the header data. /// /// This is the same as [`Self::is_type_64`], but is non-dispatchable. fn is_type_64_sized() -> bool where Self: Sized;
/// Read the file header. /// /// Also checks that the ident field in the file header is a supported format. fn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> { let header = data
.read_at::<Self>(0)
.read_error("Invalid ELF header size or alignment")?; if !header.is_supported() { return Err(Error("Unsupported ELF header"));
} // TODO: Check self.e_ehsize?
Ok(header)
}
/// Check that the ident field in the file header is a supported format. /// /// This checks the magic number, version, class, and endianness. fn is_supported(&self) -> bool { let ident = self.e_ident(); // TODO: Check self.e_version too? Requires endian though.
ident.magic == elf::ELFMAG
&& (self.is_type_64() || self.is_class_32())
&& (!self.is_type_64() || self.is_class_64())
&& (self.is_little_endian() || self.is_big_endian())
&& ident.version == elf::EV_CURRENT
}
/// Return the first section header, if present. /// /// Section 0 is a special case because getting the section headers normally /// requires `shnum`, but `shnum` may be in the first section header. fn section_0<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
) -> read::Result<Option<&'data Self::SectionHeader>> { let shoff: u64 = self.e_shoff(endian).into(); if shoff == 0 { // No section headers is ok. return Ok(None);
} let shentsize = usize::from(self.e_shentsize(endian)); if shentsize != mem::size_of::<Self::SectionHeader>() { // Section header size must match. return Err(Error("Invalid ELF section header entry size"));
}
data.read_at(shoff)
.map(Some)
.read_error("Invalid ELF section header offset or size")
}
/// Return the `e_phnum` field of the header. Handles extended values. /// /// Returns `Err` for invalid values. fn phnum<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
) -> read::Result<usize> { let e_phnum = self.e_phnum(endian); if e_phnum < elf::PN_XNUM {
Ok(e_phnum as usize)
} elseiflet Some(section_0) = self.section_0(endian, data)? {
Ok(section_0.sh_info(endian) as usize)
} else { // Section 0 must exist if e_phnum overflows.
Err(Error("Missing ELF section headers for e_phnum overflow"))
}
}
/// Return the `e_shnum` field of the header. Handles extended values. /// /// Returns `Err` for invalid values. fn shnum<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
) -> read::Result<usize> { let e_shnum = self.e_shnum(endian); if e_shnum > 0 {
Ok(e_shnum as usize)
} elseiflet Some(section_0) = self.section_0(endian, data)? {
section_0
.sh_size(endian)
.into()
.try_into()
.ok()
.read_error("Invalid ELF extended e_shnum")
} else { // No section headers is ok.
Ok(0)
}
}
/// Return the `e_shstrndx` field of the header. Handles extended values. /// /// Returns `Err` for invalid values (including if the index is 0). fn shstrndx<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
) -> read::Result<u32> { let e_shstrndx = self.e_shstrndx(endian); let index = if e_shstrndx != elf::SHN_XINDEX {
e_shstrndx.into()
} elseiflet Some(section_0) = self.section_0(endian, data)? {
section_0.sh_link(endian)
} else { // Section 0 must exist if we're trying to read e_shstrndx. return Err(Error("Missing ELF section headers for e_shstrndx overflow"));
}; if index == 0 { return Err(Error("Missing ELF e_shstrndx"));
}
Ok(index)
}
/// Return the slice of program headers. /// /// Returns `Ok(&[])` if there are no program headers. /// Returns `Err` for invalid values. fn program_headers<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
) -> read::Result<&'data [Self::ProgramHeader]> { let phoff: u64 = self.e_phoff(endian).into(); if phoff == 0 { // No program headers is ok. return Ok(&[]);
} let phnum = self.phnum(endian, data)?; if phnum == 0 { // No program headers is ok. return Ok(&[]);
} let phentsize = self.e_phentsize(endian) as usize; if phentsize != mem::size_of::<Self::ProgramHeader>() { // Program header size must match. return Err(Error("Invalid ELF program header entry size"));
}
data.read_slice_at(phoff, phnum)
.read_error("Invalid ELF program header size or alignment")
}
/// Return the slice of section headers. /// /// Returns `Ok(&[])` if there are no section headers. /// Returns `Err` for invalid values. fn section_headers<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
) -> read::Result<&'data [Self::SectionHeader]> { let shoff: u64 = self.e_shoff(endian).into(); if shoff == 0 { // No section headers is ok. return Ok(&[]);
} let shnum = self.shnum(endian, data)?; if shnum == 0 { // No section headers is ok. return Ok(&[]);
} let shentsize = usize::from(self.e_shentsize(endian)); if shentsize != mem::size_of::<Self::SectionHeader>() { // Section header size must match. return Err(Error("Invalid ELF section header entry size"));
}
data.read_slice_at(shoff, shnum)
.read_error("Invalid ELF section header offset/size/alignment")
}
/// Get the section index of the section header string table. /// /// Returns `Err` for invalid values (including if the index is 0). fn section_strings_index<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
) -> read::Result<SectionIndex> { self.shstrndx(endian, data)
.map(|index| SectionIndex(index as usize))
}
/// Return the string table for the section headers. fn section_strings<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
sections: &[Self::SectionHeader],
) -> read::Result<StringTable<'data, R>> { if sections.is_empty() { return Ok(StringTable::default());
} let index = self.section_strings_index(endian, data)?; let shstrtab = sections.get(index.0).read_error("Invalid ELF e_shstrndx")?; let strings = iflet Some((shstrtab_offset, shstrtab_size)) = shstrtab.file_range(endian) { let shstrtab_end = shstrtab_offset
.checked_add(shstrtab_size)
.read_error("Invalid ELF shstrtab size")?;
StringTable::new(data, shstrtab_offset, shstrtab_end)
} else {
StringTable::default()
};
Ok(strings)
}
/// Returns whether this is a mips64el elf file. fn is_mips64el(&self, endian: Self::Endian) -> bool { self.is_class_64() && self.is_little_endian() && self.e_machine(endian) == elf::EM_MIPS
}
}
impl<Endian: endian::Endian> FileHeader for elf::FileHeader32<Endian> { type Word = u32; type Sword = i32; type Endian = Endian; type ProgramHeader = elf::ProgramHeader32<Endian>; type SectionHeader = elf::SectionHeader32<Endian>; type CompressionHeader = elf::CompressionHeader32<Endian>; type NoteHeader = elf::NoteHeader32<Endian>; typeDyn = elf::Dyn32<Endian>; type Sym = elf::Sym32<Endian>; type Rel = elf::Rel32<Endian>; type Rela = elf::Rela32<Endian>;
impl<Endian: endian::Endian> FileHeader for elf::FileHeader64<Endian> { type Word = u64; type Sword = i64; type Endian = Endian; type ProgramHeader = elf::ProgramHeader64<Endian>; type SectionHeader = elf::SectionHeader64<Endian>; type CompressionHeader = elf::CompressionHeader64<Endian>; type NoteHeader = elf::NoteHeader32<Endian>; typeDyn = elf::Dyn64<Endian>; type Sym = elf::Sym64<Endian>; type Rel = elf::Rel64<Endian>; type Rela = elf::Rela64<Endian>;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.