Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/nornir

crates/mimir-binary/src/main.rs

//! `mimir-binary` — join one linked artifact onto a mimir-driver dump.
//!
//! ```text
//! mimir-binary --bin PATH --dump DIR [--extra-dump DIR]… [--deps-dir DIR] [--manifest-path P]
//!              [--sysroot DIR | --no-sysroot] [--ignore-driver-symbols]
//!              [--out DIR] [--sha SHA]
//! ```
//!
//! `mimir-binary --cat FILE.arrow` prints any of the IPC files as TSV.
//!
//! Writes `<out>/<bin>.binary.{nodes,edges,symbols}.arrow` and
//! `<out>/<bin>.binary.ledger.json`, prints the ledger summary.

use std::path::PathBuf;
use std::process::ExitCode;

const USAGE: &str = "usage: mimir-binary --bin PATH --dump DIR [--extra-dump DIR]... [--deps-dir DIR] [--manifest-path P] [--sysroot DIR | --no-sysroot] [--ignore-driver-symbols] [--out DIR] [--sha SHA]";

fn main() -> ExitCode {
    let mut opts = mimir_binary::Options::default();
    let mut out: Option<PathBuf> = None;
    let mut no_sysroot = false;
    let mut it = std::env::args().skip(1);
    while let Some(a) = it.next() {
        match a.as_str() {
            "--bin" => opts.binary = it.next().map(PathBuf::from).unwrap_or_default(),
            "--dump" => opts.dump = it.next().map(PathBuf::from).unwrap_or_default(),
            "--extra-dump" => opts.extra_dumps.extend(it.next().map(PathBuf::from)),
            "--deps-dir" => opts.deps_dir = it.next().map(PathBuf::from),
            "--manifest-path" => opts.manifest = it.next().map(PathBuf::from),
            "--out" => out = it.next().map(PathBuf::from),
            "--sha" => opts.sha = it.next(),
            "--sysroot" => opts.sysroot = it.next().map(PathBuf::from),
            "--no-sysroot" => no_sysroot = true,
            "--ignore-driver-symbols" => opts.ignore_driver_symbols = true,
            "--cat" => {
                // print one Arrow IPC file as TSV
                let Some(f) = it.next() else { return ExitCode::from(2) };
                return match mimir_binary::read_table(std::path::Path::new(&f)) {
                    Ok((cols, rows)) => {
                        println!("{}", cols.join("\t"));
                        for r in rows {
                            println!("{}", r.join("\t"));
                        }
                        ExitCode::SUCCESS
                    }
                    Err(e) => {
                        eprintln!("{e}");
                        ExitCode::FAILURE
                    }
                };
            }
            "-h" | "--help" => {
                eprintln!("{USAGE}");
                return ExitCode::SUCCESS;
            }
            other => {
                eprintln!("mimir-binary: unknown argument {other}\n{USAGE}");
                return ExitCode::from(2);
            }
        }
    }
    if opts.binary.as_os_str().is_empty() || opts.dump.as_os_str().is_empty() {
        eprintln!("{USAGE}");
        return ExitCode::from(2);
    }
    // default: the sysroot of the `rustc` on PATH (the toolchain that most
    // likely linked the artifact; a wrong one simply yields no id hits)
    if opts.sysroot.is_none() && !no_sysroot {
        opts.sysroot = std::process::Command::new("rustc")
            .args(["--print", "sysroot"])
            .output()
            .ok()
            .filter(|o| o.status.success())
            .map(|o| PathBuf::from(String::from_utf8_lossy(&o.stdout).trim()));
    }
    let o = match mimir_binary::run(&opts) {
        Ok(o) => o,
        Err(e) => {
            eprintln!("mimir-binary: {e}");
            return ExitCode::FAILURE;
        }
    };
    let out = out.unwrap_or_else(|| opts.dump.clone());
    let stem = opts.binary.file_name().map(|s| s.to_string_lossy().into_owned()).unwrap_or_else(|| "artifact".into());
    if let Err(e) = mimir_binary::write(&out, &stem, &o) {
        eprintln!("mimir-binary: write: {e}");
        return ExitCode::FAILURE;
    }
    let l = &o.ledger;
    eprintln!("── mimir-binary ───────────────────────────────────────");
    eprintln!("artifact         {}  ({} bytes, .text {}, dwarf {}, {})", l.binary, l.file_size, l.text_size, l.has_dwarf, l.symbol_table);
    eprintln!("crate ids known  {:?}  (cu crates {}, deps rlibs {}, sysroot rlibs {}, conflicts {})", l.crate_ids_known, l.cu_crates, l.deps_rlibs, l.sysroot_rlibs, l.crate_id_conflicts.len());
    eprintln!("symbols          defined {} ({} bytes), undefined {}", l.defined, l.defined_bytes, l.undefined);
    eprintln!("mangling         {:?}", l.by_mangling);
    eprintln!("crate via        {:?}", l.crate_via);
    eprintln!("ambiguous crates {:?}", l.ambiguous_crates);
    eprintln!("unknown crates   {:?}", l.unknown_crates);
    eprintln!("matched          {:?}  (ambiguous exact {}, loose {})", l.matched, l.ambiguous_exact, l.ambiguous_loose);
    eprintln!("roles            {:?}", l.roles);
    for (o, c) in &l.by_origin {
        eprintln!("origin {o:<9} {} symbols, {} bytes, matched to source {} ({:.1}%)", c.symbols, c.bytes, c.matched, if c.symbols == 0 { 0.0 } else { c.matched as f64 * 100.0 / c.symbols as f64 });
    }
    eprintln!("imports          {:?}", l.imports);
    eprintln!("decode errors    {:?}", l.decode_errors);
    eprintln!("nodes            both {}  binary_only {}  (mono_instance {})", l.nodes_both, l.nodes_binary_only, l.nodes_mono_instance);
    eprintln!("INSTANCE_OF      {}  (dangling {})", l.edges_instance_of, l.instance_of_dangling);
    eprintln!("moniker coverage {}% of defined, {}% of Rust; source match {}% of Rust", l.pct_moniker_of_defined, l.pct_moniker_of_rust, l.pct_source_match_of_rust);
    eprintln!("source_only      {} of {} symbol-bearing items in linked crates", l.source_only_items, l.source_items_in_linked_crates);
    eprintln!("bytes by crate (top 15):");
    for (k, b, n) in l.bytes_by_crate.iter().take(15) {
        eprintln!("  {k:<48} {b:>10}  {n:>6} syms");
    }
    eprintln!("time             read {} ms, join {} ms", l.ms_read, l.ms_join);
    eprintln!("out              {}", out.display());
    ExitCode::SUCCESS
}