From 567edaf2460e9cf4e21d2da2431c276e32fb70d4 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Sat, 27 Jan 2024 16:42:22 +1000 Subject: [PATCH] readobj: add command line options (#625) --- .github/workflows/rust.yml | 4 +- crates/examples/Cargo.toml | 1 + crates/examples/src/bin/readobj.rs | 147 +++++++++++- crates/examples/src/readobj/elf.rs | 66 +++++- crates/examples/src/readobj/macho.rs | 324 +++++++++++++++++---------- crates/examples/src/readobj/mod.rs | 84 ++++++- crates/examples/src/readobj/pe.rs | 310 +++++++++++++++---------- crates/examples/src/readobj/xcoff.rs | 106 +++++---- crates/examples/tests/testfiles.rs | 6 +- 9 files changed, 745 insertions(+), 303 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 61aaab66..40d7fac2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -83,7 +83,7 @@ jobs: run: | cargo update -p memchr --precise 2.6.2 - name: Test - run: cargo test --verbose --no-default-features --features read,std + run: cargo test -p object --verbose --no-default-features --features read,std msrv-all: runs-on: ubuntu-latest @@ -94,7 +94,7 @@ jobs: - name: Install rust run: rustup update 1.65.0 && rustup default 1.65.0 - name: Test - run: cargo test --verbose --features all + run: cargo test -p object --verbose --features all rustfmt: runs-on: ubuntu-latest diff --git a/crates/examples/Cargo.toml b/crates/examples/Cargo.toml index cca7dc81..b2ae2cc4 100644 --- a/crates/examples/Cargo.toml +++ b/crates/examples/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" edition = "2018" [dependencies] +clap = "4.3.24" memmap2 = "0.7.1" object = { path = "../..", default-features = false } diff --git a/crates/examples/src/bin/readobj.rs b/crates/examples/src/bin/readobj.rs index 3d54703c..911e94d6 100644 --- a/crates/examples/src/bin/readobj.rs +++ b/crates/examples/src/bin/readobj.rs @@ -1,38 +1,163 @@ //! Example that uses the lower level read API. +use clap::{Arg, ArgAction, Command}; use object_examples::readobj; -use std::{env, fs, io, process}; +use std::path::PathBuf; +use std::{fs, io}; fn main() { - let arg_len = env::args().len(); - if arg_len <= 1 { - eprintln!("Usage: {} ...", env::args().next().unwrap()); - process::exit(1); + let matches = Command::new("readobj") + .arg( + Arg::new("file") + .action(ArgAction::Append) + .required(true) + .value_parser(clap::value_parser!(PathBuf)) + .help("The file to read"), + ) + .arg( + Arg::new("file-header") + .long("file-header") + .action(ArgAction::SetTrue) + .help("Print the file header"), + ) + .arg( + Arg::new("segments") + .long("segments") + .action(ArgAction::SetTrue) + .help("Print the segments"), + ) + .arg( + Arg::new("sections") + .long("sections") + .action(ArgAction::SetTrue) + .help("Print the sections"), + ) + .arg( + Arg::new("symbols") + .long("symbols") + .action(ArgAction::SetTrue) + .help("Print the symbols"), + ) + .arg( + Arg::new("relocations") + .long("relocations") + .action(ArgAction::SetTrue) + .help("Print the relocations"), + ) + .arg( + Arg::new("elf-dynamic") + .long("elf-dynamic") + .action(ArgAction::SetTrue) + .help("Print the ELF dynamic section"), + ) + .arg( + Arg::new("elf-dynamic-symbols") + .long("elf-dynamic-symbols") + .action(ArgAction::SetTrue) + .help("Print the dynamic symbols"), + ) + .arg( + Arg::new("elf-notes") + .long("elf-notes") + .action(ArgAction::SetTrue) + .help("Print the ELF notes"), + ) + .arg( + Arg::new("elf-version-info") + .long("elf-version-info") + .action(ArgAction::SetTrue) + .help("Print the ELF version info sections"), + ) + .arg( + Arg::new("elf-attributes") + .long("elf-attributes") + .action(ArgAction::SetTrue) + .help("Print the ELF attribute sections"), + ) + .arg( + Arg::new("macho-load-commands") + .long("macho-load-commands") + .action(ArgAction::SetTrue) + .help("Print the Mach-O load commands"), + ) + .arg( + Arg::new("pe-rich") + .long("pe-rich") + .action(ArgAction::SetTrue) + .help("Print the PE rich header"), + ) + .arg( + Arg::new("pe-base-relocs") + .long("pe-base-relocs") + .action(ArgAction::SetTrue) + .help("Print the PE base relocations"), + ) + .arg( + Arg::new("pe-imports") + .long("pe-imports") + .action(ArgAction::SetTrue) + .help("Print the PE imports"), + ) + .arg( + Arg::new("pe-exports") + .long("pe-exports") + .action(ArgAction::SetTrue) + .help("Print the PE exports"), + ) + .arg( + Arg::new("pe-resources") + .long("pe-resources") + .action(ArgAction::SetTrue) + .help("Print the PE resource directory"), + ) + .get_matches(); + let mut options = readobj::PrintOptions { + file: matches.get_flag("file-header"), + segments: matches.get_flag("segments"), + sections: matches.get_flag("sections"), + symbols: matches.get_flag("symbols"), + relocations: matches.get_flag("relocations"), + elf_dynamic: matches.get_flag("elf-dynamic"), + elf_dynamic_symbols: matches.get_flag("elf-dynamic-symbols"), + elf_notes: matches.get_flag("elf-notes"), + elf_versions: matches.get_flag("elf-version-info"), + elf_attributes: matches.get_flag("elf-attributes"), + macho_load_commands: matches.get_flag("macho-load-commands"), + pe_rich: matches.get_flag("pe-rich"), + pe_base_relocs: matches.get_flag("pe-base-relocs"), + pe_imports: matches.get_flag("pe-imports"), + pe_exports: matches.get_flag("pe-exports"), + pe_resources: matches.get_flag("pe-resources"), + }; + if options == readobj::PrintOptions::none() { + options = readobj::PrintOptions::all(); } - for file_path in env::args().skip(1) { - if arg_len > 2 { + let file_paths = matches.get_many::("file").unwrap(); + let file_count = file_paths.len(); + for file_path in file_paths { + if file_count > 1 { println!(); - println!("{}:", file_path); + println!("{}:", file_path.display()); } let file = match fs::File::open(&file_path) { Ok(file) => file, Err(err) => { - println!("Failed to open file '{}': {}", file_path, err); + println!("Failed to open file '{}': {}", file_path.display(), err); continue; } }; let file = match unsafe { memmap2::Mmap::map(&file) } { Ok(mmap) => mmap, Err(err) => { - println!("Failed to map file '{}': {}", file_path, err); + println!("Failed to map file '{}': {}", file_path.display(), err); continue; } }; let stdout = io::stdout(); let stderr = io::stderr(); - readobj::print(&mut stdout.lock(), &mut stderr.lock(), &file); + readobj::print(&mut stdout.lock(), &mut stderr.lock(), &file, &options); } } diff --git a/crates/examples/src/readobj/elf.rs b/crates/examples/src/readobj/elf.rs index 46e4eb93..b0be5761 100644 --- a/crates/examples/src/readobj/elf.rs +++ b/crates/examples/src/readobj/elf.rs @@ -30,6 +30,9 @@ fn print_elf>(p: &mut Printer<'_>, elf: &El } fn print_file_header(p: &mut Printer<'_>, endian: Elf::Endian, elf: &Elf) { + if !p.options.file { + return; + } p.group("FileHeader", |p| { p.group("Ident", |p| print_ident(p, elf.e_ident())); p.field_enum("Type", elf.e_type(endian), FLAGS_ET); @@ -113,6 +116,13 @@ fn print_program_headers( segments: &[Elf::ProgramHeader], ) { for segment in segments { + let p_type = segment.p_type(endian); + if !p.options.segments + && !(p.options.elf_notes && p_type == PT_NOTE) + && !(p.options.elf_dynamic && p_type == PT_DYNAMIC) + { + continue; + } p.group("ProgramHeader", |p| { let proc = match elf.e_machine(endian) { EM_MIPS => FLAGS_PT_MIPS, @@ -175,6 +185,9 @@ fn print_segment_notes( elf: &Elf, segment: &Elf::ProgramHeader, ) { + if !p.options.elf_notes { + return; + } if let Some(Some(notes)) = segment.notes(endian, data).print_err(p) { print_notes(p, endian, elf, notes); } @@ -188,6 +201,9 @@ fn print_segment_dynamic( segments: &[Elf::ProgramHeader], segment: &Elf::ProgramHeader, ) { + if !p.options.elf_dynamic { + return; + } if let Some(Some(dynamic)) = segment.dynamic(endian, data).print_err(p) { // TODO: add a helper API for this and the other mandatory tags? let mut strtab = 0; @@ -221,6 +237,21 @@ fn print_section_headers( sections: &SectionTable, ) { for (index, section) in sections.iter().enumerate() { + let sh_type = section.sh_type(endian); + if !p.options.sections + && !(p.options.symbols && sh_type == SHT_SYMTAB) + && !(p.options.relocations && sh_type == SHT_REL) + && !(p.options.relocations && sh_type == SHT_RELA) + && !(p.options.elf_dynamic && sh_type == SHT_DYNAMIC) + && !(p.options.elf_dynamic_symbols && sh_type == SHT_DYNSYM) + && !(p.options.elf_notes && sh_type == SHT_NOTE) + && !(p.options.elf_versions && sh_type == SHT_GNU_VERDEF) + && !(p.options.elf_versions && sh_type == SHT_GNU_VERNEED) + && !(p.options.elf_versions && sh_type == SHT_GNU_VERSYM) + && !(p.options.elf_attributes && sh_type == SHT_GNU_ATTRIBUTES) + { + continue; + } let index = SectionIndex(index); p.group("SectionHeader", |p| { p.field("Index", index.0); @@ -272,8 +303,15 @@ fn print_section_headers( } match section.sh_type(endian) { - SHT_SYMTAB | SHT_DYNSYM => { - print_section_symbols(p, endian, data, elf, sections, index, section) + SHT_SYMTAB => { + if p.options.symbols { + print_section_symbols(p, endian, data, elf, sections, index, section); + } + } + SHT_DYNSYM => { + if p.options.elf_dynamic_symbols { + print_section_symbols(p, endian, data, elf, sections, index, section); + } } SHT_REL => print_section_rel(p, endian, data, elf, sections, section), SHT_RELA => print_section_rela(p, endian, data, elf, sections, section), @@ -396,6 +434,9 @@ fn print_section_rel( sections: &SectionTable, section: &Elf::SectionHeader, ) { + if !p.options.relocations { + return; + } if let Some(Some((relocations, link))) = section.rel(endian, data).print_err(p) { let symbols = sections .symbol_table_by_index(endian, data, link) @@ -420,6 +461,9 @@ fn print_section_rela( sections: &SectionTable, section: &Elf::SectionHeader, ) { + if !p.options.relocations { + return; + } if let Some(Some((relocations, link))) = section.rela(endian, data).print_err(p) { let symbols = sections .symbol_table_by_index(endian, data, link) @@ -500,6 +544,9 @@ fn print_section_notes( elf: &Elf, section: &Elf::SectionHeader, ) { + if !p.options.elf_notes { + return; + } if let Some(Some(notes)) = section.notes(endian, data).print_err(p) { print_notes(p, endian, elf, notes); } @@ -513,6 +560,9 @@ fn print_section_dynamic( sections: &SectionTable, section: &Elf::SectionHeader, ) { + if !p.options.elf_dynamic { + return; + } if let Some(Some((dynamic, index))) = section.dynamic(endian, data).print_err(p) { let strings = sections.strings(endian, data, index).unwrap_or_default(); print_dynamic(p, endian, elf, dynamic, strings); @@ -756,6 +806,9 @@ fn print_gnu_verdef( sections: &SectionTable, section: &Elf::SectionHeader, ) { + if !p.options.elf_versions { + return; + } if let Some(Some((mut verdefs, link))) = section.gnu_verdef(endian, data).print_err(p) { let strings = sections.strings(endian, data, link).unwrap_or_default(); while let Some(Some((verdef, mut verdauxs))) = verdefs.next().print_err(p) { @@ -791,6 +844,9 @@ fn print_gnu_verneed( sections: &SectionTable, section: &Elf::SectionHeader, ) { + if !p.options.elf_versions { + return; + } if let Some(Some((mut verneeds, link))) = section.gnu_verneed(endian, data).print_err(p) { let strings = sections.strings(endian, data, link).unwrap_or_default(); while let Some(Some((verneed, mut vernauxs))) = verneeds.next().print_err(p) { @@ -831,6 +887,9 @@ fn print_gnu_versym( sections: &SectionTable, section: &Elf::SectionHeader, ) { + if !p.options.elf_versions { + return; + } if let Some(Some((syms, _link))) = section.gnu_versym(endian, data).print_err(p) { let versions = sections.versions(endian, data).print_err(p).flatten(); for (index, sym) in syms.iter().enumerate() { @@ -850,6 +909,9 @@ fn print_attributes( _elf: &Elf, section: &Elf::SectionHeader, ) { + if !p.options.elf_attributes { + return; + } if let Some(section) = section.attributes(endian, data).print_err(p) { p.group("Attributes", |p| { p.field("Version", section.version()); diff --git a/crates/examples/src/readobj/macho.rs b/crates/examples/src/readobj/macho.rs index a216c5d8..baf97c0b 100644 --- a/crates/examples/src/readobj/macho.rs +++ b/crates/examples/src/readobj/macho.rs @@ -23,6 +23,9 @@ pub(super) fn print_dyld_cache_header( endian: Endianness, header: &DyldCacheHeader, ) { + if !p.options.file { + return; + } p.group("DyldCacheHeader", |p| { p.field_bytes("Magic", &header.magic); p.field_hex("MappingOffset", header.mapping_offset.get(endian)); @@ -38,6 +41,9 @@ pub(super) fn print_dyld_cache_mappings( endian: Endianness, mappings: &[DyldCacheMappingInfo], ) { + if !p.options.file { + return; + } for mapping in mappings { p.group("DyldCacheMappingInfo", |p| { p.field_hex("Address", mapping.address.get(endian)); @@ -59,21 +65,25 @@ pub(super) fn print_dyld_cache_images( images: &[DyldCacheImageInfo], ) { for image in images { - 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_string( - "Path", - image.path_file_offset.get(endian), - image.path(endian, data), - ); - p.field_hex("Pad", image.pad.get(endian)); - }); + if p.options.file { + 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_string( + "Path", + image.path_file_offset.get(endian), + image.path(endian, data), + ); + p.field_hex("Pad", image.pad.get(endian)); + }); + } if let Some(offset) = mappings.and_then(|mappings| image.file_offset(endian, mappings).print_err(p)) { - p.blank(); + if p.options.file { + p.blank(); + } print_object_at(p, data, offset); p.blank(); } @@ -113,6 +123,9 @@ pub(super) fn print_macho_fat64(p: &mut Printer<'_>, data: &[u8]) { } pub(super) fn print_fat_header(p: &mut Printer<'_>, data: &[u8]) { + 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)); @@ -122,6 +135,9 @@ pub(super) fn print_fat_header(p: &mut Printer<'_>, data: &[u8]) { } pub(super) fn print_fat_arch(p: &mut Printer<'_>, arch: &Arch) { + if !p.options.file { + return; + } p.group("FatArch", |p| { print_cputype(p, arch.cputype(), arch.cpusubtype()); p.field_hex("Offset", arch.offset().into()); @@ -191,15 +207,14 @@ fn print_macho>( } print_mach_header(p, endian, header); - if let Some(mut commands) = header.load_commands(endian, data, offset).print_err(p) { - while let Some(Some(command)) = commands.next().print_err(p) { - print_load_command(p, endian, data, header, command, &mut state); - } - } + print_load_commands(p, endian, data, offset, header, &mut state); } } fn print_mach_header(p: &mut Printer<'_>, endian: Mach::Endian, header: &Mach) { + if !p.options.file { + return; + } p.group("MachHeader", |p| { p.field_hex("Magic", header.magic()); print_cputype(p, header.cputype(endian), header.cpusubtype(endian)); @@ -210,6 +225,21 @@ fn print_mach_header(p: &mut Printer<'_>, endian: Mach::Endian }); } +fn print_load_commands( + p: &mut Printer<'_>, + endian: Mach::Endian, + data: &[u8], + offset: u64, + header: &Mach, + state: &mut MachState, +) { + if let Some(mut commands) = header.load_commands(endian, data, offset).print_err(p) { + while let Some(Some(command)) = commands.next().print_err(p) { + print_load_command(p, endian, data, header, command, state); + } + } +} + fn print_load_command( p: &mut Printer<'_>, endian: Mach::Endian, @@ -229,6 +259,15 @@ fn print_load_command( LoadCommandVariant::Symtab(symtab) => { print_symtab::(p, endian, data, symtab, state); } + _ => {} + } + if !p.options.macho_load_commands { + return; + } + match variant { + LoadCommandVariant::Segment32(..) + | LoadCommandVariant::Segment64(..) + | LoadCommandVariant::Symtab(..) => {} LoadCommandVariant::Thread(x, _thread_data) => { p.group("ThreadCommand", |p| { p.field_enum("Cmd", x.cmd.get(endian), FLAGS_LC); @@ -546,24 +585,34 @@ fn print_segment( section_data: &[u8], state: &mut MachState, ) { + if !p.options.macho_load_commands + && !p.options.segments + && !p.options.sections + && !p.options.relocations + { + return; + } p.group("SegmentCommand", |p| { p.field_enum("Cmd", segment.cmd(endian), FLAGS_LC); p.field_hex("CmdSize", segment.cmdsize(endian)); p.field_inline_string("SegmentName", segment.name()); - p.field_hex("VmAddress", segment.vmaddr(endian).into()); - p.field_hex("VmSize", segment.vmsize(endian).into()); - p.field_hex("FileOffset", segment.fileoff(endian).into()); - p.field_hex("FileSize", segment.filesize(endian).into()); - p.field_hex("MaxProt", segment.maxprot(endian)); - p.flags(segment.maxprot(endian), 0, FLAGS_VM); - p.field_hex("InitProt", segment.initprot(endian)); - p.flags(segment.initprot(endian), 0, FLAGS_VM); - p.field("NumberOfSections", segment.nsects(endian)); - p.field_hex("Flags", segment.flags(endian)); - p.flags(segment.flags(endian), 0, FLAGS_SG); + if p.options.macho_load_commands || p.options.segments { + p.field_hex("VmAddress", segment.vmaddr(endian).into()); + p.field_hex("VmSize", segment.vmsize(endian).into()); + p.field_hex("FileOffset", segment.fileoff(endian).into()); + p.field_hex("FileSize", segment.filesize(endian).into()); + p.field_hex("MaxProt", segment.maxprot(endian)); + p.flags(segment.maxprot(endian), 0, FLAGS_VM); + p.field_hex("InitProt", segment.initprot(endian)); + p.flags(segment.initprot(endian), 0, FLAGS_VM); + p.field("NumberOfSections", segment.nsects(endian)); + p.field_hex("Flags", segment.flags(endian)); + p.flags(segment.flags(endian), 0, FLAGS_SG); + } if let Some(sections) = segment.sections(endian, section_data).print_err(p) { for section in sections { print_section(p, endian, data, section, state); + state.section_index += 1; } } }); @@ -576,73 +625,90 @@ fn print_section( section: &S, state: &mut MachState, ) { + if !p.options.sections && !(p.options.relocations && section.nreloc(endian) != 0) { + return; + } p.group("Section", |p| { p.field("Index", state.section_index); - state.section_index += 1; p.field_inline_string("SectionName", section.name()); p.field_inline_string("SegmentName", section.segment_name()); - p.field_hex("Address", section.addr(endian).into()); - p.field_hex("Size", section.size(endian).into()); - p.field_hex("Offset", section.offset(endian)); - p.field_hex("Align", section.align(endian)); - p.field_hex("RelocationOffset", section.reloff(endian)); - p.field_hex("NumberOfRelocations", section.nreloc(endian)); - let flags = section.flags(endian); - if flags & SECTION_TYPE == flags { - p.field_enum("Flags", flags, FLAGS_S_TYPE); - } else { - p.field_hex("Flags", section.flags(endian)); - p.flags(flags, SECTION_TYPE, FLAGS_S_TYPE); - p.flags(flags, 0, FLAGS_S_ATTR); - } - if let Some(relocations) = section.relocations(endian, data).print_err(p) { - let proc = match state.cputype { - CPU_TYPE_X86 => FLAGS_GENERIC_RELOC, - CPU_TYPE_X86_64 => FLAGS_X86_64_RELOC, - CPU_TYPE_ARM => FLAGS_ARM_RELOC, - CPU_TYPE_ARM64 | CPU_TYPE_ARM64_32 => FLAGS_ARM64_RELOC, - CPU_TYPE_POWERPC | CPU_TYPE_POWERPC64 => FLAGS_PPC_RELOC, - _ => &[], - }; - for relocation in relocations { - if relocation.r_scattered(endian, state.cputype) { - let info = relocation.scattered_info(endian); - p.group("ScatteredRelocationInfo", |p| { - p.field_hex("Address", info.r_address); - p.field("PcRel", if info.r_pcrel { "yes" } else { "no" }); - p.field("Length", info.r_length); - p.field_enum("Type", info.r_type, proc); - p.field_hex("Value", info.r_value); - }); - } else { - let info = relocation.info(endian); - p.group("RelocationInfo", |p| { - p.field_hex("Address", info.r_address); - p.field("Extern", if info.r_extern { "yes" } else { "no" }); - if info.r_extern { - let name = state - .symbols - .get(info.r_symbolnum as usize) - .copied() - .flatten(); - p.field_string_option("Symbol", info.r_symbolnum, name); - } else { - let name = state - .sections - .get(info.r_symbolnum as usize) - .map(|name| &name[..]); - p.field_string_option("Section", info.r_symbolnum, name); - } - p.field("PcRel", if info.r_pcrel { "yes" } else { "no" }); - p.field("Length", info.r_length); - p.field_enum("Type", info.r_type, proc); - }); - } + if p.options.sections { + p.field_hex("Address", section.addr(endian).into()); + p.field_hex("Size", section.size(endian).into()); + p.field_hex("Offset", section.offset(endian)); + p.field_hex("Align", section.align(endian)); + p.field_hex("RelocationOffset", section.reloff(endian)); + p.field_hex("NumberOfRelocations", section.nreloc(endian)); + let flags = section.flags(endian); + if flags & SECTION_TYPE == flags { + p.field_enum("Flags", flags, FLAGS_S_TYPE); + } else { + p.field_hex("Flags", section.flags(endian)); + p.flags(flags, SECTION_TYPE, FLAGS_S_TYPE); + p.flags(flags, 0, FLAGS_S_ATTR); } } + print_section_relocations(p, endian, data, section, state); }); } +fn print_section_relocations( + p: &mut Printer<'_>, + endian: S::Endian, + data: &[u8], + section: &S, + state: &MachState, +) { + if !p.options.relocations { + return; + } + if let Some(relocations) = section.relocations(endian, data).print_err(p) { + let proc = match state.cputype { + CPU_TYPE_X86 => FLAGS_GENERIC_RELOC, + CPU_TYPE_X86_64 => FLAGS_X86_64_RELOC, + CPU_TYPE_ARM => FLAGS_ARM_RELOC, + CPU_TYPE_ARM64 | CPU_TYPE_ARM64_32 => FLAGS_ARM64_RELOC, + CPU_TYPE_POWERPC | CPU_TYPE_POWERPC64 => FLAGS_PPC_RELOC, + _ => &[], + }; + for relocation in relocations { + if relocation.r_scattered(endian, state.cputype) { + let info = relocation.scattered_info(endian); + p.group("ScatteredRelocationInfo", |p| { + p.field_hex("Address", info.r_address); + p.field("PcRel", if info.r_pcrel { "yes" } else { "no" }); + p.field("Length", info.r_length); + p.field_enum("Type", info.r_type, proc); + p.field_hex("Value", info.r_value); + }); + } else { + let info = relocation.info(endian); + p.group("RelocationInfo", |p| { + p.field_hex("Address", info.r_address); + p.field("Extern", if info.r_extern { "yes" } else { "no" }); + if info.r_extern { + let name = state + .symbols + .get(info.r_symbolnum as usize) + .copied() + .flatten(); + p.field_string_option("Symbol", info.r_symbolnum, name); + } else { + let name = state + .sections + .get(info.r_symbolnum as usize) + .map(|name| &name[..]); + p.field_string_option("Section", info.r_symbolnum, name); + } + p.field("PcRel", if info.r_pcrel { "yes" } else { "no" }); + p.field("Length", info.r_length); + p.field_enum("Type", info.r_type, proc); + }); + } + } + } +} + fn print_symtab( p: &mut Printer<'_>, endian: Mach::Endian, @@ -650,6 +716,9 @@ fn print_symtab( symtab: &SymtabCommand, state: &MachState, ) { + if !p.options.macho_load_commands && !p.options.symbols { + return; + } p.group("SymtabCommand", |p| { p.field_enum("Cmd", symtab.cmd.get(endian), FLAGS_LC); p.field_hex("CmdSize", symtab.cmdsize.get(endian)); @@ -657,44 +726,57 @@ fn print_symtab( p.field_hex("NumberOfSymbols", symtab.nsyms.get(endian)); p.field_hex("StringOffset", symtab.stroff.get(endian)); p.field_hex("StringSize", symtab.strsize.get(endian)); - if let Some(symbols) = symtab.symbols::(endian, data).print_err(p) { - for (index, nlist) in symbols.iter().enumerate() { - p.group("Nlist", |p| { - p.field("Index", index); - p.field_string( - "String", - nlist.n_strx(endian), - nlist.name(endian, symbols.strings()), - ); - let n_type = nlist.n_type(); - if nlist.is_stab() { - p.field_enum("Type", n_type, FLAGS_N_STAB); - } else if n_type & N_TYPE == n_type { - // Avoid an extra line if no flags. - p.field_enum("Type", n_type, FLAGS_N_TYPE); - } else { - p.field_hex("Type", n_type); - p.flags(n_type, N_TYPE, FLAGS_N_TYPE); - p.flags(n_type, 0, FLAGS_N_EXT); - } - let n_sect = nlist.n_sect(); - let name = state.sections.get(n_sect as usize).map(|name| &name[..]); - p.field_string_option("Section", n_sect, name); - let n_desc = nlist.n_desc(endian); - p.field_hex("Desc", n_desc); - if nlist.is_undefined() { - p.flags(n_desc, REFERENCE_TYPE, FLAGS_REFERENCE); - } - if !nlist.is_stab() { - p.flags(n_desc, 0, FLAGS_N_DESC); - } - p.field_hex("Value", nlist.n_value(endian).into()); - }); - } - } + print_symtab_symbols::(p, endian, data, symtab, state); }); } +fn print_symtab_symbols( + p: &mut Printer<'_>, + endian: Mach::Endian, + data: &[u8], + symtab: &SymtabCommand, + state: &MachState, +) { + if !p.options.symbols { + return; + } + if let Some(symbols) = symtab.symbols::(endian, data).print_err(p) { + for (index, nlist) in symbols.iter().enumerate() { + p.group("Nlist", |p| { + p.field("Index", index); + p.field_string( + "String", + nlist.n_strx(endian), + nlist.name(endian, symbols.strings()), + ); + let n_type = nlist.n_type(); + if nlist.is_stab() { + p.field_enum("Type", n_type, FLAGS_N_STAB); + } else if n_type & N_TYPE == n_type { + // Avoid an extra line if no flags. + p.field_enum("Type", n_type, FLAGS_N_TYPE); + } else { + p.field_hex("Type", n_type); + p.flags(n_type, N_TYPE, FLAGS_N_TYPE); + p.flags(n_type, 0, FLAGS_N_EXT); + } + let n_sect = nlist.n_sect(); + let name = state.sections.get(n_sect as usize).map(|name| &name[..]); + p.field_string_option("Section", n_sect, name); + let n_desc = nlist.n_desc(endian); + p.field_hex("Desc", n_desc); + if nlist.is_undefined() { + p.flags(n_desc, REFERENCE_TYPE, FLAGS_REFERENCE); + } + if !nlist.is_stab() { + p.flags(n_desc, 0, FLAGS_N_DESC); + } + p.field_hex("Value", nlist.n_value(endian).into()); + }); + } + } +} + fn print_cputype(p: &mut Printer<'_>, cputype: u32, cpusubtype: u32) { let proc = match cputype { CPU_TYPE_ANY => FLAGS_CPU_SUBTYPE_ANY, diff --git a/crates/examples/src/readobj/mod.rs b/crates/examples/src/readobj/mod.rs index d9cc923e..e49a8871 100644 --- a/crates/examples/src/readobj/mod.rs +++ b/crates/examples/src/readobj/mod.rs @@ -5,8 +5,78 @@ use object::read::archive::ArchiveFile; use object::read::macho::{FatArch, FatHeader}; use object::Endianness; -pub fn print(w: &'_ mut dyn Write, e: &'_ mut dyn Write, file: &[u8]) { - let mut printer = Printer::new(w, e); +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PrintOptions { + pub file: bool, + pub segments: bool, + pub sections: bool, + pub symbols: bool, + pub relocations: bool, + + // ELF specific + pub elf_dynamic: bool, + pub elf_dynamic_symbols: bool, + pub elf_notes: bool, + pub elf_versions: bool, + pub elf_attributes: bool, + + // Mach-O specific + pub macho_load_commands: bool, + + // PE specific + pub pe_rich: bool, + pub pe_base_relocs: bool, + pub pe_imports: bool, + pub pe_exports: bool, + pub pe_resources: bool, +} + +impl PrintOptions { + pub fn all() -> Self { + Self { + file: true, + segments: true, + sections: true, + symbols: true, + relocations: true, + elf_dynamic: true, + elf_dynamic_symbols: true, + elf_notes: true, + elf_versions: true, + elf_attributes: true, + macho_load_commands: true, + pe_rich: true, + pe_base_relocs: true, + pe_imports: true, + pe_exports: true, + pe_resources: true, + } + } + + pub fn none() -> Self { + Self { + file: false, + segments: false, + sections: false, + symbols: false, + relocations: false, + elf_dynamic: false, + elf_dynamic_symbols: false, + elf_notes: false, + elf_versions: false, + elf_attributes: false, + macho_load_commands: false, + pe_rich: false, + pe_base_relocs: false, + pe_imports: false, + pe_exports: false, + pe_resources: false, + } + } +} + +pub fn print(w: &mut dyn Write, e: &mut dyn Write, file: &[u8], options: &PrintOptions) { + let mut printer = Printer::new(w, e, options); print_object(&mut printer, file); } @@ -14,11 +84,17 @@ struct Printer<'a> { w: &'a mut dyn Write, e: &'a mut dyn Write, indent: usize, + options: &'a PrintOptions, } impl<'a> Printer<'a> { - fn new(w: &'a mut dyn Write, e: &'a mut dyn Write) -> Self { - Self { w, e, indent: 0 } + fn new(w: &'a mut dyn Write, e: &'a mut dyn Write, options: &'a PrintOptions) -> Self { + Self { + w, + e, + indent: 0, + options, + } } fn w(&mut self) -> &mut dyn Write { diff --git a/crates/examples/src/readobj/pe.rs b/crates/examples/src/readobj/pe.rs index 6004bd55..97ee305a 100644 --- a/crates/examples/src/readobj/pe.rs +++ b/crates/examples/src/readobj/pe.rs @@ -42,6 +42,9 @@ pub(super) fn print_coff_import(p: &mut Printer<'_>, data: &[u8]) { let mut offset = 0; if let Some(header) = ImportObjectHeader::parse(data, &mut offset).print_err(p) { writeln!(p.w(), "Format: COFF import").unwrap(); + if !p.options.file { + return; + } p.group("ImportObjectHeader", |p| { p.field_hex("Signature1", header.sig1.get(LE)); p.field_hex("Signature2", header.sig2.get(LE)); @@ -75,56 +78,22 @@ pub(super) fn print_pe64(p: &mut Printer<'_>, data: &[u8]) { fn print_pe(p: &mut Printer<'_>, data: &[u8]) { if let Some(dos_header) = ImageDosHeader::parse(data).print_err(p) { - p.group("ImageDosHeader", |p| { - p.field_hex("Magic", dos_header.e_magic.get(LE)); - p.field_hex("CountBytesLastPage", dos_header.e_cblp.get(LE)); - p.field_hex("CountPages", dos_header.e_cp.get(LE)); - p.field_hex("CountRelocations", dos_header.e_crlc.get(LE)); - p.field_hex("CountHeaderParagraphs", dos_header.e_cparhdr.get(LE)); - p.field_hex("MinAllocParagraphs", dos_header.e_minalloc.get(LE)); - p.field_hex("MaxAllocParagraphs", dos_header.e_maxalloc.get(LE)); - p.field_hex("StackSegment", dos_header.e_ss.get(LE)); - p.field_hex("StackPointer", dos_header.e_sp.get(LE)); - p.field_hex("Checksum", dos_header.e_csum.get(LE)); - p.field_hex("InstructionPointer", dos_header.e_ip.get(LE)); - p.field_hex("CodeSegment", dos_header.e_cs.get(LE)); - p.field_hex("AddressOfRelocations", dos_header.e_lfarlc.get(LE)); - p.field_hex("OverlayNumber", dos_header.e_ovno.get(LE)); - p.field_hex("OemId", dos_header.e_oemid.get(LE)); - p.field_hex("OemInfo", dos_header.e_oeminfo.get(LE)); - p.field_hex("AddressOfNewHeader", dos_header.e_lfanew.get(LE)); - }); + print_dos(p, dos_header); let mut offset = dos_header.nt_headers_offset().into(); - if let Some(rich_header) = RichHeaderInfo::parse(data, offset) { - p.group("RichHeader", |p| { - p.field_hex("Offset", rich_header.offset); - p.field_hex("Length", rich_header.length); - p.field_hex("XorKey", rich_header.xor_key); - for entry in rich_header.unmasked_entries() { - p.group("RichHeaderEntry", |p| { - p.field("ComponentId", format!("0x{:08X}", entry.comp_id)); - p.field("Count", entry.count); - }); - } - }); - } + print_rich(p, data, offset); if let Some((nt_headers, data_directories)) = Pe::parse(data, &mut offset).print_err(p) { - p.group("ImageNtHeaders", |p| { - p.field_hex("Signature", nt_headers.signature()); - }); + if p.options.file { + p.group("ImageNtHeaders", |p| { + p.field_hex("Signature", nt_headers.signature()); + }); + } let header = nt_headers.file_header(); let machine = header.machine.get(LE); let sections = header.sections(data, offset).print_err(p); let symbols = header.symbols(data).print_err(p); print_file(p, header); print_optional(p, nt_headers.optional_header()); - for (index, dir) in data_directories.iter().enumerate() { - p.group("ImageDataDirectory", |p| { - p.field_enum("Index", index, FLAGS_IMAGE_DIRECTORY_ENTRY); - p.field_hex("VirtualAddress", dir.virtual_address.get(LE)); - p.field_hex("Size", dir.size.get(LE)); - }); - } + print_data_directories(p, &data_directories); if let Some(ref sections) = sections { print_sections(p, data, machine, symbols.as_ref(), sections); } @@ -142,7 +111,54 @@ fn print_pe(p: &mut Printer<'_>, data: &[u8]) { } } +fn print_dos(p: &mut Printer<'_>, dos_header: &ImageDosHeader) { + if !p.options.file { + return; + } + p.group("ImageDosHeader", |p| { + p.field_hex("Magic", dos_header.e_magic.get(LE)); + p.field_hex("CountBytesLastPage", dos_header.e_cblp.get(LE)); + p.field_hex("CountPages", dos_header.e_cp.get(LE)); + p.field_hex("CountRelocations", dos_header.e_crlc.get(LE)); + p.field_hex("CountHeaderParagraphs", dos_header.e_cparhdr.get(LE)); + p.field_hex("MinAllocParagraphs", dos_header.e_minalloc.get(LE)); + p.field_hex("MaxAllocParagraphs", dos_header.e_maxalloc.get(LE)); + p.field_hex("StackSegment", dos_header.e_ss.get(LE)); + p.field_hex("StackPointer", dos_header.e_sp.get(LE)); + p.field_hex("Checksum", dos_header.e_csum.get(LE)); + p.field_hex("InstructionPointer", dos_header.e_ip.get(LE)); + p.field_hex("CodeSegment", dos_header.e_cs.get(LE)); + p.field_hex("AddressOfRelocations", dos_header.e_lfarlc.get(LE)); + p.field_hex("OverlayNumber", dos_header.e_ovno.get(LE)); + p.field_hex("OemId", dos_header.e_oemid.get(LE)); + p.field_hex("OemInfo", dos_header.e_oeminfo.get(LE)); + p.field_hex("AddressOfNewHeader", dos_header.e_lfanew.get(LE)); + }); +} + +fn print_rich(p: &mut Printer<'_>, data: &[u8], offset: u64) { + if !p.options.pe_rich { + return; + } + if let Some(rich_header) = RichHeaderInfo::parse(data, offset) { + p.group("RichHeader", |p| { + p.field_hex("Offset", rich_header.offset); + p.field_hex("Length", rich_header.length); + p.field_hex("XorKey", rich_header.xor_key); + for entry in rich_header.unmasked_entries() { + p.group("RichHeaderEntry", |p| { + p.field("ComponentId", format!("0x{:08X}", entry.comp_id)); + p.field("Count", entry.count); + }); + } + }); + } +} + fn print_file(p: &mut Printer<'_>, header: &ImageFileHeader) { + if !p.options.file { + return; + } p.group("ImageFileHeader", |p| { p.field_enum("Machine", header.machine.get(LE), FLAGS_IMAGE_FILE_MACHINE); p.field("NumberOfSections", header.number_of_sections.get(LE)); @@ -162,6 +178,9 @@ fn print_file(p: &mut Printer<'_>, header: &ImageFileHeader) { } fn print_optional(p: &mut Printer<'_>, header: &impl ImageOptionalHeader) { + if !p.options.file { + return; + } p.group("ImageOptionalHeader", |p| { p.field_hex("Magic", header.magic()); p.field("MajorLinkerVersion", header.major_linker_version()); @@ -209,7 +228,23 @@ fn print_optional(p: &mut Printer<'_>, header: &impl ImageOptionalHeader) { }); } +fn print_data_directories(p: &mut Printer<'_>, data_directories: &DataDirectories) { + if !p.options.file { + return; + } + for (index, dir) in data_directories.iter().enumerate() { + p.group("ImageDataDirectory", |p| { + p.field_enum("Index", index, FLAGS_IMAGE_DIRECTORY_ENTRY); + p.field_hex("VirtualAddress", dir.virtual_address.get(LE)); + p.field_hex("Size", dir.size.get(LE)); + }); + } +} + fn print_bigobj(p: &mut Printer<'_>, header: &AnonObjectHeaderBigobj) { + if !p.options.file { + return; + } p.group("AnonObjectHeaderBigObj", |p| { p.field_hex("Signature1", header.sig1.get(LE)); p.field_hex("Signature2", header.sig2.get(LE)); @@ -252,6 +287,9 @@ fn print_export_dir( sections: &SectionTable, data_directories: &DataDirectories, ) -> Option<()> { + if !p.options.pe_exports { + return Some(()); + } let export_dir = data_directories .export_directory(data, sections) .print_err(p)??; @@ -328,6 +366,9 @@ fn print_import_dir( sections: &SectionTable, data_directories: &DataDirectories, ) -> Option<()> { + if !p.options.pe_imports { + return Some(()); + } let import_table = data_directories .import_table(data, sections) .print_err(p)??; @@ -396,6 +437,9 @@ fn print_delay_load_dir( sections: &SectionTable, data_directories: &DataDirectories, ) -> Option<()> { + if !p.options.pe_imports { + return Some(()); + } let import_table = data_directories .delay_load_import_table(data, sections) .print_err(p)??; @@ -452,6 +496,9 @@ fn print_resource_dir( sections: &SectionTable, data_directories: &DataDirectories, ) -> Option<()> { + if !p.options.pe_resources { + return Some(()); + } let directory = data_directories .resource_directory(data, sections) .print_err(p)??; @@ -530,7 +577,15 @@ fn print_sections<'data, Coff: CoffHeader>( symbols: Option<&SymbolTable<'data, &'data [u8], Coff>>, sections: &SectionTable, ) { + if !p.options.sections && !p.options.relocations { + return; + } for (index, section) in sections.iter().enumerate() { + if !p.options.sections + && !(p.options.relocations && section.number_of_relocations.get(LE) != 0) + { + continue; + } p.group("ImageSectionHeader", |p| { p.field("Index", index + 1); if let Some(name) = @@ -540,94 +595,110 @@ fn print_sections<'data, Coff: CoffHeader>( } else { p.field_inline_string("Name", section.raw_name()); } - p.field_hex("VirtualSize", section.virtual_size.get(LE)); - p.field_hex("VirtualAddress", section.virtual_address.get(LE)); - p.field_hex("SizeOfRawData", section.size_of_raw_data.get(LE)); - p.field_hex("PointerToRawData", section.pointer_to_raw_data.get(LE)); - p.field_hex( - "PointerToRelocations", - section.pointer_to_relocations.get(LE), - ); - p.field_hex( - "PointerToLinenumbers", - section.pointer_to_linenumbers.get(LE), - ); - p.field("NumberOfRelocations", section.number_of_relocations.get(LE)); - p.field("NumberOfLinenumbers", section.number_of_linenumbers.get(LE)); - p.field_hex("Characteristics", section.characteristics.get(LE)); - p.flags(section.characteristics.get(LE), 0, FLAGS_IMAGE_SCN); - // 0 means no alignment flag. - if section.characteristics.get(LE) & IMAGE_SCN_ALIGN_MASK != 0 { - p.flags( - section.characteristics.get(LE), - IMAGE_SCN_ALIGN_MASK, - FLAGS_IMAGE_SCN_ALIGN, + if p.options.sections { + p.field_hex("VirtualSize", section.virtual_size.get(LE)); + p.field_hex("VirtualAddress", section.virtual_address.get(LE)); + p.field_hex("SizeOfRawData", section.size_of_raw_data.get(LE)); + p.field_hex("PointerToRawData", section.pointer_to_raw_data.get(LE)); + p.field_hex( + "PointerToRelocations", + section.pointer_to_relocations.get(LE), ); - } - if let Some(relocations) = section.coff_relocations(data).print_err(p) { - for relocation in relocations { - p.group("ImageRelocation", |p| { - p.field_hex("VirtualAddress", relocation.virtual_address.get(LE)); - let index = relocation.symbol_table_index.get(LE); - let name = symbols.and_then(|symbols| { - symbols - .symbol(index as usize) - .and_then(|symbol| symbol.name(symbols.strings())) - .print_err(p) - }); - p.field_string_option("Symbol", index, name); - let proc = match machine { - IMAGE_FILE_MACHINE_I386 => FLAGS_IMAGE_REL_I386, - IMAGE_FILE_MACHINE_MIPS16 - | IMAGE_FILE_MACHINE_MIPSFPU - | IMAGE_FILE_MACHINE_MIPSFPU16 => FLAGS_IMAGE_REL_MIPS, - IMAGE_FILE_MACHINE_ALPHA | IMAGE_FILE_MACHINE_ALPHA64 => { - FLAGS_IMAGE_REL_ALPHA - } - IMAGE_FILE_MACHINE_POWERPC | IMAGE_FILE_MACHINE_POWERPCFP => { - FLAGS_IMAGE_REL_PPC - } - IMAGE_FILE_MACHINE_SH3 - | IMAGE_FILE_MACHINE_SH3DSP - | IMAGE_FILE_MACHINE_SH3E - | IMAGE_FILE_MACHINE_SH4 - | IMAGE_FILE_MACHINE_SH5 => FLAGS_IMAGE_REL_SH, - IMAGE_FILE_MACHINE_ARM => FLAGS_IMAGE_REL_ARM, - IMAGE_FILE_MACHINE_AM33 => FLAGS_IMAGE_REL_AM, - IMAGE_FILE_MACHINE_ARM64 => FLAGS_IMAGE_REL_ARM64, - IMAGE_FILE_MACHINE_AMD64 => FLAGS_IMAGE_REL_AMD64, - IMAGE_FILE_MACHINE_IA64 => FLAGS_IMAGE_REL_IA64, - IMAGE_FILE_MACHINE_CEF => FLAGS_IMAGE_REL_CEF, - IMAGE_FILE_MACHINE_CEE => FLAGS_IMAGE_REL_CEE, - IMAGE_FILE_MACHINE_M32R => FLAGS_IMAGE_REL_M32R, - IMAGE_FILE_MACHINE_EBC => FLAGS_IMAGE_REL_EBC, - _ => &[], - }; - let typ = relocation.typ.get(LE); - p.field_enum("Type", typ, proc); - match machine { - IMAGE_FILE_MACHINE_POWERPC | IMAGE_FILE_MACHINE_POWERPCFP => { - p.flags(typ, 0, FLAGS_IMAGE_REL_PPC_BITS) - } - IMAGE_FILE_MACHINE_SH3 - | IMAGE_FILE_MACHINE_SH3DSP - | IMAGE_FILE_MACHINE_SH3E - | IMAGE_FILE_MACHINE_SH4 - | IMAGE_FILE_MACHINE_SH5 => p.flags(typ, 0, FLAGS_IMAGE_REL_SH_BITS), - _ => {} - } - }); + p.field_hex( + "PointerToLinenumbers", + section.pointer_to_linenumbers.get(LE), + ); + p.field("NumberOfRelocations", section.number_of_relocations.get(LE)); + p.field("NumberOfLinenumbers", section.number_of_linenumbers.get(LE)); + p.field_hex("Characteristics", section.characteristics.get(LE)); + p.flags(section.characteristics.get(LE), 0, FLAGS_IMAGE_SCN); + // 0 means no alignment flag. + if section.characteristics.get(LE) & IMAGE_SCN_ALIGN_MASK != 0 { + p.flags( + section.characteristics.get(LE), + IMAGE_SCN_ALIGN_MASK, + FLAGS_IMAGE_SCN_ALIGN, + ); } } + print_relocations(p, data, machine, symbols, section); }); } } +fn print_relocations<'data, Coff: CoffHeader>( + p: &mut Printer<'_>, + data: &[u8], + machine: u16, + symbols: Option<&SymbolTable<'data, &'data [u8], Coff>>, + section: &ImageSectionHeader, +) { + if !p.options.relocations { + return; + } + if let Some(relocations) = section.coff_relocations(data).print_err(p) { + for relocation in relocations { + p.group("ImageRelocation", |p| { + p.field_hex("VirtualAddress", relocation.virtual_address.get(LE)); + let index = relocation.symbol_table_index.get(LE); + let name = symbols.and_then(|symbols| { + symbols + .symbol(index as usize) + .and_then(|symbol| symbol.name(symbols.strings())) + .print_err(p) + }); + p.field_string_option("Symbol", index, name); + let proc = match machine { + IMAGE_FILE_MACHINE_I386 => FLAGS_IMAGE_REL_I386, + IMAGE_FILE_MACHINE_MIPS16 + | IMAGE_FILE_MACHINE_MIPSFPU + | IMAGE_FILE_MACHINE_MIPSFPU16 => FLAGS_IMAGE_REL_MIPS, + IMAGE_FILE_MACHINE_ALPHA | IMAGE_FILE_MACHINE_ALPHA64 => FLAGS_IMAGE_REL_ALPHA, + IMAGE_FILE_MACHINE_POWERPC | IMAGE_FILE_MACHINE_POWERPCFP => { + FLAGS_IMAGE_REL_PPC + } + IMAGE_FILE_MACHINE_SH3 + | IMAGE_FILE_MACHINE_SH3DSP + | IMAGE_FILE_MACHINE_SH3E + | IMAGE_FILE_MACHINE_SH4 + | IMAGE_FILE_MACHINE_SH5 => FLAGS_IMAGE_REL_SH, + IMAGE_FILE_MACHINE_ARM => FLAGS_IMAGE_REL_ARM, + IMAGE_FILE_MACHINE_AM33 => FLAGS_IMAGE_REL_AM, + IMAGE_FILE_MACHINE_ARM64 => FLAGS_IMAGE_REL_ARM64, + IMAGE_FILE_MACHINE_AMD64 => FLAGS_IMAGE_REL_AMD64, + IMAGE_FILE_MACHINE_IA64 => FLAGS_IMAGE_REL_IA64, + IMAGE_FILE_MACHINE_CEF => FLAGS_IMAGE_REL_CEF, + IMAGE_FILE_MACHINE_CEE => FLAGS_IMAGE_REL_CEE, + IMAGE_FILE_MACHINE_M32R => FLAGS_IMAGE_REL_M32R, + IMAGE_FILE_MACHINE_EBC => FLAGS_IMAGE_REL_EBC, + _ => &[], + }; + let typ = relocation.typ.get(LE); + p.field_enum("Type", typ, proc); + match machine { + IMAGE_FILE_MACHINE_POWERPC | IMAGE_FILE_MACHINE_POWERPCFP => { + p.flags(typ, 0, FLAGS_IMAGE_REL_PPC_BITS) + } + IMAGE_FILE_MACHINE_SH3 + | IMAGE_FILE_MACHINE_SH3DSP + | IMAGE_FILE_MACHINE_SH3E + | IMAGE_FILE_MACHINE_SH4 + | IMAGE_FILE_MACHINE_SH5 => p.flags(typ, 0, FLAGS_IMAGE_REL_SH_BITS), + _ => {} + } + }); + } + } +} + fn print_symbols<'data, Coff: CoffHeader>( p: &mut Printer<'_>, sections: Option<&SectionTable>, symbols: &SymbolTable<'data, &'data [u8], Coff>, ) { + if !p.options.symbols { + return; + } for (index, symbol) in symbols.iter() { p.group("ImageSymbol", |p| { p.field("Index", index); @@ -707,6 +778,9 @@ fn print_reloc_dir( sections: &SectionTable, data_directories: &DataDirectories, ) -> Option<()> { + if !p.options.pe_base_relocs { + return Some(()); + } let proc = match machine { IMAGE_FILE_MACHINE_IA64 => FLAGS_IMAGE_REL_IA64_BASED, IMAGE_FILE_MACHINE_MIPS16 | IMAGE_FILE_MACHINE_MIPSFPU | IMAGE_FILE_MACHINE_MIPSFPU16 => { diff --git a/crates/examples/src/readobj/xcoff.rs b/crates/examples/src/readobj/xcoff.rs index 62cfd65f..c8d6f49f 100644 --- a/crates/examples/src/readobj/xcoff.rs +++ b/crates/examples/src/readobj/xcoff.rs @@ -25,53 +25,12 @@ fn print_xcoff( data: &[u8], mut offset: u64, ) { - p.group("FileHeader", |p| { - p.field_hex("Magic", header.f_magic()); - p.field("NumberOfSections", header.f_nscns()); - p.field_hex("TimeDate", header.f_timdat()); - p.field_hex("SymbolPointer", header.f_symptr().into()); - p.field("NumberOfSymbols", header.f_nsyms()); - p.field_hex("SizeOfOptionalHeader", header.f_opthdr()); - p.field_hex("Flags", header.f_flags()); - p.flags(header.f_flags(), 0, FLAGS_F); - }); + print_file_header(p, header); if let Some(aux_header) = header.aux_header(data, &mut offset).print_err(p) { let sections = header.sections(data, &mut offset).print_err(p); let symbols = header.symbols(data).print_err(p); if let Some(aux_header) = aux_header { - p.group("AuxHeader", |p| { - p.field_hex("Magic", aux_header.o_mflag()); - p.field_hex("Version", aux_header.o_vstamp()); - p.field_hex("TextSize", aux_header.o_tsize().into()); - p.field_hex("DataSize", aux_header.o_dsize().into()); - p.field_hex("UninitializedDataSize", aux_header.o_bsize().into()); - p.field_hex("EntryAddress", aux_header.o_entry().into()); - p.field_hex("TextAddress", aux_header.o_text_start().into()); - p.field_hex("DataAddress", aux_header.o_data_start().into()); - p.field_hex("TocAddress", aux_header.o_toc().into()); - p.field("EntrySectionNumber", aux_header.o_snentry()); - p.field("TextSectionNumber", aux_header.o_sntext()); - p.field("DataSectionNumber", aux_header.o_sndata()); - p.field("TocSectionNumber", aux_header.o_sntoc()); - p.field("LoaderSectionNumber", aux_header.o_snloader()); - p.field_hex("TextAlignment", aux_header.o_algntext()); - p.field_hex("DataAlignment", aux_header.o_algndata()); - p.field_hex("ModuleType", aux_header.o_modtype()); - p.field_hex("CpuFlags", aux_header.o_cpuflag()); - p.field_hex("CpuType", aux_header.o_cputype()); - p.field_hex("MaximumStack", aux_header.o_maxstack().into()); - p.field_hex("MaximumData", aux_header.o_maxdata().into()); - p.field_hex("Debugger", aux_header.o_debugger()); - p.field_hex("TextPageSize", aux_header.o_textpsize()); - p.field_hex("DataPageSize", aux_header.o_datapsize()); - p.field_hex("StackPageSize", aux_header.o_stackpsize()); - p.field_hex("Flags", aux_header.o_flags()); - p.field("TlsDataSectionNumber", aux_header.o_sntdata()); - p.field("TlsUninitializedDataSectionNumber", aux_header.o_snbss()); - if let Some(x64flags) = aux_header.o_x64flags() { - p.field_hex("Flags64", x64flags); - } - }); + print_aux_header(p, aux_header); } if let Some(ref sections) = sections { print_sections(p, data, symbols.as_ref(), sections); @@ -82,12 +41,70 @@ fn print_xcoff( } } +fn print_file_header<'data, Xcoff: FileHeader>(p: &mut Printer<'_>, header: &Xcoff) { + if !p.options.file { + return; + } + p.group("FileHeader", |p| { + p.field_hex("Magic", header.f_magic()); + p.field("NumberOfSections", header.f_nscns()); + p.field_hex("TimeDate", header.f_timdat()); + p.field_hex("SymbolPointer", header.f_symptr().into()); + p.field("NumberOfSymbols", header.f_nsyms()); + p.field_hex("SizeOfOptionalHeader", header.f_opthdr()); + p.field_hex("Flags", header.f_flags()); + p.flags(header.f_flags(), 0, FLAGS_F); + }); +} + +fn print_aux_header<'data, Header: AuxHeader>(p: &mut Printer<'_>, aux_header: &Header) { + if !p.options.file { + return; + } + p.group("AuxHeader", |p| { + p.field_hex("Magic", aux_header.o_mflag()); + p.field_hex("Version", aux_header.o_vstamp()); + p.field_hex("TextSize", aux_header.o_tsize().into()); + p.field_hex("DataSize", aux_header.o_dsize().into()); + p.field_hex("UninitializedDataSize", aux_header.o_bsize().into()); + p.field_hex("EntryAddress", aux_header.o_entry().into()); + p.field_hex("TextAddress", aux_header.o_text_start().into()); + p.field_hex("DataAddress", aux_header.o_data_start().into()); + p.field_hex("TocAddress", aux_header.o_toc().into()); + p.field("EntrySectionNumber", aux_header.o_snentry()); + p.field("TextSectionNumber", aux_header.o_sntext()); + p.field("DataSectionNumber", aux_header.o_sndata()); + p.field("TocSectionNumber", aux_header.o_sntoc()); + p.field("LoaderSectionNumber", aux_header.o_snloader()); + p.field_hex("TextAlignment", aux_header.o_algntext()); + p.field_hex("DataAlignment", aux_header.o_algndata()); + p.field_hex("ModuleType", aux_header.o_modtype()); + p.field_hex("CpuFlags", aux_header.o_cpuflag()); + p.field_hex("CpuType", aux_header.o_cputype()); + p.field_hex("MaximumStack", aux_header.o_maxstack().into()); + p.field_hex("MaximumData", aux_header.o_maxdata().into()); + p.field_hex("Debugger", aux_header.o_debugger()); + p.field_hex("TextPageSize", aux_header.o_textpsize()); + p.field_hex("DataPageSize", aux_header.o_datapsize()); + p.field_hex("StackPageSize", aux_header.o_stackpsize()); + p.field_hex("Flags", aux_header.o_flags()); + p.field("TlsDataSectionNumber", aux_header.o_sntdata()); + p.field("TlsUninitializedDataSectionNumber", aux_header.o_snbss()); + if let Some(x64flags) = aux_header.o_x64flags() { + p.field_hex("Flags64", x64flags); + } + }); +} + fn print_sections<'data, Xcoff: FileHeader>( p: &mut Printer<'_>, data: &[u8], symbols: Option<&SymbolTable<'data, Xcoff>>, sections: &SectionTable<'data, Xcoff>, ) { + if !p.options.sections { + return; + } for (index, section) in sections.iter().enumerate() { p.group("SectionHeader", |p| { p.field("Index", index + 1); @@ -131,6 +148,9 @@ fn print_symbols<'data, Xcoff: FileHeader>( sections: Option<&SectionTable<'data, Xcoff>>, symbols: &SymbolTable<'data, Xcoff>, ) { + if !p.options.symbols { + return; + } for (index, symbol) in symbols.iter() { p.group("Symbol", |p| { p.field("Index", index.0); diff --git a/crates/examples/tests/testfiles.rs b/crates/examples/tests/testfiles.rs index fcae8df5..7d5c68bb 100644 --- a/crates/examples/tests/testfiles.rs +++ b/crates/examples/tests/testfiles.rs @@ -54,13 +54,15 @@ fn testfiles() { fail |= testfile(update, path, &data, "objdump", |mut out, mut err, data| { objdump::print(&mut out, &mut err, data, &[], vec![]).unwrap() }); - fail |= testfile(update, path, &data, "readobj", readobj::print); + fail |= testfile(update, path, &data, "readobj", |out, err, data| { + readobj::print(out, err, data, &readobj::PrintOptions::all()) + }); #[cfg(feature = "write")] { fail |= testfile(update, path, &data, "objcopy", |out, err, in_data| { let out_data = objcopy::copy(in_data); - readobj::print(out, err, &out_data) + readobj::print(out, err, &out_data, &readobj::PrintOptions::all()) }); } println!();