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 _ => Architecture::Unknown,
151 }
152 }
153
154 fn sub_architecture(&self) -> Option<SubArchitecture> {
155 match self.header.machine() {
156 pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC),
157 _ => None,
158 }
159 }
160
161 #[inline]
162 fn is_little_endian(&self) -> bool {
163 true
164 }
165
166 #[inline]
167 fn is_64(&self) -> bool {
168 false
170 }
171
172 fn kind(&self) -> ObjectKind {
173 ObjectKind::Relocatable
174 }
175
176 fn segments(&self) -> CoffSegmentIterator<'data, '_, R, Coff> {
177 CoffSegmentIterator {
178 file: self,
179 iter: self.common.sections.iter(),
180 }
181 }
182
183 fn section_by_name_bytes<'file>(
184 &'file self,
185 section_name: &[u8],
186 ) -> Option<CoffSection<'data, 'file, R, Coff>> {
187 self.sections()
188 .find(|section| section.name_bytes() == Ok(section_name))
189 }
190
191 fn section_by_index(&self, index: SectionIndex) -> Result<CoffSection<'data, '_, R, Coff>> {
192 let section = self.common.sections.section(index)?;
193 Ok(CoffSection {
194 file: self,
195 index,
196 section,
197 })
198 }
199
200 fn sections(&self) -> CoffSectionIterator<'data, '_, R, Coff> {
201 CoffSectionIterator {
202 file: self,
203 iter: self.common.sections.iter().enumerate(),
204 }
205 }
206
207 fn comdats(&self) -> CoffComdatIterator<'data, '_, R, Coff> {
208 CoffComdatIterator::new(self)
209 }
210
211 fn symbol_by_index(&self, index: SymbolIndex) -> Result<CoffSymbol<'data, '_, R, Coff>> {
212 let symbol = self.common.symbols.symbol(index)?;
213 Ok(CoffSymbol {
214 file: &self.common,
215 index,
216 symbol,
217 })
218 }
219
220 fn symbols(&self) -> CoffSymbolIterator<'data, '_, R, Coff> {
221 CoffSymbolIterator::new(&self.common)
222 }
223
224 #[inline]
225 fn symbol_table(&self) -> Option<CoffSymbolTable<'data, '_, R, Coff>> {
226 Some(CoffSymbolTable { file: &self.common })
227 }
228
229 fn dynamic_symbols(&self) -> CoffSymbolIterator<'data, '_, R, Coff> {
230 CoffSymbolIterator::empty(&self.common)
231 }
232
233 #[inline]
234 fn dynamic_symbol_table(&self) -> Option<CoffSymbolTable<'data, '_, R, Coff>> {
235 None
236 }
237
238 #[inline]
239 fn dynamic_relocations(&self) -> Option<NoDynamicRelocationIterator> {
240 None
241 }
242
243 #[inline]
244 fn imports(&self) -> Result<Vec<Import<'data>>> {
245 Ok(Vec::new())
247 }
248
249 #[inline]
250 fn exports(&self) -> Result<Vec<Export<'data>>> {
251 Ok(Vec::new())
253 }
254
255 fn has_debug_symbols(&self) -> bool {
256 self.section_by_name(".debug_info").is_some()
257 }
258
259 fn relative_address_base(&self) -> u64 {
260 0
261 }
262
263 #[inline]
264 fn entry(&self) -> u64 {
265 0
266 }
267
268 fn flags(&self) -> FileFlags {
269 FileFlags::Coff {
270 characteristics: self.header.characteristics(),
271 }
272 }
273}
274
275pub fn anon_object_class_id<'data, R: ReadRef<'data>>(data: R) -> Result<pe::ClsId> {
279 let header = data
280 .read_at::<pe::AnonObjectHeader>(0)
281 .read_error("Invalid anon object header size or alignment")?;
282 Ok(header.class_id)
283}
284
285#[allow(missing_docs)]
287pub trait CoffHeader: Debug + Pod {
288 type ImageSymbol: ImageSymbol;
289 type ImageSymbolBytes: Debug + Pod;
290
291 fn is_type_bigobj() -> bool;
295
296 fn machine(&self) -> u16;
297 fn number_of_sections(&self) -> u32;
298 fn pointer_to_symbol_table(&self) -> u32;
299 fn number_of_symbols(&self) -> u32;
300 fn characteristics(&self) -> u16;
301
302 fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self>;
308
309 #[inline]
314 fn sections<'data, R: ReadRef<'data>>(
315 &self,
316 data: R,
317 offset: u64,
318 ) -> read::Result<SectionTable<'data>> {
319 SectionTable::parse(self, data, offset)
320 }
321
322 #[inline]
326 fn symbols<'data, R: ReadRef<'data>>(
327 &self,
328 data: R,
329 ) -> read::Result<SymbolTable<'data, R, Self>> {
330 SymbolTable::parse(self, data)
331 }
332}
333
334impl CoffHeader for pe::ImageFileHeader {
335 type ImageSymbol = pe::ImageSymbol;
336 type ImageSymbolBytes = pe::ImageSymbolBytes;
337
338 fn is_type_bigobj() -> bool {
339 false
340 }
341
342 fn machine(&self) -> u16 {
343 self.machine.get(LE)
344 }
345
346 fn number_of_sections(&self) -> u32 {
347 self.number_of_sections.get(LE).into()
348 }
349
350 fn pointer_to_symbol_table(&self) -> u32 {
351 self.pointer_to_symbol_table.get(LE)
352 }
353
354 fn number_of_symbols(&self) -> u32 {
355 self.number_of_symbols.get(LE)
356 }
357
358 fn characteristics(&self) -> u16 {
359 self.characteristics.get(LE)
360 }
361
362 fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> {
363 let header = data
364 .read::<pe::ImageFileHeader>(offset)
365 .read_error("Invalid COFF file header size or alignment")?;
366
367 *offset = offset
369 .checked_add(header.size_of_optional_header.get(LE).into())
370 .read_error("Invalid COFF optional header size")?;
371
372 Ok(header)
374 }
375}
376
377impl CoffHeader for pe::AnonObjectHeaderBigobj {
378 type ImageSymbol = pe::ImageSymbolEx;
379 type ImageSymbolBytes = pe::ImageSymbolExBytes;
380
381 fn is_type_bigobj() -> bool {
382 true
383 }
384
385 fn machine(&self) -> u16 {
386 self.machine.get(LE)
387 }
388
389 fn number_of_sections(&self) -> u32 {
390 self.number_of_sections.get(LE)
391 }
392
393 fn pointer_to_symbol_table(&self) -> u32 {
394 self.pointer_to_symbol_table.get(LE)
395 }
396
397 fn number_of_symbols(&self) -> u32 {
398 self.number_of_symbols.get(LE)
399 }
400
401 fn characteristics(&self) -> u16 {
402 0
403 }
404
405 fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> {
406 let header = data
407 .read::<pe::AnonObjectHeaderBigobj>(offset)
408 .read_error("Invalid COFF bigobj file header size or alignment")?;
409
410 if header.sig1.get(LE) != pe::IMAGE_FILE_MACHINE_UNKNOWN
411 || header.sig2.get(LE) != 0xffff
412 || header.version.get(LE) < 2
413 || header.class_id != pe::ANON_OBJECT_HEADER_BIGOBJ_CLASS_ID
414 {
415 return Err(read::Error("Invalid COFF bigobj header values"));
416 }
417
418 Ok(header)
420 }
421}