1use std::cmp::Ordering;
2
3use goblin;
4use paste::paste;
5
6use crate::{
7 event::EventPool,
8 frontend::{
9 error::LoaderError,
10 idmap::{
11 idmap_functions,
12 HasId,
13 HasIdMut,
14 Id,
15 IdMap,
16 IdMapValues,
17 IdMapValuesMut,
18 },
19 image::VAddr,
20 perms::Perms,
21 symbol::{
22 Symbol,
23 SymbolParser,
24 },
25 },
26 listing::ListingManager,
27};
28
29#[derive(Debug, Hash)]
31pub struct Section {
32 id: Id,
33 perms: Perms,
34 vaddr: VAddr,
35 offset: Option<usize>,
36 size: usize,
37 idmap: IdMap<Symbol>,
38 cursor: usize,
39}
40
41impl Section {
42 pub(crate) fn new(perms: Perms, vaddr: VAddr, offset: Option<usize>, size: usize) -> Self {
43 Self {
44 id: Id::default(),
45 perms,
46 vaddr,
47 offset,
48 size,
49 idmap: IdMap::new(),
50 cursor: 0,
51 }
52 }
53
54 pub(crate) fn offset(&self) -> Option<usize> {
55 self.offset
56 }
57
58 pub fn last_addr(&self) -> VAddr {
60 self.vaddr + self.size as VAddr - 1
61 }
62
63 pub fn contains_address(&self, vaddr: VAddr) -> bool {
65 self.vaddr <= vaddr && vaddr <= self.last_addr()
66 }
67
68 pub fn size(&self) -> usize {
70 self.size
71 }
72
73 pub fn perms(&self) -> Perms {
75 self.perms
76 }
77
78 pub fn vaddr(&self) -> VAddr {
80 self.vaddr
81 }
82
83 pub fn set_size(&mut self, size: usize) {
85 self.size = size;
86 }
87
88 pub fn set_perms(&mut self, perms: Perms) {
90 self.perms = perms;
91 }
92
93 pub fn set_vaddr(&mut self, vaddr: VAddr) {
95 self.vaddr = vaddr;
96 }
97
98 pub fn builder() -> SectionBuilder {
100 SectionBuilder {
101 perms: None,
102 vaddr: 0,
103 size: None,
104 }
105 }
106}
107
108idmap_functions!(Section, Symbol, symbol);
109
110impl HasId for Section {
111 fn id(&self) -> Id {
112 self.id
113 }
114}
115
116impl HasIdMut for Section {
117 fn id_mut(&mut self) -> &mut Id {
118 &mut self.id
119 }
120}
121
122pub struct SectionBuilder {
124 perms: Option<Perms>,
125 vaddr: VAddr,
126 size: Option<usize>,
127}
128
129impl SectionBuilder {
130 pub fn perms(mut self, perms: Perms) -> Self {
132 self.perms = Some(perms);
133 self
134 }
135
136 pub fn vaddr(mut self, vaddr: VAddr) -> Self {
138 self.vaddr = vaddr;
139 self
140 }
141
142 pub fn size(mut self, size: usize) -> Self {
144 self.size = Some(size);
145 self
146 }
147
148 pub fn build(self) -> Result<Section, &'static str> {
150 let perms = self.perms.ok_or("Section permissions were not set")?;
151 let size = self.size.ok_or("Section size was not set")?;
152 Ok(Section::new(perms, self.vaddr, None, size))
153 }
154}
155
156pub(crate) struct SectionParser {
157 sections: Vec<Section>,
158}
159
160impl SectionParser {
161 pub(crate) fn parse(
162 elf: &goblin::elf::Elf,
163 content: &[u8],
164 listing: &ListingManager,
165 event_pool: &mut EventPool,
166 ) -> Result<IdMap<Section>, LoaderError> {
167 let mut parser = Self::new();
169 parser.parse_program_headers(elf)?;
170 parser.parse_section_headers(elf)?;
171 parser.merge_sections();
172 parser.verify(elf)?;
173
174 for section in &mut parser.sections {
183 section.idmap = SymbolParser::parse(elf, section, content, listing, event_pool)?;
184 }
185
186 let mut map = IdMap::new();
188
189 for section in parser.sections {
190 map.insert(section);
191 }
192
193 Ok(map)
194 }
195
196 fn new() -> Self {
197 Self {
198 sections: Vec::new(),
199 }
200 }
201
202 fn parse_program_headers(&mut self, elf: &goblin::elf::Elf) -> Result<(), LoaderError> {
203 for ph in &elf.program_headers {
204 if ph.p_type == goblin::elf::program_header::PT_LOAD {
205 let mut perms = Perms::from_segment_flags(ph.p_flags);
213
214 if perms.is_inaccessible() {
215 continue;
216 }
217
218 if perms.is_readable() || perms.is_writable() {
219 perms.clear_executable();
220 }
221
222 if ph.p_memsz < ph.p_filesz {
223 return Err(LoaderError::InvalidELF("Segment memsz < filesz".to_string()));
224 }
225
226 let uninit_size = ph.p_memsz - ph.p_filesz;
228
229 if ph.p_filesz > 0 {
230 self.add_section(
231 perms,
232 ph.p_vaddr as VAddr,
233 Some(ph.p_offset as usize),
234 ph.p_filesz as usize,
235 true,
236 )?;
237 }
238
239 if uninit_size > 0 {
240 self.add_section(perms, (ph.p_vaddr + ph.p_filesz) as VAddr, None, uninit_size as usize, true)?;
241 }
242 }
243 }
244
245 Ok(())
246 }
247
248 fn parse_section_headers(&mut self, elf: &goblin::elf::Elf) -> Result<(), LoaderError> {
249 for sh in &elf.section_headers {
250 if sh.is_alloc() && (sh.sh_flags & goblin::elf::section_header::SHF_TLS as u64) == 0 {
251 let offset = match sh.sh_type {
252 goblin::elf::section_header::SHT_NOBITS => None,
253 _ => Some(sh.sh_offset as usize),
254 };
255
256 self.add_section(
257 Perms::from_section_header(sh),
258 sh.sh_addr as VAddr,
259 offset,
260 sh.sh_size as usize,
261 false,
262 )?;
263 }
264 }
265
266 Ok(())
267 }
268
269 fn add_section(
270 &mut self,
271 perms: Perms,
272 vaddr: VAddr,
273 offset: Option<usize>,
274 size: usize,
275 from_segment: bool,
276 ) -> Result<(), LoaderError> {
277 if size == 0 {
278 return Ok(());
279 } else if perms.is_writable() && perms.is_executable() {
280 return Err(LoaderError::InvalidELF("Binary contains rwx sections/segments".to_string()));
281 }
282
283 let new_section = Section::new(perms, vaddr, offset, size);
284
285 match self.locate_section(&new_section) {
286 Ok(idx) => {
287 if from_segment {
288 return Err(LoaderError::InvalidELF("Found overlapping segments".to_string()));
289 }
290
291 let old_section = &mut self.sections[idx];
293 if new_section.vaddr == old_section.vaddr && new_section.last_addr() == old_section.last_addr() {
294 old_section.perms = new_section.perms;
295 old_section.offset = new_section.offset;
296 return Ok(());
297 }
298
299 let mut old_section = self.sections.remove(idx);
301
302 if new_section.vaddr() == old_section.vaddr() {
303 old_section.vaddr += new_section.size() as VAddr;
304 if let Some(offset) = &mut old_section.offset {
305 *offset += new_section.size();
306 }
307 old_section.size -= new_section.size();
308
309 self.sections.insert(idx, new_section);
310 self.sections.insert(idx + 1, old_section);
311 } else if new_section.last_addr() == old_section.last_addr() {
312 old_section.size -= new_section.size();
313
314 self.sections.insert(idx, old_section);
315 self.sections.insert(idx + 1, new_section);
316 } else {
317 let mut left =
318 Section::new(old_section.perms, old_section.vaddr, old_section.offset, old_section.size);
319 let mut right = old_section;
320
321 left.size = (new_section.vaddr - left.vaddr) as usize;
322
323 let shift_amount = left.size() + new_section.size();
324 right.vaddr += shift_amount as VAddr;
325 if let Some(offset) = &mut right.offset {
326 *offset += shift_amount;
327 }
328 right.size -= shift_amount;
329
330 self.sections.insert(idx, left);
331 self.sections.insert(idx + 1, new_section);
332 self.sections.insert(idx + 2, right);
333 }
334 },
335 Err(idx) => {
336 if !from_segment {
337 return Err(LoaderError::InvalidELF(format!("Section not in any segment: {:#x}", vaddr)));
338 }
339
340 self.sections.insert(idx, new_section);
341 },
342 }
343
344 Ok(())
345 }
346
347 fn locate_section(&self, section: &Section) -> Result<usize, usize> {
348 self.sections.binary_search_by(|x| {
349 if x.contains_address(section.vaddr) && x.contains_address(section.last_addr()) {
350 Ordering::Equal
351 } else {
352 let l = x.vaddr.cmp(§ion.vaddr);
353 let r = x.vaddr.cmp(§ion.last_addr());
354 assert_eq!(l, r, "Overlapping sections: x={:?} section={:?}", x, section);
355 l
356 }
357 })
358 }
359
360 fn merge_sections(&mut self) {
361 let mut i = 1;
362
363 while i < self.sections.len() {
364 let l = &self.sections[i - 1];
365 let r = &self.sections[i];
366
367 let same_perms = l.perms() == r.perms();
368 let cont_vaddr = l.vaddr() + l.size() as VAddr == r.vaddr();
369 let cont_offset = l.offset().map(|x| x + l.size()) == r.offset();
370
371 if same_perms && cont_vaddr && cont_offset {
372 let section = self.sections.remove(i);
373 self.sections[i - 1].size += section.size();
374 } else {
375 i += 1;
376 }
377 }
378 }
379
380 fn verify(&self, elf: &goblin::elf::Elf) -> Result<(), LoaderError> {
381 for ph in &elf.program_headers {
383 if ph.p_type == goblin::elf::program_header::PT_LOAD {
384 let mut idx = 0;
386
387 while idx < self.sections.len() && self.sections[idx].vaddr < ph.p_vaddr {
388 idx += 1;
389 }
390
391 assert!(idx < self.sections.len());
392
393 let end_addr = ph.p_vaddr + ph.p_filesz;
395 let mut vaddr_cursor = ph.p_vaddr as VAddr;
396
397 while idx < self.sections.len() && self.sections[idx].vaddr < end_addr {
398 assert_eq!(self.sections[idx].vaddr(), vaddr_cursor);
399 vaddr_cursor += self.sections[idx].size() as VAddr;
400 idx += 1;
401 }
402
403 assert_eq!(vaddr_cursor, end_addr);
404 }
405 }
406
407 for section in &self.sections {
409 assert!(!section.perms().is_inaccessible());
410 assert!(section.size() > 0);
411 }
412
413 Ok(())
414 }
415
416 }