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_ALPHA, true) => Architecture::Alpha,
249            (elf::EM_ARM, _) => Architecture::Arm,
250            (elf::EM_AVR, _) => Architecture::Avr,
251            (elf::EM_BPF, _) => Architecture::Bpf,
252            (elf::EM_CSKY, _) => Architecture::Csky,
253            (elf::EM_MCST_ELBRUS, false) => Architecture::E2K32,
254            (elf::EM_MCST_ELBRUS, true) => Architecture::E2K64,
255            (elf::EM_386, _) => Architecture::I386,
256            (elf::EM_X86_64, false) => Architecture::X86_64_X32,
257            (elf::EM_X86_64, true) => Architecture::X86_64,
258            (elf::EM_HEXAGON, _) => Architecture::Hexagon,
259            (elf::EM_LOONGARCH, false) => Architecture::LoongArch32,
260            (elf::EM_LOONGARCH, true) => Architecture::LoongArch64,
261            (elf::EM_68K, false) => Architecture::M68k,
262            (elf::EM_MIPS, false) => {
263                if (self.header.e_flags(self.endian) & elf::EF_MIPS_ABI2) != 0 {
264                    Architecture::Mips64_N32
265                } else {
266                    Architecture::Mips
267                }
268            }
269            (elf::EM_MIPS, true) => Architecture::Mips64,
270            (elf::EM_MSP430, _) => Architecture::Msp430,
271            (elf::EM_PARISC, _) => Architecture::Hppa,
272            (elf::EM_PPC, _) => Architecture::PowerPc,
273            (elf::EM_PPC64, _) => Architecture::PowerPc64,
274            (elf::EM_RISCV, false) => Architecture::Riscv32,
275            (elf::EM_RISCV, true) => Architecture::Riscv64,
276            // This is either s390 or s390x, depending on the ELF class.
277            // We only support the 64-bit variant s390x here.
278            (elf::EM_S390, true) => Architecture::S390x,
279            (elf::EM_SBF, _) => Architecture::Sbf,
280            (elf::EM_SHARC, false) => Architecture::Sharc,
281            (elf::EM_SPARC, false) => Architecture::Sparc,
282            (elf::EM_SPARC32PLUS, false) => Architecture::Sparc32Plus,
283            (elf::EM_SPARCV9, true) => Architecture::Sparc64,
284            (elf::EM_XTENSA, false) => Architecture::Xtensa,
285            (elf::EM_SH, false) => Architecture::SuperH,
286            _ => Architecture::Unknown,
287        }
288    }
289
290    #[inline]
291    fn is_little_endian(&self) -> bool {
292        self.header.is_little_endian()
293    }
294
295    #[inline]
296    fn is_64(&self) -> bool {
297        self.header.is_class_64()
298    }
299
300    fn kind(&self) -> ObjectKind {
301        match self.header.e_type(self.endian) {
302            elf::ET_REL => ObjectKind::Relocatable,
303            elf::ET_EXEC => ObjectKind::Executable,
304            // TODO: check for `DF_1_PIE`?
305            elf::ET_DYN => ObjectKind::Dynamic,
306            elf::ET_CORE => ObjectKind::Core,
307            _ => ObjectKind::Unknown,
308        }
309    }
310
311    fn segments(&self) -> ElfSegmentIterator<'data, '_, Elf, R> {
312        ElfSegmentIterator {
313            file: self,
314            iter: self.segments.iter(),
315        }
316    }
317
318    fn section_by_name_bytes<'file>(
319        &'file self,
320        section_name: &[u8],
321    ) -> Option<ElfSection<'data, 'file, Elf, R>> {
322        self.raw_section_by_name(section_name)
323            .or_else(|| self.zdebug_section_by_name(section_name))
324    }
325
326    fn section_by_index(&self, index: SectionIndex) -> read::Result<ElfSection<'data, '_, Elf, R>> {
327        let section = self.sections.section(index)?;
328        Ok(ElfSection {
329            file: self,
330            index,
331            section,
332        })
333    }
334
335    fn sections(&self) -> ElfSectionIterator<'data, '_, Elf, R> {
336        ElfSectionIterator::new(self)
337    }
338
339    fn comdats(&self) -> ElfComdatIterator<'data, '_, Elf, R> {
340        ElfComdatIterator::new(self)
341    }
342
343    fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<ElfSymbol<'data, '_, Elf, R>> {
344        let symbol = self.symbols.symbol(index)?;
345        Ok(ElfSymbol {
346            endian: self.endian,
347            symbols: &self.symbols,
348            index,
349            symbol,
350        })
351    }
352
353    fn symbols(&self) -> ElfSymbolIterator<'data, '_, Elf, R> {
354        ElfSymbolIterator::new(self.endian, &self.symbols)
355    }
356
357    fn symbol_table(&self) -> Option<ElfSymbolTable<'data, '_, Elf, R>> {
358        if self.symbols.is_empty() {
359            return None;
360        }
361        Some(ElfSymbolTable {
362            endian: self.endian,
363            symbols: &self.symbols,
364        })
365    }
366
367    fn dynamic_symbols(&self) -> ElfSymbolIterator<'data, '_, Elf, R> {
368        ElfSymbolIterator::new(self.endian, &self.dynamic_symbols)
369    }
370
371    fn dynamic_symbol_table(&self) -> Option<ElfSymbolTable<'data, '_, Elf, R>> {
372        if self.dynamic_symbols.is_empty() {
373            return None;
374        }
375        Some(ElfSymbolTable {
376            endian: self.endian,
377            symbols: &self.dynamic_symbols,
378        })
379    }
380
381    fn dynamic_relocations<'file>(
382        &'file self,
383    ) -> Option<ElfDynamicRelocationIterator<'data, 'file, Elf, R>> {
384        Some(ElfDynamicRelocationIterator {
385            section_index: SectionIndex(1),
386            file: self,
387            relocations: None,
388        })
389    }
390
391    fn imports(&self) -> read::Result<Vec<Import<'data>>> {
392        let versions = self.sections.versions(self.endian, self.data)?;
393
394        let mut imports = Vec::new();
395        for (index, symbol) in self.dynamic_symbols.enumerate() {
396            if symbol.is_undefined(self.endian) {
397                let name = symbol.name(self.endian, self.dynamic_symbols.strings())?;
398                if !name.is_empty() {
399                    let library = if let Some(svt) = versions.as_ref() {
400                        let vi = svt.version_index(self.endian, index);
401                        svt.version(vi)?.and_then(|v| v.file())
402                    } else {
403                        None
404                    }
405                    .unwrap_or(&[]);
406                    imports.push(Import {
407                        name: ByteString(name),
408                        library: ByteString(library),
409                    });
410                }
411            }
412        }
413        Ok(imports)
414    }
415
416    fn exports(&self) -> read::Result<Vec<Export<'data>>> {
417        let mut exports = Vec::new();
418        for symbol in self.dynamic_symbols.iter() {
419            if symbol.is_definition(self.endian) {
420                let name = symbol.name(self.endian, self.dynamic_symbols.strings())?;
421                let address = symbol.st_value(self.endian).into();
422                exports.push(Export {
423                    name: ByteString(name),
424                    address,
425                });
426            }
427        }
428        Ok(exports)
429    }
430
431    fn has_debug_symbols(&self) -> bool {
432        for section in self.sections.iter() {
433            if let Ok(name) = self.sections.section_name(self.endian, section) {
434                if name == b".debug_info" || name == b".zdebug_info" {
435                    return true;
436                }
437            }
438        }
439        false
440    }
441
442    fn build_id(&self) -> read::Result<Option<&'data [u8]>> {
443        let endian = self.endian;
444        // Use section headers if present, otherwise use program headers.
445        if !self.sections.is_empty() {
446            for section in self.sections.iter() {
447                if let Some(mut notes) = section.notes(endian, self.data)? {
448                    while let Some(note) = notes.next()? {
449                        if note.name() == elf::ELF_NOTE_GNU
450                            && note.n_type(endian) == elf::NT_GNU_BUILD_ID
451                        {
452                            return Ok(Some(note.desc()));
453                        }
454                    }
455                }
456            }
457        } else {
458            for segment in self.segments {
459                if let Some(mut notes) = segment.notes(endian, self.data)? {
460                    while let Some(note) = notes.next()? {
461                        if note.name() == elf::ELF_NOTE_GNU
462                            && note.n_type(endian) == elf::NT_GNU_BUILD_ID
463                        {
464                            return Ok(Some(note.desc()));
465                        }
466                    }
467                }
468            }
469        }
470        Ok(None)
471    }
472
473    fn gnu_debuglink(&self) -> read::Result<Option<(&'data [u8], u32)>> {
474        let section = match self.raw_section_by_name(b".gnu_debuglink") {
475            Some(section) => section,
476            None => return Ok(None),
477        };
478        let data = section
479            .section
480            .data(self.endian, self.data)
481            .read_error("Invalid ELF .gnu_debuglink section offset or size")
482            .map(Bytes)?;
483        let filename = data
484            .read_string_at(0)
485            .read_error("Missing ELF .gnu_debuglink filename")?;
486        let crc_offset = util::align(filename.len() + 1, 4);
487        let crc = data
488            .read_at::<U32<_>>(crc_offset)
489            .read_error("Missing ELF .gnu_debuglink crc")?
490            .get(self.endian);
491        Ok(Some((filename, crc)))
492    }
493
494    fn gnu_debugaltlink(&self) -> read::Result<Option<(&'data [u8], &'data [u8])>> {
495        let section = match self.raw_section_by_name(b".gnu_debugaltlink") {
496            Some(section) => section,
497            None => return Ok(None),
498        };
499        let mut data = section
500            .section
501            .data(self.endian, self.data)
502            .read_error("Invalid ELF .gnu_debugaltlink section offset or size")
503            .map(Bytes)?;
504        let filename = data
505            .read_string()
506            .read_error("Missing ELF .gnu_debugaltlink filename")?;
507        let build_id = data.0;
508        Ok(Some((filename, build_id)))
509    }
510
511    fn relative_address_base(&self) -> u64 {
512        0
513    }
514
515    fn entry(&self) -> u64 {
516        self.header.e_entry(self.endian).into()
517    }
518
519    fn flags(&self) -> FileFlags {
520        FileFlags::Elf {
521            os_abi: self.header.e_ident().os_abi,
522            abi_version: self.header.e_ident().abi_version,
523            e_flags: self.header.e_flags(self.endian),
524        }
525    }
526}
527
528/// A trait for generic access to [`elf::FileHeader32`] and [`elf::FileHeader64`].
529#[allow(missing_docs)]
530pub trait FileHeader: Debug + Pod {
531    // Ideally this would be a `u64: From<Word>`, but can't express that.
532    type Word: Into<u64> + Default + Copy;
533    type Sword: Into<i64>;
534    type Endian: endian::Endian;
535    type ProgramHeader: ProgramHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>;
536    type SectionHeader: SectionHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>;
537    type CompressionHeader: CompressionHeader<Endian = Self::Endian, Word = Self::Word>;
538    type NoteHeader: NoteHeader<Endian = Self::Endian>;
539    type Dyn: Dyn<Endian = Self::Endian, Word = Self::Word>;
540    type Sym: Sym<Endian = Self::Endian, Word = Self::Word>;
541    type Rel: Rel<Endian = Self::Endian, Word = Self::Word>;
542    type Rela: Rela<Endian = Self::Endian, Word = Self::Word> + From<Self::Rel>;
543    type Relr: Relr<Endian = Self::Endian, Word = Self::Word>;
544
545    /// Return true if this type is a 64-bit header.
546    ///
547    /// This is a property of the type, not a value in the header data.
548    fn is_type_64(&self) -> bool;
549
550    /// Return true if this type is a 64-bit header.
551    ///
552    /// This is a property of the type, not a value in the header data.
553    ///
554    /// This is the same as [`Self::is_type_64`], but is non-dispatchable.
555    fn is_type_64_sized() -> bool
556    where
557        Self: Sized;
558
559    fn e_ident(&self) -> &elf::Ident;
560    fn e_type(&self, endian: Self::Endian) -> u16;
561    fn e_machine(&self, endian: Self::Endian) -> u16;
562    fn e_version(&self, endian: Self::Endian) -> u32;
563    fn e_entry(&self, endian: Self::Endian) -> Self::Word;
564    fn e_phoff(&self, endian: Self::Endian) -> Self::Word;
565    fn e_shoff(&self, endian: Self::Endian) -> Self::Word;
566    fn e_flags(&self, endian: Self::Endian) -> u32;
567    fn e_ehsize(&self, endian: Self::Endian) -> u16;
568    fn e_phentsize(&self, endian: Self::Endian) -> u16;
569    fn e_phnum(&self, endian: Self::Endian) -> u16;
570    fn e_shentsize(&self, endian: Self::Endian) -> u16;
571    fn e_shnum(&self, endian: Self::Endian) -> u16;
572    fn e_shstrndx(&self, endian: Self::Endian) -> u16;
573
574    // Provided methods.
575
576    /// Read the file header.
577    ///
578    /// Also checks that the ident field in the file header is a supported format.
579    fn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> {
580        let header = data
581            .read_at::<Self>(0)
582            .read_error("Invalid ELF header size or alignment")?;
583        if !header.is_supported() {
584            return Err(Error("Unsupported ELF header"));
585        }
586        // TODO: Check self.e_ehsize?
587        Ok(header)
588    }
589
590    /// Check that the ident field in the file header is a supported format.
591    ///
592    /// This checks the magic number, version, class, and endianness.
593    fn is_supported(&self) -> bool {
594        let ident = self.e_ident();
595        // TODO: Check self.e_version too? Requires endian though.
596        ident.magic == elf::ELFMAG
597            && (self.is_type_64() || self.is_class_32())
598            && (!self.is_type_64() || self.is_class_64())
599            && (self.is_little_endian() || self.is_big_endian())
600            && ident.version == elf::EV_CURRENT
601    }
602
603    fn is_class_32(&self) -> bool {
604        self.e_ident().class == elf::ELFCLASS32
605    }
606
607    fn is_class_64(&self) -> bool {
608        self.e_ident().class == elf::ELFCLASS64
609    }
610
611    fn is_little_endian(&self) -> bool {
612        self.e_ident().data == elf::ELFDATA2LSB
613    }
614
615    fn is_big_endian(&self) -> bool {
616        self.e_ident().data == elf::ELFDATA2MSB
617    }
618
619    fn endian(&self) -> read::Result<Self::Endian> {
620        Self::Endian::from_big_endian(self.is_big_endian()).read_error("Unsupported ELF endian")
621    }
622
623    /// Return the first section header, if present.
624    ///
625    /// Section 0 is a special case because getting the section headers normally
626    /// requires `shnum`, but `shnum` may be in the first section header.
627    fn section_0<'data, R: ReadRef<'data>>(
628        &self,
629        endian: Self::Endian,
630        data: R,
631    ) -> read::Result<Option<&'data Self::SectionHeader>> {
632        let shoff: u64 = self.e_shoff(endian).into();
633        if shoff == 0 {
634            // No section headers is ok.
635            return Ok(None);
636        }
637        let shentsize = usize::from(self.e_shentsize(endian));
638        if shentsize != mem::size_of::<Self::SectionHeader>() {
639            // Section header size must match.
640            return Err(Error("Invalid ELF section header entry size"));
641        }
642        data.read_at(shoff)
643            .map(Some)
644            .read_error("Invalid ELF section header offset or size")
645    }
646
647    /// Return the `e_phnum` field of the header. Handles extended values.
648    ///
649    /// Returns `Err` for invalid values.
650    fn phnum<'data, R: ReadRef<'data>>(
651        &self,
652        endian: Self::Endian,
653        data: R,
654    ) -> read::Result<usize> {
655        let e_phnum = self.e_phnum(endian);
656        if e_phnum < elf::PN_XNUM {
657            Ok(e_phnum as usize)
658        } else if let Some(section_0) = self.section_0(endian, data)? {
659            Ok(section_0.sh_info(endian) as usize)
660        } else {
661            // Section 0 must exist if e_phnum overflows.
662            Err(Error("Missing ELF section headers for e_phnum overflow"))
663        }
664    }
665
666    /// Return the `e_shnum` field of the header. Handles extended values.
667    ///
668    /// Returns `Err` for invalid values.
669    fn shnum<'data, R: ReadRef<'data>>(
670        &self,
671        endian: Self::Endian,
672        data: R,
673    ) -> read::Result<usize> {
674        let e_shnum = self.e_shnum(endian);
675        if e_shnum > 0 {
676            Ok(e_shnum as usize)
677        } else if let Some(section_0) = self.section_0(endian, data)? {
678            section_0
679                .sh_size(endian)
680                .into()
681                .try_into()
682                .ok()
683                .read_error("Invalid ELF extended e_shnum")
684        } else {
685            // No section headers is ok.
686            Ok(0)
687        }
688    }
689
690    /// Return the `e_shstrndx` field of the header. Handles extended values.
691    ///
692    /// Returns `Err` for invalid values (including if the index is 0).
693    fn shstrndx<'data, R: ReadRef<'data>>(
694        &self,
695        endian: Self::Endian,
696        data: R,
697    ) -> read::Result<u32> {
698        let e_shstrndx = self.e_shstrndx(endian);
699        let index = if e_shstrndx != elf::SHN_XINDEX {
700            e_shstrndx.into()
701        } else if let Some(section_0) = self.section_0(endian, data)? {
702            section_0.sh_link(endian)
703        } else {
704            // Section 0 must exist if we're trying to read e_shstrndx.
705            return Err(Error("Missing ELF section headers for e_shstrndx overflow"));
706        };
707        if index == 0 {
708            return Err(Error("Missing ELF e_shstrndx"));
709        }
710        Ok(index)
711    }
712
713    /// Return the slice of program headers.
714    ///
715    /// Returns `Ok(&[])` if there are no program headers.
716    /// Returns `Err` for invalid values.
717    fn program_headers<'data, R: ReadRef<'data>>(
718        &self,
719        endian: Self::Endian,
720        data: R,
721    ) -> read::Result<&'data [Self::ProgramHeader]> {
722        let phoff: u64 = self.e_phoff(endian).into();
723        if phoff == 0 {
724            // No program headers is ok.
725            return Ok(&[]);
726        }
727        let phnum = self.phnum(endian, data)?;
728        if phnum == 0 {
729            // No program headers is ok.
730            return Ok(&[]);
731        }
732        let phentsize = self.e_phentsize(endian) as usize;
733        if phentsize != mem::size_of::<Self::ProgramHeader>() {
734            // Program header size must match.
735            return Err(Error("Invalid ELF program header entry size"));
736        }
737        data.read_slice_at(phoff, phnum)
738            .read_error("Invalid ELF program header size or alignment")
739    }
740
741    /// Return the slice of section headers.
742    ///
743    /// Returns `Ok(&[])` if there are no section headers.
744    /// Returns `Err` for invalid values.
745    fn section_headers<'data, R: ReadRef<'data>>(
746        &self,
747        endian: Self::Endian,
748        data: R,
749    ) -> read::Result<&'data [Self::SectionHeader]> {
750        let shoff: u64 = self.e_shoff(endian).into();
751        if shoff == 0 {
752            // No section headers is ok.
753            return Ok(&[]);
754        }
755        let shnum = self.shnum(endian, data)?;
756        if shnum == 0 {
757            // No section headers is ok.
758            return Ok(&[]);
759        }
760        let shentsize = usize::from(self.e_shentsize(endian));
761        if shentsize != mem::size_of::<Self::SectionHeader>() {
762            // Section header size must match.
763            return Err(Error("Invalid ELF section header entry size"));
764        }
765        data.read_slice_at(shoff, shnum)
766            .read_error("Invalid ELF section header offset/size/alignment")
767    }
768
769    /// Get the section index of the section header string table.
770    ///
771    /// Returns `Err` for invalid values (including if the index is 0).
772    fn section_strings_index<'data, R: ReadRef<'data>>(
773        &self,
774        endian: Self::Endian,
775        data: R,
776    ) -> read::Result<SectionIndex> {
777        self.shstrndx(endian, data)
778            .map(|index| SectionIndex(index as usize))
779    }
780
781    /// Return the string table for the section headers.
782    fn section_strings<'data, R: ReadRef<'data>>(
783        &self,
784        endian: Self::Endian,
785        data: R,
786        sections: &[Self::SectionHeader],
787    ) -> read::Result<StringTable<'data, R>> {
788        if sections.is_empty() {
789            return Ok(StringTable::default());
790        }
791        let index = self.section_strings_index(endian, data)?;
792        let shstrtab = sections.get(index.0).read_error("Invalid ELF e_shstrndx")?;
793        let strings = if let Some((shstrtab_offset, shstrtab_size)) = shstrtab.file_range(endian) {
794            let shstrtab_end = shstrtab_offset
795                .checked_add(shstrtab_size)
796                .read_error("Invalid ELF shstrtab size")?;
797            StringTable::new(data, shstrtab_offset, shstrtab_end)
798        } else {
799            StringTable::default()
800        };
801        Ok(strings)
802    }
803
804    /// Return the section table.
805    fn sections<'data, R: ReadRef<'data>>(
806        &self,
807        endian: Self::Endian,
808        data: R,
809    ) -> read::Result<SectionTable<'data, Self, R>> {
810        let sections = self.section_headers(endian, data)?;
811        let strings = self.section_strings(endian, data, sections)?;
812        Ok(SectionTable::new(sections, strings))
813    }
814
815    /// Returns whether this is a mips64el elf file.
816    fn is_mips64el(&self, endian: Self::Endian) -> bool {
817        self.is_class_64() && self.is_little_endian() && self.e_machine(endian) == elf::EM_MIPS
818    }
819}
820
821impl<Endian: endian::Endian> FileHeader for elf::FileHeader32<Endian> {
822    type Word = u32;
823    type Sword = i32;
824    type Endian = Endian;
825    type ProgramHeader = elf::ProgramHeader32<Endian>;
826    type SectionHeader = elf::SectionHeader32<Endian>;
827    type CompressionHeader = elf::CompressionHeader32<Endian>;
828    type NoteHeader = elf::NoteHeader32<Endian>;
829    type Dyn = elf::Dyn32<Endian>;
830    type Sym = elf::Sym32<Endian>;
831    type Rel = elf::Rel32<Endian>;
832    type Rela = elf::Rela32<Endian>;
833    type Relr = elf::Relr32<Endian>;
834
835    #[inline]
836    fn is_type_64(&self) -> bool {
837        false
838    }
839
840    #[inline]
841    fn is_type_64_sized() -> bool
842    where
843        Self: Sized,
844    {
845        false
846    }
847
848    #[inline]
849    fn e_ident(&self) -> &elf::Ident {
850        &self.e_ident
851    }
852
853    #[inline]
854    fn e_type(&self, endian: Self::Endian) -> u16 {
855        self.e_type.get(endian)
856    }
857
858    #[inline]
859    fn e_machine(&self, endian: Self::Endian) -> u16 {
860        self.e_machine.get(endian)
861    }
862
863    #[inline]
864    fn e_version(&self, endian: Self::Endian) -> u32 {
865        self.e_version.get(endian)
866    }
867
868    #[inline]
869    fn e_entry(&self, endian: Self::Endian) -> Self::Word {
870        self.e_entry.get(endian)
871    }
872
873    #[inline]
874    fn e_phoff(&self, endian: Self::Endian) -> Self::Word {
875        self.e_phoff.get(endian)
876    }
877
878    #[inline]
879    fn e_shoff(&self, endian: Self::Endian) -> Self::Word {
880        self.e_shoff.get(endian)
881    }
882
883    #[inline]
884    fn e_flags(&self, endian: Self::Endian) -> u32 {
885        self.e_flags.get(endian)
886    }
887
888    #[inline]
889    fn e_ehsize(&self, endian: Self::Endian) -> u16 {
890        self.e_ehsize.get(endian)
891    }
892
893    #[inline]
894    fn e_phentsize(&self, endian: Self::Endian) -> u16 {
895        self.e_phentsize.get(endian)
896    }
897
898    #[inline]
899    fn e_phnum(&self, endian: Self::Endian) -> u16 {
900        self.e_phnum.get(endian)
901    }
902
903    #[inline]
904    fn e_shentsize(&self, endian: Self::Endian) -> u16 {
905        self.e_shentsize.get(endian)
906    }
907
908    #[inline]
909    fn e_shnum(&self, endian: Self::Endian) -> u16 {
910        self.e_shnum.get(endian)
911    }
912
913    #[inline]
914    fn e_shstrndx(&self, endian: Self::Endian) -> u16 {
915        self.e_shstrndx.get(endian)
916    }
917}
918
919impl<Endian: endian::Endian> FileHeader for elf::FileHeader64<Endian> {
920    type Word = u64;
921    type Sword = i64;
922    type Endian = Endian;
923    type ProgramHeader = elf::ProgramHeader64<Endian>;
924    type SectionHeader = elf::SectionHeader64<Endian>;
925    type CompressionHeader = elf::CompressionHeader64<Endian>;
926    type NoteHeader = elf::NoteHeader32<Endian>;
927    type Dyn = elf::Dyn64<Endian>;
928    type Sym = elf::Sym64<Endian>;
929    type Rel = elf::Rel64<Endian>;
930    type Rela = elf::Rela64<Endian>;
931    type Relr = elf::Relr64<Endian>;
932
933    #[inline]
934    fn is_type_64(&self) -> bool {
935        true
936    }
937
938    #[inline]
939    fn is_type_64_sized() -> bool
940    where
941        Self: Sized,
942    {
943        true
944    }
945
946    #[inline]
947    fn e_ident(&self) -> &elf::Ident {
948        &self.e_ident
949    }
950
951    #[inline]
952    fn e_type(&self, endian: Self::Endian) -> u16 {
953        self.e_type.get(endian)
954    }
955
956    #[inline]
957    fn e_machine(&self, endian: Self::Endian) -> u16 {
958        self.e_machine.get(endian)
959    }
960
961    #[inline]
962    fn e_version(&self, endian: Self::Endian) -> u32 {
963        self.e_version.get(endian)
964    }
965
966    #[inline]
967    fn e_entry(&self, endian: Self::Endian) -> Self::Word {
968        self.e_entry.get(endian)
969    }
970
971    #[inline]
972    fn e_phoff(&self, endian: Self::Endian) -> Self::Word {
973        self.e_phoff.get(endian)
974    }
975
976    #[inline]
977    fn e_shoff(&self, endian: Self::Endian) -> Self::Word {
978        self.e_shoff.get(endian)
979    }
980
981    #[inline]
982    fn e_flags(&self, endian: Self::Endian) -> u32 {
983        self.e_flags.get(endian)
984    }
985
986    #[inline]
987    fn e_ehsize(&self, endian: Self::Endian) -> u16 {
988        self.e_ehsize.get(endian)
989    }
990
991    #[inline]
992    fn e_phentsize(&self, endian: Self::Endian) -> u16 {
993        self.e_phentsize.get(endian)
994    }
995
996    #[inline]
997    fn e_phnum(&self, endian: Self::Endian) -> u16 {
998        self.e_phnum.get(endian)
999    }
1000
1001    #[inline]
1002    fn e_shentsize(&self, endian: Self::Endian) -> u16 {
1003        self.e_shentsize.get(endian)
1004    }
1005
1006    #[inline]
1007    fn e_shnum(&self, endian: Self::Endian) -> u16 {
1008        self.e_shnum.get(endian)
1009    }
1010
1011    #[inline]
1012    fn e_shstrndx(&self, endian: Self::Endian) -> u16 {
1013        self.e_shstrndx.get(endian)
1014    }
1015}