object/read/coff/
comdat.rs

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 = 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
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}