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
11/// An iterator for the COMDAT section groups in a [`CoffBigFile`](super::CoffBigFile).
12pub type CoffBigComdatIterator<'data, 'file, R = &'data [u8]> =
13 CoffComdatIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
14
15/// An iterator for the COMDAT section groups in a [`CoffFile`].
16#[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: SymbolIndex = self.index;
44 let symbol: &'data ::ImageSymbol = 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<'_, '_, R, Coff>) = CoffComdat::parse(self.file, symbol, index) {
47 return Some(comdat);
48 }
49 }
50 }
51}
52
53/// A COMDAT section group in a [`CoffBigFile`](super::CoffBigFile).
54///
55/// Most functionality is provided by the [`ObjectComdat`] trait implementation.
56pub type CoffBigComdat<'data, 'file, R = &'data [u8]> =
57 CoffComdat<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
58
59/// A COMDAT section group in a [`CoffFile`].
60///
61/// Most functionality is provided by the [`ObjectComdat`] trait implementation.
62#[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 // Must be a section symbol.
82 if !section_symbol.has_aux_section() {
83 return None;
84 }
85
86 // Auxiliary record must have a non-associative selection.
87 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 // Find the COMDAT symbol.
94 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 // Find the name of first symbol referring to the section.
145 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
166/// An iterator for the sections in a COMDAT section group in a [`CoffBigFile`](super::CoffBigFile).
167pub type CoffBigComdatSectionIterator<'data, 'file, R = &'data [u8]> =
168 CoffComdatSectionIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
169
170/// An iterator for the sections in a COMDAT section group in a [`CoffFile`].
171#[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 // Find associated COMDAT symbols.
190 // TODO: it seems gcc doesn't use associated symbols for this
191 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 // Must be a section symbol.
197 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}
221