Skip to content

Commit

Permalink
readobj: fix handling of dyld subcache images
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc committed Jan 17, 2025
1 parent b2ce28d commit acffa26
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 35 deletions.
1 change: 0 additions & 1 deletion clippy.toml

This file was deleted.

41 changes: 39 additions & 2 deletions crates/examples/src/bin/readobj.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Example that uses the lower level read API.
use clap::{Arg, ArgAction, Command};
use object::read::macho::DyldCache;
use object::Endianness;
use object_examples::readobj;
use std::path::PathBuf;
use std::{fs, io};
Expand Down Expand Up @@ -156,16 +158,51 @@ fn main() {
continue;
}
};
let file = match unsafe { memmap2::Mmap::map(&file) } {
let mmap = match unsafe { memmap2::Mmap::map(&file) } {
Ok(mmap) => mmap,
Err(err) => {
println!("Failed to map file '{}': {}", file_path.display(), err);
continue;
}
};
let data = &*mmap;

let subcache_suffixes =
DyldCache::<Endianness>::subcache_suffixes(data).unwrap_or_default();
let Ok(subcache_files) = subcache_suffixes
.into_iter()
.map(|suffix| {
let mut subcache_path = file_path.clone();
subcache_path.as_mut_os_string().push(suffix);
let file = match fs::File::open(&subcache_path) {
Ok(file) => file,
Err(err) => {
println!("Failed to open file '{}': {}", subcache_path.display(), err);
return Err(());
}
};
let mmap = match unsafe { memmap2::Mmap::map(&file) } {
Ok(mmap) => mmap,
Err(err) => {
println!("Failed to map file '{}': {}", subcache_path.display(), err);
return Err(());
}
};
Ok(mmap)
})
.collect::<Result<Vec<_>, _>>()
else {
continue;
};
let subcache_data: Vec<&[u8]> = subcache_files.iter().map(|f| &**f).collect();
let stdout = io::stdout();
let stderr = io::stderr();
readobj::print(&mut stdout.lock(), &mut stderr.lock(), &file, &options);
readobj::print(
&mut stdout.lock(),
&mut stderr.lock(),
data,
&subcache_data,
&options,
);
}
}
42 changes: 18 additions & 24 deletions crates/examples/src/readobj/macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ use object::macho::*;
use object::read::macho::*;
use object::BigEndian;

