Skip to content

Commit

Permalink
read: add MachOFatFile
Browse files Browse the repository at this point in the history
My primary motivation is to avoid the impl for a type in another
module, but I think this is also closer to the API for other files.
  • Loading branch information
philipc committed Jan 30, 2024
1 parent 2125bfe commit d3da813
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 48 deletions.
10 changes: 5 additions & 5 deletions crates/examples/src/objdump.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -33,19 +33,19 @@ pub fn print<W: Write, E: Write>(
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) {
Ok(data) => dump_object(w, e, data)?,
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) {
Expand Down
28 changes: 13 additions & 15 deletions crates/examples/src/readobj/macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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<Arch: FatArch>(p: &mut Printer<'_>, arch: &Arch) {
Expand Down
68 changes: 42 additions & 26 deletions src/read/macho/fat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,60 @@ 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::<FatHeader>(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<R: ReadRef<'data>>(data: R) -> Result<Self> {
let mut offset = 0;
let header = file
let header = data
.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"));
if header.magic.get(BigEndian) != Fat::MAGIC {
return Err(Error("Invalid fat magic"));
}
file.read_slice::<FatArch32>(&mut offset, header.nfat_arch.get(BigEndian) as usize)
.read_error("Invalid nfat_arch")
let arches = data
.read_slice::<Fat>(&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::<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")
/// 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
}
}

/// A trait for generic access to [`macho::FatArch32`] and [`macho::FatArch64`].
#[allow(missing_docs)]
pub trait FatArch: Pod {
type Word: Into<u64>;
const MAGIC: u32;

fn cputype(&self) -> u32;
fn cpusubtype(&self) -> u32;
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions src/read/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit d3da813

Please sign in to comment.