mod api;
mod args;
mod c;
mod c_step;
mod callee_meta;
mod caller_ret;
mod calls;
mod carry_alu;
mod carry_cond;
mod cfg;
mod cli;
mod commands;
mod cond;
mod diffc;
mod disp;
mod dump;
mod expr;
mod fields_c;
mod find;
mod goto_elim;
mod graph;
mod image;
mod image_format;
mod inline;
mod layout;
mod layout_fmt;
mod listing;
mod live;
mod locations;
mod loops;
mod macho;
mod matching;
mod mcp;
mod reach;
mod reduce;
mod runtime;
mod scan;
mod sig;
mod simplify;
mod slice;
mod slice_parse;
mod source;
mod ssa_cfg;
mod ssa_inline;
mod ssa_webs;
mod stack_anchors;
mod stack_frame;
mod tables;
#[cfg(test)]
mod tests;
mod type_facts;
mod type_prop;
mod unrotate;
mod variant;
mod wide_alu;
use std::io::{self, BufWriter, ErrorKind, Write};
use std::process::ExitCode;
use std::time::Instant;
use clap::{CommandFactory, Parser, error::ErrorKind as ClapErrorKind};
use crate::cli::Cli;
use crate::image::Image;
fn main() -> ExitCode {
let cli = Cli::parse();
if let cli::Command::Live(cmd) = &cli.command {
let mut out = BufWriter::new(io::stdout().lock());
let result = live::run(cli.bin.as_deref(), cmd, &mut out).and_then(|()| {
out.flush()?;
Ok(())
});
return match result {
Ok(()) => ExitCode::SUCCESS,
Err(error) if error.downcast_ref::<io::Error>().is_some_and(|e| e.kind() == ErrorKind::BrokenPipe) => {
ExitCode::SUCCESS
}
Err(error) => {
eprintln!("xref: {error}");
ExitCode::FAILURE
}
};
}
let Some(bin) = cli.bin.as_deref() else {
Cli::command()
.error(
ClapErrorKind::MissingRequiredArgument,
"the following required arguments were not provided:\n --bin <BIN>",
)
.exit();
};
if let cli::Command::Mcp { allow_live_pid } = &cli.command {
return match mcp::serve_with_live(bin, *allow_live_pid) {
Ok(()) => ExitCode::SUCCESS,
Err(error) if error.downcast_ref::<io::Error>().is_some_and(|e| e.kind() == ErrorKind::BrokenPipe) => {
ExitCode::SUCCESS
}
Err(error) => {
eprintln!("xref: {error}");
ExitCode::FAILURE
}
};
}
if let cli::Command::Query { request } = &cli.command {
let mut out = BufWriter::new(io::stdout().lock());
return match api::run_cli(bin, request, &mut out) {
Ok(true) => ExitCode::SUCCESS,
Ok(false) => ExitCode::FAILURE,
Err(error) if error.kind() == ErrorKind::BrokenPipe => ExitCode::SUCCESS,
Err(error) => {
eprintln!("xref: {error}");
ExitCode::FAILURE
}
};
}
let started = Instant::now();
let result = Image::load(bin).and_then(|image| {
let loaded = started.elapsed();
let mut out = BufWriter::new(io::stdout().lock());
commands::run(&image, cli.command, &mut out)?;
out.flush()?;
eprintln!("xref: load {loaded:.1?}, total {:.1?}", started.elapsed());
Ok(())
});
match result {
Ok(()) => ExitCode::SUCCESS,
Err(error) if error.downcast_ref::<io::Error>().is_some_and(|e| e.kind() == ErrorKind::BrokenPipe) => {
ExitCode::SUCCESS
}
Err(error) => {
eprintln!("xref: {error}");
ExitCode::FAILURE
}
}
}