Add File::section_headers() iterator method for lazy header parsing
When called, this reads the section header table and wraps the data reference in an iterator which lazily parses SectionHeader structs out of it.
This commit is contained in:
parent
bab7e10ca4
commit
6ec11531d2
31
src/file.rs
31
src/file.rs
@ -54,6 +54,37 @@ impl<R: ReadBytesAt> File<R> {
|
||||
))
|
||||
}
|
||||
|
||||
/// Get an iterator over the Section Headers in the file.
|
||||
///
|
||||
/// The underlying ELF bytes backing the segment table are read all at once
|
||||
/// when the iterator is requested, but parsing is deferred to be lazily
|
||||
/// parsed on demand on each Iterator::next() call.
|
||||
///
|
||||
/// Returns a `ParseError` if the data bytes for the segment table cannot be
|
||||
/// read i.e. if the ELF [FileHeader]'s
|
||||
/// [e_shnum](FileHeader#structfield.e_shnum),
|
||||
/// [e_shoff](FileHeader#structfield.e_shoff),
|
||||
/// [e_shentsize](FileHeader#structfield.e_shentsize) are invalid and point
|
||||
/// to a range in the file data that does not actually exist.
|
||||
pub fn section_headers(&mut self) -> Result<section::SectionHeaderIterator, ParseError> {
|
||||
if self.ehdr.e_shnum == 0 {
|
||||
return Ok(section::SectionHeaderIterator::new(
|
||||
self.ehdr.endianness,
|
||||
self.ehdr.class,
|
||||
&[],
|
||||
));
|
||||
}
|
||||
|
||||
let start = self.ehdr.e_shoff as usize;
|
||||
let size = self.ehdr.e_shentsize as usize * self.ehdr.e_shnum as usize;
|
||||
let buf = self.reader.read_bytes_at(start..start + size)?;
|
||||
Ok(section::SectionHeaderIterator::new(
|
||||
self.ehdr.endianness,
|
||||
self.ehdr.class,
|
||||
buf,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn sections(&self) -> Result<§ion::SectionTable, ParseError> {
|
||||
Ok(&self.sections)
|
||||
}
|
||||
|
121
src/section.rs
121
src/section.rs
@ -3,6 +3,36 @@ use crate::gabi;
|
||||
use crate::parse::{Class, Endian, ParseAtExt, ParseError, ReadBytesAt};
|
||||
use crate::string_table::StringTable;
|
||||
|
||||
pub struct SectionHeaderIterator<'data> {
|
||||
endianness: Endian,
|
||||
class: Class,
|
||||
data: &'data [u8],
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<'data> SectionHeaderIterator<'data> {
|
||||
pub fn new(endianness: Endian, class: Class, data: &'data [u8]) -> Self {
|
||||
SectionHeaderIterator {
|
||||
endianness,
|
||||
class,
|
||||
data,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'data> Iterator for SectionHeaderIterator<'data> {
|
||||
type Item = SectionHeader;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.data.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
SectionHeader::parse_at(self.endianness, self.class, &mut self.offset, &self.data).ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SectionTable {
|
||||
headers: Vec<SectionHeader>,
|
||||
@ -386,6 +416,97 @@ mod table_tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod iter_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn get_32_lsb() {
|
||||
// init data buf with two header's worth of increasing byte values
|
||||
let mut data = [0u8; 2 * ELF32SHDRSIZE as usize];
|
||||
for n in 0..(2 * ELF32SHDRSIZE) {
|
||||
data[n as usize] = n as u8;
|
||||
}
|
||||
let mut iter = SectionHeaderIterator::new(Endian::Little, Class::ELF32, &data);
|
||||
|
||||
assert_eq!(
|
||||
iter.next().unwrap(),
|
||||
SectionHeader {
|
||||
sh_name: 0x03020100,
|
||||
sh_type: SectionType(0x07060504),
|
||||
sh_flags: SectionFlag(0xB0A0908),
|
||||
sh_addr: 0x0F0E0D0C,
|
||||
sh_offset: 0x13121110,
|
||||
sh_size: 0x17161514,
|
||||
sh_link: 0x1B1A1918,
|
||||
sh_info: 0x1F1E1D1C,
|
||||
sh_addralign: 0x23222120,
|
||||
sh_entsize: 0x27262524,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next().unwrap(),
|
||||
SectionHeader {
|
||||
sh_name: 0x2B2A2928,
|
||||
sh_type: SectionType(0x2F2E2D2C),
|
||||
sh_flags: SectionFlag(0x33323130),
|
||||
sh_addr: 0x37363534,
|
||||
sh_offset: 0x3B3A3938,
|
||||
sh_size: 0x3F3E3D3C,
|
||||
sh_link: 0x43424140,
|
||||
sh_info: 0x47464544,
|
||||
sh_addralign: 0x4B4A4948,
|
||||
sh_entsize: 0x4F4E4D4C,
|
||||
}
|
||||
);
|
||||
let next = iter.next();
|
||||
assert!(next.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_64_msb() {
|
||||
// init data buf with two header's worth of increasing byte values
|
||||
let mut data = [0u8; 2 * ELF64SHDRSIZE as usize];
|
||||
for n in 0..(2 * ELF64SHDRSIZE) {
|
||||
data[n as usize] = n as u8;
|
||||
}
|
||||
let mut iter = SectionHeaderIterator::new(Endian::Big, Class::ELF64, &data);
|
||||
|
||||
assert_eq!(
|
||||
iter.next().unwrap(),
|
||||
SectionHeader {
|
||||
sh_name: 0x00010203,
|
||||
sh_type: SectionType(0x04050607),
|
||||
sh_flags: SectionFlag(0x08090A0B0C0D0E0F),
|
||||
sh_addr: 0x1011121314151617,
|
||||
sh_offset: 0x18191A1B1C1D1E1F,
|
||||
sh_size: 0x2021222324252627,
|
||||
sh_link: 0x28292A2B,
|
||||
sh_info: 0x2C2D2E2F,
|
||||
sh_addralign: 0x3031323334353637,
|
||||
sh_entsize: 0x38393A3B3C3D3E3F,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next().unwrap(),
|
||||
SectionHeader {
|
||||
sh_name: 0x40414243,
|
||||
sh_type: SectionType(0x44454647),
|
||||
sh_flags: SectionFlag(0x48494A4B4C4D4E4F),
|
||||
sh_addr: 0x5051525354555657,
|
||||
sh_offset: 0x58595A5B5C5D5E5F,
|
||||
sh_size: 0x6061626364656667,
|
||||
sh_link: 0x68696A6B,
|
||||
sh_info: 0x6C6D6E6F,
|
||||
sh_addralign: 0x7071727374757677,
|
||||
sh_entsize: 0x78797A7B7C7D7E7F,
|
||||
}
|
||||
);
|
||||
let next = iter.next();
|
||||
assert!(next.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod shdr_tests {
|
||||
use super::*;
|
||||
|
Loading…
x
Reference in New Issue
Block a user