summaryrefslogtreecommitdiffstats
path: root/third_party/rust/goblin/examples/dyldinfo.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/goblin/examples/dyldinfo.rs')
-rw-r--r--third_party/rust/goblin/examples/dyldinfo.rs162
1 files changed, 162 insertions, 0 deletions
diff --git a/third_party/rust/goblin/examples/dyldinfo.rs b/third_party/rust/goblin/examples/dyldinfo.rs
new file mode 100644
index 0000000000..384e5e59f2
--- /dev/null
+++ b/third_party/rust/goblin/examples/dyldinfo.rs
@@ -0,0 +1,162 @@
+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(&sect.segname), name_to_str(&sect.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(&sect.segname), name_to_str(&sect.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(&sections, &imports);
+ }
+ if lazy_bind {
+ print_lazy_binds(&sections, &imports);
+ }
+ },
+ Err(err) => {
+ println!("err: {:?}", err);
+ process::exit(2);
+ }
+ }
+ }
+}