1use core::str;
2
3use crate::endian::LittleEndian as LE;
4use crate::pe;
5use crate::read::{
6 self, ComdatKind, ObjectComdat, ReadError, ReadRef, Result, SectionIndex, SymbolIndex,
7};
8
9use super::{CoffFile, CoffHeader, ImageSymbol};
10
11pub type CoffBigComdatIterator<'data, 'file, R = &'data [u8]> =
13 CoffComdatIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
14
15#[derive(Debug)]
17pub struct CoffComdatIterator<
18 'data,
19 'file,
20 R: ReadRef<'data> = &'data [u8],
21 Coff: CoffHeader = pe::ImageFileHeader,
22> {
23 file: &'file CoffFile<'data, R, Coff>,
24 index: SymbolIndex,
25}
26
27impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffComdatIterator<'data, 'file, R, Coff> {
28 pub(crate) fn new(file: &'file CoffFile<'data, R, Coff>) -> Self {
29 CoffComdatIterator {
30 file,
31 index: SymbolIndex(0),
32 }
33 }
34}
35
36impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
37 for CoffComdatIterator<'data, 'file, R, Coff>
38{
39 type Item = CoffComdat<'data, 'file, R, Coff>;
40
41 fn next(&mut self) -> Option<Self::Item> {
42 loop {
43 let index = self.index;
44 let symbol = self.file.common.symbols.symbol(index).ok()?;
45 self.index.0 += 1 + symbol.number_of_aux_symbols() as usize;
46 if let Some(comdat) = CoffComdat::parse(self.file, symbol, index) {
47 return Some(comdat);
48 }
49 }
50 }
51}
52
53pub type CoffBigComdat<'data, 'file, R = &'data [u8]> =
57 CoffComdat<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
58
59#[derive(Debug)]
63pub struct CoffComdat<
64 'data,
65 'file,
66 R: ReadRef<'data> = &'data [u8],
67 Coff: CoffHeader = pe::ImageFileHeader,
68> {
69 file: &'file CoffFile<'data, R, Coff>,
70 symbol_index: SymbolIndex,
71 symbol: &'data Coff::ImageSymbol,
72 selection: u8,
73}
74
75impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffComdat<'data, 'file, R, Coff> {
76 fn parse(
77 file: &'file CoffFile<'data, R, Coff>,
78 section_symbol: &'data Coff::ImageSymbol,
79 index: SymbolIndex,
80 ) -> Option<CoffComdat<'data, 'file, R, Coff>> {
81 if !section_symbol.has_aux_section() {
83 return None;
84 }
85
86 let aux = file.common.symbols.aux_section(index).ok()?;
88 let selection = aux.selection;
89 if selection == 0 || selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE {
90 return None;
91 }
92
93 let mut symbol_index = index;
95 let mut symbol = section_symbol;
96 let section_number = section_symbol.section_number();
97 loop {
98 symbol_index.0 += 1 + symbol.number_of_aux_symbols() as usize;
99 symbol = file.common.symbols.symbol(symbol_index).ok()?;
100 if section_number == symbol.section_number() {
101 break;
102 }
103 }
104
105 Some(CoffComdat {
106 file,
107 symbol_index,
108 symbol,
109 selection,
110 })
111 }
112}
113
114impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed
115 for CoffComdat<'data, 'file, R, Coff>
116{
117}
118
119impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectComdat<'data>
120 for CoffComdat<'data, 'file, R, Coff>
121{
122 type SectionIterator = CoffComdatSectionIterator<'data, 'file, R, Coff>;
123
124 #[inline]
125 fn kind(&self) -> ComdatKind {
126 match self.selection {
127 pe::IMAGE_COMDAT_SELECT_NODUPLICATES => ComdatKind::NoDuplicates,
128 pe::IMAGE_COMDAT_SELECT_ANY => ComdatKind::Any,
129 pe::IMAGE_COMDAT_SELECT_SAME_SIZE => ComdatKind::SameSize,
130 pe::IMAGE_COMDAT_SELECT_EXACT_MATCH => ComdatKind::ExactMatch,
131 pe::IMAGE_COMDAT_SELECT_LARGEST => ComdatKind::Largest,
132 pe::IMAGE_COMDAT_SELECT_NEWEST => ComdatKind::Newest,
133 _ => ComdatKind::Unknown,
134 }
135 }
136
137 #[inline]
138 fn symbol(&self) -> SymbolIndex {
139 self.symbol_index
140 }
141
142 #[inline]
143 fn name_bytes(&self) -> Result<&'data [u8]> {
144 self.symbol.name(self.file.common.symbols.strings())
146 }
147
148 #[inline]
149 fn name(&self) -> Result<&'data str> {
150 let bytes = self.name_bytes()?;
151 str::from_utf8(bytes)
152 .ok()
153 .read_error("Non UTF-8 COFF COMDAT name")
154 }
155
156 #[inline]
157 fn sections(&self) -> Self::SectionIterator {
158 CoffComdatSectionIterator {
159 file: self.file,
160 section_number: self.symbol.section_number(),
161 index: SymbolIndex(0),
162 }
163 }
164}
165
166pub type CoffBigComdatSectionIterator<'data, 'file, R = &'data [u8]> =
168 CoffComdatSectionIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
169
170#[derive(Debug)]
172pub struct CoffComdatSectionIterator<
173 'data,
174 'file,
175 R: ReadRef<'data> = &'data [u8],
176 Coff: CoffHeader = pe::ImageFileHeader,
177> {
178 file: &'file CoffFile<'data, R, Coff>,
179 section_number: i32,
180 index: SymbolIndex,
181}
182
183impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
184 for CoffComdatSectionIterator<'data, 'file, R, Coff>
185{
186 type Item = SectionIndex;
187
188 fn next(&mut self) -> Option<Self::Item> {
189 loop {
192 let index = self.index;
193 let symbol = self.file.common.symbols.symbol(index).ok()?;
194 self.index.0 += 1 + symbol.number_of_aux_symbols() as usize;
195
196 if !symbol.has_aux_section() {
198 continue;
199 }
200
201 let section_number = symbol.section_number();
202
203 let aux = self.file.common.symbols.aux_section(index).ok()?;
204 if aux.selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE {
205 let number = if Coff::is_type_bigobj() {
206 u32::from(aux.number.get(LE)) | (u32::from(aux.high_number.get(LE)) << 16)
207 } else {
208 u32::from(aux.number.get(LE))
209 };
210 if number as i32 == self.section_number {
211 return Some(SectionIndex(section_number as usize));
212 }
213 } else if aux.selection != 0 {
214 if section_number == self.section_number {
215 return Some(SectionIndex(section_number as usize));
216 }
217 }
218 }
219 }
220}