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