1use alloc::vec::Vec;
2use core::convert::TryInto;
3use core::fmt::Debug;
4use core::mem;
5
6use crate::read::{
7 self, util, Architecture, ByteString, Bytes, Error, Export, FileFlags, Import, Object,
8 ObjectKind, ReadError, ReadRef, SectionIndex, StringTable, SymbolIndex,
9};
10use crate::{elf, endian, Endian, Endianness, Pod, U32};
11
12use super::{
13 CompressionHeader, Dyn, ElfComdat, ElfComdatIterator, ElfDynamicRelocationIterator, ElfSection,
14 ElfSectionIterator, ElfSegment, ElfSegmentIterator, ElfSymbol, ElfSymbolIterator,
15 ElfSymbolTable, NoteHeader, ProgramHeader, Rel, Rela, RelocationSections, SectionHeader,
16 SectionTable, Sym, SymbolTable,
17};
18
19/// A 32-bit ELF object file.
20///
21/// This is a file that starts with [`elf::FileHeader32`], and corresponds
22/// to [`crate::FileKind::Elf32`].
23pub type ElfFile32<'data, Endian = Endianness, R = &'data [u8]> =
24 ElfFile<'data, elf::FileHeader32<Endian>, R>;
25/// A 64-bit ELF object file.
26///
27/// This is a file that starts with [`elf::FileHeader64`], and corresponds
28/// to [`crate::FileKind::Elf64`].
29pub type ElfFile64<'data, Endian = Endianness, R = &'data [u8]> =
30 ElfFile<'data, elf::FileHeader64<Endian>, R>;
31
32/// A partially parsed ELF file.
33///
34/// Most functionality is provided by the [`Object`] trait implementation.
35#[derive(Debug)]
36pub struct ElfFile<'data, Elf, R = &'data [u8]>
37where
38 Elf: FileHeader,
39 R: ReadRef<'data>,
40{
41 pub(super) endian: Elf::Endian,
42 pub(super) data: R,
43 pub(super) header: &'data Elf,
44 pub(super) segments: &'data [Elf::ProgramHeader],
45 pub(super) sections: SectionTable<'data, Elf, R>,
46 pub(super) relocations: RelocationSections,
47 pub(super) symbols: SymbolTable<'data, Elf, R>,
48 pub(super) dynamic_symbols: SymbolTable<'data, Elf, R>,
49}
50
51impl<'data, Elf, R> ElfFile<'data, Elf, R>
52where
53 Elf: FileHeader,
54 R: ReadRef<'data>,
55{
56 /// Parse the raw ELF file data.
57 pub fn parse(data: R) -> read::Result<Self> {
58 let header = Elf::parse(data)?;
59 let endian = header.endian()?;
60 let segments = header.program_headers(endian, data)?;
61 let sections = header.sections(endian, data)?;
62 let symbols = sections.symbols(endian, data, elf::SHT_SYMTAB)?;
63 // TODO: get dynamic symbols from DT_SYMTAB if there are no sections
64 let dynamic_symbols = sections.symbols(endian, data, elf::SHT_DYNSYM)?;
65 // The API we provide requires a mapping from section to relocations, so build it now.
66 let relocations = sections.relocation_sections(endian, symbols.section())?;
67
68 Ok(ElfFile {
69 endian,
70 data,
71 header,
72 segments,
73 sections,
74 relocations,
75 symbols,
76 dynamic_symbols,
77 })
78 }
79
80 /// Returns the endianness.
81 pub fn endian(&self) -> Elf::Endian {
82 self.endian
83 }
84
85 /// Returns the raw data.
86 pub fn data(&self) -> R {
87 self.data
88 }
89
90 /// Returns the raw ELF file header.
91 pub fn raw_header(&self) -> &'data Elf {
92 self.header
93 }
94
95 /// Returns the raw ELF segments.
96 pub fn raw_segments(&self) -> &'data [Elf::ProgramHeader] {
97 self.segments
98 }
99
100 fn raw_section_by_name<'file>(
101 &'file self,
102 section_name: &[u8],
103 ) -> Option<ElfSection<'data, 'file, Elf, R>> {
104 self.sections
105 .section_by_name(self.endian, section_name)
106 .map(|(index, section)| ElfSection {
107 file: self,
108 index: SectionIndex(index),
109 section,
110 })
111 }
112
113 #[cfg(feature = "compression")]
114 fn zdebug_section_by_name<'file>(
115 &'file self,
116 section_name: &[u8],
117 ) -> Option<ElfSection<'data, 'file, Elf, R>> {
118 if !section_name.starts_with(b".debug_") {
119 return None;
120 }
121 let mut name = Vec::with_capacity(section_name.len() + 1);
122 name.extend_from_slice(b".zdebug_");
123 name.extend_from_slice(&section_name[7..]);
124 self.raw_section_by_name(&name)
125 }
126
127 #[cfg(not(feature = "compression"))]
128 fn zdebug_section_by_name<'file>(
129 &'file self,
130 _section_name: &[u8],
131 ) -> Option<ElfSection<'data, 'file, Elf, R>> {
132 None
133 }
134}
135
136impl<'data, Elf, R> read::private::Sealed for ElfFile<'data, Elf, R>
137where
138 Elf: FileHeader,
139 R: ReadRef<'data>,
140{
141}
142
143impl<'data, 'file, Elf, R> Object<'data, 'file> for ElfFile<'data, Elf, R>
144where
145 'data: 'file,
146 Elf: FileHeader,
147 R: 'file + ReadRef<'data>,
148{
149 type Segment = ElfSegment<'data, 'file, Elf, R>;
150 type SegmentIterator = ElfSegmentIterator<'data, 'file, Elf, R>;
151 type Section = ElfSection<'data, 'file, Elf, R>;
152 type SectionIterator = ElfSectionIterator<'data, 'file, Elf, R>;
153 type Comdat = ElfComdat<'data, 'file, Elf, R>;
154 type ComdatIterator = ElfComdatIterator<'data, 'file, Elf, R>;
155 type Symbol = ElfSymbol<'data, 'file, Elf, R>;
156 type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf, R>;
157 type SymbolTable = ElfSymbolTable<'data, 'file, Elf, R>;
158 type DynamicRelocationIterator = ElfDynamicRelocationIterator<'data, 'file, Elf, R>;
159
160 fn architecture(&self) -> Architecture {
161 match (
162 self.header.e_machine(self.endian),
163 self.header.is_class_64(),
164 ) {
165 (elf::EM_AARCH64, true) => Architecture::Aarch64,
166 (elf::EM_AARCH64, false) => Architecture::Aarch64_Ilp32,
167 (elf::EM_ARM, _) => Architecture::Arm,
168 (elf::EM_AVR, _) => Architecture::Avr,
169 (elf::EM_BPF, _) => Architecture::Bpf,
170 (elf::EM_CSKY, _) => Architecture::Csky,
171 (elf::EM_386, _) => Architecture::I386,
172 (elf::EM_X86_64, false) => Architecture::X86_64_X32,
173 (elf::EM_X86_64, true) => Architecture::X86_64,
174 (elf::EM_HEXAGON, _) => Architecture::Hexagon,
175 (elf::EM_LOONGARCH, true) => Architecture::LoongArch64,
176 (elf::EM_MIPS, false) => Architecture::Mips,
177 (elf::EM_MIPS, true) => Architecture::Mips64,
178 (elf::EM_MSP430, _) => Architecture::Msp430,
179 (elf::EM_PPC, _) => Architecture::PowerPc,
180 (elf::EM_PPC64, _) => Architecture::PowerPc64,
181 (elf::EM_RISCV, false) => Architecture::Riscv32,
182 (elf::EM_RISCV, true) => Architecture::Riscv64,
183 // This is either s390 or s390x, depending on the ELF class.
184 // We only support the 64-bit variant s390x here.
185 (elf::EM_S390, true) => Architecture::S390x,
186 (elf::EM_SBF, _) => Architecture::Sbf,
187 (elf::EM_SHARC, false) => Architecture::Sharc,
188 (elf::EM_SPARCV9, true) => Architecture::Sparc64,
189 (elf::EM_XTENSA, false) => Architecture::Xtensa,
190 _ => Architecture::Unknown,
191 }
192 }
193
194 #[inline]
195 fn is_little_endian(&self) -> bool {
196 self.header.is_little_endian()
197 }
198
199 #[inline]
200 fn is_64(&self) -> bool {
201 self.header.is_class_64()
202 }
203
204 fn kind(&self) -> ObjectKind {
205 match self.header.e_type(self.endian) {
206 elf::ET_REL => ObjectKind::Relocatable,
207 elf::ET_EXEC => ObjectKind::Executable,
208 // TODO: check for `DF_1_PIE`?
209 elf::ET_DYN => ObjectKind::Dynamic,
210 elf::ET_CORE => ObjectKind::Core,
211 _ => ObjectKind::Unknown,
212 }
213 }
214
215 fn segments(&'file self) -> ElfSegmentIterator<'data, 'file, Elf, R> {
216 ElfSegmentIterator {
217 file: self,
218 iter: self.segments.iter(),
219 }
220 }
221
222 fn section_by_name_bytes(
223 &'file self,
224 section_name: &[u8],
225 ) -> Option<ElfSection<'data, 'file, Elf, R>> {
226 self.raw_section_by_name(section_name)
227 .or_else(|| self.zdebug_section_by_name(section_name))
228 }
229
230 fn section_by_index(
231 &'file self,
232 index: SectionIndex,
233 ) -> read::Result<ElfSection<'data, 'file, Elf, R>> {
234 let section = self.sections.section(index)?;
235 Ok(ElfSection {
236 file: self,
237 index,
238 section,
239 })
240 }
241
242 fn sections(&'file self) -> ElfSectionIterator<'data, 'file, Elf, R> {
243 ElfSectionIterator {
244 file: self,
245 iter: self.sections.iter().enumerate(),
246 }
247 }
248
249 fn comdats(&'file self) -> ElfComdatIterator<'data, 'file, Elf, R> {
250 ElfComdatIterator {
251 file: self,
252 iter: self.sections.iter().enumerate(),
253 }
254 }
255
256 fn symbol_by_index(
257 &'file self,
258 index: SymbolIndex,
259 ) -> read::Result<ElfSymbol<'data, 'file, Elf, R>> {
260 let symbol = self.symbols.symbol(index.0)?;
261 Ok(ElfSymbol {
262 endian: self.endian,
263 symbols: &self.symbols,
264 index,
265 symbol,
266 })
267 }
268
269 fn symbols(&'file self) -> ElfSymbolIterator<'data, 'file, Elf, R> {
270 ElfSymbolIterator {
271 endian: self.endian,
272 symbols: &self.symbols,
273 index: 0,
274 }
275 }
276
277 fn symbol_table(&'file self) -> Option<ElfSymbolTable<'data, 'file, Elf, R>> {
278 if self.symbols.is_empty() {
279 return None;
280 }
281 Some(ElfSymbolTable {
282 endian: self.endian,
283 symbols: &self.symbols,
284 })
285 }
286
287 fn dynamic_symbols(&'file self) -> ElfSymbolIterator<'data, 'file, Elf, R> {
288 ElfSymbolIterator {
289 endian: self.endian,
290 symbols: &self.dynamic_symbols,
291 index: 0,
292 }
293 }
294
295 fn dynamic_symbol_table(&'file self) -> Option<ElfSymbolTable<'data, 'file, Elf, R>> {
296 if self.dynamic_symbols.is_empty() {
297 return None;
298 }
299 Some(ElfSymbolTable {
300 endian: self.endian,
301 symbols: &self.dynamic_symbols,
302 })
303 }
304
305 fn dynamic_relocations(
306 &'file self,
307 ) -> Option<ElfDynamicRelocationIterator<'data, 'file, Elf, R>> {
308 Some(ElfDynamicRelocationIterator {
309 section_index: SectionIndex(1),
310 file: self,
311 relocations: None,
312 })
313 }
314
315 fn imports(&self) -> read::Result<Vec<Import<'data>>> {
316 let mut imports = Vec::new();
317 for symbol in self.dynamic_symbols.iter() {
318 if symbol.is_undefined(self.endian) {
319 let name = symbol.name(self.endian, self.dynamic_symbols.strings())?;
320 if !name.is_empty() {
321 // TODO: use symbol versioning to determine library
322 imports.push(Import {
323 name: ByteString(name),
324 library: ByteString(&[]),
325 });
326 }
327 }
328 }
329 Ok(imports)
330 }
331
332 fn exports(&self) -> read::Result<Vec<Export<'data>>> {
333 let mut exports = Vec::new();
334 for symbol in self.dynamic_symbols.iter() {
335 if symbol.is_definition(self.endian) {
336 let name = symbol.name(self.endian, self.dynamic_symbols.strings())?;
337 let address = symbol.st_value(self.endian).into();
338 exports.push(Export {
339 name: ByteString(name),
340 address,
341 });
342 }
343 }
344 Ok(exports)
345 }
346
347 fn has_debug_symbols(&self) -> bool {
348 for section in self.sections.iter() {
349 if let Ok(name) = self.sections.section_name(self.endian, section) {
350 if name == b".debug_info" || name == b".zdebug_info" {
351 return true;
352 }
353 }
354 }
355 false
356 }
357
358 fn build_id(&self) -> read::Result<Option<&'data [u8]>> {
359 let endian = self.endian;
360 // Use section headers if present, otherwise use program headers.
361 if !self.sections.is_empty() {
362 for section in self.sections.iter() {
363 if let Some(mut notes) = section.notes(endian, self.data)? {
364 while let Some(note) = notes.next()? {
365 if note.name() == elf::ELF_NOTE_GNU
366 && note.n_type(endian) == elf::NT_GNU_BUILD_ID
367 {
368 return Ok(Some(note.desc()));
369 }
370 }
371 }
372 }
373 } else {
374 for segment in self.segments {
375 if let Some(mut notes) = segment.notes(endian, self.data)? {
376 while let Some(note) = notes.next()? {
377 if note.name() == elf::ELF_NOTE_GNU
378 && note.n_type(endian) == elf::NT_GNU_BUILD_ID
379 {
380 return Ok(Some(note.desc()));
381 }
382 }
383 }
384 }
385 }
386 Ok(None)
387 }
388
389 fn gnu_debuglink(&self) -> read::Result<Option<(&'data [u8], u32)>> {
390 let section = match self.raw_section_by_name(b".gnu_debuglink") {
391 Some(section) => section,
392 None => return Ok(None),
393 };
394 let data = section
395 .section
396 .data(self.endian, self.data)
397 .read_error("Invalid ELF .gnu_debuglink section offset or size")
398 .map(Bytes)?;
399 let filename = data
400 .read_string_at(0)
401 .read_error("Missing ELF .gnu_debuglink filename")?;
402 let crc_offset = util::align(filename.len() + 1, 4);
403 let crc = data
404 .read_at::<U32<_>>(crc_offset)
405 .read_error("Missing ELF .gnu_debuglink crc")?
406 .get(self.endian);
407 Ok(Some((filename, crc)))
408 }
409
410 fn gnu_debugaltlink(&self) -> read::Result<Option<(&'data [u8], &'data [u8])>> {
411 let section = match self.raw_section_by_name(b".gnu_debugaltlink") {
412 Some(section) => section,
413 None => return Ok(None),
414 };
415 let mut data = section
416 .section
417 .data(self.endian, self.data)
418 .read_error("Invalid ELF .gnu_debugaltlink section offset or size")
419 .map(Bytes)?;
420 let filename = data
421 .read_string()
422 .read_error("Missing ELF .gnu_debugaltlink filename")?;
423 let build_id = data.0;
424 Ok(Some((filename, build_id)))
425 }
426
427 fn relative_address_base(&self) -> u64 {
428 0
429 }
430
431 fn entry(&self) -> u64 {
432 self.header.e_entry(self.endian).into()
433 }
434
435 fn flags(&self) -> FileFlags {
436 FileFlags::Elf {
437 os_abi: self.header.e_ident().os_abi,
438 abi_version: self.header.e_ident().abi_version,
439 e_flags: self.header.e_flags(self.endian),
440 }
441 }
442}
443
444/// A trait for generic access to [`elf::FileHeader32`] and [`elf::FileHeader64`].
445#[allow(missing_docs)]
446pub trait FileHeader: Debug + Pod {
447 // Ideally this would be a `u64: From<Word>`, but can't express that.
448 type Word: Into<u64>;
449 type Sword: Into<i64>;
450 type Endian: endian::Endian;
451 type ProgramHeader: ProgramHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>;
452 type SectionHeader: SectionHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>;
453 type CompressionHeader: CompressionHeader<Endian = Self::Endian, Word = Self::Word>;
454 type NoteHeader: NoteHeader<Endian = Self::Endian>;
455 type Dyn: Dyn<Endian = Self::Endian, Word = Self::Word>;
456 type Sym: Sym<Endian = Self::Endian, Word = Self::Word>;
457 type Rel: Rel<Endian = Self::Endian, Word = Self::Word>;
458 type Rela: Rela<Endian = Self::Endian, Word = Self::Word> + From<Self::Rel>;
459
460 /// Return true if this type is a 64-bit header.
461 ///
462 /// This is a property of the type, not a value in the header data.
463 fn is_type_64(&self) -> bool;
464
465 /// Return true if this type is a 64-bit header.
466 ///
467 /// This is a property of the type, not a value in the header data.
468 ///
469 /// This is the same as [`Self::is_type_64`], but is non-dispatchable.
470 fn is_type_64_sized() -> bool
471 where
472 Self: Sized;
473
474 fn e_ident(&self) -> &elf::Ident;
475 fn e_type(&self, endian: Self::Endian) -> u16;
476 fn e_machine(&self, endian: Self::Endian) -> u16;
477 fn e_version(&self, endian: Self::Endian) -> u32;
478 fn e_entry(&self, endian: Self::Endian) -> Self::Word;
479 fn e_phoff(&self, endian: Self::Endian) -> Self::Word;
480 fn e_shoff(&self, endian: Self::Endian) -> Self::Word;
481 fn e_flags(&self, endian: Self::Endian) -> u32;
482 fn e_ehsize(&self, endian: Self::Endian) -> u16;
483 fn e_phentsize(&self, endian: Self::Endian) -> u16;
484 fn e_phnum(&self, endian: Self::Endian) -> u16;
485 fn e_shentsize(&self, endian: Self::Endian) -> u16;
486 fn e_shnum(&self, endian: Self::Endian) -> u16;
487 fn e_shstrndx(&self, endian: Self::Endian) -> u16;
488
489 // Provided methods.
490
491 /// Read the file header.
492 ///
493 /// Also checks that the ident field in the file header is a supported format.
494 fn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> {
495 let header = data
496 .read_at::<Self>(0)
497 .read_error("Invalid ELF header size or alignment")?;
498 if !header.is_supported() {
499 return Err(Error("Unsupported ELF header"));
500 }
501 // TODO: Check self.e_ehsize?
502 Ok(header)
503 }
504
505 /// Check that the ident field in the file header is a supported format.
506 ///
507 /// This checks the magic number, version, class, and endianness.
508 fn is_supported(&self) -> bool {
509 let ident = self.e_ident();
510 // TODO: Check self.e_version too? Requires endian though.
511 ident.magic == elf::ELFMAG
512 && (self.is_type_64() || self.is_class_32())
513 && (!self.is_type_64() || self.is_class_64())
514 && (self.is_little_endian() || self.is_big_endian())
515 && ident.version == elf::EV_CURRENT
516 }
517
518 fn is_class_32(&self) -> bool {
519 self.e_ident().class == elf::ELFCLASS32
520 }
521
522 fn is_class_64(&self) -> bool {
523 self.e_ident().class == elf::ELFCLASS64
524 }
525
526 fn is_little_endian(&self) -> bool {
527 self.e_ident().data == elf::ELFDATA2LSB
528 }
529
530 fn is_big_endian(&self) -> bool {
531 self.e_ident().data == elf::ELFDATA2MSB
532 }
533
534 fn endian(&self) -> read::Result<Self::Endian> {
535 Self::Endian::from_big_endian(self.is_big_endian()).read_error("Unsupported ELF endian")
536 }
537
538 /// Return the first section header, if present.
539 ///
540 /// Section 0 is a special case because getting the section headers normally
541 /// requires `shnum`, but `shnum` may be in the first section header.
542 fn section_0<'data, R: ReadRef<'data>>(
543 &self,
544 endian: Self::Endian,
545 data: R,
546 ) -> read::Result<Option<&'data Self::SectionHeader>> {
547 let shoff: u64 = self.e_shoff(endian).into();
548 if shoff == 0 {
549 // No section headers is ok.
550 return Ok(None);
551 }
552 let shentsize = usize::from(self.e_shentsize(endian));
553 if shentsize != mem::size_of::<Self::SectionHeader>() {
554 // Section header size must match.
555 return Err(Error("Invalid ELF section header entry size"));
556 }
557 data.read_at(shoff)
558 .map(Some)
559 .read_error("Invalid ELF section header offset or size")
560 }
561
562 /// Return the `e_phnum` field of the header. Handles extended values.
563 ///
564 /// Returns `Err` for invalid values.
565 fn phnum<'data, R: ReadRef<'data>>(
566 &self,
567 endian: Self::Endian,
568 data: R,
569 ) -> read::Result<usize> {
570 let e_phnum = self.e_phnum(endian);
571 if e_phnum < elf::PN_XNUM {
572 Ok(e_phnum as usize)
573 } else if let Some(section_0) = self.section_0(endian, data)? {
574 Ok(section_0.sh_info(endian) as usize)
575 } else {
576 // Section 0 must exist if e_phnum overflows.
577 Err(Error("Missing ELF section headers for e_phnum overflow"))
578 }
579 }
580
581 /// Return the `e_shnum` field of the header. Handles extended values.
582 ///
583 /// Returns `Err` for invalid values.
584 fn shnum<'data, R: ReadRef<'data>>(
585 &self,
586 endian: Self::Endian,
587 data: R,
588 ) -> read::Result<usize> {
589 let e_shnum = self.e_shnum(endian);
590 if e_shnum > 0 {
591 Ok(e_shnum as usize)
592 } else if let Some(section_0) = self.section_0(endian, data)? {
593 section_0
594 .sh_size(endian)
595 .into()
596 .try_into()
597 .ok()
598 .read_error("Invalid ELF extended e_shnum")
599 } else {
600 // No section headers is ok.
601 Ok(0)
602 }
603 }
604
605 /// Return the `e_shstrndx` field of the header. Handles extended values.
606 ///
607 /// Returns `Err` for invalid values (including if the index is 0).
608 fn shstrndx<'data, R: ReadRef<'data>>(
609 &self,
610 endian: Self::Endian,
611 data: R,
612 ) -> read::Result<u32> {
613 let e_shstrndx = self.e_shstrndx(endian);
614 let index = if e_shstrndx != elf::SHN_XINDEX {
615 e_shstrndx.into()
616 } else if let Some(section_0) = self.section_0(endian, data)? {
617 section_0.sh_link(endian)
618 } else {
619 // Section 0 must exist if we're trying to read e_shstrndx.
620 return Err(Error("Missing ELF section headers for e_shstrndx overflow"));
621 };
622 if index == 0 {
623 return Err(Error("Missing ELF e_shstrndx"));
624 }
625 Ok(index)
626 }
627
628 /// Return the slice of program headers.
629 ///
630 /// Returns `Ok(&[])` if there are no program headers.
631 /// Returns `Err` for invalid values.
632 fn program_headers<'data, R: ReadRef<'data>>(
633 &self,
634 endian: Self::Endian,
635 data: R,
636 ) -> read::Result<&'data [Self::ProgramHeader]> {
637 let phoff: u64 = self.e_phoff(endian).into();
638 if phoff == 0 {
639 // No program headers is ok.
640 return Ok(&[]);
641 }
642 let phnum = self.phnum(endian, data)?;
643 if phnum == 0 {
644 // No program headers is ok.
645 return Ok(&[]);
646 }
647 let phentsize = self.e_phentsize(endian) as usize;
648 if phentsize != mem::size_of::<Self::ProgramHeader>() {
649 // Program header size must match.
650 return Err(Error("Invalid ELF program header entry size"));
651 }
652 data.read_slice_at(phoff, phnum)
653 .read_error("Invalid ELF program header size or alignment")
654 }
655
656 /// Return the slice of section headers.
657 ///
658 /// Returns `Ok(&[])` if there are no section headers.
659 /// Returns `Err` for invalid values.
660 fn section_headers<'data, R: ReadRef<'data>>(
661 &self,
662 endian: Self::Endian,
663 data: R,
664 ) -> read::Result<&'data [Self::SectionHeader]> {
665 let shoff: u64 = self.e_shoff(endian).into();
666 if shoff == 0 {
667 // No section headers is ok.
668 return Ok(&[]);
669 }
670 let shnum = self.shnum(endian, data)?;
671 if shnum == 0 {
672 // No section headers is ok.
673 return Ok(&[]);
674 }
675 let shentsize = usize::from(self.e_shentsize(endian));
676 if shentsize != mem::size_of::<Self::SectionHeader>() {
677 // Section header size must match.
678 return Err(Error("Invalid ELF section header entry size"));
679 }
680 data.read_slice_at(shoff, shnum)
681 .read_error("Invalid ELF section header offset/size/alignment")
682 }
683
684 /// Return the string table for the section headers.
685 fn section_strings<'data, R: ReadRef<'data>>(
686 &self,
687 endian: Self::Endian,
688 data: R,
689 sections: &[Self::SectionHeader],
690 ) -> read::Result<StringTable<'data, R>> {
691 if sections.is_empty() {
692 return Ok(StringTable::default());
693 }
694 let index = self.shstrndx(endian, data)? as usize;
695 let shstrtab = sections.get(index).read_error("Invalid ELF e_shstrndx")?;
696 let strings = if let Some((shstrtab_offset, shstrtab_size)) = shstrtab.file_range(endian) {
697 let shstrtab_end = shstrtab_offset
698 .checked_add(shstrtab_size)
699 .read_error("Invalid ELF shstrtab size")?;
700 StringTable::new(data, shstrtab_offset, shstrtab_end)
701 } else {
702 StringTable::default()
703 };
704 Ok(strings)
705 }
706
707 /// Return the section table.
708 fn sections<'data, R: ReadRef<'data>>(
709 &self,
710 endian: Self::Endian,
711 data: R,
712 ) -> read::Result<SectionTable<'data, Self, R>> {
713 let sections = self.section_headers(endian, data)?;
714 let strings = self.section_strings(endian, data, sections)?;
715 Ok(SectionTable::new(sections, strings))
716 }
717
718 /// Returns whether this is a mips64el elf file.
719 fn is_mips64el(&self, endian: Self::Endian) -> bool {
720 self.is_class_64() && self.is_little_endian() && self.e_machine(endian) == elf::EM_MIPS
721 }
722}
723
724impl<Endian: endian::Endian> FileHeader for elf::FileHeader32<Endian> {
725 type Word = u32;
726 type Sword = i32;
727 type Endian = Endian;
728 type ProgramHeader = elf::ProgramHeader32<Endian>;
729 type SectionHeader = elf::SectionHeader32<Endian>;
730 type CompressionHeader = elf::CompressionHeader32<Endian>;
731 type NoteHeader = elf::NoteHeader32<Endian>;
732 type Dyn = elf::Dyn32<Endian>;
733 type Sym = elf::Sym32<Endian>;
734 type Rel = elf::Rel32<Endian>;
735 type Rela = elf::Rela32<Endian>;
736
737 #[inline]
738 fn is_type_64(&self) -> bool {
739 false
740 }
741
742 #[inline]
743 fn is_type_64_sized() -> bool
744 where
745 Self: Sized,
746 {
747 false
748 }
749
750 #[inline]
751 fn e_ident(&self) -> &elf::Ident {
752 &self.e_ident
753 }
754
755 #[inline]
756 fn e_type(&self, endian: Self::Endian) -> u16 {
757 self.e_type.get(endian)
758 }
759
760 #[inline]
761 fn e_machine(&self, endian: Self::Endian) -> u16 {
762 self.e_machine.get(endian)
763 }
764
765 #[inline]
766 fn e_version(&self, endian: Self::Endian) -> u32 {
767 self.e_version.get(endian)
768 }
769
770 #[inline]
771 fn e_entry(&self, endian: Self::Endian) -> Self::Word {
772 self.e_entry.get(endian)
773 }
774
775 #[inline]
776 fn e_phoff(&self, endian: Self::Endian) -> Self::Word {
777 self.e_phoff.get(endian)
778 }
779
780 #[inline]
781 fn e_shoff(&self, endian: Self::Endian) -> Self::Word {
782 self.e_shoff.get(endian)
783 }
784
785 #[inline]
786 fn e_flags(&self, endian: Self::Endian) -> u32 {
787 self.e_flags.get(endian)
788 }
789
790 #[inline]
791 fn e_ehsize(&self, endian: Self::Endian) -> u16 {
792 self.e_ehsize.get(endian)
793 }
794
795 #[inline]
796 fn e_phentsize(&self, endian: Self::Endian) -> u16 {
797 self.e_phentsize.get(endian)
798 }
799
800 #[inline]
801 fn e_phnum(&self, endian: Self::Endian) -> u16 {
802 self.e_phnum.get(endian)
803 }
804
805 #[inline]
806 fn e_shentsize(&self, endian: Self::Endian) -> u16 {
807 self.e_shentsize.get(endian)
808 }
809
810 #[inline]
811 fn e_shnum(&self, endian: Self::Endian) -> u16 {
812 self.e_shnum.get(endian)
813 }
814
815 #[inline]
816 fn e_shstrndx(&self, endian: Self::Endian) -> u16 {
817 self.e_shstrndx.get(endian)
818 }
819}
820
821impl<Endian: endian::Endian> FileHeader for elf::FileHeader64<Endian> {
822 type Word = u64;
823 type Sword = i64;
824 type Endian = Endian;
825 type ProgramHeader = elf::ProgramHeader64<Endian>;
826 type SectionHeader = elf::SectionHeader64<Endian>;
827 type CompressionHeader = elf::CompressionHeader64<Endian>;
828 type NoteHeader = elf::NoteHeader32<Endian>;
829 type Dyn = elf::Dyn64<Endian>;
830 type Sym = elf::Sym64<Endian>;
831 type Rel = elf::Rel64<Endian>;
832 type Rela = elf::Rela64<Endian>;
833
834 #[inline]
835 fn is_type_64(&self) -> bool {
836 true
837 }
838
839 #[inline]
840 fn is_type_64_sized() -> bool
841 where
842 Self: Sized,
843 {
844 true
845 }
846
847 #[inline]
848 fn e_ident(&self) -> &elf::Ident {
849 &self.e_ident
850 }
851
852 #[inline]
853 fn e_type(&self, endian: Self::Endian) -> u16 {
854 self.e_type.get(endian)
855 }
856
857 #[inline]
858 fn e_machine(&self, endian: Self::Endian) -> u16 {
859 self.e_machine.get(endian)
860 }
861
862 #[inline]
863 fn e_version(&self, endian: Self::Endian) -> u32 {
864 self.e_version.get(endian)
865 }
866
867 #[inline]
868 fn e_entry(&self, endian: Self::Endian) -> Self::Word {
869 self.e_entry.get(endian)
870 }
871
872 #[inline]
873 fn e_phoff(&self, endian: Self::Endian) -> Self::Word {
874 self.e_phoff.get(endian)
875 }
876
877 #[inline]
878 fn e_shoff(&self, endian: Self::Endian) -> Self::Word {
879 self.e_shoff.get(endian)
880 }
881
882 #[inline]
883 fn e_flags(&self, endian: Self::Endian) -> u32 {
884 self.e_flags.get(endian)
885 }
886
887 #[inline]
888 fn e_ehsize(&self, endian: Self::Endian) -> u16 {
889 self.e_ehsize.get(endian)
890 }
891
892 #[inline]
893 fn e_phentsize(&self, endian: Self::Endian) -> u16 {
894 self.e_phentsize.get(endian)
895 }
896
897 #[inline]
898 fn e_phnum(&self, endian: Self::Endian) -> u16 {
899 self.e_phnum.get(endian)
900 }
901
902 #[inline]
903 fn e_shentsize(&self, endian: Self::Endian) -> u16 {
904 self.e_shentsize.get(endian)
905 }
906
907 #[inline]
908 fn e_shnum(&self, endian: Self::Endian) -> u16 {
909 self.e_shnum.get(endian)
910 }
911
912 #[inline]
913 fn e_shstrndx(&self, endian: Self::Endian) -> u16 {
914 self.e_shstrndx.get(endian)
915 }
916}
917