use crate::endian::EndianParse;
use crate::file::Class;
use crate::parse::{ParseAt, ParseError, ParsingTable};
pub type SegmentTable<'data, E> = ParsingTable<'data, E, ProgramHeader>;
#[derive(Debug)]
#[repr(C)]
pub struct Elf32_Phdr {
pub p_type: u32,
pub p_offset: u32,
pub p_vaddr: u32,
pub p_paddr: u32,
pub p_filesz: u32,
pub p_memsz: u32,
pub p_flags: u32,
pub p_align: u32,
}
#[derive(Debug)]
#[repr(C)]
pub struct Elf64_Phdr {
pub p_type: u32,
pub p_flags: u32,
pub p_offset: u64,
pub p_vaddr: u64,
pub p_paddr: u64,
pub p_filesz: u64,
pub p_memsz: u64,
pub p_align: u64,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ProgramHeader {
pub p_type: u32,
pub p_offset: u64,
pub p_vaddr: u64,
pub p_paddr: u64,
pub p_filesz: u64,
pub p_memsz: u64,
pub p_flags: u32,
pub p_align: u64,
}
impl ParseAt for ProgramHeader {
fn parse_at<E: EndianParse>(
endian: E,
class: Class,
offset: &mut usize,
data: &[u8],
) -> Result<Self, ParseError> {
if class == Class::ELF32 {
return Ok(ProgramHeader {
p_type: endian.parse_u32_at(offset, data)?,
p_offset: endian.parse_u32_at(offset, data)? as u64,
p_vaddr: endian.parse_u32_at(offset, data)? as u64,
p_paddr: endian.parse_u32_at(offset, data)? as u64,
p_filesz: endian.parse_u32_at(offset, data)? as u64,
p_memsz: endian.parse_u32_at(offset, data)? as u64,
p_flags: endian.parse_u32_at(offset, data)?,
p_align: endian.parse_u32_at(offset, data)? as u64,
});
}
let p_type = endian.parse_u32_at(offset, data)?;
let p_flags = endian.parse_u32_at(offset, data)?;
let p_offset = endian.parse_u64_at(offset, data)?;
let p_vaddr = endian.parse_u64_at(offset, data)?;
let p_paddr = endian.parse_u64_at(offset, data)?;
let p_filesz = endian.parse_u64_at(offset, data)?;
let p_memsz = endian.parse_u64_at(offset, data)?;
let p_align = endian.parse_u64_at(offset, data)?;
Ok(ProgramHeader {
p_type,
p_offset,
p_vaddr,
p_paddr,
p_filesz,
p_memsz,
p_flags,
p_align,
})
}
#[inline]
fn size_for(class: Class) -> usize {
match class {
Class::ELF32 => 32,
Class::ELF64 => 56,
}
}
}
impl ProgramHeader {
pub(crate) fn get_file_data_range(&self) -> Result<(usize, usize), ParseError> {
let start: usize = self.p_offset.try_into()?;
let size: usize = self.p_filesz.try_into()?;
let end = start.checked_add(size).ok_or(ParseError::IntegerOverflow)?;
Ok((start, end))
}
}
#[cfg(test)]
mod parse_tests {
use super::*;
use crate::endian::{BigEndian, LittleEndian};
use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
#[test]
fn parse_phdr32_lsb() {
test_parse_for(
LittleEndian,
Class::ELF32,
ProgramHeader {
p_type: 0x03020100,
p_offset: 0x07060504,
p_vaddr: 0xB0A0908,
p_paddr: 0x0F0E0D0C,
p_filesz: 0x13121110,
p_memsz: 0x17161514,
p_flags: 0x1B1A1918,
p_align: 0x1F1E1D1C,
},
);
}
#[test]
fn parse_phdr32_msb() {
test_parse_for(
BigEndian,
Class::ELF32,
ProgramHeader {
p_type: 0x00010203,
p_offset: 0x04050607,
p_vaddr: 0x08090A0B,
p_paddr: 0x0C0D0E0F,
p_filesz: 0x10111213,
p_memsz: 0x14151617,
p_flags: 0x18191A1B,
p_align: 0x1C1D1E1F,
},
);
}
#[test]
fn parse_phdr64_lsb() {
test_parse_for(
LittleEndian,
Class::ELF64,
ProgramHeader {
p_type: 0x03020100,
p_offset: 0x0F0E0D0C0B0A0908,
p_vaddr: 0x1716151413121110,
p_paddr: 0x1F1E1D1C1B1A1918,
p_filesz: 0x2726252423222120,
p_memsz: 0x2F2E2D2C2B2A2928,
p_flags: 0x07060504,
p_align: 0x3736353433323130,
},
);
}
#[test]
fn parse_phdr64_msb() {
test_parse_for(
BigEndian,
Class::ELF64,
ProgramHeader {
p_type: 0x00010203,
p_offset: 0x08090A0B0C0D0E0F,
p_vaddr: 0x1011121314151617,
p_paddr: 0x18191A1B1C1D1E1F,
p_filesz: 0x2021222324252627,
p_memsz: 0x28292A2B2C2D2E2F,
p_flags: 0x04050607,
p_align: 0x3031323334353637,
},
);
}
#[test]
fn parse_phdr32_lsb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, ProgramHeader>(LittleEndian, Class::ELF32);
}
#[test]
fn parse_phdr32_msb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, ProgramHeader>(BigEndian, Class::ELF32);
}
#[test]
fn parse_phdr64_lsb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, ProgramHeader>(LittleEndian, Class::ELF64);
}
#[test]
fn parse_phdr64_msb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, ProgramHeader>(BigEndian, Class::ELF64);
}
}