Skip to content

Commit

Permalink
readobj: add command line options (#625)
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc committed Jan 27, 2024
1 parent 8a7a9b6 commit 567edaf
Show file tree
Hide file tree
Showing 9 changed files with 745 additions and 303 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions crates/examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version = "0.0.0"
edition = "2018"

[dependencies]
clap = "4.3.24"
memmap2 = "0.7.1"
object = { path = "../..", default-features = false }

Expand Down
147 changes: 136 additions & 11 deletions crates/examples/src/bin/readobj.rs
Original file line number Diff line number Diff line change
@@ -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: {} <file> ...", 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::<PathBuf>("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);
}
}
66 changes: 64 additions & 2 deletions crates/examples/src/readobj/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ fn print_elf<Elf: FileHeader<Endian = Endianness>>(p: &mut Printer<'_>, elf: &El
}

fn print_file_header<Elf: FileHeader>(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);
Expand Down Expand Up @@ -113,6 +116,13 @@ fn print_program_headers<Elf: FileHeader>(
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,
Expand Down Expand Up @@ -175,6 +185,9 @@ fn print_segment_notes<Elf: FileHeader>(
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);
}
Expand All @@ -188,6 +201,9 @@ fn print_segment_dynamic<Elf: FileHeader>(
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;
Expand Down Expand Up @@ -221,6 +237,21 @@ fn print_section_headers<Elf: FileHeader>(
sections: &SectionTable<Elf>,
) {
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);
Expand Down Expand Up @@ -272,8 +303,15 @@ fn print_section_headers<Elf: FileHeader>(
}

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),
Expand Down Expand Up @@ -396,6 +434,9 @@ fn print_section_rel<Elf: FileHeader>(
sections: &SectionTable<Elf>,
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)
Expand All @@ -420,6 +461,9 @@ fn print_section_rela<Elf: FileHeader>(
sections: &SectionTable<Elf>,
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)
Expand Down Expand Up @@ -500,6 +544,9 @@ fn print_section_notes<Elf: FileHeader>(
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);
}
Expand All @@ -513,6 +560,9 @@ fn print_section_dynamic<Elf: FileHeader>(
sections: &SectionTable<Elf>,
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);
Expand Down Expand Up @@ -756,6 +806,9 @@ fn print_gnu_verdef<Elf: FileHeader>(
sections: &SectionTable<Elf>,
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) {
Expand Down Expand Up @@ -791,6 +844,9 @@ fn print_gnu_verneed<Elf: FileHeader>(
sections: &SectionTable<Elf>,
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) {
Expand Down Expand Up @@ -831,6 +887,9 @@ fn print_gnu_versym<Elf: FileHeader>(
sections: &SectionTable<Elf>,
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() {
Expand All @@ -850,6 +909,9 @@ fn print_attributes<Elf: FileHeader>(
_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());
Expand Down
Loading

0 comments on commit 567edaf

Please sign in to comment.