diff --git a/crates/examples/src/objdump.rs b/crates/examples/src/objdump.rs index a9a56d3c..33a5e084 100644 --- a/crates/examples/src/objdump.rs +++ b/crates/examples/src/objdump.rs @@ -1,6 +1,6 @@ use object::read::archive::ArchiveFile; use object::read::coff; -use object::read::macho::{DyldCache, FatArch, FatHeader}; +use object::read::macho::{DyldCache, FatArch, MachOFatFile32, MachOFatFile64}; use object::{Endianness, FileKind, Object, ObjectComdat, ObjectSection, ObjectSymbol}; use std::io::{Result, Write}; @@ -33,9 +33,9 @@ pub fn print( Err(err) => writeln!(e, "Failed to parse archive member: {}", err)?, } } - } else if let Ok(arches) = FatHeader::parse_arch32(file) { + } else if let Ok(fat) = MachOFatFile32::parse(file) { writeln!(w, "Format: Mach-O Fat 32")?; - for arch in arches { + for arch in fat.arches() { writeln!(w)?; writeln!(w, "Fat Arch: {:?}", arch.architecture())?; match arch.data(file) { @@ -43,9 +43,9 @@ pub fn print( Err(err) => writeln!(e, "Failed to parse Fat 32 data: {}", err)?, } } - } else if let Ok(arches) = FatHeader::parse_arch64(file) { + } else if let Ok(fat) = MachOFatFile64::parse(file) { writeln!(w, "Format: Mach-O Fat 64")?; - for arch in arches { + for arch in fat.arches() { writeln!(w)?; writeln!(w, "Fat Arch: {:?}", arch.architecture())?; match arch.data(file) { diff --git a/crates/examples/src/readobj/macho.rs b/crates/examples/src/readobj/macho.rs index 7b75f1bd..e2cd7c32 100644 --- a/crates/examples/src/readobj/macho.rs +++ b/crates/examples/src/readobj/macho.rs @@ -91,13 +91,13 @@ pub(super) fn print_dyld_cache_images( } pub(super) fn print_macho_fat32(p: &mut Printer<'_>, data: &[u8]) { - if let Some(arches) = FatHeader::parse_arch32(data).print_err(p) { + if let Some(fat) = MachOFatFile32::parse(data).print_err(p) { writeln!(p.w(), "Format: Mach-O Fat 32-bit").unwrap(); - print_fat_header(p, data); - for arch in arches { + print_fat_header(p, fat.header()); + for arch in fat.arches() { print_fat_arch(p, arch); } - for arch in arches { + for arch in fat.arches() { if let Some(data) = arch.data(data).print_err(p) { p.blank(); print_object(p, data); @@ -107,13 +107,13 @@ pub(super) fn print_macho_fat32(p: &mut Printer<'_>, data: &[u8]) { } pub(super) fn print_macho_fat64(p: &mut Printer<'_>, data: &[u8]) { - if let Some(arches) = FatHeader::parse_arch64(data).print_err(p) { + if let Some(fat) = MachOFatFile64::parse(data).print_err(p) { writeln!(p.w(), "Format: Mach-O Fat 64-bit").unwrap(); - print_fat_header(p, data); - for arch in arches { + print_fat_header(p, fat.header()); + for arch in fat.arches() { print_fat_arch(p, arch); } - for arch in arches { + for arch in fat.arches() { if let Some(data) = arch.data(data).print_err(p) { p.blank(); print_object(p, data); @@ -122,16 +122,14 @@ pub(super) fn print_macho_fat64(p: &mut Printer<'_>, data: &[u8]) { } } -pub(super) fn print_fat_header(p: &mut Printer<'_>, data: &[u8]) { +pub(super) fn print_fat_header(p: &mut Printer<'_>, header: &macho::FatHeader) { if !p.options.file { return; } - if let Some(header) = FatHeader::parse(data).print_err(p) { - p.group("FatHeader", |p| { - p.field_hex("Magic", header.magic.get(BigEndian)); - p.field("NumberOfFatArch", header.nfat_arch.get(BigEndian)); - }); - } + p.group("FatHeader", |p| { + p.field_hex("Magic", header.magic.get(BigEndian)); + p.field("NumberOfFatArch", header.nfat_arch.get(BigEndian)); + }); } pub(super) fn print_fat_arch(p: &mut Printer<'_>, arch: &Arch) { diff --git a/src/read/macho/fat.rs b/src/read/macho/fat.rs index d12e1dad..9a049d98 100644 --- a/src/read/macho/fat.rs +++ b/src/read/macho/fat.rs @@ -5,39 +5,52 @@ use crate::read::{Architecture, Error, ReadError, ReadRef, Result}; 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::(0) - .read_error("Invalid fat header size or alignment") - } +/// A 32-bit Mach-O universal binary. +/// +/// This is a file that starts with [`macho::FatHeader`], and corresponds +/// to [`crate::FileKind::MachOFat32`]. +pub type MachOFatFile32<'data> = MachOFatFile<'data, macho::FatArch32>; + +/// A 64-bit Mach-O universal binary. +/// +/// This is a file that starts with [`macho::FatHeader`], and corresponds +/// to [`crate::FileKind::MachOFat64`]. +pub type MachOFatFile64<'data> = MachOFatFile<'data, macho::FatArch64>; + +/// A Mach-O universal binary. +/// +/// This is a file that starts with [`macho::FatHeader`], and corresponds +/// to [`crate::FileKind::MachOFat32`] or [`crate::FileKind::MachOFat64`]. +#[derive(Debug, Clone)] +pub struct MachOFatFile<'data, Fat: FatArch> { + header: &'data macho::FatHeader, + arches: &'data [Fat], +} - /// Attempt to parse a fat header and 32-bit fat arches. - pub fn parse_arch32<'data, R: ReadRef<'data>>(file: R) -> Result<&'data [FatArch32]> { +impl<'data, Fat: FatArch> MachOFatFile<'data, Fat> { + /// Attempt to parse the fat header and fat arches. + pub fn parse>(data: R) -> Result { let mut offset = 0; - let header = file + let header = data .read::(&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")); + if header.magic.get(BigEndian) != Fat::MAGIC { + return Err(Error("Invalid fat magic")); } - file.read_slice::(&mut offset, header.nfat_arch.get(BigEndian) as usize) - .read_error("Invalid nfat_arch") + let arches = data + .read_slice::(&mut offset, header.nfat_arch.get(BigEndian) as usize) + .read_error("Invalid nfat_arch")?; + Ok(MachOFatFile { header, arches }) } - /// 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::(&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::(&mut offset, header.nfat_arch.get(BigEndian) as usize) - .read_error("Invalid nfat_arch") + /// Return the fat header + pub fn header(&self) -> &'data macho::FatHeader { + self.header + } + + /// Return the array of fat arches. + pub fn arches(&self) -> &'data [Fat] { + self.arches } } @@ -45,6 +58,7 @@ impl FatHeader { #[allow(missing_docs)] pub trait FatArch: Pod { type Word: Into; + const MAGIC: u32; fn cputype(&self) -> u32; fn cpusubtype(&self) -> u32; @@ -77,6 +91,7 @@ pub trait FatArch: Pod { impl FatArch for FatArch32 { type Word = u32; + const MAGIC: u32 = macho::FAT_MAGIC; fn cputype(&self) -> u32 { self.cputype.get(BigEndian) @@ -101,6 +116,7 @@ impl FatArch for FatArch32 { impl FatArch for FatArch64 { type Word = u64; + const MAGIC: u32 = macho::FAT_MAGIC_64; fn cputype(&self) -> u32 { self.cputype.get(BigEndian) diff --git a/src/read/mod.rs b/src/read/mod.rs index 66ae5c56..7db12192 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -237,12 +237,12 @@ pub enum FileKind { MachO64, /// A 32-bit Mach-O fat binary. /// - /// See [`macho::FatHeader::parse_arch32`]. + /// See [`macho::MachOFatFile32`]. #[cfg(feature = "macho")] MachOFat32, /// A 64-bit Mach-O fat binary. /// - /// See [`macho::FatHeader::parse_arch64`]. + /// See [`macho::MachOFatFile64`]. #[cfg(feature = "macho")] MachOFat64, /// A 32-bit PE file.