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:
parent
4875ff8981
commit
19e7f685c8
@ -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());
|
||||
|
53
src/file.rs
53
src/file.rs
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user