1pub mod binja;
8pub mod cpp;
9pub mod ida;
10pub mod rust;
11
12use crate::config::GenTarget;
13use crate::types::ValidatedDef;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum OperandKind {
18 Register,
19 Immediate,
20 Address,
21 Memory,
22}
23
24#[derive(Debug, Clone, Default)]
26pub struct FlowConfig {
27 pub calls: Vec<String>,
28 pub branches: Vec<String>,
29 pub unconditional_branches: Vec<String>,
30 pub returns: Vec<String>,
31 pub stops: Vec<String>,
32}
33
34pub trait CodegenBackend {
36 fn lang(&self) -> &str;
38
39 fn validate_lang_options(&self, options: &toml::Value) -> Result<(), Vec<String>>;
42
43 fn generate(&self, ir: &ValidatedDef, config: &GenTarget) -> Result<String, CodegenError>;
45
46 fn formatter_command(&self) -> Option<&[&str]>;
48}
49
50#[derive(Debug)]
51pub enum CodegenError {
52 Internal(String),
53}
54
55impl std::fmt::Display for CodegenError {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 match self {
58 CodegenError::Internal(msg) => write!(f, "codegen error: {}", msg),
59 }
60 }
61}
62
63impl std::error::Error for CodegenError {}
64
65pub fn get_backend(lang: &str) -> Option<Box<dyn CodegenBackend>> {
67 match lang {
68 "rust" => Some(Box::new(rust::RustBackend)),
69 "ida" => Some(Box::new(ida::IdaBackend)),
70 "binja" => Some(Box::new(binja::BinjaBackend)),
71 "cpp" => Some(Box::new(cpp::CppBackend)),
72 _ => None,
73 }
74}
75
76pub fn run_formatter(cmd: &[&str], path: &str) {
78 let status = std::process::Command::new(cmd[0])
79 .args(&cmd[1..])
80 .arg(path)
81 .status();
82
83 match status {
84 Ok(s) if s.success() => {}
85 Ok(s) => eprintln!("warning: formatter exited with {}", s),
86 Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
87 eprintln!("warning: formatter '{}' not found, skipping", cmd[0]);
88 }
89 Err(e) => eprintln!("warning: failed to run formatter: {}", e),
90 }
91}