diff --git a/examples/objcopy.rs b/examples/objcopy.rs index 54b43c8b..390f5d62 100644 --- a/examples/objcopy.rs +++ b/examples/objcopy.rs @@ -2,8 +2,8 @@ use std::collections::HashMap; use std::{env, fs, process}; use object::{ - write, Object, ObjectComdat, ObjectSection, ObjectSymbol, RelocationTarget, SectionKind, - SymbolFlags, SymbolKind, SymbolSection, + write, Object, ObjectComdat, ObjectKind, ObjectSection, ObjectSymbol, RelocationTarget, + SectionKind, SymbolFlags, SymbolKind, SymbolSection, }; fn main() { @@ -38,6 +38,10 @@ fn main() { process::exit(1); } }; + if in_object.kind() != ObjectKind::Relocatable { + eprintln!("Unsupported object kind: {:?}", in_object.kind()); + process::exit(1); + } let mut out_object = write::Object::new( in_object.format(), diff --git a/examples/objdump.rs b/examples/objdump.rs index b6eb0003..917264a4 100644 --- a/examples/objdump.rs +++ b/examples/objdump.rs @@ -120,6 +120,7 @@ fn dump_parsed_object(file: &object::File) { file.endianness(), if file.is_64() { "64" } else { "32" } ); + println!("Kind: {:?}", file.kind()); println!("Architecture: {:?}", file.architecture()); println!("Flags: {:x?}", file.flags()); println!("Relative Address Base: {:x?}", file.relative_address_base()); diff --git a/src/read/any.rs b/src/read/any.rs index cb7cd925..940cf278 100644 --- a/src/read/any.rs +++ b/src/read/any.rs @@ -14,10 +14,10 @@ use crate::read::pe; use crate::read::wasm; use crate::read::{ self, Architecture, BinaryFormat, CodeView, ComdatKind, CompressedData, CompressedFileRange, - Error, Export, FileFlags, FileKind, Import, Object, ObjectComdat, ObjectMap, ObjectSection, - ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadRef, Relocation, Result, SectionFlags, - SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapName, - SymbolScope, SymbolSection, + Error, Export, FileFlags, FileKind, Import, Object, ObjectComdat, ObjectKind, ObjectMap, + ObjectSection, ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadRef, Relocation, Result, + SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, + SymbolMapName, SymbolScope, SymbolSection, }; #[allow(unused_imports)] use crate::Endianness; @@ -286,6 +286,10 @@ where with_inner!(self.inner, FileInternal, |x| x.is_64()) } + fn kind(&self) -> ObjectKind { + with_inner!(self.inner, FileInternal, |x| x.kind()) + } + fn segments(&'file self) -> SegmentIterator<'data, 'file, R> { SegmentIterator { inner: map_inner!(self.inner, FileInternal, SegmentIteratorInternal, |x| x diff --git a/src/read/coff/file.rs b/src/read/coff/file.rs index 84ed8191..c6cc9f84 100644 --- a/src/read/coff/file.rs +++ b/src/read/coff/file.rs @@ -1,7 +1,7 @@ use alloc::vec::Vec; use crate::read::{ - self, Architecture, Export, FileFlags, Import, NoDynamicRelocationIterator, Object, + self, Architecture, Export, FileFlags, Import, NoDynamicRelocationIterator, Object, ObjectKind, ObjectSection, ReadError, ReadRef, Result, SectionIndex, SymbolIndex, }; use crate::{pe, LittleEndian as LE}; @@ -88,6 +88,10 @@ where false } + fn kind(&self) -> ObjectKind { + ObjectKind::Relocatable + } + fn segments(&'file self) -> CoffSegmentIterator<'data, 'file, R> { CoffSegmentIterator { file: self, diff --git a/src/read/elf/file.rs b/src/read/elf/file.rs index a26737cd..7df4ab2c 100644 --- a/src/read/elf/file.rs +++ b/src/read/elf/file.rs @@ -5,7 +5,7 @@ use core::mem; use crate::read::{ self, util, Architecture, ByteString, Bytes, Error, Export, FileFlags, Import, Object, - ReadError, ReadRef, SectionIndex, StringTable, SymbolIndex, + ObjectKind, ReadError, ReadRef, SectionIndex, StringTable, SymbolIndex, }; use crate::{elf, endian, Endian, Endianness, Pod, U32}; @@ -189,6 +189,17 @@ where self.header.is_class_64() } + fn kind(&self) -> ObjectKind { + match self.header.e_type(self.endian) { + elf::ET_REL => ObjectKind::Relocatable, + elf::ET_EXEC => ObjectKind::Executable, + // TODO: check for `DF_1_PIE`? + elf::ET_DYN => ObjectKind::Dynamic, + elf::ET_CORE => ObjectKind::Core, + _ => ObjectKind::Unknown, + } + } + fn segments(&'file self) -> ElfSegmentIterator<'data, 'file, Elf, R> { ElfSegmentIterator { file: self, diff --git a/src/read/macho/file.rs b/src/read/macho/file.rs index 85936588..0d4961b1 100644 --- a/src/read/macho/file.rs +++ b/src/read/macho/file.rs @@ -4,8 +4,8 @@ use core::{mem, str}; use crate::read::{ self, Architecture, ComdatKind, Error, Export, FileFlags, Import, NoDynamicRelocationIterator, - Object, ObjectComdat, ObjectMap, ObjectSection, ReadError, ReadRef, Result, SectionIndex, - SymbolIndex, + Object, ObjectComdat, ObjectKind, ObjectMap, ObjectSection, ReadError, ReadRef, Result, + SectionIndex, SymbolIndex, }; use crate::{endian, macho, BigEndian, ByteString, Endian, Endianness, Pod}; @@ -142,6 +142,16 @@ where self.header.is_type_64() } + fn kind(&self) -> ObjectKind { + match self.header.filetype(self.endian) { + macho::MH_OBJECT => ObjectKind::Relocatable, + macho::MH_EXECUTE => ObjectKind::Executable, + macho::MH_CORE => ObjectKind::Core, + macho::MH_DYLIB => ObjectKind::Dynamic, + _ => ObjectKind::Unknown, + } + } + fn segments(&'file self) -> MachOSegmentIterator<'data, 'file, Mach, R> { MachOSegmentIterator { file: self, diff --git a/src/read/mod.rs b/src/read/mod.rs index 83dff5d5..17f1ec32 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -136,7 +136,7 @@ pub type NativeFile<'data, R = &'data [u8]> = pe::PeFile64<'data, R>; #[cfg(all(feature = "wasm", target_arch = "wasm32", feature = "wasm"))] pub type NativeFile<'data, R = &'data [u8]> = wasm::WasmFile<'data, R>; -/// An object file kind. +/// A file format kind. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum FileKind { @@ -242,6 +242,22 @@ impl FileKind { } } +/// An object kind. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum ObjectKind { + /// The object kind is unknown. + Unknown, + /// Relocatable object. + Relocatable, + /// Executable. + Executable, + /// Dynamic shared object. + Dynamic, + /// Core. + Core, +} + /// The index used to identify a section of a file. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct SectionIndex(pub usize); diff --git a/src/read/pe/file.rs b/src/read/pe/file.rs index de91e832..5a190898 100644 --- a/src/read/pe/file.rs +++ b/src/read/pe/file.rs @@ -7,7 +7,7 @@ use core::convert::TryInto; use crate::read::coff::{CoffCommon, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SymbolTable}; use crate::read::{ self, Architecture, ComdatKind, Error, Export, FileFlags, Import, NoDynamicRelocationIterator, - Object, ObjectComdat, ReadError, ReadRef, Result, SectionIndex, SymbolIndex, + Object, ObjectComdat, ObjectKind, ReadError, ReadRef, Result, SectionIndex, SymbolIndex, }; use crate::{pe, ByteString, Bytes, CodeView, LittleEndian as LE, Pod, U32, U64}; @@ -140,6 +140,17 @@ where self.nt_headers.is_type_64() } + fn kind(&self) -> ObjectKind { + let characteristics = self.nt_headers.file_header().characteristics.get(LE); + if characteristics & pe::IMAGE_FILE_DLL != 0 { + ObjectKind::Dynamic + } else if characteristics & pe::IMAGE_FILE_SYSTEM != 0 { + ObjectKind::Unknown + } else { + ObjectKind::Executable + } + } + fn segments(&'file self) -> PeSegmentIterator<'data, 'file, Pe, R> { PeSegmentIterator { file: self, diff --git a/src/read/traits.rs b/src/read/traits.rs index 91f49939..e28bd8ff 100644 --- a/src/read/traits.rs +++ b/src/read/traits.rs @@ -3,8 +3,9 @@ use alloc::vec::Vec; use crate::read::{ self, Architecture, CodeView, ComdatKind, CompressedData, CompressedFileRange, Export, - FileFlags, Import, ObjectMap, Relocation, Result, SectionFlags, SectionIndex, SectionKind, - SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapName, SymbolScope, SymbolSection, + FileFlags, Import, ObjectKind, ObjectMap, Relocation, Result, SectionFlags, SectionIndex, + SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapName, SymbolScope, + SymbolSection, }; use crate::Endianness; @@ -66,6 +67,9 @@ pub trait Object<'data: 'file, 'file>: read::private::Sealed { /// Return true if the file can contain 64-bit addresses. fn is_64(&self) -> bool; + /// Return the kind of this object. + fn kind(&self) -> ObjectKind; + /// Get an iterator over the segments in the file. fn segments(&'file self) -> Self::SegmentIterator; diff --git a/src/read/wasm.rs b/src/read/wasm.rs index b62da615..29318f84 100644 --- a/src/read/wasm.rs +++ b/src/read/wasm.rs @@ -11,9 +11,10 @@ use wasmparser as wp; use crate::read::{ self, Architecture, ComdatKind, CompressedData, CompressedFileRange, Error, Export, FileFlags, - Import, NoDynamicRelocationIterator, Object, ObjectComdat, ObjectSection, ObjectSegment, - ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Relocation, Result, SectionFlags, - SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, SymbolSection, + Import, NoDynamicRelocationIterator, Object, ObjectComdat, ObjectKind, ObjectSection, + ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Relocation, Result, + SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, + SymbolSection, }; const SECTION_CUSTOM: usize = 0; @@ -326,6 +327,11 @@ where false } + fn kind(&self) -> ObjectKind { + // TODO: check for `linking` custom section + ObjectKind::Unknown + } + fn segments(&'file self) -> Self::SegmentIterator { WasmSegmentIterator { file: self } }