diff options
author | Valentin Popov <valentin@popov.link> | 2024-07-19 15:37:58 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2024-07-19 15:37:58 +0300 |
commit | a990de90fe41456a23e58bd087d2f107d321f3a1 (patch) | |
tree | 15afc392522a9e85dc3332235e311b7d39352ea9 /vendor/object/src/read/elf | |
parent | 3d48cd3f81164bbfc1a755dc1d4a9a02f98c8ddd (diff) | |
download | fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.tar.xz fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.zip |
Deleted vendor folder
Diffstat (limited to 'vendor/object/src/read/elf')
-rw-r--r-- | vendor/object/src/read/elf/attributes.rs | 307 | ||||
-rw-r--r-- | vendor/object/src/read/elf/comdat.rs | 162 | ||||
-rw-r--r-- | vendor/object/src/read/elf/compression.rs | 56 | ||||
-rw-r--r-- | vendor/object/src/read/elf/dynamic.rs | 117 | ||||
-rw-r--r-- | vendor/object/src/read/elf/file.rs | 916 | ||||
-rw-r--r-- | vendor/object/src/read/elf/hash.rs | 224 | ||||
-rw-r--r-- | vendor/object/src/read/elf/mod.rs | 78 | ||||
-rw-r--r-- | vendor/object/src/read/elf/note.rs | 271 | ||||
-rw-r--r-- | vendor/object/src/read/elf/relocation.rs | 628 | ||||
-rw-r--r-- | vendor/object/src/read/elf/section.rs | 1150 | ||||
-rw-r--r-- | vendor/object/src/read/elf/segment.rs | 334 | ||||
-rw-r--r-- | vendor/object/src/read/elf/symbol.rs | 595 | ||||
-rw-r--r-- | vendor/object/src/read/elf/version.rs | 424 |
13 files changed, 0 insertions, 5262 deletions
diff --git a/vendor/object/src/read/elf/attributes.rs b/vendor/object/src/read/elf/attributes.rs deleted file mode 100644 index bf6f35c..0000000 --- a/vendor/object/src/read/elf/attributes.rs +++ /dev/null @@ -1,307 +0,0 @@ -use core::convert::TryInto; - -use crate::elf; -use crate::endian; -use crate::read::{Bytes, Error, ReadError, Result}; - -use super::FileHeader; - -/// An ELF attributes section. -/// -/// This may be a GNU attributes section, or an architecture specific attributes section. -/// -/// An attributes section contains a series of [`AttributesSubsection`]. -/// -/// Returned by [`SectionHeader::attributes`](super::SectionHeader::attributes) -/// and [`SectionHeader::gnu_attributes`](super::SectionHeader::gnu_attributes). -#[derive(Debug, Clone)] -pub struct AttributesSection<'data, Elf: FileHeader> { - endian: Elf::Endian, - version: u8, - data: Bytes<'data>, -} - -impl<'data, Elf: FileHeader> AttributesSection<'data, Elf> { - /// Parse an ELF attributes section given the section data. - pub fn new(endian: Elf::Endian, data: &'data [u8]) -> Result<Self> { - let mut data = Bytes(data); - - // Skip the version field that is one byte long. - let version = *data - .read::<u8>() - .read_error("Invalid ELF attributes section offset or size")?; - - Ok(AttributesSection { - endian, - version, - data, - }) - } - - /// Return the version of the attributes section. - pub fn version(&self) -> u8 { - self.version - } - - /// Return an iterator over the subsections. - pub fn subsections(&self) -> Result<AttributesSubsectionIterator<'data, Elf>> { - // There is currently only one format version. - if self.version != b'A' { - return Err(Error("Unsupported ELF attributes section version")); - } - - Ok(AttributesSubsectionIterator { - endian: self.endian, - data: self.data, - }) - } -} - -/// An iterator for the subsections in an [`AttributesSection`]. -#[derive(Debug, Clone)] -pub struct AttributesSubsectionIterator<'data, Elf: FileHeader> { - endian: Elf::Endian, - data: Bytes<'data>, -} - -impl<'data, Elf: FileHeader> AttributesSubsectionIterator<'data, Elf> { - /// Return the next subsection. - pub fn next(&mut self) -> Result<Option<AttributesSubsection<'data, Elf>>> { - if self.data.is_empty() { - return Ok(None); - } - - let result = self.parse(); - if result.is_err() { - self.data = Bytes(&[]); - } - result - } - - fn parse(&mut self) -> Result<Option<AttributesSubsection<'data, Elf>>> { - // First read the subsection length. - let mut data = self.data; - let length = data - .read::<endian::U32Bytes<Elf::Endian>>() - .read_error("ELF attributes section is too short")? - .get(self.endian); - - // Now read the entire subsection, updating self.data. - let mut data = self - .data - .read_bytes(length as usize) - .read_error("Invalid ELF attributes subsection length")?; - // Skip the subsection length field. - data.skip(4) - .read_error("Invalid ELF attributes subsection length")?; - - let vendor = data - .read_string() - .read_error("Invalid ELF attributes vendor")?; - - Ok(Some(AttributesSubsection { - endian: self.endian, - length, - vendor, - data, - })) - } -} - -/// A subsection in an [`AttributesSection`]. -/// -/// A subsection is identified by a vendor name. It contains a series of -/// [`AttributesSubsubsection`]. -#[derive(Debug, Clone)] -pub struct AttributesSubsection<'data, Elf: FileHeader> { - endian: Elf::Endian, - length: u32, - vendor: &'data [u8], - data: Bytes<'data>, -} - -impl<'data, Elf: FileHeader> AttributesSubsection<'data, Elf> { - /// Return the length of the attributes subsection. - pub fn length(&self) -> u32 { - self.length - } - - /// Return the vendor name of the attributes subsection. - pub fn vendor(&self) -> &'data [u8] { - self.vendor - } - - /// Return an iterator over the sub-subsections. - pub fn subsubsections(&self) -> AttributesSubsubsectionIterator<'data, Elf> { - AttributesSubsubsectionIterator { - endian: self.endian, - data: self.data, - } - } -} - -/// An iterator for the sub-subsections in an [`AttributesSubsection`]. -#[derive(Debug, Clone)] -pub struct AttributesSubsubsectionIterator<'data, Elf: FileHeader> { - endian: Elf::Endian, - data: Bytes<'data>, -} - -impl<'data, Elf: FileHeader> AttributesSubsubsectionIterator<'data, Elf> { - /// Return the next sub-subsection. - pub fn next(&mut self) -> Result<Option<AttributesSubsubsection<'data>>> { - if self.data.is_empty() { - return Ok(None); - } - - let result = self.parse(); - if result.is_err() { - self.data = Bytes(&[]); - } - result - } - - fn parse(&mut self) -> Result<Option<AttributesSubsubsection<'data>>> { - // The format of a sub-section looks like this: - // - // <file-tag> <size> <attribute>* - // | <section-tag> <size> <section-number>* 0 <attribute>* - // | <symbol-tag> <size> <symbol-number>* 0 <attribute>* - let mut data = self.data; - let tag = *data - .read::<u8>() - .read_error("ELF attributes subsection is too short")?; - let length = data - .read::<endian::U32Bytes<Elf::Endian>>() - .read_error("ELF attributes subsection is too short")? - .get(self.endian); - - // Now read the entire sub-subsection, updating self.data. - let mut data = self - .data - .read_bytes(length as usize) - .read_error("Invalid ELF attributes sub-subsection length")?; - // Skip the tag and sub-subsection size field. - data.skip(1 + 4) - .read_error("Invalid ELF attributes sub-subsection length")?; - - let indices = if tag == elf::Tag_Section || tag == elf::Tag_Symbol { - data.read_string() - .map(Bytes) - .read_error("Missing ELF attributes sub-subsection indices")? - } else if tag == elf::Tag_File { - Bytes(&[]) - } else { - return Err(Error("Unimplemented ELF attributes sub-subsection tag")); - }; - - Ok(Some(AttributesSubsubsection { - tag, - length, - indices, - data, - })) - } -} - -/// A sub-subsection in an [`AttributesSubsection`]. -/// -/// A sub-subsection is identified by a tag. It contains an optional series of indices, -/// followed by a series of attributes. -#[derive(Debug, Clone)] -pub struct AttributesSubsubsection<'data> { - tag: u8, - length: u32, - indices: Bytes<'data>, - data: Bytes<'data>, -} - -impl<'data> AttributesSubsubsection<'data> { - /// Return the tag of the attributes sub-subsection. - pub fn tag(&self) -> u8 { - self.tag - } - - /// Return the length of the attributes sub-subsection. - pub fn length(&self) -> u32 { - self.length - } - - /// Return the data containing the indices. - pub fn indices_data(&self) -> &'data [u8] { - self.indices.0 - } - - /// Return the indices. - /// - /// This will be section indices if the tag is `Tag_Section`, - /// or symbol indices if the tag is `Tag_Symbol`, - /// and otherwise it will be empty. - pub fn indices(&self) -> AttributeIndexIterator<'data> { - AttributeIndexIterator { data: self.indices } - } - - /// Return the data containing the attributes. - pub fn attributes_data(&self) -> &'data [u8] { - self.data.0 - } - - /// Return a parser for the data containing the attributes. - pub fn attributes(&self) -> AttributeReader<'data> { - AttributeReader { data: self.data } - } -} - -/// An iterator over the indices in an [`AttributesSubsubsection`]. -#[derive(Debug, Clone)] -pub struct AttributeIndexIterator<'data> { - data: Bytes<'data>, -} - -impl<'data> AttributeIndexIterator<'data> { - /// Parse the next index. - pub fn next(&mut self) -> Result<Option<u32>> { - if self.data.is_empty() { - return Ok(None); - } - let err = "Invalid ELF attribute index"; - self.data - .read_uleb128() - .read_error(err)? - .try_into() - .map_err(|_| ()) - .read_error(err) - .map(Some) - } -} - -/// A parser for the attributes in an [`AttributesSubsubsection`]. -/// -/// The parser relies on the caller to know the format of the data for each attribute tag. -#[derive(Debug, Clone)] -pub struct AttributeReader<'data> { - data: Bytes<'data>, -} - -impl<'data> AttributeReader<'data> { - /// Parse a tag. - pub fn read_tag(&mut self) -> Result<Option<u64>> { - if self.data.is_empty() { - return Ok(None); - } - let err = "Invalid ELF attribute tag"; - self.data.read_uleb128().read_error(err).map(Some) - } - - /// Parse an integer value. - pub fn read_integer(&mut self) -> Result<u64> { - let err = "Invalid ELF attribute integer value"; - self.data.read_uleb128().read_error(err) - } - - /// Parse a string value. - pub fn read_string(&mut self) -> Result<&'data [u8]> { - let err = "Invalid ELF attribute string value"; - self.data.read_string().read_error(err) - } -} diff --git a/vendor/object/src/read/elf/comdat.rs b/vendor/object/src/read/elf/comdat.rs deleted file mode 100644 index 882d253..0000000 --- a/vendor/object/src/read/elf/comdat.rs +++ /dev/null @@ -1,162 +0,0 @@ -use core::fmt::Debug; -use core::{iter, slice, str}; - -use crate::elf; -use crate::endian::{Endianness, U32Bytes}; -use crate::read::{self, ComdatKind, ObjectComdat, ReadError, ReadRef, SectionIndex, SymbolIndex}; - -use super::{ElfFile, FileHeader, SectionHeader, Sym}; - -/// An iterator for the COMDAT section groups in an [`ElfFile32`](super::ElfFile32). -pub type ElfComdatIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfComdatIterator<'data, 'file, elf::FileHeader32<Endian>, R>; -/// An iterator for the COMDAT section groups in an [`ElfFile64`](super::ElfFile64). -pub type ElfComdatIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfComdatIterator<'data, 'file, elf::FileHeader64<Endian>, R>; - -/// An iterator for the COMDAT section groups in an [`ElfFile`]. -#[derive(Debug)] -pub struct ElfComdatIterator<'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 ElfComdatIterator<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - type Item = ElfComdat<'data, 'file, Elf, R>; - - fn next(&mut self) -> Option<Self::Item> { - for (_index, section) in self.iter.by_ref() { - if let Some(comdat) = ElfComdat::parse(self.file, section) { - return Some(comdat); - } - } - None - } -} - -/// A COMDAT section group in an [`ElfFile32`](super::ElfFile32). -pub type ElfComdat32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfComdat<'data, 'file, elf::FileHeader32<Endian>, R>; -/// A COMDAT section group in an [`ElfFile64`](super::ElfFile64). -pub type ElfComdat64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfComdat<'data, 'file, elf::FileHeader64<Endian>, R>; - -/// A COMDAT section group in an [`ElfFile`]. -/// -/// Most functionality is provided by the [`ObjectComdat`] trait implementation. -#[derive(Debug)] -pub struct ElfComdat<'data, 'file, Elf, R = &'data [u8]> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - file: &'file ElfFile<'data, Elf, R>, - section: &'data Elf::SectionHeader, - sections: &'data [U32Bytes<Elf::Endian>], -} - -impl<'data, 'file, Elf, R> ElfComdat<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - fn parse( - file: &'file ElfFile<'data, Elf, R>, - section: &'data Elf::SectionHeader, - ) -> Option<ElfComdat<'data, 'file, Elf, R>> { - let (flag, sections) = section.group(file.endian, file.data).ok()??; - if flag != elf::GRP_COMDAT { - return None; - } - Some(ElfComdat { - file, - section, - sections, - }) - } -} - -impl<'data, 'file, Elf, R> read::private::Sealed for ElfComdat<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Elf, R> ObjectComdat<'data> for ElfComdat<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - type SectionIterator = ElfComdatSectionIterator<'data, 'file, Elf, R>; - - #[inline] - fn kind(&self) -> ComdatKind { - ComdatKind::Any - } - - #[inline] - fn symbol(&self) -> SymbolIndex { - SymbolIndex(self.section.sh_info(self.file.endian) as usize) - } - - fn name_bytes(&self) -> read::Result<&[u8]> { - // FIXME: check sh_link - let index = self.section.sh_info(self.file.endian) as usize; - let symbol = self.file.symbols.symbol(index)?; - symbol.name(self.file.endian, self.file.symbols.strings()) - } - - fn name(&self) -> read::Result<&str> { - let name = self.name_bytes()?; - str::from_utf8(name) - .ok() - .read_error("Non UTF-8 ELF COMDAT name") - } - - fn sections(&self) -> Self::SectionIterator { - ElfComdatSectionIterator { - file: self.file, - sections: self.sections.iter(), - } - } -} - -/// An iterator for the sections in a COMDAT section group in an [`ElfFile32`](super::ElfFile32). -pub type ElfComdatSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfComdatSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>; -/// An iterator for the sections in a COMDAT section group in an [`ElfFile64`](super::ElfFile64). -pub type ElfComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfComdatSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>; - -/// An iterator for the sections in a COMDAT section group in an [`ElfFile`]. -#[derive(Debug)] -pub struct ElfComdatSectionIterator<'data, 'file, Elf, R = &'data [u8]> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - file: &'file ElfFile<'data, Elf, R>, - sections: slice::Iter<'data, U32Bytes<Elf::Endian>>, -} - -impl<'data, 'file, Elf, R> Iterator for ElfComdatSectionIterator<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - type Item = SectionIndex; - - fn next(&mut self) -> Option<Self::Item> { - let index = self.sections.next()?; - Some(SectionIndex(index.get(self.file.endian) as usize)) - } -} diff --git a/vendor/object/src/read/elf/compression.rs b/vendor/object/src/read/elf/compression.rs deleted file mode 100644 index de2533f..0000000 --- a/vendor/object/src/read/elf/compression.rs +++ /dev/null @@ -1,56 +0,0 @@ -use core::fmt::Debug; - -use crate::elf; -use crate::endian; -use crate::pod::Pod; - -/// A trait for generic access to [`elf::CompressionHeader32`] and [`elf::CompressionHeader64`]. -#[allow(missing_docs)] -pub trait CompressionHeader: Debug + Pod { - type Word: Into<u64>; - type Endian: endian::Endian; - - fn ch_type(&self, endian: Self::Endian) -> u32; - fn ch_size(&self, endian: Self::Endian) -> Self::Word; - fn ch_addralign(&self, endian: Self::Endian) -> Self::Word; -} - -impl<Endian: endian::Endian> CompressionHeader for elf::CompressionHeader32<Endian> { - type Word = u32; - type Endian = Endian; - - #[inline] - fn ch_type(&self, endian: Self::Endian) -> u32 { - self.ch_type.get(endian) - } - - #[inline] - fn ch_size(&self, endian: Self::Endian) -> Self::Word { - self.ch_size.get(endian) - } - - #[inline] - fn ch_addralign(&self, endian: Self::Endian) -> Self::Word { - self.ch_addralign.get(endian) - } -} - -impl<Endian: endian::Endian> CompressionHeader for elf::CompressionHeader64<Endian> { - type Word = u64; - type Endian = Endian; - - #[inline] - fn ch_type(&self, endian: Self::Endian) -> u32 { - self.ch_type.get(endian) - } - - #[inline] - fn ch_size(&self, endian: Self::Endian) -> Self::Word { - self.ch_size.get(endian) - } - - #[inline] - fn ch_addralign(&self, endian: Self::Endian) -> Self::Word { - self.ch_addralign.get(endian) - } -} diff --git a/vendor/object/src/read/elf/dynamic.rs b/vendor/object/src/read/elf/dynamic.rs deleted file mode 100644 index 1661434..0000000 --- a/vendor/object/src/read/elf/dynamic.rs +++ /dev/null @@ -1,117 +0,0 @@ -use core::convert::TryInto; -use core::fmt::Debug; - -use crate::elf; -use crate::endian; -use crate::pod::Pod; -use crate::read::{ReadError, Result, StringTable}; - -/// A trait for generic access to [`elf::Dyn32`] and [`elf::Dyn64`]. -#[allow(missing_docs)] -pub trait Dyn: Debug + Pod { - type Word: Into<u64>; - type Endian: endian::Endian; - - fn d_tag(&self, endian: Self::Endian) -> Self::Word; - fn d_val(&self, endian: Self::Endian) -> Self::Word; - - /// Try to convert the tag to a `u32`. - fn tag32(&self, endian: Self::Endian) -> Option<u32> { - self.d_tag(endian).into().try_into().ok() - } - - /// Try to convert the value to a `u32`. - fn val32(&self, endian: Self::Endian) -> Option<u32> { - self.d_val(endian).into().try_into().ok() - } - - /// Return true if the value is an offset in the dynamic string table. - fn is_string(&self, endian: Self::Endian) -> bool { - if let Some(tag) = self.tag32(endian) { - match tag { - elf::DT_NEEDED - | elf::DT_SONAME - | elf::DT_RPATH - | elf::DT_RUNPATH - | elf::DT_AUXILIARY - | elf::DT_FILTER => true, - _ => false, - } - } else { - false - } - } - - /// Use the value to get a string in a string table. - /// - /// Does not check for an appropriate tag. - fn string<'data>( - &self, - endian: Self::Endian, - strings: StringTable<'data>, - ) -> Result<&'data [u8]> { - self.val32(endian) - .and_then(|val| strings.get(val).ok()) - .read_error("Invalid ELF dyn string") - } - - /// Return true if the value is an address. - fn is_address(&self, endian: Self::Endian) -> bool { - if let Some(tag) = self.tag32(endian) { - match tag { - elf::DT_PLTGOT - | elf::DT_HASH - | elf::DT_STRTAB - | elf::DT_SYMTAB - | elf::DT_RELA - | elf::DT_INIT - | elf::DT_FINI - | elf::DT_SYMBOLIC - | elf::DT_REL - | elf::DT_DEBUG - | elf::DT_JMPREL - | elf::DT_FINI_ARRAY - | elf::DT_INIT_ARRAY - | elf::DT_PREINIT_ARRAY - | elf::DT_SYMTAB_SHNDX - | elf::DT_VERDEF - | elf::DT_VERNEED - | elf::DT_VERSYM - | elf::DT_ADDRRNGLO..=elf::DT_ADDRRNGHI => true, - _ => false, - } - } else { - false - } - } -} - -impl<Endian: endian::Endian> Dyn for elf::Dyn32<Endian> { - type Word = u32; - type Endian = Endian; - - #[inline] - fn d_tag(&self, endian: Self::Endian) -> Self::Word { - self.d_tag.get(endian) - } - - #[inline] - fn d_val(&self, endian: Self::Endian) -> Self::Word { - self.d_val.get(endian) - } -} - -impl<Endian: endian::Endian> Dyn for elf::Dyn64<Endian> { - type Word = u64; - type Endian = Endian; - - #[inline] - fn d_tag(&self, endian: Self::Endian) -> Self::Word { - self.d_tag.get(endian) - } - - #[inline] - fn d_val(&self, endian: Self::Endian) -> Self::Word { - self.d_val.get(endian) - } -} diff --git a/vendor/object/src/read/elf/file.rs b/vendor/object/src/read/elf/file.rs deleted file mode 100644 index 14ba568..0000000 --- a/vendor/object/src/read/elf/file.rs +++ /dev/null @@ -1,916 +0,0 @@ -use alloc::vec::Vec; -use core::convert::TryInto; -use core::fmt::Debug; -use core::mem; - -use crate::read::{ - self, util, Architecture, ByteString, Bytes, Error, Export, FileFlags, Import, Object, - ObjectKind, ReadError, ReadRef, SectionIndex, StringTable, SymbolIndex, -}; -use crate::{elf, endian, Endian, Endianness, Pod, U32}; - -use super::{ - CompressionHeader, Dyn, ElfComdat, ElfComdatIterator, ElfDynamicRelocationIterator, ElfSection, - ElfSectionIterator, ElfSegment, ElfSegmentIterator, ElfSymbol, ElfSymbolIterator, - ElfSymbolTable, NoteHeader, ProgramHeader, Rel, Rela, RelocationSections, SectionHeader, - SectionTable, Sym, SymbolTable, -}; - -/// A 32-bit ELF object file. -/// -/// This is a file that starts with [`elf::FileHeader32`], and corresponds -/// to [`crate::FileKind::Elf32`]. -pub type ElfFile32<'data, Endian = Endianness, R = &'data [u8]> = - ElfFile<'data, elf::FileHeader32<Endian>, R>; -/// A 64-bit ELF object file. -/// -/// This is a file that starts with [`elf::FileHeader64`], and corresponds -/// to [`crate::FileKind::Elf64`]. -pub type ElfFile64<'data, Endian = Endianness, R = &'data [u8]> = - ElfFile<'data, elf::FileHeader64<Endian>, R>; - -/// A partially parsed ELF file. -/// -/// Most functionality is provided by the [`Object`] trait implementation. -#[derive(Debug)] -pub struct ElfFile<'data, Elf, R = &'data [u8]> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - pub(super) endian: Elf::Endian, - pub(super) data: R, - pub(super) header: &'data Elf, - pub(super) segments: &'data [Elf::ProgramHeader], - pub(super) sections: SectionTable<'data, Elf, R>, - pub(super) relocations: RelocationSections, - pub(super) symbols: SymbolTable<'data, Elf, R>, - pub(super) dynamic_symbols: SymbolTable<'data, Elf, R>, -} - -impl<'data, Elf, R> ElfFile<'data, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - /// Parse the raw ELF file data. - pub fn parse(data: R) -> read::Result<Self> { - let header = Elf::parse(data)?; - let endian = header.endian()?; - let segments = header.program_headers(endian, data)?; - let sections = header.sections(endian, data)?; - let symbols = sections.symbols(endian, data, elf::SHT_SYMTAB)?; - // TODO: get dynamic symbols from DT_SYMTAB if there are no sections - let dynamic_symbols = sections.symbols(endian, data, elf::SHT_DYNSYM)?; - // The API we provide requires a mapping from section to relocations, so build it now. - let relocations = sections.relocation_sections(endian, symbols.section())?; - - Ok(ElfFile { - endian, - data, - header, - segments, - sections, - relocations, - symbols, - dynamic_symbols, - }) - } - - /// Returns the endianness. - pub fn endian(&self) -> Elf::Endian { - self.endian - } - - /// Returns the raw data. - pub fn data(&self) -> R { - self.data - } - - /// Returns the raw ELF file header. - pub fn raw_header(&self) -> &'data Elf { - self.header - } - - /// Returns the raw ELF segments. - pub fn raw_segments(&self) -> &'data [Elf::ProgramHeader] { - self.segments - } - - fn raw_section_by_name<'file>( - &'file self, - section_name: &[u8], - ) -> Option<ElfSection<'data, 'file, Elf, R>> { - self.sections - .section_by_name(self.endian, section_name) - .map(|(index, section)| ElfSection { - file: self, - index: SectionIndex(index), - section, - }) - } - - #[cfg(feature = "compression")] - fn zdebug_section_by_name<'file>( - &'file self, - section_name: &[u8], - ) -> Option<ElfSection<'data, 'file, Elf, R>> { - if !section_name.starts_with(b".debug_") { - return None; - } - let mut name = Vec::with_capacity(section_name.len() + 1); - name.extend_from_slice(b".zdebug_"); - name.extend_from_slice(§ion_name[7..]); - self.raw_section_by_name(&name) - } - - #[cfg(not(feature = "compression"))] - fn zdebug_section_by_name<'file>( - &'file self, - _section_name: &[u8], - ) -> Option<ElfSection<'data, 'file, Elf, R>> { - None - } -} - -impl<'data, Elf, R> read::private::Sealed for ElfFile<'data, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Elf, R> Object<'data, 'file> for ElfFile<'data, Elf, R> -where - 'data: 'file, - Elf: FileHeader, - R: 'file + ReadRef<'data>, -{ - type Segment = ElfSegment<'data, 'file, Elf, R>; - type SegmentIterator = ElfSegmentIterator<'data, 'file, Elf, R>; - type Section = ElfSection<'data, 'file, Elf, R>; - type SectionIterator = ElfSectionIterator<'data, 'file, Elf, R>; - type Comdat = ElfComdat<'data, 'file, Elf, R>; - type ComdatIterator = ElfComdatIterator<'data, 'file, Elf, R>; - type Symbol = ElfSymbol<'data, 'file, Elf, R>; - type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf, R>; - type SymbolTable = ElfSymbolTable<'data, 'file, Elf, R>; - type DynamicRelocationIterator = ElfDynamicRelocationIterator<'data, 'file, Elf, R>; - - fn architecture(&self) -> Architecture { - match ( - self.header.e_machine(self.endian), - self.header.is_class_64(), - ) { - (elf::EM_AARCH64, true) => Architecture::Aarch64, - (elf::EM_AARCH64, false) => Architecture::Aarch64_Ilp32, - (elf::EM_ARM, _) => Architecture::Arm, - (elf::EM_AVR, _) => Architecture::Avr, - (elf::EM_BPF, _) => Architecture::Bpf, - (elf::EM_CSKY, _) => Architecture::Csky, - (elf::EM_386, _) => Architecture::I386, - (elf::EM_X86_64, false) => Architecture::X86_64_X32, - (elf::EM_X86_64, true) => Architecture::X86_64, - (elf::EM_HEXAGON, _) => Architecture::Hexagon, - (elf::EM_LOONGARCH, true) => Architecture::LoongArch64, - (elf::EM_MIPS, false) => Architecture::Mips, - (elf::EM_MIPS, true) => Architecture::Mips64, - (elf::EM_MSP430, _) => Architecture::Msp430, - (elf::EM_PPC, _) => Architecture::PowerPc, - (elf::EM_PPC64, _) => Architecture::PowerPc64, - (elf::EM_RISCV, false) => Architecture::Riscv32, - (elf::EM_RISCV, true) => Architecture::Riscv64, - // This is either s390 or s390x, depending on the ELF class. - // We only support the 64-bit variant s390x here. - (elf::EM_S390, true) => Architecture::S390x, - (elf::EM_SBF, _) => Architecture::Sbf, - (elf::EM_SHARC, false) => Architecture::Sharc, - (elf::EM_SPARCV9, true) => Architecture::Sparc64, - (elf::EM_XTENSA, false) => Architecture::Xtensa, - _ => Architecture::Unknown, - } - } - - #[inline] - fn is_little_endian(&self) -> bool { - self.header.is_little_endian() - } - - #[inline] - fn is_64(&self) -> bool { - self.header.is_class_64() - } - - fn kind(&self) -> ObjectKind { - match self.header.e_type(self.endian) { - elf::ET_REL => ObjectKind::Relocatable, - elf::ET_EXEC => ObjectKind::Executable, - // TODO: check for `DF_1_PIE`? - elf::ET_DYN => ObjectKind::Dynamic, - elf::ET_CORE => ObjectKind::Core, - _ => ObjectKind::Unknown, - } - } - - fn segments(&'file self) -> ElfSegmentIterator<'data, 'file, Elf, R> { - ElfSegmentIterator { - file: self, - iter: self.segments.iter(), - } - } - - fn section_by_name_bytes( - &'file self, - section_name: &[u8], - ) -> Option<ElfSection<'data, 'file, Elf, R>> { - self.raw_section_by_name(section_name) - .or_else(|| self.zdebug_section_by_name(section_name)) - } - - fn section_by_index( - &'file self, - index: SectionIndex, - ) -> read::Result<ElfSection<'data, 'file, Elf, R>> { - let section = self.sections.section(index)?; - Ok(ElfSection { - file: self, - index, - section, - }) - } - - fn sections(&'file self) -> ElfSectionIterator<'data, 'file, Elf, R> { - ElfSectionIterator { - file: self, - iter: self.sections.iter().enumerate(), - } - } - - fn comdats(&'file self) -> ElfComdatIterator<'data, 'file, Elf, R> { - ElfComdatIterator { - file: self, - iter: self.sections.iter().enumerate(), - } - } - - fn symbol_by_index( - &'file self, - index: SymbolIndex, - ) -> read::Result<ElfSymbol<'data, 'file, Elf, R>> { - let symbol = self.symbols.symbol(index.0)?; - Ok(ElfSymbol { - endian: self.endian, - symbols: &self.symbols, - index, - symbol, - }) - } - - fn symbols(&'file self) -> ElfSymbolIterator<'data, 'file, Elf, R> { - ElfSymbolIterator { - endian: self.endian, - symbols: &self.symbols, - index: 0, - } - } - - fn symbol_table(&'file self) -> Option<ElfSymbolTable<'data, 'file, Elf, R>> { - if self.symbols.is_empty() { - return None; - } - Some(ElfSymbolTable { - endian: self.endian, - symbols: &self.symbols, - }) - } - - fn dynamic_symbols(&'file self) -> ElfSymbolIterator<'data, 'file, Elf, R> { - ElfSymbolIterator { - endian: self.endian, - symbols: &self.dynamic_symbols, - index: 0, - } - } - - fn dynamic_symbol_table(&'file self) -> Option<ElfSymbolTable<'data, 'file, Elf, R>> { - if self.dynamic_symbols.is_empty() { - return None; - } - Some(ElfSymbolTable { - endian: self.endian, - symbols: &self.dynamic_symbols, - }) - } - - fn dynamic_relocations( - &'file self, - ) -> Option<ElfDynamicRelocationIterator<'data, 'file, Elf, R>> { - Some(ElfDynamicRelocationIterator { - section_index: SectionIndex(1), - file: self, - relocations: None, - }) - } - - fn imports(&self) -> read::Result<Vec<Import<'data>>> { - let mut imports = Vec::new(); - for symbol in self.dynamic_symbols.iter() { - if symbol.is_undefined(self.endian) { - let name = symbol.name(self.endian, self.dynamic_symbols.strings())?; - if !name.is_empty() { - // TODO: use symbol versioning to determine library - imports.push(Import { - name: ByteString(name), - library: ByteString(&[]), - }); - } - } - } - Ok(imports) - } - - fn exports(&self) -> read::Result<Vec<Export<'data>>> { - let mut exports = Vec::new(); - for symbol in self.dynamic_symbols.iter() { - if symbol.is_definition(self.endian) { - let name = symbol.name(self.endian, self.dynamic_symbols.strings())?; - let address = symbol.st_value(self.endian).into(); - exports.push(Export { - name: ByteString(name), - address, - }); - } - } - Ok(exports) - } - - fn has_debug_symbols(&self) -> bool { - for section in self.sections.iter() { - if let Ok(name) = self.sections.section_name(self.endian, section) { - if name == b".debug_info" || name == b".zdebug_info" { - return true; - } - } - } - false - } - - fn build_id(&self) -> read::Result<Option<&'data [u8]>> { - let endian = self.endian; - // Use section headers if present, otherwise use program headers. - if !self.sections.is_empty() { - for section in self.sections.iter() { - if let Some(mut notes) = section.notes(endian, self.data)? { - while let Some(note) = notes.next()? { - if note.name() == elf::ELF_NOTE_GNU - && note.n_type(endian) == elf::NT_GNU_BUILD_ID - { - return Ok(Some(note.desc())); - } - } - } - } - } else { - for segment in self.segments { - if let Some(mut notes) = segment.notes(endian, self.data)? { - while let Some(note) = notes.next()? { - if note.name() == elf::ELF_NOTE_GNU - && note.n_type(endian) == elf::NT_GNU_BUILD_ID - { - return Ok(Some(note.desc())); - } - } - } - } - } - Ok(None) - } - - fn gnu_debuglink(&self) -> read::Result<Option<(&'data [u8], u32)>> { - let section = match self.raw_section_by_name(b".gnu_debuglink") { - Some(section) => section, - None => return Ok(None), - }; - let data = section - .section - .data(self.endian, self.data) - .read_error("Invalid ELF .gnu_debuglink section offset or size") - .map(Bytes)?; - let filename = data - .read_string_at(0) - .read_error("Missing ELF .gnu_debuglink filename")?; - let crc_offset = util::align(filename.len() + 1, 4); - let crc = data - .read_at::<U32<_>>(crc_offset) - .read_error("Missing ELF .gnu_debuglink crc")? - .get(self.endian); - Ok(Some((filename, crc))) - } - - fn gnu_debugaltlink(&self) -> read::Result<Option<(&'data [u8], &'data [u8])>> { - let section = match self.raw_section_by_name(b".gnu_debugaltlink") { - Some(section) => section, - None => return Ok(None), - }; - let mut data = section - .section - .data(self.endian, self.data) - .read_error("Invalid ELF .gnu_debugaltlink section offset or size") - .map(Bytes)?; - let filename = data - .read_string() - .read_error("Missing ELF .gnu_debugaltlink filename")?; - let build_id = data.0; - Ok(Some((filename, build_id))) - } - - fn relative_address_base(&self) -> u64 { - 0 - } - - fn entry(&self) -> u64 { - self.header.e_entry(self.endian).into() - } - - fn flags(&self) -> FileFlags { - FileFlags::Elf { - os_abi: self.header.e_ident().os_abi, - abi_version: self.header.e_ident().abi_version, - e_flags: self.header.e_flags(self.endian), - } - } -} - -/// A trait for generic access to [`elf::FileHeader32`] and [`elf::FileHeader64`]. -#[allow(missing_docs)] -pub trait FileHeader: Debug + Pod { - // Ideally this would be a `u64: From<Word>`, but can't express that. - type Word: Into<u64>; - type Sword: Into<i64>; - type Endian: endian::Endian; - type ProgramHeader: ProgramHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>; - type SectionHeader: SectionHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>; - type CompressionHeader: CompressionHeader<Endian = Self::Endian, Word = Self::Word>; - type NoteHeader: NoteHeader<Endian = Self::Endian>; - type Dyn: Dyn<Endian = Self::Endian, Word = Self::Word>; - type Sym: Sym<Endian = Self::Endian, Word = Self::Word>; - type Rel: Rel<Endian = Self::Endian, Word = Self::Word>; - type Rela: Rela<Endian = Self::Endian, Word = Self::Word> + From<Self::Rel>; - - /// Return true if this type is a 64-bit header. - /// - /// This is a property of the type, not a value in the header data. - fn is_type_64(&self) -> bool; - - /// Return true if this type is a 64-bit header. - /// - /// This is a property of the type, not a value in the header data. - /// - /// This is the same as [`Self::is_type_64`], but is non-dispatchable. - fn is_type_64_sized() -> bool - where - Self: Sized; - - fn e_ident(&self) -> &elf::Ident; - fn e_type(&self, endian: Self::Endian) -> u16; - fn e_machine(&self, endian: Self::Endian) -> u16; - fn e_version(&self, endian: Self::Endian) -> u32; - fn e_entry(&self, endian: Self::Endian) -> Self::Word; - fn e_phoff(&self, endian: Self::Endian) -> Self::Word; - fn e_shoff(&self, endian: Self::Endian) -> Self::Word; - fn e_flags(&self, endian: Self::Endian) -> u32; - fn e_ehsize(&self, endian: Self::Endian) -> u16; - fn e_phentsize(&self, endian: Self::Endian) -> u16; - fn e_phnum(&self, endian: Self::Endian) -> u16; - fn e_shentsize(&self, endian: Self::Endian) -> u16; - fn e_shnum(&self, endian: Self::Endian) -> u16; - fn e_shstrndx(&self, endian: Self::Endian) -> u16; - - // Provided methods. - - /// Read the file header. - /// - /// Also checks that the ident field in the file header is a supported format. - fn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> { - let header = data - .read_at::<Self>(0) - .read_error("Invalid ELF header size or alignment")?; - if !header.is_supported() { - return Err(Error("Unsupported ELF header")); - } - // TODO: Check self.e_ehsize? - Ok(header) - } - - /// Check that the ident field in the file header is a supported format. - /// - /// This checks the magic number, version, class, and endianness. - fn is_supported(&self) -> bool { - let ident = self.e_ident(); - // TODO: Check self.e_version too? Requires endian though. - ident.magic == elf::ELFMAG - && (self.is_type_64() || self.is_class_32()) - && (!self.is_type_64() || self.is_class_64()) - && (self.is_little_endian() || self.is_big_endian()) - && ident.version == elf::EV_CURRENT - } - - fn is_class_32(&self) -> bool { - self.e_ident().class == elf::ELFCLASS32 - } - - fn is_class_64(&self) -> bool { - self.e_ident().class == elf::ELFCLASS64 - } - - fn is_little_endian(&self) -> bool { - self.e_ident().data == elf::ELFDATA2LSB - } - - fn is_big_endian(&self) -> bool { - self.e_ident().data == elf::ELFDATA2MSB - } - - fn endian(&self) -> read::Result<Self::Endian> { - Self::Endian::from_big_endian(self.is_big_endian()).read_error("Unsupported ELF endian") - } - - /// Return the first section header, if present. - /// - /// Section 0 is a special case because getting the section headers normally - /// requires `shnum`, but `shnum` may be in the first section header. - fn section_0<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> read::Result<Option<&'data Self::SectionHeader>> { - let shoff: u64 = self.e_shoff(endian).into(); - if shoff == 0 { - // No section headers is ok. - return Ok(None); - } - let shentsize = usize::from(self.e_shentsize(endian)); - if shentsize != mem::size_of::<Self::SectionHeader>() { - // Section header size must match. - return Err(Error("Invalid ELF section header entry size")); - } - data.read_at(shoff) - .map(Some) - .read_error("Invalid ELF section header offset or size") - } - - /// Return the `e_phnum` field of the header. Handles extended values. - /// - /// Returns `Err` for invalid values. - fn phnum<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> read::Result<usize> { - let e_phnum = self.e_phnum(endian); - if e_phnum < elf::PN_XNUM { - Ok(e_phnum as usize) - } else if let Some(section_0) = self.section_0(endian, data)? { - Ok(section_0.sh_info(endian) as usize) - } else { - // Section 0 must exist if e_phnum overflows. - Err(Error("Missing ELF section headers for e_phnum overflow")) - } - } - - /// Return the `e_shnum` field of the header. Handles extended values. - /// - /// Returns `Err` for invalid values. - fn shnum<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> read::Result<usize> { - let e_shnum = self.e_shnum(endian); - if e_shnum > 0 { - Ok(e_shnum as usize) - } else if let Some(section_0) = self.section_0(endian, data)? { - section_0 - .sh_size(endian) - .into() - .try_into() - .ok() - .read_error("Invalid ELF extended e_shnum") - } else { - // No section headers is ok. - Ok(0) - } - } - - /// Return the `e_shstrndx` field of the header. Handles extended values. - /// - /// Returns `Err` for invalid values (including if the index is 0). - fn shstrndx<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> read::Result<u32> { - let e_shstrndx = self.e_shstrndx(endian); - let index = if e_shstrndx != elf::SHN_XINDEX { - e_shstrndx.into() - } else if let Some(section_0) = self.section_0(endian, data)? { - section_0.sh_link(endian) - } else { - // Section 0 must exist if we're trying to read e_shstrndx. - return Err(Error("Missing ELF section headers for e_shstrndx overflow")); - }; - if index == 0 { - return Err(Error("Missing ELF e_shstrndx")); - } - Ok(index) - } - - /// Return the slice of program headers. - /// - /// Returns `Ok(&[])` if there are no program headers. - /// Returns `Err` for invalid values. - fn program_headers<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> read::Result<&'data [Self::ProgramHeader]> { - let phoff: u64 = self.e_phoff(endian).into(); - if phoff == 0 { - // No program headers is ok. - return Ok(&[]); - } - let phnum = self.phnum(endian, data)?; - if phnum == 0 { - // No program headers is ok. - return Ok(&[]); - } - let phentsize = self.e_phentsize(endian) as usize; - if phentsize != mem::size_of::<Self::ProgramHeader>() { - // Program header size must match. - return Err(Error("Invalid ELF program header entry size")); - } - data.read_slice_at(phoff, phnum) - .read_error("Invalid ELF program header size or alignment") - } - - /// Return the slice of section headers. - /// - /// Returns `Ok(&[])` if there are no section headers. - /// Returns `Err` for invalid values. - fn section_headers<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> read::Result<&'data [Self::SectionHeader]> { - let shoff: u64 = self.e_shoff(endian).into(); - if shoff == 0 { - // No section headers is ok. - return Ok(&[]); - } - let shnum = self.shnum(endian, data)?; - if shnum == 0 { - // No section headers is ok. - return Ok(&[]); - } - let shentsize = usize::from(self.e_shentsize(endian)); - if shentsize != mem::size_of::<Self::SectionHeader>() { - // Section header size must match. - return Err(Error("Invalid ELF section header entry size")); - } - data.read_slice_at(shoff, shnum) - .read_error("Invalid ELF section header offset/size/alignment") - } - - /// Return the string table for the section headers. - fn section_strings<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - sections: &[Self::SectionHeader], - ) -> read::Result<StringTable<'data, R>> { - if sections.is_empty() { - return Ok(StringTable::default()); - } - let index = self.shstrndx(endian, data)? as usize; - let shstrtab = sections.get(index).read_error("Invalid ELF e_shstrndx")?; - let strings = if let Some((shstrtab_offset, shstrtab_size)) = shstrtab.file_range(endian) { - let shstrtab_end = shstrtab_offset - .checked_add(shstrtab_size) - .read_error("Invalid ELF shstrtab size")?; - StringTable::new(data, shstrtab_offset, shstrtab_end) - } else { - StringTable::default() - }; - Ok(strings) - } - - /// Return the section table. - fn sections<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> read::Result<SectionTable<'data, Self, R>> { - let sections = self.section_headers(endian, data)?; - let strings = self.section_strings(endian, data, sections)?; - Ok(SectionTable::new(sections, strings)) - } - - /// Returns whether this is a mips64el elf file. - fn is_mips64el(&self, endian: Self::Endian) -> bool { - self.is_class_64() && self.is_little_endian() && self.e_machine(endian) == elf::EM_MIPS - } -} - -impl<Endian: endian::Endian> FileHeader for elf::FileHeader32<Endian> { - type Word = u32; - type Sword = i32; - type Endian = Endian; - type ProgramHeader = elf::ProgramHeader32<Endian>; - type SectionHeader = elf::SectionHeader32<Endian>; - type CompressionHeader = elf::CompressionHeader32<Endian>; - type NoteHeader = elf::NoteHeader32<Endian>; - type Dyn = elf::Dyn32<Endian>; - type Sym = elf::Sym32<Endian>; - type Rel = elf::Rel32<Endian>; - type Rela = elf::Rela32<Endian>; - - #[inline] - fn is_type_64(&self) -> bool { - false - } - - #[inline] - fn is_type_64_sized() -> bool - where - Self: Sized, - { - false - } - - #[inline] - fn e_ident(&self) -> &elf::Ident { - &self.e_ident - } - - #[inline] - fn e_type(&self, endian: Self::Endian) -> u16 { - self.e_type.get(endian) - } - - #[inline] - fn e_machine(&self, endian: Self::Endian) -> u16 { - self.e_machine.get(endian) - } - - #[inline] - fn e_version(&self, endian: Self::Endian) -> u32 { - self.e_version.get(endian) - } - - #[inline] - fn e_entry(&self, endian: Self::Endian) -> Self::Word { - self.e_entry.get(endian) - } - - #[inline] - fn e_phoff(&self, endian: Self::Endian) -> Self::Word { - self.e_phoff.get(endian) - } - - #[inline] - fn e_shoff(&self, endian: Self::Endian) -> Self::Word { - self.e_shoff.get(endian) - } - - #[inline] - fn e_flags(&self, endian: Self::Endian) -> u32 { - self.e_flags.get(endian) - } - - #[inline] - fn e_ehsize(&self, endian: Self::Endian) -> u16 { - self.e_ehsize.get(endian) - } - - #[inline] - fn e_phentsize(&self, endian: Self::Endian) -> u16 { - self.e_phentsize.get(endian) - } - - #[inline] - fn e_phnum(&self, endian: Self::Endian) -> u16 { - self.e_phnum.get(endian) - } - - #[inline] - fn e_shentsize(&self, endian: Self::Endian) -> u16 { - self.e_shentsize.get(endian) - } - - #[inline] - fn e_shnum(&self, endian: Self::Endian) -> u16 { - self.e_shnum.get(endian) - } - - #[inline] - fn e_shstrndx(&self, endian: Self::Endian) -> u16 { - self.e_shstrndx.get(endian) - } -} - -impl<Endian: endian::Endian> FileHeader for elf::FileHeader64<Endian> { - type Word = u64; - type Sword = i64; - type Endian = Endian; - type ProgramHeader = elf::ProgramHeader64<Endian>; - type SectionHeader = elf::SectionHeader64<Endian>; - type CompressionHeader = elf::CompressionHeader64<Endian>; - type NoteHeader = elf::NoteHeader32<Endian>; - type Dyn = elf::Dyn64<Endian>; - type Sym = elf::Sym64<Endian>; - type Rel = elf::Rel64<Endian>; - type Rela = elf::Rela64<Endian>; - - #[inline] - fn is_type_64(&self) -> bool { - true - } - - #[inline] - fn is_type_64_sized() -> bool - where - Self: Sized, - { - true - } - - #[inline] - fn e_ident(&self) -> &elf::Ident { - &self.e_ident - } - - #[inline] - fn e_type(&self, endian: Self::Endian) -> u16 { - self.e_type.get(endian) - } - - #[inline] - fn e_machine(&self, endian: Self::Endian) -> u16 { - self.e_machine.get(endian) - } - - #[inline] - fn e_version(&self, endian: Self::Endian) -> u32 { - self.e_version.get(endian) - } - - #[inline] - fn e_entry(&self, endian: Self::Endian) -> Self::Word { - self.e_entry.get(endian) - } - - #[inline] - fn e_phoff(&self, endian: Self::Endian) -> Self::Word { - self.e_phoff.get(endian) - } - - #[inline] - fn e_shoff(&self, endian: Self::Endian) -> Self::Word { - self.e_shoff.get(endian) - } - - #[inline] - fn e_flags(&self, endian: Self::Endian) -> u32 { - self.e_flags.get(endian) - } - - #[inline] - fn e_ehsize(&self, endian: Self::Endian) -> u16 { - self.e_ehsize.get(endian) - } - - #[inline] - fn e_phentsize(&self, endian: Self::Endian) -> u16 { - self.e_phentsize.get(endian) - } - - #[inline] - fn e_phnum(&self, endian: Self::Endian) -> u16 { - self.e_phnum.get(endian) - } - - #[inline] - fn e_shentsize(&self, endian: Self::Endian) -> u16 { - self.e_shentsize.get(endian) - } - - #[inline] - fn e_shnum(&self, endian: Self::Endian) -> u16 { - self.e_shnum.get(endian) - } - - #[inline] - fn e_shstrndx(&self, endian: Self::Endian) -> u16 { - self.e_shstrndx.get(endian) - } -} diff --git a/vendor/object/src/read/elf/hash.rs b/vendor/object/src/read/elf/hash.rs deleted file mode 100644 index b0130cc..0000000 --- a/vendor/object/src/read/elf/hash.rs +++ /dev/null @@ -1,224 +0,0 @@ -use core::mem; - -use crate::elf; -use crate::read::{ReadError, ReadRef, Result}; -use crate::{U32, U64}; - -use super::{FileHeader, Sym, SymbolTable, Version, VersionTable}; - -/// A SysV symbol hash table in an ELF file. -/// -/// Returned by [`SectionHeader::hash`](super::SectionHeader::hash). -#[derive(Debug)] -pub struct HashTable<'data, Elf: FileHeader> { - buckets: &'data [U32<Elf::Endian>], - chains: &'data [U32<Elf::Endian>], -} - -impl<'data, Elf: FileHeader> HashTable<'data, Elf> { - /// Parse a SysV hash table. - /// - /// `data` should be from an [`elf::SHT_HASH`] section, or from a - /// segment pointed to via the [`elf::DT_HASH`] entry. - /// - /// The header is read at offset 0 in the given `data`. - pub fn parse(endian: Elf::Endian, data: &'data [u8]) -> Result<Self> { - let mut offset = 0; - let header = data - .read::<elf::HashHeader<Elf::Endian>>(&mut offset) - .read_error("Invalid hash header")?; - let buckets = data - .read_slice(&mut offset, header.bucket_count.get(endian) as usize) - .read_error("Invalid hash buckets")?; - let chains = data - .read_slice(&mut offset, header.chain_count.get(endian) as usize) - .read_error("Invalid hash chains")?; - Ok(HashTable { buckets, chains }) - } - - /// Return the symbol table length. - pub fn symbol_table_length(&self) -> u32 { - self.chains.len() as u32 - } - - /// Use the hash table to find the symbol table entry with the given name, hash and version. - pub fn find<R: ReadRef<'data>>( - &self, - endian: Elf::Endian, - name: &[u8], - hash: u32, - version: Option<&Version<'_>>, - symbols: &SymbolTable<'data, Elf, R>, - versions: &VersionTable<'data, Elf>, - ) -> Option<(usize, &'data Elf::Sym)> { - // Get the chain start from the bucket for this hash. - let mut index = self.buckets[(hash as usize) % self.buckets.len()].get(endian) as usize; - // Avoid infinite loop. - let mut i = 0; - let strings = symbols.strings(); - while index != 0 && i < self.chains.len() { - if let Ok(symbol) = symbols.symbol(index) { - if symbol.name(endian, strings) == Ok(name) - && versions.matches(endian, index, version) - { - return Some((index, symbol)); - } - } - index = self.chains.get(index)?.get(endian) as usize; - i += 1; - } - None - } -} - -/// A GNU symbol hash table in an ELF file. -/// -/// Returned by [`SectionHeader::gnu_hash`](super::SectionHeader::gnu_hash). -#[derive(Debug)] -pub struct GnuHashTable<'data, Elf: FileHeader> { - symbol_base: u32, - bloom_shift: u32, - bloom_filters: &'data [u8], - buckets: &'data [U32<Elf::Endian>], - values: &'data [U32<Elf::Endian>], -} - -impl<'data, Elf: FileHeader> GnuHashTable<'data, Elf> { - /// Parse a GNU hash table. - /// - /// `data` should be from an [`elf::SHT_GNU_HASH`] section, or from a - /// segment pointed to via the [`elf::DT_GNU_HASH`] entry. - /// - /// The header is read at offset 0 in the given `data`. - /// - /// The header does not contain a length field, and so all of `data` - /// will be used as the hash table values. It does not matter if this - /// is longer than needed, and this will often the case when accessing - /// the hash table via the [`elf::DT_GNU_HASH`] entry. - pub fn parse(endian: Elf::Endian, data: &'data [u8]) -> Result<Self> { - let mut offset = 0; - let header = data - .read::<elf::GnuHashHeader<Elf::Endian>>(&mut offset) - .read_error("Invalid GNU hash header")?; - let bloom_len = - u64::from(header.bloom_count.get(endian)) * mem::size_of::<Elf::Word>() as u64; - let bloom_filters = data - .read_bytes(&mut offset, bloom_len) - .read_error("Invalid GNU hash bloom filters")?; - let buckets = data - .read_slice(&mut offset, header.bucket_count.get(endian) as usize) - .read_error("Invalid GNU hash buckets")?; - let chain_count = (data.len() - offset as usize) / 4; - let values = data - .read_slice(&mut offset, chain_count) - .read_error("Invalid GNU hash values")?; - Ok(GnuHashTable { - symbol_base: header.symbol_base.get(endian), - bloom_shift: header.bloom_shift.get(endian), - bloom_filters, - buckets, - values, - }) - } - - /// Return the symbol table index of the first symbol in the hash table. - pub fn symbol_base(&self) -> u32 { - self.symbol_base - } - - /// Determine the symbol table length by finding the last entry in the hash table. - /// - /// Returns `None` if the hash table is empty or invalid. - pub fn symbol_table_length(&self, endian: Elf::Endian) -> Option<u32> { - // Ensure we find a non-empty bucket. - if self.symbol_base == 0 { - return None; - } - - // Find the highest chain index in a bucket. - let mut max_symbol = 0; - for bucket in self.buckets { - let bucket = bucket.get(endian); - if max_symbol < bucket { - max_symbol = bucket; - } - } - - // Find the end of the chain. - for value in self - .values - .get(max_symbol.checked_sub(self.symbol_base)? as usize..)? - { - max_symbol += 1; - if value.get(endian) & 1 != 0 { - return Some(max_symbol); - } - } - - None - } - - /// Use the hash table to find the symbol table entry with the given name, hash, and version. - pub fn find<R: ReadRef<'data>>( - &self, - endian: Elf::Endian, - name: &[u8], - hash: u32, - version: Option<&Version<'_>>, - symbols: &SymbolTable<'data, Elf, R>, - versions: &VersionTable<'data, Elf>, - ) -> Option<(usize, &'data Elf::Sym)> { - let word_bits = mem::size_of::<Elf::Word>() as u32 * 8; - - // Test against bloom filter. - let bloom_count = self.bloom_filters.len() / mem::size_of::<Elf::Word>(); - let offset = - ((hash / word_bits) & (bloom_count as u32 - 1)) * mem::size_of::<Elf::Word>() as u32; - let filter = if word_bits == 64 { - self.bloom_filters - .read_at::<U64<Elf::Endian>>(offset.into()) - .ok()? - .get(endian) - } else { - self.bloom_filters - .read_at::<U32<Elf::Endian>>(offset.into()) - .ok()? - .get(endian) - .into() - }; - if filter & (1 << (hash % word_bits)) == 0 { - return None; - } - if filter & (1 << ((hash >> self.bloom_shift) % word_bits)) == 0 { - return None; - } - - // Get the chain start from the bucket for this hash. - let mut index = self.buckets[(hash as usize) % self.buckets.len()].get(endian) as usize; - if index == 0 { - return None; - } - - // Test symbols in the chain. - let strings = symbols.strings(); - let symbols = symbols.symbols().get(index..)?; - let values = self - .values - .get(index.checked_sub(self.symbol_base as usize)?..)?; - for (symbol, value) in symbols.iter().zip(values.iter()) { - let value = value.get(endian); - if value | 1 == hash | 1 { - if symbol.name(endian, strings) == Ok(name) - && versions.matches(endian, index, version) - { - return Some((index, symbol)); - } - } - if value & 1 != 0 { - break; - } - index += 1; - } - None - } -} diff --git a/vendor/object/src/read/elf/mod.rs b/vendor/object/src/read/elf/mod.rs deleted file mode 100644 index 66931bd..0000000 --- a/vendor/object/src/read/elf/mod.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Support for reading ELF files. -//! -//! Traits are used to abstract over the difference between 32-bit and 64-bit ELF. -//! The primary trait for this is [`FileHeader`]. -//! -//! ## High level API -//! -//! [`ElfFile`] implements the [`Object`](crate::read::Object) trait for ELF files. -//! [`ElfFile`] is parameterised by [`FileHeader`] to allow reading both 32-bit and -//! 64-bit ELF. There are type aliases for these parameters ([`ElfFile32`] and -//! [`ElfFile64`]). -//! -//! ## Low level API -//! -//! The [`FileHeader`] trait can be directly used to parse both [`elf::FileHeader32`] -//! and [`elf::FileHeader64`]. -//! -//! ### Example for low level API -//! ```no_run -//! use object::elf; -//! use object::read::elf::{FileHeader, Sym}; -//! use std::error::Error; -//! use std::fs; -//! -//! /// Reads a file and displays the name of each symbol. -//! fn main() -> Result<(), Box<dyn Error>> { -//! # #[cfg(feature = "std")] { -//! let data = fs::read("path/to/binary")?; -//! let elf = elf::FileHeader64::<object::Endianness>::parse(&*data)?; -//! let endian = elf.endian()?; -//! let sections = elf.sections(endian, &*data)?; -//! let symbols = sections.symbols(endian, &*data, elf::SHT_SYMTAB)?; -//! for symbol in symbols.iter() { -//! let name = symbol.name(endian, symbols.strings())?; -//! println!("{}", String::from_utf8_lossy(name)); -//! } -//! # } -//! Ok(()) -//! } -//! ``` -#[cfg(doc)] -use crate::elf; - -mod file; -pub use file::*; - -mod segment; -pub use segment::*; - -mod section; -pub use section::*; - -mod symbol; -pub use symbol::*; - -mod relocation; -pub use relocation::*; - -mod comdat; -pub use comdat::*; - -mod dynamic; -pub use dynamic::*; - -mod compression; -pub use compression::*; - -mod note; -pub use note::*; - -mod hash; -pub use hash::*; - -mod version; -pub use version::*; - -mod attributes; -pub use attributes::*; diff --git a/vendor/object/src/read/elf/note.rs b/vendor/object/src/read/elf/note.rs deleted file mode 100644 index e2beef9..0000000 --- a/vendor/object/src/read/elf/note.rs +++ /dev/null @@ -1,271 +0,0 @@ -use core::fmt::Debug; -use core::mem; - -use crate::elf; -use crate::endian::{self, U32}; -use crate::pod::Pod; -use crate::read::util; -use crate::read::{self, Bytes, Error, ReadError}; - -use super::FileHeader; - -/// An iterator over the notes in an ELF section or segment. -/// -/// Returned [`ProgramHeader::notes`](super::ProgramHeader::notes) -/// and [`SectionHeader::notes`](super::SectionHeader::notes). -#[derive(Debug)] -pub struct NoteIterator<'data, Elf> -where - Elf: FileHeader, -{ - endian: Elf::Endian, - align: usize, - data: Bytes<'data>, -} - -impl<'data, Elf> NoteIterator<'data, Elf> -where - Elf: FileHeader, -{ - /// An iterator over the notes in an ELF section or segment. - /// - /// `align` should be from the `p_align` field of the segment, - /// or the `sh_addralign` field of the section. Supported values are - /// either 4 or 8, but values less than 4 are treated as 4. - /// This matches the behaviour of binutils. - /// - /// Returns `Err` if `align` is invalid. - pub fn new(endian: Elf::Endian, align: Elf::Word, data: &'data [u8]) -> read::Result<Self> { - let align = match align.into() { - 0u64..=4 => 4, - 8 => 8, - _ => return Err(Error("Invalid ELF note alignment")), - }; - // TODO: check data alignment? - Ok(NoteIterator { - endian, - align, - data: Bytes(data), - }) - } - - /// Returns the next note. - pub fn next(&mut self) -> read::Result<Option<Note<'data, Elf>>> { - let mut data = self.data; - if data.is_empty() { - return Ok(None); - } - - let header = data - .read_at::<Elf::NoteHeader>(0) - .read_error("ELF note is too short")?; - - // The name has no alignment requirement. - let offset = mem::size_of::<Elf::NoteHeader>(); - let namesz = header.n_namesz(self.endian) as usize; - let name = data - .read_bytes_at(offset, namesz) - .read_error("Invalid ELF note namesz")? - .0; - - // The descriptor must be aligned. - let offset = util::align(offset + namesz, self.align); - let descsz = header.n_descsz(self.endian) as usize; - let desc = data - .read_bytes_at(offset, descsz) - .read_error("Invalid ELF note descsz")? - .0; - - // The next note (if any) must be aligned. - let offset = util::align(offset + descsz, self.align); - if data.skip(offset).is_err() { - data = Bytes(&[]); - } - self.data = data; - - Ok(Some(Note { header, name, desc })) - } -} - -/// A parsed [`NoteHeader`]. -#[derive(Debug)] -pub struct Note<'data, Elf> -where - Elf: FileHeader, -{ - header: &'data Elf::NoteHeader, - name: &'data [u8], - desc: &'data [u8], -} - -impl<'data, Elf: FileHeader> Note<'data, Elf> { - /// Return the `n_type` field of the `NoteHeader`. - /// - /// The meaning of this field is determined by `name`. - pub fn n_type(&self, endian: Elf::Endian) -> u32 { - self.header.n_type(endian) - } - - /// Return the `n_namesz` field of the `NoteHeader`. - pub fn n_namesz(&self, endian: Elf::Endian) -> u32 { - self.header.n_namesz(endian) - } - - /// Return the `n_descsz` field of the `NoteHeader`. - pub fn n_descsz(&self, endian: Elf::Endian) -> u32 { - self.header.n_descsz(endian) - } - - /// Return the bytes for the name field following the `NoteHeader`. - /// - /// This field is usually a string including one or more trailing null bytes - /// (but it is not required to be). - /// - /// The length of this field is given by `n_namesz`. - pub fn name_bytes(&self) -> &'data [u8] { - self.name - } - - /// Return the bytes for the name field following the `NoteHeader`, - /// excluding all trailing null bytes. - pub fn name(&self) -> &'data [u8] { - let mut name = self.name; - while let [rest @ .., 0] = name { - name = rest; - } - name - } - - /// Return the bytes for the desc field following the `NoteHeader`. - /// - /// The length of this field is given by `n_descsz`. The meaning - /// of this field is determined by `name` and `n_type`. - pub fn desc(&self) -> &'data [u8] { - self.desc - } - - /// Return an iterator for properties if this note's type is [`elf::NT_GNU_PROPERTY_TYPE_0`]. - pub fn gnu_properties( - &self, - endian: Elf::Endian, - ) -> Option<GnuPropertyIterator<'data, Elf::Endian>> { - if self.name() != elf::ELF_NOTE_GNU || self.n_type(endian) != elf::NT_GNU_PROPERTY_TYPE_0 { - return None; - } - // Use the ELF class instead of the section alignment. - // This matches what other parsers do. - let align = if Elf::is_type_64_sized() { 8 } else { 4 }; - Some(GnuPropertyIterator { - endian, - align, - data: Bytes(self.desc), - }) - } -} - -/// A trait for generic access to [`elf::NoteHeader32`] and [`elf::NoteHeader64`]. -#[allow(missing_docs)] -pub trait NoteHeader: Debug + Pod { - type Endian: endian::Endian; - - fn n_namesz(&self, endian: Self::Endian) -> u32; - fn n_descsz(&self, endian: Self::Endian) -> u32; - fn n_type(&self, endian: Self::Endian) -> u32; -} - -impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader32<Endian> { - type Endian = Endian; - - #[inline] - fn n_namesz(&self, endian: Self::Endian) -> u32 { - self.n_namesz.get(endian) - } - - #[inline] - fn n_descsz(&self, endian: Self::Endian) -> u32 { - self.n_descsz.get(endian) - } - - #[inline] - fn n_type(&self, endian: Self::Endian) -> u32 { - self.n_type.get(endian) - } -} - -impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader64<Endian> { - type Endian = Endian; - - #[inline] - fn n_namesz(&self, endian: Self::Endian) -> u32 { - self.n_namesz.get(endian) - } - - #[inline] - fn n_descsz(&self, endian: Self::Endian) -> u32 { - self.n_descsz.get(endian) - } - - #[inline] - fn n_type(&self, endian: Self::Endian) -> u32 { - self.n_type.get(endian) - } -} - -/// An iterator for the properties in a [`elf::NT_GNU_PROPERTY_TYPE_0`] note. -/// -/// Returned by [`Note::gnu_properties`]. -#[derive(Debug)] -pub struct GnuPropertyIterator<'data, Endian: endian::Endian> { - endian: Endian, - align: usize, - data: Bytes<'data>, -} - -impl<'data, Endian: endian::Endian> GnuPropertyIterator<'data, Endian> { - /// Returns the next property. - pub fn next(&mut self) -> read::Result<Option<GnuProperty<'data>>> { - let mut data = self.data; - if data.is_empty() { - return Ok(None); - } - - (|| -> Result<_, ()> { - let pr_type = data.read_at::<U32<Endian>>(0)?.get(self.endian); - let pr_datasz = data.read_at::<U32<Endian>>(4)?.get(self.endian) as usize; - let pr_data = data.read_bytes_at(8, pr_datasz)?.0; - data.skip(util::align(8 + pr_datasz, self.align))?; - self.data = data; - Ok(Some(GnuProperty { pr_type, pr_data })) - })() - .read_error("Invalid ELF GNU property") - } -} - -/// A property in a [`elf::NT_GNU_PROPERTY_TYPE_0`] note. -#[derive(Debug)] -pub struct GnuProperty<'data> { - pr_type: u32, - pr_data: &'data [u8], -} - -impl<'data> GnuProperty<'data> { - /// Return the property type. - /// - /// This is one of the `GNU_PROPERTY_*` constants. - pub fn pr_type(&self) -> u32 { - self.pr_type - } - - /// Return the property data. - pub fn pr_data(&self) -> &'data [u8] { - self.pr_data - } - - /// Parse the property data as an unsigned 32-bit integer. - pub fn data_u32<E: endian::Endian>(&self, endian: E) -> read::Result<u32> { - Bytes(self.pr_data) - .read_at::<U32<E>>(0) - .read_error("Invalid ELF GNU property data") - .map(|val| val.get(endian)) - } -} diff --git a/vendor/object/src/read/elf/relocation.rs b/vendor/object/src/read/elf/relocation.rs deleted file mode 100644 index aac1574..0000000 --- a/vendor/object/src/read/elf/relocation.rs +++ /dev/null @@ -1,628 +0,0 @@ -use alloc::fmt; -use alloc::vec::Vec; -use core::fmt::Debug; -use core::slice; - -use crate::elf; -use crate::endian::{self, Endianness}; -use crate::pod::Pod; -use crate::read::{ - self, Error, ReadRef, Relocation, RelocationEncoding, RelocationKind, RelocationTarget, - SectionIndex, SymbolIndex, -}; - -use super::{ElfFile, FileHeader, SectionHeader, SectionTable}; - -/// A mapping from section index to associated relocation sections. -#[derive(Debug)] -pub struct RelocationSections { - relocations: Vec<usize>, -} - -impl RelocationSections { - /// Create a new mapping using the section table. - /// - /// Skips relocation sections that do not use the given symbol table section. - pub fn parse<'data, Elf: FileHeader, R: ReadRef<'data>>( - endian: Elf::Endian, - sections: &SectionTable<'data, Elf, R>, - symbol_section: SectionIndex, - ) -> read::Result<Self> { - let mut relocations = vec![0; sections.len()]; - for (index, section) in sections.iter().enumerate().rev() { - let sh_type = section.sh_type(endian); - if sh_type == elf::SHT_REL || sh_type == elf::SHT_RELA { - // The symbol indices used in relocations must be for the symbol table - // we are expecting to use. - let sh_link = SectionIndex(section.sh_link(endian) as usize); - if sh_link != symbol_section { - continue; - } - - let sh_info = section.sh_info(endian) as usize; - if sh_info == 0 { - // Skip dynamic relocations. - continue; - } - if sh_info >= relocations.len() { - return Err(Error("Invalid ELF sh_info for relocation section")); - } - - // Handle multiple relocation sections by chaining them. - let next = relocations[sh_info]; - relocations[sh_info] = index; - relocations[index] = next; - } - } - Ok(Self { relocations }) - } - - /// Given a section index, return the section index of the associated relocation section. - /// - /// This may also be called with a relocation section index, and it will return the - /// next associated relocation section. - pub fn get(&self, index: usize) -> Option<usize> { - self.relocations.get(index).cloned().filter(|x| *x != 0) - } -} - -pub(super) enum ElfRelaIterator<'data, Elf: FileHeader> { - Rel(slice::Iter<'data, Elf::Rel>), - Rela(slice::Iter<'data, Elf::Rela>), -} - -impl<'data, Elf: FileHeader> ElfRelaIterator<'data, Elf> { - fn is_rel(&self) -> bool { - match self { - ElfRelaIterator::Rel(_) => true, - ElfRelaIterator::Rela(_) => false, - } - } -} - -impl<'data, Elf: FileHeader> Iterator for ElfRelaIterator<'data, Elf> { - type Item = Elf::Rela; - - fn next(&mut self) -> Option<Self::Item> { - match self { - ElfRelaIterator::Rel(ref mut i) => i.next().cloned().map(Self::Item::from), - ElfRelaIterator::Rela(ref mut i) => i.next().cloned(), - } - } -} - -/// An iterator for the dynamic relocations in an [`ElfFile32`](super::ElfFile32). -pub type ElfDynamicRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>; -/// An iterator for the dynamic relocations in an [`ElfFile64`](super::ElfFile64). -pub type ElfDynamicRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>; - -/// An iterator for the dynamic relocations in an [`ElfFile`]. -pub struct ElfDynamicRelocationIterator<'data, 'file, Elf, R = &'data [u8]> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - /// The current relocation section index. - pub(super) section_index: SectionIndex, - pub(super) file: &'file ElfFile<'data, Elf, R>, - pub(super) relocations: Option<ElfRelaIterator<'data, Elf>>, -} - -impl<'data, 'file, Elf, R> Iterator for ElfDynamicRelocationIterator<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - type Item = (u64, Relocation); - - fn next(&mut self) -> Option<Self::Item> { - let endian = self.file.endian; - loop { - if let Some(ref mut relocations) = self.relocations { - if let Some(reloc) = relocations.next() { - let relocation = - parse_relocation(self.file.header, endian, reloc, relocations.is_rel()); - return Some((reloc.r_offset(endian).into(), relocation)); - } - self.relocations = None; - } - - let section = self.file.sections.section(self.section_index).ok()?; - self.section_index.0 += 1; - - let sh_link = SectionIndex(section.sh_link(endian) as usize); - if sh_link != self.file.dynamic_symbols.section() { - continue; - } - - match section.sh_type(endian) { - elf::SHT_REL => { - if let Ok(relocations) = section.data_as_array(endian, self.file.data) { - self.relocations = Some(ElfRelaIterator::Rel(relocations.iter())); - } - } - elf::SHT_RELA => { - if let Ok(relocations) = section.data_as_array(endian, self.file.data) { - self.relocations = Some(ElfRelaIterator::Rela(relocations.iter())); - } - } - _ => {} - } - } - } -} - -impl<'data, 'file, Elf, R> fmt::Debug for ElfDynamicRelocationIterator<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ElfDynamicRelocationIterator").finish() - } -} - -/// An iterator for the relocations for an [`ElfSection32`](super::ElfSection32). -pub type ElfSectionRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSectionRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>; -/// An iterator for the relocations for an [`ElfSection64`](super::ElfSection64). -pub type ElfSectionRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSectionRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>; - -/// An iterator for the relocations for an [`ElfSection`](super::ElfSection). -pub struct ElfSectionRelocationIterator<'data, 'file, Elf, R = &'data [u8]> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - /// The current pointer in the chain of relocation sections. - pub(super) section_index: SectionIndex, - pub(super) file: &'file ElfFile<'data, Elf, R>, - pub(super) relocations: Option<ElfRelaIterator<'data, Elf>>, -} - -impl<'data, 'file, Elf, R> Iterator for ElfSectionRelocationIterator<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - type Item = (u64, Relocation); - - fn next(&mut self) -> Option<Self::Item> { - let endian = self.file.endian; - loop { - if let Some(ref mut relocations) = self.relocations { - if let Some(reloc) = relocations.next() { - let relocation = - parse_relocation(self.file.header, endian, reloc, relocations.is_rel()); - return Some((reloc.r_offset(endian).into(), relocation)); - } - self.relocations = None; - } - self.section_index = SectionIndex(self.file.relocations.get(self.section_index.0)?); - // The construction of RelocationSections ensures section_index is valid. - let section = self.file.sections.section(self.section_index).unwrap(); - match section.sh_type(endian) { - elf::SHT_REL => { - if let Ok(relocations) = section.data_as_array(endian, self.file.data) { - self.relocations = Some(ElfRelaIterator::Rel(relocations.iter())); - } - } - elf::SHT_RELA => { - if let Ok(relocations) = section.data_as_array(endian, self.file.data) { - self.relocations = Some(ElfRelaIterator::Rela(relocations.iter())); - } - } - _ => {} - } - } - } -} - -impl<'data, 'file, Elf, R> fmt::Debug for ElfSectionRelocationIterator<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ElfSectionRelocationIterator").finish() - } -} - -fn parse_relocation<Elf: FileHeader>( - header: &Elf, - endian: Elf::Endian, - reloc: Elf::Rela, - implicit_addend: bool, -) -> Relocation { - let mut encoding = RelocationEncoding::Generic; - let is_mips64el = header.is_mips64el(endian); - let (kind, size) = match header.e_machine(endian) { - elf::EM_AARCH64 => { - if header.is_type_64() { - match reloc.r_type(endian, false) { - elf::R_AARCH64_ABS64 => (RelocationKind::Absolute, 64), - elf::R_AARCH64_ABS32 => (RelocationKind::Absolute, 32), - elf::R_AARCH64_ABS16 => (RelocationKind::Absolute, 16), - elf::R_AARCH64_PREL64 => (RelocationKind::Relative, 64), - elf::R_AARCH64_PREL32 => (RelocationKind::Relative, 32), - elf::R_AARCH64_PREL16 => (RelocationKind::Relative, 16), - elf::R_AARCH64_CALL26 => { - encoding = RelocationEncoding::AArch64Call; - (RelocationKind::PltRelative, 26) - } - r_type => (RelocationKind::Elf(r_type), 0), - } - } else { - match reloc.r_type(endian, false) { - elf::R_AARCH64_P32_ABS32 => (RelocationKind::Absolute, 32), - r_type => (RelocationKind::Elf(r_type), 0), - } - } - } - elf::EM_ARM => match reloc.r_type(endian, false) { - elf::R_ARM_ABS32 => (RelocationKind::Absolute, 32), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_AVR => match reloc.r_type(endian, false) { - elf::R_AVR_32 => (RelocationKind::Absolute, 32), - elf::R_AVR_16 => (RelocationKind::Absolute, 16), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_BPF => match reloc.r_type(endian, false) { - elf::R_BPF_64_64 => (RelocationKind::Absolute, 64), - elf::R_BPF_64_32 => (RelocationKind::Absolute, 32), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_CSKY => match reloc.r_type(endian, false) { - elf::R_CKCORE_ADDR32 => (RelocationKind::Absolute, 32), - elf::R_CKCORE_PCREL32 => (RelocationKind::Relative, 32), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_386 => match reloc.r_type(endian, false) { - elf::R_386_32 => (RelocationKind::Absolute, 32), - elf::R_386_PC32 => (RelocationKind::Relative, 32), - elf::R_386_GOT32 => (RelocationKind::Got, 32), - elf::R_386_PLT32 => (RelocationKind::PltRelative, 32), - elf::R_386_GOTOFF => (RelocationKind::GotBaseOffset, 32), - elf::R_386_GOTPC => (RelocationKind::GotBaseRelative, 32), - elf::R_386_16 => (RelocationKind::Absolute, 16), - elf::R_386_PC16 => (RelocationKind::Relative, 16), - elf::R_386_8 => (RelocationKind::Absolute, 8), - elf::R_386_PC8 => (RelocationKind::Relative, 8), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_X86_64 => match reloc.r_type(endian, false) { - elf::R_X86_64_64 => (RelocationKind::Absolute, 64), - elf::R_X86_64_PC32 => (RelocationKind::Relative, 32), - elf::R_X86_64_GOT32 => (RelocationKind::Got, 32), - elf::R_X86_64_PLT32 => (RelocationKind::PltRelative, 32), - elf::R_X86_64_GOTPCREL => (RelocationKind::GotRelative, 32), - elf::R_X86_64_32 => (RelocationKind::Absolute, 32), - elf::R_X86_64_32S => { - encoding = RelocationEncoding::X86Signed; - (RelocationKind::Absolute, 32) - } - elf::R_X86_64_16 => (RelocationKind::Absolute, 16), - elf::R_X86_64_PC16 => (RelocationKind::Relative, 16), - elf::R_X86_64_8 => (RelocationKind::Absolute, 8), - elf::R_X86_64_PC8 => (RelocationKind::Relative, 8), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_HEXAGON => match reloc.r_type(endian, false) { - elf::R_HEX_32 => (RelocationKind::Absolute, 32), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_LOONGARCH => match reloc.r_type(endian, false) { - elf::R_LARCH_32 => (RelocationKind::Absolute, 32), - elf::R_LARCH_64 => (RelocationKind::Absolute, 64), - elf::R_LARCH_32_PCREL => (RelocationKind::Relative, 32), - elf::R_LARCH_64_PCREL => (RelocationKind::Relative, 64), - elf::R_LARCH_B16 => { - encoding = RelocationEncoding::LoongArchBranch; - (RelocationKind::Relative, 16) - } - elf::R_LARCH_B21 => { - encoding = RelocationEncoding::LoongArchBranch; - (RelocationKind::Relative, 21) - } - elf::R_LARCH_B26 => { - encoding = RelocationEncoding::LoongArchBranch; - (RelocationKind::Relative, 26) - } - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_MIPS => match reloc.r_type(endian, is_mips64el) { - elf::R_MIPS_16 => (RelocationKind::Absolute, 16), - elf::R_MIPS_32 => (RelocationKind::Absolute, 32), - elf::R_MIPS_64 => (RelocationKind::Absolute, 64), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_MSP430 => match reloc.r_type(endian, false) { - elf::R_MSP430_32 => (RelocationKind::Absolute, 32), - elf::R_MSP430_16_BYTE => (RelocationKind::Absolute, 16), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_PPC => match reloc.r_type(endian, false) { - elf::R_PPC_ADDR32 => (RelocationKind::Absolute, 32), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_PPC64 => match reloc.r_type(endian, false) { - elf::R_PPC64_ADDR32 => (RelocationKind::Absolute, 32), - elf::R_PPC64_ADDR64 => (RelocationKind::Absolute, 64), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_RISCV => match reloc.r_type(endian, false) { - elf::R_RISCV_32 => (RelocationKind::Absolute, 32), - elf::R_RISCV_64 => (RelocationKind::Absolute, 64), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_S390 => match reloc.r_type(endian, false) { - elf::R_390_8 => (RelocationKind::Absolute, 8), - elf::R_390_16 => (RelocationKind::Absolute, 16), - elf::R_390_32 => (RelocationKind::Absolute, 32), - elf::R_390_64 => (RelocationKind::Absolute, 64), - elf::R_390_PC16 => (RelocationKind::Relative, 16), - elf::R_390_PC32 => (RelocationKind::Relative, 32), - elf::R_390_PC64 => (RelocationKind::Relative, 64), - elf::R_390_PC16DBL => { - encoding = RelocationEncoding::S390xDbl; - (RelocationKind::Relative, 16) - } - elf::R_390_PC32DBL => { - encoding = RelocationEncoding::S390xDbl; - (RelocationKind::Relative, 32) - } - elf::R_390_PLT16DBL => { - encoding = RelocationEncoding::S390xDbl; - (RelocationKind::PltRelative, 16) - } - elf::R_390_PLT32DBL => { - encoding = RelocationEncoding::S390xDbl; - (RelocationKind::PltRelative, 32) - } - elf::R_390_GOT16 => (RelocationKind::Got, 16), - elf::R_390_GOT32 => (RelocationKind::Got, 32), - elf::R_390_GOT64 => (RelocationKind::Got, 64), - elf::R_390_GOTENT => { - encoding = RelocationEncoding::S390xDbl; - (RelocationKind::GotRelative, 32) - } - elf::R_390_GOTOFF16 => (RelocationKind::GotBaseOffset, 16), - elf::R_390_GOTOFF32 => (RelocationKind::GotBaseOffset, 32), - elf::R_390_GOTOFF64 => (RelocationKind::GotBaseOffset, 64), - elf::R_390_GOTPC => (RelocationKind::GotBaseRelative, 64), - elf::R_390_GOTPCDBL => { - encoding = RelocationEncoding::S390xDbl; - (RelocationKind::GotBaseRelative, 32) - } - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_SBF => match reloc.r_type(endian, false) { - elf::R_SBF_64_64 => (RelocationKind::Absolute, 64), - elf::R_SBF_64_32 => (RelocationKind::Absolute, 32), - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_SHARC => match reloc.r_type(endian, false) { - elf::R_SHARC_ADDR24_V3 => { - encoding = RelocationEncoding::SharcTypeA; - (RelocationKind::Absolute, 24) - } - elf::R_SHARC_ADDR32_V3 => { - encoding = RelocationEncoding::SharcTypeA; - (RelocationKind::Absolute, 32) - } - elf::R_SHARC_ADDR_VAR_V3 => { - encoding = RelocationEncoding::Generic; - (RelocationKind::Absolute, 32) - } - elf::R_SHARC_PCRSHORT_V3 => { - encoding = RelocationEncoding::SharcTypeA; - (RelocationKind::Relative, 6) - } - elf::R_SHARC_PCRLONG_V3 => { - encoding = RelocationEncoding::SharcTypeA; - (RelocationKind::Relative, 24) - } - elf::R_SHARC_DATA6_V3 => { - encoding = RelocationEncoding::SharcTypeA; - (RelocationKind::Absolute, 6) - } - elf::R_SHARC_DATA16_V3 => { - encoding = RelocationEncoding::SharcTypeA; - (RelocationKind::Absolute, 16) - } - elf::R_SHARC_DATA6_VISA_V3 => { - encoding = RelocationEncoding::SharcTypeB; - (RelocationKind::Absolute, 6) - } - elf::R_SHARC_DATA7_VISA_V3 => { - encoding = RelocationEncoding::SharcTypeB; - (RelocationKind::Absolute, 7) - } - elf::R_SHARC_DATA16_VISA_V3 => { - encoding = RelocationEncoding::SharcTypeB; - (RelocationKind::Absolute, 16) - } - elf::R_SHARC_PCR6_VISA_V3 => { - encoding = RelocationEncoding::SharcTypeB; - (RelocationKind::Relative, 16) - } - elf::R_SHARC_ADDR_VAR16_V3 => { - encoding = RelocationEncoding::Generic; - (RelocationKind::Absolute, 16) - } - r_type => (RelocationKind::Elf(r_type), 0), - }, - elf::EM_SPARC | elf::EM_SPARC32PLUS | elf::EM_SPARCV9 => { - match reloc.r_type(endian, false) { - elf::R_SPARC_32 | elf::R_SPARC_UA32 => (RelocationKind::Absolute, 32), - elf::R_SPARC_64 | elf::R_SPARC_UA64 => (RelocationKind::Absolute, 64), - r_type => (RelocationKind::Elf(r_type), 0), - } - } - elf::EM_XTENSA => match reloc.r_type(endian, false) { - elf::R_XTENSA_32 => (RelocationKind::Absolute, 32), - elf::R_XTENSA_32_PCREL => (RelocationKind::Relative, 32), - r_type => (RelocationKind::Elf(r_type), 0), - }, - _ => (RelocationKind::Elf(reloc.r_type(endian, false)), 0), - }; - let sym = reloc.r_sym(endian, is_mips64el) as usize; - let target = if sym == 0 { - RelocationTarget::Absolute - } else { - RelocationTarget::Symbol(SymbolIndex(sym)) - }; - Relocation { - kind, - encoding, - size, - target, - addend: reloc.r_addend(endian).into(), - implicit_addend, - } -} - -/// A trait for generic access to [`elf::Rel32`] and [`elf::Rel64`]. -#[allow(missing_docs)] -pub trait Rel: Debug + Pod + Clone { - type Word: Into<u64>; - type Sword: Into<i64>; - type Endian: endian::Endian; - - fn r_offset(&self, endian: Self::Endian) -> Self::Word; - fn r_info(&self, endian: Self::Endian) -> Self::Word; - fn r_sym(&self, endian: Self::Endian) -> u32; - fn r_type(&self, endian: Self::Endian) -> u32; -} - -impl<Endian: endian::Endian> Rel for elf::Rel32<Endian> { - type Word = u32; - type Sword = i32; - type Endian = Endian; - - #[inline] - fn r_offset(&self, endian: Self::Endian) -> Self::Word { - self.r_offset.get(endian) - } - - #[inline] - fn r_info(&self, endian: Self::Endian) -> Self::Word { - self.r_info.get(endian) - } - - #[inline] - fn r_sym(&self, endian: Self::Endian) -> u32 { - self.r_sym(endian) - } - - #[inline] - fn r_type(&self, endian: Self::Endian) -> u32 { - self.r_type(endian) - } -} - -impl<Endian: endian::Endian> Rel for elf::Rel64<Endian> { - type Word = u64; - type Sword = i64; - type Endian = Endian; - - #[inline] - fn r_offset(&self, endian: Self::Endian) -> Self::Word { - self.r_offset.get(endian) - } - - #[inline] - fn r_info(&self, endian: Self::Endian) -> Self::Word { - self.r_info.get(endian) - } - - #[inline] - fn r_sym(&self, endian: Self::Endian) -> u32 { - self.r_sym(endian) - } - - #[inline] - fn r_type(&self, endian: Self::Endian) -> u32 { - self.r_type(endian) - } -} - -/// A trait for generic access to [`elf::Rela32`] and [`elf::Rela64`]. -#[allow(missing_docs)] -pub trait Rela: Debug + Pod + Clone { - type Word: Into<u64>; - type Sword: Into<i64>; - type Endian: endian::Endian; - - fn r_offset(&self, endian: Self::Endian) -> Self::Word; - fn r_info(&self, endian: Self::Endian, is_mips64el: bool) -> Self::Word; - fn r_addend(&self, endian: Self::Endian) -> Self::Sword; - fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32; - fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32; -} - -impl<Endian: endian::Endian> Rela for elf::Rela32<Endian> { - type Word = u32; - type Sword = i32; - type Endian = Endian; - - #[inline] - fn r_offset(&self, endian: Self::Endian) -> Self::Word { - self.r_offset.get(endian) - } - - #[inline] - fn r_info(&self, endian: Self::Endian, _is_mips64el: bool) -> Self::Word { - self.r_info.get(endian) - } - - #[inline] - fn r_addend(&self, endian: Self::Endian) -> Self::Sword { - self.r_addend.get(endian) - } - - #[inline] - fn r_sym(&self, endian: Self::Endian, _is_mips64el: bool) -> u32 { - self.r_sym(endian) - } - - #[inline] - fn r_type(&self, endian: Self::Endian, _is_mips64el: bool) -> u32 { - self.r_type(endian) - } -} - -impl<Endian: endian::Endian> Rela for elf::Rela64<Endian> { - type Word = u64; - type Sword = i64; - type Endian = Endian; - - #[inline] - fn r_offset(&self, endian: Self::Endian) -> Self::Word { - self.r_offset.get(endian) - } - - #[inline] - fn r_info(&self, endian: Self::Endian, is_mips64el: bool) -> Self::Word { - self.get_r_info(endian, is_mips64el) - } - - #[inline] - fn r_addend(&self, endian: Self::Endian) -> Self::Sword { - self.r_addend.get(endian) - } - - #[inline] - fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32 { - self.r_sym(endian, is_mips64el) - } - - #[inline] - fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32 { - self.r_type(endian, is_mips64el) - } -} diff --git a/vendor/object/src/read/elf/section.rs b/vendor/object/src/read/elf/section.rs deleted file mode 100644 index 2b5ae01..0000000 --- a/vendor/object/src/read/elf/section.rs +++ /dev/null @@ -1,1150 +0,0 @@ -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) - } -} diff --git a/vendor/object/src/read/elf/segment.rs b/vendor/object/src/read/elf/segment.rs deleted file mode 100644 index 957117a..0000000 --- a/vendor/object/src/read/elf/segment.rs +++ /dev/null @@ -1,334 +0,0 @@ -use core::fmt::Debug; -use core::{mem, slice, str}; - -use crate::elf; -use crate::endian::{self, Endianness}; -use crate::pod::Pod; -use crate::read::{self, Bytes, ObjectSegment, ReadError, ReadRef, SegmentFlags}; - -use super::{ElfFile, FileHeader, NoteIterator}; - -/// An iterator for the segments in an [`ElfFile32`](super::ElfFile32). -pub type ElfSegmentIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSegmentIterator<'data, 'file, elf::FileHeader32<Endian>, R>; -/// An iterator for the segments in an [`ElfFile64`](super::ElfFile64). -pub type ElfSegmentIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSegmentIterator<'data, 'file, elf::FileHeader64<Endian>, R>; - -/// An iterator for the segments in an [`ElfFile`]. -#[derive(Debug)] -pub struct ElfSegmentIterator<'data, 'file, Elf, R = &'data [u8]> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file ElfFile<'data, Elf, R>, - pub(super) iter: slice::Iter<'data, Elf::ProgramHeader>, -} - -impl<'data, 'file, Elf, R> Iterator for ElfSegmentIterator<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - type Item = ElfSegment<'data, 'file, Elf, R>; - - fn next(&mut self) -> Option<Self::Item> { - for segment in self.iter.by_ref() { - if segment.p_type(self.file.endian) == elf::PT_LOAD { - return Some(ElfSegment { - file: self.file, - segment, - }); - } - } - None - } -} - -/// A segment in an [`ElfFile32`](super::ElfFile32). -pub type ElfSegment32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSegment<'data, 'file, elf::FileHeader32<Endian>, R>; -/// A segment in an [`ElfFile64`](super::ElfFile64). -pub type ElfSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSegment<'data, 'file, elf::FileHeader64<Endian>, R>; - -/// A segment in an [`ElfFile`]. -/// -/// Most functionality is provided by the [`ObjectSegment`] trait implementation. -#[derive(Debug)] -pub struct ElfSegment<'data, 'file, Elf, R = &'data [u8]> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file ElfFile<'data, Elf, R>, - pub(super) segment: &'data Elf::ProgramHeader, -} - -impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSegment<'data, 'file, Elf, R> { - fn bytes(&self) -> read::Result<&'data [u8]> { - self.segment - .data(self.file.endian, self.file.data) - .read_error("Invalid ELF segment size or offset") - } -} - -impl<'data, 'file, Elf, R> read::private::Sealed for ElfSegment<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Elf, R> ObjectSegment<'data> for ElfSegment<'data, 'file, Elf, R> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - #[inline] - fn address(&self) -> u64 { - self.segment.p_vaddr(self.file.endian).into() - } - - #[inline] - fn size(&self) -> u64 { - self.segment.p_memsz(self.file.endian).into() - } - - #[inline] - fn align(&self) -> u64 { - self.segment.p_align(self.file.endian).into() - } - - #[inline] - fn file_range(&self) -> (u64, u64) { - self.segment.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, - )) - } - - #[inline] - fn name_bytes(&self) -> read::Result<Option<&[u8]>> { - Ok(None) - } - - #[inline] - fn name(&self) -> read::Result<Option<&str>> { - Ok(None) - } - - #[inline] - fn flags(&self) -> SegmentFlags { - let p_flags = self.segment.p_flags(self.file.endian); - SegmentFlags::Elf { p_flags } - } -} - -/// A trait for generic access to [`elf::ProgramHeader32`] and [`elf::ProgramHeader64`]. -#[allow(missing_docs)] -pub trait ProgramHeader: Debug + Pod { - type Elf: FileHeader<ProgramHeader = Self, Endian = Self::Endian, Word = Self::Word>; - type Word: Into<u64>; - type Endian: endian::Endian; - - fn p_type(&self, endian: Self::Endian) -> u32; - fn p_flags(&self, endian: Self::Endian) -> u32; - fn p_offset(&self, endian: Self::Endian) -> Self::Word; - fn p_vaddr(&self, endian: Self::Endian) -> Self::Word; - fn p_paddr(&self, endian: Self::Endian) -> Self::Word; - fn p_filesz(&self, endian: Self::Endian) -> Self::Word; - fn p_memsz(&self, endian: Self::Endian) -> Self::Word; - fn p_align(&self, endian: Self::Endian) -> Self::Word; - - /// Return the offset and size of the segment in the file. - fn file_range(&self, endian: Self::Endian) -> (u64, u64) { - (self.p_offset(endian).into(), self.p_filesz(endian).into()) - } - - /// Return the segment data. - /// - /// Returns `Err` for invalid values. - fn data<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> Result<&'data [u8], ()> { - let (offset, size) = self.file_range(endian); - data.read_bytes_at(offset, size) - } - - /// Return the segment data as a slice of the given type. - /// - /// Allows padding at the end of the data. - /// Returns `Ok(&[])` if the segment 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, - ) -> Result<&'data [T], ()> { - let mut data = self.data(endian, data).map(Bytes)?; - data.read_slice(data.len() / mem::size_of::<T>()) - } - - /// Return the segment data in the given virtual address range - /// - /// Returns `Ok(None)` if the segment does not contain the address. - /// Returns `Err` for invalid values. - fn data_range<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - address: u64, - size: u64, - ) -> Result<Option<&'data [u8]>, ()> { - Ok(read::util::data_range( - self.data(endian, data)?, - self.p_vaddr(endian).into(), - address, - size, - )) - } - - /// Return entries in a dynamic segment. - /// - /// Returns `Ok(None)` if the segment is not `PT_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]>> { - if self.p_type(endian) != elf::PT_DYNAMIC { - return Ok(None); - } - let dynamic = self - .data_as_array(endian, data) - .read_error("Invalid ELF dynamic segment offset or size")?; - Ok(Some(dynamic)) - } - - /// Return a note iterator for the segment data. - /// - /// Returns `Ok(None)` if the segment 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.p_type(endian) != elf::PT_NOTE { - return Ok(None); - } - let data = self - .data(endian, data) - .read_error("Invalid ELF note segment offset or size")?; - let notes = NoteIterator::new(endian, self.p_align(endian), data)?; - Ok(Some(notes)) - } -} - -impl<Endian: endian::Endian> ProgramHeader for elf::ProgramHeader32<Endian> { - type Word = u32; - type Endian = Endian; - type Elf = elf::FileHeader32<Endian>; - - #[inline] - fn p_type(&self, endian: Self::Endian) -> u32 { - self.p_type.get(endian) - } - - #[inline] - fn p_flags(&self, endian: Self::Endian) -> u32 { - self.p_flags.get(endian) - } - - #[inline] - fn p_offset(&self, endian: Self::Endian) -> Self::Word { - self.p_offset.get(endian) - } - - #[inline] - fn p_vaddr(&self, endian: Self::Endian) -> Self::Word { - self.p_vaddr.get(endian) - } - - #[inline] - fn p_paddr(&self, endian: Self::Endian) -> Self::Word { - self.p_paddr.get(endian) - } - - #[inline] - fn p_filesz(&self, endian: Self::Endian) -> Self::Word { - self.p_filesz.get(endian) - } - - #[inline] - fn p_memsz(&self, endian: Self::Endian) -> Self::Word { - self.p_memsz.get(endian) - } - - #[inline] - fn p_align(&self, endian: Self::Endian) -> Self::Word { - self.p_align.get(endian) - } -} - -impl<Endian: endian::Endian> ProgramHeader for elf::ProgramHeader64<Endian> { - type Word = u64; - type Endian = Endian; - type Elf = elf::FileHeader64<Endian>; - - #[inline] - fn p_type(&self, endian: Self::Endian) -> u32 { - self.p_type.get(endian) - } - - #[inline] - fn p_flags(&self, endian: Self::Endian) -> u32 { - self.p_flags.get(endian) - } - - #[inline] - fn p_offset(&self, endian: Self::Endian) -> Self::Word { - self.p_offset.get(endian) - } - - #[inline] - fn p_vaddr(&self, endian: Self::Endian) -> Self::Word { - self.p_vaddr.get(endian) - } - - #[inline] - fn p_paddr(&self, endian: Self::Endian) -> Self::Word { - self.p_paddr.get(endian) - } - - #[inline] - fn p_filesz(&self, endian: Self::Endian) -> Self::Word { - self.p_filesz.get(endian) - } - - #[inline] - fn p_memsz(&self, endian: Self::Endian) -> Self::Word { - self.p_memsz.get(endian) - } - - #[inline] - fn p_align(&self, endian: Self::Endian) -> Self::Word { - self.p_align.get(endian) - } -} diff --git a/vendor/object/src/read/elf/symbol.rs b/vendor/object/src/read/elf/symbol.rs deleted file mode 100644 index 8ba707f..0000000 --- a/vendor/object/src/read/elf/symbol.rs +++ /dev/null @@ -1,595 +0,0 @@ -use alloc::fmt; -use alloc::vec::Vec; -use core::fmt::Debug; -use core::slice; -use core::str; - -use crate::endian::{self, Endianness}; -use crate::pod::Pod; -use crate::read::util::StringTable; -use crate::read::{ - self, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, SectionIndex, SymbolFlags, - SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection, -}; -use crate::{elf, U32}; - -use super::{FileHeader, SectionHeader, SectionTable}; - -/// A table of symbol entries in an ELF file. -/// -/// Also includes the string table used for the symbol names. -/// -/// Returned by [`SectionTable::symbols`]. -#[derive(Debug, Clone, Copy)] -pub struct SymbolTable<'data, Elf: FileHeader, R = &'data [u8]> -where - R: ReadRef<'data>, -{ - section: SectionIndex, - string_section: SectionIndex, - shndx_section: SectionIndex, - symbols: &'data [Elf::Sym], - strings: StringTable<'data, R>, - shndx: &'data [U32<Elf::Endian>], -} - -impl<'data, Elf: FileHeader, R: ReadRef<'data>> Default for SymbolTable<'data, Elf, R> { - fn default() -> Self { - SymbolTable { - section: SectionIndex(0), - string_section: SectionIndex(0), - shndx_section: SectionIndex(0), - symbols: &[], - strings: Default::default(), - shndx: &[], - } - } -} - -impl<'data, Elf: FileHeader, R: ReadRef<'data>> SymbolTable<'data, Elf, R> { - /// Parse the given symbol table section. - pub fn parse( - endian: Elf::Endian, - data: R, - sections: &SectionTable<'data, Elf, R>, - section_index: SectionIndex, - section: &Elf::SectionHeader, - ) -> read::Result<SymbolTable<'data, Elf, R>> { - debug_assert!( - section.sh_type(endian) == elf::SHT_DYNSYM - || section.sh_type(endian) == elf::SHT_SYMTAB - ); - - let symbols = section - .data_as_array(endian, data) - .read_error("Invalid ELF symbol table data")?; - - let link = SectionIndex(section.sh_link(endian) as usize); - let strings = sections.strings(endian, data, link)?; - - let mut shndx_section = SectionIndex(0); - let mut shndx = &[][..]; - for (i, s) in sections.iter().enumerate() { - if s.sh_type(endian) == elf::SHT_SYMTAB_SHNDX - && s.sh_link(endian) as usize == section_index.0 - { - shndx_section = SectionIndex(i); - shndx = s - .data_as_array(endian, data) - .read_error("Invalid ELF symtab_shndx data")?; - } - } - - Ok(SymbolTable { - section: section_index, - string_section: link, - symbols, - strings, - shndx, - shndx_section, - }) - } - - /// Return the section index of this symbol table. - #[inline] - pub fn section(&self) -> SectionIndex { - self.section - } - - /// Return the section index of the shndx table. - #[inline] - pub fn shndx_section(&self) -> SectionIndex { - self.shndx_section - } - - /// Return the section index of the linked string table. - #[inline] - pub fn string_section(&self) -> SectionIndex { - self.string_section - } - - /// Return the string table used for the symbol names. - #[inline] - pub fn strings(&self) -> StringTable<'data, R> { - self.strings - } - - /// Return the symbol table. - #[inline] - pub fn symbols(&self) -> &'data [Elf::Sym] { - self.symbols - } - - /// Iterate over the symbols. - #[inline] - pub fn iter(&self) -> slice::Iter<'data, Elf::Sym> { - self.symbols.iter() - } - - /// Return true if the symbol table is empty. - #[inline] - pub fn is_empty(&self) -> bool { - self.symbols.is_empty() - } - - /// The number of symbols. - #[inline] - pub fn len(&self) -> usize { - self.symbols.len() - } - - /// Return the symbol at the given index. - pub fn symbol(&self, index: usize) -> read::Result<&'data Elf::Sym> { - self.symbols - .get(index) - .read_error("Invalid ELF symbol index") - } - - /// Return the extended section index for the given symbol if present. - #[inline] - pub fn shndx(&self, endian: Elf::Endian, index: usize) -> Option<u32> { - self.shndx.get(index).map(|x| x.get(endian)) - } - - /// Return the section index for the given symbol. - /// - /// This uses the extended section index if present. - pub fn symbol_section( - &self, - endian: Elf::Endian, - symbol: &'data Elf::Sym, - index: usize, - ) -> read::Result<Option<SectionIndex>> { - match symbol.st_shndx(endian) { - elf::SHN_UNDEF => Ok(None), - elf::SHN_XINDEX => self - .shndx(endian, index) - .read_error("Missing ELF symbol extended index") - .map(|index| Some(SectionIndex(index as usize))), - shndx if shndx < elf::SHN_LORESERVE => Ok(Some(SectionIndex(shndx.into()))), - _ => Ok(None), - } - } - - /// Return the symbol name for the given symbol. - pub fn symbol_name( - &self, - endian: Elf::Endian, - symbol: &'data Elf::Sym, - ) -> read::Result<&'data [u8]> { - symbol.name(endian, self.strings) - } - - /// Construct a map from addresses to a user-defined map entry. - pub fn map<Entry: SymbolMapEntry, F: Fn(&'data Elf::Sym) -> Option<Entry>>( - &self, - endian: Elf::Endian, - f: F, - ) -> SymbolMap<Entry> { - let mut symbols = Vec::with_capacity(self.symbols.len()); - for symbol in self.symbols { - if !symbol.is_definition(endian) { - continue; - } - if let Some(entry) = f(symbol) { - symbols.push(entry); - } - } - SymbolMap::new(symbols) - } -} - -/// A symbol table in an [`ElfFile32`](super::ElfFile32). -pub type ElfSymbolTable32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSymbolTable<'data, 'file, elf::FileHeader32<Endian>, R>; -/// A symbol table in an [`ElfFile32`](super::ElfFile32). -pub type ElfSymbolTable64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSymbolTable<'data, 'file, elf::FileHeader64<Endian>, R>; - -/// A symbol table in an [`ElfFile`](super::ElfFile). -#[derive(Debug, Clone, Copy)] -pub struct ElfSymbolTable<'data, 'file, Elf, R = &'data [u8]> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - pub(super) endian: Elf::Endian, - pub(super) symbols: &'file SymbolTable<'data, Elf, R>, -} - -impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> read::private::Sealed - for ElfSymbolTable<'data, 'file, Elf, R> -{ -} - -impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data> - for ElfSymbolTable<'data, 'file, Elf, R> -{ - type Symbol = ElfSymbol<'data, 'file, Elf, R>; - type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf, R>; - - fn symbols(&self) -> Self::SymbolIterator { - ElfSymbolIterator { - endian: self.endian, - symbols: self.symbols, - index: 0, - } - } - - fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<Self::Symbol> { - let symbol = self.symbols.symbol(index.0)?; - Ok(ElfSymbol { - endian: self.endian, - symbols: self.symbols, - index, - symbol, - }) - } -} - -/// An iterator for the symbols in an [`ElfFile32`](super::ElfFile32). -pub type ElfSymbolIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSymbolIterator<'data, 'file, elf::FileHeader32<Endian>, R>; -/// An iterator for the symbols in an [`ElfFile64`](super::ElfFile64). -pub type ElfSymbolIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSymbolIterator<'data, 'file, elf::FileHeader64<Endian>, R>; - -/// An iterator for the symbols in an [`ElfFile`](super::ElfFile). -pub struct ElfSymbolIterator<'data, 'file, Elf, R = &'data [u8]> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - pub(super) endian: Elf::Endian, - pub(super) symbols: &'file SymbolTable<'data, Elf, R>, - pub(super) index: usize, -} - -impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> fmt::Debug - for ElfSymbolIterator<'data, 'file, Elf, R> -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ElfSymbolIterator").finish() - } -} - -impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> Iterator - for ElfSymbolIterator<'data, 'file, Elf, R> -{ - type Item = ElfSymbol<'data, 'file, Elf, R>; - - fn next(&mut self) -> Option<Self::Item> { - let index = self.index; - let symbol = self.symbols.symbols.get(index)?; - self.index += 1; - Some(ElfSymbol { - endian: self.endian, - symbols: self.symbols, - index: SymbolIndex(index), - symbol, - }) - } -} - -/// A symbol in an [`ElfFile32`](super::ElfFile32). -pub type ElfSymbol32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSymbol<'data, 'file, elf::FileHeader32<Endian>, R>; -/// A symbol in an [`ElfFile64`](super::ElfFile64). -pub type ElfSymbol64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - ElfSymbol<'data, 'file, elf::FileHeader64<Endian>, R>; - -/// A symbol in an [`ElfFile`](super::ElfFile). -/// -/// Most functionality is provided by the [`ObjectSymbol`] trait implementation. -#[derive(Debug, Clone, Copy)] -pub struct ElfSymbol<'data, 'file, Elf, R = &'data [u8]> -where - Elf: FileHeader, - R: ReadRef<'data>, -{ - pub(super) endian: Elf::Endian, - pub(super) symbols: &'file SymbolTable<'data, Elf, R>, - pub(super) index: SymbolIndex, - pub(super) symbol: &'data Elf::Sym, -} - -impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSymbol<'data, 'file, Elf, R> { - /// Return a reference to the raw symbol structure. - #[inline] - pub fn raw_symbol(&self) -> &'data Elf::Sym { - self.symbol - } -} - -impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> read::private::Sealed - for ElfSymbol<'data, 'file, Elf, R> -{ -} - -impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> - for ElfSymbol<'data, 'file, Elf, R> -{ - #[inline] - fn index(&self) -> SymbolIndex { - self.index - } - - fn name_bytes(&self) -> read::Result<&'data [u8]> { - self.symbol.name(self.endian, self.symbols.strings()) - } - - fn name(&self) -> read::Result<&'data str> { - let name = self.name_bytes()?; - str::from_utf8(name) - .ok() - .read_error("Non UTF-8 ELF symbol name") - } - - #[inline] - fn address(&self) -> u64 { - self.symbol.st_value(self.endian).into() - } - - #[inline] - fn size(&self) -> u64 { - self.symbol.st_size(self.endian).into() - } - - fn kind(&self) -> SymbolKind { - match self.symbol.st_type() { - elf::STT_NOTYPE if self.index.0 == 0 => SymbolKind::Null, - elf::STT_NOTYPE => SymbolKind::Unknown, - elf::STT_OBJECT | elf::STT_COMMON => SymbolKind::Data, - elf::STT_FUNC | elf::STT_GNU_IFUNC => SymbolKind::Text, - elf::STT_SECTION => SymbolKind::Section, - elf::STT_FILE => SymbolKind::File, - elf::STT_TLS => SymbolKind::Tls, - _ => SymbolKind::Unknown, - } - } - - fn section(&self) -> SymbolSection { - match self.symbol.st_shndx(self.endian) { - elf::SHN_UNDEF => SymbolSection::Undefined, - elf::SHN_ABS => { - if self.symbol.st_type() == elf::STT_FILE { - SymbolSection::None - } else { - SymbolSection::Absolute - } - } - elf::SHN_COMMON => SymbolSection::Common, - elf::SHN_XINDEX => match self.symbols.shndx(self.endian, self.index.0) { - Some(index) => SymbolSection::Section(SectionIndex(index as usize)), - None => SymbolSection::Unknown, - }, - index if index < elf::SHN_LORESERVE => { - SymbolSection::Section(SectionIndex(index as usize)) - } - _ => SymbolSection::Unknown, - } - } - - #[inline] - fn is_undefined(&self) -> bool { - self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF - } - - #[inline] - fn is_definition(&self) -> bool { - self.symbol.is_definition(self.endian) - } - - #[inline] - fn is_common(&self) -> bool { - self.symbol.st_shndx(self.endian) == elf::SHN_COMMON - } - - #[inline] - fn is_weak(&self) -> bool { - self.symbol.st_bind() == elf::STB_WEAK - } - - fn scope(&self) -> SymbolScope { - if self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF { - SymbolScope::Unknown - } else { - match self.symbol.st_bind() { - elf::STB_LOCAL => SymbolScope::Compilation, - elf::STB_GLOBAL | elf::STB_WEAK => { - if self.symbol.st_visibility() == elf::STV_HIDDEN { - SymbolScope::Linkage - } else { - SymbolScope::Dynamic - } - } - _ => SymbolScope::Unknown, - } - } - } - - #[inline] - fn is_global(&self) -> bool { - self.symbol.st_bind() != elf::STB_LOCAL - } - - #[inline] - fn is_local(&self) -> bool { - self.symbol.st_bind() == elf::STB_LOCAL - } - - #[inline] - fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> { - SymbolFlags::Elf { - st_info: self.symbol.st_info(), - st_other: self.symbol.st_other(), - } - } -} - -/// A trait for generic access to [`elf::Sym32`] and [`elf::Sym64`]. -#[allow(missing_docs)] -pub trait Sym: Debug + Pod { - type Word: Into<u64>; - type Endian: endian::Endian; - - fn st_name(&self, endian: Self::Endian) -> u32; - fn st_info(&self) -> u8; - fn st_bind(&self) -> u8; - fn st_type(&self) -> u8; - fn st_other(&self) -> u8; - fn st_visibility(&self) -> u8; - fn st_shndx(&self, endian: Self::Endian) -> u16; - fn st_value(&self, endian: Self::Endian) -> Self::Word; - fn st_size(&self, endian: Self::Endian) -> Self::Word; - - /// Parse the symbol 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.st_name(endian)) - .read_error("Invalid ELF symbol name offset") - } - - /// Return true if the symbol is undefined. - #[inline] - fn is_undefined(&self, endian: Self::Endian) -> bool { - self.st_shndx(endian) == elf::SHN_UNDEF - } - - /// Return true if the symbol is a definition of a function or data object. - fn is_definition(&self, endian: Self::Endian) -> bool { - let shndx = self.st_shndx(endian); - if shndx == elf::SHN_UNDEF || (shndx >= elf::SHN_LORESERVE && shndx != elf::SHN_XINDEX) { - return false; - } - match self.st_type() { - elf::STT_NOTYPE => self.st_size(endian).into() != 0, - elf::STT_FUNC | elf::STT_OBJECT => true, - _ => false, - } - } -} - -impl<Endian: endian::Endian> Sym for elf::Sym32<Endian> { - type Word = u32; - type Endian = Endian; - - #[inline] - fn st_name(&self, endian: Self::Endian) -> u32 { - self.st_name.get(endian) - } - - #[inline] - fn st_info(&self) -> u8 { - self.st_info - } - - #[inline] - fn st_bind(&self) -> u8 { - self.st_bind() - } - - #[inline] - fn st_type(&self) -> u8 { - self.st_type() - } - - #[inline] - fn st_other(&self) -> u8 { - self.st_other - } - - #[inline] - fn st_visibility(&self) -> u8 { - self.st_visibility() - } - - #[inline] - fn st_shndx(&self, endian: Self::Endian) -> u16 { - self.st_shndx.get(endian) - } - - #[inline] - fn st_value(&self, endian: Self::Endian) -> Self::Word { - self.st_value.get(endian) - } - - #[inline] - fn st_size(&self, endian: Self::Endian) -> Self::Word { - self.st_size.get(endian) - } -} - -impl<Endian: endian::Endian> Sym for elf::Sym64<Endian> { - type Word = u64; - type Endian = Endian; - - #[inline] - fn st_name(&self, endian: Self::Endian) -> u32 { - self.st_name.get(endian) - } - - #[inline] - fn st_info(&self) -> u8 { - self.st_info - } - - #[inline] - fn st_bind(&self) -> u8 { - self.st_bind() - } - - #[inline] - fn st_type(&self) -> u8 { - self.st_type() - } - - #[inline] - fn st_other(&self) -> u8 { - self.st_other - } - - #[inline] - fn st_visibility(&self) -> u8 { - self.st_visibility() - } - - #[inline] - fn st_shndx(&self, endian: Self::Endian) -> u16 { - self.st_shndx.get(endian) - } - - #[inline] - fn st_value(&self, endian: Self::Endian) -> Self::Word { - self.st_value.get(endian) - } - - #[inline] - fn st_size(&self, endian: Self::Endian) -> Self::Word { - self.st_size.get(endian) - } -} diff --git a/vendor/object/src/read/elf/version.rs b/vendor/object/src/read/elf/version.rs deleted file mode 100644 index 28eeed0..0000000 --- a/vendor/object/src/read/elf/version.rs +++ /dev/null @@ -1,424 +0,0 @@ -use alloc::vec::Vec; - -use crate::read::{Bytes, ReadError, ReadRef, Result, StringTable}; -use crate::{elf, endian}; - -use super::FileHeader; - -/// A version index. -#[derive(Debug, Default, Clone, Copy)] -pub struct VersionIndex(pub u16); - -impl VersionIndex { - /// Return the version index. - pub fn index(&self) -> u16 { - self.0 & elf::VERSYM_VERSION - } - - /// Return true if it is the local index. - pub fn is_local(&self) -> bool { - self.index() == elf::VER_NDX_LOCAL - } - - /// Return true if it is the global index. - pub fn is_global(&self) -> bool { - self.index() == elf::VER_NDX_GLOBAL - } - - /// Return the hidden flag. - pub fn is_hidden(&self) -> bool { - self.0 & elf::VERSYM_HIDDEN != 0 - } -} - -/// A version definition or requirement. -/// -/// This is derived from entries in the [`elf::SHT_GNU_VERDEF`] and [`elf::SHT_GNU_VERNEED`] sections. -#[derive(Debug, Default, Clone, Copy)] -pub struct Version<'data> { - name: &'data [u8], - hash: u32, - // Used to keep track of valid indices in `VersionTable`. - valid: bool, -} - -impl<'data> Version<'data> { - /// Return the version name. - pub fn name(&self) -> &'data [u8] { - self.name - } - - /// Return hash of the version name. - pub fn hash(&self) -> u32 { - self.hash - } -} - -/// A table of version definitions and requirements. -/// -/// It allows looking up the version information for a given symbol index. -/// -/// This is derived from entries in the [`elf::SHT_GNU_VERSYM`], [`elf::SHT_GNU_VERDEF`] -/// and [`elf::SHT_GNU_VERNEED`] sections. -/// -/// Returned by [`SectionTable::versions`](super::SectionTable::versions). -#[derive(Debug, Clone)] -pub struct VersionTable<'data, Elf: FileHeader> { - symbols: &'data [elf::Versym<Elf::Endian>], - versions: Vec<Version<'data>>, -} - -impl<'data, Elf: FileHeader> Default for VersionTable<'data, Elf> { - fn default() -> Self { - VersionTable { - symbols: &[], - versions: Vec::new(), - } - } -} - -impl<'data, Elf: FileHeader> VersionTable<'data, Elf> { - /// Parse the version sections. - pub fn parse<R: ReadRef<'data>>( - endian: Elf::Endian, - versyms: &'data [elf::Versym<Elf::Endian>], - verdefs: Option<VerdefIterator<'data, Elf>>, - verneeds: Option<VerneedIterator<'data, Elf>>, - strings: StringTable<'data, R>, - ) -> Result<Self> { - let mut max_index = 0; - if let Some(mut verdefs) = verdefs.clone() { - while let Some((verdef, _)) = verdefs.next()? { - if verdef.vd_flags.get(endian) & elf::VER_FLG_BASE != 0 { - continue; - } - let index = verdef.vd_ndx.get(endian) & elf::VERSYM_VERSION; - if max_index < index { - max_index = index; - } - } - } - if let Some(mut verneeds) = verneeds.clone() { - while let Some((_, mut vernauxs)) = verneeds.next()? { - while let Some(vernaux) = vernauxs.next()? { - let index = vernaux.vna_other.get(endian) & elf::VERSYM_VERSION; - if max_index < index { - max_index = index; - } - } - } - } - - // Indices should be sequential, but this could be up to - // 32k * size_of::<Version>() if max_index is bad. - let mut versions = vec![Version::default(); max_index as usize + 1]; - - if let Some(mut verdefs) = verdefs { - while let Some((verdef, mut verdauxs)) = verdefs.next()? { - if verdef.vd_flags.get(endian) & elf::VER_FLG_BASE != 0 { - continue; - } - let index = verdef.vd_ndx.get(endian) & elf::VERSYM_VERSION; - if index <= elf::VER_NDX_GLOBAL { - // TODO: return error? - continue; - } - if let Some(verdaux) = verdauxs.next()? { - versions[usize::from(index)] = Version { - name: verdaux.name(endian, strings)?, - hash: verdef.vd_hash.get(endian), - valid: true, - }; - } - } - } - if let Some(mut verneeds) = verneeds { - while let Some((_, mut vernauxs)) = verneeds.next()? { - while let Some(vernaux) = vernauxs.next()? { - let index = vernaux.vna_other.get(endian) & elf::VERSYM_VERSION; - if index <= elf::VER_NDX_GLOBAL { - // TODO: return error? - continue; - } - versions[usize::from(index)] = Version { - name: vernaux.name(endian, strings)?, - hash: vernaux.vna_hash.get(endian), - valid: true, - }; - } - } - } - - Ok(VersionTable { - symbols: versyms, - versions, - }) - } - - /// Return true if the version table is empty. - pub fn is_empty(&self) -> bool { - self.symbols.is_empty() - } - - /// Return version index for a given symbol index. - pub fn version_index(&self, endian: Elf::Endian, index: usize) -> VersionIndex { - let version_index = match self.symbols.get(index) { - Some(x) => x.0.get(endian), - // Ideally this would be VER_NDX_LOCAL for undefined symbols, - // but currently there are no checks that need this distinction. - None => elf::VER_NDX_GLOBAL, - }; - VersionIndex(version_index) - } - - /// Return version information for a given symbol version index. - /// - /// Returns `Ok(None)` for local and global versions. - /// Returns `Err(_)` if index is invalid. - pub fn version(&self, index: VersionIndex) -> Result<Option<&Version<'data>>> { - if index.index() <= elf::VER_NDX_GLOBAL { - return Ok(None); - } - self.versions - .get(usize::from(index.index())) - .filter(|version| version.valid) - .read_error("Invalid ELF symbol version index") - .map(Some) - } - - /// Return true if the given symbol index satisfies the requirements of `need`. - /// - /// Returns false for any error. - /// - /// Note: this function hasn't been fully tested and is likely to be incomplete. - pub fn matches(&self, endian: Elf::Endian, index: usize, need: Option<&Version<'_>>) -> bool { - let version_index = self.version_index(endian, index); - let def = match self.version(version_index) { - Ok(def) => def, - Err(_) => return false, - }; - match (def, need) { - (Some(def), Some(need)) => need.hash == def.hash && need.name == def.name, - (None, Some(_need)) => { - // Version must be present if needed. - false - } - (Some(_def), None) => { - // For a dlsym call, use the newest version. - // TODO: if not a dlsym call, then use the oldest version. - !version_index.is_hidden() - } - (None, None) => true, - } - } -} - -/// An iterator for the entries in an ELF [`elf::SHT_GNU_VERDEF`] section. -#[derive(Debug, Clone)] -pub struct VerdefIterator<'data, Elf: FileHeader> { - endian: Elf::Endian, - data: Bytes<'data>, -} - -impl<'data, Elf: FileHeader> VerdefIterator<'data, Elf> { - pub(super) fn new(endian: Elf::Endian, data: &'data [u8]) -> Self { - VerdefIterator { - endian, - data: Bytes(data), - } - } - - /// Return the next `Verdef` entry. - pub fn next( - &mut self, - ) -> Result<Option<(&'data elf::Verdef<Elf::Endian>, VerdauxIterator<'data, Elf>)>> { - if self.data.is_empty() { - return Ok(None); - } - - let verdef = self - .data - .read_at::<elf::Verdef<_>>(0) - .read_error("ELF verdef is too short")?; - - let mut verdaux_data = self.data; - verdaux_data - .skip(verdef.vd_aux.get(self.endian) as usize) - .read_error("Invalid ELF vd_aux")?; - let verdaux = - VerdauxIterator::new(self.endian, verdaux_data.0, verdef.vd_cnt.get(self.endian)); - - let next = verdef.vd_next.get(self.endian); - if next != 0 { - self.data - .skip(next as usize) - .read_error("Invalid ELF vd_next")?; - } else { - self.data = Bytes(&[]); - } - Ok(Some((verdef, verdaux))) - } -} - -/// An iterator for the auxiliary records for an entry in an ELF [`elf::SHT_GNU_VERDEF`] section. -#[derive(Debug, Clone)] -pub struct VerdauxIterator<'data, Elf: FileHeader> { - endian: Elf::Endian, - data: Bytes<'data>, - count: u16, -} - -impl<'data, Elf: FileHeader> VerdauxIterator<'data, Elf> { - pub(super) fn new(endian: Elf::Endian, data: &'data [u8], count: u16) -> Self { - VerdauxIterator { - endian, - data: Bytes(data), - count, - } - } - - /// Return the next `Verdaux` entry. - pub fn next(&mut self) -> Result<Option<&'data elf::Verdaux<Elf::Endian>>> { - if self.count == 0 { - return Ok(None); - } - - let verdaux = self - .data - .read_at::<elf::Verdaux<_>>(0) - .read_error("ELF verdaux is too short")?; - - self.data - .skip(verdaux.vda_next.get(self.endian) as usize) - .read_error("Invalid ELF vda_next")?; - self.count -= 1; - Ok(Some(verdaux)) - } -} - -/// An iterator for the entries in an ELF [`elf::SHT_GNU_VERNEED`] section. -#[derive(Debug, Clone)] -pub struct VerneedIterator<'data, Elf: FileHeader> { - endian: Elf::Endian, - data: Bytes<'data>, -} - -impl<'data, Elf: FileHeader> VerneedIterator<'data, Elf> { - pub(super) fn new(endian: Elf::Endian, data: &'data [u8]) -> Self { - VerneedIterator { - endian, - data: Bytes(data), - } - } - - /// Return the next `Verneed` entry. - pub fn next( - &mut self, - ) -> Result< - Option<( - &'data elf::Verneed<Elf::Endian>, - VernauxIterator<'data, Elf>, - )>, - > { - if self.data.is_empty() { - return Ok(None); - } - - let verneed = self - .data - .read_at::<elf::Verneed<_>>(0) - .read_error("ELF verneed is too short")?; - - let mut vernaux_data = self.data; - vernaux_data - .skip(verneed.vn_aux.get(self.endian) as usize) - .read_error("Invalid ELF vn_aux")?; - let vernaux = - VernauxIterator::new(self.endian, vernaux_data.0, verneed.vn_cnt.get(self.endian)); - - let next = verneed.vn_next.get(self.endian); - if next != 0 { - self.data - .skip(next as usize) - .read_error("Invalid ELF vn_next")?; - } else { - self.data = Bytes(&[]); - } - Ok(Some((verneed, vernaux))) - } -} - -/// An iterator for the auxiliary records for an entry in an ELF [`elf::SHT_GNU_VERNEED`] section. -#[derive(Debug, Clone)] -pub struct VernauxIterator<'data, Elf: FileHeader> { - endian: Elf::Endian, - data: Bytes<'data>, - count: u16, -} - -impl<'data, Elf: FileHeader> VernauxIterator<'data, Elf> { - pub(super) fn new(endian: Elf::Endian, data: &'data [u8], count: u16) -> Self { - VernauxIterator { - endian, - data: Bytes(data), - count, - } - } - - /// Return the next `Vernaux` entry. - pub fn next(&mut self) -> Result<Option<&'data elf::Vernaux<Elf::Endian>>> { - if self.count == 0 { - return Ok(None); - } - - let vernaux = self - .data - .read_at::<elf::Vernaux<_>>(0) - .read_error("ELF vernaux is too short")?; - - self.data - .skip(vernaux.vna_next.get(self.endian) as usize) - .read_error("Invalid ELF vna_next")?; - self.count -= 1; - Ok(Some(vernaux)) - } -} - -impl<Endian: endian::Endian> elf::Verdaux<Endian> { - /// Parse the version name from the string table. - pub fn name<'data, R: ReadRef<'data>>( - &self, - endian: Endian, - strings: StringTable<'data, R>, - ) -> Result<&'data [u8]> { - strings - .get(self.vda_name.get(endian)) - .read_error("Invalid ELF vda_name") - } -} - -impl<Endian: endian::Endian> elf::Verneed<Endian> { - /// Parse the file from the string table. - pub fn file<'data, R: ReadRef<'data>>( - &self, - endian: Endian, - strings: StringTable<'data, R>, - ) -> Result<&'data [u8]> { - strings - .get(self.vn_file.get(endian)) - .read_error("Invalid ELF vn_file") - } -} - -impl<Endian: endian::Endian> elf::Vernaux<Endian> { - /// Parse the version name from the string table. - pub fn name<'data, R: ReadRef<'data>>( - &self, - endian: Endian, - strings: StringTable<'data, R>, - ) -> Result<&'data [u8]> { - strings - .get(self.vna_name.get(endian)) - .read_error("Invalid ELF vna_name") - } -} |