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 | pub(super) file: &'file CoffFile<'data, R, Coff>, |
24 | pub(super) index: usize, |
25 | } |
26 | |
27 | impl<'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. |
47 | pub 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)] |
54 | pub 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 | |
66 | impl<'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 | |
105 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed |
106 | for CoffComdat<'data, 'file, R, Coff> |
107 | { |
108 | } |
109 | |
110 | impl<'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). |
158 | pub 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)] |
163 | pub 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 | |
174 | impl<'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 | |