summaryrefslogtreecommitdiffstats
path: root/third_party/rust/object/src/read/coff/comdat.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/object/src/read/coff/comdat.rs')
-rw-r--r--third_party/rust/object/src/read/coff/comdat.rs207
1 files changed, 207 insertions, 0 deletions
diff --git a/third_party/rust/object/src/read/coff/comdat.rs b/third_party/rust/object/src/read/coff/comdat.rs
new file mode 100644
index 0000000000..22e061a236
--- /dev/null
+++ b/third_party/rust/object/src/read/coff/comdat.rs
@@ -0,0 +1,207 @@
+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, CoffHeader, ImageSymbol};
+
+/// An iterator over the COMDAT section groups of a `CoffBigFile`.
+pub type CoffBigComdatIterator<'data, 'file, R = &'data [u8]> =
+ CoffComdatIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// An iterator over the COMDAT section groups of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffComdatIterator<
+ 'data,
+ 'file,
+ R: ReadRef<'data> = &'data [u8],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ pub(super) file: &'file CoffFile<'data, R, Coff>,
+ pub(super) index: usize,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
+ for CoffComdatIterator<'data, 'file, R, Coff>
+{
+ type Item = CoffComdat<'data, 'file, R, Coff>;
+
+ 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 `CoffBigFile`.
+pub type CoffBigComdat<'data, 'file, R = &'data [u8]> =
+ CoffComdat<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// A COMDAT section group of a `CoffFile`.
+#[derive(Debug)]
+pub struct CoffComdat<
+ 'data,
+ 'file,
+ R: ReadRef<'data> = &'data [u8],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ file: &'file CoffFile<'data, R, Coff>,
+ symbol_index: SymbolIndex,
+ symbol: &'data Coff::ImageSymbol,
+ selection: u8,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffComdat<'data, 'file, R, Coff> {
+ fn parse(
+ file: &'file CoffFile<'data, R, Coff>,
+ section_symbol: &'data Coff::ImageSymbol,
+ index: usize,
+ ) -> Option<CoffComdat<'data, 'file, R, Coff>> {
+ // 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();
+ 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() {
+ break;
+ }
+ }
+
+ Some(CoffComdat {
+ file,
+ symbol_index: SymbolIndex(symbol_index),
+ symbol,
+ selection,
+ })
+ }
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed
+ for CoffComdat<'data, 'file, R, Coff>
+{
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectComdat<'data>
+ for CoffComdat<'data, 'file, R, Coff>
+{
+ type SectionIterator = CoffComdatSectionIterator<'data, 'file, R, Coff>;
+
+ #[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_bytes(&self) -> Result<&[u8]> {
+ // Find the name of first symbol referring to the section.
+ self.symbol.name(self.file.common.symbols.strings())
+ }
+
+ #[inline]
+ fn name(&self) -> Result<&str> {
+ let bytes = self.name_bytes()?;
+ str::from_utf8(bytes)
+ .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(),
+ index: 0,
+ }
+ }
+}
+
+/// An iterator over the sections in a COMDAT section group of a `CoffBigFile`.
+pub type CoffBigComdatSectionIterator<'data, 'file, R = &'data [u8]> =
+ CoffComdatSectionIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
+
+/// 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],
+ Coff: CoffHeader = pe::ImageFileHeader,
+> {
+ file: &'file CoffFile<'data, R, Coff>,
+ section_number: i32,
+ index: usize,
+}
+
+impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
+ for CoffComdatSectionIterator<'data, 'file, R, Coff>
+{
+ 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();
+
+ let aux = self.file.common.symbols.aux_section(index).ok()?;
+ if aux.selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE {
+ let number = if Coff::is_type_bigobj() {
+ u32::from(aux.number.get(LE)) | (u32::from(aux.high_number.get(LE)) << 16)
+ } else {
+ u32::from(aux.number.get(LE))
+ };
+ if number as i32 == 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));
+ }
+ }
+ }
+ }
+}