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>
94 = CoffSegment<'data, 'file, R, Coff>
95 where
96 Self: 'file,
97 'data: 'file;
98 type SegmentIterator<'file>
99 = CoffSegmentIterator<'data, 'file, R, Coff>
100 where
101 Self: 'file,
102 'data: 'file;
103 type Section<'file>
104 = CoffSection<'data, 'file, R, Coff>
105 where
106 Self: 'file,
107 'data: 'file;
108 type SectionIterator<'file>
109 = CoffSectionIterator<'data, 'file, R, Coff>
110 where
111 Self: 'file,
112 'data: 'file;
113 type Comdat<'file>
114 = CoffComdat<'data, 'file, R, Coff>
115 where
116 Self: 'file,
117 'data: 'file;
118 type ComdatIterator<'file>
119 = CoffComdatIterator<'data, 'file, R, Coff>
120 where
121 Self: 'file,
122 'data: 'file;
123 type Symbol<'file>
124 = CoffSymbol<'data, 'file, R, Coff>
125 where
126 Self: 'file,
127 'data: 'file;
128 type SymbolIterator<'file>
129 = CoffSymbolIterator<'data, 'file, R, Coff>
130 where
131 Self: 'file,
132 'data: 'file;
133 type SymbolTable<'file>
134 = CoffSymbolTable<'data, 'file, R, Coff>
135 where
136 Self: 'file,
137 'data: 'file;
138 type DynamicRelocationIterator<'file>
139 = NoDynamicRelocationIterator
140 where
141 Self: 'file,
142 'data: 'file;
143
144 fn architecture(&self) -> Architecture {
145 match self.header.machine() {
146 pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm,
147 pe::IMAGE_FILE_MACHINE_ARM64 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64,
148 pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386,
149 pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64,
150 pe::IMAGE_FILE_MACHINE_POWERPC
151 | pe::IMAGE_FILE_MACHINE_POWERPCFP
152 | pe::IMAGE_FILE_MACHINE_POWERPCBE => Architecture::PowerPc,
153 _ => Architecture::Unknown,
154 }
155 }
156
157 fn sub_architecture(&self) -> Option<SubArchitecture> {
158 match self.header.machine() {
159 pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC),
160 _ => None,
161 }
162 }
163
164 #[inline]
165 fn is_little_endian(&self) -> bool {
166 match self.header.machine() {
167 pe::IMAGE_FILE_MACHINE_POWERPCBE => false,
168 _ => true,
169 }
170 }
171
172 #[inline]
173 fn is_64(&self) -> bool {
174 false
176 }
177
178 fn kind(&self) -> ObjectKind {
179 ObjectKind::Relocatable
180 }
181
182 fn segments(&self) -> CoffSegmentIterator<'data, '_, R, Coff> {
183 CoffSegmentIterator {
184 file: self,
185 iter: self.common.sections.iter(),
186 }
187 }
188
189 fn section_by_name_bytes<'file>(
190 &'file self,
191 section_name: &[u8],
192 ) -> Option<CoffSection<'data, 'file, R, Coff>> {
193 self.sections()
194 .find(|section| section.name_bytes() == Ok(section_name))
195 }
196
197 fn section_by_index(&self, index: SectionIndex) -> Result<CoffSection<'data, '_, R, Coff>> {
198 let section = self.common.sections.section(index)?;
199 Ok(CoffSection {
200 file: self,
201 index,
202 section,
203 })
204 }
205
206 fn sections(&self) -> CoffSectionIterator<'data, '_, R, Coff> {
207 CoffSectionIterator {
208 file: self,
209 iter: self.common.sections.iter().enumerate(),
210 }
211 }
212
213 fn comdats(&self) -> CoffComdatIterator<'data, '_, R, Coff> {
214 CoffComdatIterator::new(self)
215 }
216
217 fn symbol_by_index(&self, index: SymbolIndex) -> Result<CoffSymbol<'data, '_, R, Coff>> {
218 let symbol = self.common.symbols.symbol(index)?;
219 Ok(CoffSymbol {
220 file: &self.common,
221 index,
222 symbol,
223 })
224 }
225
226 fn symbols(&self) -> CoffSymbolIterator<'data, '_, R, Coff> {
227 CoffSymbolIterator::new(&self.common)
228 }
229
230 #[inline]
231 fn symbol_table(&self) -> Option<CoffSymbolTable<'data, '_, R, Coff>> {
232 Some(CoffSymbolTable { file: &self.common })
233 }
234
235 fn dynamic_symbols(&self) -> CoffSymbolIterator<'data, '_, R, Coff> {
236 CoffSymbolIterator::empty(&self.common)
237 }
238
239 #[inline]
240 fn dynamic_symbol_table(&self) -> Option<CoffSymbolTable<'data, '_, R, Coff>> {
241 None
242 }
243
244 #[inline]
245 fn dynamic_relocations(&self) -> Option<NoDynamicRelocationIterator> {
246 None
247 }
248
249 #[inline]
250 fn imports(&self) -> Result<Vec<Import<'data>>> {
251 Ok(Vec::new())
253 }
254
255 #[inline]
256 fn exports(&self) -> Result<Vec<Export<'data>>> {
257 Ok(Vec::new())
259 }
260
261 fn has_debug_symbols(&self) -> bool {
262 self.section_by_name(".debug_info").is_some()
263 }
264
265 fn relative_address_base(&self) -> u64 {
266 0
267 }
268
269 #[inline]
270 fn entry(&self) -> u64 {
271 0
272 }
273
274 fn flags(&self) -> FileFlags {
275 FileFlags::Coff {
276 characteristics: self.header.characteristics(),
277 }
278 }
279}
280
281pub fn anon_object_class_id<'data, R: ReadRef<'data>>(data: R) -> Result<pe::ClsId> {
285 let header = data
286 .read_at::<pe::AnonObjectHeader>(0)
287 .read_error("Invalid anon object header size or alignment")?;
288 Ok(header.class_id)
289}
290
291#[allow(missing_docs)]
293pub trait CoffHeader: Debug + Pod {
294 type ImageSymbol: ImageSymbol;
295 type ImageSymbolBytes: Debug + Pod;
296
297 fn is_type_bigobj() -> bool;
301
302 fn machine(&self) -> u16;
303 fn number_of_sections(&self) -> u32;
304 fn pointer_to_symbol_table(&self) -> u32;
305 fn number_of_symbols(&self) -> u32;
306 fn characteristics(&self) -> u16;
307
308 fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self>;
314
315 #[inline]
320 fn sections<'data, R: ReadRef<'data>>(
321 &self,
322 data: R,
323 offset: u64,
324 ) -> read::Result<SectionTable<'data>> {
325 SectionTable::parse(self, data, offset)
326 }
327
328 #[inline]
332 fn symbols<'data, R: ReadRef<'data>>(
333 &self,
334 data: R,
335 ) -> read::Result<SymbolTable<'data, R, Self>> {
336 SymbolTable::parse(self, data)
337 }
338}
339
340impl CoffHeader for pe::ImageFileHeader {
341 type ImageSymbol = pe::ImageSymbol;
342 type ImageSymbolBytes = pe::ImageSymbolBytes;
343
344 fn is_type_bigobj() -> bool {
345 false
346 }
347
348 fn machine(&self) -> u16 {
349 self.machine.get(LE)
350 }
351
352 fn number_of_sections(&self) -> u32 {
353 self.number_of_sections.get(LE).into()
354 }
355
356 fn pointer_to_symbol_table(&self) -> u32 {
357 self.pointer_to_symbol_table.get(LE)
358 }
359
360 fn number_of_symbols(&self) -> u32 {
361 self.number_of_symbols.get(LE)
362 }
363
364 fn characteristics(&self) -> u16 {
365 self.characteristics.get(LE)
366 }
367
368 fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> {
369 let header = data
370 .read::<pe::ImageFileHeader>(offset)
371 .read_error("Invalid COFF file header size or alignment")?;
372
373 *offset = offset
375 .checked_add(header.size_of_optional_header.get(LE).into())
376 .read_error("Invalid COFF optional header size")?;
377
378 Ok(header)
380 }
381}
382
383impl CoffHeader for pe::AnonObjectHeaderBigobj {
384 type ImageSymbol = pe::ImageSymbolEx;
385 type ImageSymbolBytes = pe::ImageSymbolExBytes;
386
387 fn is_type_bigobj() -> bool {
388 true
389 }
390
391 fn machine(&self) -> u16 {
392 self.machine.get(LE)
393 }
394
395 fn number_of_sections(&self) -> u32 {
396 self.number_of_sections.get(LE)
397 }
398
399 fn pointer_to_symbol_table(&self) -> u32 {
400 self.pointer_to_symbol_table.get(LE)
401 }
402
403 fn number_of_symbols(&self) -> u32 {
404 self.number_of_symbols.get(LE)
405 }
406
407 fn characteristics(&self) -> u16 {
408 0
409 }
410
411 fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> {
412 let header = data
413 .read::<pe::AnonObjectHeaderBigobj>(offset)
414 .read_error("Invalid COFF bigobj file header size or alignment")?;
415
416 if header.sig1.get(LE) != pe::IMAGE_FILE_MACHINE_UNKNOWN
417 || header.sig2.get(LE) != 0xffff
418 || header.version.get(LE) < 2
419 || header.class_id != pe::ANON_OBJECT_HEADER_BIGOBJ_CLASS_ID
420 {
421 return Err(read::Error("Invalid COFF bigobj header values"));
422 }
423
424 Ok(header)
426 }
427}