summaryrefslogtreecommitdiff
path: root/vendor/object/src/read/elf/section.rs
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
committerValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
commit1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch)
tree7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/object/src/read/elf/section.rs
parent5ecd8cf2cba827454317368b68571df0d13d7842 (diff)
downloadfparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz
fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/object/src/read/elf/section.rs')
-rw-r--r--vendor/object/src/read/elf/section.rs1150
1 files changed, 1150 insertions, 0 deletions
diff --git a/vendor/object/src/read/elf/section.rs b/vendor/object/src/read/elf/section.rs
new file mode 100644
index 0000000..2b5ae01
--- /dev/null
+++ b/vendor/object/src/read/elf/section.rs
@@ -0,0 +1,1150 @@
+use core::fmt::Debug;
+use core::{iter, mem, slice, str};
+
+use crate::elf;
+use crate::endian::{self, Endianness, U32Bytes};
+use crate::pod::Pod;
+use crate::read::{
+ self, Bytes, CompressedData, CompressedFileRange, CompressionFormat, Error, ObjectSection,
+ ReadError, ReadRef, SectionFlags, SectionIndex, SectionKind, StringTable,
+};
+
+use super::{
+ AttributesSection, CompressionHeader, ElfFile, ElfSectionRelocationIterator, FileHeader,
+ GnuHashTable, HashTable, NoteIterator, RelocationSections, SymbolTable, VerdefIterator,
+ VerneedIterator, VersionTable,
+};
+
+/// The table of section headers in an ELF file.
+///
+/// Also includes the string table used for the section names.
+///
+/// Returned by [`FileHeader::sections`].
+#[derive(Debug, Default, Clone, Copy)]
+pub struct SectionTable<'data, Elf: FileHeader, R = &'data [u8]>
+where
+ R: ReadRef<'data>,
+{
+ sections: &'data [Elf::SectionHeader],
+ strings: StringTable<'data, R>,
+}
+
+impl<'data, Elf: FileHeader, R: ReadRef<'data>> SectionTable<'data, Elf, R> {
+ /// Create a new section table.
+ #[inline]
+ pub fn new(sections: &'data [Elf::SectionHeader], strings: StringTable<'data, R>) -> Self {
+ SectionTable { sections, strings }
+ }
+
+ /// Iterate over the section headers.
+ #[inline]
+ pub fn iter(&self) -> slice::Iter<'data, Elf::SectionHeader> {
+ self.sections.iter()
+ }
+
+ /// Return true if the section table is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.sections.is_empty()
+ }
+
+ /// The number of section headers.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.sections.len()
+ }
+
+ /// Return the section header at the given index.
+ pub fn section(&self, index: SectionIndex) -> read::Result<&'data Elf::SectionHeader> {
+ self.sections
+ .get(index.0)
+ .read_error("Invalid ELF section index")
+ }
+
+ /// Return the section header with the given name.
+ ///
+ /// Ignores sections with invalid names.
+ pub fn section_by_name(
+ &self,
+ endian: Elf::Endian,
+ name: &[u8],
+ ) -> Option<(usize, &'data Elf::SectionHeader)> {
+ self.sections
+ .iter()
+ .enumerate()
+ .find(|(_, section)| self.section_name(endian, section) == Ok(name))
+ }
+
+ /// Return the section name for the given section header.
+ pub fn section_name(
+ &self,
+ endian: Elf::Endian,
+ section: &'data Elf::SectionHeader,
+ ) -> read::Result<&'data [u8]> {
+ section.name(endian, self.strings)
+ }
+
+ /// Return the string table at the given section index.
+ ///
+ /// Returns an error if the section is not a string table.
+ #[inline]
+ pub fn strings(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ index: SectionIndex,
+ ) -> read::Result<StringTable<'data, R>> {
+ self.section(index)?
+ .strings(endian, data)?
+ .read_error("Invalid ELF string section type")
+ }
+
+ /// Return the symbol table of the given section type.
+ ///
+ /// Returns an empty symbol table if the symbol table does not exist.
+ #[inline]
+ pub fn symbols(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ sh_type: u32,
+ ) -> read::Result<SymbolTable<'data, Elf, R>> {
+ debug_assert!(sh_type == elf::SHT_DYNSYM || sh_type == elf::SHT_SYMTAB);
+
+ let (index, section) = match self
+ .iter()
+ .enumerate()
+ .find(|s| s.1.sh_type(endian) == sh_type)
+ {
+ Some(s) => s,
+ None => return Ok(SymbolTable::default()),
+ };
+
+ SymbolTable::parse(endian, data, self, SectionIndex(index), section)
+ }
+
+ /// Return the symbol table at the given section index.
+ ///
+ /// Returns an error if the section is not a symbol table.
+ #[inline]
+ pub fn symbol_table_by_index(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ index: SectionIndex,
+ ) -> read::Result<SymbolTable<'data, Elf, R>> {
+ let section = self.section(index)?;
+ match section.sh_type(endian) {
+ elf::SHT_DYNSYM | elf::SHT_SYMTAB => {}
+ _ => return Err(Error("Invalid ELF symbol table section type")),
+ }
+ SymbolTable::parse(endian, data, self, index, section)
+ }
+
+ /// Create a mapping from section index to associated relocation sections.
+ #[inline]
+ pub fn relocation_sections(
+ &self,
+ endian: Elf::Endian,
+ symbol_section: SectionIndex,
+ ) -> read::Result<RelocationSections> {
+ RelocationSections::parse(endian, self, symbol_section)
+ }
+
+ /// Return the contents of a dynamic section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if there is no `SHT_DYNAMIC` section.
+ /// Returns `Err` for invalid values.
+ pub fn dynamic(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [Elf::Dyn], SectionIndex)>> {
+ for section in self.sections {
+ if let Some(dynamic) = section.dynamic(endian, data)? {
+ return Ok(Some(dynamic));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the header of a SysV hash section.
+ ///
+ /// Returns `Ok(None)` if there is no SysV GNU hash section.
+ /// Returns `Err` for invalid values.
+ pub fn hash_header(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<&'data elf::HashHeader<Elf::Endian>>> {
+ for section in self.sections {
+ if let Some(hash) = section.hash_header(endian, data)? {
+ return Ok(Some(hash));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the contents of a SysV hash section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if there is no SysV hash section.
+ /// Returns `Err` for invalid values.
+ pub fn hash(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(HashTable<'data, Elf>, SectionIndex)>> {
+ for section in self.sections {
+ if let Some(hash) = section.hash(endian, data)? {
+ return Ok(Some(hash));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the header of a GNU hash section.
+ ///
+ /// Returns `Ok(None)` if there is no GNU hash section.
+ /// Returns `Err` for invalid values.
+ pub fn gnu_hash_header(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<&'data elf::GnuHashHeader<Elf::Endian>>> {
+ for section in self.sections {
+ if let Some(hash) = section.gnu_hash_header(endian, data)? {
+ return Ok(Some(hash));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the contents of a GNU hash section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if there is no GNU hash section.
+ /// Returns `Err` for invalid values.
+ pub fn gnu_hash(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(GnuHashTable<'data, Elf>, SectionIndex)>> {
+ for section in self.sections {
+ if let Some(hash) = section.gnu_hash(endian, data)? {
+ return Ok(Some(hash));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the contents of a `SHT_GNU_VERSYM` section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if there is no `SHT_GNU_VERSYM` section.
+ /// Returns `Err` for invalid values.
+ pub fn gnu_versym(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [elf::Versym<Elf::Endian>], SectionIndex)>> {
+ for section in self.sections {
+ if let Some(syms) = section.gnu_versym(endian, data)? {
+ return Ok(Some(syms));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the contents of a `SHT_GNU_VERDEF` section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if there is no `SHT_GNU_VERDEF` section.
+ /// Returns `Err` for invalid values.
+ pub fn gnu_verdef(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(VerdefIterator<'data, Elf>, SectionIndex)>> {
+ for section in self.sections {
+ if let Some(defs) = section.gnu_verdef(endian, data)? {
+ return Ok(Some(defs));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Return the contents of a `SHT_GNU_VERNEED` section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if there is no `SHT_GNU_VERNEED` section.
+ /// Returns `Err` for invalid values.
+ pub fn gnu_verneed(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<(VerneedIterator<'data, Elf>, SectionIndex)>> {
+ for section in self.sections {
+ if let Some(needs) = section.gnu_verneed(endian, data)? {
+ return Ok(Some(needs));
+ }
+ }
+ Ok(None)
+ }
+
+ /// Returns the symbol version table.
+ ///
+ /// Returns `Ok(None)` if there is no `SHT_GNU_VERSYM` section.
+ /// Returns `Err` for invalid values.
+ pub fn versions(
+ &self,
+ endian: Elf::Endian,
+ data: R,
+ ) -> read::Result<Option<VersionTable<'data, Elf>>> {
+ let (versyms, link) = match self.gnu_versym(endian, data)? {
+ Some(val) => val,
+ None => return Ok(None),
+ };
+ let strings = self.symbol_table_by_index(endian, data, link)?.strings();
+ // TODO: check links?
+ let verdefs = self.gnu_verdef(endian, data)?.map(|x| x.0);
+ let verneeds = self.gnu_verneed(endian, data)?.map(|x| x.0);
+ VersionTable::parse(endian, versyms, verdefs, verneeds, strings).map(Some)
+ }
+}
+
+/// An iterator for the sections in an [`ElfFile32`](super::ElfFile32).
+pub type ElfSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// An iterator for the sections in an [`ElfFile64`](super::ElfFile64).
+pub type ElfSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// An iterator for the sections in an [`ElfFile`].
+#[derive(Debug)]
+pub struct ElfSectionIterator<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file ElfFile<'data, Elf, R>,
+ pub(super) iter: iter::Enumerate<slice::Iter<'data, Elf::SectionHeader>>,
+}
+
+impl<'data, 'file, Elf, R> Iterator for ElfSectionIterator<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ type Item = ElfSection<'data, 'file, Elf, R>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|(index, section)| ElfSection {
+ index: SectionIndex(index),
+ file: self.file,
+ section,
+ })
+ }
+}
+
+/// A section in an [`ElfFile32`](super::ElfFile32).
+pub type ElfSection32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSection<'data, 'file, elf::FileHeader32<Endian>, R>;
+/// A section in an [`ElfFile64`](super::ElfFile64).
+pub type ElfSection64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
+ ElfSection<'data, 'file, elf::FileHeader64<Endian>, R>;
+
+/// A section in an [`ElfFile`].
+///
+/// Most functionality is provided by the [`ObjectSection`] trait implementation.
+#[derive(Debug)]
+pub struct ElfSection<'data, 'file, Elf, R = &'data [u8]>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ pub(super) file: &'file ElfFile<'data, Elf, R>,
+ pub(super) index: SectionIndex,
+ pub(super) section: &'data Elf::SectionHeader,
+}
+
+impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSection<'data, 'file, Elf, R> {
+ fn bytes(&self) -> read::Result<&'data [u8]> {
+ self.section
+ .data(self.file.endian, self.file.data)
+ .read_error("Invalid ELF section size or offset")
+ }
+
+ fn maybe_compressed(&self) -> read::Result<Option<CompressedFileRange>> {
+ let endian = self.file.endian;
+ if let Some((header, offset, compressed_size)) =
+ self.section.compression(endian, self.file.data)?
+ {
+ let format = match header.ch_type(endian) {
+ elf::ELFCOMPRESS_ZLIB => CompressionFormat::Zlib,
+ elf::ELFCOMPRESS_ZSTD => CompressionFormat::Zstandard,
+ _ => return Err(Error("Unsupported ELF compression type")),
+ };
+ let uncompressed_size = header.ch_size(endian).into();
+ Ok(Some(CompressedFileRange {
+ format,
+ offset,
+ compressed_size,
+ uncompressed_size,
+ }))
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Try GNU-style "ZLIB" header decompression.
+ fn maybe_compressed_gnu(&self) -> read::Result<Option<CompressedFileRange>> {
+ let name = match self.name() {
+ Ok(name) => name,
+ // I think it's ok to ignore this error?
+ Err(_) => return Ok(None),
+ };
+ if !name.starts_with(".zdebug_") {
+ return Ok(None);
+ }
+ let (section_offset, section_size) = self
+ .section
+ .file_range(self.file.endian)
+ .read_error("Invalid ELF GNU compressed section type")?;
+ let mut offset = section_offset;
+ let data = self.file.data;
+ // Assume ZLIB-style uncompressed data is no more than 4GB to avoid accidentally
+ // huge allocations. This also reduces the chance of accidentally matching on a
+ // .debug_str that happens to start with "ZLIB".
+ if data
+ .read_bytes(&mut offset, 8)
+ .read_error("ELF GNU compressed section is too short")?
+ != b"ZLIB\0\0\0\0"
+ {
+ return Err(Error("Invalid ELF GNU compressed section header"));
+ }
+ let uncompressed_size = data
+ .read::<U32Bytes<_>>(&mut offset)
+ .read_error("ELF GNU compressed section is too short")?
+ .get(endian::BigEndian)
+ .into();
+ let compressed_size = section_size
+ .checked_sub(offset - section_offset)
+ .read_error("ELF GNU compressed section is too short")?;
+ Ok(Some(CompressedFileRange {
+ format: CompressionFormat::Zlib,
+ offset,
+ compressed_size,
+ uncompressed_size,
+ }))
+ }
+}
+
+impl<'data, 'file, Elf, R> read::private::Sealed for ElfSection<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+}
+
+impl<'data, 'file, Elf, R> ObjectSection<'data> for ElfSection<'data, 'file, Elf, R>
+where
+ Elf: FileHeader,
+ R: ReadRef<'data>,
+{
+ type RelocationIterator = ElfSectionRelocationIterator<'data, 'file, Elf, R>;
+
+ #[inline]
+ fn index(&self) -> SectionIndex {
+ self.index
+ }
+
+ #[inline]
+ fn address(&self) -> u64 {
+ self.section.sh_addr(self.file.endian).into()
+ }
+
+ #[inline]
+ fn size(&self) -> u64 {
+ self.section.sh_size(self.file.endian).into()
+ }
+
+ #[inline]
+ fn align(&self) -> u64 {
+ self.section.sh_addralign(self.file.endian).into()
+ }
+
+ #[inline]
+ fn file_range(&self) -> Option<(u64, u64)> {
+ self.section.file_range(self.file.endian)
+ }
+
+ #[inline]
+ fn data(&self) -> read::Result<&'data [u8]> {
+ self.bytes()
+ }
+
+ fn data_range(&self, address: u64, size: u64) -> read::Result<Option<&'data [u8]>> {
+ Ok(read::util::data_range(
+ self.bytes()?,
+ self.address(),
+ address,
+ size,
+ ))
+ }
+
+ fn compressed_file_range(&self) -> read::Result<CompressedFileRange> {
+ Ok(if let Some(data) = self.maybe_compressed()? {
+ data
+ } else if let Some(data) = self.maybe_compressed_gnu()? {
+ data
+ } else {
+ CompressedFileRange::none(self.file_range())
+ })
+ }
+
+ fn compressed_data(&self) -> read::Result<CompressedData<'data>> {
+ self.compressed_file_range()?.data(self.file.data)
+ }
+
+ fn name_bytes(&self) -> read::Result<&[u8]> {
+ self.file
+ .sections
+ .section_name(self.file.endian, self.section)
+ }
+
+ fn name(&self) -> read::Result<&str> {
+ let name = self.name_bytes()?;
+ str::from_utf8(name)
+ .ok()
+ .read_error("Non UTF-8 ELF section name")
+ }
+
+ #[inline]
+ fn segment_name_bytes(&self) -> read::Result<Option<&[u8]>> {
+ Ok(None)
+ }
+
+ #[inline]
+ fn segment_name(&self) -> read::Result<Option<&str>> {
+ Ok(None)
+ }
+
+ fn kind(&self) -> SectionKind {
+ let flags = self.section.sh_flags(self.file.endian).into();
+ let sh_type = self.section.sh_type(self.file.endian);
+ match sh_type {
+ elf::SHT_PROGBITS => {
+ if flags & u64::from(elf::SHF_ALLOC) != 0 {
+ if flags & u64::from(elf::SHF_EXECINSTR) != 0 {
+ SectionKind::Text
+ } else if flags & u64::from(elf::SHF_TLS) != 0 {
+ SectionKind::Tls
+ } else if flags & u64::from(elf::SHF_WRITE) != 0 {
+ SectionKind::Data
+ } else if flags & u64::from(elf::SHF_STRINGS) != 0 {
+ SectionKind::ReadOnlyString
+ } else {
+ SectionKind::ReadOnlyData
+ }
+ } else if flags & u64::from(elf::SHF_STRINGS) != 0 {
+ SectionKind::OtherString
+ } else {
+ SectionKind::Other
+ }
+ }
+ elf::SHT_NOBITS => {
+ if flags & u64::from(elf::SHF_TLS) != 0 {
+ SectionKind::UninitializedTls
+ } else {
+ SectionKind::UninitializedData
+ }
+ }
+ elf::SHT_NOTE => SectionKind::Note,
+ elf::SHT_NULL
+ | elf::SHT_SYMTAB
+ | elf::SHT_STRTAB
+ | elf::SHT_RELA
+ | elf::SHT_HASH
+ | elf::SHT_DYNAMIC
+ | elf::SHT_REL
+ | elf::SHT_DYNSYM
+ | elf::SHT_GROUP => SectionKind::Metadata,
+ _ => SectionKind::Elf(sh_type),
+ }
+ }
+
+ fn relocations(&self) -> ElfSectionRelocationIterator<'data, 'file, Elf, R> {
+ ElfSectionRelocationIterator {
+ section_index: self.index,
+ file: self.file,
+ relocations: None,
+ }
+ }
+
+ fn flags(&self) -> SectionFlags {
+ SectionFlags::Elf {
+ sh_flags: self.section.sh_flags(self.file.endian).into(),
+ }
+ }
+}
+
+/// A trait for generic access to [`elf::SectionHeader32`] and [`elf::SectionHeader64`].
+#[allow(missing_docs)]
+pub trait SectionHeader: Debug + Pod {
+ type Elf: FileHeader<SectionHeader = Self, Endian = Self::Endian, Word = Self::Word>;
+ type Word: Into<u64>;
+ type Endian: endian::Endian;
+
+ fn sh_name(&self, endian: Self::Endian) -> u32;
+ fn sh_type(&self, endian: Self::Endian) -> u32;
+ fn sh_flags(&self, endian: Self::Endian) -> Self::Word;
+ fn sh_addr(&self, endian: Self::Endian) -> Self::Word;
+ fn sh_offset(&self, endian: Self::Endian) -> Self::Word;
+ fn sh_size(&self, endian: Self::Endian) -> Self::Word;
+ fn sh_link(&self, endian: Self::Endian) -> u32;
+ fn sh_info(&self, endian: Self::Endian) -> u32;
+ fn sh_addralign(&self, endian: Self::Endian) -> Self::Word;
+ fn sh_entsize(&self, endian: Self::Endian) -> Self::Word;
+
+ /// Parse the section name from the string table.
+ fn name<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ strings: StringTable<'data, R>,
+ ) -> read::Result<&'data [u8]> {
+ strings
+ .get(self.sh_name(endian))
+ .read_error("Invalid ELF section name offset")
+ }
+
+ /// Return the offset and size of the section in the file.
+ ///
+ /// Returns `None` for sections that have no data in the file.
+ fn file_range(&self, endian: Self::Endian) -> Option<(u64, u64)> {
+ if self.sh_type(endian) == elf::SHT_NOBITS {
+ None
+ } else {
+ Some((self.sh_offset(endian).into(), self.sh_size(endian).into()))
+ }
+ }
+
+ /// Return the section data.
+ ///
+ /// Returns `Ok(&[])` if the section has no data.
+ /// Returns `Err` for invalid values.
+ fn data<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<&'data [u8]> {
+ if let Some((offset, size)) = self.file_range(endian) {
+ data.read_bytes_at(offset, size)
+ .read_error("Invalid ELF section size or offset")
+ } else {
+ Ok(&[])
+ }
+ }
+
+ /// Return the section data as a slice of the given type.
+ ///
+ /// Allows padding at the end of the data.
+ /// Returns `Ok(&[])` if the section has no data.
+ /// Returns `Err` for invalid values, including bad alignment.
+ fn data_as_array<'data, T: Pod, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<&'data [T]> {
+ let mut data = self.data(endian, data).map(Bytes)?;
+ data.read_slice(data.len() / mem::size_of::<T>())
+ .read_error("Invalid ELF section size or offset")
+ }
+
+ /// Return the strings in the section.
+ ///
+ /// Returns `Ok(None)` if the section does not contain strings.
+ /// Returns `Err` for invalid values.
+ fn strings<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<StringTable<'data, R>>> {
+ if self.sh_type(endian) != elf::SHT_STRTAB {
+ return Ok(None);
+ }
+ let str_offset = self.sh_offset(endian).into();
+ let str_size = self.sh_size(endian).into();
+ let str_end = str_offset
+ .checked_add(str_size)
+ .read_error("Invalid ELF string section offset or size")?;
+ Ok(Some(StringTable::new(data, str_offset, str_end)))
+ }
+
+ /// Return the symbols in the section.
+ ///
+ /// Also finds the linked string table in `sections`.
+ ///
+ /// `section_index` must be the 0-based index of this section, and is used
+ /// to find the corresponding extended section index table in `sections`.
+ ///
+ /// Returns `Ok(None)` if the section does not contain symbols.
+ /// Returns `Err` for invalid values.
+ fn symbols<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ sections: &SectionTable<'data, Self::Elf, R>,
+ section_index: SectionIndex,
+ ) -> read::Result<Option<SymbolTable<'data, Self::Elf, R>>> {
+ let sh_type = self.sh_type(endian);
+ if sh_type != elf::SHT_SYMTAB && sh_type != elf::SHT_DYNSYM {
+ return Ok(None);
+ }
+ SymbolTable::parse(endian, data, sections, section_index, self).map(Some)
+ }
+
+ /// Return the `Elf::Rel` entries in the section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if the section does not contain relocations.
+ /// Returns `Err` for invalid values.
+ fn rel<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [<Self::Elf as FileHeader>::Rel], SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_REL {
+ return Ok(None);
+ }
+ let rel = self
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF relocation section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((rel, link)))
+ }
+
+ /// Return the `Elf::Rela` entries in the section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if the section does not contain relocations.
+ /// Returns `Err` for invalid values.
+ fn rela<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [<Self::Elf as FileHeader>::Rela], SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_RELA {
+ return Ok(None);
+ }
+ let rela = self
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF relocation section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((rela, link)))
+ }
+
+ /// Return entries in a dynamic section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if the section type is not `SHT_DYNAMIC`.
+ /// Returns `Err` for invalid values.
+ fn dynamic<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [<Self::Elf as FileHeader>::Dyn], SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_DYNAMIC {
+ return Ok(None);
+ }
+ let dynamic = self
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF dynamic section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((dynamic, link)))
+ }
+
+ /// Return a note iterator for the section data.
+ ///
+ /// Returns `Ok(None)` if the section does not contain notes.
+ /// Returns `Err` for invalid values.
+ fn notes<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<NoteIterator<'data, Self::Elf>>> {
+ if self.sh_type(endian) != elf::SHT_NOTE {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF note section offset or size")?;
+ let notes = NoteIterator::new(endian, self.sh_addralign(endian), data)?;
+ Ok(Some(notes))
+ }
+
+ /// Return the contents of a group section.
+ ///
+ /// The first value is a `GRP_*` value, and the remaining values
+ /// are section indices.
+ ///
+ /// Returns `Ok(None)` if the section does not define a group.
+ /// Returns `Err` for invalid values.
+ fn group<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(u32, &'data [U32Bytes<Self::Endian>])>> {
+ if self.sh_type(endian) != elf::SHT_GROUP {
+ return Ok(None);
+ }
+ let mut data = self
+ .data(endian, data)
+ .read_error("Invalid ELF group section offset or size")
+ .map(Bytes)?;
+ let flag = data
+ .read::<U32Bytes<_>>()
+ .read_error("Invalid ELF group section offset or size")?
+ .get(endian);
+ let count = data.len() / mem::size_of::<U32Bytes<Self::Endian>>();
+ let sections = data
+ .read_slice(count)
+ .read_error("Invalid ELF group section offset or size")?;
+ Ok(Some((flag, sections)))
+ }
+
+ /// Return the header of a SysV hash section.
+ ///
+ /// Returns `Ok(None)` if the section does not contain a SysV hash.
+ /// Returns `Err` for invalid values.
+ fn hash_header<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<&'data elf::HashHeader<Self::Endian>>> {
+ if self.sh_type(endian) != elf::SHT_HASH {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF hash section offset or size")?;
+ let header = data
+ .read_at::<elf::HashHeader<Self::Endian>>(0)
+ .read_error("Invalid hash header")?;
+ Ok(Some(header))
+ }
+
+ /// Return the contents of a SysV hash section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if the section does not contain a SysV hash.
+ /// Returns `Err` for invalid values.
+ fn hash<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(HashTable<'data, Self::Elf>, SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_HASH {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF hash section offset or size")?;
+ let hash = HashTable::parse(endian, data)?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((hash, link)))
+ }
+
+ /// Return the header of a GNU hash section.
+ ///
+ /// Returns `Ok(None)` if the section does not contain a GNU hash.
+ /// Returns `Err` for invalid values.
+ fn gnu_hash_header<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<&'data elf::GnuHashHeader<Self::Endian>>> {
+ if self.sh_type(endian) != elf::SHT_GNU_HASH {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF GNU hash section offset or size")?;
+ let header = data
+ .read_at::<elf::GnuHashHeader<Self::Endian>>(0)
+ .read_error("Invalid GNU hash header")?;
+ Ok(Some(header))
+ }
+
+ /// Return the contents of a GNU hash section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if the section does not contain a GNU hash.
+ /// Returns `Err` for invalid values.
+ fn gnu_hash<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(GnuHashTable<'data, Self::Elf>, SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_GNU_HASH {
+ return Ok(None);
+ }
+ let data = self
+ .data(endian, data)
+ .read_error("Invalid ELF GNU hash section offset or size")?;
+ let hash = GnuHashTable::parse(endian, data)?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((hash, link)))
+ }
+
+ /// Return the contents of a `SHT_GNU_VERSYM` section.
+ ///
+ /// Also returns the linked symbol table index.
+ ///
+ /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERSYM`.
+ /// Returns `Err` for invalid values.
+ fn gnu_versym<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(&'data [elf::Versym<Self::Endian>], SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_GNU_VERSYM {
+ return Ok(None);
+ }
+ let versym = self
+ .data_as_array(endian, data)
+ .read_error("Invalid ELF GNU versym section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((versym, link)))
+ }
+
+ /// Return an iterator for the entries of a `SHT_GNU_VERDEF` section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERDEF`.
+ /// Returns `Err` for invalid values.
+ fn gnu_verdef<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(VerdefIterator<'data, Self::Elf>, SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_GNU_VERDEF {
+ return Ok(None);
+ }
+ let verdef = self
+ .data(endian, data)
+ .read_error("Invalid ELF GNU verdef section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((VerdefIterator::new(endian, verdef), link)))
+ }
+
+ /// Return an iterator for the entries of a `SHT_GNU_VERNEED` section.
+ ///
+ /// Also returns the linked string table index.
+ ///
+ /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERNEED`.
+ /// Returns `Err` for invalid values.
+ fn gnu_verneed<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<(VerneedIterator<'data, Self::Elf>, SectionIndex)>> {
+ if self.sh_type(endian) != elf::SHT_GNU_VERNEED {
+ return Ok(None);
+ }
+ let verneed = self
+ .data(endian, data)
+ .read_error("Invalid ELF GNU verneed section offset or size")?;
+ let link = SectionIndex(self.sh_link(endian) as usize);
+ Ok(Some((VerneedIterator::new(endian, verneed), link)))
+ }
+
+ /// Return the contents of a `SHT_GNU_ATTRIBUTES` section.
+ ///
+ /// Returns `Ok(None)` if the section type is not `SHT_GNU_ATTRIBUTES`.
+ /// Returns `Err` for invalid values.
+ fn gnu_attributes<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<Option<AttributesSection<'data, Self::Elf>>> {
+ if self.sh_type(endian) != elf::SHT_GNU_ATTRIBUTES {
+ return Ok(None);
+ }
+ self.attributes(endian, data).map(Some)
+ }
+
+ /// Parse the contents of the section as attributes.
+ ///
+ /// This function does not check whether section type corresponds
+ /// to a section that contains attributes.
+ ///
+ /// Returns `Err` for invalid values.
+ fn attributes<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<AttributesSection<'data, Self::Elf>> {
+ let data = self.data(endian, data)?;
+ AttributesSection::new(endian, data)
+ }
+
+ /// Parse the compression header if present.
+ ///
+ /// Returns the header, and the offset and size of the compressed section data
+ /// in the file.
+ ///
+ /// Returns `Ok(None)` if the section flags do not have `SHF_COMPRESSED`.
+ /// Returns `Err` for invalid values.
+ fn compression<'data, R: ReadRef<'data>>(
+ &self,
+ endian: Self::Endian,
+ data: R,
+ ) -> read::Result<
+ Option<(
+ &'data <Self::Elf as FileHeader>::CompressionHeader,
+ u64,
+ u64,
+ )>,
+ > {
+ if (self.sh_flags(endian).into() & u64::from(elf::SHF_COMPRESSED)) == 0 {
+ return Ok(None);
+ }
+ let (section_offset, section_size) = self
+ .file_range(endian)
+ .read_error("Invalid ELF compressed section type")?;
+ let mut offset = section_offset;
+ let header = data
+ .read::<<Self::Elf as FileHeader>::CompressionHeader>(&mut offset)
+ .read_error("Invalid ELF compressed section offset")?;
+ let compressed_size = section_size
+ .checked_sub(offset - section_offset)
+ .read_error("Invalid ELF compressed section size")?;
+ Ok(Some((header, offset, compressed_size)))
+ }
+}
+
+impl<Endian: endian::Endian> SectionHeader for elf::SectionHeader32<Endian> {
+ type Elf = elf::FileHeader32<Endian>;
+ type Word = u32;
+ type Endian = Endian;
+
+ #[inline]
+ fn sh_name(&self, endian: Self::Endian) -> u32 {
+ self.sh_name.get(endian)
+ }
+
+ #[inline]
+ fn sh_type(&self, endian: Self::Endian) -> u32 {
+ self.sh_type.get(endian)
+ }
+
+ #[inline]
+ fn sh_flags(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_flags.get(endian)
+ }
+
+ #[inline]
+ fn sh_addr(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_addr.get(endian)
+ }
+
+ #[inline]
+ fn sh_offset(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_offset.get(endian)
+ }
+
+ #[inline]
+ fn sh_size(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_size.get(endian)
+ }
+
+ #[inline]
+ fn sh_link(&self, endian: Self::Endian) -> u32 {
+ self.sh_link.get(endian)
+ }
+
+ #[inline]
+ fn sh_info(&self, endian: Self::Endian) -> u32 {
+ self.sh_info.get(endian)
+ }
+
+ #[inline]
+ fn sh_addralign(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_addralign.get(endian)
+ }
+
+ #[inline]
+ fn sh_entsize(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_entsize.get(endian)
+ }
+}
+
+impl<Endian: endian::Endian> SectionHeader for elf::SectionHeader64<Endian> {
+ type Word = u64;
+ type Endian = Endian;
+ type Elf = elf::FileHeader64<Endian>;
+
+ #[inline]
+ fn sh_name(&self, endian: Self::Endian) -> u32 {
+ self.sh_name.get(endian)
+ }
+
+ #[inline]
+ fn sh_type(&self, endian: Self::Endian) -> u32 {
+ self.sh_type.get(endian)
+ }
+
+ #[inline]
+ fn sh_flags(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_flags.get(endian)
+ }
+
+ #[inline]
+ fn sh_addr(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_addr.get(endian)
+ }
+
+ #[inline]
+ fn sh_offset(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_offset.get(endian)
+ }
+
+ #[inline]
+ fn sh_size(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_size.get(endian)
+ }
+
+ #[inline]
+ fn sh_link(&self, endian: Self::Endian) -> u32 {
+ self.sh_link.get(endian)
+ }
+
+ #[inline]
+ fn sh_info(&self, endian: Self::Endian) -> u32 {
+ self.sh_info.get(endian)
+ }
+
+ #[inline]
+ fn sh_addralign(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_addralign.get(endian)
+ }
+
+ #[inline]
+ fn sh_entsize(&self, endian: Self::Endian) -> Self::Word {
+ self.sh_entsize.get(endian)
+ }
+}