This commit is contained in:
nora 2023-02-21 12:24:53 +01:00
parent d849e07c58
commit e8195f32f6
3 changed files with 149 additions and 111 deletions

5
Cargo.lock generated
View file

@ -66,9 +66,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.1.4" version = "4.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"clap_derive", "clap_derive",
@ -106,6 +106,7 @@ name = "elven-forest"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap",
"elven-parser", "elven-parser",
"memmap2", "memmap2",
"tabled", "tabled",

View file

@ -7,6 +7,7 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.69" anyhow = "1.0.69"
clap = { version = "4.1.6", features = ["derive"] }
elven-parser = { path = "../elven-parser" } elven-parser = { path = "../elven-parser" }
memmap2 = "0.5.8" memmap2 = "0.5.8"
tabled = "0.10.0" tabled = "0.10.0"

View file

@ -1,6 +1,11 @@
use std::{fmt::Display, fs::File}; use std::{
fmt::Display,
fs::File,
path::{Path, PathBuf},
};
use anyhow::Context; use anyhow::Context;
use clap::Parser;
use elven_parser::{ use elven_parser::{
consts::{self as c, DynamicTag, PhFlags, PhType, ShFlags, ShType, SymbolVisibility, RX86_64}, consts::{self as c, DynamicTag, PhFlags, PhType, ShFlags, ShType, SymbolVisibility, RX86_64},
read::{ElfReadError, ElfReader, Sym, SymInfo}, read::{ElfReadError, ElfReader, Sym, SymInfo},
@ -9,11 +14,29 @@ use elven_parser::{
use memmap2::Mmap; use memmap2::Mmap;
use tabled::{object::Rows, Disable, Style, Table, Tabled}; use tabled::{object::Rows, Disable, Style, Table, Tabled};
fn main() -> anyhow::Result<()> { #[derive(Parser)]
let objs = std::env::args().skip(1); struct Opts {
#[arg(long("file-header"), long("header"))]
header: bool,
#[arg(short('l'), long("program-headers"), long("segments"))]
program_headers: bool,
#[arg(short('S'), long("section-headers"), long("sections"))]
section_headers: bool,
#[arg(short('s'), long("symbols"), long("syms"))]
symbols: bool,
#[arg(short('r'), long("relocs"))]
relocs: bool,
/// Not in readelf.
#[arg(short('d'), long("dyns"))]
dyns: bool,
files: Vec<PathBuf>,
}
for obj in objs { fn main() -> anyhow::Result<()> {
print_file(&obj).with_context(|| format!("Failed to print {obj}"))?; let opts = Opts::parse();
for obj in &opts.files {
print_file(&opts, obj).with_context(|| format!("Failed to print {}", obj.display()))?;
} }
Ok(()) Ok(())
@ -76,142 +99,155 @@ struct DynTable {
value: Addr, value: Addr,
} }
fn print_file(path: &str) -> anyhow::Result<()> { fn print_file(opts: &Opts, path: &Path) -> anyhow::Result<()> {
println!("{path}"); println!("{}", path.display());
let file = File::open(path)?; let file = File::open(path)?;
let mmap = unsafe { Mmap::map(&file) }?; let mmap = unsafe { Mmap::map(&file) }?;
let elf = ElfReader::new(&mmap)?; let elf = ElfReader::new(&mmap)?;
println!("\nHeader"); if opts.header {
println!("\nHeader");
let header = elf.header()?; let header = elf.header()?;
let ident = header.ident; let ident = header.ident;
let header_tab = vec![ let header_tab = vec![
HeaderTable("class", &ident.class), HeaderTable("class", &ident.class),
HeaderTable("data", &ident.data), HeaderTable("data", &ident.data),
HeaderTable("version", &ident.version), HeaderTable("version", &ident.version),
HeaderTable("osabi", &ident.osabi), HeaderTable("osabi", &ident.osabi),
HeaderTable("type", &header.r#type), HeaderTable("type", &header.r#type),
HeaderTable("machine", &header.machine), HeaderTable("machine", &header.machine),
HeaderTable("entrypoint", &header.entry), HeaderTable("entrypoint", &header.entry),
HeaderTable("header size", &header.ehsize), HeaderTable("header size", &header.ehsize),
HeaderTable("program header size", &header.phentsize), HeaderTable("program header size", &header.phentsize),
HeaderTable("section header size", &header.shentsize), HeaderTable("section header size", &header.shentsize),
]; ];
let mut table = Table::new(header_tab); let mut table = Table::new(header_tab);
// No header // No header
table.with(Disable::row(Rows::first())); table.with(Disable::row(Rows::first()));
print_table(table); print_table(table);
}
println!("\nSections"); if opts.section_headers {
println!("\nSections");
let sections = elf let sections = elf
.section_headers()? .section_headers()?
.iter() .iter()
.map(|sh| { .map(|sh| {
let name = elf.sh_string(sh.name)?.to_string(); let name = elf.sh_string(sh.name)?.to_string();
Ok(SectionTable { Ok(SectionTable {
name, name,
r#type: sh.r#type, r#type: sh.r#type,
size: Addr(sh.size), size: Addr(sh.size),
offset: sh.offset, offset: sh.offset,
flags: sh.flags, flags: sh.flags,
})
}) })
}) .collect::<Result<Vec<_>, ElfReadError>>()?;
.collect::<Result<Vec<_>, ElfReadError>>()?;
print_table(Table::new(sections)); print_table(Table::new(sections));
}
println!("\nProgram headers"); if opts.program_headers {
println!("\nProgram headers");
let sections = elf let sections = elf
.program_headers()? .program_headers()?
.iter() .iter()
.map(|ph| { .map(|ph| {
let (inside_section, inside_section_offset) = section_name_of_offset(elf, ph.offset)?; let (inside_section, inside_section_offset) =
section_name_of_offset(elf, ph.offset)?;
Ok(ProgramHeaderTable { Ok(ProgramHeaderTable {
r#type: ph.r#type, r#type: ph.r#type,
flags: ph.flags, flags: ph.flags,
offset: ph.offset, offset: ph.offset,
virtual_addr: ph.vaddr, virtual_addr: ph.vaddr,
phys_addr: ph.paddr, phys_addr: ph.paddr,
file_size: Addr(ph.filesz), file_size: Addr(ph.filesz),
mem_size: Addr(ph.memsz), mem_size: Addr(ph.memsz),
align: Addr(ph.align), align: Addr(ph.align),
inside_section, inside_section,
inside_section_offset, inside_section_offset,
})
}) })
}) .collect::<Result<Vec<_>, ElfReadError>>()?;
.collect::<Result<Vec<_>, ElfReadError>>()?;
print_table(Table::new(sections)); print_table(Table::new(sections));
}
println!("\nSymbols"); if opts.symbols {
println!("\nSymbols");
let symbols = elf let symbols = elf
.symbols()? .symbols()?
.iter() .iter()
.map(|sym| { .map(|sym| {
let name = sym_display_name(elf, sym)?; let name = sym_display_name(elf, sym)?;
let section = match sym.shndx.0 { let section = match sym.shndx.0 {
c::SHN_ABS | c::SHN_COMMON => String::new(), c::SHN_ABS | c::SHN_COMMON => String::new(),
_ => elf _ => elf
.sh_string(elf.section_header(sym.shndx)?.name)? .sh_string(elf.section_header(sym.shndx)?.name)?
.to_string(), .to_string(),
}; };
Ok(SymbolTable { Ok(SymbolTable {
name, name,
info: sym.info, info: sym.info,
other: sym.other, other: sym.other,
section, section,
size: sym.size, size: sym.size,
value: sym.value, value: sym.value,
})
}) })
}) .collect::<Result<Vec<_>, ElfReadError>>()?;
.collect::<Result<Vec<_>, ElfReadError>>()?;
print_table(Table::new(symbols)); print_table(Table::new(symbols));
}
println!("\nRelocations"); if opts.relocs {
println!("\nRelocations");
let relas = elf let relas = elf
.relas()? .relas()?
.map(|(sh, rela)| { .map(|(sh, rela)| {
let section = elf.sh_string(sh.name)?.to_string(); let section = elf.sh_string(sh.name)?.to_string();
let sym = elf.symbol(rela.info.sym())?; let sym = elf.symbol(rela.info.sym())?;
let symbol = sym_display_name(elf, sym)?; let symbol = sym_display_name(elf, sym)?;
let offset = rela.offset; let offset = rela.offset;
let r#type = c::RX86_64(rela.info.r#type()); let r#type = c::RX86_64(rela.info.r#type());
let addend = rela.addend; let addend = rela.addend;
Ok(RelaTable { Ok(RelaTable {
section, section,
symbol, symbol,
offset, offset,
r#type, r#type,
addend, addend,
})
}) })
}) .collect::<Result<Vec<_>, ElfReadError>>()?;
.collect::<Result<Vec<_>, ElfReadError>>()?;
print_table(Table::new(relas)); print_table(Table::new(relas));
}
if let Ok(dyns) = elf.dyn_entries() { if opts.dyns {
println!("\nDynamic entries"); if let Ok(dyns) = elf.dyn_entries() {
println!("\nDynamic entries");
let dyns = dyns.iter().map(|dy| DynTable { let dyns = dyns.iter().map(|dy| DynTable {
tag: dy.tag, tag: dy.tag,
value: Addr(dy.val), value: Addr(dy.val),
}); });
print_table(Table::new(dyns)); print_table(Table::new(dyns));
}
} }
println!(); println!();