pub(super) fn print_dyld_cache(p: &mut Printer<'_>, data: &[u8]) {
pub(super) fn print_dyld_cache(p: &mut Printer<'_>, data: &[u8], subcache_data: &[&[u8]]) {
if let Some(header) = DyldCacheHeader::<Endianness>::parse(data).print_err(p) {
if let Some((_, endian)) = header.parse_magic().print_err(p) {
print_dyld_cache_header(p, endian, header);
let mappings = header.mappings(endian, data).print_err(p);
if let Some(mappings) = mappings {
print_dyld_cache_mappings(p, mappings);
}
if let Some(images) = header.images(endian, data).print_err(p) {
print_dyld_cache_images(p, endian, data, mappings, images);
}
}
}
if let Some(cache) = DyldCache::<Endianness>::parse(data, subcache_data).print_err(p) {
print_dyld_cache_images(p, &cache);
}
}

pub(super) fn print_dyld_cache_header(
Expand Down Expand Up @@ -93,31 +93,25 @@ pub(super) fn print_dyld_cache_mappings(p: &mut Printer<'_>, mappings: DyldCache
}
}

pub(super) fn print_dyld_cache_images(
p: &mut Printer<'_>,
endian: Endianness,
data: &[u8],
mappings: Option<DyldCacheMappingSlice>,
images: &[DyldCacheImageInfo<Endianness>],
) {
for image in images {
pub(super) fn print_dyld_cache_images(p: &mut Printer<'_>, cache: &DyldCache) {
let endian = cache.endianness();
let data = cache.data();
for image in cache.images() {
if p.options.file {
let info = image.info();
p.group("DyldCacheImageInfo", |p| {
p.field_hex("Address", image.address.get(endian));
p.field_hex("ModTime", image.mod_time.get(endian));
p.field_hex("Inode", image.inode.get(endian));
p.field_hex("Address", info.address.get(endian));
p.field_hex("ModTime", info.mod_time.get(endian));
p.field_hex("Inode", info.inode.get(endian));
p.field_string(
"Path",
image.path_file_offset.get(endian),
image.path(endian, data),
info.path_file_offset.get(endian),
info.path(endian, data),
);
p.field_hex("Pad", image.pad.get(endian));
p.field_hex("Pad", info.pad.get(endian));
});
}
if let Some(offset) = mappings
.as_ref()
.and_then(|mappings| image.file_offset(endian, mappings).print_err(p))
{
if let Some((data, offset)) = image.image_data_and_offset().print_err(p) {
if p.options.file {
p.blank();
}
Expand All @@ -137,7 +131,7 @@ pub(super) fn print_macho_fat32(p: &mut Printer<'_>, data: &[u8]) {
for arch in fat.arches() {
if let Some(data) = arch.data(data).print_err(p) {
p.blank();
print_object(p, data);
print_object(p, data, &[]);
}
}
}
Expand All @@ -153,7 +147,7 @@ pub(super) fn print_macho_fat64(p: &mut Printer<'_>, data: &[u8]) {
for arch in fat.arches() {
if let Some(data) = arch.data(data).print_err(p) {
p.blank();
print_object(p, data);
print_object(p, data, &[]);
}
}
}
Expand Down
16 changes: 11 additions & 5 deletions crates/examples/src/readobj/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,15 @@ impl PrintOptions {
}
}

pub fn print(w: &mut dyn Write, e: &mut dyn Write, file: &[u8], options: &PrintOptions) {
pub fn print(
w: &mut dyn Write,
e: &mut dyn Write,
file: &[u8],
extra_files: &[&[u8]],
options: &PrintOptions,
) {
let mut printer = Printer::new(w, e, options);
print_object(&mut printer, file);
print_object(&mut printer, file, extra_files);
}

struct Printer<'a> {
Expand Down Expand Up @@ -268,7 +274,7 @@ macro_rules! flags {
($($name:ident),+ $(,)?) => ( [ $(Flag { value: $name, name: stringify!($name), }),+ ] )
}

fn print_object(p: &mut Printer<'_>, data: &[u8]) {
fn print_object(p: &mut Printer<'_>, data: &[u8], extra_files: &[&[u8]]) {
let kind = match object::FileKind::parse(data) {
Ok(file) => file,
Err(err) => {
Expand All @@ -281,7 +287,7 @@ fn print_object(p: &mut Printer<'_>, data: &[u8]) {
object::FileKind::Coff => pe::print_coff(p, data),
object::FileKind::CoffBig => pe::print_coff_big(p, data),
object::FileKind::CoffImport => pe::print_coff_import(p, data),
object::FileKind::DyldCache => macho::print_dyld_cache(p, data),
object::FileKind::DyldCache => macho::print_dyld_cache(p, data, extra_files),
object::FileKind::Elf32 => elf::print_elf32(p, data),
object::FileKind::Elf64 => elf::print_elf64(p, data),
object::FileKind::MachO32 => macho::print_macho32(p, data, 0),
Expand Down Expand Up @@ -327,7 +333,7 @@ fn print_archive(p: &mut Printer<'_>, data: &[u8]) {
if member.is_thin() {
p.field("Size", member.size());
} else if let Some(data) = member.data(data).print_err(p) {
print_object(p, data);
print_object(p, data, &[]);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/examples/tests/testfiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ fn testfiles() {
}
};
fail |= testfile(&in_path, &out_path, err_path, |out, err, data| {
readobj::print(out, err, data, &options);
readobj::print(out, err, data, &[], &options);
});
} else if extension == "objcopy" {
#[cfg(feature = "write")]
{
fail |= testfile(&in_path, &out_path, err_path, |out, err, in_data| {
let copy_data = objcopy::copy(in_data);
readobj::print(out, err, &copy_data, &readobj::PrintOptions::all());
readobj::print(out, err, &copy_data, &[], &readobj::PrintOptions::all());
});
}
} else {
Expand Down
8 changes: 7 additions & 1 deletion crates/rewrite/tests/testfiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,13 @@ fn testfile(

let mut out_data = Vec::new();
let mut err_data = Vec::new();
readobj::print(&mut out_data, &mut err_data, &rewrite_data, print_options);
readobj::print(
&mut out_data,
&mut err_data,
&rewrite_data,
&[],
print_options,
);

let update = env::var_os("OBJECT_TESTFILES_UPDATE").is_some();
let mut fail = false;
Expand Down
11 changes: 11 additions & 0 deletions src/read/macho/dyld_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ where
}
}

/// Get the data of the main cache file.
#[inline]
pub fn data(&self) -> R {
self.data
}

/// 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()
Expand Down Expand Up @@ -253,6 +259,11 @@ where
E: Endian,
R: ReadRef<'data>,
{
/// Return the raw data structure for this image.
pub fn info(&self) -> &'data macho::DyldCacheImageInfo<E> {
self.image_info
}

/// 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)?;
Expand Down

0 comments on commit acffa26

Please sign in to comment.