1 use core::str; 2 3 use crate::endian::LittleEndian as LE; 4 use crate::pe; 5 use crate::read::{ 6 self, ComdatKind, ObjectComdat, ReadError, ReadRef, Result, SectionIndex, SymbolIndex, 7 }; 8 9 use super::CoffFile; 10 11 /// An iterator over the COMDAT section groups of a `CoffFile`. 12 #[derive(Debug)] 13 pub struct CoffComdatIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> { 14 pub(super) file: &'file CoffFile<'data, R>, 15 pub(super) index: usize, 16 } 17 18 impl<'data, 'file, R: ReadRef<'data>> Iterator for CoffComdatIterator<'data, 'file, R> { 19 type Item = CoffComdat<'data, 'file, R>; 20 next(&mut self) -> Option<Self::Item>21 fn next(&mut self) -> Option<Self::Item> { 22 loop { 23 let index = self.index; 24 let symbol = self.file.common.symbols.symbol(index).ok()?; 25 self.index += 1 + symbol.number_of_aux_symbols as usize; 26 if let Some(comdat) = CoffComdat::parse(self.file, symbol, index) { 27 return Some(comdat); 28 } 29 } 30 } 31 } 32 33 /// A COMDAT section group of a `CoffFile`. 34 #[derive(Debug)] 35 pub struct CoffComdat<'data, 'file, R: ReadRef<'data> = &'data [u8]> { 36 file: &'file CoffFile<'data, R>, 37 symbol_index: SymbolIndex, 38 symbol: &'data pe::ImageSymbol, 39 selection: u8, 40 } 41 42 impl<'data, 'file, R: ReadRef<'data>> CoffComdat<'data, 'file, R> { parse( file: &'file CoffFile<'data, R>, section_symbol: &'data pe::ImageSymbol, index: usize, ) -> Option<CoffComdat<'data, 'file, R>>43 fn parse( 44 file: &'file CoffFile<'data, R>, 45 section_symbol: &'data pe::ImageSymbol, 46 index: usize, 47 ) -> Option<CoffComdat<'data, 'file, R>> { 48 // Must be a section symbol. 49 if !section_symbol.has_aux_section() { 50 return None; 51 } 52 53 // Auxiliary record must have a non-associative selection. 54 let aux = file.common.symbols.aux_section(index).ok()?; 55 let selection = aux.selection; 56 if selection == 0 || selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE { 57 return None; 58 } 59 60 // Find the COMDAT symbol. 61 let mut symbol_index = index; 62 let mut symbol = section_symbol; 63 let section_number = section_symbol.section_number.get(LE); 64 loop { 65 symbol_index += 1 + symbol.number_of_aux_symbols as usize; 66 symbol = file.common.symbols.symbol(symbol_index).ok()?; 67 if section_number == symbol.section_number.get(LE) { 68 break; 69 } 70 } 71 72 Some(CoffComdat { 73 file, 74 symbol_index: SymbolIndex(symbol_index), 75 symbol, 76 selection, 77 }) 78 } 79 } 80 81 impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for CoffComdat<'data, 'file, R> {} 82 83 impl<'data, 'file, R: ReadRef<'data>> ObjectComdat<'data> for CoffComdat<'data, 'file, R> { 84 type SectionIterator = CoffComdatSectionIterator<'data, 'file, R>; 85 86 #[inline] kind(&self) -> ComdatKind87 fn kind(&self) -> ComdatKind { 88 match self.selection { 89 pe::IMAGE_COMDAT_SELECT_NODUPLICATES => ComdatKind::NoDuplicates, 90 pe::IMAGE_COMDAT_SELECT_ANY => ComdatKind::Any, 91 pe::IMAGE_COMDAT_SELECT_SAME_SIZE => ComdatKind::SameSize, 92 pe::IMAGE_COMDAT_SELECT_EXACT_MATCH => ComdatKind::ExactMatch, 93 pe::IMAGE_COMDAT_SELECT_LARGEST => ComdatKind::Largest, 94 pe::IMAGE_COMDAT_SELECT_NEWEST => ComdatKind::Newest, 95 _ => ComdatKind::Unknown, 96 } 97 } 98 99 #[inline] symbol(&self) -> SymbolIndex100 fn symbol(&self) -> SymbolIndex { 101 self.symbol_index 102 } 103 104 #[inline] name(&self) -> Result<&str>105 fn name(&self) -> Result<&str> { 106 // Find the name of first symbol referring to the section. 107 let name = self.symbol.name(self.file.common.symbols.strings())?; 108 str::from_utf8(name) 109 .ok() 110 .read_error("Non UTF-8 COFF COMDAT name") 111 } 112 113 #[inline] sections(&self) -> Self::SectionIterator114 fn sections(&self) -> Self::SectionIterator { 115 CoffComdatSectionIterator { 116 file: self.file, 117 section_number: self.symbol.section_number.get(LE), 118 index: 0, 119 } 120 } 121 } 122 123 /// An iterator over the sections in a COMDAT section group of a `CoffFile`. 124 #[derive(Debug)] 125 pub struct CoffComdatSectionIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> { 126 file: &'file CoffFile<'data, R>, 127 section_number: u16, 128 index: usize, 129 } 130 131 impl<'data, 'file, R: ReadRef<'data>> Iterator for CoffComdatSectionIterator<'data, 'file, R> { 132 type Item = SectionIndex; 133 next(&mut self) -> Option<Self::Item>134 fn next(&mut self) -> Option<Self::Item> { 135 // Find associated COMDAT symbols. 136 // TODO: it seems gcc doesn't use associated symbols for this 137 loop { 138 let index = self.index; 139 let symbol = self.file.common.symbols.symbol(index).ok()?; 140 self.index += 1 + symbol.number_of_aux_symbols as usize; 141 142 // Must be a section symbol. 143 if !symbol.has_aux_section() { 144 continue; 145 } 146 147 let section_number = symbol.section_number.get(LE); 148 149 let aux = self.file.common.symbols.aux_section(index).ok()?; 150 if aux.selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE { 151 // TODO: use high_number for bigobj 152 if aux.number.get(LE) == self.section_number { 153 return Some(SectionIndex(section_number as usize)); 154 } 155 } else if aux.selection != 0 { 156 if section_number == self.section_number { 157 return Some(SectionIndex(section_number as usize)); 158 } 159 } 160 } 161 } 162 } 163