diff options
Diffstat (limited to 'vendor/object/src/read/coff/file.rs')
-rw-r--r-- | vendor/object/src/read/coff/file.rs | 219 |
1 files changed, 168 insertions, 51 deletions
diff --git a/vendor/object/src/read/coff/file.rs b/vendor/object/src/read/coff/file.rs index c6cc9f846..4219f8f02 100644 --- a/vendor/object/src/read/coff/file.rs +++ b/vendor/object/src/read/coff/file.rs @@ -1,39 +1,43 @@ use alloc::vec::Vec; +use core::fmt::Debug; use crate::read::{ self, Architecture, Export, FileFlags, Import, NoDynamicRelocationIterator, Object, ObjectKind, ObjectSection, ReadError, ReadRef, Result, SectionIndex, SymbolIndex, }; -use crate::{pe, LittleEndian as LE}; +use crate::{pe, LittleEndian as LE, Pod}; use super::{ CoffComdat, CoffComdatIterator, CoffSection, CoffSectionIterator, CoffSegment, - CoffSegmentIterator, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SectionTable, - SymbolTable, + CoffSegmentIterator, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, ImageSymbol, + SectionTable, SymbolTable, }; /// The common parts of `PeFile` and `CoffFile`. #[derive(Debug)] -pub(crate) struct CoffCommon<'data, R: ReadRef<'data>> { +pub(crate) struct CoffCommon<'data, R: ReadRef<'data>, Coff: CoffHeader = pe::ImageFileHeader> { pub(crate) sections: SectionTable<'data>, - // TODO: ImageSymbolExBytes - pub(crate) symbols: SymbolTable<'data, R>, + pub(crate) symbols: SymbolTable<'data, R, Coff>, pub(crate) image_base: u64, } +/// A COFF bigobj object file with 32-bit section numbers. +pub type CoffBigFile<'data, R = &'data [u8]> = CoffFile<'data, R, pe::AnonObjectHeaderBigobj>; + /// A COFF object file. #[derive(Debug)] -pub struct CoffFile<'data, R: ReadRef<'data> = &'data [u8]> { - pub(super) header: &'data pe::ImageFileHeader, - pub(super) common: CoffCommon<'data, R>, +pub struct CoffFile<'data, R: ReadRef<'data> = &'data [u8], Coff: CoffHeader = pe::ImageFileHeader> +{ + pub(super) header: &'data Coff, + pub(super) common: CoffCommon<'data, R, Coff>, pub(super) data: R, } -impl<'data, R: ReadRef<'data>> CoffFile<'data, R> { +impl<'data, R: ReadRef<'data>, Coff: CoffHeader> CoffFile<'data, R, Coff> { /// Parse the raw COFF file data. pub fn parse(data: R) -> Result<Self> { let mut offset = 0; - let header = pe::ImageFileHeader::parse(data, &mut offset)?; + let header = Coff::parse(data, &mut offset)?; let sections = header.sections(data, offset)?; let symbols = header.symbols(data)?; @@ -49,26 +53,30 @@ impl<'data, R: ReadRef<'data>> CoffFile<'data, R> { } } -impl<'data, R: ReadRef<'data>> read::private::Sealed for CoffFile<'data, R> {} +impl<'data, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed + for CoffFile<'data, R, Coff> +{ +} -impl<'data, 'file, R> Object<'data, 'file> for CoffFile<'data, R> +impl<'data, 'file, R, Coff> Object<'data, 'file> for CoffFile<'data, R, Coff> where 'data: 'file, R: 'file + ReadRef<'data>, + Coff: CoffHeader, { - type Segment = CoffSegment<'data, 'file, R>; - type SegmentIterator = CoffSegmentIterator<'data, 'file, R>; - type Section = CoffSection<'data, 'file, R>; - type SectionIterator = CoffSectionIterator<'data, 'file, R>; - type Comdat = CoffComdat<'data, 'file, R>; - type ComdatIterator = CoffComdatIterator<'data, 'file, R>; - type Symbol = CoffSymbol<'data, 'file, R>; - type SymbolIterator = CoffSymbolIterator<'data, 'file, R>; - type SymbolTable = CoffSymbolTable<'data, 'file, R>; + type Segment = CoffSegment<'data, 'file, R, Coff>; + type SegmentIterator = CoffSegmentIterator<'data, 'file, R, Coff>; + type Section = CoffSection<'data, 'file, R, Coff>; + type SectionIterator = CoffSectionIterator<'data, 'file, R, Coff>; + type Comdat = CoffComdat<'data, 'file, R, Coff>; + type ComdatIterator = CoffComdatIterator<'data, 'file, R, Coff>; + type Symbol = CoffSymbol<'data, 'file, R, Coff>; + type SymbolIterator = CoffSymbolIterator<'data, 'file, R, Coff>; + type SymbolTable = CoffSymbolTable<'data, 'file, R, Coff>; type DynamicRelocationIterator = NoDynamicRelocationIterator; fn architecture(&self) -> Architecture { - match self.header.machine.get(LE) { + match self.header.machine() { pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm, pe::IMAGE_FILE_MACHINE_ARM64 => Architecture::Aarch64, pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386, @@ -92,7 +100,7 @@ where ObjectKind::Relocatable } - fn segments(&'file self) -> CoffSegmentIterator<'data, 'file, R> { + fn segments(&'file self) -> CoffSegmentIterator<'data, 'file, R, Coff> { CoffSegmentIterator { file: self, iter: self.common.sections.iter(), @@ -102,12 +110,15 @@ where fn section_by_name_bytes( &'file self, section_name: &[u8], - ) -> Option<CoffSection<'data, 'file, R>> { + ) -> Option<CoffSection<'data, 'file, R, Coff>> { self.sections() .find(|section| section.name_bytes() == Ok(section_name)) } - fn section_by_index(&'file self, index: SectionIndex) -> Result<CoffSection<'data, 'file, R>> { + fn section_by_index( + &'file self, + index: SectionIndex, + ) -> Result<CoffSection<'data, 'file, R, Coff>> { let section = self.common.sections.section(index.0)?; Ok(CoffSection { file: self, @@ -116,21 +127,24 @@ where }) } - fn sections(&'file self) -> CoffSectionIterator<'data, 'file, R> { + fn sections(&'file self) -> CoffSectionIterator<'data, 'file, R, Coff> { CoffSectionIterator { file: self, iter: self.common.sections.iter().enumerate(), } } - fn comdats(&'file self) -> CoffComdatIterator<'data, 'file, R> { + fn comdats(&'file self) -> CoffComdatIterator<'data, 'file, R, Coff> { CoffComdatIterator { file: self, index: 0, } } - fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<CoffSymbol<'data, 'file, R>> { + fn symbol_by_index( + &'file self, + index: SymbolIndex, + ) -> Result<CoffSymbol<'data, 'file, R, Coff>> { let symbol = self.common.symbols.symbol(index.0)?; Ok(CoffSymbol { file: &self.common, @@ -139,7 +153,7 @@ where }) } - fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R> { + fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R, Coff> { CoffSymbolIterator { file: &self.common, index: 0, @@ -147,11 +161,11 @@ where } #[inline] - fn symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R>> { + fn symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R, Coff>> { Some(CoffSymbolTable { file: &self.common }) } - fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R> { + fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R, Coff> { CoffSymbolIterator { file: &self.common, // Hack: don't return any. @@ -160,7 +174,7 @@ where } #[inline] - fn dynamic_symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R>> { + fn dynamic_symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R, Coff>> { None } @@ -196,37 +210,51 @@ where fn flags(&self) -> FileFlags { FileFlags::Coff { - characteristics: self.header.characteristics.get(LE), + characteristics: self.header.characteristics(), } } } -impl pe::ImageFileHeader { +/// Read the `class_id` field from an anon object header. +/// +/// This can be used to determine the format of the header. +pub fn anon_object_class_id<'data, R: ReadRef<'data>>(data: R) -> Result<pe::ClsId> { + let header = data + .read_at::<pe::AnonObjectHeader>(0) + .read_error("Invalid anon object header size or alignment")?; + Ok(header.class_id) +} + +/// A trait for generic access to `ImageFileHeader` and `AnonObjectHeaderBigobj`. +#[allow(missing_docs)] +pub trait CoffHeader: Debug + Pod { + type ImageSymbol: ImageSymbol; + type ImageSymbolBytes: Debug + Pod; + + /// Return true if this type is `AnonObjectHeaderBigobj`. + /// + /// This is a property of the type, not a value in the header data. + fn is_type_bigobj() -> bool; + + fn machine(&self) -> u16; + fn number_of_sections(&self) -> u32; + fn pointer_to_symbol_table(&self) -> u32; + fn number_of_symbols(&self) -> u32; + fn characteristics(&self) -> u16; + /// Read the file header. /// /// `data` must be the entire file data. /// `offset` must be the file header offset. It is updated to point after the optional header, /// which is where the section headers are located. - pub fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> { - let header = data - .read::<pe::ImageFileHeader>(offset) - .read_error("Invalid COFF file header size or alignment")?; - - // Skip over the optional header. - *offset = offset - .checked_add(header.size_of_optional_header.get(LE).into()) - .read_error("Invalid COFF optional header size")?; - - // TODO: maybe validate that the machine is known? - Ok(header) - } + fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self>; /// Read the section table. /// /// `data` must be the entire file data. /// `offset` must be after the optional file header. #[inline] - pub fn sections<'data, R: ReadRef<'data>>( + fn sections<'data, R: ReadRef<'data>>( &self, data: R, offset: u64, @@ -238,10 +266,99 @@ impl pe::ImageFileHeader { /// /// `data` must be the entire file data. #[inline] - pub fn symbols<'data, R: ReadRef<'data>>( + fn symbols<'data, R: ReadRef<'data>>( &self, data: R, - ) -> read::Result<SymbolTable<'data, R>> { + ) -> read::Result<SymbolTable<'data, R, Self>> { SymbolTable::parse(self, data) } } + +impl CoffHeader for pe::ImageFileHeader { + type ImageSymbol = pe::ImageSymbol; + type ImageSymbolBytes = pe::ImageSymbolBytes; + + fn is_type_bigobj() -> bool { + false + } + + fn machine(&self) -> u16 { + self.machine.get(LE) + } + + fn number_of_sections(&self) -> u32 { + self.number_of_sections.get(LE).into() + } + + fn pointer_to_symbol_table(&self) -> u32 { + self.pointer_to_symbol_table.get(LE) + } + + fn number_of_symbols(&self) -> u32 { + self.number_of_symbols.get(LE) + } + + fn characteristics(&self) -> u16 { + self.characteristics.get(LE) + } + + fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> { + let header = data + .read::<pe::ImageFileHeader>(offset) + .read_error("Invalid COFF file header size or alignment")?; + + // Skip over the optional header. + *offset = offset + .checked_add(header.size_of_optional_header.get(LE).into()) + .read_error("Invalid COFF optional header size")?; + + // TODO: maybe validate that the machine is known? + Ok(header) + } +} + +impl CoffHeader for pe::AnonObjectHeaderBigobj { + type ImageSymbol = pe::ImageSymbolEx; + type ImageSymbolBytes = pe::ImageSymbolExBytes; + + fn is_type_bigobj() -> bool { + true + } + + fn machine(&self) -> u16 { + self.machine.get(LE) + } + + fn number_of_sections(&self) -> u32 { + self.number_of_sections.get(LE) + } + + fn pointer_to_symbol_table(&self) -> u32 { + self.pointer_to_symbol_table.get(LE) + } + + fn number_of_symbols(&self) -> u32 { + self.number_of_symbols.get(LE) + } + + fn characteristics(&self) -> u16 { + 0 + } + + fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> read::Result<&'data Self> { + let header = data + .read::<pe::AnonObjectHeaderBigobj>(offset) + .read_error("Invalid COFF bigobj file header size or alignment")?; + + if header.sig1.get(LE) != pe::IMAGE_FILE_MACHINE_UNKNOWN + || header.sig2.get(LE) != 0xffff + || header.version.get(LE) < 2 + || header.class_id != pe::ANON_OBJECT_HEADER_BIGOBJ_CLASS_ID + { + return Err(read::Error("Invalid COFF bigobj header values")); + } + + // TODO: maybe validate that the machine is known? + Ok(header) + } +} |