diff options
Diffstat (limited to 'vendor/object-0.26.2/src/read/coff/comdat.rs')
-rw-r--r-- | vendor/object-0.26.2/src/read/coff/comdat.rs | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/vendor/object-0.26.2/src/read/coff/comdat.rs b/vendor/object-0.26.2/src/read/coff/comdat.rs new file mode 100644 index 000000000..2d87a6d99 --- /dev/null +++ b/vendor/object-0.26.2/src/read/coff/comdat.rs @@ -0,0 +1,162 @@ +use core::str; + +use crate::endian::LittleEndian as LE; +use crate::pe; +use crate::read::{ + self, ComdatKind, ObjectComdat, ReadError, ReadRef, Result, SectionIndex, SymbolIndex, +}; + +use super::CoffFile; + +/// An iterator over the COMDAT section groups of a `CoffFile`. +#[derive(Debug)] +pub struct CoffComdatIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> { + pub(super) file: &'file CoffFile<'data, R>, + pub(super) index: usize, +} + +impl<'data, 'file, R: ReadRef<'data>> Iterator for CoffComdatIterator<'data, 'file, R> { + type Item = CoffComdat<'data, 'file, R>; + + fn next(&mut self) -> Option<Self::Item> { + loop { + let index = self.index; + let symbol = self.file.common.symbols.symbol(index).ok()?; + self.index += 1 + symbol.number_of_aux_symbols as usize; + if let Some(comdat) = CoffComdat::parse(self.file, symbol, index) { + return Some(comdat); + } + } + } +} + +/// A COMDAT section group of a `CoffFile`. +#[derive(Debug)] +pub struct CoffComdat<'data, 'file, R: ReadRef<'data> = &'data [u8]> { + file: &'file CoffFile<'data, R>, + symbol_index: SymbolIndex, + symbol: &'data pe::ImageSymbol, + selection: u8, +} + +impl<'data, 'file, R: ReadRef<'data>> CoffComdat<'data, 'file, R> { + fn parse( + file: &'file CoffFile<'data, R>, + section_symbol: &'data pe::ImageSymbol, + index: usize, + ) -> Option<CoffComdat<'data, 'file, R>> { + // Must be a section symbol. + if !section_symbol.has_aux_section() { + return None; + } + + // Auxiliary record must have a non-associative selection. + let aux = file.common.symbols.aux_section(index).ok()?; + let selection = aux.selection; + if selection == 0 || selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE { + return None; + } + + // Find the COMDAT symbol. + let mut symbol_index = index; + let mut symbol = section_symbol; + let section_number = section_symbol.section_number.get(LE); + loop { + symbol_index += 1 + symbol.number_of_aux_symbols as usize; + symbol = file.common.symbols.symbol(symbol_index).ok()?; + if section_number == symbol.section_number.get(LE) { + break; + } + } + + Some(CoffComdat { + file, + symbol_index: SymbolIndex(symbol_index), + symbol, + selection, + }) + } +} + +impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for CoffComdat<'data, 'file, R> {} + +impl<'data, 'file, R: ReadRef<'data>> ObjectComdat<'data> for CoffComdat<'data, 'file, R> { + type SectionIterator = CoffComdatSectionIterator<'data, 'file, R>; + + #[inline] + fn kind(&self) -> ComdatKind { + match self.selection { + pe::IMAGE_COMDAT_SELECT_NODUPLICATES => ComdatKind::NoDuplicates, + pe::IMAGE_COMDAT_SELECT_ANY => ComdatKind::Any, + pe::IMAGE_COMDAT_SELECT_SAME_SIZE => ComdatKind::SameSize, + pe::IMAGE_COMDAT_SELECT_EXACT_MATCH => ComdatKind::ExactMatch, + pe::IMAGE_COMDAT_SELECT_LARGEST => ComdatKind::Largest, + pe::IMAGE_COMDAT_SELECT_NEWEST => ComdatKind::Newest, + _ => ComdatKind::Unknown, + } + } + + #[inline] + fn symbol(&self) -> SymbolIndex { + self.symbol_index + } + + #[inline] + fn name(&self) -> Result<&str> { + // Find the name of first symbol referring to the section. + let name = self.symbol.name(self.file.common.symbols.strings())?; + str::from_utf8(name) + .ok() + .read_error("Non UTF-8 COFF COMDAT name") + } + + #[inline] + fn sections(&self) -> Self::SectionIterator { + CoffComdatSectionIterator { + file: self.file, + section_number: self.symbol.section_number.get(LE), + index: 0, + } + } +} + +/// An iterator over the sections in a COMDAT section group of a `CoffFile`. +#[derive(Debug)] +pub struct CoffComdatSectionIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> { + file: &'file CoffFile<'data, R>, + section_number: u16, + index: usize, +} + +impl<'data, 'file, R: ReadRef<'data>> Iterator for CoffComdatSectionIterator<'data, 'file, R> { + type Item = SectionIndex; + + fn next(&mut self) -> Option<Self::Item> { + // Find associated COMDAT symbols. + // TODO: it seems gcc doesn't use associated symbols for this + loop { + let index = self.index; + let symbol = self.file.common.symbols.symbol(index).ok()?; + self.index += 1 + symbol.number_of_aux_symbols as usize; + + // Must be a section symbol. + if !symbol.has_aux_section() { + continue; + } + + let section_number = symbol.section_number.get(LE); + + let aux = self.file.common.symbols.aux_section(index).ok()?; + if aux.selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE { + // TODO: use high_number for bigobj + if aux.number.get(LE) == self.section_number { + return Some(SectionIndex(section_number as usize)); + } + } else if aux.selection != 0 { + if section_number == self.section_number { + return Some(SectionIndex(section_number as usize)); + } + } + } + } +} |