Skip to main content

kernel_elf_parser/
info.rs

1//! ELF information parsed from the ELF file
2
3use alloc::vec::Vec;
4use core::ops::Range;
5
6use xmas_elf::{
7    header::Class,
8    program::{ProgramHeader32, ProgramHeader64},
9};
10
11use crate::auxv::{AuxEntry, AuxType};
12
13pub struct ELFHeadersBuilder<'a>(ELFHeaders<'a>);
14impl<'a> ELFHeadersBuilder<'a> {
15    pub fn new(input: &'a [u8]) -> Result<Self, &'static str> {
16        Ok(Self(ELFHeaders {
17            header: xmas_elf::header::parse_header(input)?,
18            ph: Vec::new(),
19        }))
20    }
21
22    pub fn ph_range(&self) -> Range<u64> {
23        let start = self.0.header.pt2.ph_offset();
24        let size = self.0.header.pt2.ph_entry_size() as u64 * self.0.header.pt2.ph_count() as u64;
25        start..start + size
26    }
27
28    pub fn build(mut self, ph: &[u8]) -> Result<ELFHeaders<'a>, &'static str> {
29        self.0.ph = ph
30            .chunks_exact(self.0.header.pt2.ph_entry_size() as usize)
31            .map(|chunk| match self.0.header.pt1.class() {
32                Class::ThirtyTwo => {
33                    let ph: &ProgramHeader32 = zero::read(chunk);
34                    ProgramHeader64 {
35                        type_: ph.type_,
36                        offset: ph.offset as _,
37                        virtual_addr: ph.virtual_addr as _,
38                        physical_addr: ph.physical_addr as _,
39                        file_size: ph.file_size as _,
40                        mem_size: ph.mem_size as _,
41                        flags: ph.flags,
42                        align: ph.align as _,
43                    }
44                }
45                Class::SixtyFour => *zero::read(chunk),
46                Class::None | Class::Other(_) => unreachable!(),
47            })
48            .collect();
49        Ok(self.0)
50    }
51}
52
53pub struct ELFHeaders<'a> {
54    pub header: xmas_elf::header::Header<'a>,
55    pub ph: Vec<ProgramHeader64>,
56}
57
58/// A wrapper for the ELF file data with some useful methods.
59pub struct ELFParser<'a> {
60    headers: &'a ELFHeaders<'a>,
61    /// Base address of the ELF file loaded into the memory.
62    base: usize,
63}
64
65impl<'a> ELFParser<'a> {
66    /// Create a new `ELFInfo` instance.
67    pub fn new(headers: &'a ELFHeaders<'a>, bias: usize) -> Result<Self, &'static str> {
68        let base = if headers.header.pt2.type_().as_type() == xmas_elf::header::Type::SharedObject {
69            bias
70        } else {
71            0
72        };
73        Ok(Self { headers, base })
74    }
75
76    /// The entry point of the ELF file.
77    pub fn entry(&self) -> usize {
78        // TODO: base_load_address_offset?
79        self.headers.header.pt2.entry_point() as usize + self.base
80    }
81
82    /// The number of program headers in the ELF file.
83    pub fn phnum(&self) -> usize {
84        self.headers.header.pt2.ph_count() as usize
85    }
86
87    /// The size of the program header table entry in the ELF file.
88    pub fn phent(&self) -> usize {
89        self.headers.header.pt2.ph_entry_size() as usize
90    }
91
92    /// The offset of the program header table in the ELF file.
93    pub fn phdr(&self) -> usize {
94        let ph_offset = self.headers.header.pt2.ph_offset() as usize;
95        let header = self
96            .headers
97            .ph
98            .iter()
99            .find(|header| {
100                (header.offset..header.offset + header.file_size).contains(&(ph_offset as u64))
101            })
102            .expect("can not find program header table address in elf");
103        ph_offset - header.offset as usize + header.virtual_addr as usize + self.base
104    }
105
106    /// The base address of the ELF file loaded into the memory.
107    pub fn base(&self) -> usize {
108        self.base
109    }
110
111    pub fn headers(&self) -> &'a ELFHeaders<'a> {
112        self.headers
113    }
114
115    /// Part of auxiliary vectors from the ELF file.
116    ///
117    /// # Arguments
118    ///
119    /// * `pagesz` - The page size of the system
120    /// * `ldso_base` - The base address of the dynamic linker (if exists)
121    ///
122    /// Details about auxiliary vectors are described in <https://articles.manugarg.com/aboutelfauxiliaryvectors.html>
123    pub fn aux_vector(
124        &self,
125        pagesz: usize,
126        ldso_base: Option<usize>,
127    ) -> impl Iterator<Item = AuxEntry> {
128        [
129            (AuxType::PHDR, self.phdr()),
130            (AuxType::PHENT, self.phent()),
131            (AuxType::PHNUM, self.phnum()),
132            (AuxType::PAGESZ, pagesz),
133            (AuxType::ENTRY, self.entry()),
134        ]
135        .into_iter()
136        .chain(ldso_base.into_iter().map(|base| (AuxType::BASE, base)))
137        .map(|(at, val)| AuxEntry::new(at, val))
138    }
139}