use std::collections::HashMap;
use std::path::Path;
use crate::backend::{FlowConfig, OperandKind};
#[derive(Debug, Clone)]
pub struct GenTarget {
pub input: String,
pub lang: String,
pub output: String,
pub format: bool,
pub dispatch: Dispatch,
pub dispatch_overrides: HashMap<String, Dispatch>,
pub type_map: HashMap<String, String>,
pub lang_options: LangOptions,
}
impl GenTarget {
pub fn new(
input: impl Into<String>,
lang: impl Into<String>,
output: impl Into<String>,
) -> Self {
Self {
input: input.into(),
lang: lang.into(),
output: output.into(),
format: false,
dispatch: Dispatch::default(),
dispatch_overrides: HashMap::new(),
type_map: HashMap::new(),
lang_options: LangOptions::None,
}
}
}
#[derive(Debug, Clone)]
pub struct LutTarget {
pub input: String,
pub output: String,
pub handler_mod: String,
pub ctx_type: String,
pub dispatch: Dispatch,
pub groups: HashMap<String, Vec<String>>,
pub lut_mod: Option<String>,
pub instr_type: Option<String>,
pub raw_expr: Option<String>,
pub instr_type_output: Option<String>,
pub subdecoder_groups: HashMap<String, HashMap<String, Vec<String>>>,
pub subdecoder_instr_type_outputs: HashMap<String, String>,
pub subdecoder_instr_types: HashMap<String, String>,
pub subdecoder_dispatch: HashMap<String, Dispatch>,
pub invalid_handler: Option<String>,
pub subdecoder_invalid_handlers: HashMap<String, String>,
pub subdecoder_handler_mods: HashMap<String, String>,
pub handler_consts: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Dispatch {
JumpTable,
#[default]
FnPtrLut,
FlatLut,
FlatMatch,
}
#[derive(Debug, Clone, Default)]
pub enum LangOptions {
#[default]
None,
Cpp(CppOptions),
Ida(IdaOptions),
Binja(BinjaOptions),
}
impl LangOptions {
pub fn as_cpp(&self) -> Option<&CppOptions> {
match self {
LangOptions::Cpp(o) => Some(o),
_ => None,
}
}
pub fn as_ida(&self) -> Option<&IdaOptions> {
match self {
LangOptions::Ida(o) => Some(o),
_ => None,
}
}
pub fn as_binja(&self) -> Option<&BinjaOptions> {
match self {
LangOptions::Binja(o) => Some(o),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct IdaOptions {
pub processor_name: String,
pub processor_long_name: String,
pub processor_id: u64,
pub register_names: Vec<String>,
pub segment_registers: Vec<String>,
pub address_size: u32,
pub bytes_per_unit: u32,
pub flags: Vec<String>,
pub operand_types: HashMap<String, OperandKind>,
pub display_prefixes: HashMap<String, String>,
pub flow: FlowConfig,
}
#[derive(Debug, Clone)]
pub struct BinjaOptions {
pub architecture_name: String,
pub address_size: u32,
pub default_int_size: u32,
pub max_instr_length: u32,
pub endianness: String,
pub register_names: Vec<String>,
pub register_size: u32,
pub stack_pointer: Option<String>,
pub link_register: Option<String>,
pub bytes_per_unit: u32,
pub display_prefixes: HashMap<String, String>,
pub operand_types: HashMap<String, OperandKind>,
pub flow: FlowConfig,
}
#[derive(Debug, Clone, Default)]
pub struct CppOptions {
pub namespace: Option<String>,
pub guard_style: CppGuardStyle,
pub includes: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum CppGuardStyle {
#[default]
Pragma,
Ifndef,
}
pub fn expand_env(s: &str) -> String {
let mut result = String::with_capacity(s.len());
let mut chars = s.chars().peekable();
while let Some(c) = chars.next() {
if c == '$' {
let braced = chars.peek() == Some(&'{');
if braced {
chars.next();
}
let mut name = String::new();
if braced {
while let Some(&c) = chars.peek() {
if c == '}' {
chars.next();
break;
}
name.push(c);
chars.next();
}
} else {
while let Some(&c) = chars.peek() {
if c.is_ascii_alphanumeric() || c == '_' {
name.push(c);
chars.next();
} else {
break;
}
}
}
if let Ok(val) = std::env::var(&name) {
result.push_str(&val);
} else if braced {
result.push_str(&format!("${{{}}}", name));
} else {
result.push('$');
result.push_str(&name);
}
} else {
result.push(c);
}
}
result
}
pub fn resolve_path(path: &str, base_dir: &Path) -> String {
let expanded = expand_env(path);
let p = Path::new(&expanded);
if p.is_absolute() {
expanded
} else {
base_dir.join(&expanded).to_string_lossy().into_owned()
}
}
pub fn resolve_gen_paths(target: &mut GenTarget, base_dir: &Path) {
target.input = resolve_path(&target.input, base_dir);
target.output = resolve_path(&target.output, base_dir);
}
pub fn resolve_lut_paths(target: &mut LutTarget, base_dir: &Path) {
target.input = resolve_path(&target.input, base_dir);
target.output = resolve_path(&target.output, base_dir);
if let Some(ref mut p) = target.instr_type_output {
*p = resolve_path(p, base_dir);
}
for p in target.subdecoder_instr_type_outputs.values_mut() {
*p = resolve_path(p, base_dir);
}
}