pub mod binja;
pub mod cpp;
pub mod ida;
pub mod rust;
use crate::config::GenTarget;
use crate::types::ValidatedDef;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OperandKind {
Register,
Immediate,
Address,
Memory,
}
#[derive(Debug, Clone, Default)]
pub struct FlowConfig {
pub calls: Vec<String>,
pub branches: Vec<String>,
pub unconditional_branches: Vec<String>,
pub returns: Vec<String>,
pub stops: Vec<String>,
}
pub trait CodegenBackend {
fn lang(&self) -> &str;
fn generate(&self, ir: &ValidatedDef, config: &GenTarget) -> Result<String, CodegenError>;
fn formatter_command(&self) -> Option<&[&str]>;
}
#[derive(Debug)]
pub enum CodegenError {
Internal(String),
}
impl std::fmt::Display for CodegenError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CodegenError::Internal(msg) => write!(f, "codegen error: {}", msg),
}
}
}
impl std::error::Error for CodegenError {}
pub fn get_backend(lang: &str) -> Option<Box<dyn CodegenBackend>> {
match lang {
"rust" => Some(Box::new(rust::RustBackend)),
"ida" => Some(Box::new(ida::IdaBackend)),
"binja" => Some(Box::new(binja::BinjaBackend)),
"cpp" => Some(Box::new(cpp::CppBackend)),
_ => None,
}
}
pub fn run_formatter(cmd: &[&str], path: &str) {
let status = std::process::Command::new(cmd[0])
.args(&cmd[1..])
.arg(path)
.status();
match status {
Ok(s) if s.success() => {}
Ok(s) => eprintln!("warning: formatter exited with {}", s),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
eprintln!("warning: formatter '{}' not found, skipping", cmd[0]);
}
Err(e) => eprintln!("warning: failed to run formatter: {}", e),
}
}