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, CoffHeader, ImageSymbol}; |
10 | |
11 | /// An iterator for the COMDAT section groups in a [`CoffBigFile`](super::CoffBigFile). |
12 | pub 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)] |
17 | pub 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 | |
27 | impl<'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 | |
36 | impl<'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. |
56 | pub 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)] |
63 | pub 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 | |
75 | impl<'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 | |
114 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed |
115 | for CoffComdat<'data, 'file, R, Coff> |
116 | { |
117 | } |
118 | |
119 | impl<'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). |
167 | pub 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)] |
172 | pub 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 | |
183 | impl<'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 | |