Change the Parse trait to take a ReadExt
This eliminates the Endian argument from Parse::parse by bundling it into the ReadExt's responsibility and allows implementors of Parse to not have to care about endianness and plumbing it around correctly. Also, change FileHeader::parse to no longer implement Parse. It previously needed to take bogus unused Endian and Class specifications. There's a unique bootstrapping situation with parsing the FileHeader, as it is the structure that informs the Endian and Class specifications used by all the other parsers. I opted to simply make this implement parse() (but not for the trait Parse) by taking the underlying delegate reader rather than a ReadExt which seemed intuitive to me.
This commit is contained in:
parent
79a54e21cb
commit
3fc22a31bf
40
src/file.rs
40
src/file.rs
@ -1,5 +1,5 @@
|
||||
use crate::gabi;
|
||||
use crate::parse::{Endian, Parse, Reader, ReadExt};
|
||||
use crate::parse::{Endian, Reader, ReadExt};
|
||||
|
||||
/// Encapsulates the contents of the ELF File Header
|
||||
///
|
||||
@ -97,13 +97,8 @@ impl FileHeader {
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Parse<R> for FileHeader
|
||||
where
|
||||
R: std::io::Read,
|
||||
{
|
||||
fn parse(_endian: Endian, _class: Class, reader: &mut R) -> Result<Self, crate::ParseError> {
|
||||
pub fn parse<R: std::io::Read>(reader: &mut R) -> Result<Self, crate::ParseError> {
|
||||
let mut ident = [0u8; gabi::EI_NIDENT];
|
||||
Self::parse_ident(reader, &mut ident)?;
|
||||
|
||||
@ -111,7 +106,7 @@ where
|
||||
let endian = if ident[gabi::EI_DATA] == gabi::ELFDATA2LSB { Endian::Little } else { Endian::Big };
|
||||
|
||||
let mut io_r = Reader::new(reader, endian);
|
||||
|
||||
|
||||
let elftype = ObjectFileType(io_r.read_u16()?);
|
||||
let arch = Architecture(io_r.read_u16()?);
|
||||
let version = io_r.read_u32()?;
|
||||
@ -473,7 +468,6 @@ impl std::fmt::Display for Architecture {
|
||||
mod tests {
|
||||
use crate::file::{Architecture, Class, Endian, FileHeader, ObjectFileType, OSABI};
|
||||
use crate::gabi;
|
||||
use crate::parse::Parse;
|
||||
|
||||
#[test]
|
||||
fn test_parse_ident_empty_buf_errors() {
|
||||
@ -653,12 +647,7 @@ mod tests {
|
||||
|
||||
let slice: &mut [u8] = data.as_mut_slice();
|
||||
assert_eq!(
|
||||
FileHeader::parse(
|
||||
Endian::Little,
|
||||
Class(gabi::ELFCLASSNONE),
|
||||
&mut slice.as_ref()
|
||||
)
|
||||
.unwrap(),
|
||||
FileHeader::parse(&mut slice.as_ref()).unwrap(),
|
||||
FileHeader {
|
||||
class: Class(gabi::ELFCLASS32),
|
||||
endianness: Endian::Little,
|
||||
@ -705,12 +694,7 @@ mod tests {
|
||||
|
||||
for n in 0..36 {
|
||||
let slice = data.as_mut_slice().split_at(gabi::EI_NIDENT + n).0;
|
||||
assert!(FileHeader::parse(
|
||||
Endian::Little,
|
||||
Class(gabi::ELFCLASSNONE),
|
||||
&mut slice.as_ref()
|
||||
)
|
||||
.is_err());
|
||||
assert!(FileHeader::parse(&mut slice.as_ref()).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@ -741,12 +725,7 @@ mod tests {
|
||||
|
||||
let slice: &mut [u8] = data.as_mut_slice();
|
||||
assert_eq!(
|
||||
FileHeader::parse(
|
||||
Endian::Little,
|
||||
Class(gabi::ELFCLASSNONE),
|
||||
&mut slice.as_ref()
|
||||
)
|
||||
.unwrap(),
|
||||
FileHeader::parse(&mut slice.as_ref()).unwrap(),
|
||||
FileHeader {
|
||||
class: Class(gabi::ELFCLASS64),
|
||||
endianness: Endian::Big,
|
||||
@ -793,12 +772,7 @@ mod tests {
|
||||
|
||||
for n in 0..48 {
|
||||
let slice = data.as_mut_slice().split_at(gabi::EI_NIDENT + n).0;
|
||||
assert!(FileHeader::parse(
|
||||
Endian::Little,
|
||||
Class(gabi::ELFCLASSNONE),
|
||||
&mut slice.as_ref()
|
||||
)
|
||||
.is_err());
|
||||
assert!(FileHeader::parse(&mut slice.as_ref()).is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
src/lib.rs
10
src/lib.rs
@ -10,7 +10,7 @@ pub mod section;
|
||||
pub mod symbol;
|
||||
pub mod parse;
|
||||
|
||||
use crate::parse::{Endian, Parse, read_u16, read_u32, read_u64};
|
||||
use crate::parse::{Parse, Reader, read_u16, read_u32, read_u64};
|
||||
|
||||
mod utils;
|
||||
|
||||
@ -73,14 +73,15 @@ impl File {
|
||||
}
|
||||
|
||||
pub fn open_stream<T: Read + Seek>(io_file: &mut T) -> Result<File, ParseError> {
|
||||
let ehdr = file::FileHeader::parse(Endian::Little, file::Class(gabi::ELFCLASSNONE), io_file)?;
|
||||
let ehdr = file::FileHeader::parse(io_file)?;
|
||||
|
||||
// Parse the program headers
|
||||
io_file.seek(io::SeekFrom::Start(ehdr.e_phoff))?;
|
||||
let mut phdrs = Vec::<segment::ProgramHeader>::default();
|
||||
|
||||
for _ in 0..ehdr.e_phnum {
|
||||
let phdr = segment::ProgramHeader::parse(ehdr.endianness, ehdr.class, io_file)?;
|
||||
let mut reader = Reader::new(io_file, ehdr.endianness);
|
||||
let phdr = segment::ProgramHeader::parse(ehdr.class, &mut reader)?;
|
||||
phdrs.push(phdr);
|
||||
}
|
||||
|
||||
@ -89,7 +90,8 @@ impl File {
|
||||
// Parse the section headers
|
||||
io_file.seek(io::SeekFrom::Start(ehdr.e_shoff))?;
|
||||
for _ in 0..ehdr.e_shnum {
|
||||
let shdr = section::SectionHeader::parse(ehdr.endianness, ehdr.class, io_file)?;
|
||||
let mut reader = Reader::new(io_file, ehdr.endianness);
|
||||
let shdr = section::SectionHeader::parse(ehdr.class, &mut reader)?;
|
||||
sections.push(
|
||||
Section {
|
||||
name: String::new(),
|
||||
|
@ -98,9 +98,9 @@ pub fn read_u64<T: std::io::Read>(endian: Endian, io: &mut T) -> Result<u64, Par
|
||||
}
|
||||
|
||||
pub trait Parse<R>: Copy {
|
||||
fn parse(endian: Endian, class: Class, reader: &mut R) -> Result<Self, crate::ParseError>
|
||||
fn parse(class: Class, reader: &mut R) -> Result<Self, crate::ParseError>
|
||||
where
|
||||
R: std::io::Read;
|
||||
R: ReadExt;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::file::Class;
|
||||
use crate::gabi;
|
||||
use crate::parse::{Endian, Parse, Reader, ReadExt};
|
||||
use crate::parse::{Parse, ReadExt};
|
||||
|
||||
/// Encapsulates the contents of an ELF Section Header
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
@ -29,36 +29,35 @@ pub struct SectionHeader {
|
||||
|
||||
impl<R> Parse<R> for SectionHeader
|
||||
where
|
||||
R: std::io::Read,
|
||||
R: ReadExt,
|
||||
{
|
||||
fn parse(endian: Endian, class: Class, reader: &mut R) -> Result<Self, crate::ParseError> {
|
||||
let mut io_r = Reader::new(reader, endian);
|
||||
fn parse(class: Class, reader: &mut R) -> Result<Self, crate::ParseError> {
|
||||
if class == gabi::ELFCLASS32 {
|
||||
return Ok(SectionHeader {
|
||||
sh_name: io_r.read_u32()?,
|
||||
sh_type: SectionType(io_r.read_u32()?),
|
||||
sh_flags: SectionFlag(io_r.read_u32()? as u64),
|
||||
sh_addr: io_r.read_u32()? as u64,
|
||||
sh_offset: io_r.read_u32()? as u64,
|
||||
sh_size: io_r.read_u32()? as u64,
|
||||
sh_link: io_r.read_u32()?,
|
||||
sh_info: io_r.read_u32()?,
|
||||
sh_addralign: io_r.read_u32()? as u64,
|
||||
sh_entsize: io_r.read_u32()? as u64,
|
||||
sh_name: reader.read_u32()?,
|
||||
sh_type: SectionType(reader.read_u32()?),
|
||||
sh_flags: SectionFlag(reader.read_u32()? as u64),
|
||||
sh_addr: reader.read_u32()? as u64,
|
||||
sh_offset: reader.read_u32()? as u64,
|
||||
sh_size: reader.read_u32()? as u64,
|
||||
sh_link: reader.read_u32()?,
|
||||
sh_info: reader.read_u32()?,
|
||||
sh_addralign: reader.read_u32()? as u64,
|
||||
sh_entsize: reader.read_u32()? as u64,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(SectionHeader {
|
||||
sh_name: io_r.read_u32()?,
|
||||
sh_type: SectionType(io_r.read_u32()?),
|
||||
sh_flags: SectionFlag(io_r.read_u64()?),
|
||||
sh_addr: io_r.read_u64()?,
|
||||
sh_offset: io_r.read_u64()?,
|
||||
sh_size: io_r.read_u64()?,
|
||||
sh_link: io_r.read_u32()?,
|
||||
sh_info: io_r.read_u32()?,
|
||||
sh_addralign: io_r.read_u64()?,
|
||||
sh_entsize: io_r.read_u64()?,
|
||||
sh_name: reader.read_u32()?,
|
||||
sh_type: SectionType(reader.read_u32()?),
|
||||
sh_flags: SectionFlag(reader.read_u64()?),
|
||||
sh_addr: reader.read_u64()?,
|
||||
sh_offset: reader.read_u64()?,
|
||||
sh_size: reader.read_u64()?,
|
||||
sh_link: reader.read_u32()?,
|
||||
sh_info: reader.read_u32()?,
|
||||
sh_addralign: reader.read_u64()?,
|
||||
sh_entsize: reader.read_u64()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -136,20 +135,16 @@ impl std::fmt::Display for SectionFlag {
|
||||
mod tests {
|
||||
use crate::file::Class;
|
||||
use crate::gabi;
|
||||
use crate::parse::{Endian, Parse};
|
||||
use crate::parse::{Endian, Parse, Reader};
|
||||
use crate::section::{SectionFlag, SectionHeader, SectionType};
|
||||
|
||||
#[test]
|
||||
fn parse_shdr32_fuzz_too_short() {
|
||||
let data = [0u8; 40];
|
||||
for n in 0..40 {
|
||||
let slice = data.split_at(n).0;
|
||||
assert!(SectionHeader::parse(
|
||||
Endian::Little,
|
||||
Class(gabi::ELFCLASS32),
|
||||
&mut slice.as_ref()
|
||||
)
|
||||
.is_err());
|
||||
let mut slice = data.split_at(n).0.as_ref();
|
||||
let mut reader = Reader::new(&mut slice, Endian::Little);
|
||||
assert!(SectionHeader::parse(Class(gabi::ELFCLASS32), &mut reader).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,13 +155,10 @@ mod tests {
|
||||
data[n as usize] = n;
|
||||
}
|
||||
|
||||
let mut slice = data.as_ref();
|
||||
let mut reader = Reader::new(&mut slice, Endian::Little);
|
||||
assert_eq!(
|
||||
SectionHeader::parse(
|
||||
Endian::Little,
|
||||
Class(gabi::ELFCLASS32),
|
||||
&mut data.as_ref()
|
||||
)
|
||||
.unwrap(),
|
||||
SectionHeader::parse(Class(gabi::ELFCLASS32), &mut reader).unwrap(),
|
||||
SectionHeader {
|
||||
sh_name: 0x03020100,
|
||||
sh_type: SectionType(0x07060504),
|
||||
@ -186,13 +178,9 @@ mod tests {
|
||||
fn parse_shdr64_fuzz_too_short() {
|
||||
let data = [0u8; 64];
|
||||
for n in 0..64 {
|
||||
let slice = data.split_at(n).0;
|
||||
assert!(SectionHeader::parse(
|
||||
Endian::Big,
|
||||
Class(gabi::ELFCLASS64),
|
||||
&mut slice.as_ref()
|
||||
)
|
||||
.is_err());
|
||||
let mut slice = data.split_at(n).0.as_ref();
|
||||
let mut reader = Reader::new(&mut slice, Endian::Big);
|
||||
assert!(SectionHeader::parse(Class(gabi::ELFCLASS64), &mut reader).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,13 +191,10 @@ mod tests {
|
||||
data[n as usize] = n;
|
||||
}
|
||||
|
||||
let mut slice = data.as_ref();
|
||||
let mut reader = Reader::new(&mut slice, Endian::Big);
|
||||
assert_eq!(
|
||||
SectionHeader::parse(
|
||||
Endian::Big,
|
||||
Class(gabi::ELFCLASS64),
|
||||
&mut data.as_ref()
|
||||
)
|
||||
.unwrap(),
|
||||
SectionHeader::parse(Class(gabi::ELFCLASS64), &mut reader).unwrap(),
|
||||
SectionHeader {
|
||||
sh_name: 0x00010203,
|
||||
sh_type: SectionType(0x04050607),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::file::Class;
|
||||
use crate::gabi;
|
||||
use crate::parse::{Endian, Parse, Reader, ReadExt};
|
||||
use crate::parse::{Parse, ReadExt};
|
||||
|
||||
/// Encapsulates the contents of an ELF Program Header
|
||||
///
|
||||
@ -28,19 +28,18 @@ pub struct ProgramHeader {
|
||||
|
||||
impl<R> Parse<R> for ProgramHeader
|
||||
where
|
||||
R: std::io::Read,
|
||||
R: ReadExt,
|
||||
{
|
||||
fn parse(endian: Endian, class: Class, reader: &mut R) -> Result<Self, crate::ParseError> {
|
||||
let mut io_r = Reader::new(reader, endian);
|
||||
fn parse(class: Class, reader: &mut R) -> Result<Self, crate::ParseError> {
|
||||
if class == gabi::ELFCLASS32 {
|
||||
let p_type = io_r.read_u32()?;
|
||||
let p_offset = io_r.read_u32()?;
|
||||
let p_vaddr = io_r.read_u32()?;
|
||||
let p_paddr = io_r.read_u32()?;
|
||||
let p_filesz = io_r.read_u32()?;
|
||||
let p_memsz = io_r.read_u32()?;
|
||||
let p_flags = io_r.read_u32()?;
|
||||
let p_align = io_r.read_u32()?;
|
||||
let p_type = reader.read_u32()?;
|
||||
let p_offset = reader.read_u32()?;
|
||||
let p_vaddr = reader.read_u32()?;
|
||||
let p_paddr = reader.read_u32()?;
|
||||
let p_filesz = reader.read_u32()?;
|
||||
let p_memsz = reader.read_u32()?;
|
||||
let p_flags = reader.read_u32()?;
|
||||
let p_align = reader.read_u32()?;
|
||||
return Ok(ProgramHeader {
|
||||
progtype: ProgType(p_type),
|
||||
offset: p_offset as u64,
|
||||
@ -53,14 +52,14 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
let p_type = io_r.read_u32()?;
|
||||
let p_flags = io_r.read_u32()?;
|
||||
let p_offset = io_r.read_u64()?;
|
||||
let p_vaddr = io_r.read_u64()?;
|
||||
let p_paddr = io_r.read_u64()?;
|
||||
let p_filesz = io_r.read_u64()?;
|
||||
let p_memsz = io_r.read_u64()?;
|
||||
let p_align = io_r.read_u64()?;
|
||||
let p_type = reader.read_u32()?;
|
||||
let p_flags = reader.read_u32()?;
|
||||
let p_offset = reader.read_u64()?;
|
||||
let p_vaddr = reader.read_u64()?;
|
||||
let p_paddr = reader.read_u64()?;
|
||||
let p_filesz = reader.read_u64()?;
|
||||
let p_memsz = reader.read_u64()?;
|
||||
let p_align = reader.read_u64()?;
|
||||
Ok(ProgramHeader {
|
||||
progtype: ProgType(p_type),
|
||||
offset: p_offset,
|
||||
@ -146,20 +145,16 @@ impl std::fmt::Display for ProgType {
|
||||
mod tests {
|
||||
use crate::file::Class;
|
||||
use crate::gabi;
|
||||
use crate::parse::{Endian, Parse};
|
||||
use crate::parse::{Endian, Parse, Reader};
|
||||
use crate::segment::{ProgFlag, ProgType, ProgramHeader};
|
||||
|
||||
#[test]
|
||||
fn parse_phdr32_fuzz_too_short() {
|
||||
let data = [0u8; 32];
|
||||
for n in 0..32 {
|
||||
let slice = data.split_at(n).0;
|
||||
assert!(ProgramHeader::parse(
|
||||
Endian::Little,
|
||||
Class(gabi::ELFCLASS32),
|
||||
&mut slice.as_ref()
|
||||
)
|
||||
.is_err());
|
||||
let mut slice = data.split_at(n).0.as_ref();
|
||||
let mut reader = Reader::new(&mut slice, Endian::Little);
|
||||
assert!(ProgramHeader::parse(Class(gabi::ELFCLASS32), &mut reader).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,13 +165,10 @@ mod tests {
|
||||
data[n as usize] = n;
|
||||
}
|
||||
|
||||
let mut slice = data.as_ref();
|
||||
let mut reader = Reader::new(&mut slice, Endian::Little);
|
||||
assert_eq!(
|
||||
ProgramHeader::parse(
|
||||
Endian::Little,
|
||||
Class(gabi::ELFCLASS32),
|
||||
&mut data.as_ref()
|
||||
)
|
||||
.unwrap(),
|
||||
ProgramHeader::parse(Class(gabi::ELFCLASS32), &mut reader).unwrap(),
|
||||
ProgramHeader {
|
||||
progtype: ProgType(0x03020100),
|
||||
offset: 0x07060504,
|
||||
@ -194,13 +186,9 @@ mod tests {
|
||||
fn parse_phdr64_fuzz_too_short() {
|
||||
let data = [0u8; 56];
|
||||
for n in 0..56 {
|
||||
let slice = data.split_at(n).0;
|
||||
assert!(ProgramHeader::parse(
|
||||
Endian::Big,
|
||||
Class(gabi::ELFCLASS64),
|
||||
&mut slice.as_ref()
|
||||
)
|
||||
.is_err());
|
||||
let mut slice = data.split_at(n).0.as_ref();
|
||||
let mut reader = Reader::new(&mut slice, Endian::Big);
|
||||
assert!(ProgramHeader::parse(Class(gabi::ELFCLASS64), &mut reader).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,13 +199,10 @@ mod tests {
|
||||
data[n as usize] = n;
|
||||
}
|
||||
|
||||
let mut slice = data.as_ref();
|
||||
let mut reader = Reader::new(&mut slice, Endian::Big);
|
||||
assert_eq!(
|
||||
ProgramHeader::parse(
|
||||
Endian::Big,
|
||||
Class(gabi::ELFCLASS64),
|
||||
&mut data.as_ref()
|
||||
)
|
||||
.unwrap(),
|
||||
ProgramHeader::parse(Class(gabi::ELFCLASS64), &mut reader).unwrap(),
|
||||
ProgramHeader {
|
||||
progtype: ProgType(0x00010203),
|
||||
offset: 0x08090A0B0C0D0E0F,
|
||||
|
Loading…
x
Reference in New Issue
Block a user