Refactor endianness storage so its not duplicated on FileHeader and ElfBytes+ElfStream

This eliminates the funky double-storage of the endianness spec and removes the unparsed u8 storage
of ei_data off FileHeader. Now, FileHeader just stores the appropriate parsed endianness spec enum,
and all methods that want to use it grab it from there.
This commit is contained in:
Christopher Cole 2022-11-12 13:28:58 -08:00
parent 4875ff8981
commit 19e7f685c8
No known key found for this signature in database
GPG Key ID: 0AC856975983E9DB
3 changed files with 175 additions and 123 deletions

@ -2,7 +2,7 @@ use crate::abi;
use crate::compression::CompressionHeader;
use crate::dynamic::{Dyn, DynamicTable};
use crate::endian::EndianParse;
use crate::file::{Class, FileHeader};
use crate::file::{parse_ident, Class, FileHeader};
use crate::gnu_symver::{
SymbolVersionTable, VerDefIterator, VerNeedIterator, VersionIndex, VersionIndexTable,
};
@ -62,9 +62,8 @@ use crate::symbol::{Symbol, SymbolTable};
/// println!("There are {} PT_LOAD segments", all_load_phdrs.len());
/// ```
pub struct ElfBytes<'data, E: EndianParse> {
pub ehdr: FileHeader,
pub ehdr: FileHeader<E>,
data: &'data [u8],
endian: E,
shdrs: Option<SectionHeaderTable<'data, E>>,
phdrs: Option<SegmentTable<'data, E>>,
}
@ -74,8 +73,7 @@ pub struct ElfBytes<'data, E: EndianParse> {
/// If shnum > SHN_LORESERVE (0xff00), then this will additionally parse out shdr[0] to calculate
/// the full table size, but all other parsing of SectionHeaders is deferred.
fn find_shdrs<'data, E: EndianParse>(
endian: E,
ehdr: &FileHeader,
ehdr: &FileHeader<E>,
data: &'data [u8],
) -> Result<Option<SectionHeaderTable<'data, E>>, ParseError> {
// It's Ok to have no section headers
@ -90,7 +88,7 @@ fn find_shdrs<'data, E: EndianParse>(
let mut shnum = ehdr.e_shnum as usize;
if shnum == 0 {
let mut offset = shoff;
let shdr0 = SectionHeader::parse_at(endian, ehdr.class, &mut offset, data)?;
let shdr0 = SectionHeader::parse_at(ehdr.endianness, ehdr.class, &mut offset, data)?;
shnum = shdr0.sh_size.try_into()?;
}
@ -102,14 +100,17 @@ fn find_shdrs<'data, E: EndianParse>(
.ok_or(ParseError::IntegerOverflow)?;
let end = shoff.checked_add(size).ok_or(ParseError::IntegerOverflow)?;
let buf = data.get_bytes(shoff..end)?;
Ok(Some(SectionHeaderTable::new(endian, ehdr.class, buf)))
Ok(Some(SectionHeaderTable::new(
ehdr.endianness,
ehdr.class,
buf,
)))
}
/// Find the location (if any) of the program headers in the given data buffer and take a
/// subslice of their data and wrap it in a lazy-parsing SegmentTable.
fn find_phdrs<'data, E: EndianParse>(
endian: E,
ehdr: &FileHeader,
ehdr: &FileHeader<E>,
data: &'data [u8],
) -> Result<Option<SegmentTable<'data, E>>, ParseError> {
// It's Ok to have no program headers
@ -124,7 +125,7 @@ fn find_phdrs<'data, E: EndianParse>(
if phnum == abi::PN_XNUM as usize {
let shoff: usize = ehdr.e_shoff.try_into()?;
let mut offset = shoff;
let shdr0 = SectionHeader::parse_at(endian, ehdr.class, &mut offset, data)?;
let shdr0 = SectionHeader::parse_at(ehdr.endianness, ehdr.class, &mut offset, data)?;
phnum = shdr0.sh_info.try_into()?;
}
@ -137,7 +138,7 @@ fn find_phdrs<'data, E: EndianParse>(
.ok_or(ParseError::IntegerOverflow)?;
let end = phoff.checked_add(size).ok_or(ParseError::IntegerOverflow)?;
let buf = data.get_bytes(phoff..end)?;
Ok(Some(SegmentTable::new(endian, ehdr.class, buf)))
Ok(Some(SegmentTable::new(ehdr.endianness, ehdr.class, buf)))
}
/// This struct collects the common sections found in ELF objects
@ -172,7 +173,7 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
// N.B. I thought about calling this "sparse_parse", but it felt too silly for a serious lib like this
pub fn minimal_parse(data: &'data [u8]) -> Result<Self, ParseError> {
let ident_buf = data.get_bytes(0..abi::EI_NIDENT)?;
let ident = FileHeader::parse_ident(ident_buf)?;
let ident = parse_ident(ident_buf)?;
let tail_start = abi::EI_NIDENT;
let tail_end = match ident.1 {
@ -182,14 +183,12 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
let tail_buf = data.get_bytes(tail_start..tail_end)?;
let ehdr = FileHeader::parse_tail(ident, tail_buf)?;
let endian = E::from_ei_data(ehdr.ei_data)?;
let shdrs = find_shdrs(endian, &ehdr, data)?;
let phdrs = find_phdrs(endian, &ehdr, data)?;
let shdrs = find_shdrs(&ehdr, data)?;
let phdrs = find_phdrs(&ehdr, data)?;
Ok(ElfBytes {
ehdr,
data,
endian,
shdrs,
phdrs,
})
@ -387,14 +386,20 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
abi::SHT_HASH => {
let (start, end) = shdr.get_data_range()?;
let buf = self.data.get_bytes(start..end)?;
result.sysv_hash =
Some(SysVHashTable::new(self.endian, self.ehdr.class, buf)?);
result.sysv_hash = Some(SysVHashTable::new(
self.ehdr.endianness,
self.ehdr.class,
buf,
)?);
}
abi::SHT_GNU_HASH => {
let (start, end) = shdr.get_data_range()?;
let buf = self.data.get_bytes(start..end)?;
result.gnu_hash =
Some(GnuHashTable::new(self.endian, self.ehdr.class, buf)?);
result.gnu_hash = Some(GnuHashTable::new(
self.ehdr.endianness,
self.ehdr.class,
buf,
)?);
}
_ => {
continue;
@ -409,7 +414,11 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
if let Some(dyn_phdr) = phdrs.iter().find(|phdr| phdr.p_type == abi::PT_DYNAMIC) {
let (start, end) = dyn_phdr.get_file_data_range()?;
let buf = self.data.get_bytes(start..end)?;
result.dynamic = Some(DynamicTable::new(self.endian, self.ehdr.class, buf));
result.dynamic = Some(DynamicTable::new(
self.ehdr.endianness,
self.ehdr.class,
buf,
));
}
}
}
@ -441,7 +450,12 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
Ok((buf, None))
} else {
let mut offset = 0;
let chdr = CompressionHeader::parse_at(self.endian, self.ehdr.class, &mut offset, buf)?;
let chdr = CompressionHeader::parse_at(
self.ehdr.endianness,
self.ehdr.class,
&mut offset,
buf,
)?;
let compressed_buf = buf.get(offset..).ok_or(ParseError::SliceReadError((
offset,
shdr.sh_size.try_into()?,
@ -484,7 +498,7 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
}
let (buf, _) = self.section_data(shdr)?;
Ok(RelIterator::new(self.endian, self.ehdr.class, buf))
Ok(RelIterator::new(self.ehdr.endianness, self.ehdr.class, buf))
}
/// Get the section data for a given [SectionHeader], and interpret it as an
@ -503,7 +517,11 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
}
let (buf, _) = self.section_data(shdr)?;
Ok(RelaIterator::new(self.endian, self.ehdr.class, buf))
Ok(RelaIterator::new(
self.ehdr.endianness,
self.ehdr.class,
buf,
))
}
/// Get the section data for a given [SectionHeader], and interpret it as an
@ -523,7 +541,7 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
let (buf, _) = self.section_data(shdr)?;
Ok(NoteIterator::new(
self.endian,
self.ehdr.endianness,
self.ehdr.class,
shdr.sh_addralign as usize,
buf,
@ -546,7 +564,11 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
// Validate entsize before trying to read the table so that we can error early for corrupted files
Dyn::validate_entsize(self.ehdr.class, shdr.sh_entsize.try_into()?)?;
let (buf, _) = self.section_data(shdr)?;
Ok(DynamicTable::new(self.endian, self.ehdr.class, buf))
Ok(DynamicTable::new(
self.ehdr.endianness,
self.ehdr.class,
buf,
))
}
/// Get the segment's file data for a given segment/[ProgramHeader].
@ -574,7 +596,7 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
let buf = self.segment_data(phdr)?;
Ok(NoteIterator::new(
self.endian,
self.ehdr.endianness,
self.ehdr.class,
phdr.p_align as usize,
buf,
@ -593,7 +615,11 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
if let Some(phdr) = phdrs.iter().find(|phdr| phdr.p_type == abi::PT_DYNAMIC) {
let (start, end) = phdr.get_file_data_range()?;
let buf = self.data.get_bytes(start..end)?;
return Ok(Some(DynamicTable::new(self.endian, self.ehdr.class, buf)));
return Ok(Some(DynamicTable::new(
self.ehdr.endianness,
self.ehdr.class,
buf,
)));
}
}
@ -620,7 +646,7 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
let (strtab_start, strtab_end) = strtab_shdr.get_data_range()?;
let strtab_buf = self.data.get_bytes(strtab_start..strtab_end)?;
let symtab = SymbolTable::new(self.endian, self.ehdr.class, symtab_buf);
let symtab = SymbolTable::new(self.ehdr.endianness, self.ehdr.class, symtab_buf);
let strtab = StringTable::new(strtab_buf);
Ok((symtab, strtab))
}
@ -725,7 +751,7 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
VersionIndex::validate_entsize(self.ehdr.class, versym_shdr.sh_entsize.try_into()?)?;
let (versym_start, versym_end) = versym_shdr.get_data_range()?;
let version_ids = VersionIndexTable::new(
self.endian,
self.ehdr.endianness,
self.ehdr.class,
self.data.get_bytes(versym_start..versym_end)?,
);
@ -742,7 +768,7 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
Some((
VerNeedIterator::new(
self.endian,
self.ehdr.endianness,
self.ehdr.class,
shdr.sh_info as u64,
0,
@ -768,7 +794,7 @@ impl<'data, E: EndianParse> ElfBytes<'data, E> {
Some((
VerDefIterator::new(
self.endian,
self.ehdr.endianness,
self.ehdr.class,
shdr.sh_info as u64,
0,
@ -1417,7 +1443,7 @@ mod arch_tests {
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("should parse");
assert_eq!(file.ehdr.e_machine, $e_machine);
assert_eq!(file.endian, $endian);
assert_eq!(file.ehdr.endianness, $endian);
let (shdrs, strtab) = file.section_headers_with_strtab().expect("should parse");
let (shdrs, strtab) = (shdrs.unwrap(), strtab.unwrap());

@ -6,7 +6,7 @@ use crate::abi;
use crate::compression::CompressionHeader;
use crate::dynamic::DynamicTable;
use crate::endian::EndianParse;
use crate::file::Class;
use crate::file::{parse_ident, Class};
use crate::gnu_symver::{
SymbolVersionTable, VerDefIterator, VerNeedIterator, VersionIndex, VersionIndexTable,
};
@ -24,11 +24,10 @@ use crate::file::FileHeader;
/// This type encapsulates the stream-oriented interface for parsing ELF objects from
/// a `Read + Seek`.
pub struct ElfStream<E: EndianParse, S: std::io::Read + std::io::Seek> {
pub ehdr: FileHeader,
pub ehdr: FileHeader<E>,
shdrs: Vec<SectionHeader>,
phdrs: Vec<ProgramHeader>,
reader: CachingReader<S>,
endian: E,
}
/// Read the stream bytes backing the section headers table and parse them all into their Rust native type.
@ -37,8 +36,7 @@ pub struct ElfStream<E: EndianParse, S: std::io::Read + std::io::Seek> {
/// i.e. if the ELF [FileHeader]'s e_shnum, e_shoff, e_shentsize are invalid and point
/// to a range in the file data that does not actually exist, or if any of the headers failed to parse.
fn parse_section_headers<E: EndianParse, S: Read + Seek>(
endian: E,
ehdr: &FileHeader,
ehdr: &FileHeader<E>,
reader: &mut CachingReader<S>,
) -> Result<Vec<SectionHeader>, ParseError> {
// It's Ok to have no section headers
@ -60,7 +58,7 @@ fn parse_section_headers<E: EndianParse, S: Read + Seek>(
.ok_or(ParseError::IntegerOverflow)?;
let mut offset = 0;
let data = reader.read_bytes(shoff, end)?;
let shdr0 = SectionHeader::parse_at(endian, ehdr.class, &mut offset, data)?;
let shdr0 = SectionHeader::parse_at(ehdr.endianness, ehdr.class, &mut offset, data)?;
shnum = shdr0.sh_size.try_into()?;
}
@ -69,15 +67,14 @@ fn parse_section_headers<E: EndianParse, S: Read + Seek>(
.ok_or(ParseError::IntegerOverflow)?;
let end = shoff.checked_add(size).ok_or(ParseError::IntegerOverflow)?;
let buf = reader.read_bytes(shoff, end)?;
let shdr_vec = SectionHeaderTable::new(endian, ehdr.class, buf)
let shdr_vec = SectionHeaderTable::new(ehdr.endianness, ehdr.class, buf)
.iter()
.collect();
Ok(shdr_vec)
}
fn parse_program_headers<E: EndianParse, S: Read + Seek>(
endian: E,
ehdr: &FileHeader,
ehdr: &FileHeader<E>,
reader: &mut CachingReader<S>,
) -> Result<Vec<ProgramHeader>, ParseError> {
// It's Ok to have no program headers
@ -96,7 +93,7 @@ fn parse_program_headers<E: EndianParse, S: Read + Seek>(
.ok_or(ParseError::IntegerOverflow)?;
let data = reader.read_bytes(shoff, end)?;
let mut offset = 0;
let shdr0 = SectionHeader::parse_at(endian, ehdr.class, &mut offset, data)?;
let shdr0 = SectionHeader::parse_at(ehdr.endianness, ehdr.class, &mut offset, data)?;
phnum = shdr0.sh_info.try_into()?;
}
@ -109,7 +106,9 @@ fn parse_program_headers<E: EndianParse, S: Read + Seek>(
.ok_or(ParseError::IntegerOverflow)?;
let end = phoff.checked_add(size).ok_or(ParseError::IntegerOverflow)?;
let buf = reader.read_bytes(phoff, end)?;
let phdrs_vec = SegmentTable::new(endian, ehdr.class, buf).iter().collect();
let phdrs_vec = SegmentTable::new(ehdr.endianness, ehdr.class, buf)
.iter()
.collect();
Ok(phdrs_vec)
}
@ -121,7 +120,7 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
pub fn open_stream(reader: S) -> Result<ElfStream<E, S>, ParseError> {
let mut cr = CachingReader::new(reader)?;
let ident_buf = cr.read_bytes(0, abi::EI_NIDENT)?;
let ident = FileHeader::parse_ident(ident_buf)?;
let ident = parse_ident(ident_buf)?;
let tail_start = abi::EI_NIDENT;
let tail_end = match ident.1 {
@ -131,10 +130,9 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
let tail_buf = cr.read_bytes(tail_start, tail_end)?;
let ehdr = FileHeader::parse_tail(ident, tail_buf)?;
let endian = E::from_ei_data(ehdr.ei_data)?;
let shdrs = parse_section_headers(endian, &ehdr, &mut cr)?;
let phdrs = parse_program_headers(endian, &ehdr, &mut cr)?;
let shdrs = parse_section_headers(&ehdr, &mut cr)?;
let phdrs = parse_program_headers(&ehdr, &mut cr)?;
// We parsed out the ehdr and shdrs into their own allocated containers, so there's no need to keep
// around their backing data anymore.
@ -145,7 +143,6 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
shdrs,
phdrs,
reader: cr,
endian,
})
}
@ -293,7 +290,12 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
Ok((buf, None))
} else {
let mut offset = 0;
let chdr = CompressionHeader::parse_at(self.endian, self.ehdr.class, &mut offset, buf)?;
let chdr = CompressionHeader::parse_at(
self.ehdr.endianness,
self.ehdr.class,
&mut offset,
buf,
)?;
let compressed_buf = buf.get(offset..).ok_or(ParseError::SliceReadError((
offset,
shdr.sh_size.try_into()?,
@ -353,7 +355,7 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
// Validate entsize before trying to read the table so that we can error early for corrupted files
Symbol::validate_entsize(self.ehdr.class, shdr.sh_entsize.try_into()?)?;
let symtab = SymbolTable::new(
self.endian,
self.ehdr.endianness,
self.ehdr.class,
self.reader.get_bytes(symtab_start..symtab_end),
);
@ -391,7 +393,11 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
{
let (start, end) = shdr.get_data_range()?;
let buf = self.reader.read_bytes(start, end)?;
return Ok(Some(DynamicTable::new(self.endian, self.ehdr.class, buf)));
return Ok(Some(DynamicTable::new(
self.ehdr.endianness,
self.ehdr.class,
buf,
)));
}
// Otherwise, look up the PT_DYNAMIC segment (if any)
} else if self.phdrs.len() > 0 {
@ -402,7 +408,11 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
{
let (start, end) = phdr.get_file_data_range()?;
let buf = self.reader.read_bytes(start, end)?;
return Ok(Some(DynamicTable::new(self.endian, self.ehdr.class, buf)));
return Ok(Some(DynamicTable::new(
self.ehdr.endianness,
self.ehdr.class,
buf,
)));
}
}
Ok(None)
@ -501,7 +511,13 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
let (start, end) = shdr.get_data_range()?;
let buf = self.reader.get_bytes(start..end);
Some((
VerNeedIterator::new(self.endian, self.ehdr.class, shdr.sh_info as u64, 0, buf),
VerNeedIterator::new(
self.ehdr.endianness,
self.ehdr.class,
shdr.sh_info as u64,
0,
buf,
),
StringTable::new(strs_buf),
))
}
@ -518,7 +534,13 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
let (start, end) = shdr.get_data_range()?;
let buf = self.reader.get_bytes(start..end);
Some((
VerDefIterator::new(self.endian, self.ehdr.class, shdr.sh_info as u64, 0, buf),
VerDefIterator::new(
self.ehdr.endianness,
self.ehdr.class,
shdr.sh_info as u64,
0,
buf,
),
StringTable::new(strs_buf),
))
}
@ -528,7 +550,7 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
// Wrap the versym section data in a parsing table
let version_ids = VersionIndexTable::new(
self.endian,
self.ehdr.endianness,
self.ehdr.class,
self.reader.get_bytes(versym_start..versym_end),
);
@ -561,7 +583,7 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
let (start, end) = shdr.get_data_range()?;
let buf = self.reader.read_bytes(start, end)?;
Ok(RelIterator::new(self.endian, self.ehdr.class, buf))
Ok(RelIterator::new(self.ehdr.endianness, self.ehdr.class, buf))
}
/// Read the section data for the given
@ -584,7 +606,11 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
let (start, end) = shdr.get_data_range()?;
let buf = self.reader.read_bytes(start, end)?;
Ok(RelaIterator::new(self.endian, self.ehdr.class, buf))
Ok(RelaIterator::new(
self.ehdr.endianness,
self.ehdr.class,
buf,
))
}
/// Read the section data for the given
@ -608,7 +634,7 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
let (start, end) = shdr.get_data_range()?;
let buf = self.reader.read_bytes(start, end)?;
Ok(NoteIterator::new(
self.endian,
self.ehdr.endianness,
self.ehdr.class,
shdr.sh_addralign as usize,
buf,
@ -636,7 +662,7 @@ impl<E: EndianParse, S: std::io::Read + std::io::Seek> ElfStream<E, S> {
let (start, end) = phdr.get_file_data_range()?;
let buf = self.reader.read_bytes(start, end)?;
Ok(NoteIterator::new(
self.endian,
self.ehdr.endianness,
self.ehdr.class,
phdr.p_align as usize,
buf,
@ -1097,7 +1123,8 @@ mod interface_tests {
.section_data(&hash_shdr)
.expect("Failed to get hash section data");
let data_copy: Vec<u8> = data.into();
let hash_table = SysVHashTable::new(file.endian, file.ehdr.class, data_copy.as_ref())
let hash_table =
SysVHashTable::new(file.ehdr.endianness, file.ehdr.class, data_copy.as_ref())
.expect("Failed to parse hash table");
// Get the dynamic symbol table.
@ -1144,7 +1171,7 @@ mod arch_tests {
let mut file = ElfStream::<AnyEndian, _>::open_stream(io).expect("should parse");
assert_eq!(file.ehdr.e_machine, $e_machine);
assert_eq!(file.endian, $endian);
assert_eq!(file.ehdr.endianness, $endian);
let (shdrs, strtab) = file.section_headers_with_strtab().expect("should parse");
let (shdrs, strtab) = (shdrs, strtab.unwrap());

@ -1,6 +1,6 @@
//! Parsing the ELF File Header
use crate::abi;
use crate::endian::{AnyEndian, EndianParse};
use crate::endian::EndianParse;
use crate::parse::ParseError;
/// Represents the ELF file data format (little-endian vs big-endian)
@ -17,11 +17,11 @@ pub enum Class {
/// the width of certain fields (32-bit vs 64-bit), the data endianness, the
/// file type, and more.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FileHeader {
pub struct FileHeader<E: EndianParse> {
/// 32-bit vs 64-bit
pub class: Class,
// file byte order
pub ei_data: u8,
pub endianness: E,
/// elf version
pub version: u32,
/// OS ABI
@ -77,8 +77,6 @@ pub struct FileHeader {
pub const ELF32_EHDR_TAILSIZE: usize = 36;
pub const ELF64_EHDR_TAILSIZE: usize = 48;
// Read the platform-independent ident bytes
impl FileHeader {
fn verify_ident(buf: &[u8]) -> Result<(), ParseError> {
// Verify the magic number
let magic = buf.split_at(abi::EI_CLASS).0;
@ -100,8 +98,8 @@ impl FileHeader {
return Ok(());
}
pub fn parse_ident(data: &[u8]) -> Result<(u8, Class, u8, u8), ParseError> {
Self::verify_ident(data)?;
pub fn parse_ident<E: EndianParse>(data: &[u8]) -> Result<(E, Class, u8, u8), ParseError> {
verify_ident(data)?;
let e_class = data[abi::EI_CLASS];
let class = match e_class {
@ -112,20 +110,20 @@ impl FileHeader {
}
};
// Verify endianness is something we know how to parse
let file_endian = E::from_ei_data(data[abi::EI_DATA])?;
Ok((
data[abi::EI_DATA],
file_endian,
class,
data[abi::EI_OSABI],
data[abi::EI_ABIVERSION],
))
}
pub fn parse_tail(ident: (u8, Class, u8, u8), data: &[u8]) -> Result<FileHeader, ParseError> {
let (ei_data, class, osabi, abiversion) = ident;
let file_endian: AnyEndian;
// Verify endianness is something we know how to parse
file_endian = AnyEndian::from_ei_data(ei_data)?;
impl<E: EndianParse> FileHeader<E> {
pub fn parse_tail(ident: (E, Class, u8, u8), data: &[u8]) -> Result<FileHeader<E>, ParseError> {
let (file_endian, class, osabi, abiversion) = ident;
let mut offset = 0;
let e_type = file_endian.parse_u16_at(&mut offset, data)?;
@ -156,7 +154,7 @@ impl FileHeader {
Ok(FileHeader {
class,
ei_data,
endianness: file_endian,
version,
e_type,
e_machine,
@ -179,6 +177,7 @@ impl FileHeader {
#[cfg(test)]
mod parse_tests {
use super::*;
use crate::endian::AnyEndian;
#[test]
fn test_verify_ident_valid() {
@ -200,7 +199,7 @@ mod parse_tests {
0,
0,
];
FileHeader::verify_ident(&mut data.as_ref()).expect("Expected Ok result");
verify_ident(&mut data.as_ref()).expect("Expected Ok result");
}
#[test]
@ -223,7 +222,7 @@ mod parse_tests {
0,
0,
];
let result = FileHeader::verify_ident(&mut data.as_ref()).expect_err("Expected an error");
let result = verify_ident(&mut data.as_ref()).expect_err("Expected an error");
assert!(
matches!(result, ParseError::BadMagic(_)),
"Unexpected Error type found: {result}"
@ -250,7 +249,7 @@ mod parse_tests {
0,
0,
];
let result = FileHeader::verify_ident(&mut data.as_ref()).expect_err("Expected an error");
let result = verify_ident(&mut data.as_ref()).expect_err("Expected an error");
assert!(
matches!(result, ParseError::BadMagic(_)),
"Unexpected Error type found: {result}"
@ -277,7 +276,7 @@ mod parse_tests {
0,
0,
];
let result = FileHeader::verify_ident(&mut data.as_ref()).expect_err("Expected an error");
let result = verify_ident(&mut data.as_ref()).expect_err("Expected an error");
assert!(
matches!(result, ParseError::BadMagic(_)),
"Unexpected Error type found: {result}"
@ -304,7 +303,7 @@ mod parse_tests {
0,
0,
];
let result = FileHeader::verify_ident(&mut data.as_ref()).expect_err("Expected an error");
let result = verify_ident(&mut data.as_ref()).expect_err("Expected an error");
assert!(
matches!(result, ParseError::BadMagic(_)),
"Unexpected Error type found: {result}"
@ -332,7 +331,7 @@ mod parse_tests {
0,
0,
];
let result = FileHeader::verify_ident(&mut data.as_ref()).expect_err("Expected an error");
let result = verify_ident(&mut data.as_ref()).expect_err("Expected an error");
assert!(
matches!(result, ParseError::UnsupportedVersion((42, 1))),
"Unexpected Error type found: {result}"
@ -341,7 +340,7 @@ mod parse_tests {
#[test]
fn test_parse_ehdr32_works() {
let ident = (abi::ELFDATA2LSB, Class::ELF32, abi::ELFOSABI_LINUX, 7u8);
let ident = (AnyEndian::Little, Class::ELF32, abi::ELFOSABI_LINUX, 7u8);
let mut tail = [0u8; ELF64_EHDR_TAILSIZE];
for n in 0..ELF64_EHDR_TAILSIZE {
tail[n] = n as u8;
@ -351,7 +350,7 @@ mod parse_tests {
FileHeader::parse_tail(ident, &tail).unwrap(),
FileHeader {
class: Class::ELF32,
ei_data: abi::ELFDATA2LSB,
endianness: AnyEndian::Little,
version: 0x7060504,
osabi: abi::ELFOSABI_LINUX,
abiversion: 7,
@ -373,7 +372,7 @@ mod parse_tests {
#[test]
fn test_parse_ehdr32_fuzz_too_short() {
let ident = (abi::ELFDATA2LSB, Class::ELF32, abi::ELFOSABI_LINUX, 7u8);
let ident = (AnyEndian::Little, Class::ELF32, abi::ELFOSABI_LINUX, 7u8);
let tail = [0u8; ELF32_EHDR_TAILSIZE];
for n in 0..ELF32_EHDR_TAILSIZE {
@ -388,7 +387,7 @@ mod parse_tests {
#[test]
fn test_parse_ehdr64_works() {
let ident = (abi::ELFDATA2MSB, Class::ELF64, abi::ELFOSABI_LINUX, 7u8);
let ident = (AnyEndian::Big, Class::ELF64, abi::ELFOSABI_LINUX, 7u8);
let mut tail = [0u8; ELF64_EHDR_TAILSIZE];
for n in 0..ELF64_EHDR_TAILSIZE {
tail[n] = n as u8;
@ -398,7 +397,7 @@ mod parse_tests {
FileHeader::parse_tail(ident, &tail).unwrap(),
FileHeader {
class: Class::ELF64,
ei_data: abi::ELFDATA2MSB,
endianness: AnyEndian::Big,
version: 0x04050607,
osabi: abi::ELFOSABI_LINUX,
abiversion: 7,
@ -420,7 +419,7 @@ mod parse_tests {
#[test]
fn test_parse_ehdr64_fuzz_too_short() {
let ident = (abi::ELFDATA2LSB, Class::ELF64, abi::ELFOSABI_LINUX, 7u8);
let ident = (AnyEndian::Little, Class::ELF64, abi::ELFOSABI_LINUX, 7u8);
let tail = [0u8; ELF64_EHDR_TAILSIZE];
for n in 0..ELF64_EHDR_TAILSIZE {