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