mirror of
https://git.proxmox.com/git/rustc
synced 2026-01-01 17:44:55 +00:00
231 lines
7.0 KiB
Rust
231 lines
7.0 KiB
Rust
use object::read::archive::ArchiveFile;
|
|
use object::read::macho::{DyldCache, FatArch, FatHeader};
|
|
use object::{Endianness, Object, ObjectComdat, ObjectSection, ObjectSymbol};
|
|
use std::{env, fs, process};
|
|
|
|
fn main() {
|
|
let mut args = env::args();
|
|
let cmd = args.next().unwrap();
|
|
if args.len() == 0 {
|
|
eprintln!("Usage: {} <file> [<member>...]", cmd);
|
|
process::exit(1);
|
|
}
|
|
let file_path = args.next().unwrap();
|
|
let mut member_names: Vec<_> = args.map(|name| (name, false)).collect();
|
|
|
|
let file = match fs::File::open(&file_path) {
|
|
Ok(file) => file,
|
|
Err(err) => {
|
|
eprintln!("Failed to open file '{}': {}", file_path, err,);
|
|
process::exit(1);
|
|
}
|
|
};
|
|
let file = match unsafe { memmap2::Mmap::map(&file) } {
|
|
Ok(mmap) => mmap,
|
|
Err(err) => {
|
|
eprintln!("Failed to map file '{}': {}", file_path, err,);
|
|
process::exit(1);
|
|
}
|
|
};
|
|
|
|
if let Ok(archive) = ArchiveFile::parse(&*file) {
|
|
eprintln!("Format: Archive (kind: {:?})", archive.kind());
|
|
for member in archive.members() {
|
|
if let Ok(member) = member {
|
|
if find_member(&mut member_names, member.name()) {
|
|
println!();
|
|
println!("{}:", String::from_utf8_lossy(member.name()));
|
|
if let Ok(data) = member.data(&*file) {
|
|
dump_object(data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if let Ok(arches) = FatHeader::parse_arch32(&*file) {
|
|
println!("Format: Mach-O Fat 32");
|
|
for arch in arches {
|
|
println!();
|
|
println!("Fat Arch: {:?}", arch.architecture());
|
|
if let Ok(data) = arch.data(&*file) {
|
|
dump_object(data);
|
|
}
|
|
}
|
|
} else if let Ok(arches) = FatHeader::parse_arch64(&*file) {
|
|
println!("Format: Mach-O Fat 64");
|
|
for arch in arches {
|
|
println!();
|
|
println!("Fat Arch: {:?}", arch.architecture());
|
|
if let Ok(data) = arch.data(&*file) {
|
|
dump_object(data);
|
|
}
|
|
}
|
|
} else if let Ok(cache) = DyldCache::<Endianness>::parse(&*file) {
|
|
println!("Format: dyld cache {:?}-endian", cache.endianness());
|
|
println!("Architecture: {:?}", cache.architecture());
|
|
for image in cache.images() {
|
|
if let Ok(path) = image.path() {
|
|
if find_member(&mut member_names, path.as_bytes()) {
|
|
println!();
|
|
println!("{}:", path);
|
|
let file = match image.parse_object() {
|
|
Ok(file) => file,
|
|
Err(err) => {
|
|
eprintln!("Failed to parse file: {}", err);
|
|
continue;
|
|
}
|
|
};
|
|
dump_parsed_object(&file);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
dump_object(&*file);
|
|
}
|
|
|
|
for (name, found) in member_names {
|
|
if !found {
|
|
eprintln!("Failed to find member '{}", name);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn find_member(member_names: &mut [(String, bool)], name: &[u8]) -> bool {
|
|
if member_names.is_empty() {
|
|
return true;
|
|
}
|
|
match member_names.iter().position(|x| x.0.as_bytes() == name) {
|
|
Some(i) => {
|
|
member_names[i].1 = true;
|
|
true
|
|
}
|
|
None => false,
|
|
}
|
|
}
|
|
|
|
fn dump_object(data: &[u8]) {
|
|
let file = match object::File::parse(data) {
|
|
Ok(file) => file,
|
|
Err(err) => {
|
|
println!("Failed to parse file: {}", err);
|
|
return;
|
|
}
|
|
};
|
|
dump_parsed_object(&file);
|
|
}
|
|
|
|
fn dump_parsed_object(file: &object::File) {
|
|
println!(
|
|
"Format: {:?} {:?}-endian {}-bit",
|
|
file.format(),
|
|
file.endianness(),
|
|
if file.is_64() { "64" } else { "32" }
|
|
);
|
|
println!("Architecture: {:?}", file.architecture());
|
|
println!("Flags: {:x?}", file.flags());
|
|
println!("Relative Address Base: {:x?}", file.relative_address_base());
|
|
println!("Entry Address: {:x?}", file.entry());
|
|
|
|
match file.mach_uuid() {
|
|
Ok(Some(uuid)) => println!("Mach UUID: {:x?}", uuid),
|
|
Ok(None) => {}
|
|
Err(e) => println!("Failed to parse Mach UUID: {}", e),
|
|
}
|
|
match file.build_id() {
|
|
Ok(Some(build_id)) => println!("Build ID: {:x?}", build_id),
|
|
Ok(None) => {}
|
|
Err(e) => println!("Failed to parse build ID: {}", e),
|
|
}
|
|
match file.gnu_debuglink() {
|
|
Ok(Some((filename, crc))) => println!(
|
|
"GNU debug link: {} CRC: {:08x}",
|
|
String::from_utf8_lossy(filename),
|
|
crc,
|
|
),
|
|
Ok(None) => {}
|
|
Err(e) => println!("Failed to parse GNU debug link: {}", e),
|
|
}
|
|
match file.gnu_debugaltlink() {
|
|
Ok(Some((filename, build_id))) => println!(
|
|
"GNU debug alt link: {}, build ID: {:x?}",
|
|
String::from_utf8_lossy(filename),
|
|
build_id,
|
|
),
|
|
Ok(None) => {}
|
|
Err(e) => println!("Failed to parse GNU debug alt link: {}", e),
|
|
}
|
|
match file.pdb_info() {
|
|
Ok(Some(info)) => println!(
|
|
"PDB file: {}, GUID: {:x?}, Age: {}",
|
|
String::from_utf8_lossy(info.path()),
|
|
info.guid(),
|
|
info.age()
|
|
),
|
|
Ok(None) => {}
|
|
Err(e) => println!("Failed to parse PE CodeView info: {}", e),
|
|
}
|
|
|
|
for segment in file.segments() {
|
|
println!("{:x?}", segment);
|
|
}
|
|
|
|
for section in file.sections() {
|
|
println!("{}: {:x?}", section.index().0, section);
|
|
}
|
|
|
|
for comdat in file.comdats() {
|
|
print!("{:?} Sections:", comdat);
|
|
for section in comdat.sections() {
|
|
print!(" {}", section.0);
|
|
}
|
|
println!();
|
|
}
|
|
|
|
println!();
|
|
println!("Symbols");
|
|
for symbol in file.symbols() {
|
|
println!("{}: {:x?}", symbol.index().0, symbol);
|
|
}
|
|
|
|
for section in file.sections() {
|
|
if section.relocations().next().is_some() {
|
|
println!(
|
|
"\n{} relocations",
|
|
section.name().unwrap_or("<invalid name>")
|
|
);
|
|
for relocation in section.relocations() {
|
|
println!("{:x?}", relocation);
|
|
}
|
|
}
|
|
}
|
|
|
|
println!();
|
|
println!("Dynamic symbols");
|
|
for symbol in file.dynamic_symbols() {
|
|
println!("{}: {:x?}", symbol.index().0, symbol);
|
|
}
|
|
|
|
if let Some(relocations) = file.dynamic_relocations() {
|
|
println!();
|
|
println!("Dynamic relocations");
|
|
for relocation in relocations {
|
|
println!("{:x?}", relocation);
|
|
}
|
|
}
|
|
|
|
let imports = file.imports().unwrap();
|
|
if !imports.is_empty() {
|
|
println!();
|
|
for import in imports {
|
|
println!("{:?}", import);
|
|
}
|
|
}
|
|
|
|
let exports = file.exports().unwrap();
|
|
if !exports.is_empty() {
|
|
println!();
|
|
for export in exports {
|
|
println!("{:x?}", export);
|
|
}
|
|
}
|
|
}
|