use crate::header::Header;
use crate::sections::{SectionError, SectionTable, SectionIndex};
use crate::{Result, Error, SECTION_HDR_SIZE, SECTION_INDEX_SIZE, HEADER_SIZE};
#[derive(Debug, Clone, Copy)]
pub struct Parser<'a> {
buf: &'a [u8],
header: Header,
total_sections: u16,
}
impl<'a> Parser<'a> {
pub fn init(buf: &'a [u8]) -> Result<Self> {
let header_raw = &buf[0..HEADER_SIZE]; let header = unsafe { *(header_raw.as_ptr() as *const Header) };
if header.validate().is_err() {
return Err(Error::NotValidExecutable);
}
if header.sections == 0 {
return Err(Error::NoSections);
}
let offset = HEADER_SIZE + (header.sections as usize - 1) * SECTION_INDEX_SIZE;
let index_content = &buf[offset..offset + SECTION_INDEX_SIZE];
let index = unsafe { *(index_content.as_ptr() as *const SectionIndex) };
let len = (index.base + index.name_len) as usize + SECTION_HDR_SIZE;
if buf.len() < len {
return Err(Error::ExecutableCorrupted);
}
unsafe { Ok(Self::init_unchecked(buf)) }
}
pub unsafe fn init_unchecked(buf: &'a [u8]) -> Self {
let header_raw = &buf[0..HEADER_SIZE];
let header = unsafe { *(header_raw.as_ptr() as *const Header) };
Self {
buf,
header,
total_sections: header.sections,
}
}
pub fn validate(&self) -> Result<()> {
let minimal = self.header.min;
let maximum = self.header.max;
for (&min, &max) in minimal.iter().zip(maximum.iter()) {
if min > max {
return Err(Error::VersionIncorrect(minimal, maximum));
}
}
let min_base = HEADER_SIZE + self.header.sections as usize * SECTION_HDR_SIZE;
for (index, section_index) in self.sections().enumerate() {
let section = self.sections().get_hdr_secindex(section_index);
let base_off = section.base as usize;
let len = section.size as usize;
let entry_sec = self.header.entry_sec as usize;
if base_off < min_base {
return Err(Error::SectionError(SectionError::BaseError(
base_off as u32,
)));
}
if len == 0 {
return Err(Error::SectionError(SectionError::LengthError));
}
if index == entry_sec {
let entry_off = self.header.entry_off as usize;
if entry_off > len {
return Err(Error::SectionError(SectionError::EntryOffsetOutOfRange(
entry_off as u32,
len as u32,
)));
}
}
}
Ok(())
}
pub fn get_section_content(&self, secname: &str) -> Option<&'a [u8]> {
for section_index in self.sections() {
let table = self.sections();
let name = table.get_name_secindex(section_index);
let section = table.get_hdr_secindex(section_index);
if secname == name {
let base = section.base as usize;
let length = section.size as usize;
let content = &self.buf[base..base + length];
return Some(content);
}
}
None
}
#[inline]
pub fn header(&self) -> Header {
self.header
}
pub fn sections(&self) -> SectionTable<'_> {
SectionTable::new(self.buf, self.total_sections)
}
}