forked from mirrors/gecko-dev
Depends on D45046 Differential Revision: https://phabricator.services.mozilla.com/D45047 --HG-- rename : third_party/rust/goblin/src/elf/dyn.rs => third_party/rust/goblin/src/elf/dynamic.rs rename : third_party/rust/object/src/lib.rs => third_party/rust/object/src/read/any.rs rename : third_party/rust/object/src/pe.rs => third_party/rust/object/src/read/pe.rs rename : third_party/rust/object/src/wasm.rs => third_party/rust/object/src/read/wasm.rs extra : moz-landing-system : lando
162 lines
4.8 KiB
Rust
162 lines
4.8 KiB
Rust
use goblin::mach;
|
|
use std::env;
|
|
use std::process;
|
|
use std::path::Path;
|
|
use std::fs::File;
|
|
use std::io::Read;
|
|
use std::borrow::Cow;
|
|
|
|
fn usage() -> ! {
|
|
println!("usage: dyldinfo <options> <mach-o file>");
|
|
println!(" -bind print binds as seen by macho::imports()");
|
|
println!(" -lazy_bind print lazy binds as seen by macho::imports()");
|
|
process::exit(1);
|
|
}
|
|
|
|
fn name_to_str(name: &[u8; 16]) -> Cow<'_, str> {
|
|
for i in 0..16 {
|
|
if name[i] == 0 {
|
|
return String::from_utf8_lossy(&name[0..i])
|
|
}
|
|
}
|
|
String::from_utf8_lossy(&name[..])
|
|
}
|
|
|
|
fn dylib_name(name: &str) -> &str {
|
|
// observed behavior:
|
|
// "/usr/lib/libc++.1.dylib" => "libc++"
|
|
// "/usr/lib/libSystem.B.dylib" => "libSystem"
|
|
// "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" => "CoreFoundation"
|
|
name
|
|
.rsplit('/').next().unwrap()
|
|
.split('.').next().unwrap()
|
|
}
|
|
|
|
fn print_binds(sections: &[mach::segment::Section], imports: &[mach::imports::Import]) {
|
|
println!("bind information:");
|
|
|
|
println!(
|
|
"{:7} {:16} {:14} {:7} {:6} {:16} symbol",
|
|
"segment",
|
|
"section",
|
|
"address",
|
|
"type",
|
|
"addend",
|
|
"dylib",
|
|
);
|
|
|
|
for import in imports.iter().filter(|i| !i.is_lazy) {
|
|
// find the section that imported this symbol
|
|
let section = sections.iter()
|
|
.find(|s| import.address >= s.addr && import.address < (s.addr + s.size));
|
|
|
|
// get &strs for its name
|
|
let (segname, sectname) = section
|
|
.map(|sect| (name_to_str(§.segname), name_to_str(§.sectname)))
|
|
.unwrap_or((Cow::Borrowed("?"), Cow::Borrowed("?")));
|
|
|
|
println!(
|
|
"{:7} {:16} 0x{:<12X} {:7} {:6} {:16} {}{}",
|
|
segname,
|
|
sectname,
|
|
import.address,
|
|
"pointer",
|
|
import.addend,
|
|
dylib_name(import.dylib),
|
|
import.name,
|
|
if import.is_weak { " (weak import)" } else { "" }
|
|
);
|
|
}
|
|
}
|
|
|
|
fn print_lazy_binds(sections: &[mach::segment::Section], imports: &[mach::imports::Import]) {
|
|
println!("lazy binding information (from lazy_bind part of dyld info):");
|
|
|
|
println!(
|
|
"{:7} {:16} {:10} {:6} {:16} symbol",
|
|
"segment",
|
|
"section",
|
|
"address",
|
|
"index",
|
|
"dylib",
|
|
);
|
|
|
|
for import in imports.iter().filter(|i| i.is_lazy) {
|
|
// find the section that imported this symbol
|
|
let section = sections.iter()
|
|
.find(|s| import.address >= s.addr && import.address < (s.addr + s.size));
|
|
|
|
// get &strs for its name
|
|
let (segname, sectname) = section
|
|
.map(|sect| (name_to_str(§.segname), name_to_str(§.sectname)))
|
|
.unwrap_or((Cow::Borrowed("?"), Cow::Borrowed("?")));
|
|
|
|
println!(
|
|
"{:7} {:16} 0x{:<8X} {:<06} {:16} {}",
|
|
segname,
|
|
sectname,
|
|
import.address,
|
|
format!("0x{:04X}", import.start_of_sequence_offset),
|
|
dylib_name(import.dylib),
|
|
import.name
|
|
);
|
|
}
|
|
}
|
|
|
|
fn main () {
|
|
let len = env::args().len();
|
|
|
|
let mut bind = false;
|
|
let mut lazy_bind = false;
|
|
|
|
if len <= 2 {
|
|
usage();
|
|
} else {
|
|
// parse flags
|
|
{
|
|
let mut flags = env::args().collect::<Vec<_>>();
|
|
flags.pop();
|
|
flags.remove(0);
|
|
for option in flags {
|
|
match option.as_str() {
|
|
"-bind" => { bind = true }
|
|
"-lazy_bind" => { lazy_bind = true }
|
|
other => {
|
|
println!("unknown flag: {}", other);
|
|
println!();
|
|
usage();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// open the file
|
|
let path = env::args_os().last().unwrap();
|
|
let path = Path::new(&path);
|
|
let buffer = { let mut v = Vec::new(); let mut f = File::open(&path).unwrap(); f.read_to_end(&mut v).unwrap(); v};
|
|
match mach::MachO::parse(&buffer, 0) {
|
|
Ok(macho) => {
|
|
// collect sections and sort by address
|
|
let mut sections: Vec<mach::segment::Section> = Vec::new();
|
|
for sects in macho.segments.sections() {
|
|
sections.extend(sects.map(|r| r.expect("section").0));
|
|
}
|
|
sections.sort_by_key(|s| s.addr);
|
|
|
|
// get the imports
|
|
let imports = macho.imports().expect("imports");
|
|
|
|
if bind {
|
|
print_binds(§ions, &imports);
|
|
}
|
|
if lazy_bind {
|
|
print_lazy_binds(§ions, &imports);
|
|
}
|
|
},
|
|
Err(err) => {
|
|
println!("err: {:?}", err);
|
|
process::exit(2);
|
|
}
|
|
}
|
|
}
|
|
}
|