diff options
Diffstat (limited to 'vendor/object/src/read/xcoff/symbol.rs')
-rw-r--r-- | vendor/object/src/read/xcoff/symbol.rs | 786 |
1 files changed, 0 insertions, 786 deletions
diff --git a/vendor/object/src/read/xcoff/symbol.rs b/vendor/object/src/read/xcoff/symbol.rs deleted file mode 100644 index 72651c3..0000000 --- a/vendor/object/src/read/xcoff/symbol.rs +++ /dev/null @@ -1,786 +0,0 @@ -use alloc::fmt; -use core::convert::TryInto; -use core::fmt::Debug; -use core::marker::PhantomData; -use core::str; - -use crate::endian::{BigEndian as BE, U32Bytes}; -use crate::pod::{bytes_of, Pod}; -use crate::read::util::StringTable; -use crate::xcoff; - -use crate::read::{ - self, Bytes, Error, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result, SectionIndex, - SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, SymbolSection, -}; - -use super::{FileHeader, XcoffFile}; - -/// A table of symbol entries in an XCOFF file. -/// -/// Also includes the string table used for the symbol names. -/// -/// Returned by [`FileHeader::symbols`]. -#[derive(Debug)] -pub struct SymbolTable<'data, Xcoff, R = &'data [u8]> -where - Xcoff: FileHeader, - R: ReadRef<'data>, -{ - symbols: &'data [xcoff::SymbolBytes], - strings: StringTable<'data, R>, - header: PhantomData<Xcoff>, -} - -impl<'data, Xcoff, R> Default for SymbolTable<'data, Xcoff, R> -where - Xcoff: FileHeader, - R: ReadRef<'data>, -{ - fn default() -> Self { - Self { - symbols: &[], - strings: StringTable::default(), - header: PhantomData, - } - } -} - -impl<'data, Xcoff, R> SymbolTable<'data, Xcoff, R> -where - Xcoff: FileHeader, - R: ReadRef<'data>, -{ - /// Parse the symbol table. - pub fn parse(header: Xcoff, data: R) -> Result<Self> { - let mut offset = header.f_symptr().into(); - let (symbols, strings) = if offset != 0 { - let symbols = data - .read_slice(&mut offset, header.f_nsyms() as usize) - .read_error("Invalid XCOFF symbol table offset or size")?; - - // Parse the string table. - // Note: don't update data when reading length; the length includes itself. - let length = data - .read_at::<U32Bytes<_>>(offset) - .read_error("Missing XCOFF string table")? - .get(BE); - let str_end = offset - .checked_add(length as u64) - .read_error("Invalid XCOFF string table length")?; - let strings = StringTable::new(data, offset, str_end); - - (symbols, strings) - } else { - (&[][..], StringTable::default()) - }; - - Ok(SymbolTable { - symbols, - strings, - header: PhantomData, - }) - } - - /// Return the string table used for the symbol names. - #[inline] - pub fn strings(&self) -> StringTable<'data, R> { - self.strings - } - - /// Iterate over the symbols. - #[inline] - pub fn iter<'table>(&'table self) -> SymbolIterator<'data, 'table, Xcoff, R> { - SymbolIterator { - symbols: self, - index: 0, - } - } - - /// Empty symbol iterator. - #[inline] - pub(super) fn iter_none<'table>(&'table self) -> SymbolIterator<'data, 'table, Xcoff, R> { - SymbolIterator { - symbols: self, - index: self.symbols.len(), - } - } - - /// Return the symbol entry at the given index and offset. - pub fn get<T: Pod>(&self, index: usize, offset: usize) -> Result<&'data T> { - let entry = index - .checked_add(offset) - .and_then(|x| self.symbols.get(x)) - .read_error("Invalid XCOFF symbol index")?; - let bytes = bytes_of(entry); - Bytes(bytes).read().read_error("Invalid XCOFF symbol data") - } - - /// Return the symbol at the given index. - pub fn symbol(&self, index: usize) -> Result<&'data Xcoff::Symbol> { - self.get::<Xcoff::Symbol>(index, 0) - } - - /// Return a file auxiliary symbol. - pub fn aux_file(&self, index: usize, offset: usize) -> Result<&'data Xcoff::FileAux> { - debug_assert!(self.symbol(index)?.has_aux_file()); - let aux_file = self.get::<Xcoff::FileAux>(index, offset)?; - if let Some(aux_type) = aux_file.x_auxtype() { - if aux_type != xcoff::AUX_FILE { - return Err(Error("Invalid index for file auxiliary symbol.")); - } - } - Ok(aux_file) - } - - /// Return the csect auxiliary symbol. - pub fn aux_csect(&self, index: usize, offset: usize) -> Result<&'data Xcoff::CsectAux> { - debug_assert!(self.symbol(index)?.has_aux_csect()); - let aux_csect = self.get::<Xcoff::CsectAux>(index, offset)?; - if let Some(aux_type) = aux_csect.x_auxtype() { - if aux_type != xcoff::AUX_CSECT { - return Err(Error("Invalid index/offset for csect auxiliary symbol.")); - } - } - Ok(aux_csect) - } - - /// Return true if the symbol table is empty. - #[inline] - pub fn is_empty(&self) -> bool { - self.symbols.is_empty() - } - - /// The number of symbol table entries. - /// - /// This includes auxiliary symbol table entries. - #[inline] - pub fn len(&self) -> usize { - self.symbols.len() - } -} - -/// An iterator for symbol entries in an XCOFF file. -/// -/// Yields the index and symbol structure for each symbol. -#[derive(Debug)] -pub struct SymbolIterator<'data, 'table, Xcoff, R = &'data [u8]> -where - Xcoff: FileHeader, - R: ReadRef<'data>, -{ - symbols: &'table SymbolTable<'data, Xcoff, R>, - index: usize, -} - -impl<'data, 'table, Xcoff: FileHeader, R: ReadRef<'data>> Iterator - for SymbolIterator<'data, 'table, Xcoff, R> -{ - type Item = (SymbolIndex, &'data Xcoff::Symbol); - - fn next(&mut self) -> Option<Self::Item> { - let index = self.index; - let symbol = self.symbols.symbol(index).ok()?; - self.index += 1 + symbol.n_numaux() as usize; - Some((SymbolIndex(index), symbol)) - } -} - -/// A symbol table in an [`XcoffFile32`](super::XcoffFile32). -pub type XcoffSymbolTable32<'data, 'file, R = &'data [u8]> = - XcoffSymbolTable<'data, 'file, xcoff::FileHeader32, R>; -/// A symbol table in an [`XcoffFile64`](super::XcoffFile64). -pub type XcoffSymbolTable64<'data, 'file, R = &'data [u8]> = - XcoffSymbolTable<'data, 'file, xcoff::FileHeader64, R>; - -/// A symbol table in an [`XcoffFile`]. -#[derive(Debug, Clone, Copy)] -pub struct XcoffSymbolTable<'data, 'file, Xcoff, R = &'data [u8]> -where - Xcoff: FileHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file XcoffFile<'data, Xcoff, R>, - pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>, -} - -impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed - for XcoffSymbolTable<'data, 'file, Xcoff, R> -{ -} - -impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data> - for XcoffSymbolTable<'data, 'file, Xcoff, R> -{ - type Symbol = XcoffSymbol<'data, 'file, Xcoff, R>; - type SymbolIterator = XcoffSymbolIterator<'data, 'file, Xcoff, R>; - - fn symbols(&self) -> Self::SymbolIterator { - XcoffSymbolIterator { - file: self.file, - symbols: self.symbols.iter(), - } - } - - fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<Self::Symbol> { - let symbol = self.symbols.symbol(index.0)?; - Ok(XcoffSymbol { - file: self.file, - symbols: self.symbols, - index, - symbol, - }) - } -} - -/// An iterator for the symbols in an [`XcoffFile32`](super::XcoffFile32). -pub type XcoffSymbolIterator32<'data, 'file, R = &'data [u8]> = - XcoffSymbolIterator<'data, 'file, xcoff::FileHeader32, R>; -/// An iterator for the symbols in an [`XcoffFile64`](super::XcoffFile64). -pub type XcoffSymbolIterator64<'data, 'file, R = &'data [u8]> = - XcoffSymbolIterator<'data, 'file, xcoff::FileHeader64, R>; - -/// An iterator for the symbols in an [`XcoffFile`]. -pub struct XcoffSymbolIterator<'data, 'file, Xcoff, R = &'data [u8]> -where - Xcoff: FileHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file XcoffFile<'data, Xcoff, R>, - pub(super) symbols: SymbolIterator<'data, 'file, Xcoff, R>, -} - -impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> fmt::Debug - for XcoffSymbolIterator<'data, 'file, Xcoff, R> -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("XcoffSymbolIterator").finish() - } -} - -impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> Iterator - for XcoffSymbolIterator<'data, 'file, Xcoff, R> -{ - type Item = XcoffSymbol<'data, 'file, Xcoff, R>; - - fn next(&mut self) -> Option<Self::Item> { - let (index, symbol) = self.symbols.next()?; - Some(XcoffSymbol { - file: self.file, - symbols: self.symbols.symbols, - index, - symbol, - }) - } -} - -/// A symbol in an [`XcoffFile32`](super::XcoffFile32). -pub type XcoffSymbol32<'data, 'file, R = &'data [u8]> = - XcoffSymbol<'data, 'file, xcoff::FileHeader32, R>; -/// A symbol in an [`XcoffFile64`](super::XcoffFile64). -pub type XcoffSymbol64<'data, 'file, R = &'data [u8]> = - XcoffSymbol<'data, 'file, xcoff::FileHeader64, R>; - -/// A symbol in an [`XcoffFile`]. -/// -/// Most functionality is provided by the [`ObjectSymbol`] trait implementation. -#[derive(Debug, Clone, Copy)] -pub struct XcoffSymbol<'data, 'file, Xcoff, R = &'data [u8]> -where - Xcoff: FileHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file XcoffFile<'data, Xcoff, R>, - pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>, - pub(super) index: SymbolIndex, - pub(super) symbol: &'data Xcoff::Symbol, -} - -impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed - for XcoffSymbol<'data, 'file, Xcoff, R> -{ -} - -impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> - for XcoffSymbol<'data, 'file, Xcoff, R> -{ - #[inline] - fn index(&self) -> SymbolIndex { - self.index - } - - fn name_bytes(&self) -> Result<&'data [u8]> { - if self.symbol.has_aux_file() { - // By convention the file name is in the first auxiliary entry. - self.symbols - .aux_file(self.index.0, 1)? - .fname(self.symbols.strings) - } else { - self.symbol.name(self.symbols.strings) - } - } - - fn name(&self) -> Result<&'data str> { - let name = self.name_bytes()?; - str::from_utf8(name) - .ok() - .read_error("Non UTF-8 XCOFF symbol name") - } - - #[inline] - fn address(&self) -> u64 { - match self.symbol.n_sclass() { - // Relocatable address. - xcoff::C_EXT - | xcoff::C_WEAKEXT - | xcoff::C_HIDEXT - | xcoff::C_FCN - | xcoff::C_BLOCK - | xcoff::C_STAT - | xcoff::C_INFO => self.symbol.n_value().into(), - _ => 0, - } - } - - #[inline] - fn size(&self) -> u64 { - if self.symbol.has_aux_csect() { - // XCOFF32 must have the csect auxiliary entry as the last auxiliary entry. - // XCOFF64 doesn't require this, but conventionally does. - if let Ok(aux_csect) = self - .file - .symbols - .aux_csect(self.index.0, self.symbol.n_numaux() as usize) - { - let sym_type = aux_csect.sym_type(); - if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM { - return aux_csect.x_scnlen(); - } - } - } - 0 - } - - fn kind(&self) -> SymbolKind { - if self.symbol.has_aux_csect() { - if let Ok(aux_csect) = self - .file - .symbols - .aux_csect(self.index.0, self.symbol.n_numaux() as usize) - { - let sym_type = aux_csect.sym_type(); - if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM { - return match aux_csect.x_smclas() { - xcoff::XMC_PR | xcoff::XMC_GL => SymbolKind::Text, - xcoff::XMC_RO | xcoff::XMC_RW | xcoff::XMC_TD | xcoff::XMC_BS => { - SymbolKind::Data - } - xcoff::XMC_TL | xcoff::XMC_UL => SymbolKind::Tls, - xcoff::XMC_DS | xcoff::XMC_TC0 | xcoff::XMC_TC => { - // `Metadata` might be a better kind for these if we had it. - SymbolKind::Data - } - _ => SymbolKind::Unknown, - }; - } else if sym_type == xcoff::XTY_LD { - // A function entry point. Neither `Text` nor `Label` are a good fit for this. - return SymbolKind::Text; - } else if sym_type == xcoff::XTY_ER { - return SymbolKind::Unknown; - } - } - } - match self.symbol.n_sclass() { - xcoff::C_NULL => SymbolKind::Null, - xcoff::C_FILE => SymbolKind::File, - _ => SymbolKind::Unknown, - } - } - - fn section(&self) -> SymbolSection { - match self.symbol.n_scnum() { - xcoff::N_ABS => SymbolSection::Absolute, - xcoff::N_UNDEF => SymbolSection::Undefined, - xcoff::N_DEBUG => SymbolSection::None, - index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)), - _ => SymbolSection::Unknown, - } - } - - #[inline] - fn is_undefined(&self) -> bool { - self.symbol.is_undefined() - } - - /// Return true if the symbol is a definition of a function or data object. - #[inline] - fn is_definition(&self) -> bool { - if self.symbol.n_scnum() <= 0 { - return false; - } - if self.symbol.has_aux_csect() { - if let Ok(aux_csect) = self - .symbols - .aux_csect(self.index.0, self.symbol.n_numaux() as usize) - { - let sym_type = aux_csect.sym_type(); - sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_LD || sym_type == xcoff::XTY_CM - } else { - false - } - } else { - false - } - } - - #[inline] - fn is_common(&self) -> bool { - self.symbol.n_sclass() == xcoff::C_EXT && self.symbol.n_scnum() == xcoff::N_UNDEF - } - - #[inline] - fn is_weak(&self) -> bool { - self.symbol.n_sclass() == xcoff::C_WEAKEXT - } - - fn scope(&self) -> SymbolScope { - if self.symbol.n_scnum() == xcoff::N_UNDEF { - SymbolScope::Unknown - } else { - match self.symbol.n_sclass() { - xcoff::C_EXT | xcoff::C_WEAKEXT => { - let visibility = self.symbol.n_type() & xcoff::SYM_V_MASK; - if visibility == xcoff::SYM_V_HIDDEN { - SymbolScope::Linkage - } else { - SymbolScope::Dynamic - } - } - _ => SymbolScope::Compilation, - } - } - } - - #[inline] - fn is_global(&self) -> bool { - match self.symbol.n_sclass() { - xcoff::C_EXT | xcoff::C_WEAKEXT => true, - _ => false, - } - } - - #[inline] - fn is_local(&self) -> bool { - !self.is_global() - } - - #[inline] - fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> { - let mut x_smtyp = 0; - let mut x_smclas = 0; - let mut containing_csect = None; - if self.symbol.has_aux_csect() { - if let Ok(aux_csect) = self - .file - .symbols - .aux_csect(self.index.0, self.symbol.n_numaux() as usize) - { - x_smtyp = aux_csect.x_smtyp(); - x_smclas = aux_csect.x_smclas(); - if aux_csect.sym_type() == xcoff::XTY_LD { - containing_csect = Some(SymbolIndex(aux_csect.x_scnlen() as usize)) - } - } - } - SymbolFlags::Xcoff { - n_sclass: self.symbol.n_sclass(), - x_smtyp, - x_smclas, - containing_csect, - } - } -} - -/// A trait for generic access to [`xcoff::Symbol32`] and [`xcoff::Symbol64`]. -#[allow(missing_docs)] -pub trait Symbol: Debug + Pod { - type Word: Into<u64>; - - fn n_value(&self) -> Self::Word; - fn n_scnum(&self) -> i16; - fn n_type(&self) -> u16; - fn n_sclass(&self) -> u8; - fn n_numaux(&self) -> u8; - - fn name_offset(&self) -> Option<u32>; - fn name<'data, R: ReadRef<'data>>( - &'data self, - strings: StringTable<'data, R>, - ) -> Result<&'data [u8]>; - - /// Return true if the symbol is undefined. - #[inline] - fn is_undefined(&self) -> bool { - let n_sclass = self.n_sclass(); - (n_sclass == xcoff::C_EXT || n_sclass == xcoff::C_WEAKEXT) - && self.n_scnum() == xcoff::N_UNDEF - } - - /// Return true if the symbol has file auxiliary entry. - fn has_aux_file(&self) -> bool { - self.n_numaux() > 0 && self.n_sclass() == xcoff::C_FILE - } - - /// Return true if the symbol has csect auxiliary entry. - /// - /// A csect auxiliary entry is required for each symbol table entry that has - /// a storage class value of C_EXT, C_WEAKEXT, or C_HIDEXT. - fn has_aux_csect(&self) -> bool { - let sclass = self.n_sclass(); - self.n_numaux() > 0 - && (sclass == xcoff::C_EXT || sclass == xcoff::C_WEAKEXT || sclass == xcoff::C_HIDEXT) - } -} - -impl Symbol for xcoff::Symbol64 { - type Word = u64; - - fn n_value(&self) -> Self::Word { - self.n_value.get(BE) - } - - fn n_scnum(&self) -> i16 { - self.n_scnum.get(BE) - } - - fn n_type(&self) -> u16 { - self.n_type.get(BE) - } - - fn n_sclass(&self) -> u8 { - self.n_sclass - } - - fn n_numaux(&self) -> u8 { - self.n_numaux - } - - fn name_offset(&self) -> Option<u32> { - Some(self.n_offset.get(BE)) - } - - /// Parse the symbol name for XCOFF64. - fn name<'data, R: ReadRef<'data>>( - &'data self, - strings: StringTable<'data, R>, - ) -> Result<&'data [u8]> { - strings - .get(self.n_offset.get(BE)) - .read_error("Invalid XCOFF symbol name offset") - } -} - -impl Symbol for xcoff::Symbol32 { - type Word = u32; - - fn n_value(&self) -> Self::Word { - self.n_value.get(BE) - } - - fn n_scnum(&self) -> i16 { - self.n_scnum.get(BE) - } - - fn n_type(&self) -> u16 { - self.n_type.get(BE) - } - - fn n_sclass(&self) -> u8 { - self.n_sclass - } - - fn n_numaux(&self) -> u8 { - self.n_numaux - } - - fn name_offset(&self) -> Option<u32> { - if self.n_name[0] == 0 { - let offset = u32::from_be_bytes(self.n_name[4..8].try_into().unwrap()); - Some(offset) - } else { - None - } - } - - /// Parse the symbol name for XCOFF32. - fn name<'data, R: ReadRef<'data>>( - &'data self, - strings: StringTable<'data, R>, - ) -> Result<&'data [u8]> { - if let Some(offset) = self.name_offset() { - // If the name starts with 0 then the last 4 bytes are a string table offset. - strings - .get(offset) - .read_error("Invalid XCOFF symbol name offset") - } else { - // The name is inline and padded with nulls. - Ok(match memchr::memchr(b'\0', &self.n_name) { - Some(end) => &self.n_name[..end], - None => &self.n_name, - }) - } - } -} - -/// A trait for generic access to [`xcoff::FileAux32`] and [`xcoff::FileAux64`]. -#[allow(missing_docs)] -pub trait FileAux: Debug + Pod { - fn x_fname(&self) -> &[u8; 8]; - fn x_ftype(&self) -> u8; - fn x_auxtype(&self) -> Option<u8>; - - fn name_offset(&self) -> Option<u32> { - let x_fname = self.x_fname(); - if x_fname[0] == 0 { - Some(u32::from_be_bytes(x_fname[4..8].try_into().unwrap())) - } else { - None - } - } - - /// Parse the x_fname field, which may be an inline string or a string table offset. - fn fname<'data, R: ReadRef<'data>>( - &'data self, - strings: StringTable<'data, R>, - ) -> Result<&'data [u8]> { - if let Some(offset) = self.name_offset() { - // If the name starts with 0 then the last 4 bytes are a string table offset. - strings - .get(offset) - .read_error("Invalid XCOFF symbol name offset") - } else { - // The name is inline and padded with nulls. - let x_fname = self.x_fname(); - Ok(match memchr::memchr(b'\0', x_fname) { - Some(end) => &x_fname[..end], - None => x_fname, - }) - } - } -} - -impl FileAux for xcoff::FileAux64 { - fn x_fname(&self) -> &[u8; 8] { - &self.x_fname - } - - fn x_ftype(&self) -> u8 { - self.x_ftype - } - - fn x_auxtype(&self) -> Option<u8> { - Some(self.x_auxtype) - } -} - -impl FileAux for xcoff::FileAux32 { - fn x_fname(&self) -> &[u8; 8] { - &self.x_fname - } - - fn x_ftype(&self) -> u8 { - self.x_ftype - } - - fn x_auxtype(&self) -> Option<u8> { - None - } -} - -/// A trait for generic access to [`xcoff::CsectAux32`] and [`xcoff::CsectAux64`]. -#[allow(missing_docs)] -pub trait CsectAux: Debug + Pod { - fn x_scnlen(&self) -> u64; - fn x_parmhash(&self) -> u32; - fn x_snhash(&self) -> u16; - fn x_smtyp(&self) -> u8; - fn x_smclas(&self) -> u8; - fn x_stab(&self) -> Option<u32>; - fn x_snstab(&self) -> Option<u16>; - fn x_auxtype(&self) -> Option<u8>; - - fn alignment(&self) -> u8 { - self.x_smtyp() >> 3 - } - fn sym_type(&self) -> u8 { - self.x_smtyp() & 0x07 - } -} - -impl CsectAux for xcoff::CsectAux64 { - fn x_scnlen(&self) -> u64 { - self.x_scnlen_lo.get(BE) as u64 | ((self.x_scnlen_hi.get(BE) as u64) << 32) - } - - fn x_parmhash(&self) -> u32 { - self.x_parmhash.get(BE) - } - - fn x_snhash(&self) -> u16 { - self.x_snhash.get(BE) - } - - fn x_smtyp(&self) -> u8 { - self.x_smtyp - } - - fn x_smclas(&self) -> u8 { - self.x_smclas - } - - fn x_stab(&self) -> Option<u32> { - None - } - - fn x_snstab(&self) -> Option<u16> { - None - } - - fn x_auxtype(&self) -> Option<u8> { - Some(self.x_auxtype) - } -} - -impl CsectAux for xcoff::CsectAux32 { - fn x_scnlen(&self) -> u64 { - self.x_scnlen.get(BE) as u64 - } - - fn x_parmhash(&self) -> u32 { - self.x_parmhash.get(BE) - } - - fn x_snhash(&self) -> u16 { - self.x_snhash.get(BE) - } - - fn x_smtyp(&self) -> u8 { - self.x_smtyp - } - - fn x_smclas(&self) -> u8 { - self.x_smclas - } - - fn x_stab(&self) -> Option<u32> { - Some(self.x_stab.get(BE)) - } - - fn x_snstab(&self) -> Option<u16> { - Some(self.x_snstab.get(BE)) - } - - fn x_auxtype(&self) -> Option<u8> { - None - } -} |