object/read/elf/
file.rs

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