1use alloc::vec::Vec;
2use core::fmt::Debug;
3
4use crate::endian::LittleEndian as LE;
5use crate::pe;
6use crate::pod::Pod;
7use crate::read::{
8 self, Architecture, Export, FileFlags, Import, NoDynamicRelocationIterator, Object, ObjectKind,
9 ObjectSection, ReadError, ReadRef, Result, SectionIndex, SubArchitecture, SymbolIndex,
10};
11
12use super::{
13 CoffComdat, CoffComdatIterator, CoffSection, CoffSectionIterator, CoffSegment,
14 CoffSegmentIterator, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, ImageSymbol,
15 SectionTable, SymbolTable,
16};
17
18#[derive(Debug)]
20pub(crate) struct CoffCommon<'data, R: ReadRef<'data>, Coff: CoffHeader = pe::ImageFileHeader> {
21 pub(crate) sections: SectionTable<'data>,
22 pub(crate) symbols: SymbolTable<'data, R, Coff>,
23 pub(crate) image_base: u64,
24}
25
26pub type CoffBigFile<'data, R = &'data [u8]> = CoffFile<'data, R, pe::AnonObjectHeaderBigobj>;
33
34#[derive(Debug)]
41pub struct CoffFile<'data, R: ReadRef<'data> = &'data [u8], Coff: CoffHeader = pe::ImageFileHeader>
42{
43 pub(super) header: &'data Coff,
44 pub(super) common: CoffCommon<'data, R, Coff>,
45 pub(super) data: R,
46}
47
48impl<'data, R: ReadRef<'data>, Coff: CoffHeader> CoffFile<'data, R, Coff> {
49 pub fn parse(data: R) -> Result<Self> {
51 let mut offset = 0;
52 let header = Coff::parse(data, &mut offset)?;
53 let sections = header.sections(data, offset)?;
54 let symbols = header.symbols(data)?;
55
56 Ok(CoffFile {
57 header,
58 common: CoffCommon {
59 sections,
60 symbols,
61 image_base: 0,
62 },
63 data,
64 })
65 }
66
67 pub fn coff_header(&self) -> &'data Coff {
69 self.header
70 }
71
72 pub fn coff_section_table(&self) -> SectionTable<'data> {
74 self.common.sections
75 }
76
77 pub fn coff_symbol_table(&self) -> &SymbolTable<'data, R, Coff> {
79 &self.common.symbols
80 }
81}
82
83impl<'data, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed
84 for CoffFile<'data, R, Coff>
85{
86}
87
88impl<'data, R, Coff> Object<'data> for CoffFile<'data, R, Coff>
89where
90 R: ReadRef<'data>,
91 Coff: CoffHeader,
92{
93 type Segment<'file> = CoffSegment<'data, 'file, R, Coff> where Self: 'file, 'data: 'file;
94 type SegmentIterator<'file> = CoffSegmentIterator<'data, 'file, R, Coff> where Self: 'file, 'data: 'file;
95 type Section<'file> = CoffSection<'data, 'file, R, Coff> where Self: 'file, 'data: 'file;
96 type SectionIterator<'file> = CoffSectionIterator<'data, 'file, R, Coff> where Self: 'file, 'data: 'file;
97 type Comdat<'file> = CoffComdat<'data, 'file, R, Coff> where Self: 'file, 'data: 'file;
98 type ComdatIterator<'file> = CoffComdatIterator<'data, 'file, R, Coff> where Self: 'file, 'data: 'file;
99 type Symbol<'file> = CoffSymbol<'data, 'file, R, Coff> where Self: 'file, 'data: 'file;
100 type SymbolIterator<'file> = CoffSymbolIterator<'data, 'file, R, Coff> where Self: 'file, 'data: 'file;
101 type SymbolTable<'file> = CoffSymbolTable<'data, 'file, R, Coff> where Self: 'file, 'data: 'file;
102 type DynamicRelocationIterator<'file> = NoDynamicRelocationIterator where Self: 'file, 'data: 'file;
103
104 fn architecture(&self) -> Architecture {
105 match self.header.machine() {
106 pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm,
107 pe::IMAGE_FILE_MACHINE_ARM64 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64,
108 pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386,
109 pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64,
110 _ => Architecture::Unknown,
111 }
112 }
113
114 fn sub_architecture(&self) -> Option<SubArchitecture> {
115 match self.header.machine() {
116 pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC),
117 _ => None,
118 }
119 }
120
121 #[inline]
122 fn is_little_endian(&self) -> bool {
123 true
124 }
125
126 #[inline]
127 fn is_64(&self) -> bool {
128 false
130 }
131
132 fn kind(&self) -> ObjectKind {
133 ObjectKind::Relocatable
134 }
135
136 fn segments(&self) -> CoffSegmentIterator<'data, '_, R, Coff> {
137 CoffSegmentIterator {
138 file: self,
139 iter: self.common.sections.iter(),
140 }
141 }
142
143 fn section_by_name_bytes<'file>(
144 &'file self,
145 section_name: &[u8],
146 ) -> Option<CoffSection<'data, 'file, R, Coff>> {
147 self.sections()
148 .find(|section| section.name_bytes() == Ok(section_name))
149 }
150
151 fn section_by_index(&self, index: SectionIndex) -> Result<CoffSection<'data, '_, R, Coff>> {
152 let section = self.common.sections.section(index)?;
153 Ok(CoffSection {
154 file: self,
155 index,
156 section,
157 })
158 }
159
160 fn sections(&self) -> CoffSectionIterator<'data, '_, R, Coff> {
161 CoffSectionIterator {
162 file: self,
163 iter: self.common.sections.iter().enumerate(),
164 }
165 }
166
167 fn comdats(&self) -> CoffComdatIterator<'data, '_, R, Coff> {
168 CoffComdatIterator::new(self)
169 }
170
171 fn symbol_by_index(&self, index: SymbolIndex) -> Result<CoffSymbol<'data, '_, R, Coff>> {
172 let symbol = self.common.symbols.symbol(index)?;
173 Ok(CoffSymbol {
174 file: &self.common,
175 index,
176 symbol,
177 })
178 }
179
180 fn symbols(&self) -> CoffSymbolIterator<'data, '_, R, Coff> {
181 CoffSymbolIterator::new(&self.common)
182 }
183
184 #[inline]
185 fn symbol_table(&self) -> Option<CoffSymbolTable<'data, '_, R, Coff>> {
186 Some(CoffSymbolTable { file: &self.common })
187 }
188
189 fn dynamic_symbols(&self) -> CoffSymbolIterator<'data, '_, R, Coff> {
190 CoffSymbolIterator::empty(&self.common)
191 }
192
193 #[inline]
194 fn dynamic_symbol_table(&self) -> Option<CoffSymbolTable<'data, '_, R, Coff>> {
195 None
196 }
197
198 #[inline]
199 fn dynamic_relocations(&self) -> Option<NoDynamicRelocationIterator> {
200 None
201 }
202
203 #[inline]
204 fn imports(&self) -> Result<Vec<Import<'data>>> {
205 Ok(Vec::new())
207 }
208
209 #[inline]
210 fn exports(&self) -> Result<Vec<Export<'data>>> {
211 Ok(Vec::new())
213 }
214
215 fn has_debug_symbols(&self) -> bool {
216 self.section_by_name(".debug_info").is_some()
217 }
218
219 fn relative_address_base(&self) -> u64 {
220 0
221 }
222
223 #[inline]
224 fn entry(&self) -> u64 {
225 0
226 }
227
228 fn flags(&self) -> FileFlags {
229 FileFlags::Coff {
230 characteristics: self.header.characteristics(),
231 }
232 }
233}
234
235pub fn anon_object_class_id<'data, R: ReadRef<'data>>(data: R) -> Result<pe::ClsId> {
239 let header = data
240 .read_at::<pe::AnonObjectHeader>(0)
241 .read_error("Invalid anon object header size or alignment")?;
242 Ok(header.class_id)
243}
244
245#[allow(missing_docs)]
247pub trait CoffHeader: Debug + Pod {
248 type ImageSymbol: ImageSymbol;
249 type ImageSymbolBytes: Debug + Pod;
250
251 fn is_type_bigobj() -> bool;
255
256 fn machine(&self) -> u16;
257 fn number_of_sections(&self) -> u32;
258 fn pointer_to_symbol_table(&self) -> u32;
259 fn number_of_symbols(&self) -> u32;
260 fn characteristics(&self) -> u16;
261
262 fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self>;
268
269 #[inline]
274 fn sections<'data, R: ReadRef<'data>>(
275 &self,
276 data: R,
277 offset: u64,
278 ) -> read::Result<SectionTable<'data>> {
279 SectionTable::parse(self, data, offset)
280 }
281
282 #[inline]
286 fn symbols<'data, R: ReadRef<'data>>(
287 &self,
288 data: R,
289 ) -> read::Result<SymbolTable<'data, R, Self>> {
290 SymbolTable::parse(self, data)
291 }
292}
293
294impl CoffHeader for pe::ImageFileHeader {
295 type ImageSymbol = pe::ImageSymbol;
296 type ImageSymbolBytes = pe::ImageSymbolBytes;
297
298 fn is_type_bigobj() -> bool {
299 false
300 }
301
302 fn machine(&self) -> u16 {
303 self.machine.get(LE)
304 }
305
306 fn number_of_sections(&self) -> u32 {
307 self.number_of_sections.get(LE).into()
308 }
309
310 fn pointer_to_symbol_table(&self) -> u32 {
311 self.pointer_to_symbol_table.get(LE)
312 }
313
314 fn number_of_symbols(&self) -> u32 {
315 self.number_of_symbols.get(LE)
316 }
317
318 fn characteristics(&self) -> u16 {
319 self.characteristics.get(LE)
320 }
321
322 fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> {
323 let header = data
324 .read::<pe::ImageFileHeader>(offset)
325 .read_error("Invalid COFF file header size or alignment")?;
326
327 *offset = offset
329 .checked_add(header.size_of_optional_header.get(LE).into())
330 .read_error("Invalid COFF optional header size")?;
331
332 Ok(header)
334 }
335}
336
337impl CoffHeader for pe::AnonObjectHeaderBigobj {
338 type ImageSymbol = pe::ImageSymbolEx;
339 type ImageSymbolBytes = pe::ImageSymbolExBytes;
340
341 fn is_type_bigobj() -> bool {
342 true
343 }
344
345 fn machine(&self) -> u16 {
346 self.machine.get(LE)
347 }
348
349 fn number_of_sections(&self) -> u32 {
350 self.number_of_sections.get(LE)
351 }
352
353 fn pointer_to_symbol_table(&self) -> u32 {
354 self.pointer_to_symbol_table.get(LE)
355 }
356
357 fn number_of_symbols(&self) -> u32 {
358 self.number_of_symbols.get(LE)
359 }
360
361 fn characteristics(&self) -> u16 {
362 0
363 }
364
365 fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> {
366 let header = data
367 .read::<pe::AnonObjectHeaderBigobj>(offset)
368 .read_error("Invalid COFF bigobj file header size or alignment")?;
369
370 if header.sig1.get(LE) != pe::IMAGE_FILE_MACHINE_UNKNOWN
371 || header.sig2.get(LE) != 0xffff
372 || header.version.get(LE) < 2
373 || header.class_id != pe::ANON_OBJECT_HEADER_BIGOBJ_CLASS_ID
374 {
375 return Err(read::Error("Invalid COFF bigobj header values"));
376 }
377
378 Ok(header)
380 }
381}