diff options
Diffstat (limited to 'vendor/object/src/read/macho')
-rw-r--r-- | vendor/object/src/read/macho/dyld_cache.rs | 344 | ||||
-rw-r--r-- | vendor/object/src/read/macho/fat.rs | 122 | ||||
-rw-r--r-- | vendor/object/src/read/macho/file.rs | 781 | ||||
-rw-r--r-- | vendor/object/src/read/macho/load_command.rs | 382 | ||||
-rw-r--r-- | vendor/object/src/read/macho/mod.rs | 72 | ||||
-rw-r--r-- | vendor/object/src/read/macho/relocation.rs | 158 | ||||
-rw-r--r-- | vendor/object/src/read/macho/section.rs | 389 | ||||
-rw-r--r-- | vendor/object/src/read/macho/segment.rs | 303 | ||||
-rw-r--r-- | vendor/object/src/read/macho/symbol.rs | 492 |
9 files changed, 0 insertions, 3043 deletions
diff --git a/vendor/object/src/read/macho/dyld_cache.rs b/vendor/object/src/read/macho/dyld_cache.rs deleted file mode 100644 index 0f5dfc5..0000000 --- a/vendor/object/src/read/macho/dyld_cache.rs +++ /dev/null @@ -1,344 +0,0 @@ -use alloc::vec::Vec; -use core::slice; - -use crate::read::{Error, File, ReadError, ReadRef, Result}; -use crate::{macho, Architecture, Endian, Endianness}; - -/// A parsed representation of the dyld shared cache. -#[derive(Debug)] -pub struct DyldCache<'data, E = Endianness, R = &'data [u8]> -where - E: Endian, - R: ReadRef<'data>, -{ - endian: E, - data: R, - subcaches: Vec<DyldSubCache<'data, E, R>>, - mappings: &'data [macho::DyldCacheMappingInfo<E>], - images: &'data [macho::DyldCacheImageInfo<E>], - arch: Architecture, -} - -/// Information about a subcache. -#[derive(Debug)] -pub struct DyldSubCache<'data, E = Endianness, R = &'data [u8]> -where - E: Endian, - R: ReadRef<'data>, -{ - data: R, - mappings: &'data [macho::DyldCacheMappingInfo<E>], -} - -// This is the offset of the images_across_all_subcaches_count field. -const MIN_HEADER_SIZE_SUBCACHES: u32 = 0x1c4; - -impl<'data, E, R> DyldCache<'data, E, R> -where - E: Endian, - R: ReadRef<'data>, -{ - /// Parse the raw dyld shared cache data. - /// - /// For shared caches from macOS 12 / iOS 15 and above, the subcache files need to be - /// supplied as well, in the correct order, with the `.symbols` subcache last (if present). - /// For example, `data` would be the data for `dyld_shared_cache_x86_64`, - /// and `subcache_data` would be the data for `[dyld_shared_cache_x86_64.1, dyld_shared_cache_x86_64.2, ...]`. - pub fn parse(data: R, subcache_data: &[R]) -> Result<Self> { - let header = macho::DyldCacheHeader::parse(data)?; - let (arch, endian) = header.parse_magic()?; - let mappings = header.mappings(endian, data)?; - - let symbols_subcache_uuid = header.symbols_subcache_uuid(endian); - let subcaches_info = header.subcaches(endian, data)?.unwrap_or(&[]); - - if subcache_data.len() != subcaches_info.len() + symbols_subcache_uuid.is_some() as usize { - return Err(Error("Incorrect number of SubCaches")); - } - - // Split out the .symbols subcache data from the other subcaches. - let (symbols_subcache_data_and_uuid, subcache_data) = - if let Some(symbols_uuid) = symbols_subcache_uuid { - let (sym_data, rest_data) = subcache_data.split_last().unwrap(); - (Some((*sym_data, symbols_uuid)), rest_data) - } else { - (None, subcache_data) - }; - - // Read the regular SubCaches (.1, .2, ...), if present. - let mut subcaches = Vec::new(); - for (&data, info) in subcache_data.iter().zip(subcaches_info.iter()) { - let sc_header = macho::DyldCacheHeader::<E>::parse(data)?; - if sc_header.uuid != info.uuid { - return Err(Error("Unexpected SubCache UUID")); - } - let mappings = sc_header.mappings(endian, data)?; - subcaches.push(DyldSubCache { data, mappings }); - } - - // Read the .symbols SubCache, if present. - // Other than the UUID verification, the symbols SubCache is currently unused. - let _symbols_subcache = match symbols_subcache_data_and_uuid { - Some((data, uuid)) => { - let sc_header = macho::DyldCacheHeader::<E>::parse(data)?; - if sc_header.uuid != uuid { - return Err(Error("Unexpected .symbols SubCache UUID")); - } - let mappings = sc_header.mappings(endian, data)?; - Some(DyldSubCache { data, mappings }) - } - None => None, - }; - - let images = header.images(endian, data)?; - Ok(DyldCache { - endian, - data, - subcaches, - mappings, - images, - arch, - }) - } - - /// Get the architecture type of the file. - pub fn architecture(&self) -> Architecture { - self.arch - } - - /// Get the endianness of the file. - #[inline] - pub fn endianness(&self) -> Endianness { - if self.is_little_endian() { - Endianness::Little - } else { - Endianness::Big - } - } - - /// Return true if the file is little endian, false if it is big endian. - pub fn is_little_endian(&self) -> bool { - self.endian.is_little_endian() - } - - /// Iterate over the images in this cache. - pub fn images<'cache>(&'cache self) -> DyldCacheImageIterator<'data, 'cache, E, R> { - DyldCacheImageIterator { - cache: self, - iter: self.images.iter(), - } - } - - /// Find the address in a mapping and return the cache or subcache data it was found in, - /// together with the translated file offset. - pub fn data_and_offset_for_address(&self, address: u64) -> Option<(R, u64)> { - if let Some(file_offset) = address_to_file_offset(address, self.endian, self.mappings) { - return Some((self.data, file_offset)); - } - for subcache in &self.subcaches { - if let Some(file_offset) = - address_to_file_offset(address, self.endian, subcache.mappings) - { - return Some((subcache.data, file_offset)); - } - } - None - } -} - -/// An iterator over all the images (dylibs) in the dyld shared cache. -#[derive(Debug)] -pub struct DyldCacheImageIterator<'data, 'cache, E = Endianness, R = &'data [u8]> -where - E: Endian, - R: ReadRef<'data>, -{ - cache: &'cache DyldCache<'data, E, R>, - iter: slice::Iter<'data, macho::DyldCacheImageInfo<E>>, -} - -impl<'data, 'cache, E, R> Iterator for DyldCacheImageIterator<'data, 'cache, E, R> -where - E: Endian, - R: ReadRef<'data>, -{ - type Item = DyldCacheImage<'data, 'cache, E, R>; - - fn next(&mut self) -> Option<DyldCacheImage<'data, 'cache, E, R>> { - let image_info = self.iter.next()?; - Some(DyldCacheImage { - cache: self.cache, - image_info, - }) - } -} - -/// One image (dylib) from inside the dyld shared cache. -#[derive(Debug)] -pub struct DyldCacheImage<'data, 'cache, E = Endianness, R = &'data [u8]> -where - E: Endian, - R: ReadRef<'data>, -{ - pub(crate) cache: &'cache DyldCache<'data, E, R>, - image_info: &'data macho::DyldCacheImageInfo<E>, -} - -impl<'data, 'cache, E, R> DyldCacheImage<'data, 'cache, E, R> -where - E: Endian, - R: ReadRef<'data>, -{ - /// The file system path of this image. - pub fn path(&self) -> Result<&'data str> { - let path = self.image_info.path(self.cache.endian, self.cache.data)?; - // The path should always be ascii, so from_utf8 should always succeed. - let path = core::str::from_utf8(path).map_err(|_| Error("Path string not valid utf-8"))?; - Ok(path) - } - - /// The subcache data which contains the Mach-O header for this image, - /// together with the file offset at which this image starts. - pub fn image_data_and_offset(&self) -> Result<(R, u64)> { - let address = self.image_info.address.get(self.cache.endian); - self.cache - .data_and_offset_for_address(address) - .ok_or(Error("Address not found in any mapping")) - } - - /// Parse this image into an Object. - pub fn parse_object(&self) -> Result<File<'data, R>> { - File::parse_dyld_cache_image(self) - } -} - -impl<E: Endian> macho::DyldCacheHeader<E> { - /// Read the dyld cache header. - pub fn parse<'data, R: ReadRef<'data>>(data: R) -> Result<&'data Self> { - data.read_at::<macho::DyldCacheHeader<E>>(0) - .read_error("Invalid dyld cache header size or alignment") - } - - /// Returns (arch, endian) based on the magic string. - pub fn parse_magic(&self) -> Result<(Architecture, E)> { - let (arch, is_big_endian) = match &self.magic { - b"dyld_v1 i386\0" => (Architecture::I386, false), - b"dyld_v1 x86_64\0" => (Architecture::X86_64, false), - b"dyld_v1 x86_64h\0" => (Architecture::X86_64, false), - b"dyld_v1 ppc\0" => (Architecture::PowerPc, true), - b"dyld_v1 armv6\0" => (Architecture::Arm, false), - b"dyld_v1 armv7\0" => (Architecture::Arm, false), - b"dyld_v1 armv7f\0" => (Architecture::Arm, false), - b"dyld_v1 armv7s\0" => (Architecture::Arm, false), - b"dyld_v1 armv7k\0" => (Architecture::Arm, false), - b"dyld_v1 arm64\0" => (Architecture::Aarch64, false), - b"dyld_v1 arm64e\0" => (Architecture::Aarch64, false), - _ => return Err(Error("Unrecognized dyld cache magic")), - }; - let endian = - E::from_big_endian(is_big_endian).read_error("Unsupported dyld cache endian")?; - Ok((arch, endian)) - } - - /// Return the mapping information table. - pub fn mappings<'data, R: ReadRef<'data>>( - &self, - endian: E, - data: R, - ) -> Result<&'data [macho::DyldCacheMappingInfo<E>]> { - data.read_slice_at::<macho::DyldCacheMappingInfo<E>>( - self.mapping_offset.get(endian).into(), - self.mapping_count.get(endian) as usize, - ) - .read_error("Invalid dyld cache mapping size or alignment") - } - - /// Return the information about subcaches, if present. - pub fn subcaches<'data, R: ReadRef<'data>>( - &self, - endian: E, - data: R, - ) -> Result<Option<&'data [macho::DyldSubCacheInfo<E>]>> { - if self.mapping_offset.get(endian) >= MIN_HEADER_SIZE_SUBCACHES { - let subcaches = data - .read_slice_at::<macho::DyldSubCacheInfo<E>>( - self.subcaches_offset.get(endian).into(), - self.subcaches_count.get(endian) as usize, - ) - .read_error("Invalid dyld subcaches size or alignment")?; - Ok(Some(subcaches)) - } else { - Ok(None) - } - } - - /// Return the UUID for the .symbols subcache, if present. - pub fn symbols_subcache_uuid(&self, endian: E) -> Option<[u8; 16]> { - if self.mapping_offset.get(endian) >= MIN_HEADER_SIZE_SUBCACHES { - let uuid = self.symbols_subcache_uuid; - if uuid != [0; 16] { - return Some(uuid); - } - } - None - } - - /// Return the image information table. - pub fn images<'data, R: ReadRef<'data>>( - &self, - endian: E, - data: R, - ) -> Result<&'data [macho::DyldCacheImageInfo<E>]> { - if self.mapping_offset.get(endian) >= MIN_HEADER_SIZE_SUBCACHES { - data.read_slice_at::<macho::DyldCacheImageInfo<E>>( - self.images_across_all_subcaches_offset.get(endian).into(), - self.images_across_all_subcaches_count.get(endian) as usize, - ) - .read_error("Invalid dyld cache image size or alignment") - } else { - data.read_slice_at::<macho::DyldCacheImageInfo<E>>( - self.images_offset.get(endian).into(), - self.images_count.get(endian) as usize, - ) - .read_error("Invalid dyld cache image size or alignment") - } - } -} - -impl<E: Endian> macho::DyldCacheImageInfo<E> { - /// The file system path of this image. - pub fn path<'data, R: ReadRef<'data>>(&self, endian: E, data: R) -> Result<&'data [u8]> { - let r_start = self.path_file_offset.get(endian).into(); - let r_end = data.len().read_error("Couldn't get data len()")?; - data.read_bytes_at_until(r_start..r_end, 0) - .read_error("Couldn't read dyld cache image path") - } - - /// Find the file offset of the image by looking up its address in the mappings. - pub fn file_offset( - &self, - endian: E, - mappings: &[macho::DyldCacheMappingInfo<E>], - ) -> Result<u64> { - let address = self.address.get(endian); - address_to_file_offset(address, endian, mappings) - .read_error("Invalid dyld cache image address") - } -} - -/// Find the file offset of the image by looking up its address in the mappings. -pub fn address_to_file_offset<E: Endian>( - address: u64, - endian: E, - mappings: &[macho::DyldCacheMappingInfo<E>], -) -> Option<u64> { - for mapping in mappings { - let mapping_address = mapping.address.get(endian); - if address >= mapping_address - && address < mapping_address.wrapping_add(mapping.size.get(endian)) - { - return Some(address - mapping_address + mapping.file_offset.get(endian)); - } - } - None -} diff --git a/vendor/object/src/read/macho/fat.rs b/vendor/object/src/read/macho/fat.rs deleted file mode 100644 index a481351..0000000 --- a/vendor/object/src/read/macho/fat.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::read::{Architecture, Error, ReadError, ReadRef, Result}; -use crate::{macho, BigEndian, Pod}; - -pub use macho::{FatArch32, FatArch64, FatHeader}; - -impl FatHeader { - /// Attempt to parse a fat header. - /// - /// Does not validate the magic value. - pub fn parse<'data, R: ReadRef<'data>>(file: R) -> Result<&'data FatHeader> { - file.read_at::<FatHeader>(0) - .read_error("Invalid fat header size or alignment") - } - - /// Attempt to parse a fat header and 32-bit fat arches. - pub fn parse_arch32<'data, R: ReadRef<'data>>(file: R) -> Result<&'data [FatArch32]> { - let mut offset = 0; - let header = file - .read::<FatHeader>(&mut offset) - .read_error("Invalid fat header size or alignment")?; - if header.magic.get(BigEndian) != macho::FAT_MAGIC { - return Err(Error("Invalid 32-bit fat magic")); - } - file.read_slice::<FatArch32>(&mut offset, header.nfat_arch.get(BigEndian) as usize) - .read_error("Invalid nfat_arch") - } - - /// Attempt to parse a fat header and 64-bit fat arches. - pub fn parse_arch64<'data, R: ReadRef<'data>>(file: R) -> Result<&'data [FatArch64]> { - let mut offset = 0; - let header = file - .read::<FatHeader>(&mut offset) - .read_error("Invalid fat header size or alignment")?; - if header.magic.get(BigEndian) != macho::FAT_MAGIC_64 { - return Err(Error("Invalid 64-bit fat magic")); - } - file.read_slice::<FatArch64>(&mut offset, header.nfat_arch.get(BigEndian) as usize) - .read_error("Invalid nfat_arch") - } -} - -/// A trait for generic access to [`macho::FatArch32`] and [`macho::FatArch64`]. -#[allow(missing_docs)] -pub trait FatArch: Pod { - type Word: Into<u64>; - - fn cputype(&self) -> u32; - fn cpusubtype(&self) -> u32; - fn offset(&self) -> Self::Word; - fn size(&self) -> Self::Word; - fn align(&self) -> u32; - - fn architecture(&self) -> Architecture { - match self.cputype() { - macho::CPU_TYPE_ARM => Architecture::Arm, - macho::CPU_TYPE_ARM64 => Architecture::Aarch64, - macho::CPU_TYPE_X86 => Architecture::I386, - macho::CPU_TYPE_X86_64 => Architecture::X86_64, - macho::CPU_TYPE_MIPS => Architecture::Mips, - macho::CPU_TYPE_POWERPC => Architecture::PowerPc, - macho::CPU_TYPE_POWERPC64 => Architecture::PowerPc64, - _ => Architecture::Unknown, - } - } - - fn file_range(&self) -> (u64, u64) { - (self.offset().into(), self.size().into()) - } - - fn data<'data, R: ReadRef<'data>>(&self, file: R) -> Result<&'data [u8]> { - file.read_bytes_at(self.offset().into(), self.size().into()) - .read_error("Invalid fat arch offset or size") - } -} - -impl FatArch for FatArch32 { - type Word = u32; - - fn cputype(&self) -> u32 { - self.cputype.get(BigEndian) - } - - fn cpusubtype(&self) -> u32 { - self.cpusubtype.get(BigEndian) - } - - fn offset(&self) -> Self::Word { - self.offset.get(BigEndian) - } - - fn size(&self) -> Self::Word { - self.size.get(BigEndian) - } - - fn align(&self) -> u32 { - self.align.get(BigEndian) - } -} - -impl FatArch for FatArch64 { - type Word = u64; - - fn cputype(&self) -> u32 { - self.cputype.get(BigEndian) - } - - fn cpusubtype(&self) -> u32 { - self.cpusubtype.get(BigEndian) - } - - fn offset(&self) -> Self::Word { - self.offset.get(BigEndian) - } - - fn size(&self) -> Self::Word { - self.size.get(BigEndian) - } - - fn align(&self) -> u32 { - self.align.get(BigEndian) - } -} diff --git a/vendor/object/src/read/macho/file.rs b/vendor/object/src/read/macho/file.rs deleted file mode 100644 index 0e04477..0000000 --- a/vendor/object/src/read/macho/file.rs +++ /dev/null @@ -1,781 +0,0 @@ -use alloc::vec::Vec; -use core::fmt::Debug; -use core::{mem, str}; - -use crate::read::{ - self, Architecture, ComdatKind, Error, Export, FileFlags, Import, NoDynamicRelocationIterator, - Object, ObjectComdat, ObjectKind, ObjectMap, ObjectSection, ReadError, ReadRef, Result, - SectionIndex, SubArchitecture, SymbolIndex, -}; -use crate::{endian, macho, BigEndian, ByteString, Endian, Endianness, Pod}; - -use super::{ - DyldCacheImage, LoadCommandIterator, MachOSection, MachOSectionInternal, MachOSectionIterator, - MachOSegment, MachOSegmentInternal, MachOSegmentIterator, MachOSymbol, MachOSymbolIterator, - MachOSymbolTable, Nlist, Section, Segment, SymbolTable, -}; - -/// A 32-bit Mach-O object file. -/// -/// This is a file that starts with [`macho::MachHeader32`], and corresponds -/// to [`crate::FileKind::MachO32`]. -pub type MachOFile32<'data, Endian = Endianness, R = &'data [u8]> = - MachOFile<'data, macho::MachHeader32<Endian>, R>; -/// A 64-bit Mach-O object file. -/// -/// This is a file that starts with [`macho::MachHeader64`], and corresponds -/// to [`crate::FileKind::MachO64`]. -pub type MachOFile64<'data, Endian = Endianness, R = &'data [u8]> = - MachOFile<'data, macho::MachHeader64<Endian>, R>; - -/// A partially parsed Mach-O file. -/// -/// Most of the functionality of this type is provided by the [`Object`] trait implementation. -#[derive(Debug)] -pub struct MachOFile<'data, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - pub(super) endian: Mach::Endian, - pub(super) data: R, - pub(super) header_offset: u64, - pub(super) header: &'data Mach, - pub(super) segments: Vec<MachOSegmentInternal<'data, Mach, R>>, - pub(super) sections: Vec<MachOSectionInternal<'data, Mach>>, - pub(super) symbols: SymbolTable<'data, Mach, R>, -} - -impl<'data, Mach, R> MachOFile<'data, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - /// Parse the raw Mach-O file data. - pub fn parse(data: R) -> Result<Self> { - let header = Mach::parse(data, 0)?; - let endian = header.endian()?; - - // Build a list of segments and sections to make some operations more efficient. - let mut segments = Vec::new(); - let mut sections = Vec::new(); - let mut symbols = SymbolTable::default(); - if let Ok(mut commands) = header.load_commands(endian, data, 0) { - while let Ok(Some(command)) = commands.next() { - if let Some((segment, section_data)) = Mach::Segment::from_command(command)? { - let segment_index = segments.len(); - segments.push(MachOSegmentInternal { segment, data }); - for section in segment.sections(endian, section_data)? { - let index = SectionIndex(sections.len() + 1); - sections.push(MachOSectionInternal::parse(index, segment_index, section)); - } - } else if let Some(symtab) = command.symtab()? { - symbols = symtab.symbols(endian, data)?; - } - } - } - - Ok(MachOFile { - endian, - data, - header_offset: 0, - header, - segments, - sections, - symbols, - }) - } - - /// Parse the Mach-O file for the given image from the dyld shared cache. - /// This will read different sections from different subcaches, if necessary. - pub fn parse_dyld_cache_image<'cache, E: Endian>( - image: &DyldCacheImage<'data, 'cache, E, R>, - ) -> Result<Self> { - let (data, header_offset) = image.image_data_and_offset()?; - let header = Mach::parse(data, header_offset)?; - let endian = header.endian()?; - - // Build a list of sections to make some operations more efficient. - // Also build a list of segments, because we need to remember which ReadRef - // to read each section's data from. Only the DyldCache knows this information, - // and we won't have access to it once we've exited this function. - let mut segments = Vec::new(); - let mut sections = Vec::new(); - let mut linkedit_data: Option<R> = None; - let mut symtab = None; - if let Ok(mut commands) = header.load_commands(endian, data, header_offset) { - while let Ok(Some(command)) = commands.next() { - if let Some((segment, section_data)) = Mach::Segment::from_command(command)? { - // Each segment can be stored in a different subcache. Get the segment's - // address and look it up in the cache mappings, to find the correct cache data. - let addr = segment.vmaddr(endian).into(); - let (data, _offset) = image - .cache - .data_and_offset_for_address(addr) - .read_error("Could not find segment data in dyld shared cache")?; - if segment.name() == macho::SEG_LINKEDIT.as_bytes() { - linkedit_data = Some(data); - } - let segment_index = segments.len(); - segments.push(MachOSegmentInternal { segment, data }); - - for section in segment.sections(endian, section_data)? { - let index = SectionIndex(sections.len() + 1); - sections.push(MachOSectionInternal::parse(index, segment_index, section)); - } - } else if let Some(st) = command.symtab()? { - symtab = Some(st); - } - } - } - - // The symbols are found in the __LINKEDIT segment, so make sure to read them from the - // correct subcache. - let symbols = match (symtab, linkedit_data) { - (Some(symtab), Some(linkedit_data)) => symtab.symbols(endian, linkedit_data)?, - _ => SymbolTable::default(), - }; - - Ok(MachOFile { - endian, - data, - header_offset, - header, - segments, - sections, - symbols, - }) - } - - /// Return the section at the given index. - #[inline] - pub(super) fn section_internal( - &self, - index: SectionIndex, - ) -> Result<&MachOSectionInternal<'data, Mach>> { - index - .0 - .checked_sub(1) - .and_then(|index| self.sections.get(index)) - .read_error("Invalid Mach-O section index") - } - - pub(super) fn segment_internal( - &self, - index: usize, - ) -> Result<&MachOSegmentInternal<'data, Mach, R>> { - self.segments - .get(index) - .read_error("Invalid Mach-O segment index") - } - - /// Returns the endianness. - pub fn endian(&self) -> Mach::Endian { - self.endian - } - - /// Returns the raw data. - pub fn data(&self) -> R { - self.data - } - - /// Returns the raw Mach-O file header. - pub fn raw_header(&self) -> &'data Mach { - self.header - } - - /// Return the `LC_BUILD_VERSION` load command if present. - pub fn build_version(&self) -> Result<Option<&'data macho::BuildVersionCommand<Mach::Endian>>> { - let mut commands = self - .header - .load_commands(self.endian, self.data, self.header_offset)?; - while let Some(command) = commands.next()? { - if let Some(build_version) = command.build_version()? { - return Ok(Some(build_version)); - } - } - Ok(None) - } -} - -impl<'data, Mach, R> read::private::Sealed for MachOFile<'data, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Mach, R> Object<'data, 'file> for MachOFile<'data, Mach, R> -where - 'data: 'file, - Mach: MachHeader, - R: 'file + ReadRef<'data>, -{ - type Segment = MachOSegment<'data, 'file, Mach, R>; - type SegmentIterator = MachOSegmentIterator<'data, 'file, Mach, R>; - type Section = MachOSection<'data, 'file, Mach, R>; - type SectionIterator = MachOSectionIterator<'data, 'file, Mach, R>; - type Comdat = MachOComdat<'data, 'file, Mach, R>; - type ComdatIterator = MachOComdatIterator<'data, 'file, Mach, R>; - type Symbol = MachOSymbol<'data, 'file, Mach, R>; - type SymbolIterator = MachOSymbolIterator<'data, 'file, Mach, R>; - type SymbolTable = MachOSymbolTable<'data, 'file, Mach, R>; - type DynamicRelocationIterator = NoDynamicRelocationIterator; - - fn architecture(&self) -> Architecture { - match self.header.cputype(self.endian) { - macho::CPU_TYPE_ARM => Architecture::Arm, - macho::CPU_TYPE_ARM64 => Architecture::Aarch64, - macho::CPU_TYPE_ARM64_32 => Architecture::Aarch64_Ilp32, - macho::CPU_TYPE_X86 => Architecture::I386, - macho::CPU_TYPE_X86_64 => Architecture::X86_64, - macho::CPU_TYPE_MIPS => Architecture::Mips, - macho::CPU_TYPE_POWERPC => Architecture::PowerPc, - macho::CPU_TYPE_POWERPC64 => Architecture::PowerPc64, - _ => Architecture::Unknown, - } - } - - fn sub_architecture(&self) -> Option<SubArchitecture> { - match ( - self.header.cputype(self.endian), - self.header.cpusubtype(self.endian), - ) { - (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64E) => Some(SubArchitecture::Arm64E), - _ => None, - } - } - - #[inline] - fn is_little_endian(&self) -> bool { - self.header.is_little_endian() - } - - #[inline] - fn is_64(&self) -> bool { - 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, - iter: self.segments.iter(), - } - } - - fn section_by_name_bytes( - &'file self, - section_name: &[u8], - ) -> Option<MachOSection<'data, 'file, Mach, R>> { - // Translate the "." prefix to the "__" prefix used by OSX/Mach-O, eg - // ".debug_info" to "__debug_info", and limit to 16 bytes total. - let system_name = if section_name.starts_with(b".") { - if section_name.len() > 15 { - Some(§ion_name[1..15]) - } else { - Some(§ion_name[1..]) - } - } else { - None - }; - let cmp_section_name = |section: &MachOSection<'data, 'file, Mach, R>| { - section - .name_bytes() - .map(|name| { - section_name == name - || system_name - .filter(|system_name| { - name.starts_with(b"__") && name[2..] == **system_name - }) - .is_some() - }) - .unwrap_or(false) - }; - - self.sections().find(cmp_section_name) - } - - fn section_by_index( - &'file self, - index: SectionIndex, - ) -> Result<MachOSection<'data, 'file, Mach, R>> { - let internal = *self.section_internal(index)?; - Ok(MachOSection { - file: self, - internal, - }) - } - - fn sections(&'file self) -> MachOSectionIterator<'data, 'file, Mach, R> { - MachOSectionIterator { - file: self, - iter: self.sections.iter(), - } - } - - fn comdats(&'file self) -> MachOComdatIterator<'data, 'file, Mach, R> { - MachOComdatIterator { file: self } - } - - fn symbol_by_index( - &'file self, - index: SymbolIndex, - ) -> Result<MachOSymbol<'data, 'file, Mach, R>> { - let nlist = self.symbols.symbol(index.0)?; - MachOSymbol::new(self, index, nlist).read_error("Unsupported Mach-O symbol index") - } - - fn symbols(&'file self) -> MachOSymbolIterator<'data, 'file, Mach, R> { - MachOSymbolIterator { - file: self, - index: 0, - } - } - - #[inline] - fn symbol_table(&'file self) -> Option<MachOSymbolTable<'data, 'file, Mach, R>> { - Some(MachOSymbolTable { file: self }) - } - - fn dynamic_symbols(&'file self) -> MachOSymbolIterator<'data, 'file, Mach, R> { - MachOSymbolIterator { - file: self, - index: self.symbols.len(), - } - } - - #[inline] - fn dynamic_symbol_table(&'file self) -> Option<MachOSymbolTable<'data, 'file, Mach, R>> { - None - } - - fn object_map(&'file self) -> ObjectMap<'data> { - self.symbols.object_map(self.endian) - } - - fn imports(&self) -> Result<Vec<Import<'data>>> { - let mut dysymtab = None; - let mut libraries = Vec::new(); - let twolevel = self.header.flags(self.endian) & macho::MH_TWOLEVEL != 0; - if twolevel { - libraries.push(&[][..]); - } - let mut commands = self - .header - .load_commands(self.endian, self.data, self.header_offset)?; - while let Some(command) = commands.next()? { - if let Some(command) = command.dysymtab()? { - dysymtab = Some(command); - } - if twolevel { - if let Some(dylib) = command.dylib()? { - libraries.push(command.string(self.endian, dylib.dylib.name)?); - } - } - } - - let mut imports = Vec::new(); - if let Some(dysymtab) = dysymtab { - let index = dysymtab.iundefsym.get(self.endian) as usize; - let number = dysymtab.nundefsym.get(self.endian) as usize; - for i in index..(index.wrapping_add(number)) { - let symbol = self.symbols.symbol(i)?; - let name = symbol.name(self.endian, self.symbols.strings())?; - let library = if twolevel { - libraries - .get(symbol.library_ordinal(self.endian) as usize) - .copied() - .read_error("Invalid Mach-O symbol library ordinal")? - } else { - &[] - }; - imports.push(Import { - name: ByteString(name), - library: ByteString(library), - }); - } - } - Ok(imports) - } - - fn exports(&self) -> Result<Vec<Export<'data>>> { - let mut dysymtab = None; - let mut commands = self - .header - .load_commands(self.endian, self.data, self.header_offset)?; - while let Some(command) = commands.next()? { - if let Some(command) = command.dysymtab()? { - dysymtab = Some(command); - break; - } - } - - let mut exports = Vec::new(); - if let Some(dysymtab) = dysymtab { - let index = dysymtab.iextdefsym.get(self.endian) as usize; - let number = dysymtab.nextdefsym.get(self.endian) as usize; - for i in index..(index.wrapping_add(number)) { - let symbol = self.symbols.symbol(i)?; - let name = symbol.name(self.endian, self.symbols.strings())?; - let address = symbol.n_value(self.endian).into(); - exports.push(Export { - name: ByteString(name), - address, - }); - } - } - Ok(exports) - } - - #[inline] - fn dynamic_relocations(&'file self) -> Option<NoDynamicRelocationIterator> { - None - } - - fn has_debug_symbols(&self) -> bool { - self.section_by_name(".debug_info").is_some() - } - - fn mach_uuid(&self) -> Result<Option<[u8; 16]>> { - self.header.uuid(self.endian, self.data, self.header_offset) - } - - fn relative_address_base(&self) -> u64 { - 0 - } - - fn entry(&self) -> u64 { - if let Ok(mut commands) = - self.header - .load_commands(self.endian, self.data, self.header_offset) - { - while let Ok(Some(command)) = commands.next() { - if let Ok(Some(command)) = command.entry_point() { - return command.entryoff.get(self.endian); - } - } - } - 0 - } - - fn flags(&self) -> FileFlags { - FileFlags::MachO { - flags: self.header.flags(self.endian), - } - } -} - -/// An iterator for the COMDAT section groups in a [`MachOFile64`]. -pub type MachOComdatIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOComdatIterator<'data, 'file, macho::MachHeader32<Endian>, R>; -/// An iterator for the COMDAT section groups in a [`MachOFile64`]. -pub type MachOComdatIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOComdatIterator<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// An iterator for the COMDAT section groups in a [`MachOFile`]. -/// -/// This is a stub that doesn't implement any functionality. -#[derive(Debug)] -pub struct MachOComdatIterator<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - #[allow(unused)] - file: &'file MachOFile<'data, Mach, R>, -} - -impl<'data, 'file, Mach, R> Iterator for MachOComdatIterator<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - type Item = MachOComdat<'data, 'file, Mach, R>; - - #[inline] - fn next(&mut self) -> Option<Self::Item> { - None - } -} - -/// A COMDAT section group in a [`MachOFile32`]. -pub type MachOComdat32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOComdat<'data, 'file, macho::MachHeader32<Endian>, R>; - -/// A COMDAT section group in a [`MachOFile64`]. -pub type MachOComdat64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOComdat<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// A COMDAT section group in a [`MachOFile`]. -/// -/// This is a stub that doesn't implement any functionality. -#[derive(Debug)] -pub struct MachOComdat<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - #[allow(unused)] - file: &'file MachOFile<'data, Mach, R>, -} - -impl<'data, 'file, Mach, R> read::private::Sealed for MachOComdat<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Mach, R> ObjectComdat<'data> for MachOComdat<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - type SectionIterator = MachOComdatSectionIterator<'data, 'file, Mach, R>; - - #[inline] - fn kind(&self) -> ComdatKind { - unreachable!(); - } - - #[inline] - fn symbol(&self) -> SymbolIndex { - unreachable!(); - } - - #[inline] - fn name_bytes(&self) -> Result<&[u8]> { - unreachable!(); - } - - #[inline] - fn name(&self) -> Result<&str> { - unreachable!(); - } - - #[inline] - fn sections(&self) -> Self::SectionIterator { - unreachable!(); - } -} - -/// An iterator for the sections in a COMDAT section group in a [`MachOFile32`]. -pub type MachOComdatSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOComdatSectionIterator<'data, 'file, macho::MachHeader32<Endian>, R>; -/// An iterator for the sections in a COMDAT section group in a [`MachOFile64`]. -pub type MachOComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOComdatSectionIterator<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// An iterator for the sections in a COMDAT section group in a [`MachOFile`]. -/// -/// This is a stub that doesn't implement any functionality. -#[derive(Debug)] -pub struct MachOComdatSectionIterator<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - #[allow(unused)] - file: &'file MachOFile<'data, Mach, R>, -} - -impl<'data, 'file, Mach, R> Iterator for MachOComdatSectionIterator<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - type Item = SectionIndex; - - fn next(&mut self) -> Option<Self::Item> { - None - } -} - -/// A trait for generic access to [`macho::MachHeader32`] and [`macho::MachHeader64`]. -#[allow(missing_docs)] -pub trait MachHeader: Debug + Pod { - type Word: Into<u64>; - type Endian: endian::Endian; - type Segment: Segment<Endian = Self::Endian, Section = Self::Section>; - type Section: Section<Endian = Self::Endian>; - type Nlist: Nlist<Endian = Self::Endian>; - - /// Return true if this type is a 64-bit header. - /// - /// This is a property of the type, not a value in the header data. - fn is_type_64(&self) -> bool; - - /// Return true if the `magic` field signifies big-endian. - fn is_big_endian(&self) -> bool; - - /// Return true if the `magic` field signifies little-endian. - fn is_little_endian(&self) -> bool; - - fn magic(&self) -> u32; - fn cputype(&self, endian: Self::Endian) -> u32; - fn cpusubtype(&self, endian: Self::Endian) -> u32; - fn filetype(&self, endian: Self::Endian) -> u32; - fn ncmds(&self, endian: Self::Endian) -> u32; - fn sizeofcmds(&self, endian: Self::Endian) -> u32; - fn flags(&self, endian: Self::Endian) -> u32; - - // Provided methods. - - /// Read the file header. - /// - /// Also checks that the magic field in the file header is a supported format. - fn parse<'data, R: ReadRef<'data>>(data: R, offset: u64) -> read::Result<&'data Self> { - let header = data - .read_at::<Self>(offset) - .read_error("Invalid Mach-O header size or alignment")?; - if !header.is_supported() { - return Err(Error("Unsupported Mach-O header")); - } - Ok(header) - } - - fn is_supported(&self) -> bool { - self.is_little_endian() || self.is_big_endian() - } - - fn endian(&self) -> Result<Self::Endian> { - Self::Endian::from_big_endian(self.is_big_endian()).read_error("Unsupported Mach-O endian") - } - - fn load_commands<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - header_offset: u64, - ) -> Result<LoadCommandIterator<'data, Self::Endian>> { - let data = data - .read_bytes_at( - header_offset + mem::size_of::<Self>() as u64, - self.sizeofcmds(endian).into(), - ) - .read_error("Invalid Mach-O load command table size")?; - Ok(LoadCommandIterator::new(endian, data, self.ncmds(endian))) - } - - /// Return the UUID from the `LC_UUID` load command, if one is present. - fn uuid<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - header_offset: u64, - ) -> Result<Option<[u8; 16]>> { - let mut commands = self.load_commands(endian, data, header_offset)?; - while let Some(command) = commands.next()? { - if let Ok(Some(uuid)) = command.uuid() { - return Ok(Some(uuid.uuid)); - } - } - Ok(None) - } -} - -impl<Endian: endian::Endian> MachHeader for macho::MachHeader32<Endian> { - type Word = u32; - type Endian = Endian; - type Segment = macho::SegmentCommand32<Endian>; - type Section = macho::Section32<Endian>; - type Nlist = macho::Nlist32<Endian>; - - fn is_type_64(&self) -> bool { - false - } - - fn is_big_endian(&self) -> bool { - self.magic() == macho::MH_MAGIC - } - - fn is_little_endian(&self) -> bool { - self.magic() == macho::MH_CIGAM - } - - fn magic(&self) -> u32 { - self.magic.get(BigEndian) - } - - fn cputype(&self, endian: Self::Endian) -> u32 { - self.cputype.get(endian) - } - - fn cpusubtype(&self, endian: Self::Endian) -> u32 { - self.cpusubtype.get(endian) - } - - fn filetype(&self, endian: Self::Endian) -> u32 { - self.filetype.get(endian) - } - - fn ncmds(&self, endian: Self::Endian) -> u32 { - self.ncmds.get(endian) - } - - fn sizeofcmds(&self, endian: Self::Endian) -> u32 { - self.sizeofcmds.get(endian) - } - - fn flags(&self, endian: Self::Endian) -> u32 { - self.flags.get(endian) - } -} - -impl<Endian: endian::Endian> MachHeader for macho::MachHeader64<Endian> { - type Word = u64; - type Endian = Endian; - type Segment = macho::SegmentCommand64<Endian>; - type Section = macho::Section64<Endian>; - type Nlist = macho::Nlist64<Endian>; - - fn is_type_64(&self) -> bool { - true - } - - fn is_big_endian(&self) -> bool { - self.magic() == macho::MH_MAGIC_64 - } - - fn is_little_endian(&self) -> bool { - self.magic() == macho::MH_CIGAM_64 - } - - fn magic(&self) -> u32 { - self.magic.get(BigEndian) - } - - fn cputype(&self, endian: Self::Endian) -> u32 { - self.cputype.get(endian) - } - - fn cpusubtype(&self, endian: Self::Endian) -> u32 { - self.cpusubtype.get(endian) - } - - fn filetype(&self, endian: Self::Endian) -> u32 { - self.filetype.get(endian) - } - - fn ncmds(&self, endian: Self::Endian) -> u32 { - self.ncmds.get(endian) - } - - fn sizeofcmds(&self, endian: Self::Endian) -> u32 { - self.sizeofcmds.get(endian) - } - - fn flags(&self, endian: Self::Endian) -> u32 { - self.flags.get(endian) - } -} diff --git a/vendor/object/src/read/macho/load_command.rs b/vendor/object/src/read/macho/load_command.rs deleted file mode 100644 index 7225fbd..0000000 --- a/vendor/object/src/read/macho/load_command.rs +++ /dev/null @@ -1,382 +0,0 @@ -use core::marker::PhantomData; -use core::mem; - -use crate::endian::Endian; -use crate::macho; -use crate::pod::Pod; -use crate::read::macho::{MachHeader, SymbolTable}; -use crate::read::{Bytes, Error, ReadError, ReadRef, Result, StringTable}; - -/// An iterator for the load commands from a [`MachHeader`]. -#[derive(Debug, Default, Clone, Copy)] -pub struct LoadCommandIterator<'data, E: Endian> { - endian: E, - data: Bytes<'data>, - ncmds: u32, -} - -impl<'data, E: Endian> LoadCommandIterator<'data, E> { - pub(super) fn new(endian: E, data: &'data [u8], ncmds: u32) -> Self { - LoadCommandIterator { - endian, - data: Bytes(data), - ncmds, - } - } - - /// Return the next load command. - pub fn next(&mut self) -> Result<Option<LoadCommandData<'data, E>>> { - if self.ncmds == 0 { - return Ok(None); - } - let header = self - .data - .read_at::<macho::LoadCommand<E>>(0) - .read_error("Invalid Mach-O load command header")?; - let cmd = header.cmd.get(self.endian); - let cmdsize = header.cmdsize.get(self.endian) as usize; - if cmdsize < mem::size_of::<macho::LoadCommand<E>>() { - return Err(Error("Invalid Mach-O load command size")); - } - let data = self - .data - .read_bytes(cmdsize) - .read_error("Invalid Mach-O load command size")?; - self.ncmds -= 1; - Ok(Some(LoadCommandData { - cmd, - data, - marker: Default::default(), - })) - } -} - -/// The data for a [`macho::LoadCommand`]. -#[derive(Debug, Clone, Copy)] -pub struct LoadCommandData<'data, E: Endian> { - cmd: u32, - // Includes the header. - data: Bytes<'data>, - marker: PhantomData<E>, -} - -impl<'data, E: Endian> LoadCommandData<'data, E> { - /// Return the `cmd` field of the [`macho::LoadCommand`]. - /// - /// This is one of the `LC_` constants. - pub fn cmd(&self) -> u32 { - self.cmd - } - - /// Return the `cmdsize` field of the [`macho::LoadCommand`]. - pub fn cmdsize(&self) -> u32 { - self.data.len() as u32 - } - - /// Parse the data as the given type. - #[inline] - pub fn data<T: Pod>(&self) -> Result<&'data T> { - self.data - .read_at(0) - .read_error("Invalid Mach-O command size") - } - - /// Raw bytes of this [`macho::LoadCommand`] structure. - pub fn raw_data(&self) -> &'data [u8] { - self.data.0 - } - - /// Parse a load command string value. - /// - /// Strings used by load commands are specified by offsets that are - /// relative to the load command header. - pub fn string(&self, endian: E, s: macho::LcStr<E>) -> Result<&'data [u8]> { - self.data - .read_string_at(s.offset.get(endian) as usize) - .read_error("Invalid load command string offset") - } - - /// Parse the command data according to the `cmd` field. - pub fn variant(&self) -> Result<LoadCommandVariant<'data, E>> { - Ok(match self.cmd { - macho::LC_SEGMENT => { - let mut data = self.data; - let segment = data.read().read_error("Invalid Mach-O command size")?; - LoadCommandVariant::Segment32(segment, data.0) - } - macho::LC_SYMTAB => LoadCommandVariant::Symtab(self.data()?), - macho::LC_THREAD | macho::LC_UNIXTHREAD => { - let mut data = self.data; - let thread = data.read().read_error("Invalid Mach-O command size")?; - LoadCommandVariant::Thread(thread, data.0) - } - macho::LC_DYSYMTAB => LoadCommandVariant::Dysymtab(self.data()?), - macho::LC_LOAD_DYLIB - | macho::LC_LOAD_WEAK_DYLIB - | macho::LC_REEXPORT_DYLIB - | macho::LC_LAZY_LOAD_DYLIB - | macho::LC_LOAD_UPWARD_DYLIB => LoadCommandVariant::Dylib(self.data()?), - macho::LC_ID_DYLIB => LoadCommandVariant::IdDylib(self.data()?), - macho::LC_LOAD_DYLINKER => LoadCommandVariant::LoadDylinker(self.data()?), - macho::LC_ID_DYLINKER => LoadCommandVariant::IdDylinker(self.data()?), - macho::LC_PREBOUND_DYLIB => LoadCommandVariant::PreboundDylib(self.data()?), - macho::LC_ROUTINES => LoadCommandVariant::Routines32(self.data()?), - macho::LC_SUB_FRAMEWORK => LoadCommandVariant::SubFramework(self.data()?), - macho::LC_SUB_UMBRELLA => LoadCommandVariant::SubUmbrella(self.data()?), - macho::LC_SUB_CLIENT => LoadCommandVariant::SubClient(self.data()?), - macho::LC_SUB_LIBRARY => LoadCommandVariant::SubLibrary(self.data()?), - macho::LC_TWOLEVEL_HINTS => LoadCommandVariant::TwolevelHints(self.data()?), - macho::LC_PREBIND_CKSUM => LoadCommandVariant::PrebindCksum(self.data()?), - macho::LC_SEGMENT_64 => { - let mut data = self.data; - let segment = data.read().read_error("Invalid Mach-O command size")?; - LoadCommandVariant::Segment64(segment, data.0) - } - macho::LC_ROUTINES_64 => LoadCommandVariant::Routines64(self.data()?), - macho::LC_UUID => LoadCommandVariant::Uuid(self.data()?), - macho::LC_RPATH => LoadCommandVariant::Rpath(self.data()?), - macho::LC_CODE_SIGNATURE - | macho::LC_SEGMENT_SPLIT_INFO - | macho::LC_FUNCTION_STARTS - | macho::LC_DATA_IN_CODE - | macho::LC_DYLIB_CODE_SIGN_DRS - | macho::LC_LINKER_OPTIMIZATION_HINT - | macho::LC_DYLD_EXPORTS_TRIE - | macho::LC_DYLD_CHAINED_FIXUPS => LoadCommandVariant::LinkeditData(self.data()?), - macho::LC_ENCRYPTION_INFO => LoadCommandVariant::EncryptionInfo32(self.data()?), - macho::LC_DYLD_INFO | macho::LC_DYLD_INFO_ONLY => { - LoadCommandVariant::DyldInfo(self.data()?) - } - macho::LC_VERSION_MIN_MACOSX - | macho::LC_VERSION_MIN_IPHONEOS - | macho::LC_VERSION_MIN_TVOS - | macho::LC_VERSION_MIN_WATCHOS => LoadCommandVariant::VersionMin(self.data()?), - macho::LC_DYLD_ENVIRONMENT => LoadCommandVariant::DyldEnvironment(self.data()?), - macho::LC_MAIN => LoadCommandVariant::EntryPoint(self.data()?), - macho::LC_SOURCE_VERSION => LoadCommandVariant::SourceVersion(self.data()?), - macho::LC_ENCRYPTION_INFO_64 => LoadCommandVariant::EncryptionInfo64(self.data()?), - macho::LC_LINKER_OPTION => LoadCommandVariant::LinkerOption(self.data()?), - macho::LC_NOTE => LoadCommandVariant::Note(self.data()?), - macho::LC_BUILD_VERSION => LoadCommandVariant::BuildVersion(self.data()?), - macho::LC_FILESET_ENTRY => LoadCommandVariant::FilesetEntry(self.data()?), - _ => LoadCommandVariant::Other, - }) - } - - /// Try to parse this command as a [`macho::SegmentCommand32`]. - /// - /// Returns the segment command and the data containing the sections. - pub fn segment_32(self) -> Result<Option<(&'data macho::SegmentCommand32<E>, &'data [u8])>> { - if self.cmd == macho::LC_SEGMENT { - let mut data = self.data; - let segment = data.read().read_error("Invalid Mach-O command size")?; - Ok(Some((segment, data.0))) - } else { - Ok(None) - } - } - - /// Try to parse this command as a [`macho::SymtabCommand`]. - /// - /// Returns the segment command and the data containing the sections. - pub fn symtab(self) -> Result<Option<&'data macho::SymtabCommand<E>>> { - if self.cmd == macho::LC_SYMTAB { - Some(self.data()).transpose() - } else { - Ok(None) - } - } - - /// Try to parse this command as a [`macho::DysymtabCommand`]. - pub fn dysymtab(self) -> Result<Option<&'data macho::DysymtabCommand<E>>> { - if self.cmd == macho::LC_DYSYMTAB { - Some(self.data()).transpose() - } else { - Ok(None) - } - } - - /// Try to parse this command as a [`macho::DylibCommand`]. - pub fn dylib(self) -> Result<Option<&'data macho::DylibCommand<E>>> { - if self.cmd == macho::LC_LOAD_DYLIB - || self.cmd == macho::LC_LOAD_WEAK_DYLIB - || self.cmd == macho::LC_REEXPORT_DYLIB - || self.cmd == macho::LC_LAZY_LOAD_DYLIB - || self.cmd == macho::LC_LOAD_UPWARD_DYLIB - { - Some(self.data()).transpose() - } else { - Ok(None) - } - } - - /// Try to parse this command as a [`macho::UuidCommand`]. - pub fn uuid(self) -> Result<Option<&'data macho::UuidCommand<E>>> { - if self.cmd == macho::LC_UUID { - Some(self.data()).transpose() - } else { - Ok(None) - } - } - - /// Try to parse this command as a [`macho::SegmentCommand64`]. - pub fn segment_64(self) -> Result<Option<(&'data macho::SegmentCommand64<E>, &'data [u8])>> { - if self.cmd == macho::LC_SEGMENT_64 { - let mut data = self.data; - let command = data.read().read_error("Invalid Mach-O command size")?; - Ok(Some((command, data.0))) - } else { - Ok(None) - } - } - - /// Try to parse this command as a [`macho::DyldInfoCommand`]. - pub fn dyld_info(self) -> Result<Option<&'data macho::DyldInfoCommand<E>>> { - if self.cmd == macho::LC_DYLD_INFO || self.cmd == macho::LC_DYLD_INFO_ONLY { - Some(self.data()).transpose() - } else { - Ok(None) - } - } - - /// Try to parse this command as an [`macho::EntryPointCommand`]. - pub fn entry_point(self) -> Result<Option<&'data macho::EntryPointCommand<E>>> { - if self.cmd == macho::LC_MAIN { - Some(self.data()).transpose() - } else { - Ok(None) - } - } - - /// Try to parse this command as a [`macho::BuildVersionCommand`]. - pub fn build_version(self) -> Result<Option<&'data macho::BuildVersionCommand<E>>> { - if self.cmd == macho::LC_BUILD_VERSION { - Some(self.data()).transpose() - } else { - Ok(None) - } - } -} - -/// A [`macho::LoadCommand`] that has been interpreted according to its `cmd` field. -#[derive(Debug, Clone, Copy)] -#[non_exhaustive] -pub enum LoadCommandVariant<'data, E: Endian> { - /// `LC_SEGMENT` - Segment32(&'data macho::SegmentCommand32<E>, &'data [u8]), - /// `LC_SYMTAB` - Symtab(&'data macho::SymtabCommand<E>), - // obsolete: `LC_SYMSEG` - //Symseg(&'data macho::SymsegCommand<E>), - /// `LC_THREAD` or `LC_UNIXTHREAD` - Thread(&'data macho::ThreadCommand<E>, &'data [u8]), - // obsolete: `LC_IDFVMLIB` or `LC_LOADFVMLIB` - //Fvmlib(&'data macho::FvmlibCommand<E>), - // obsolete: `LC_IDENT` - //Ident(&'data macho::IdentCommand<E>), - // internal: `LC_FVMFILE` - //Fvmfile(&'data macho::FvmfileCommand<E>), - // internal: `LC_PREPAGE` - /// `LC_DYSYMTAB` - Dysymtab(&'data macho::DysymtabCommand<E>), - /// `LC_LOAD_DYLIB`, `LC_LOAD_WEAK_DYLIB`, `LC_REEXPORT_DYLIB`, - /// `LC_LAZY_LOAD_DYLIB`, or `LC_LOAD_UPWARD_DYLIB` - Dylib(&'data macho::DylibCommand<E>), - /// `LC_ID_DYLIB` - IdDylib(&'data macho::DylibCommand<E>), - /// `LC_LOAD_DYLINKER` - LoadDylinker(&'data macho::DylinkerCommand<E>), - /// `LC_ID_DYLINKER` - IdDylinker(&'data macho::DylinkerCommand<E>), - /// `LC_PREBOUND_DYLIB` - PreboundDylib(&'data macho::PreboundDylibCommand<E>), - /// `LC_ROUTINES` - Routines32(&'data macho::RoutinesCommand32<E>), - /// `LC_SUB_FRAMEWORK` - SubFramework(&'data macho::SubFrameworkCommand<E>), - /// `LC_SUB_UMBRELLA` - SubUmbrella(&'data macho::SubUmbrellaCommand<E>), - /// `LC_SUB_CLIENT` - SubClient(&'data macho::SubClientCommand<E>), - /// `LC_SUB_LIBRARY` - SubLibrary(&'data macho::SubLibraryCommand<E>), - /// `LC_TWOLEVEL_HINTS` - TwolevelHints(&'data macho::TwolevelHintsCommand<E>), - /// `LC_PREBIND_CKSUM` - PrebindCksum(&'data macho::PrebindCksumCommand<E>), - /// `LC_SEGMENT_64` - Segment64(&'data macho::SegmentCommand64<E>, &'data [u8]), - /// `LC_ROUTINES_64` - Routines64(&'data macho::RoutinesCommand64<E>), - /// `LC_UUID` - Uuid(&'data macho::UuidCommand<E>), - /// `LC_RPATH` - Rpath(&'data macho::RpathCommand<E>), - /// `LC_CODE_SIGNATURE`, `LC_SEGMENT_SPLIT_INFO`, `LC_FUNCTION_STARTS`, - /// `LC_DATA_IN_CODE`, `LC_DYLIB_CODE_SIGN_DRS`, `LC_LINKER_OPTIMIZATION_HINT`, - /// `LC_DYLD_EXPORTS_TRIE`, or `LC_DYLD_CHAINED_FIXUPS`. - LinkeditData(&'data macho::LinkeditDataCommand<E>), - /// `LC_ENCRYPTION_INFO` - EncryptionInfo32(&'data macho::EncryptionInfoCommand32<E>), - /// `LC_DYLD_INFO` or `LC_DYLD_INFO_ONLY` - DyldInfo(&'data macho::DyldInfoCommand<E>), - /// `LC_VERSION_MIN_MACOSX`, `LC_VERSION_MIN_IPHONEOS`, `LC_VERSION_MIN_WATCHOS`, - /// or `LC_VERSION_MIN_TVOS` - VersionMin(&'data macho::VersionMinCommand<E>), - /// `LC_DYLD_ENVIRONMENT` - DyldEnvironment(&'data macho::DylinkerCommand<E>), - /// `LC_MAIN` - EntryPoint(&'data macho::EntryPointCommand<E>), - /// `LC_SOURCE_VERSION` - SourceVersion(&'data macho::SourceVersionCommand<E>), - /// `LC_ENCRYPTION_INFO_64` - EncryptionInfo64(&'data macho::EncryptionInfoCommand64<E>), - /// `LC_LINKER_OPTION` - LinkerOption(&'data macho::LinkerOptionCommand<E>), - /// `LC_NOTE` - Note(&'data macho::NoteCommand<E>), - /// `LC_BUILD_VERSION` - BuildVersion(&'data macho::BuildVersionCommand<E>), - /// `LC_FILESET_ENTRY` - FilesetEntry(&'data macho::FilesetEntryCommand<E>), - /// An unrecognized or obsolete load command. - Other, -} - -impl<E: Endian> macho::SymtabCommand<E> { - /// Return the symbol table that this command references. - pub fn symbols<'data, Mach: MachHeader<Endian = E>, R: ReadRef<'data>>( - &self, - endian: E, - data: R, - ) -> Result<SymbolTable<'data, Mach, R>> { - let symbols = data - .read_slice_at( - self.symoff.get(endian).into(), - self.nsyms.get(endian) as usize, - ) - .read_error("Invalid Mach-O symbol table offset or size")?; - let str_start: u64 = self.stroff.get(endian).into(); - let str_end = str_start - .checked_add(self.strsize.get(endian).into()) - .read_error("Invalid Mach-O string table length")?; - let strings = StringTable::new(data, str_start, str_end); - Ok(SymbolTable::new(symbols, strings)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::LittleEndian; - - #[test] - fn cmd_size_invalid() { - let mut commands = LoadCommandIterator::new(LittleEndian, &[0; 8], 10); - assert!(commands.next().is_err()); - let mut commands = LoadCommandIterator::new(LittleEndian, &[0, 0, 0, 0, 7, 0, 0, 0, 0], 10); - assert!(commands.next().is_err()); - let mut commands = LoadCommandIterator::new(LittleEndian, &[0, 0, 0, 0, 8, 0, 0, 0, 0], 10); - assert!(commands.next().is_ok()); - } -} diff --git a/vendor/object/src/read/macho/mod.rs b/vendor/object/src/read/macho/mod.rs deleted file mode 100644 index ab51ff3..0000000 --- a/vendor/object/src/read/macho/mod.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! Support for reading Mach-O files. -//! -//! Traits are used to abstract over the difference between 32-bit and 64-bit Mach-O -//! files. The primary trait for this is [`MachHeader`]. -//! -//! ## High level API -//! -//! [`MachOFile`] implements the [`Object`](crate::read::Object) trait for Mach-O files. -//! [`MachOFile`] is parameterised by [`MachHeader`] to allow reading both 32-bit and -//! 64-bit Mach-O files. There are type aliases for these parameters ([`MachOFile32`] and -//! [`MachOFile64`]). -//! -//! ## Low level API -//! -//! The [`MachHeader`] trait can be directly used to parse both [`macho::MachHeader32`] -//! and [`macho::MachHeader64`]. Additionally, [`FatHeader`] and the [`FatArch`] trait -//! can be used to iterate images in multi-architecture binaries, and [`DyldCache`] can -//! be used to locate images in a dyld shared cache. -//! -//! ### Example for low level API -//! ```no_run -//! use object::macho; -//! use object::read::macho::{MachHeader, Nlist}; -//! use std::error::Error; -//! use std::fs; -//! -//! /// Reads a file and displays the name of each symbol. -//! fn main() -> Result<(), Box<dyn Error>> { -//! # #[cfg(feature = "std")] { -//! let data = fs::read("path/to/binary")?; -//! let header = macho::MachHeader64::<object::Endianness>::parse(&*data, 0)?; -//! let endian = header.endian()?; -//! let mut commands = header.load_commands(endian, &*data, 0)?; -//! while let Some(command) = commands.next()? { -//! if let Some(symtab_command) = command.symtab()? { -//! let symbols = symtab_command.symbols::<macho::MachHeader64<_>, _>(endian, &*data)?; -//! for symbol in symbols.iter() { -//! let name = symbol.name(endian, symbols.strings())?; -//! println!("{}", String::from_utf8_lossy(name)); -//! } -//! } -//! } -//! # } -//! Ok(()) -//! } -//! ``` -#[cfg(doc)] -use crate::macho; - -mod dyld_cache; -pub use dyld_cache::*; - -mod fat; -pub use fat::*; - -mod file; -pub use file::*; - -mod load_command; -pub use load_command::*; - -mod segment; -pub use segment::*; - -mod section; -pub use section::*; - -mod symbol; -pub use symbol::*; - -mod relocation; -pub use relocation::*; diff --git a/vendor/object/src/read/macho/relocation.rs b/vendor/object/src/read/macho/relocation.rs deleted file mode 100644 index 709f1a4..0000000 --- a/vendor/object/src/read/macho/relocation.rs +++ /dev/null @@ -1,158 +0,0 @@ -use core::{fmt, slice}; - -use crate::endian::Endianness; -use crate::macho; -use crate::read::{ - ReadRef, Relocation, RelocationEncoding, RelocationKind, RelocationTarget, SectionIndex, - SymbolIndex, -}; - -use super::{MachHeader, MachOFile}; - -/// An iterator for the relocations in a [`MachOSection32`](super::MachOSection32). -pub type MachORelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachORelocationIterator<'data, 'file, macho::MachHeader32<Endian>, R>; -/// An iterator for the relocations in a [`MachOSection64`](super::MachOSection64). -pub type MachORelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachORelocationIterator<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// An iterator for the relocations in a [`MachOSection`](super::MachOSection). -pub struct MachORelocationIterator<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file MachOFile<'data, Mach, R>, - pub(super) relocations: slice::Iter<'data, macho::Relocation<Mach::Endian>>, -} - -impl<'data, 'file, Mach, R> Iterator for MachORelocationIterator<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - type Item = (u64, Relocation); - - fn next(&mut self) -> Option<Self::Item> { - let mut paired_addend = 0; - loop { - let reloc = self.relocations.next()?; - let endian = self.file.endian; - let cputype = self.file.header.cputype(endian); - if reloc.r_scattered(endian, cputype) { - // FIXME: handle scattered relocations - // We need to add `RelocationTarget::Address` for this. - continue; - } - let reloc = reloc.info(self.file.endian); - let mut encoding = RelocationEncoding::Generic; - let kind = match cputype { - macho::CPU_TYPE_ARM => match (reloc.r_type, reloc.r_pcrel) { - (macho::ARM_RELOC_VANILLA, false) => RelocationKind::Absolute, - _ => RelocationKind::MachO { - value: reloc.r_type, - relative: reloc.r_pcrel, - }, - }, - macho::CPU_TYPE_ARM64 | macho::CPU_TYPE_ARM64_32 => { - match (reloc.r_type, reloc.r_pcrel) { - (macho::ARM64_RELOC_UNSIGNED, false) => RelocationKind::Absolute, - (macho::ARM64_RELOC_ADDEND, _) => { - paired_addend = i64::from(reloc.r_symbolnum) - .wrapping_shl(64 - 24) - .wrapping_shr(64 - 24); - continue; - } - _ => RelocationKind::MachO { - value: reloc.r_type, - relative: reloc.r_pcrel, - }, - } - } - macho::CPU_TYPE_X86 => match (reloc.r_type, reloc.r_pcrel) { - (macho::GENERIC_RELOC_VANILLA, false) => RelocationKind::Absolute, - _ => RelocationKind::MachO { - value: reloc.r_type, - relative: reloc.r_pcrel, - }, - }, - macho::CPU_TYPE_X86_64 => match (reloc.r_type, reloc.r_pcrel) { - (macho::X86_64_RELOC_UNSIGNED, false) => RelocationKind::Absolute, - (macho::X86_64_RELOC_SIGNED, true) => { - encoding = RelocationEncoding::X86RipRelative; - RelocationKind::Relative - } - (macho::X86_64_RELOC_BRANCH, true) => { - encoding = RelocationEncoding::X86Branch; - RelocationKind::Relative - } - (macho::X86_64_RELOC_GOT, true) => RelocationKind::GotRelative, - (macho::X86_64_RELOC_GOT_LOAD, true) => { - encoding = RelocationEncoding::X86RipRelativeMovq; - RelocationKind::GotRelative - } - _ => RelocationKind::MachO { - value: reloc.r_type, - relative: reloc.r_pcrel, - }, - }, - _ => RelocationKind::MachO { - value: reloc.r_type, - relative: reloc.r_pcrel, - }, - }; - let size = 8 << reloc.r_length; - let target = if reloc.r_extern { - RelocationTarget::Symbol(SymbolIndex(reloc.r_symbolnum as usize)) - } else { - RelocationTarget::Section(SectionIndex(reloc.r_symbolnum as usize)) - }; - let implicit_addend = paired_addend == 0; - let mut addend = paired_addend; - if reloc.r_pcrel { - // For PC relative relocations on some architectures, the - // addend does not include the offset required due to the - // PC being different from the place of the relocation. - // This differs from other file formats, so adjust the - // addend here to account for this. - match cputype { - macho::CPU_TYPE_X86 => { - addend -= 1 << reloc.r_length; - } - macho::CPU_TYPE_X86_64 => { - addend -= 1 << reloc.r_length; - match reloc.r_type { - macho::X86_64_RELOC_SIGNED_1 => addend -= 1, - macho::X86_64_RELOC_SIGNED_2 => addend -= 2, - macho::X86_64_RELOC_SIGNED_4 => addend -= 4, - _ => {} - } - } - // TODO: maybe missing support for some architectures and relocations - _ => {} - } - } - return Some(( - reloc.r_address as u64, - Relocation { - kind, - encoding, - size, - target, - addend, - implicit_addend, - }, - )); - } - } -} - -impl<'data, 'file, Mach, R> fmt::Debug for MachORelocationIterator<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MachORelocationIterator").finish() - } -} diff --git a/vendor/object/src/read/macho/section.rs b/vendor/object/src/read/macho/section.rs deleted file mode 100644 index 7c79123..0000000 --- a/vendor/object/src/read/macho/section.rs +++ /dev/null @@ -1,389 +0,0 @@ -use core::fmt::Debug; -use core::{fmt, result, slice, str}; - -use crate::endian::{self, Endianness}; -use crate::macho; -use crate::pod::Pod; -use crate::read::{ - self, CompressedData, CompressedFileRange, ObjectSection, ReadError, ReadRef, Result, - SectionFlags, SectionIndex, SectionKind, -}; - -use super::{MachHeader, MachOFile, MachORelocationIterator}; - -/// An iterator for the sections in a [`MachOFile32`](super::MachOFile32). -pub type MachOSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSectionIterator<'data, 'file, macho::MachHeader32<Endian>, R>; -/// An iterator for the sections in a [`MachOFile64`](super::MachOFile64). -pub type MachOSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSectionIterator<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// An iterator for the sections in a [`MachOFile`]. -pub struct MachOSectionIterator<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file MachOFile<'data, Mach, R>, - pub(super) iter: slice::Iter<'file, MachOSectionInternal<'data, Mach>>, -} - -impl<'data, 'file, Mach, R> fmt::Debug for MachOSectionIterator<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // It's painful to do much better than this - f.debug_struct("MachOSectionIterator").finish() - } -} - -impl<'data, 'file, Mach, R> Iterator for MachOSectionIterator<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - type Item = MachOSection<'data, 'file, Mach, R>; - - fn next(&mut self) -> Option<Self::Item> { - self.iter.next().map(|&internal| MachOSection { - file: self.file, - internal, - }) - } -} - -/// A section in a [`MachOFile32`](super::MachOFile32). -pub type MachOSection32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSection<'data, 'file, macho::MachHeader32<Endian>, R>; -/// A section in a [`MachOFile64`](super::MachOFile64). -pub type MachOSection64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSection<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// A section in a [`MachOFile`]. -/// -/// Most functionality is provided by the [`ObjectSection`] trait implementation. -#[derive(Debug)] -pub struct MachOSection<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file MachOFile<'data, Mach, R>, - pub(super) internal: MachOSectionInternal<'data, Mach>, -} - -impl<'data, 'file, Mach, R> MachOSection<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - fn bytes(&self) -> Result<&'data [u8]> { - let segment_index = self.internal.segment_index; - let segment = self.file.segment_internal(segment_index)?; - self.internal - .section - .data(self.file.endian, segment.data) - .read_error("Invalid Mach-O section size or offset") - } -} - -impl<'data, 'file, Mach, R> read::private::Sealed for MachOSection<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Mach, R> ObjectSection<'data> for MachOSection<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - type RelocationIterator = MachORelocationIterator<'data, 'file, Mach, R>; - - #[inline] - fn index(&self) -> SectionIndex { - self.internal.index - } - - #[inline] - fn address(&self) -> u64 { - self.internal.section.addr(self.file.endian).into() - } - - #[inline] - fn size(&self) -> u64 { - self.internal.section.size(self.file.endian).into() - } - - #[inline] - fn align(&self) -> u64 { - let align = self.internal.section.align(self.file.endian); - if align < 64 { - 1 << align - } else { - 0 - } - } - - #[inline] - fn file_range(&self) -> Option<(u64, u64)> { - self.internal.section.file_range(self.file.endian) - } - - #[inline] - fn data(&self) -> Result<&'data [u8]> { - self.bytes() - } - - fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { - Ok(read::util::data_range( - self.bytes()?, - self.address(), - address, - size, - )) - } - - #[inline] - fn compressed_file_range(&self) -> Result<CompressedFileRange> { - Ok(CompressedFileRange::none(self.file_range())) - } - - #[inline] - fn compressed_data(&self) -> Result<CompressedData<'data>> { - self.data().map(CompressedData::none) - } - - #[inline] - fn name_bytes(&self) -> Result<&[u8]> { - Ok(self.internal.section.name()) - } - - #[inline] - fn name(&self) -> Result<&str> { - str::from_utf8(self.internal.section.name()) - .ok() - .read_error("Non UTF-8 Mach-O section name") - } - - #[inline] - fn segment_name_bytes(&self) -> Result<Option<&[u8]>> { - Ok(Some(self.internal.section.segment_name())) - } - - #[inline] - fn segment_name(&self) -> Result<Option<&str>> { - Ok(Some( - str::from_utf8(self.internal.section.segment_name()) - .ok() - .read_error("Non UTF-8 Mach-O segment name")?, - )) - } - - fn kind(&self) -> SectionKind { - self.internal.kind - } - - fn relocations(&self) -> MachORelocationIterator<'data, 'file, Mach, R> { - MachORelocationIterator { - file: self.file, - relocations: self - .internal - .section - .relocations(self.file.endian, self.file.data) - .unwrap_or(&[]) - .iter(), - } - } - - fn flags(&self) -> SectionFlags { - SectionFlags::MachO { - flags: self.internal.section.flags(self.file.endian), - } - } -} - -#[derive(Debug, Clone, Copy)] -pub(super) struct MachOSectionInternal<'data, Mach: MachHeader> { - pub index: SectionIndex, - pub segment_index: usize, - pub kind: SectionKind, - pub section: &'data Mach::Section, -} - -impl<'data, Mach: MachHeader> MachOSectionInternal<'data, Mach> { - pub(super) fn parse( - index: SectionIndex, - segment_index: usize, - section: &'data Mach::Section, - ) -> Self { - // TODO: we don't validate flags, should we? - let kind = match (section.segment_name(), section.name()) { - (b"__TEXT", b"__text") => SectionKind::Text, - (b"__TEXT", b"__const") => SectionKind::ReadOnlyData, - (b"__TEXT", b"__cstring") => SectionKind::ReadOnlyString, - (b"__TEXT", b"__literal4") => SectionKind::ReadOnlyData, - (b"__TEXT", b"__literal8") => SectionKind::ReadOnlyData, - (b"__TEXT", b"__literal16") => SectionKind::ReadOnlyData, - (b"__TEXT", b"__eh_frame") => SectionKind::ReadOnlyData, - (b"__TEXT", b"__gcc_except_tab") => SectionKind::ReadOnlyData, - (b"__DATA", b"__data") => SectionKind::Data, - (b"__DATA", b"__const") => SectionKind::ReadOnlyData, - (b"__DATA", b"__bss") => SectionKind::UninitializedData, - (b"__DATA", b"__common") => SectionKind::Common, - (b"__DATA", b"__thread_data") => SectionKind::Tls, - (b"__DATA", b"__thread_bss") => SectionKind::UninitializedTls, - (b"__DATA", b"__thread_vars") => SectionKind::TlsVariables, - (b"__DWARF", _) => SectionKind::Debug, - _ => SectionKind::Unknown, - }; - MachOSectionInternal { - index, - segment_index, - kind, - section, - } - } -} - -/// A trait for generic access to [`macho::Section32`] and [`macho::Section64`]. -#[allow(missing_docs)] -pub trait Section: Debug + Pod { - type Word: Into<u64>; - type Endian: endian::Endian; - - fn sectname(&self) -> &[u8; 16]; - fn segname(&self) -> &[u8; 16]; - fn addr(&self, endian: Self::Endian) -> Self::Word; - fn size(&self, endian: Self::Endian) -> Self::Word; - fn offset(&self, endian: Self::Endian) -> u32; - fn align(&self, endian: Self::Endian) -> u32; - fn reloff(&self, endian: Self::Endian) -> u32; - fn nreloc(&self, endian: Self::Endian) -> u32; - fn flags(&self, endian: Self::Endian) -> u32; - - /// Return the `sectname` bytes up until the null terminator. - fn name(&self) -> &[u8] { - let sectname = &self.sectname()[..]; - match memchr::memchr(b'\0', sectname) { - Some(end) => §name[..end], - None => sectname, - } - } - - /// Return the `segname` bytes up until the null terminator. - fn segment_name(&self) -> &[u8] { - let segname = &self.segname()[..]; - match memchr::memchr(b'\0', segname) { - Some(end) => &segname[..end], - None => segname, - } - } - - /// Return the offset and size of the section in the file. - /// - /// Returns `None` for sections that have no data in the file. - fn file_range(&self, endian: Self::Endian) -> Option<(u64, u64)> { - match self.flags(endian) & macho::SECTION_TYPE { - macho::S_ZEROFILL | macho::S_GB_ZEROFILL | macho::S_THREAD_LOCAL_ZEROFILL => None, - _ => Some((self.offset(endian).into(), self.size(endian).into())), - } - } - - /// Return the section data. - /// - /// Returns `Ok(&[])` if the section has no data. - /// Returns `Err` for invalid values. - fn data<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> result::Result<&'data [u8], ()> { - if let Some((offset, size)) = self.file_range(endian) { - data.read_bytes_at(offset, size) - } else { - Ok(&[]) - } - } - - /// Return the relocation array. - /// - /// Returns `Err` for invalid values. - fn relocations<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> Result<&'data [macho::Relocation<Self::Endian>]> { - data.read_slice_at(self.reloff(endian).into(), self.nreloc(endian) as usize) - .read_error("Invalid Mach-O relocations offset or number") - } -} - -impl<Endian: endian::Endian> Section for macho::Section32<Endian> { - type Word = u32; - type Endian = Endian; - - fn sectname(&self) -> &[u8; 16] { - &self.sectname - } - fn segname(&self) -> &[u8; 16] { - &self.segname - } - fn addr(&self, endian: Self::Endian) -> Self::Word { - self.addr.get(endian) - } - fn size(&self, endian: Self::Endian) -> Self::Word { - self.size.get(endian) - } - fn offset(&self, endian: Self::Endian) -> u32 { - self.offset.get(endian) - } - fn align(&self, endian: Self::Endian) -> u32 { - self.align.get(endian) - } - fn reloff(&self, endian: Self::Endian) -> u32 { - self.reloff.get(endian) - } - fn nreloc(&self, endian: Self::Endian) -> u32 { - self.nreloc.get(endian) - } - fn flags(&self, endian: Self::Endian) -> u32 { - self.flags.get(endian) - } -} - -impl<Endian: endian::Endian> Section for macho::Section64<Endian> { - type Word = u64; - type Endian = Endian; - - fn sectname(&self) -> &[u8; 16] { - &self.sectname - } - fn segname(&self) -> &[u8; 16] { - &self.segname - } - fn addr(&self, endian: Self::Endian) -> Self::Word { - self.addr.get(endian) - } - fn size(&self, endian: Self::Endian) -> Self::Word { - self.size.get(endian) - } - fn offset(&self, endian: Self::Endian) -> u32 { - self.offset.get(endian) - } - fn align(&self, endian: Self::Endian) -> u32 { - self.align.get(endian) - } - fn reloff(&self, endian: Self::Endian) -> u32 { - self.reloff.get(endian) - } - fn nreloc(&self, endian: Self::Endian) -> u32 { - self.nreloc.get(endian) - } - fn flags(&self, endian: Self::Endian) -> u32 { - self.flags.get(endian) - } -} diff --git a/vendor/object/src/read/macho/segment.rs b/vendor/object/src/read/macho/segment.rs deleted file mode 100644 index c889ad2..0000000 --- a/vendor/object/src/read/macho/segment.rs +++ /dev/null @@ -1,303 +0,0 @@ -use core::fmt::Debug; -use core::{result, slice, str}; - -use crate::endian::{self, Endianness}; -use crate::macho; -use crate::pod::Pod; -use crate::read::{self, ObjectSegment, ReadError, ReadRef, Result, SegmentFlags}; - -use super::{LoadCommandData, MachHeader, MachOFile, Section}; - -/// An iterator for the segments in a [`MachOFile32`](super::MachOFile32). -pub type MachOSegmentIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSegmentIterator<'data, 'file, macho::MachHeader32<Endian>, R>; -/// An iterator for the segments in a [`MachOFile64`](super::MachOFile64). -pub type MachOSegmentIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSegmentIterator<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// An iterator for the segments in a [`MachOFile`]. -#[derive(Debug)] -pub struct MachOSegmentIterator<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file MachOFile<'data, Mach, R>, - pub(super) iter: slice::Iter<'file, MachOSegmentInternal<'data, Mach, R>>, -} - -impl<'data, 'file, Mach, R> Iterator for MachOSegmentIterator<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - type Item = MachOSegment<'data, 'file, Mach, R>; - - fn next(&mut self) -> Option<Self::Item> { - self.iter.next().map(|internal| MachOSegment { - file: self.file, - internal, - }) - } -} - -/// A segment in a [`MachOFile32`](super::MachOFile32). -pub type MachOSegment32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSegment<'data, 'file, macho::MachHeader32<Endian>, R>; -/// A segment in a [`MachOFile64`](super::MachOFile64). -pub type MachOSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSegment<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// A segment in a [`MachOFile`]. -/// -/// Most functionality is provided by the [`ObjectSegment`] trait implementation. -#[derive(Debug)] -pub struct MachOSegment<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - file: &'file MachOFile<'data, Mach, R>, - internal: &'file MachOSegmentInternal<'data, Mach, R>, -} - -impl<'data, 'file, Mach, R> MachOSegment<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - fn bytes(&self) -> Result<&'data [u8]> { - self.internal - .segment - .data(self.file.endian, self.file.data) - .read_error("Invalid Mach-O segment size or offset") - } -} - -impl<'data, 'file, Mach, R> read::private::Sealed for MachOSegment<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Mach, R> ObjectSegment<'data> for MachOSegment<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - #[inline] - fn address(&self) -> u64 { - self.internal.segment.vmaddr(self.file.endian).into() - } - - #[inline] - fn size(&self) -> u64 { - self.internal.segment.vmsize(self.file.endian).into() - } - - #[inline] - fn align(&self) -> u64 { - // Page size. - 0x1000 - } - - #[inline] - fn file_range(&self) -> (u64, u64) { - self.internal.segment.file_range(self.file.endian) - } - - fn data(&self) -> Result<&'data [u8]> { - self.bytes() - } - - fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { - Ok(read::util::data_range( - self.bytes()?, - self.address(), - address, - size, - )) - } - - #[inline] - fn name_bytes(&self) -> Result<Option<&[u8]>> { - Ok(Some(self.internal.segment.name())) - } - - #[inline] - fn name(&self) -> Result<Option<&str>> { - Ok(Some( - str::from_utf8(self.internal.segment.name()) - .ok() - .read_error("Non UTF-8 Mach-O segment name")?, - )) - } - - #[inline] - fn flags(&self) -> SegmentFlags { - let flags = self.internal.segment.flags(self.file.endian); - let maxprot = self.internal.segment.maxprot(self.file.endian); - let initprot = self.internal.segment.initprot(self.file.endian); - SegmentFlags::MachO { - flags, - maxprot, - initprot, - } - } -} - -#[derive(Debug, Clone, Copy)] -pub(super) struct MachOSegmentInternal<'data, Mach: MachHeader, R: ReadRef<'data>> { - pub data: R, - pub segment: &'data Mach::Segment, -} - -/// A trait for generic access to [`macho::SegmentCommand32`] and [`macho::SegmentCommand64`]. -#[allow(missing_docs)] -pub trait Segment: Debug + Pod { - type Word: Into<u64>; - type Endian: endian::Endian; - type Section: Section<Endian = Self::Endian>; - - fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>>; - - fn cmd(&self, endian: Self::Endian) -> u32; - fn cmdsize(&self, endian: Self::Endian) -> u32; - fn segname(&self) -> &[u8; 16]; - fn vmaddr(&self, endian: Self::Endian) -> Self::Word; - fn vmsize(&self, endian: Self::Endian) -> Self::Word; - fn fileoff(&self, endian: Self::Endian) -> Self::Word; - fn filesize(&self, endian: Self::Endian) -> Self::Word; - fn maxprot(&self, endian: Self::Endian) -> u32; - fn initprot(&self, endian: Self::Endian) -> u32; - fn nsects(&self, endian: Self::Endian) -> u32; - fn flags(&self, endian: Self::Endian) -> u32; - - /// Return the `segname` bytes up until the null terminator. - fn name(&self) -> &[u8] { - let segname = &self.segname()[..]; - match memchr::memchr(b'\0', segname) { - Some(end) => &segname[..end], - None => segname, - } - } - - /// Return the offset and size of the segment in the file. - fn file_range(&self, endian: Self::Endian) -> (u64, u64) { - (self.fileoff(endian).into(), self.filesize(endian).into()) - } - - /// Get the segment data from the file data. - /// - /// Returns `Err` for invalid values. - fn data<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - data: R, - ) -> result::Result<&'data [u8], ()> { - let (offset, size) = self.file_range(endian); - data.read_bytes_at(offset, size) - } - - /// Get the array of sections from the data following the segment command. - /// - /// Returns `Err` for invalid values. - fn sections<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - section_data: R, - ) -> Result<&'data [Self::Section]> { - section_data - .read_slice_at(0, self.nsects(endian) as usize) - .read_error("Invalid Mach-O number of sections") - } -} - -impl<Endian: endian::Endian> Segment for macho::SegmentCommand32<Endian> { - type Word = u32; - type Endian = Endian; - type Section = macho::Section32<Self::Endian>; - - fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>> { - command.segment_32() - } - - fn cmd(&self, endian: Self::Endian) -> u32 { - self.cmd.get(endian) - } - fn cmdsize(&self, endian: Self::Endian) -> u32 { - self.cmdsize.get(endian) - } - fn segname(&self) -> &[u8; 16] { - &self.segname - } - fn vmaddr(&self, endian: Self::Endian) -> Self::Word { - self.vmaddr.get(endian) - } - fn vmsize(&self, endian: Self::Endian) -> Self::Word { - self.vmsize.get(endian) - } - fn fileoff(&self, endian: Self::Endian) -> Self::Word { - self.fileoff.get(endian) - } - fn filesize(&self, endian: Self::Endian) -> Self::Word { - self.filesize.get(endian) - } - fn maxprot(&self, endian: Self::Endian) -> u32 { - self.maxprot.get(endian) - } - fn initprot(&self, endian: Self::Endian) -> u32 { - self.initprot.get(endian) - } - fn nsects(&self, endian: Self::Endian) -> u32 { - self.nsects.get(endian) - } - fn flags(&self, endian: Self::Endian) -> u32 { - self.flags.get(endian) - } -} - -impl<Endian: endian::Endian> Segment for macho::SegmentCommand64<Endian> { - type Word = u64; - type Endian = Endian; - type Section = macho::Section64<Self::Endian>; - - fn from_command(command: LoadCommandData<'_, Self::Endian>) -> Result<Option<(&Self, &[u8])>> { - command.segment_64() - } - - fn cmd(&self, endian: Self::Endian) -> u32 { - self.cmd.get(endian) - } - fn cmdsize(&self, endian: Self::Endian) -> u32 { - self.cmdsize.get(endian) - } - fn segname(&self) -> &[u8; 16] { - &self.segname - } - fn vmaddr(&self, endian: Self::Endian) -> Self::Word { - self.vmaddr.get(endian) - } - fn vmsize(&self, endian: Self::Endian) -> Self::Word { - self.vmsize.get(endian) - } - fn fileoff(&self, endian: Self::Endian) -> Self::Word { - self.fileoff.get(endian) - } - fn filesize(&self, endian: Self::Endian) -> Self::Word { - self.filesize.get(endian) - } - fn maxprot(&self, endian: Self::Endian) -> u32 { - self.maxprot.get(endian) - } - fn initprot(&self, endian: Self::Endian) -> u32 { - self.initprot.get(endian) - } - fn nsects(&self, endian: Self::Endian) -> u32 { - self.nsects.get(endian) - } - fn flags(&self, endian: Self::Endian) -> u32 { - self.flags.get(endian) - } -} diff --git a/vendor/object/src/read/macho/symbol.rs b/vendor/object/src/read/macho/symbol.rs deleted file mode 100644 index 434361f..0000000 --- a/vendor/object/src/read/macho/symbol.rs +++ /dev/null @@ -1,492 +0,0 @@ -use alloc::vec::Vec; -use core::fmt::Debug; -use core::{fmt, slice, str}; - -use crate::endian::{self, Endianness}; -use crate::macho; -use crate::pod::Pod; -use crate::read::util::StringTable; -use crate::read::{ - self, ObjectMap, ObjectMapEntry, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result, - SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, - SymbolScope, SymbolSection, -}; - -use super::{MachHeader, MachOFile}; - -/// A table of symbol entries in a Mach-O file. -/// -/// Also includes the string table used for the symbol names. -/// -/// Returned by [`macho::SymtabCommand::symbols`]. -#[derive(Debug, Clone, Copy)] -pub struct SymbolTable<'data, Mach: MachHeader, R = &'data [u8]> -where - R: ReadRef<'data>, -{ - symbols: &'data [Mach::Nlist], - strings: StringTable<'data, R>, -} - -impl<'data, Mach: MachHeader, R: ReadRef<'data>> Default for SymbolTable<'data, Mach, R> { - fn default() -> Self { - SymbolTable { - symbols: &[], - strings: Default::default(), - } - } -} - -impl<'data, Mach: MachHeader, R: ReadRef<'data>> SymbolTable<'data, Mach, R> { - #[inline] - pub(super) fn new(symbols: &'data [Mach::Nlist], strings: StringTable<'data, R>) -> Self { - SymbolTable { symbols, strings } - } - - /// Return the string table used for the symbol names. - #[inline] - pub fn strings(&self) -> StringTable<'data, R> { - self.strings - } - - /// Iterate over the symbols. - #[inline] - pub fn iter(&self) -> slice::Iter<'data, Mach::Nlist> { - self.symbols.iter() - } - - /// Return true if the symbol table is empty. - #[inline] - pub fn is_empty(&self) -> bool { - self.symbols.is_empty() - } - - /// The number of symbols. - #[inline] - pub fn len(&self) -> usize { - self.symbols.len() - } - - /// Return the symbol at the given index. - pub fn symbol(&self, index: usize) -> Result<&'data Mach::Nlist> { - self.symbols - .get(index) - .read_error("Invalid Mach-O symbol index") - } - - /// Construct a map from addresses to a user-defined map entry. - pub fn map<Entry: SymbolMapEntry, F: Fn(&'data Mach::Nlist) -> Option<Entry>>( - &self, - f: F, - ) -> SymbolMap<Entry> { - let mut symbols = Vec::new(); - for nlist in self.symbols { - if !nlist.is_definition() { - continue; - } - if let Some(entry) = f(nlist) { - symbols.push(entry); - } - } - SymbolMap::new(symbols) - } - - /// Construct a map from addresses to symbol names and object file names. - pub fn object_map(&self, endian: Mach::Endian) -> ObjectMap<'data> { - let mut symbols = Vec::new(); - let mut objects = Vec::new(); - let mut object = None; - let mut current_function = None; - // Each module starts with one or two N_SO symbols (path, or directory + filename) - // and one N_OSO symbol. The module is terminated by an empty N_SO symbol. - for nlist in self.symbols { - let n_type = nlist.n_type(); - if n_type & macho::N_STAB == 0 { - continue; - } - // TODO: includes variables too (N_GSYM, N_STSYM). These may need to get their - // address from regular symbols though. - match n_type { - macho::N_SO => { - object = None; - } - macho::N_OSO => { - object = None; - if let Ok(name) = nlist.name(endian, self.strings) { - if !name.is_empty() { - object = Some(objects.len()); - objects.push(name); - } - } - } - macho::N_FUN => { - if let Ok(name) = nlist.name(endian, self.strings) { - if !name.is_empty() { - current_function = Some((name, nlist.n_value(endian).into())) - } else if let Some((name, address)) = current_function.take() { - if let Some(object) = object { - symbols.push(ObjectMapEntry { - address, - size: nlist.n_value(endian).into(), - name, - object, - }); - } - } - } - } - _ => {} - } - } - ObjectMap { - symbols: SymbolMap::new(symbols), - objects, - } - } -} - -/// A symbol table in a [`MachOFile32`](super::MachOFile32). -pub type MachOSymbolTable32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSymbolTable<'data, 'file, macho::MachHeader32<Endian>, R>; -/// A symbol table in a [`MachOFile64`](super::MachOFile64). -pub type MachOSymbolTable64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSymbolTable<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// A symbol table in a [`MachOFile`]. -#[derive(Debug, Clone, Copy)] -pub struct MachOSymbolTable<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file MachOFile<'data, Mach, R>, -} - -impl<'data, 'file, Mach, R> read::private::Sealed for MachOSymbolTable<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Mach, R> ObjectSymbolTable<'data> for MachOSymbolTable<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - type Symbol = MachOSymbol<'data, 'file, Mach, R>; - type SymbolIterator = MachOSymbolIterator<'data, 'file, Mach, R>; - - fn symbols(&self) -> Self::SymbolIterator { - MachOSymbolIterator { - file: self.file, - index: 0, - } - } - - fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol> { - let nlist = self.file.symbols.symbol(index.0)?; - MachOSymbol::new(self.file, index, nlist).read_error("Unsupported Mach-O symbol index") - } -} - -/// An iterator for the symbols in a [`MachOFile32`](super::MachOFile32). -pub type MachOSymbolIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSymbolIterator<'data, 'file, macho::MachHeader32<Endian>, R>; -/// An iterator for the symbols in a [`MachOFile64`](super::MachOFile64). -pub type MachOSymbolIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSymbolIterator<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// An iterator for the symbols in a [`MachOFile`]. -pub struct MachOSymbolIterator<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - pub(super) file: &'file MachOFile<'data, Mach, R>, - pub(super) index: usize, -} - -impl<'data, 'file, Mach, R> fmt::Debug for MachOSymbolIterator<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MachOSymbolIterator").finish() - } -} - -impl<'data, 'file, Mach, R> Iterator for MachOSymbolIterator<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - type Item = MachOSymbol<'data, 'file, Mach, R>; - - fn next(&mut self) -> Option<Self::Item> { - loop { - let index = self.index; - let nlist = self.file.symbols.symbols.get(index)?; - self.index += 1; - if let Some(symbol) = MachOSymbol::new(self.file, SymbolIndex(index), nlist) { - return Some(symbol); - } - } - } -} - -/// A symbol in a [`MachOFile32`](super::MachOFile32). -pub type MachOSymbol32<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSymbol<'data, 'file, macho::MachHeader32<Endian>, R>; -/// A symbol in a [`MachOFile64`](super::MachOFile64). -pub type MachOSymbol64<'data, 'file, Endian = Endianness, R = &'data [u8]> = - MachOSymbol<'data, 'file, macho::MachHeader64<Endian>, R>; - -/// A symbol in a [`MachOFile`]. -/// -/// Most functionality is provided by the [`ObjectSymbol`] trait implementation. -#[derive(Debug, Clone, Copy)] -pub struct MachOSymbol<'data, 'file, Mach, R = &'data [u8]> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - file: &'file MachOFile<'data, Mach, R>, - index: SymbolIndex, - nlist: &'data Mach::Nlist, -} - -impl<'data, 'file, Mach, R> MachOSymbol<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - pub(super) fn new( - file: &'file MachOFile<'data, Mach, R>, - index: SymbolIndex, - nlist: &'data Mach::Nlist, - ) -> Option<Self> { - if nlist.n_type() & macho::N_STAB != 0 { - return None; - } - Some(MachOSymbol { file, index, nlist }) - } -} - -impl<'data, 'file, Mach, R> read::private::Sealed for MachOSymbol<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Mach, R> ObjectSymbol<'data> for MachOSymbol<'data, 'file, Mach, R> -where - Mach: MachHeader, - R: ReadRef<'data>, -{ - #[inline] - fn index(&self) -> SymbolIndex { - self.index - } - - fn name_bytes(&self) -> Result<&'data [u8]> { - self.nlist.name(self.file.endian, self.file.symbols.strings) - } - - fn name(&self) -> Result<&'data str> { - let name = self.name_bytes()?; - str::from_utf8(name) - .ok() - .read_error("Non UTF-8 Mach-O symbol name") - } - - #[inline] - fn address(&self) -> u64 { - self.nlist.n_value(self.file.endian).into() - } - - #[inline] - fn size(&self) -> u64 { - 0 - } - - fn kind(&self) -> SymbolKind { - self.section() - .index() - .and_then(|index| self.file.section_internal(index).ok()) - .map(|section| match section.kind { - SectionKind::Text => SymbolKind::Text, - SectionKind::Data - | SectionKind::ReadOnlyData - | SectionKind::ReadOnlyString - | SectionKind::UninitializedData - | SectionKind::Common => SymbolKind::Data, - SectionKind::Tls | SectionKind::UninitializedTls | SectionKind::TlsVariables => { - SymbolKind::Tls - } - _ => SymbolKind::Unknown, - }) - .unwrap_or(SymbolKind::Unknown) - } - - fn section(&self) -> SymbolSection { - match self.nlist.n_type() & macho::N_TYPE { - macho::N_UNDF => SymbolSection::Undefined, - macho::N_ABS => SymbolSection::Absolute, - macho::N_SECT => { - let n_sect = self.nlist.n_sect(); - if n_sect != 0 { - SymbolSection::Section(SectionIndex(n_sect as usize)) - } else { - SymbolSection::Unknown - } - } - _ => SymbolSection::Unknown, - } - } - - #[inline] - fn is_undefined(&self) -> bool { - self.nlist.n_type() & macho::N_TYPE == macho::N_UNDF - } - - #[inline] - fn is_definition(&self) -> bool { - self.nlist.is_definition() - } - - #[inline] - fn is_common(&self) -> bool { - // Mach-O common symbols are based on section, not symbol - false - } - - #[inline] - fn is_weak(&self) -> bool { - self.nlist.n_desc(self.file.endian) & (macho::N_WEAK_REF | macho::N_WEAK_DEF) != 0 - } - - fn scope(&self) -> SymbolScope { - let n_type = self.nlist.n_type(); - if n_type & macho::N_TYPE == macho::N_UNDF { - SymbolScope::Unknown - } else if n_type & macho::N_EXT == 0 { - SymbolScope::Compilation - } else if n_type & macho::N_PEXT != 0 { - SymbolScope::Linkage - } else { - SymbolScope::Dynamic - } - } - - #[inline] - fn is_global(&self) -> bool { - self.scope() != SymbolScope::Compilation - } - - #[inline] - fn is_local(&self) -> bool { - self.scope() == SymbolScope::Compilation - } - - #[inline] - fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> { - let n_desc = self.nlist.n_desc(self.file.endian); - SymbolFlags::MachO { n_desc } - } -} - -/// A trait for generic access to [`macho::Nlist32`] and [`macho::Nlist64`]. -#[allow(missing_docs)] -pub trait Nlist: Debug + Pod { - type Word: Into<u64>; - type Endian: endian::Endian; - - fn n_strx(&self, endian: Self::Endian) -> u32; - fn n_type(&self) -> u8; - fn n_sect(&self) -> u8; - fn n_desc(&self, endian: Self::Endian) -> u16; - fn n_value(&self, endian: Self::Endian) -> Self::Word; - - fn name<'data, R: ReadRef<'data>>( - &self, - endian: Self::Endian, - strings: StringTable<'data, R>, - ) -> Result<&'data [u8]> { - strings - .get(self.n_strx(endian)) - .read_error("Invalid Mach-O symbol name offset") - } - - /// Return true if this is a STAB symbol. - /// - /// This determines the meaning of the `n_type` field. - fn is_stab(&self) -> bool { - self.n_type() & macho::N_STAB != 0 - } - - /// Return true if this is an undefined symbol. - fn is_undefined(&self) -> bool { - let n_type = self.n_type(); - n_type & macho::N_STAB == 0 && n_type & macho::N_TYPE == macho::N_UNDF - } - - /// Return true if the symbol is a definition of a function or data object. - fn is_definition(&self) -> bool { - let n_type = self.n_type(); - n_type & macho::N_STAB == 0 && n_type & macho::N_TYPE == macho::N_SECT - } - - /// Return the library ordinal. - /// - /// This is either a 1-based index into the dylib load commands, - /// or a special ordinal. - #[inline] - fn library_ordinal(&self, endian: Self::Endian) -> u8 { - (self.n_desc(endian) >> 8) as u8 - } -} - -impl<Endian: endian::Endian> Nlist for macho::Nlist32<Endian> { - type Word = u32; - type Endian = Endian; - - fn n_strx(&self, endian: Self::Endian) -> u32 { - self.n_strx.get(endian) - } - fn n_type(&self) -> u8 { - self.n_type - } - fn n_sect(&self) -> u8 { - self.n_sect - } - fn n_desc(&self, endian: Self::Endian) -> u16 { - self.n_desc.get(endian) - } - fn n_value(&self, endian: Self::Endian) -> Self::Word { - self.n_value.get(endian) - } -} - -impl<Endian: endian::Endian> Nlist for macho::Nlist64<Endian> { - type Word = u64; - type Endian = Endian; - - fn n_strx(&self, endian: Self::Endian) -> u32 { - self.n_strx.get(endian) - } - fn n_type(&self) -> u8 { - self.n_type - } - fn n_sect(&self) -> u8 { - self.n_sect - } - fn n_desc(&self, endian: Self::Endian) -> u16 { - self.n_desc.get(endian) - } - fn n_value(&self, endian: Self::Endian) -> Self::Word { - self.n_value.get(endian) - } -} |