Skip to main content

proka_exec/
sections.rs

1//! The definitions of section entry.
2use crate::{Error, HEADER_SIZE, Result, SECTION_HDR_SIZE, SECTION_INDEX_SIZE, slice_to_str};
3use bitflags::bitflags;
4use bytemuck::{Pod, Zeroable};
5
6/// Errors in section
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum SectionError {
9    /// Section length error.
10    ///
11    /// Will appear if recorded section length is 0.
12    LengthError,
13
14    /// Section base error.
15    ///
16    /// Will appear if specified section base is lower than metadata length (128+32).
17    ///
18    /// Contains the incorrect base.
19    BaseError(u32),
20
21    /// Entry offset out of range.
22    ///
23    /// Will appear if entry offset is out of range of the section.
24    ///
25    /// Contains the incorrect entry offset (0) and the section length (1).
26    EntryOffsetOutOfRange(u32, u32),
27}
28
29/// A section entry.
30#[repr(C)]
31#[derive(Debug, Clone, Copy, Pod, Zeroable)]
32pub struct SectionHdr {
33    /// The flag of the section.
34    pub flag: SectionFlag,
35
36    /// Paddings of header.
37    pub _pad1: [u8; 3],
38
39    /// The offset of the section start.
40    pub base: u32,
41
42    /// The size of the section.
43    pub size: u32,
44
45    /// Paddings of header.
46    pub _pad2: [u8; 4],
47}
48
49bitflags! {
50    /// Flags of this section.
51    #[repr(transparent)]
52    #[derive(Debug, Clone, Copy, Pod, Zeroable)]
53    pub struct SectionFlag: u8 {
54        /// The section is loadable.
55        const LOADABLE = 1;
56
57        /// The section is executable.
58        const EXECABLE = 1 << 1;
59    }
60}
61
62impl SectionHdr {
63    /// Convert this object to array.
64    #[inline]
65    pub const fn to_array(&self) -> [u8; SECTION_HDR_SIZE] {
66        // SAFETY: used `#[repr(C)]`
67        unsafe { core::ptr::read(self as *const Self as *const [u8; SECTION_HDR_SIZE]) }
68    }
69
70    /// Validate is this section not corrupted.
71    #[inline]
72    pub fn validate(&self) -> Result<()> {
73        // Check: Is size 0
74        if self.size == 0 {
75            return Err(Error::SectionError(SectionError::LengthError));
76        }
77
78        Ok(())
79    }
80}
81
82/// The index of each section entry.
83#[repr(C, packed)]
84#[derive(Debug, Clone, Copy, Pod, Zeroable)]
85pub struct SectionIndex {
86    /// The base offset of the section header ([`SectionHdr`]).
87    pub base: u32,
88
89    /// The total length of the section name.
90    pub name_len: u32,
91}
92
93impl SectionIndex {
94    /// Convert this object to array.
95    #[inline]
96    pub const fn to_array(&self) -> [u8; SECTION_INDEX_SIZE] {
97        // SAFETY: used `#[repr(C)]`
98        unsafe { core::ptr::read(self as *const Self as *const [u8; SECTION_INDEX_SIZE]) }
99    }
100}
101
102/// The iterator of each sections
103#[derive(Debug, Clone, Copy)]
104pub struct SectionTable<'a> {
105    buf: &'a [u8],
106    total: u16,
107    current: u16,
108}
109
110impl<'a> SectionTable<'a> {
111    /// Create a new object of this table.
112    pub(crate) fn new(buf: &'a [u8], total: u16) -> Self {
113        Self {
114            buf,
115            total,
116            current: 0,
117        }
118    }
119
120    /// A safe way to get [`SectionIndex`] by index.
121    pub fn get(&self, index: usize) -> Option<SectionIndex> {
122        // Check: Is given index out of bounds?
123        if index >= self.total as usize {
124            return None;
125        }
126
127        // Get the section index content
128        let offset = HEADER_SIZE + index * SECTION_INDEX_SIZE;
129        let slice = &self.buf[offset..offset + SECTION_INDEX_SIZE];
130
131        // Initialize and copy content to entry
132        let mut section_index = SectionIndex::zeroed();
133        bytemuck::bytes_of_mut(&mut section_index).copy_from_slice(slice);
134        Some(section_index)
135    }
136
137    /// Get the section header by using [`SectionIndex`].
138    pub fn get_hdr_secindex(&self, section_index: SectionIndex) -> SectionHdr {
139        // Get slice through section index
140        let offset = section_index.base as usize;
141        let slice = &self.buf[offset..offset + SECTION_HDR_SIZE];
142
143        // Initialize and copy content to entry
144        let mut hdr = SectionHdr::zeroed();
145        bytemuck::bytes_of_mut(&mut hdr).copy_from_slice(slice);
146        hdr
147    }
148
149    /// Get the section header by using index number.
150    pub fn get_hdr_idx(&self, index: usize) -> Option<SectionHdr> {
151        // Get slice through section index
152        let section_index = self.get(index)?;
153        Some(self.get_hdr_secindex(section_index))
154    }
155
156    /// Get the section name by using [`SectionIndex`].
157    pub fn get_name_secindex(&self, section_index: SectionIndex) -> &str {
158        // Get slice through section index
159        let offset = section_index.base as usize + SECTION_HDR_SIZE;
160        let content = &self.buf[offset..offset + section_index.name_len as usize];
161        slice_to_str(content).expect("Failed to get section's name")
162    }
163
164    /// Get the section name by using index number.
165    pub fn get_name_idx(&self, index: usize) -> Option<&str> {
166        // Get slice through section index
167        let section_index = self.get(index)?;
168        Some(self.get_name_secindex(section_index))
169    }
170}
171
172impl<'a> Iterator for SectionTable<'a> {
173    type Item = SectionIndex;
174
175    fn next(&mut self) -> Option<Self::Item> {
176        let result = self.get(self.current as usize)?;
177        self.current += 1;
178        Some(result)
179    }
180}
181
182// Tests
183#[cfg(test)]
184mod tests {
185    use super::*;
186
187    #[test]
188    fn test_header_length() {
189        assert_eq!(crate::SECTION_HDR_SIZE, 16);
190        assert_eq!(core::mem::size_of::<SectionHdr>(), 16)
191    }
192}