1#![no_std]
6
7pub mod sections;
12pub mod segments;
13pub mod traits;
14
15#[doc(inline)]
16pub use sections::Header as SectionHeader;
17
18#[doc(inline)]
19pub use segments::Header as ProgramHeader;
20
21#[doc(inline)]
22pub use traits::Source;
23
24#[derive(Debug, Clone)]
38pub enum Error<E>
39where
40 E: core::fmt::Debug,
41{
42 NotAnElfFile,
44 WrongElfFile,
46 Source(E),
48 NotEnoughSpace,
50 InvalidString,
52}
53
54impl<E> From<E> for Error<E>
55where
56 E: core::fmt::Debug,
57{
58 fn from(value: E) -> Error<E> {
59 Error::Source(value)
60 }
61}
62
63pub struct Loader<DS> {
65 data_source: DS,
67 e_entry: u32,
69 e_phoff: u32,
71 e_shoff: u32,
73 e_phnum: u16,
75 e_shnum: u16,
77 e_shstrndx: u16,
79}
80
81impl<DS> Loader<DS>
82where
83 DS: Source,
84{
85 const EM_ARM: u16 = 0x0028;
87 const ET_EXEC: u16 = 0x0002;
89 const ELF_MAGIC: u32 = 0x7F454C46;
91 const DESIRED_ELF_VERSION: u32 = 0x01010100;
93
94 pub fn new(data_source: DS) -> Result<Loader<DS>, Error<DS::Error>> {
96 let elf_header = data_source.read_u32_be(0x00)?;
97 if elf_header != Self::ELF_MAGIC {
98 return Err(Error::NotAnElfFile);
100 }
101 let class_endian_version_abi = data_source.read_u32_be(0x04)?;
102 if class_endian_version_abi != Self::DESIRED_ELF_VERSION {
103 return Err(Error::WrongElfFile);
104 }
105
106 let elf_type = data_source.read_u16_le(0x10)?;
109 if elf_type != Self::ET_EXEC {
110 return Err(Error::WrongElfFile);
112 }
113
114 let elf_machine = data_source.read_u16_le(0x12)?;
115 if elf_machine != Self::EM_ARM {
116 return Err(Error::WrongElfFile);
118 }
119
120 let elf_version = data_source.read_u32_le(0x14)?;
121 if elf_version != 1 {
122 return Err(Error::WrongElfFile);
124 }
125
126 let e_entry = data_source.read_u32_le(0x18)?;
127 let e_phoff = data_source.read_u32_le(0x1C)?;
128 let e_shoff = data_source.read_u32_le(0x20)?;
129 let e_phentsize = data_source.read_u16_le(0x2A)?;
130
131 if e_phentsize != ProgramHeader::SIZE_IN_BYTES {
132 return Err(Error::WrongElfFile);
133 }
134
135 let e_phnum = data_source.read_u16_le(0x2C)?;
136 let e_shentsize = data_source.read_u16_le(0x2E)?;
137
138 if e_shentsize != SectionHeader::SIZE_IN_BYTES {
139 return Err(Error::WrongElfFile);
140 }
141
142 let e_shnum = data_source.read_u16_le(0x30)?;
143
144 let e_shstrndx = data_source.read_u16_le(0x32)?;
145
146 let loader = Loader {
147 data_source,
148 e_entry,
149 e_phoff,
150 e_shoff,
151 e_phnum,
152 e_shnum,
153 e_shstrndx,
154 };
155 Ok(loader)
156 }
157
158 pub fn iter_section_headers(&self) -> IterSectionHeaders<DS> {
160 IterSectionHeaders {
161 parent: self,
162 next_section: 0,
163 }
164 }
165
166 pub fn iter_program_headers(&self) -> IterProgramHeaders<DS> {
168 IterProgramHeaders {
169 parent: self,
170 next_program_header: 0,
171 }
172 }
173
174 pub fn e_entry(&self) -> u32 {
176 self.e_entry
177 }
178
179 pub fn e_phoff(&self) -> u32 {
181 self.e_phoff
182 }
183
184 pub fn e_shoff(&self) -> u32 {
186 self.e_shoff
187 }
188
189 pub fn e_phnum(&self) -> u16 {
191 self.e_phnum
192 }
193
194 pub fn e_shnum(&self) -> u16 {
196 self.e_shnum
197 }
198
199 pub fn segment_start_offset(&self) -> u32 {
203 self.e_phoff() + u32::from(self.e_phnum()) * u32::from(ProgramHeader::SIZE_IN_BYTES)
204 }
205}
206
207pub struct IterSectionHeaders<'a, DS> {
211 parent: &'a Loader<DS>,
212 next_section: u16,
213}
214
215impl<'a, DS> Iterator for IterSectionHeaders<'a, DS>
216where
217 DS: Source,
218{
219 type Item = Result<SectionHeader, Error<DS::Error>>;
220
221 fn next(&mut self) -> Option<Self::Item> {
222 if self.next_section == self.parent.e_shnum {
223 return None;
224 }
225
226 let current_section = self.next_section;
227 self.next_section = self.next_section.wrapping_add(1);
228
229 Some(SectionHeader::new(self.parent, current_section))
230 }
231}
232
233pub struct IterProgramHeaders<'a, DS> {
237 parent: &'a Loader<DS>,
238 next_program_header: u16,
239}
240
241impl<'a, DS> Iterator for IterProgramHeaders<'a, DS>
242where
243 DS: Source,
244{
245 type Item = Result<ProgramHeader, Error<DS::Error>>;
246
247 fn next(&mut self) -> Option<Self::Item> {
248 if self.next_program_header == self.parent.e_phnum {
249 return None;
250 }
251
252 let current_program_header = self.next_program_header;
253 self.next_program_header = self.next_program_header.wrapping_add(1);
254
255 Some(ProgramHeader::new(self.parent, current_program_header))
256 }
257}
258
259