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>, from(segment: T) -> Self20 // 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. 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, from(ident: T) -> Self46 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 70 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 default() -> Self78 #[inline] 79 fn is_little_endian(&self) -> bool { 80 true 81 } 82 83 #[inline] is_empty(&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 89 fn segments(&'file self) -> CoffSegmentIterator<'data, 'file> { 90 CoffSegmentIterator { 91 file: self, 92 iter: self.common.sections.iter(), is_none(&self) -> bool93 } 94 } 95 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 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 110 fn sections(&'file self) -> CoffSectionIterator<'data, 'file> { 111 CoffSectionIterator { 112 file: self, 113 iter: self.common.sections.iter().enumerate(), 114 } 115 } 116 117 fn comdats(&'file self) -> CoffComdatIterator<'data, 'file> { 118 CoffComdatIterator { 119 file: self, 120 index: 0, 121 } 122 } 123 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 133 fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file> { 134 CoffSymbolIterator { 135 file: &self.common, 136 index: 0, 137 } 138 } 139 140 #[inline] 141 fn symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file>> { 142 Some(CoffSymbolTable { file: &self.common }) 143 } 144 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] 154 fn dynamic_symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file>> { 155 None 156 } 157 158 #[inline] 159 fn dynamic_relocations(&'file self) -> Option<NoDynamicRelocationIterator> { 160 None 161 } 162 163 #[inline] 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] 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 175 fn has_debug_symbols(&self) -> bool { 176 self.section_by_name(".debug_info").is_some() 177 } 178 179 #[inline] 180 fn entry(&self) -> u64 { 181 0 182 } 183 184 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. 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] 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] parse(input: ParseStream) -> Result<Self>221 fn symbols<'data>(&self, data: Bytes<'data>) -> read::Result<SymbolTable<'data>> { 222 SymbolTable::parse(self, data) 223 } 224 } 225