Change File::segments() to return an iterator
This avoids the up front Vec allocation and parsing in favor of lazily parsing ProgramHeaders iteratively out of the segment table bytes that were read from the file. I opted to read the whole segment table up front with the thought that one larger for the whole table I/O is likely faster than lots of small I/Os to get each phdr, though that assumes that the segment table isn't huge (multi-MBs) which is likely the common case.
This commit is contained in:
parent
40fd8d39bf
commit
0f60bec6db
30
src/file.rs
30
src/file.rs
@ -28,29 +28,23 @@ impl<'data, D: Read + Seek> File<D> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn segments(&mut self) -> Result<Vec<segment::ProgramHeader>, ParseError> {
|
||||
let phnum = self.ehdr.e_phnum as usize;
|
||||
// It's OK to have zero segments
|
||||
if phnum == 0 {
|
||||
return Ok(Vec::<segment::ProgramHeader>::default());
|
||||
pub fn segments(&mut self) -> Result<segment::SegmentIterator, ParseError> {
|
||||
if self.ehdr.e_phnum == 0 {
|
||||
return Ok(segment::SegmentIterator::new(
|
||||
self.ehdr.endianness,
|
||||
self.ehdr.class,
|
||||
&[],
|
||||
));
|
||||
}
|
||||
|
||||
let start = self.ehdr.e_phoff as usize;
|
||||
let size = self.ehdr.e_phentsize as usize * self.ehdr.e_phnum as usize;
|
||||
let buf = self.reader.read_bytes_at(start..start + size)?;
|
||||
|
||||
let mut offset = 0;
|
||||
let mut phdrs = Vec::<segment::ProgramHeader>::with_capacity(phnum);
|
||||
for _ in 0..phnum {
|
||||
let phdr = segment::ProgramHeader::parse_at(
|
||||
self.ehdr.endianness,
|
||||
self.ehdr.class,
|
||||
&mut offset,
|
||||
&buf,
|
||||
)?;
|
||||
phdrs.push(phdr);
|
||||
}
|
||||
Ok(phdrs)
|
||||
Ok(segment::SegmentIterator::new(
|
||||
self.ehdr.endianness,
|
||||
self.ehdr.class,
|
||||
buf,
|
||||
))
|
||||
}
|
||||
|
||||
/// Get the string table for the section headers
|
||||
|
@ -1,6 +1,36 @@
|
||||
use crate::gabi;
|
||||
use crate::parse::{Class, Endian, ParseAtExt, ParseError};
|
||||
|
||||
pub struct SegmentIterator<'data> {
|
||||
endianness: Endian,
|
||||
class: Class,
|
||||
data: &'data [u8],
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<'data> SegmentIterator<'data> {
|
||||
pub fn new(endianness: Endian, class: Class, data: &'data [u8]) -> Self {
|
||||
SegmentIterator {
|
||||
endianness,
|
||||
class,
|
||||
data,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'data> Iterator for SegmentIterator<'data> {
|
||||
type Item = ProgramHeader;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.data.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
ProgramHeader::parse_at(self.endianness, self.class, &mut self.offset, &self.data).ok()
|
||||
}
|
||||
}
|
||||
|
||||
/// Encapsulates the contents of an ELF Program Header
|
||||
///
|
||||
/// The program header table is an array of program header structures describing
|
||||
|
Loading…
x
Reference in New Issue
Block a user