Skip to main content

object/read/elf/
file.rs

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