zelf/
program.rs

1use crate::context::PropU32;
2use crate::context::*;
3use crate::elf::Variant;
4use crate::utils::{as_offset, read, read_n, Pod};
5use core::marker::PhantomData;
6
7#[derive(Debug, Clone)]
8pub enum ParseProgramsError {
9    BrokenHeaders,
10    BadPropertyPhentsize,
11}
12
13#[derive(Debug, Clone)]
14pub enum ParseProgramError {
15    BadPropertyType,
16    BrokenContent,
17}
18
19#[derive(Debug, Clone, Copy)]
20pub struct Programs<'a, T: Context> {
21    data: &'a [u8],
22    offset: usize,
23    num: u16,
24    _maker: PhantomData<T>,
25}
26
27impl<'a, T: Context> Programs<'a, T> {
28    pub fn parse(elf: Variant<'a, T>) -> Result<Option<Programs<'a, T>>, ParseProgramsError> {
29        use ParseProgramsError::*;
30        let data = elf.data();
31        let offset = as_offset::<T>(elf.header().phoff()).ok_or(BrokenHeaders)?;
32        if offset == 0 {
33            return Ok(None);
34        }
35        if elf.header().phentsize() as usize != core::mem::size_of::<ProgramHeader<T>>() {
36            return Err(BadPropertyPhentsize);
37        }
38        let num = elf.header().phnum();
39        read_n::<ProgramHeader<T>>(data, offset, num as usize).ok_or(BrokenHeaders)?;
40        Ok(Some(Self {
41            data,
42            offset,
43            num,
44            _maker: PhantomData,
45        }))
46    }
47    pub fn num(&self) -> u16 {
48        self.num
49    }
50}
51
52pub struct Program<'a, T: Context> {
53    pheader: &'a ProgramHeader<T>,
54    content: &'a [u8],
55}
56
57impl<'a, T: Context> Program<'a, T> {
58    pub fn parse(programs: Programs<'a, T>, index: u16) -> Option<Result<Self, ParseProgramError>> {
59        use ParseProgramError::*;
60        use ProgramType::*;
61        if index >= programs.num {
62            return None;
63        }
64        let offset = programs.offset + index as usize * core::mem::size_of::<ProgramHeader<T>>();
65        fn helper<'a, T: Context>(
66            programs: Programs<'a, T>,
67            offset: usize,
68        ) -> Result<Program<'a, T>, ParseProgramError> {
69            let pheader: &'a ProgramHeader<T> = read(programs.data, offset).unwrap();
70            let typa = pheader.checked_type().ok_or(BadPropertyType)?;
71            if let Null = typa {
72                return Ok(Program {
73                    pheader,
74                    content: &[],
75                });
76            }
77            let content_offset = as_offset::<T>(pheader.offset()).ok_or(BrokenContent)?;
78            let content_size = as_offset::<T>(pheader.filesz()).ok_or(BrokenContent)?;
79            let content =
80                read_n::<u8>(programs.data, content_offset, content_size).ok_or(BrokenContent)?;
81            Ok(Program { pheader, content })
82        }
83        Some(helper(programs, offset))
84    }
85    pub fn header(&self) -> &'a ProgramHeader<T> {
86        self.pheader
87    }
88    pub fn content(&self) -> &'a [u8] {
89        self.content
90    }
91}
92
93#[repr(C)]
94#[derive(Debug, Clone)]
95pub struct ProgramHeader<T: Context> {
96    pub typa: PropU32,
97    pub flags64: T::PropU32If64,
98    pub offset: T::PropUsize,
99    pub vaddr: T::PropUsize,
100    pub paddr: T::PropUsize,
101    pub filesz: T::PropUsize,
102    pub memsz: T::PropUsize,
103    pub flags32: T::PropU32If32,
104    pub align: T::PropUsize,
105}
106
107impl<T: Context> ProgramHeader<T> {
108    pub fn checked_type(&self) -> Option<ProgramType> {
109        ProgramType::try_from(T::interpret(self.typa)).ok()
110    }
111    /// # Panics
112    ///
113    /// Panics if it's not a vaild program type.
114    pub fn typa(&self) -> ProgramType {
115        self.checked_type().unwrap()
116    }
117    pub fn flags(&self) -> ProgramFlags {
118        T::interpret((self.flags32, self.flags64)).into()
119    }
120    pub fn offset(&self) -> T::Integer {
121        T::interpret(self.offset)
122    }
123    pub fn vaddr(&self) -> T::Integer {
124        T::interpret(self.vaddr)
125    }
126    pub fn paddr(&self) -> T::Integer {
127        T::interpret(self.paddr)
128    }
129    pub fn filesz(&self) -> T::Integer {
130        T::interpret(self.filesz)
131    }
132    pub fn memsz(&self) -> T::Integer {
133        T::interpret(self.memsz)
134    }
135    pub fn align(&self) -> T::Integer {
136        T::interpret(self.align)
137    }
138}
139
140unsafe impl<T: Context> Pod for ProgramHeader<T> {}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub enum ProgramType {
144    /// Program header table entry unused.
145    Null,
146    /// Loadable segment.
147    Load,
148    /// Dynamic linking information.
149    Dynamic,
150    /// Interpreter information.
151    Interp,
152    /// Auxiliary information.
153    Note,
154    /// Reserved.
155    Shlib,
156    /// Segment containing program header table itself.
157    Phdr,
158    /// Thread-Local Storage template.
159    Tls,
160    /// Operating system-specific.
161    OsSpecific(u32),
162    /// Processor-specific.
163    ProcessorSpecific(u32),
164}
165
166impl TryFrom<u32> for ProgramType {
167    type Error = ();
168
169    fn try_from(value: u32) -> Result<Self, Self::Error> {
170        use ProgramType::*;
171        match value {
172            0 => Ok(Null),
173            1 => Ok(Load),
174            2 => Ok(Dynamic),
175            3 => Ok(Interp),
176            4 => Ok(Note),
177            5 => Ok(Shlib),
178            6 => Ok(Phdr),
179            7 => Ok(Tls),
180            x @ 0x60000000..=0x6FFFFFFF => Ok(OsSpecific(x)),
181            x @ 0x70000000..=0x7FFFFFFF => Ok(ProcessorSpecific(x)),
182            _ => Err(()),
183        }
184    }
185}
186
187impl From<ProgramType> for u32 {
188    fn from(value: ProgramType) -> Self {
189        use ProgramType::*;
190        match value {
191            Null => 0,
192            Load => 1,
193            Dynamic => 2,
194            Interp => 3,
195            Note => 4,
196            Shlib => 5,
197            Phdr => 6,
198            Tls => 7,
199            OsSpecific(x) => x,
200            ProcessorSpecific(x) => x,
201        }
202    }
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq, From, Into, BitXor, BitAnd, BitOr, LowerHex)]
206pub struct ProgramFlags(pub u32);
207
208impl ProgramFlags {
209    /// Execute permission
210    pub const EXECUTE: Self = Self(0x1);
211    /// Writing permission
212    pub const WRITE: Self = Self(0x2);
213    /// Read permission
214    pub const READ: Self = Self(0x4);
215    /// OS specific mask
216    pub const MASKOS: Self = Self(0x0ff00000);
217    /// Processor specific mask
218    pub const MASKPROCESSOR: Self = Self(0xf0000000);
219}