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