1 use alloc::vec::Vec;
2 use core::str;
3 
4 use crate::read::{
5     self, Architecture, Export, FileFlags, Import, NoDynamicRelocationIterator, Object,
6     ObjectSection, ReadError, Result, SectionIndex, SymbolIndex,
7 };
8 use crate::{pe, Bytes, LittleEndian as LE};
9 
10 use super::{
11     CoffComdat, CoffComdatIterator, CoffSection, CoffSectionIterator, CoffSegment,
12     CoffSegmentIterator, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SectionTable,
13     SymbolTable,
14 };
15 
16 /// The common parts of `PeFile` and `CoffFile`.
17 #[derive(Debug)]
18 pub(crate) struct CoffCommon<'data> {
19     pub(crate) sections: SectionTable<'data>,
20     // TODO: ImageSymbolExBytes
21     pub(crate) symbols: SymbolTable<'data>,
22     pub(crate) image_base: u64,
23 }
24 
25 /// A COFF object file.
26 #[derive(Debug)]
27 pub struct CoffFile<'data> {
28     pub(super) header: &'data pe::ImageFileHeader,
29     pub(super) common: CoffCommon<'data>,
30     pub(super) data: Bytes<'data>,
31 }
32 
33 impl<'data> CoffFile<'data> {
34     /// Parse the raw COFF file data.
parse(data: &'data [u8]) -> Result<Self>35     pub fn parse(data: &'data [u8]) -> Result<Self> {
36         let data = Bytes(data);
37         let (header, tail) = pe::ImageFileHeader::parse(data)?;
38         let sections = header.sections(tail)?;
39         let symbols = header.symbols(data)?;
40 
41         Ok(CoffFile {
42             header,
43             common: CoffCommon {
44                 sections,
45                 symbols,
46                 image_base: 0,
47             },
48             data,
49         })
50     }
51 }
52 
53 impl<'data> read::private::Sealed for CoffFile<'data> {}
54 
55 impl<'data, 'file> Object<'data, 'file> for CoffFile<'data>
56 where
57     'data: 'file,
58 {
59     type Segment = CoffSegment<'data, 'file>;
60     type SegmentIterator = CoffSegmentIterator<'data, 'file>;
61     type Section = CoffSection<'data, 'file>;
62     type SectionIterator = CoffSectionIterator<'data, 'file>;
63     type Comdat = CoffComdat<'data, 'file>;
64     type ComdatIterator = CoffComdatIterator<'data, 'file>;
65     type Symbol = CoffSymbol<'data, 'file>;
66     type SymbolIterator = CoffSymbolIterator<'data, 'file>;
67     type SymbolTable = CoffSymbolTable<'data, 'file>;
68     type DynamicRelocationIterator = NoDynamicRelocationIterator;
69 
architecture(&self) -> Architecture70     fn architecture(&self) -> Architecture {
71         match self.header.machine.get(LE) {
72             pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386,
73             pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64,
74             _ => Architecture::Unknown,
75         }
76     }
77 
78     #[inline]
is_little_endian(&self) -> bool79     fn is_little_endian(&self) -> bool {
80         true
81     }
82 
83     #[inline]
is_64(&self) -> bool84     fn is_64(&self) -> bool {
85         // Windows COFF is always 32-bit, even for 64-bit architectures. This could be confusing.
86         false
87     }
88 
segments(&'file self) -> CoffSegmentIterator<'data, 'file>89     fn segments(&'file self) -> CoffSegmentIterator<'data, 'file> {
90         CoffSegmentIterator {
91             file: self,
92             iter: self.common.sections.iter(),
93         }
94     }
95 
section_by_name(&'file self, section_name: &str) -> Option<CoffSection<'data, 'file>>96     fn section_by_name(&'file self, section_name: &str) -> Option<CoffSection<'data, 'file>> {
97         self.sections()
98             .find(|section| section.name() == Ok(section_name))
99     }
100 
section_by_index(&'file self, index: SectionIndex) -> Result<CoffSection<'data, 'file>>101     fn section_by_index(&'file self, index: SectionIndex) -> Result<CoffSection<'data, 'file>> {
102         let section = self.common.sections.section(index.0)?;
103         Ok(CoffSection {
104             file: self,
105             index,
106             section,
107         })
108     }
109 
sections(&'file self) -> CoffSectionIterator<'data, 'file>110     fn sections(&'file self) -> CoffSectionIterator<'data, 'file> {
111         CoffSectionIterator {
112             file: self,
113             iter: self.common.sections.iter().enumerate(),
114         }
115     }
116 
comdats(&'file self) -> CoffComdatIterator<'data, 'file>117     fn comdats(&'file self) -> CoffComdatIterator<'data, 'file> {
118         CoffComdatIterator {
119             file: self,
120             index: 0,
121         }
122     }
123 
symbol_by_index(&'file self, index: SymbolIndex) -> Result<CoffSymbol<'data, 'file>>124     fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<CoffSymbol<'data, 'file>> {
125         let symbol = self.common.symbols.symbol(index.0)?;
126         Ok(CoffSymbol {
127             file: &self.common,
128             index,
129             symbol,
130         })
131     }
132 
symbols(&'file self) -> CoffSymbolIterator<'data, 'file>133     fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file> {
134         CoffSymbolIterator {
135             file: &self.common,
136             index: 0,
137         }
138     }
139 
140     #[inline]
symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file>>141     fn symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file>> {
142         Some(CoffSymbolTable { file: &self.common })
143     }
144 
dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file>145     fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file> {
146         CoffSymbolIterator {
147             file: &self.common,
148             // Hack: don't return any.
149             index: self.common.symbols.len(),
150         }
151     }
152 
153     #[inline]
dynamic_symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file>>154     fn dynamic_symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file>> {
155         None
156     }
157 
158     #[inline]
dynamic_relocations(&'file self) -> Option<NoDynamicRelocationIterator>159     fn dynamic_relocations(&'file self) -> Option<NoDynamicRelocationIterator> {
160         None
161     }
162 
163     #[inline]
imports(&self) -> Result<Vec<Import<'data>>>164     fn imports(&self) -> Result<Vec<Import<'data>>> {
165         // TODO: this could return undefined symbols, but not needed yet.
166         Ok(Vec::new())
167     }
168 
169     #[inline]
exports(&self) -> Result<Vec<Export<'data>>>170     fn exports(&self) -> Result<Vec<Export<'data>>> {
171         // TODO: this could return global symbols, but not needed yet.
172         Ok(Vec::new())
173     }
174 
has_debug_symbols(&self) -> bool175     fn has_debug_symbols(&self) -> bool {
176         self.section_by_name(".debug_info").is_some()
177     }
178 
179     #[inline]
entry(&self) -> u64180     fn entry(&self) -> u64 {
181         0
182     }
183 
flags(&self) -> FileFlags184     fn flags(&self) -> FileFlags {
185         FileFlags::Coff {
186             characteristics: self.header.characteristics.get(LE),
187         }
188     }
189 }
190 
191 impl pe::ImageFileHeader {
192     /// Read the DOS header.
193     ///
194     /// The given data must be for the entire file.  Returns the data following the optional
195     /// header, which will contain the section headers.
parse<'data>(mut data: Bytes<'data>) -> read::Result<(&'data Self, Bytes<'data>)>196     pub fn parse<'data>(mut data: Bytes<'data>) -> read::Result<(&'data Self, Bytes<'data>)> {
197         let header = data
198             .read::<pe::ImageFileHeader>()
199             .read_error("Invalid COFF file header size or alignment")?;
200 
201         // Skip over the optional header.
202         data.skip(header.size_of_optional_header.get(LE) as usize)
203             .read_error("Invalid COFF optional header size")?;
204 
205         // TODO: maybe validate that the machine is known?
206         Ok((header, data))
207     }
208 
209     /// Read the section table.
210     ///
211     /// `tail` must be the data following the optional header.
212     #[inline]
sections<'data>(&self, tail: Bytes<'data>) -> read::Result<SectionTable<'data>>213     fn sections<'data>(&self, tail: Bytes<'data>) -> read::Result<SectionTable<'data>> {
214         SectionTable::parse(self, tail)
215     }
216 
217     /// Read the symbol table and string table.
218     ///
219     /// `data` must be the entire file data.
220     #[inline]
symbols<'data>(&self, data: Bytes<'data>) -> read::Result<SymbolTable<'data>>221     fn symbols<'data>(&self, data: Bytes<'data>) -> read::Result<SymbolTable<'data>> {
222         SymbolTable::parse(self, data)
223     }
224 }
225