object/read/elf/
section.rs

1use core::fmt::Debug;
2use core::{iter, slice, str};
3
4use crate::elf;
5use crate::endian::{self, Endianness, U32Bytes};
6use crate::pod::{self, Pod};
7use crate::read::{
8    self, gnu_compression, CompressedData, CompressedFileRange, CompressionFormat, Error,
9    ObjectSection, ReadError, ReadRef, RelocationMap, SectionFlags, SectionIndex, SectionKind,
10    StringTable,
11};
12
13use super::{
14    AttributesSection, CompressionHeader, CrelIterator, ElfFile, ElfSectionRelocationIterator,
15    FileHeader, GnuHashTable, HashTable, NoteIterator, RelocationSections, RelrIterator,
16    SymbolTable, VerdefIterator, VerneedIterator, VersionTable,
17};
18
19/// The table of section headers in an ELF file.
20///
21/// Also includes the string table used for the section names.
22///
23/// Returned by [`FileHeader::sections`].
24#[derive(Debug, Clone, Copy)]
25pub struct SectionTable<'data, Elf: FileHeader, R = &'data [u8]>
26where
27    R: ReadRef<'data>,
28{
29    sections: &'data [Elf::SectionHeader],
30    strings: StringTable<'data, R>,
31}
32
33impl<'data, Elf: FileHeader, R: ReadRef<'data>> Default for SectionTable<'data, Elf, R> {
34    fn default() -> Self {
35        SectionTable {
36            sections: &[],
37            strings: StringTable::default(),
38        }
39    }
40}
41
42impl<'data, Elf: FileHeader, R: ReadRef<'data>> SectionTable<'data, Elf, R> {
43    /// Create a new section table.
44    #[inline]
45    pub fn new(sections: &'data [Elf::SectionHeader], strings: StringTable<'data, R>) -> Self {
46        SectionTable { sections, strings }
47    }
48
49    /// Iterate over the section headers.
50    ///
51    /// This includes the null section at index 0, which you will usually need to skip.
52    #[inline]
53    pub fn iter(&self) -> slice::Iter<'data, Elf::SectionHeader> {
54        self.sections.iter()
55    }
56
57    /// Iterate over the section headers and their indices.
58    ///
59    /// This includes the null section at index 0, which you will usually need to skip.
60    #[inline]
61    pub fn enumerate(&self) -> impl Iterator<Item = (SectionIndex, &'data Elf::SectionHeader)> {
62        self.sections
63            .iter()
64            .enumerate()
65            .map(|(i, section)| (SectionIndex(i), section))
66    }
67
68    /// Return true if the section table is empty.
69    #[inline]
70    pub fn is_empty(&self) -> bool {
71        self.sections.is_empty()
72    }
73
74    /// The number of section headers.
75    #[inline]
76    pub fn len(&self) -> usize {
77        self.sections.len()
78    }
79
80    /// Get the section header at the given index.
81    ///
82    /// Returns an error for the null section at index 0.
83    pub fn section(&self, index: SectionIndex) -> read::Result<&'data Elf::SectionHeader> {
84        if index == SectionIndex(0) {
85            return Err(read::Error("Invalid ELF section index"));
86        }
87        self.sections
88            .get(index.0)
89            .read_error("Invalid ELF section index")
90    }
91
92    /// Return the section header with the given name.
93    ///
94    /// Ignores sections with invalid names.
95    pub fn section_by_name(
96        &self,
97        endian: Elf::Endian,
98        name: &[u8],
99    ) -> Option<(SectionIndex, &'data Elf::SectionHeader)> {
100        self.enumerate()
101            .find(|(_, section)| self.section_name(endian, section) == Ok(name))
102    }
103
104    /// Return the section name for the given section header.
105    pub fn section_name(
106        &self,
107        endian: Elf::Endian,
108        section: &Elf::SectionHeader,
109    ) -> read::Result<&'data [u8]> {
110        section.name(endian, self.strings)
111    }
112
113    /// Return the string table at the given section index.
114    ///
115    /// Returns an empty string table if the index is 0.
116    /// Returns an error if the section is not a string table.
117    #[inline]
118    pub fn strings(
119        &self,
120        endian: Elf::Endian,
121        data: R,
122        index: SectionIndex,
123    ) -> read::Result<StringTable<'data, R>> {
124        if index == SectionIndex(0) {
125            return Ok(StringTable::default());
126        }
127        self.section(index)?
128            .strings(endian, data)?
129            .read_error("Invalid ELF string section type")
130    }
131
132    /// Return the symbol table of the given section type.
133    ///
134    /// Returns an empty symbol table if the symbol table does not exist.
135    #[inline]
136    pub fn symbols(
137        &self,
138        endian: Elf::Endian,
139        data: R,
140        sh_type: u32,
141    ) -> read::Result<SymbolTable<'data, Elf, R>> {
142        debug_assert!(sh_type == elf::SHT_DYNSYM || sh_type == elf::SHT_SYMTAB);
143
144        let (index, section) = match self.enumerate().find(|s| s.1.sh_type(endian) == sh_type) {
145            Some(s) => s,
146            None => return Ok(SymbolTable::default()),
147        };
148
149        SymbolTable::parse(endian, data, self, index, section)
150    }
151
152    /// Return the symbol table at the given section index.
153    ///
154    /// Returns an error if the section is not a symbol table.
155    #[inline]
156    pub fn symbol_table_by_index(
157        &self,
158        endian: Elf::Endian,
159        data: R,
160        index: SectionIndex,
161    ) -> read::Result<SymbolTable<'data, Elf, R>> {
162        let section = self.section(index)?;
163        match section.sh_type(endian) {
164            elf::SHT_DYNSYM | elf::SHT_SYMTAB => {}
165            _ => return Err(Error("Invalid ELF symbol table section type")),
166        }
167        SymbolTable::parse(endian, data, self, index, section)
168    }
169
170    /// Create a mapping from section index to associated relocation sections.
171    #[inline]
172    pub fn relocation_sections(
173        &self,
174        endian: Elf::Endian,
175        symbol_section: SectionIndex,
176    ) -> read::Result<RelocationSections> {
177        RelocationSections::parse(endian, self, symbol_section)
178    }
179
180    /// Return the contents of a dynamic section.
181    ///
182    /// Also returns the linked string table index.
183    ///
184    /// Returns `Ok(None)` if there is no `SHT_DYNAMIC` section.
185    /// Returns `Err` for invalid values.
186    pub fn dynamic(
187        &self,
188        endian: Elf::Endian,
189        data: R,
190    ) -> read::Result<Option<(&'data [Elf::Dyn], SectionIndex)>> {
191        for section in self.sections {
192            if let Some(dynamic) = section.dynamic(endian, data)? {
193                return Ok(Some(dynamic));
194            }
195        }
196        Ok(None)
197    }
198
199    /// Return the header of a SysV hash section.
200    ///
201    /// Returns `Ok(None)` if there is no SysV GNU hash section.
202    /// Returns `Err` for invalid values.
203    pub fn hash_header(
204        &self,
205        endian: Elf::Endian,
206        data: R,
207    ) -> read::Result<Option<&'data elf::HashHeader<Elf::Endian>>> {
208        for section in self.sections {
209            if let Some(hash) = section.hash_header(endian, data)? {
210                return Ok(Some(hash));
211            }
212        }
213        Ok(None)
214    }
215
216    /// Return the contents of a SysV hash section.
217    ///
218    /// Also returns the linked symbol table index.
219    ///
220    /// Returns `Ok(None)` if there is no SysV hash section.
221    /// Returns `Err` for invalid values.
222    pub fn hash(
223        &self,
224        endian: Elf::Endian,
225        data: R,
226    ) -> read::Result<Option<(HashTable<'data, Elf>, SectionIndex)>> {
227        for section in self.sections {
228            if let Some(hash) = section.hash(endian, data)? {
229                return Ok(Some(hash));
230            }
231        }
232        Ok(None)
233    }
234
235    /// Return the header of a GNU hash section.
236    ///
237    /// Returns `Ok(None)` if there is no GNU hash section.
238    /// Returns `Err` for invalid values.
239    pub fn gnu_hash_header(
240        &self,
241        endian: Elf::Endian,
242        data: R,
243    ) -> read::Result<Option<&'data elf::GnuHashHeader<Elf::Endian>>> {
244        for section in self.sections {
245            if let Some(hash) = section.gnu_hash_header(endian, data)? {
246                return Ok(Some(hash));
247            }
248        }
249        Ok(None)
250    }
251
252    /// Return the contents of a GNU hash section.
253    ///
254    /// Also returns the linked symbol table index.
255    ///
256    /// Returns `Ok(None)` if there is no GNU hash section.
257    /// Returns `Err` for invalid values.
258    pub fn gnu_hash(
259        &self,
260        endian: Elf::Endian,
261        data: R,
262    ) -> read::Result<Option<(GnuHashTable<'data, Elf>, SectionIndex)>> {
263        for section in self.sections {
264            if let Some(hash) = section.gnu_hash(endian, data)? {
265                return Ok(Some(hash));
266            }
267        }
268        Ok(None)
269    }
270
271    /// Return the contents of a `SHT_GNU_VERSYM` section.
272    ///
273    /// Also returns the linked symbol table index.
274    ///
275    /// Returns `Ok(None)` if there is no `SHT_GNU_VERSYM` section.
276    /// Returns `Err` for invalid values.
277    pub fn gnu_versym(
278        &self,
279        endian: Elf::Endian,
280        data: R,
281    ) -> read::Result<Option<(&'data [elf::Versym<Elf::Endian>], SectionIndex)>> {
282        for section in self.sections {
283            if let Some(syms) = section.gnu_versym(endian, data)? {
284                return Ok(Some(syms));
285            }
286        }
287        Ok(None)
288    }
289
290    /// Return the contents of a `SHT_GNU_VERDEF` section.
291    ///
292    /// Also returns the linked string table index.
293    ///
294    /// Returns `Ok(None)` if there is no `SHT_GNU_VERDEF` section.
295    /// Returns `Err` for invalid values.
296    pub fn gnu_verdef(
297        &self,
298        endian: Elf::Endian,
299        data: R,
300    ) -> read::Result<Option<(VerdefIterator<'data, Elf>, SectionIndex)>> {
301        for section in self.sections {
302            if let Some(defs) = section.gnu_verdef(endian, data)? {
303                return Ok(Some(defs));
304            }
305        }
306        Ok(None)
307    }
308
309    /// Return the contents of a `SHT_GNU_VERNEED` section.
310    ///
311    /// Also returns the linked string table index.
312    ///
313    /// Returns `Ok(None)` if there is no `SHT_GNU_VERNEED` section.
314    /// Returns `Err` for invalid values.
315    pub fn gnu_verneed(
316        &self,
317        endian: Elf::Endian,
318        data: R,
319    ) -> read::Result<Option<(VerneedIterator<'data, Elf>, SectionIndex)>> {
320        for section in self.sections {
321            if let Some(needs) = section.gnu_verneed(endian, data)? {
322                return Ok(Some(needs));
323            }
324        }
325        Ok(None)
326    }
327
328    /// Returns the symbol version table.
329    ///
330    /// Returns `Ok(None)` if there is no `SHT_GNU_VERSYM` section.
331    /// Returns `Err` for invalid values.
332    pub fn versions(
333        &self,
334        endian: Elf::Endian,
335        data: R,
336    ) -> read::Result<Option<VersionTable<'data, Elf>>> {
337        let (versyms, link) = match self.gnu_versym(endian, data)? {
338            Some(val) => val,
339            None => return Ok(None),
340        };
341        let strings = self.symbol_table_by_index(endian, data, link)?.strings();
342        // TODO: check links?
343        let verdefs = self.gnu_verdef(endian, data)?.map(|x| x.0);
344        let verneeds = self.gnu_verneed(endian, data)?.map(|x| x.0);
345        VersionTable::parse(endian, versyms, verdefs, verneeds, strings).map(Some)
346    }
347}
348
349/// An iterator for the sections in an [`ElfFile32`](super::ElfFile32).
350pub type ElfSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
351    ElfSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
352/// An iterator for the sections in an [`ElfFile64`](super::ElfFile64).
353pub type ElfSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
354    ElfSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
355
356/// An iterator for the sections in an [`ElfFile`].
357#[derive(Debug)]
358pub struct ElfSectionIterator<'data, 'file, Elf, R = &'data [u8]>
359where
360    Elf: FileHeader,
361    R: ReadRef<'data>,
362{
363    file: &'file ElfFile<'data, Elf, R>,
364    iter: iter::Enumerate<slice::Iter<'data, Elf::SectionHeader>>,
365}
366
367impl<'data, 'file, Elf, R> ElfSectionIterator<'data, 'file, Elf, R>
368where
369    Elf: FileHeader,
370    R: ReadRef<'data>,
371{
372    pub(super) fn new(file: &'file ElfFile<'data, Elf, R>) -> Self {
373        let mut iter = file.sections.iter().enumerate();
374        iter.next(); // Skip null section.
375        ElfSectionIterator { file, iter }
376    }
377}
378
379impl<'data, 'file, Elf, R> Iterator for ElfSectionIterator<'data, 'file, Elf, R>
380where
381    Elf: FileHeader,
382    R: ReadRef<'data>,
383{
384    type Item = ElfSection<'data, 'file, Elf, R>;
385
386    fn next(&mut self) -> Option<Self::Item> {
387        self.iter.next().map(|(index, section)| ElfSection {
388            index: SectionIndex(index),
389            file: self.file,
390            section,
391        })
392    }
393}
394
395/// A section in an [`ElfFile32`](super::ElfFile32).
396pub type ElfSection32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
397    ElfSection<'data, 'file, elf::FileHeader32<Endian>, R>;
398/// A section in an [`ElfFile64`](super::ElfFile64).
399pub type ElfSection64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
400    ElfSection<'data, 'file, elf::FileHeader64<Endian>, R>;
401
402/// A section in an [`ElfFile`].
403///
404/// Most functionality is provided by the [`ObjectSection`] trait implementation.
405#[derive(Debug)]
406pub struct ElfSection<'data, 'file, Elf, R = &'data [u8]>
407where
408    Elf: FileHeader,
409    R: ReadRef<'data>,
410{
411    pub(super) file: &'file ElfFile<'data, Elf, R>,
412    pub(super) index: SectionIndex,
413    pub(super) section: &'data Elf::SectionHeader,
414}
415
416impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSection<'data, 'file, Elf, R> {
417    /// Get the ELF file containing this section.
418    pub fn elf_file(&self) -> &'file ElfFile<'data, Elf, R> {
419        self.file
420    }
421
422    /// Get the raw ELF section header.
423    pub fn elf_section_header(&self) -> &'data Elf::SectionHeader {
424        self.section
425    }
426
427    /// Get the index of the relocation section that references this section.
428    ///
429    /// Returns `None` if there are no relocations.
430    /// Returns an error if there are multiple relocation sections that reference this section.
431    pub fn elf_relocation_section_index(&self) -> read::Result<Option<SectionIndex>> {
432        let Some(relocation_index) = self.file.relocations.get(self.index) else {
433            return Ok(None);
434        };
435        if self.file.relocations.get(relocation_index).is_some() {
436            return Err(Error(
437                "Unsupported ELF section with multiple relocation sections",
438            ));
439        }
440        Ok(Some(relocation_index))
441    }
442
443    /// Get the relocation section that references this section.
444    ///
445    /// Returns `None` if there are no relocations.
446    /// Returns an error if there are multiple relocation sections that reference this section.
447    pub fn elf_relocation_section(&self) -> read::Result<Option<&'data Elf::SectionHeader>> {
448        let Some(relocation_index) = self.elf_relocation_section_index()? else {
449            return Ok(None);
450        };
451        self.file.sections.section(relocation_index).map(Some)
452    }
453
454    /// Get the `Elf::Rel` entries that apply to this section.
455    ///
456    /// Returns an empty slice if there are no relocations.
457    /// Returns an error if there are multiple relocation sections that reference this section.
458    pub fn elf_linked_rel(&self) -> read::Result<&'data [Elf::Rel]> {
459        let Some(relocation_section) = self.elf_relocation_section()? else {
460            return Ok(&[]);
461        };
462        // The linked symbol table was already checked when self.file.relocations was created.
463        let Some((rel, _)) = relocation_section.rel(self.file.endian, self.file.data)? else {
464            return Ok(&[]);
465        };
466        Ok(rel)
467    }
468
469    /// Get the `Elf::Rela` entries that apply to this section.
470    ///
471    /// Returns an empty slice if there are no relocations.
472    /// Returns an error if there are multiple relocation sections that reference this section.
473    pub fn elf_linked_rela(&self) -> read::Result<&'data [Elf::Rela]> {
474        let Some(relocation_section) = self.elf_relocation_section()? else {
475            return Ok(&[]);
476        };
477        // The linked symbol table was already checked when self.file.relocations was created.
478        let Some((rela, _)) = relocation_section.rela(self.file.endian, self.file.data)? else {
479            return Ok(&[]);
480        };
481        Ok(rela)
482    }
483
484    fn bytes(&self) -> read::Result<&'data [u8]> {
485        self.section
486            .data(self.file.endian, self.file.data)
487            .read_error("Invalid ELF section size or offset")
488    }
489
490    fn maybe_compressed(&self) -> read::Result<Option<CompressedFileRange>> {
491        let endian = self.file.endian;
492        if let Some((header, offset, compressed_size)) =
493            self.section.compression(endian, self.file.data)?
494        {
495            let format = match header.ch_type(endian) {
496                elf::ELFCOMPRESS_ZLIB => CompressionFormat::Zlib,
497                elf::ELFCOMPRESS_ZSTD => CompressionFormat::Zstandard,
498                _ => return Err(Error("Unsupported ELF compression type")),
499            };
500            let uncompressed_size = header.ch_size(endian).into();
501            Ok(Some(CompressedFileRange {
502                format,
503                offset,
504                compressed_size,
505                uncompressed_size,
506            }))
507        } else {
508            Ok(None)
509        }
510    }
511
512    // Try GNU-style "ZLIB" header decompression.
513    fn maybe_compressed_gnu(&self) -> read::Result<Option<CompressedFileRange>> {
514        if !self
515            .name()
516            .map_or(false, |name| name.starts_with(".zdebug_"))
517        {
518            return Ok(None);
519        }
520        let (section_offset, section_size) = self
521            .file_range()
522            .read_error("Invalid ELF GNU compressed section type")?;
523        gnu_compression::compressed_file_range(self.file.data, section_offset, section_size)
524            .map(Some)
525    }
526}
527
528impl<'data, 'file, Elf, R> read::private::Sealed for ElfSection<'data, 'file, Elf, R>
529where
530    Elf: FileHeader,
531    R: ReadRef<'data>,
532{
533}
534
535impl<'data, 'file, Elf, R> ObjectSection<'data> for ElfSection<'data, 'file, Elf, R>
536where
537    Elf: FileHeader,
538    R: ReadRef<'data>,
539{
540    type RelocationIterator = ElfSectionRelocationIterator<'data, 'file, Elf, R>;
541
542    #[inline]
543    fn index(&self) -> SectionIndex {
544        self.index
545    }
546
547    #[inline]
548    fn address(&self) -> u64 {
549        self.section.sh_addr(self.file.endian).into()
550    }
551
552    #[inline]
553    fn size(&self) -> u64 {
554        self.section.sh_size(self.file.endian).into()
555    }
556
557    #[inline]
558    fn align(&self) -> u64 {
559        self.section.sh_addralign(self.file.endian).into()
560    }
561
562    #[inline]
563    fn file_range(&self) -> Option<(u64, u64)> {
564        self.section.file_range(self.file.endian)
565    }
566
567    #[inline]
568    fn data(&self) -> read::Result<&'data [u8]> {
569        self.bytes()
570    }
571
572    fn data_range(&self, address: u64, size: u64) -> read::Result<Option<&'data [u8]>> {
573        Ok(read::util::data_range(
574            self.bytes()?,
575            self.address(),
576            address,
577            size,
578        ))
579    }
580
581    fn compressed_file_range(&self) -> read::Result<CompressedFileRange> {
582        Ok(if let Some(data) = self.maybe_compressed()? {
583            data
584        } else if let Some(data) = self.maybe_compressed_gnu()? {
585            data
586        } else {
587            CompressedFileRange::none(self.file_range())
588        })
589    }
590
591    fn compressed_data(&self) -> read::Result<CompressedData<'data>> {
592        self.compressed_file_range()?.data(self.file.data)
593    }
594
595    fn name_bytes(&self) -> read::Result<&'data [u8]> {
596        self.file
597            .sections
598            .section_name(self.file.endian, self.section)
599    }
600
601    fn name(&self) -> read::Result<&'data str> {
602        let name = self.name_bytes()?;
603        str::from_utf8(name)
604            .ok()
605            .read_error("Non UTF-8 ELF section name")
606    }
607
608    #[inline]
609    fn segment_name_bytes(&self) -> read::Result<Option<&[u8]>> {
610        Ok(None)
611    }
612
613    #[inline]
614    fn segment_name(&self) -> read::Result<Option<&str>> {
615        Ok(None)
616    }
617
618    fn kind(&self) -> SectionKind {
619        let flags = self.section.sh_flags(self.file.endian).into();
620        let sh_type = self.section.sh_type(self.file.endian);
621        match sh_type {
622            elf::SHT_PROGBITS => {
623                if flags & u64::from(elf::SHF_ALLOC) != 0 {
624                    if flags & u64::from(elf::SHF_EXECINSTR) != 0 {
625                        SectionKind::Text
626                    } else if flags & u64::from(elf::SHF_TLS) != 0 {
627                        SectionKind::Tls
628                    } else if flags & u64::from(elf::SHF_WRITE) != 0 {
629                        SectionKind::Data
630                    } else if flags & u64::from(elf::SHF_STRINGS) != 0 {
631                        SectionKind::ReadOnlyString
632                    } else {
633                        SectionKind::ReadOnlyData
634                    }
635                } else if flags & u64::from(elf::SHF_STRINGS) != 0 {
636                    SectionKind::OtherString
637                } else {
638                    SectionKind::Other
639                }
640            }
641            elf::SHT_NOBITS => {
642                if flags & u64::from(elf::SHF_TLS) != 0 {
643                    SectionKind::UninitializedTls
644                } else {
645                    SectionKind::UninitializedData
646                }
647            }
648            elf::SHT_NOTE => SectionKind::Note,
649            elf::SHT_NULL
650            | elf::SHT_SYMTAB
651            | elf::SHT_STRTAB
652            | elf::SHT_RELA
653            | elf::SHT_HASH
654            | elf::SHT_DYNAMIC
655            | elf::SHT_REL
656            | elf::SHT_DYNSYM
657            | elf::SHT_GROUP
658            | elf::SHT_SYMTAB_SHNDX
659            | elf::SHT_RELR
660            | elf::SHT_CREL => SectionKind::Metadata,
661            _ => SectionKind::Elf(sh_type),
662        }
663    }
664
665    fn relocations(&self) -> ElfSectionRelocationIterator<'data, 'file, Elf, R> {
666        ElfSectionRelocationIterator {
667            section_index: self.index,
668            file: self.file,
669            relocations: None,
670        }
671    }
672
673    fn relocation_map(&self) -> read::Result<RelocationMap> {
674        RelocationMap::new(self.file, self)
675    }
676
677    fn flags(&self) -> SectionFlags {
678        SectionFlags::Elf {
679            sh_flags: self.section.sh_flags(self.file.endian).into(),
680        }
681    }
682}
683
684/// A trait for generic access to [`elf::SectionHeader32`] and [`elf::SectionHeader64`].
685#[allow(missing_docs)]
686pub trait SectionHeader: Debug + Pod {
687    type Elf: FileHeader<SectionHeader = Self, Endian = Self::Endian, Word = Self::Word>;
688    type Word: Into<u64>;
689    type Endian: endian::Endian;
690
691    fn sh_name(&self, endian: Self::Endian) -> u32;
692    fn sh_type(&self, endian: Self::Endian) -> u32;
693    fn sh_flags(&self, endian: Self::Endian) -> Self::Word;
694    fn sh_addr(&self, endian: Self::Endian) -> Self::Word;
695    fn sh_offset(&self, endian: Self::Endian) -> Self::Word;
696    fn sh_size(&self, endian: Self::Endian) -> Self::Word;
697    fn sh_link(&self, endian: Self::Endian) -> u32;
698    fn sh_info(&self, endian: Self::Endian) -> u32;
699    fn sh_addralign(&self, endian: Self::Endian) -> Self::Word;
700    fn sh_entsize(&self, endian: Self::Endian) -> Self::Word;
701
702    /// Parse the section name from the string table.
703    fn name<'data, R: ReadRef<'data>>(
704        &self,
705        endian: Self::Endian,
706        strings: StringTable<'data, R>,
707    ) -> read::Result<&'data [u8]> {
708        strings
709            .get(self.sh_name(endian))
710            .read_error("Invalid ELF section name offset")
711    }
712
713    /// Get the `sh_link` field as a section index.
714    ///
715    /// This may return a null section index, and does not check for validity.
716    fn link(&self, endian: Self::Endian) -> SectionIndex {
717        SectionIndex(self.sh_link(endian) as usize)
718    }
719
720    /// Return true if the `SHF_INFO_LINK` flag is set.
721    fn has_info_link(&self, endian: Self::Endian) -> bool {
722        self.sh_flags(endian).into() & u64::from(elf::SHF_INFO_LINK) != 0
723    }
724
725    /// Get the `sh_info` field as a section index.
726    ///
727    /// This does not check the `SHF_INFO_LINK` flag.
728    /// This may return a null section index, and does not check for validity.
729    fn info_link(&self, endian: Self::Endian) -> SectionIndex {
730        SectionIndex(self.sh_info(endian) as usize)
731    }
732
733    /// Return the offset and size of the section in the file.
734    ///
735    /// Returns `None` for sections that have no data in the file.
736    fn file_range(&self, endian: Self::Endian) -> Option<(u64, u64)> {
737        if self.sh_type(endian) == elf::SHT_NOBITS {
738            None
739        } else {
740            Some((self.sh_offset(endian).into(), self.sh_size(endian).into()))
741        }
742    }
743
744    /// Return the section data.
745    ///
746    /// Returns `Ok(&[])` if the section has no data.
747    /// Returns `Err` for invalid values.
748    fn data<'data, R: ReadRef<'data>>(
749        &self,
750        endian: Self::Endian,
751        data: R,
752    ) -> read::Result<&'data [u8]> {
753        if let Some((offset, size)) = self.file_range(endian) {
754            data.read_bytes_at(offset, size)
755                .read_error("Invalid ELF section size or offset")
756        } else {
757            Ok(&[])
758        }
759    }
760
761    /// Return the section data as a slice of the given type.
762    ///
763    /// Allows padding at the end of the data.
764    /// Returns `Ok(&[])` if the section has no data.
765    /// Returns `Err` for invalid values, including bad alignment.
766    fn data_as_array<'data, T: Pod, R: ReadRef<'data>>(
767        &self,
768        endian: Self::Endian,
769        data: R,
770    ) -> read::Result<&'data [T]> {
771        pod::slice_from_all_bytes(self.data(endian, data)?)
772            .read_error("Invalid ELF section size or offset")
773    }
774
775    /// Return the strings in the section.
776    ///
777    /// Returns `Ok(None)` if the section does not contain strings.
778    /// Returns `Err` for invalid values.
779    fn strings<'data, R: ReadRef<'data>>(
780        &self,
781        endian: Self::Endian,
782        data: R,
783    ) -> read::Result<Option<StringTable<'data, R>>> {
784        if self.sh_type(endian) != elf::SHT_STRTAB {
785            return Ok(None);
786        }
787        let str_offset = self.sh_offset(endian).into();
788        let str_size = self.sh_size(endian).into();
789        let str_end = str_offset
790            .checked_add(str_size)
791            .read_error("Invalid ELF string section offset or size")?;
792        Ok(Some(StringTable::new(data, str_offset, str_end)))
793    }
794
795    /// Return the symbols in the section.
796    ///
797    /// Also finds the linked string table in `sections`.
798    ///
799    /// `section_index` must be the 0-based index of this section, and is used
800    /// to find the corresponding extended section index table in `sections`.
801    ///
802    /// Returns `Ok(None)` if the section does not contain symbols.
803    /// Returns `Err` for invalid values.
804    fn symbols<'data, R: ReadRef<'data>>(
805        &self,
806        endian: Self::Endian,
807        data: R,
808        sections: &SectionTable<'data, Self::Elf, R>,
809        section_index: SectionIndex,
810    ) -> read::Result<Option<SymbolTable<'data, Self::Elf, R>>> {
811        let sh_type = self.sh_type(endian);
812        if sh_type != elf::SHT_SYMTAB && sh_type != elf::SHT_DYNSYM {
813            return Ok(None);
814        }
815        SymbolTable::parse(endian, data, sections, section_index, self).map(Some)
816    }
817
818    /// Return the `Elf::Rel` entries in the section.
819    ///
820    /// Also returns the linked symbol table index.
821    ///
822    /// Returns `Ok(None)` if the section does not contain relocations.
823    /// Returns `Err` for invalid values.
824    fn rel<'data, R: ReadRef<'data>>(
825        &self,
826        endian: Self::Endian,
827        data: R,
828    ) -> read::Result<Option<(&'data [<Self::Elf as FileHeader>::Rel], SectionIndex)>> {
829        if self.sh_type(endian) != elf::SHT_REL {
830            return Ok(None);
831        }
832        let rel = self
833            .data_as_array(endian, data)
834            .read_error("Invalid ELF relocation section offset or size")?;
835        Ok(Some((rel, self.link(endian))))
836    }
837
838    /// Return the `Elf::Rela` entries in the section.
839    ///
840    /// Also returns the linked symbol table index.
841    ///
842    /// Returns `Ok(None)` if the section does not contain relocations.
843    /// Returns `Err` for invalid values.
844    fn rela<'data, R: ReadRef<'data>>(
845        &self,
846        endian: Self::Endian,
847        data: R,
848    ) -> read::Result<Option<(&'data [<Self::Elf as FileHeader>::Rela], SectionIndex)>> {
849        if self.sh_type(endian) != elf::SHT_RELA {
850            return Ok(None);
851        }
852        let rela = self
853            .data_as_array(endian, data)
854            .read_error("Invalid ELF relocation section offset or size")?;
855        Ok(Some((rela, self.link(endian))))
856    }
857
858    /// Return the `Elf::Relr` entries in the section.
859    ///
860    /// Returns `Ok(None)` if the section does not contain relative relocations.
861    /// Returns `Err` for invalid values.
862    fn relr<'data, R: ReadRef<'data>>(
863        &self,
864        endian: Self::Endian,
865        data: R,
866    ) -> read::Result<Option<RelrIterator<'data, Self::Elf>>> {
867        if self.sh_type(endian) != elf::SHT_RELR {
868            return Ok(None);
869        }
870        let data = self
871            .data_as_array(endian, data)
872            .read_error("Invalid ELF relocation section offset or size")?;
873        let relrs = RelrIterator::new(endian, data);
874        Ok(Some(relrs))
875    }
876
877    /// Return the `Crel` entries in the section.
878    ///
879    /// Returns `Ok(None)` if the section does not contain compact relocations.
880    /// Returns `Err` for invalid values.
881    fn crel<'data, R: ReadRef<'data>>(
882        &self,
883        endian: Self::Endian,
884        data: R,
885    ) -> read::Result<Option<(CrelIterator<'data>, SectionIndex)>> {
886        if self.sh_type(endian) != elf::SHT_CREL {
887            return Ok(None);
888        }
889        let data = self
890            .data(endian, data)
891            .read_error("Invalid ELF relocation section offset or size")?;
892        let relrs = CrelIterator::new(data);
893        Ok(Some((relrs?, self.link(endian))))
894    }
895
896    /// Return entries in a dynamic section.
897    ///
898    /// Also returns the linked string table index.
899    ///
900    /// Returns `Ok(None)` if the section type is not `SHT_DYNAMIC`.
901    /// Returns `Err` for invalid values.
902    fn dynamic<'data, R: ReadRef<'data>>(
903        &self,
904        endian: Self::Endian,
905        data: R,
906    ) -> read::Result<Option<(&'data [<Self::Elf as FileHeader>::Dyn], SectionIndex)>> {
907        if self.sh_type(endian) != elf::SHT_DYNAMIC {
908            return Ok(None);
909        }
910        let dynamic = self
911            .data_as_array(endian, data)
912            .read_error("Invalid ELF dynamic section offset or size")?;
913        Ok(Some((dynamic, self.link(endian))))
914    }
915
916    /// Return a note iterator for the section data.
917    ///
918    /// Returns `Ok(None)` if the section does not contain notes.
919    /// Returns `Err` for invalid values.
920    fn notes<'data, R: ReadRef<'data>>(
921        &self,
922        endian: Self::Endian,
923        data: R,
924    ) -> read::Result<Option<NoteIterator<'data, Self::Elf>>> {
925        if self.sh_type(endian) != elf::SHT_NOTE {
926            return Ok(None);
927        }
928        let data = self
929            .data(endian, data)
930            .read_error("Invalid ELF note section offset or size")?;
931        let notes = NoteIterator::new(endian, self.sh_addralign(endian), data)?;
932        Ok(Some(notes))
933    }
934
935    /// Return the contents of a group section.
936    ///
937    /// The first value is a `GRP_*` value, and the remaining values
938    /// are section indices.
939    ///
940    /// Returns `Ok(None)` if the section does not define a group.
941    /// Returns `Err` for invalid values.
942    fn group<'data, R: ReadRef<'data>>(
943        &self,
944        endian: Self::Endian,
945        data: R,
946    ) -> read::Result<Option<(u32, &'data [U32Bytes<Self::Endian>])>> {
947        if self.sh_type(endian) != elf::SHT_GROUP {
948            return Ok(None);
949        }
950        let msg = "Invalid ELF group section offset or size";
951        let data = self.data(endian, data).read_error(msg)?;
952        let (flag, data) = pod::from_bytes::<U32Bytes<_>>(data).read_error(msg)?;
953        let sections = pod::slice_from_all_bytes(data).read_error(msg)?;
954        Ok(Some((flag.get(endian), sections)))
955    }
956
957    /// Return the header of a SysV hash section.
958    ///
959    /// Returns `Ok(None)` if the section does not contain a SysV hash.
960    /// Returns `Err` for invalid values.
961    fn hash_header<'data, R: ReadRef<'data>>(
962        &self,
963        endian: Self::Endian,
964        data: R,
965    ) -> read::Result<Option<&'data elf::HashHeader<Self::Endian>>> {
966        if self.sh_type(endian) != elf::SHT_HASH {
967            return Ok(None);
968        }
969        let data = self
970            .data(endian, data)
971            .read_error("Invalid ELF hash section offset or size")?;
972        let header = data
973            .read_at::<elf::HashHeader<Self::Endian>>(0)
974            .read_error("Invalid hash header")?;
975        Ok(Some(header))
976    }
977
978    /// Return the contents of a SysV hash section.
979    ///
980    /// Also returns the linked symbol table index.
981    ///
982    /// Returns `Ok(None)` if the section does not contain a SysV hash.
983    /// Returns `Err` for invalid values.
984    fn hash<'data, R: ReadRef<'data>>(
985        &self,
986        endian: Self::Endian,
987        data: R,
988    ) -> read::Result<Option<(HashTable<'data, Self::Elf>, SectionIndex)>> {
989        if self.sh_type(endian) != elf::SHT_HASH {
990            return Ok(None);
991        }
992        let data = self
993            .data(endian, data)
994            .read_error("Invalid ELF hash section offset or size")?;
995        let hash = HashTable::parse(endian, data)?;
996        Ok(Some((hash, self.link(endian))))
997    }
998
999    /// Return the header of a GNU hash section.
1000    ///
1001    /// Returns `Ok(None)` if the section does not contain a GNU hash.
1002    /// Returns `Err` for invalid values.
1003    fn gnu_hash_header<'data, R: ReadRef<'data>>(
1004        &self,
1005        endian: Self::Endian,
1006        data: R,
1007    ) -> read::Result<Option<&'data elf::GnuHashHeader<Self::Endian>>> {
1008        if self.sh_type(endian) != elf::SHT_GNU_HASH {
1009            return Ok(None);
1010        }
1011        let data = self
1012            .data(endian, data)
1013            .read_error("Invalid ELF GNU hash section offset or size")?;
1014        let header = data
1015            .read_at::<elf::GnuHashHeader<Self::Endian>>(0)
1016            .read_error("Invalid GNU hash header")?;
1017        Ok(Some(header))
1018    }
1019
1020    /// Return the contents of a GNU hash section.
1021    ///
1022    /// Also returns the linked symbol table index.
1023    ///
1024    /// Returns `Ok(None)` if the section does not contain a GNU hash.
1025    /// Returns `Err` for invalid values.
1026    fn gnu_hash<'data, R: ReadRef<'data>>(
1027        &self,
1028        endian: Self::Endian,
1029        data: R,
1030    ) -> read::Result<Option<(GnuHashTable<'data, Self::Elf>, SectionIndex)>> {
1031        if self.sh_type(endian) != elf::SHT_GNU_HASH {
1032            return Ok(None);
1033        }
1034        let data = self
1035            .data(endian, data)
1036            .read_error("Invalid ELF GNU hash section offset or size")?;
1037        let hash = GnuHashTable::parse(endian, data)?;
1038        Ok(Some((hash, self.link(endian))))
1039    }
1040
1041    /// Return the contents of a `SHT_GNU_VERSYM` section.
1042    ///
1043    /// Also returns the linked symbol table index.
1044    ///
1045    /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERSYM`.
1046    /// Returns `Err` for invalid values.
1047    fn gnu_versym<'data, R: ReadRef<'data>>(
1048        &self,
1049        endian: Self::Endian,
1050        data: R,
1051    ) -> read::Result<Option<(&'data [elf::Versym<Self::Endian>], SectionIndex)>> {
1052        if self.sh_type(endian) != elf::SHT_GNU_VERSYM {
1053            return Ok(None);
1054        }
1055        let versym = self
1056            .data_as_array(endian, data)
1057            .read_error("Invalid ELF GNU versym section offset or size")?;
1058        Ok(Some((versym, self.link(endian))))
1059    }
1060
1061    /// Return an iterator for the entries of a `SHT_GNU_VERDEF` section.
1062    ///
1063    /// Also returns the linked string table index.
1064    ///
1065    /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERDEF`.
1066    /// Returns `Err` for invalid values.
1067    fn gnu_verdef<'data, R: ReadRef<'data>>(
1068        &self,
1069        endian: Self::Endian,
1070        data: R,
1071    ) -> read::Result<Option<(VerdefIterator<'data, Self::Elf>, SectionIndex)>> {
1072        if self.sh_type(endian) != elf::SHT_GNU_VERDEF {
1073            return Ok(None);
1074        }
1075        let verdef = self
1076            .data(endian, data)
1077            .read_error("Invalid ELF GNU verdef section offset or size")?;
1078        Ok(Some((
1079            VerdefIterator::new(endian, verdef),
1080            self.link(endian),
1081        )))
1082    }
1083
1084    /// Return an iterator for the entries of a `SHT_GNU_VERNEED` section.
1085    ///
1086    /// Also returns the linked string table index.
1087    ///
1088    /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERNEED`.
1089    /// Returns `Err` for invalid values.
1090    fn gnu_verneed<'data, R: ReadRef<'data>>(
1091        &self,
1092        endian: Self::Endian,
1093        data: R,
1094    ) -> read::Result<Option<(VerneedIterator<'data, Self::Elf>, SectionIndex)>> {
1095        if self.sh_type(endian) != elf::SHT_GNU_VERNEED {
1096            return Ok(None);
1097        }
1098        let verneed = self
1099            .data(endian, data)
1100            .read_error("Invalid ELF GNU verneed section offset or size")?;
1101        Ok(Some((
1102            VerneedIterator::new(endian, verneed),
1103            self.link(endian),
1104        )))
1105    }
1106
1107    /// Return the contents of a `SHT_GNU_ATTRIBUTES` section.
1108    ///
1109    /// Returns `Ok(None)` if the section type is not `SHT_GNU_ATTRIBUTES`.
1110    /// Returns `Err` for invalid values.
1111    fn gnu_attributes<'data, R: ReadRef<'data>>(
1112        &self,
1113        endian: Self::Endian,
1114        data: R,
1115    ) -> read::Result<Option<AttributesSection<'data, Self::Elf>>> {
1116        if self.sh_type(endian) != elf::SHT_GNU_ATTRIBUTES {
1117            return Ok(None);
1118        }
1119        self.attributes(endian, data).map(Some)
1120    }
1121
1122    /// Parse the contents of the section as attributes.
1123    ///
1124    /// This function does not check whether section type corresponds
1125    /// to a section that contains attributes.
1126    ///
1127    /// Returns `Err` for invalid values.
1128    fn attributes<'data, R: ReadRef<'data>>(
1129        &self,
1130        endian: Self::Endian,
1131        data: R,
1132    ) -> read::Result<AttributesSection<'data, Self::Elf>> {
1133        let data = self.data(endian, data)?;
1134        AttributesSection::new(endian, data)
1135    }
1136
1137    /// Parse the compression header if present.
1138    ///
1139    /// Returns the header, and the offset and size of the compressed section data
1140    /// in the file.
1141    ///
1142    /// Returns `Ok(None)` if the section flags do not have `SHF_COMPRESSED`.
1143    /// Returns `Err` for invalid values.
1144    fn compression<'data, R: ReadRef<'data>>(
1145        &self,
1146        endian: Self::Endian,
1147        data: R,
1148    ) -> read::Result<
1149        Option<(
1150            &'data <Self::Elf as FileHeader>::CompressionHeader,
1151            u64,
1152            u64,
1153        )>,
1154    > {
1155        if (self.sh_flags(endian).into() & u64::from(elf::SHF_COMPRESSED)) == 0 {
1156            return Ok(None);
1157        }
1158        let (section_offset, section_size) = self
1159            .file_range(endian)
1160            .read_error("Invalid ELF compressed section type")?;
1161        let mut offset = section_offset;
1162        let header = data
1163            .read::<<Self::Elf as FileHeader>::CompressionHeader>(&mut offset)
1164            .read_error("Invalid ELF compressed section offset")?;
1165        let compressed_size = section_size
1166            .checked_sub(offset - section_offset)
1167            .read_error("Invalid ELF compressed section size")?;
1168        Ok(Some((header, offset, compressed_size)))
1169    }
1170}
1171
1172impl<Endian: endian::Endian> SectionHeader for elf::SectionHeader32<Endian> {
1173    type Elf = elf::FileHeader32<Endian>;
1174    type Word = u32;
1175    type Endian = Endian;
1176
1177    #[inline]
1178    fn sh_name(&self, endian: Self::Endian) -> u32 {
1179        self.sh_name.get(endian)
1180    }
1181
1182    #[inline]
1183    fn sh_type(&self, endian: Self::Endian) -> u32 {
1184        self.sh_type.get(endian)
1185    }
1186
1187    #[inline]
1188    fn sh_flags(&self, endian: Self::Endian) -> Self::Word {
1189        self.sh_flags.get(endian)
1190    }
1191
1192    #[inline]
1193    fn sh_addr(&self, endian: Self::Endian) -> Self::Word {
1194        self.sh_addr.get(endian)
1195    }
1196
1197    #[inline]
1198    fn sh_offset(&self, endian: Self::Endian) -> Self::Word {
1199        self.sh_offset.get(endian)
1200    }
1201
1202    #[inline]
1203    fn sh_size(&self, endian: Self::Endian) -> Self::Word {
1204        self.sh_size.get(endian)
1205    }
1206
1207    #[inline]
1208    fn sh_link(&self, endian: Self::Endian) -> u32 {
1209        self.sh_link.get(endian)
1210    }
1211
1212    #[inline]
1213    fn sh_info(&self, endian: Self::Endian) -> u32 {
1214        self.sh_info.get(endian)
1215    }
1216
1217    #[inline]
1218    fn sh_addralign(&self, endian: Self::Endian) -> Self::Word {
1219        self.sh_addralign.get(endian)
1220    }
1221
1222    #[inline]
1223    fn sh_entsize(&self, endian: Self::Endian) -> Self::Word {
1224        self.sh_entsize.get(endian)
1225    }
1226}
1227
1228impl<Endian: endian::Endian> SectionHeader for elf::SectionHeader64<Endian> {
1229    type Word = u64;
1230    type Endian = Endian;
1231    type Elf = elf::FileHeader64<Endian>;
1232
1233    #[inline]
1234    fn sh_name(&self, endian: Self::Endian) -> u32 {
1235        self.sh_name.get(endian)
1236    }
1237
1238    #[inline]
1239    fn sh_type(&self, endian: Self::Endian) -> u32 {
1240        self.sh_type.get(endian)
1241    }
1242
1243    #[inline]
1244    fn sh_flags(&self, endian: Self::Endian) -> Self::Word {
1245        self.sh_flags.get(endian)
1246    }
1247
1248    #[inline]
1249    fn sh_addr(&self, endian: Self::Endian) -> Self::Word {
1250        self.sh_addr.get(endian)
1251    }
1252
1253    #[inline]
1254    fn sh_offset(&self, endian: Self::Endian) -> Self::Word {
1255        self.sh_offset.get(endian)
1256    }
1257
1258    #[inline]
1259    fn sh_size(&self, endian: Self::Endian) -> Self::Word {
1260        self.sh_size.get(endian)
1261    }
1262
1263    #[inline]
1264    fn sh_link(&self, endian: Self::Endian) -> u32 {
1265        self.sh_link.get(endian)
1266    }
1267
1268    #[inline]
1269    fn sh_info(&self, endian: Self::Endian) -> u32 {
1270        self.sh_info.get(endian)
1271    }
1272
1273    #[inline]
1274    fn sh_addralign(&self, endian: Self::Endian) -> Self::Word {
1275        self.sh_addralign.get(endian)
1276    }
1277
1278    #[inline]
1279    fn sh_entsize(&self, endian: Self::Endian) -> Self::Word {
1280        self.sh_entsize.get(endian)
1281    }
1282}