Skip to content

Commit

Permalink
Test
Browse files Browse the repository at this point in the history
  • Loading branch information
d-e-s-o committed Oct 31, 2024
1 parent 3ed2372 commit d605382
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 15 deletions.
125 changes: 117 additions & 8 deletions src/elf/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::io::SeekFrom;
use std::mem;
use std::mem::MaybeUninit;
use std::ops::ControlFlow;
use std::ops::Deref;
use std::ops::Deref as _;
use std::path::Path;
use std::path::PathBuf;
Expand Down Expand Up @@ -567,18 +568,126 @@ impl Debug for Cache<'_> {
}
}

#[derive(Clone, Copy, Debug)]
struct EhdrExt2<'bcknd, B>
where
B: Backend<'bcknd>,
{
/// The ELF header.
ehdr: B::Item<Elf64_Ehdr>,
/// Override of `ehdr.e_shnum`, handling of which is special-cased by
/// the ELF standard.
shnum: usize,
/// Override of `ehdr.e_phnum`, handling of which is special-cased by
/// the ELF standard.
phnum: usize,
}

struct Cache2<'bcknd, B>
where
B: Backend<'bcknd>,
{
/// A slice of the raw ELF data that we are about to parse.
backend: &'bcknd B,
/// The cached ELF header.
ehdr: OnceCell<EhdrExt2<'bcknd, B>>,
}

impl<'bcknd, B> Cache2<'bcknd, B>
where
B: Backend<'bcknd>,
{
/// Create a new `Cache2` using the provided backend.
fn new(backend: &'bcknd B) -> Self {
Self {
backend,
ehdr: OnceCell::new(),
}
}

/// Read the very first section header.
///
/// ELF contains a couple of clauses that special case data ranges
/// of certain member variables to reference data from this header,
/// which otherwise is zeroed out.
#[inline]
fn read_first_shdr(&self, ehdr: &Elf64_Ehdr) -> Result<B::Item<Elf64_Shdr>> {
let shdr = self
.backend
.read_pod::<Elf64_Shdr>(ehdr.e_shoff as _)
.context("failed to read Elf64_Shdr")?;
Ok(shdr)
}

fn parse_ehdr(&self) -> Result<EhdrExt2<'bcknd, B>> {
let ehdr = self.backend
.read_pod::<Elf64_Ehdr>(0)
.context("failed to read Elf64_Ehdr")?;
if !(ehdr.e_ident[0] == 0x7f
&& ehdr.e_ident[1] == b'E'
&& ehdr.e_ident[2] == b'L'
&& ehdr.e_ident[3] == b'F')
{
return Err(Error::with_invalid_data(format!(
"encountered unexpected e_ident: {:x?}",
&ehdr.e_ident[0..4]
)))
}

// "If the number of entries in the section header table is larger than
// or equal to SHN_LORESERVE, e_shnum holds the value zero and the real
// number of entries in the section header table is held in the sh_size
// member of the initial entry in section header table."
let shnum = if ehdr.e_shnum == 0 {
let shdr = self.read_first_shdr(ehdr)?;
usize::try_from(shdr.sh_size).ok().ok_or_invalid_data(|| {
format!(
"ELF file contains unsupported number of sections ({})",
shdr.sh_size
)
})?
} else {
ehdr.e_shnum.into()
};

// "If the number of entries in the program header table is
// larger than or equal to PN_XNUM (0xffff), this member holds
// PN_XNUM (0xffff) and the real number of entries in the
// program header table is held in the sh_info member of the
// initial entry in section header table."
let phnum = if ehdr.e_phnum == PN_XNUM {
let shdr = self.read_first_shdr(&ehdr)?;
usize::try_from(shdr.sh_info).ok().ok_or_invalid_data(|| {
format!(
"ELF file contains unsupported number of program headers ({})",
shdr.sh_info
)
})?
} else {
ehdr.e_phnum.into()
};

let ehdr = EhdrExt2 { ehdr, shnum, phnum };
Ok(ehdr)
}

fn ensure_ehdr(&self) -> Result<&EhdrExt2<'bcknd, B>> {
self.ehdr.get_or_try_init(|| self.parse_ehdr())
}
}


trait Backend<'r> {
type Item<T: 'r>;
type Array<T: 'r>;
type Item<T: 'r>: Deref<Target = T>;
type Array<T: 'r>: Deref<Target = [T]>;

