1 use alloc::vec::Vec;
2 use core::str;
3 
4 use crate::read::{
5     self, Architecture, FileFlags, Object, ObjectSection, ReadError, Result, SectionIndex, Symbol,
6     SymbolIndex, SymbolMap,
7 };
8 use crate::{pe, Bytes, LittleEndian as LE};
9 
10 use super::{
11     parse_symbol, CoffSection, CoffSectionIterator, CoffSegment, CoffSegmentIterator,
12     CoffSymbolIterator, SectionTable, SymbolTable,
13 };
14 
15 /// A COFF object file.
16 #[derive(Debug)]
17 pub struct CoffFile<'data> {
18     pub(super) header: &'data pe::ImageFileHeader,
19     pub(super) sections: SectionTable<'data>,
20     // TODO: ImageSymbolExBytes
21     pub(super) symbols: SymbolTable<'data>,
22     pub(super) data: Bytes<'data>,
23 }
24 
25 impl<'data> CoffFile<'data> {
26     /// Parse the raw COFF file data.
parse(data: &'data [u8]) -> Result<Self>27     pub fn parse(data: &'data [u8]) -> Result<Self> {
28         let data = Bytes(data);
29         let (header, tail) = pe::ImageFileHeader::parse(data)?;
30         let sections = header.sections(tail)?;
31         let symbols = header.symbols(data)?;
32 
33         Ok(CoffFile {
34             header,
35             sections,
36             symbols,
37             data,
38         })
39     }
40 }
41 
42 impl<'data> read::private::Sealed for CoffFile<'data> {}
43 
44 impl<'data, 'file> Object<'data, 'file> for CoffFile<'data>
45 where
46     'data: 'file,
47 {
48     type Segment = CoffSegment<'data, 'file>;
49     type SegmentIterator = CoffSegmentIterator<'data, 'file>;
50     type Section = CoffSection<'data, 'file>;
51     type SectionIterator = CoffSectionIterator<'data, 'file>;
52     type SymbolIterator = CoffSymbolIterator<'data, 'file>;
53 
architecture(&self) -> Architecture54     fn architecture(&self) -> Architecture {
55         match self.header.machine.get(LE) {
56             pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386,
57             pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64,
58             _ => Architecture::Unknown,
59         }
60     }
61 
62     #[inline]
is_little_endian(&self) -> bool63     fn is_little_endian(&self) -> bool {
64         true
65     }
66 
67     #[inline]
is_64(&self) -> bool68     fn is_64(&self) -> bool {
69         // Windows COFF is always 32-bit, even for 64-bit architectures. This could be confusing.
70         false
71     }
72 
segments(&'file self) -> CoffSegmentIterator<'data, 'file>73     fn segments(&'file self) -> CoffSegmentIterator<'data, 'file> {
74         CoffSegmentIterator {
75             file: self,
76             iter: self.sections.iter(),
77         }
78     }
79 
section_by_name(&'file self, section_name: &str) -> Option<CoffSection<'data, 'file>>80     fn section_by_name(&'file self, section_name: &str) -> Option<CoffSection<'data, 'file>> {
81         self.sections()
82             .find(|section| section.name() == Ok(section_name))
83     }
84 
section_by_index(&'file self, index: SectionIndex) -> Result<CoffSection<'data, 'file>>85     fn section_by_index(&'file self, index: SectionIndex) -> Result<CoffSection<'data, 'file>> {
86         let section = self.sections.section(index.0)?;
87         Ok(CoffSection {
88             file: self,
89             index,
90             section,
91         })
92     }
93 
sections(&'file self) -> CoffSectionIterator<'data, 'file>94     fn sections(&'file self) -> CoffSectionIterator<'data, 'file> {
95         CoffSectionIterator {
96             file: self,
97             iter: self.sections.iter().enumerate(),
98         }
99     }
100 
symbol_by_index(&self, index: SymbolIndex) -> Result<Symbol<'data>>101     fn symbol_by_index(&self, index: SymbolIndex) -> Result<Symbol<'data>> {
102         let symbol = self
103             .symbols
104             .get(index.0)
105             .read_error("Invalid COFF symbol index")?;
106         Ok(parse_symbol(&self.symbols, index.0, symbol))
107     }
108 
symbols(&'file self) -> CoffSymbolIterator<'data, 'file>109     fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file> {
110         CoffSymbolIterator {
111             symbols: &self.symbols,
112             index: 0,
113         }
114     }
115 
dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file>116     fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file> {
117         CoffSymbolIterator {
118             symbols: &self.symbols,
119             // Hack: don't return any.
120             index: self.symbols.len(),
121         }
122     }
123 
symbol_map(&self) -> SymbolMap<'data>124     fn symbol_map(&self) -> SymbolMap<'data> {
125         // TODO: untested
126         let mut symbols: Vec<_> = self
127             .symbols()
128             .map(|(_, s)| s)
129             .filter(SymbolMap::filter)
130             .collect();
131         symbols.sort_by_key(|x| x.address);
132         SymbolMap { symbols }
133     }
134 
has_debug_symbols(&self) -> bool135     fn has_debug_symbols(&self) -> bool {
136         self.section_by_name(".debug_info").is_some()
137     }
138 
139     #[inline]
entry(&self) -> u64140     fn entry(&self) -> u64 {
141         0
142     }
143 
flags(&self) -> FileFlags144     fn flags(&self) -> FileFlags {
145         FileFlags::Coff {
146             characteristics: self.header.characteristics.get(LE),
147         }
148     }
149 }
150 
151 impl pe::ImageFileHeader {
152     /// Read the DOS header.
153     ///
154     /// The given data must be for the entire file.  Returns the data following the optional
155     /// header, which will contain the section headers.
parse<'data>(mut data: Bytes<'data>) -> read::Result<(&'data Self, Bytes<'data>)>156     pub fn parse<'data>(mut data: Bytes<'data>) -> read::Result<(&'data Self, Bytes<'data>)> {
157         let header = data
158             .read::<pe::ImageFileHeader>()
159             .read_error("Invalid COFF file header size or alignment")?;
160 
161         // Skip over the optional header.
162         data.skip(header.size_of_optional_header.get(LE) as usize)
163             .read_error("Invalid COFF optional header size")?;
164 
165         // TODO: maybe validate that the machine is known?
166         Ok((header, data))
167     }
168 
169     /// Read the section table.
170     ///
171     /// `tail` must be the data following the optional header.
172     #[inline]
sections<'data>(&self, tail: Bytes<'data>) -> read::Result<SectionTable<'data>>173     fn sections<'data>(&self, tail: Bytes<'data>) -> read::Result<SectionTable<'data>> {
174         SectionTable::parse(self, tail)
175     }
176 
177     /// Read the symbol table and string table.
178     ///
179     /// `data` must be the entire file data.
180     #[inline]
symbols<'data>(&self, data: Bytes<'data>) -> read::Result<SymbolTable<'data>>181     fn symbols<'data>(&self, data: Bytes<'data>) -> read::Result<SymbolTable<'data>> {
182         SymbolTable::parse(self, data)
183     }
184 }
185