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