fn read_pod<T>(&mut self, offset: u64) -> Result<Self::Item<T>, Error>
where
T: Clone + Pod + 'r;
T: Copy + Pod + 'r;

fn read_pod_slice<T>(&mut self, offset: u64, count: usize) -> Result<Self::Array<T>, Error>
where
T: Clone + Pod + 'r;
T: Copy + Pod + 'r;
}

impl<'r> Backend<'r> for &'r Mmap {
Expand All @@ -587,7 +696,7 @@ impl<'r> Backend<'r> for &'r Mmap {

fn read_pod<T>(&mut self, offset: u64) -> Result<Self::Item<T>, Error>
where
T: Clone + Pod + 'r,
T: Pod + 'r,
{
let value = self
.get(offset as _..)
Expand All @@ -599,7 +708,7 @@ impl<'r> Backend<'r> for &'r Mmap {

fn read_pod_slice<T>(&mut self, offset: u64, count: usize) -> Result<Self::Array<T>, Error>
where
T: Clone + Pod + 'r,
T: Pod + 'r,
{
let value = self
.get(offset as _..)
Expand All @@ -616,7 +725,7 @@ impl<'r> Backend<'r> for &'r File {

fn read_pod<T>(&mut self, offset: u64) -> Result<Self::Item<T>, Error>
where
T: Clone + Pod + 'r,
T: Pod + 'r,
{
let _pos = self.seek(SeekFrom::Start(offset))?;

Expand All @@ -634,7 +743,7 @@ impl<'r> Backend<'r> for &'r File {

fn read_pod_slice<T>(&mut self, offset: u64, count: usize) -> Result<Self::Array<T>, Error>
where
T: Clone + Pod + 'r,
T: Pod + 'r,
{
let _pos = self.seek(SeekFrom::Start(offset))?;
let mut vec = Vec::<T>::new();
Expand Down
12 changes: 6 additions & 6 deletions src/elf/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type Elf64_Xword = u64;
pub(crate) const ET_EXEC: u16 = 2;
pub(crate) const ET_DYN: u16 = 3;

#[derive(Debug)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub(crate) struct Elf64_Ehdr {
pub e_ident: [u8; EI_NIDENT], /* ELF "magic number" */
Expand All @@ -36,7 +36,7 @@ unsafe impl Pod for Elf64_Ehdr {}

pub(crate) const PT_LOAD: u32 = 1;

#[derive(Debug)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub(crate) struct Elf64_Phdr {
pub p_type: Elf64_Word,
Expand All @@ -56,7 +56,7 @@ pub(crate) const PF_X: Elf64_Word = 1;

pub(crate) const PN_XNUM: u16 = 0xffff;

#[derive(Debug)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub(crate) struct Elf64_Shdr {
pub sh_name: Elf64_Word, /* Section name, index in string tbl */
Expand Down Expand Up @@ -87,7 +87,7 @@ pub(crate) const STT_OBJECT: u8 = 1;
pub(crate) const STT_FUNC: u8 = 2;
pub(crate) const STT_GNU_IFUNC: u8 = 10;

#[derive(Clone, Debug)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub(crate) struct Elf64_Sym {
pub st_name: Elf64_Word, /* Symbol name, index in string tbl */
Expand Down Expand Up @@ -138,7 +138,7 @@ unsafe impl Pod for Elf64_Sym {}

pub(crate) const NT_GNU_BUILD_ID: Elf64_Word = 3;

#[derive(Debug)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub(crate) struct Elf64_Nhdr {
pub n_namesz: Elf64_Word,
Expand All @@ -150,7 +150,7 @@ pub(crate) struct Elf64_Nhdr {
unsafe impl Pod for Elf64_Nhdr {}


#[derive(Debug)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub(crate) struct Elf64_Chdr {
/// Compression format.
Expand Down
2 changes: 1 addition & 1 deletion src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ where
///
/// # Safety
/// Only safe to implement for types that are valid for any bit pattern.
pub(crate) unsafe trait Pod {}
pub(crate) unsafe trait Pod: Copy + Clone {}

unsafe impl Pod for i8 {}
unsafe impl Pod for u8 {}
Expand Down

0 comments on commit d605382

Please sign in to comment.