1use crate::{Error, HEADER_SIZE, Result, SECTION_HDR_SIZE, SECTION_INDEX_SIZE, slice_to_str};
3use bitflags::bitflags;
4use bytemuck::{Pod, Zeroable};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum SectionError {
9 LengthError,
13
14 BaseError(u32),
20
21 EntryOffsetOutOfRange(u32, u32),
27}
28
29#[repr(C)]
31#[derive(Debug, Clone, Copy, Pod, Zeroable)]
32pub struct SectionHdr {
33 pub flag: SectionFlag,
35
36 pub _pad1: [u8; 3],
38
39 pub base: u32,
41
42 pub size: u32,
44
45 pub _pad2: [u8; 4],
47}
48
49bitflags! {
50 #[repr(transparent)]
52 #[derive(Debug, Clone, Copy, Pod, Zeroable)]
53 pub struct SectionFlag: u8 {
54 const LOADABLE = 1;
56
57 const EXECABLE = 1 << 1;
59 }
60}
61
62impl SectionHdr {
63 #[inline]
65 pub const fn to_array(&self) -> [u8; SECTION_HDR_SIZE] {
66 unsafe { core::ptr::read(self as *const Self as *const [u8; SECTION_HDR_SIZE]) }
68 }
69
70 #[inline]
72 pub fn validate(&self) -> Result<()> {
73 if self.size == 0 {
75 return Err(Error::SectionError(SectionError::LengthError));
76 }
77
78 Ok(())
79 }
80}
81
82#[repr(C, packed)]
84#[derive(Debug, Clone, Copy, Pod, Zeroable)]
85pub struct SectionIndex {
86 pub base: u32,
88
89 pub name_len: u32,
91}
92
93impl SectionIndex {
94 #[inline]
96 pub const fn to_array(&self) -> [u8; SECTION_INDEX_SIZE] {
97 unsafe { core::ptr::read(self as *const Self as *const [u8; SECTION_INDEX_SIZE]) }
99 }
100}
101
102#[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 pub(crate) fn new(buf: &'a [u8], total: u16) -> Self {
113 Self {
114 buf,
115 total,
116 current: 0,
117 }
118 }
119
120 pub fn get(&self, index: usize) -> Option<SectionIndex> {
122 if index >= self.total as usize {
124 return None;
125 }
126
127 let offset = HEADER_SIZE + index * SECTION_INDEX_SIZE;
129 let slice = &self.buf[offset..offset + SECTION_INDEX_SIZE];
130
131 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 pub fn get_hdr_secindex(&self, section_index: SectionIndex) -> SectionHdr {
139 let offset = section_index.base as usize;
141 let slice = &self.buf[offset..offset + SECTION_HDR_SIZE];
142
143 let mut hdr = SectionHdr::zeroed();
145 bytemuck::bytes_of_mut(&mut hdr).copy_from_slice(slice);
146 hdr
147 }
148
149 pub fn get_hdr_idx(&self, index: usize) -> Option<SectionHdr> {
151 let section_index = self.get(index)?;
153 Some(self.get_hdr_secindex(section_index))
154 }
155
156 pub fn get_name_secindex(&self, section_index: SectionIndex) -> &str {
158 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 pub fn get_name_idx(&self, index: usize) -> Option<&str> {
166 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#[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}