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