diff --git a/clippy.toml b/clippy.toml deleted file mode 100644 index e034672c..00000000 --- a/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -msrv = "1.65.0" diff --git a/crates/examples/src/bin/readobj.rs b/crates/examples/src/bin/readobj.rs index 66d4404f..c30e9e11 100644 --- a/crates/examples/src/bin/readobj.rs +++ b/crates/examples/src/bin/readobj.rs @@ -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}; @@ -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::::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::, _>>() + 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, + ); } } diff --git a/crates/examples/src/readobj/macho.rs b/crates/examples/src/readobj/macho.rs index 11672427..34e4d504 100644 --- a/crates/examples/src/readobj/macho.rs +++ b/crates/examples/src/readobj/macho.rs @@ -3,7 +3,7 @@ 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::::parse(data).print_err(p) { if let Some((_, endian)) = header.parse_magic().print_err(p) { print_dyld_cache_header(p, endian, header); @@ -11,11 +11,11 @@ pub(super) fn print_dyld_cache(p: &mut Printer<'_>, data: &[u8]) { 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::::parse(data, subcache_data).print_err(p) { + print_dyld_cache_images(p, &cache); + } } pub(super) fn print_dyld_cache_header( @@ -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, - images: &[DyldCacheImageInfo], -) { - 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(); } @@ -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, &[]); } } } @@ -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, &[]); } } } diff --git a/crates/examples/src/readobj/mod.rs b/crates/examples/src/readobj/mod.rs index cffecb02..ab8238bf 100644 --- a/crates/examples/src/readobj/mod.rs +++ b/crates/examples/src/readobj/mod.rs @@ -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> { @@ -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) => { @@ -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), @@ -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, &[]); } } } diff --git a/crates/examples/tests/testfiles.rs b/crates/examples/tests/testfiles.rs index ecf06a9f..5e1d446c 100644 --- a/crates/examples/tests/testfiles.rs +++ b/crates/examples/tests/testfiles.rs @@ -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, ©_data, &readobj::PrintOptions::all()); + readobj::print(out, err, ©_data, &[], &readobj::PrintOptions::all()); }); } } else { diff --git a/crates/rewrite/tests/testfiles.rs b/crates/rewrite/tests/testfiles.rs index c017919d..0c39621d 100644 --- a/crates/rewrite/tests/testfiles.rs +++ b/crates/rewrite/tests/testfiles.rs @@ -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; diff --git a/src/read/macho/dyld_cache.rs b/src/read/macho/dyld_cache.rs index 9190502b..2415d8db 100644 --- a/src/read/macho/dyld_cache.rs +++ b/src/read/macho/dyld_cache.rs @@ -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() @@ -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 { + 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)?;