use crate::endian::EndianParse;
use crate::file::Class;
use crate::parse::{ParseAt, ParseError, ParsingTable};
pub type SectionHeaderTable<'data, E> = ParsingTable<'data, E, SectionHeader>;
#[derive(Debug)]
#[repr(C)]
pub struct Elf32_Shdr {
pub sh_name: u32,
pub sh_type: u32,
pub sh_flags: u32,
pub sh_addr: u32,
pub sh_offset: u32,
pub sh_size: u32,
pub sh_link: u32,
pub sh_info: u32,
pub sh_addralign: u32,
pub sh_entsize: u32,
}
#[derive(Debug)]
#[repr(C)]
pub struct Elf64_Shdr {
pub sh_name: u32,
pub sh_type: u32,
pub sh_flags: u64,
pub sh_addr: u64,
pub sh_offset: u64,
pub sh_size: u64,
pub sh_link: u32,
pub sh_info: u32,
pub sh_addralign: u64,
pub sh_entsize: u64,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SectionHeader {
pub sh_name: u32,
pub sh_type: u32,
pub sh_flags: u64,
pub sh_addr: u64,
pub sh_offset: u64,
pub sh_size: u64,
pub sh_link: u32,
pub sh_info: u32,
pub sh_addralign: u64,
pub sh_entsize: u64,
}
impl ParseAt for SectionHeader {
fn parse_at<E: EndianParse>(
endian: E,
class: Class,
offset: &mut usize,
data: &[u8],
) -> Result<Self, ParseError> {
match class {
Class::ELF32 => Ok(SectionHeader {
sh_name: endian.parse_u32_at(offset, data)?,
sh_type: endian.parse_u32_at(offset, data)?,
sh_flags: endian.parse_u32_at(offset, data)? as u64,
sh_addr: endian.parse_u32_at(offset, data)? as u64,
sh_offset: endian.parse_u32_at(offset, data)? as u64,
sh_size: endian.parse_u32_at(offset, data)? as u64,
sh_link: endian.parse_u32_at(offset, data)?,
sh_info: endian.parse_u32_at(offset, data)?,
sh_addralign: endian.parse_u32_at(offset, data)? as u64,
sh_entsize: endian.parse_u32_at(offset, data)? as u64,
}),
Class::ELF64 => Ok(SectionHeader {
sh_name: endian.parse_u32_at(offset, data)?,
sh_type: endian.parse_u32_at(offset, data)?,
sh_flags: endian.parse_u64_at(offset, data)?,
sh_addr: endian.parse_u64_at(offset, data)?,
sh_offset: endian.parse_u64_at(offset, data)?,
sh_size: endian.parse_u64_at(offset, data)?,
sh_link: endian.parse_u32_at(offset, data)?,
sh_info: endian.parse_u32_at(offset, data)?,
sh_addralign: endian.parse_u64_at(offset, data)?,
sh_entsize: endian.parse_u64_at(offset, data)?,
}),
}
}
#[inline]
fn size_for(class: Class) -> usize {
match class {
Class::ELF32 => 40,
Class::ELF64 => 64,
}
}
}
impl SectionHeader {
pub(crate) fn get_data_range(&self) -> Result<(usize, usize), ParseError> {
let start: usize = self.sh_offset.try_into()?;
let size: usize = self.sh_size.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_shdr32_lsb() {
test_parse_for(
LittleEndian,
Class::ELF32,
SectionHeader {
sh_name: 0x03020100,
sh_type: 0x07060504,
sh_flags: 0xB0A0908,
sh_addr: 0x0F0E0D0C,
sh_offset: 0x13121110,
sh_size: 0x17161514,
sh_link: 0x1B1A1918,
sh_info: 0x1F1E1D1C,
sh_addralign: 0x23222120,
sh_entsize: 0x27262524,
},
);
}
#[test]
fn parse_shdr32_msb() {
test_parse_for(
BigEndian,
Class::ELF32,
SectionHeader {
sh_name: 0x00010203,
sh_type: 0x04050607,
sh_flags: 0x08090A0B,
sh_addr: 0x0C0D0E0F,
sh_offset: 0x10111213,
sh_size: 0x14151617,
sh_link: 0x18191A1B,
sh_info: 0x1C1D1E1F,
sh_addralign: 0x20212223,
sh_entsize: 0x24252627,
},
);
}
#[test]
fn parse_shdr64_lsb() {
test_parse_for(
LittleEndian,
Class::ELF64,
SectionHeader {
sh_name: 0x03020100,
sh_type: 0x07060504,
sh_flags: 0x0F0E0D0C0B0A0908,
sh_addr: 0x1716151413121110,
sh_offset: 0x1F1E1D1C1B1A1918,
sh_size: 0x2726252423222120,
sh_link: 0x2B2A2928,
sh_info: 0x2F2E2D2C,
sh_addralign: 0x3736353433323130,
sh_entsize: 0x3F3E3D3C3B3A3938,
},
);
}
#[test]
fn parse_shdr64_msb() {
test_parse_for(
BigEndian,
Class::ELF64,
SectionHeader {
sh_name: 0x00010203,
sh_type: 0x04050607,
sh_flags: 0x08090A0B0C0D0E0F,
sh_addr: 0x1011121314151617,
sh_offset: 0x18191A1B1C1D1E1F,
sh_size: 0x2021222324252627,
sh_link: 0x28292A2B,
sh_info: 0x2C2D2E2F,
sh_addralign: 0x3031323334353637,
sh_entsize: 0x38393A3B3C3D3E3F,
},
);
}
#[test]
fn parse_shdr32_lsb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, SectionHeader>(LittleEndian, Class::ELF32);
}
#[test]
fn parse_shdr32_msb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, SectionHeader>(BigEndian, Class::ELF32);
}
#[test]
fn parse_shdr64_lsb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, SectionHeader>(LittleEndian, Class::ELF64);
}
#[test]
fn parse_shdr64_msb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, SectionHeader>(BigEndian, Class::ELF64);
}
}