Skip to main content

object/read/elf/
section.rs

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