1use std::collections::HashMap;
7use std::path::Path;
8
9use crate::backend::{FlowConfig, OperandKind};
10
11#[derive(Debug, Clone)]
13pub struct GenTarget {
14 pub input: String,
16
17 pub lang: String,
19
20 pub output: String,
22
23 pub format: bool,
25
26 pub dispatch: Dispatch,
28
29 pub dispatch_overrides: HashMap<String, Dispatch>,
31
32 pub type_map: HashMap<String, String>,
34
35 pub lang_options: LangOptions,
37}
38
39impl GenTarget {
40 pub fn new(
41 input: impl Into<String>,
42 lang: impl Into<String>,
43 output: impl Into<String>,
44 ) -> Self {
45 Self {
46 input: input.into(),
47 lang: lang.into(),
48 output: output.into(),
49 format: false,
50 dispatch: Dispatch::default(),
51 dispatch_overrides: HashMap::new(),
52 type_map: HashMap::new(),
53 lang_options: LangOptions::None,
54 }
55 }
56}
57
58#[derive(Debug, Clone)]
60pub struct LutTarget {
61 pub input: String,
63
64 pub output: String,
66
67 pub handler_mod: String,
69
70 pub ctx_type: String,
72
73 pub dispatch: Dispatch,
75
76 pub groups: HashMap<String, Vec<String>>,
78
79 pub lut_mod: Option<String>,
81
82 pub instr_type: Option<String>,
84
85 pub raw_expr: Option<String>,
87
88 pub instr_type_output: Option<String>,
90
91 pub subdecoder_groups: HashMap<String, HashMap<String, Vec<String>>>,
93
94 pub subdecoder_instr_type_outputs: HashMap<String, String>,
96
97 pub subdecoder_instr_types: HashMap<String, String>,
99
100 pub subdecoder_dispatch: HashMap<String, Dispatch>,
103
104 pub invalid_handler: Option<String>,
107
108 pub subdecoder_invalid_handlers: HashMap<String, String>,
110
111 pub subdecoder_handler_mods: HashMap<String, String>,
113
114 pub handler_consts: Vec<String>,
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
124pub enum Dispatch {
125 JumpTable,
127 #[default]
129 FnPtrLut,
130 FlatLut,
132 FlatMatch,
134}
135
136#[derive(Debug, Clone, Default)]
138pub enum LangOptions {
139 #[default]
140 None,
141 Cpp(CppOptions),
142 Ida(IdaOptions),
143 Binja(BinjaOptions),
144}
145
146impl LangOptions {
147 pub fn as_cpp(&self) -> Option<&CppOptions> {
148 match self {
149 LangOptions::Cpp(o) => Some(o),
150 _ => None,
151 }
152 }
153
154 pub fn as_ida(&self) -> Option<&IdaOptions> {
155 match self {
156 LangOptions::Ida(o) => Some(o),
157 _ => None,
158 }
159 }
160
161 pub fn as_binja(&self) -> Option<&BinjaOptions> {
162 match self {
163 LangOptions::Binja(o) => Some(o),
164 _ => None,
165 }
166 }
167}
168
169#[derive(Debug, Clone)]
171pub struct IdaOptions {
172 pub processor_name: String,
173 pub processor_long_name: String,
174 pub processor_id: u64,
175 pub register_names: Vec<String>,
176 pub segment_registers: Vec<String>,
177 pub address_size: u32,
178 pub bytes_per_unit: u32,
180 pub flags: Vec<String>,
181 pub operand_types: HashMap<String, OperandKind>,
182 pub display_prefixes: HashMap<String, String>,
184 pub flow: FlowConfig,
185}
186
187#[derive(Debug, Clone)]
189pub struct BinjaOptions {
190 pub architecture_name: String,
191 pub address_size: u32,
192 pub default_int_size: u32,
193 pub max_instr_length: u32,
194 pub endianness: String,
195 pub register_names: Vec<String>,
196 pub register_size: u32,
197 pub stack_pointer: Option<String>,
198 pub link_register: Option<String>,
199 pub bytes_per_unit: u32,
200 pub display_prefixes: HashMap<String, String>,
201 pub operand_types: HashMap<String, OperandKind>,
202 pub flow: FlowConfig,
203}
204
205#[derive(Debug, Clone, Default)]
207pub struct CppOptions {
208 pub namespace: Option<String>,
211 pub guard_style: CppGuardStyle,
212 pub includes: Vec<String>,
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
217pub enum CppGuardStyle {
218 #[default]
219 Pragma,
220 Ifndef,
221}
222
223pub fn expand_env(s: &str) -> String {
226 let mut result = String::with_capacity(s.len());
227 let mut chars = s.chars().peekable();
228 while let Some(c) = chars.next() {
229 if c == '$' {
230 let braced = chars.peek() == Some(&'{');
231 if braced {
232 chars.next();
233 }
234 let mut name = String::new();
235 if braced {
236 while let Some(&c) = chars.peek() {
237 if c == '}' {
238 chars.next();
239 break;
240 }
241 name.push(c);
242 chars.next();
243 }
244 } else {
245 while let Some(&c) = chars.peek() {
246 if c.is_ascii_alphanumeric() || c == '_' {
247 name.push(c);
248 chars.next();
249 } else {
250 break;
251 }
252 }
253 }
254 if let Ok(val) = std::env::var(&name) {
255 result.push_str(&val);
256 } else if braced {
257 result.push_str(&format!("${{{}}}", name));
258 } else {
259 result.push('$');
260 result.push_str(&name);
261 }
262 } else {
263 result.push(c);
264 }
265 }
266 result
267}
268
269pub fn resolve_path(path: &str, base_dir: &Path) -> String {
271 let expanded = expand_env(path);
272 let p = Path::new(&expanded);
273 if p.is_absolute() {
274 expanded
275 } else {
276 base_dir.join(&expanded).to_string_lossy().into_owned()
277 }
278}
279
280pub fn resolve_gen_paths(target: &mut GenTarget, base_dir: &Path) {
282 target.input = resolve_path(&target.input, base_dir);
283 target.output = resolve_path(&target.output, base_dir);
284}
285
286pub fn resolve_lut_paths(target: &mut LutTarget, base_dir: &Path) {
288 target.input = resolve_path(&target.input, base_dir);
289 target.output = resolve_path(&target.output, base_dir);
290 if let Some(ref mut p) = target.instr_type_output {
291 *p = resolve_path(p, base_dir);
292 }
293 for p in target.subdecoder_instr_type_outputs.values_mut() {
294 *p = resolve_path(p, base_dir);
295 }
296}