diff options
Diffstat (limited to 'vendor/object/src/read/elf/version.rs')
-rw-r--r-- | vendor/object/src/read/elf/version.rs | 424 |
1 files changed, 0 insertions, 424 deletions
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") - } -} |