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