Move endianness-aware read_u* parsing methods into parse.rs

This is getting us closer to having a more centralized trait-driven parser combinator approach
that can hopefully clean up the code a bit and make it easier to follow.
This commit is contained in:
Christopher Cole 2022-10-06 18:02:24 -07:00
parent eca60d8f49
commit e14e083ad3
6 changed files with 116 additions and 121 deletions

View File

@ -1,6 +1,5 @@
use crate::gabi;
use crate::parse::{Endian, Parse};
use crate::utils::{read_u16, read_u32, read_u64};
use crate::parse::{Endian, Parse, read_u16, read_u32, read_u64};
/// Encapsulates the contents of the ELF File Header
///

View File

@ -10,7 +10,7 @@ pub mod section;
pub mod symbol;
pub mod parse;
use crate::parse::{Endian, Parse};
use crate::parse::{Endian, Parse, read_u16, read_u32, read_u64};
mod utils;
@ -143,19 +143,19 @@ impl File {
let mut other: [u8; 1] = [0u8];
if self.ehdr.class == gabi::ELFCLASS32 {
name = utils::read_u32(self.ehdr.endianness, io_section)?;
value = utils::read_u32(self.ehdr.endianness, io_section)? as u64;
size = utils::read_u32(self.ehdr.endianness, io_section)? as u64;
name = read_u32(self.ehdr.endianness, io_section)?;
value = read_u32(self.ehdr.endianness, io_section)? as u64;
size = read_u32(self.ehdr.endianness, io_section)? as u64;
io_section.read_exact(&mut info)?;
io_section.read_exact(&mut other)?;
shndx = utils::read_u16(self.ehdr.endianness, io_section)?;
shndx = read_u16(self.ehdr.endianness, io_section)?;
} else {
name = utils::read_u32(self.ehdr.endianness, io_section)?;
name = read_u32(self.ehdr.endianness, io_section)?;
io_section.read_exact(&mut info)?;
io_section.read_exact(&mut other)?;
shndx = utils::read_u16(self.ehdr.endianness, io_section)?;
value = utils::read_u64(self.ehdr.endianness, io_section)?;
size = utils::read_u64(self.ehdr.endianness, io_section)?;
shndx = read_u16(self.ehdr.endianness, io_section)?;
value = read_u64(self.ehdr.endianness, io_section)?;
size = read_u64(self.ehdr.endianness, io_section)?;
}
symbols.push(symbol::Symbol {

View File

@ -1,4 +1,5 @@
use crate::file::Class;
use crate::ParseError;
/// Represents the ELF file data format (little-endian vs big-endian)
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@ -17,8 +18,110 @@ impl std::fmt::Display for Endian {
}
}
#[inline]
pub fn read_u16<T: std::io::Read>(endian: Endian, io: &mut T) -> Result<u16, ParseError> {
let mut buf = [0u8; 2];
io.read_exact(&mut buf)?;
match endian {
Endian::Little => Ok(u16::from_le_bytes(buf)),
Endian::Big => Ok(u16::from_be_bytes(buf)),
}
}
#[inline]
pub fn read_u32<T: std::io::Read>(endian: Endian, io: &mut T) -> Result<u32, ParseError> {
let mut buf = [0u8; 4];
io.read_exact(&mut buf)?;
match endian {
Endian::Little => Ok(u32::from_le_bytes(buf)),
Endian::Big => Ok(u32::from_be_bytes(buf)),
}
}
#[inline]
pub fn read_u64<T: std::io::Read>(endian: Endian, io: &mut T) -> Result<u64, ParseError> {
let mut buf = [0u8; 8];
io.read_exact(&mut buf)?;
match endian {
Endian::Little => Ok(u64::from_le_bytes(buf)),
Endian::Big => Ok(u64::from_be_bytes(buf)),
}
}
pub trait Parse<R>: Copy {
fn parse(endian: Endian, class: Class, reader: &mut R) -> Result<Self, crate::ParseError>
where
R: std::io::Read;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_read_u16_lsb() {
let data = [0x10u8, 0x20u8];
let result = read_u16(Endian::Little, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x2010u16);
}
#[test]
fn test_read_u16_msb() {
let data = [0x10u8, 0x20u8];
let result = read_u16(Endian::Big, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x1020u16);
}
#[test]
fn test_read_u16_too_short() {
let data = [0x10u8];
let result: Result<u16, ParseError> = read_u16(Endian::Little, &mut data.as_ref());
assert!(result.is_err());
}
#[test]
fn test_read_u32_lsb() {
let data = [0x10u8, 0x20u8, 0x30u8, 0x40u8];
let result = read_u32(Endian::Little, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x40302010u32);
}
#[test]
fn test_read_u32_msb() {
let data = [0x10u8, 0x20u8, 0x30u8, 0x40u8];
let result = read_u32(Endian::Big, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x10203040u32);
}
#[test]
fn test_read_u32_too_short() {
let data = [0x10u8, 0x20u8];
let result: Result<u32, ParseError> = read_u32(Endian::Little, &mut data.as_ref());
assert!(result.is_err());
}
#[test]
fn test_read_u64_lsb() {
let data = [
0x10u8, 0x20u8, 0x30u8, 0x40u8, 0x50u8, 0x60u8, 0x70u8, 0x80u8,
];
let result = read_u64(Endian::Little, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x8070605040302010u64);
}
#[test]
fn test_read_u64_msb() {
let data = [
0x10u8, 0x20u8, 0x30u8, 0x40u8, 0x50u8, 0x60u8, 0x70u8, 0x80u8,
];
let result = read_u64(Endian::Big, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x1020304050607080u64);
}
#[test]
fn test_read_u64_too_short() {
let data = [0x10u8, 0x20u8];
let result: Result<u64, ParseError> = read_u64(Endian::Little, &mut data.as_ref());
assert!(result.is_err());
}
}

View File

@ -1,7 +1,6 @@
use crate::file::Class;
use crate::gabi;
use crate::parse::{Endian, Parse};
use crate::utils::{read_u32, read_u64};
use crate::parse::{Endian, Parse, read_u32, read_u64};
/// Encapsulates the contents of an ELF Section Header
#[derive(Copy, Clone, Debug, PartialEq, Eq)]

View File

@ -1,7 +1,6 @@
use crate::file::Class;
use crate::gabi;
use crate::parse::{Endian, Parse};
use crate::utils::{read_u32, read_u64};
use crate::parse::{Endian, Parse, read_u32, read_u64};
/// Encapsulates the contents of an ELF Program Header
///

View File

@ -1,36 +1,3 @@
use crate::parse::Endian;
use std::io;
use crate::ParseError;
#[inline]
pub fn read_u16<T: io::Read>(endian: Endian, io: &mut T) -> Result<u16, ParseError> {
let mut buf = [0u8; 2];
io.read_exact(&mut buf)?;
match endian {
Endian::Little => Ok(u16::from_le_bytes(buf)),
Endian::Big => Ok(u16::from_be_bytes(buf)),
}
}
#[inline]
pub fn read_u32<T: io::Read>(endian: Endian, io: &mut T) -> Result<u32, ParseError> {
let mut buf = [0u8; 4];
io.read_exact(&mut buf)?;
match endian {
Endian::Little => Ok(u32::from_le_bytes(buf)),
Endian::Big => Ok(u32::from_be_bytes(buf)),
}
}
#[inline]
pub fn read_u64<T: io::Read>(endian: Endian, io: &mut T) -> Result<u64, ParseError> {
let mut buf = [0u8; 8];
io.read_exact(&mut buf)?;
match endian {
Endian::Little => Ok(u64::from_le_bytes(buf)),
Endian::Big => Ok(u64::from_be_bytes(buf)),
}
}
use std;
pub fn get_string(data: &[u8], start: usize) -> Result<String, std::string::FromUtf8Error> {
@ -46,76 +13,4 @@ pub fn get_string(data: &[u8], start: usize) -> Result<String, std::string::From
rtn.push(data[i] as char);
}
Ok(rtn)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_read_u16_lsb() {
let data = [0x10u8, 0x20u8];
let result = read_u16(Endian::Little, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x2010u16);
}
#[test]
fn test_read_u16_msb() {
let data = [0x10u8, 0x20u8];
let result = read_u16(Endian::Big, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x1020u16);
}
#[test]
fn test_read_u16_too_short() {
let data = [0x10u8];
let result: Result<u16, ParseError> = read_u16(Endian::Little, &mut data.as_ref());
assert!(result.is_err());
}
#[test]
fn test_read_u32_lsb() {
let data = [0x10u8, 0x20u8, 0x30u8, 0x40u8];
let result = read_u32(Endian::Little, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x40302010u32);
}
#[test]
fn test_read_u32_msb() {
let data = [0x10u8, 0x20u8, 0x30u8, 0x40u8];
let result = read_u32(Endian::Big, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x10203040u32);
}
#[test]
fn test_read_u32_too_short() {
let data = [0x10u8, 0x20u8];
let result: Result<u32, ParseError> = read_u32(Endian::Little, &mut data.as_ref());
assert!(result.is_err());
}
#[test]
fn test_read_u64_lsb() {
let data = [
0x10u8, 0x20u8, 0x30u8, 0x40u8, 0x50u8, 0x60u8, 0x70u8, 0x80u8,
];
let result = read_u64(Endian::Little, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x8070605040302010u64);
}
#[test]
fn test_read_u64_msb() {
let data = [
0x10u8, 0x20u8, 0x30u8, 0x40u8, 0x50u8, 0x60u8, 0x70u8, 0x80u8,
];
let result = read_u64(Endian::Big, &mut data.as_ref()).unwrap();
assert_eq!(result, 0x1020304050607080u64);
}
#[test]
fn test_read_u64_too_short() {
let data = [0x10u8, 0x20u8];
let result: Result<u64, ParseError> = read_u64(Endian::Little, &mut data.as_ref());
assert!(result.is_err());
}
}
}