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, bytes_of};
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/// The header of each section metadata.
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 fn to_array(&self) -> [u8; SECTION_HDR_SIZE] {
66        let mut arr = [0u8; SECTION_HDR_SIZE];
67        arr.copy_from_slice(bytes_of(self));
68        arr
69    }
70
71    /// Validate is this section not corrupted.
72    #[inline]
73    pub fn validate(&self) -> Result<()> {
74        // Check: Is size 0
75        if self.size == 0 {
76            return Err(Error::SectionError(SectionError::LengthError));
77        }
78
79        Ok(())
80    }
81}
82
83/// The index of each section entry.
84#[repr(C)]
85#[derive(Debug, Clone, Copy, Pod, Zeroable)]
86pub struct SectionIndex {
87    /// The base offset of the section header ([`SectionHdr`]).
88    pub base: u32,
89
90    /// The total length of the section name.
91    pub name_len: u32,
92}
93
94impl SectionIndex {
95    /// Convert this object to array.
96    #[inline]
97    pub fn to_array(&self) -> [u8; SECTION_INDEX_SIZE] {
98        let mut arr = [0u8; SECTION_INDEX_SIZE];
99        arr.copy_from_slice(bytes_of(self));
100        arr
101    }
102}
103
104/// The iterator of each sections
105#[derive(Debug, Clone, Copy)]
106pub struct SectionTable<'a> {
107    buf: &'a [u8],
108    total: u16,
109    current: u16,
110}
111
112impl<'a> SectionTable<'a> {
113    /// Create a new object of this table.
114    pub(crate) fn new(buf: &'a [u8], total: u16) -> Self {
115        Self {
116            buf,
117            total,
118            current: 0,
119        }
120    }
121
122    /// A safe way to get [`SectionIndex`] by index.
123    pub fn get(&self, index: usize) -> Option<SectionIndex> {
124        // Check: Is given index out of bounds?
125        if index >= self.total as usize {
126            return None;
127        }
128
129        // Get the section index content
130        let offset = HEADER_SIZE + index * SECTION_INDEX_SIZE;
131        let slice = &self.buf[offset..offset + SECTION_INDEX_SIZE];
132
133        // Initialize and copy content to entry
134        let mut section_index = SectionIndex::zeroed();
135        bytemuck::bytes_of_mut(&mut section_index).copy_from_slice(slice);
136        Some(section_index)
137    }
138
139    /// Get the section header by using [`SectionIndex`].
140    pub fn get_hdr_secindex(&self, section_index: SectionIndex) -> SectionHdr {
141        // Get slice through section index
142        let offset = section_index.base as usize;
143        let slice = &self.buf[offset..offset + SECTION_HDR_SIZE];
144
145        // Initialize and copy content to entry
146        let mut hdr = SectionHdr::zeroed();
147        bytemuck::bytes_of_mut(&mut hdr).copy_from_slice(slice);
148        hdr
149    }
150
151    /// Get the section header by using index number.
152    pub fn get_hdr_idx(&self, index: usize) -> Option<SectionHdr> {
153        // Get slice through section index
154        let section_index = self.get(index)?;
155        Some(self.get_hdr_secindex(section_index))
156    }
157
158    /// Get the section name by using [`SectionIndex`].
159    pub fn get_name_secindex(&self, section_index: SectionIndex) -> &str {
160        // Get slice through section index
161        let offset = section_index.base as usize + SECTION_HDR_SIZE;
162        let content = &self.buf[offset..offset + section_index.name_len as usize];
163        slice_to_str(content).expect("Failed to get section's name")
164    }
165
166    /// Get the section name by using index number.
167    pub fn get_name_idx(&self, index: usize) -> Option<&str> {
168        // Get slice through section index
169        let section_index = self.get(index)?;
170        Some(self.get_name_secindex(section_index))
171    }
172}
173
174impl<'a> Iterator for SectionTable<'a> {
175    type Item = SectionIndex;
176
177    fn next(&mut self) -> Option<Self::Item> {
178        let result = self.get(self.current as usize)?;
179        self.current += 1;
180        Some(result)
181    }
182}
183
184// Tests
185#[cfg(test)]
186mod tests {
187    use super::*;
188
189    #[test]
190    fn test_header_length() {
191        assert_eq!(crate::SECTION_HDR_SIZE, 16);
192        assert_eq!(core::mem::size_of::<SectionHdr>(), 16)
193    }
194}