1use std::collections::HashMap;
7use std::path::{Path, PathBuf};
8
9use crate::backend::{self, run_formatter};
10use crate::config::{
11 self, BinjaOptions, GenTarget, IdaOptions, LangOptions, LutTarget, resolve_gen_paths,
12 resolve_lut_paths,
13};
14use crate::error::{Error, ErrorKind, Errors, Span};
15use crate::instr_gen;
16use crate::lut_gen::{self, generate_lut_code, generate_subdecoder_flat_dispatch};
17use crate::tree;
18use crate::types::ValidatedDef;
19use crate::validate::validate as validate_spec;
20
21use super::lower::{LoweredBindings, LoweredItem, LoweredKind, lower_resolved};
22use super::parser::parse_file_with_includes;
23use super::resolve::{ResolvedBindings, resolve};
24use super::types::{TargetBinding, TargetKind};
25use super::validate::validate as validate_bindings;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum RunMode {
29 Generate,
30 Preview,
31 Check,
32}
33
34pub fn run(
36 bindings_path: &Path,
37 target_filter: Option<&str>,
38 decoder_filter: Option<&str>,
39 mode: RunMode,
40) -> Result<(), Vec<Error>> {
41 let parsed = parse_file_with_includes(bindings_path)?;
42 let resolved = resolve(parsed)?;
43 validate_bindings(&resolved)?;
44 let lowered = lower_resolved(&resolved)?;
45 run_lowered(
46 &resolved,
47 &lowered,
48 bindings_path,
49 target_filter,
50 decoder_filter,
51 mode,
52 )
53}
54
55pub fn run_lowered(
58 resolved: &ResolvedBindings,
59 lowered: &LoweredBindings,
60 bindings_path: &Path,
61 target_filter: Option<&str>,
62 decoder_filter: Option<&str>,
63 mode: RunMode,
64) -> Result<(), Vec<Error>> {
65 if mode == RunMode::Check {
66 return Ok(());
68 }
69
70 let target_kind = match target_filter {
72 Some(t) => Some(parse_target_kind(t)?),
73 None => None,
74 };
75 let target_kinds_present: Vec<TargetKind> =
76 resolved.file.targets.iter().map(|t| t.kind).collect();
77 if target_kind.is_none() && distinct(&target_kinds_present).len() > 1 {
78 return Err(vec![Error::new(
79 ErrorKind::MultipleTargetsAmbiguous(
80 distinct(&target_kinds_present)
81 .iter()
82 .map(|k| k.name().to_string())
83 .collect(),
84 ),
85 Span::new(&bindings_path.display().to_string(), 1, 1, 0),
86 )]);
87 }
88
89 let base_dir = bindings_path
90 .parent()
91 .map(|p| p.to_path_buf())
92 .unwrap_or_else(|| PathBuf::from("."));
93
94 let filtered: Vec<&LoweredItem> = lowered
95 .items
96 .iter()
97 .filter(|it| target_kind.map_or(true, |k| k == it.target_kind))
98 .filter(|it| decoder_filter.map_or(true, |d| d == it.decoder_name))
99 .collect();
100
101 if filtered.is_empty() {
102 return Err(vec![Error::new(
103 ErrorKind::BindingsParse(format!(
104 "no targets match {}{}",
105 target_filter
106 .map(|s| format!("--target {} ", s))
107 .unwrap_or_default(),
108 decoder_filter
109 .map(|s| format!("--decoder {}", s))
110 .unwrap_or_default()
111 )),
112 Span::new(&bindings_path.display().to_string(), 1, 1, 0),
113 )]);
114 }
115
116 if decoder_filter.is_none() {
119 let names: Vec<String> = filtered.iter().map(|i| i.decoder_name.clone()).collect();
120 if distinct(&names).len() > 1
121 && lowered.items.len() > filtered.len()
122 && target_kind.is_none()
123 {
124 } else if distinct(&names).len() > 1 && target_kind.is_some() {
126 return Err(vec![Error::new(
127 ErrorKind::MultipleDecodersAmbiguous(distinct(&names)),
128 Span::new(&bindings_path.display().to_string(), 1, 1, 0),
129 )]);
130 }
131 }
132
133 for item in &filtered {
134 match &item.kind {
135 LoweredKind::Gen(g) => run_gen(g, &base_dir, mode)?,
136 LoweredKind::Lut(l) => run_lut(l, &base_dir, mode)?,
137 LoweredKind::InstrType {
138 input,
139 output,
140 struct_name,
141 subdecoder,
142 } => run_instr_type(input, output, struct_name, subdecoder.as_deref(), &base_dir)?,
143 }
144 }
145
146 Ok(())
147}
148
149fn parse_target_kind(name: &str) -> Result<TargetKind, Vec<Error>> {
150 Ok(match name {
151 "rust" => TargetKind::Rust,
152 "cpp" | "c++" => TargetKind::Cpp,
153 "ida" => TargetKind::Ida,
154 "binja" => TargetKind::Binja,
155 other => {
156 return Err(vec![Error::new(
157 ErrorKind::UnknownTargetKind(other.to_string()),
158 Span::new("<cli>", 1, 1, 0),
159 )]);
160 }
161 })
162}
163
164fn distinct<T: Clone + Eq>(v: &[T]) -> Vec<T> {
165 let mut out: Vec<T> = Vec::new();
166 for x in v {
167 if !out.iter().any(|y| y == x) {
168 out.push(x.clone());
169 }
170 }
171 out
172}
173
174fn run_gen(target: &GenTarget, base_dir: &Path, mode: RunMode) -> Result<(), Vec<Error>> {
175 let mut t = target.clone();
176 resolve_gen_paths(&mut t, base_dir);
177
178 if mode == RunMode::Preview {
179 print_gen_preview(&t);
180 return Ok(());
181 }
182
183 let (def, _deps) = crate::parser::parse_file_with_deps(Path::new(&t.input))?;
184 let validated = validate_spec(&def)?;
185 let backend = backend::get_backend(&t.lang).ok_or_else(|| {
186 vec![Error::new(
187 ErrorKind::BindingsParse(format!("unknown backend '{}'", t.lang)),
188 Span::new("<lower>", 0, 0, 0),
189 )]
190 })?;
191 let code = backend.generate(&validated, &t).map_err(|e| {
192 vec![Error::new(
193 ErrorKind::BindingsParse(format!("codegen error: {}", e)),
194 Span::new("<lower>", 0, 0, 0),
195 )]
196 })?;
197 std::fs::write(&t.output, code).map_err(|e| {
198 vec![Error::new(
199 ErrorKind::BindingsParse(format!("failed to write {}: {}", t.output, e)),
200 Span::new("<lower>", 0, 0, 0),
201 )]
202 })?;
203 if t.format {
204 if let Some(cmd) = backend.formatter_command() {
205 run_formatter(cmd, &t.output);
206 }
207 }
208 Ok(())
209}
210
211fn run_lut(target: &LutTarget, base_dir: &Path, mode: RunMode) -> Result<(), Vec<Error>> {
212 let mut t = target.clone();
213 resolve_lut_paths(&mut t, base_dir);
214
215 if mode == RunMode::Preview {
216 print_lut_preview(&t);
217 return Ok(());
218 }
219
220 let (def, _deps) = crate::parser::parse_file_with_deps(Path::new(&t.input))?;
221 let validated = validate_spec(&def)?;
222 let tree = tree::build_tree(&validated);
223
224 let mut instr_to_group: HashMap<String, String> = HashMap::new();
226 for (group, instrs) in &t.groups {
227 for instr in instrs {
228 instr_to_group.insert(instr.clone(), group.clone());
229 }
230 }
231
232 let mut code = generate_lut_code(
233 &validated,
234 &tree,
235 &t.handler_mod,
236 &t.ctx_type,
237 &instr_to_group,
238 t.instr_type.as_deref(),
239 t.raw_expr.as_deref(),
240 t.dispatch,
241 t.invalid_handler.as_deref(),
242 &t.handler_consts,
243 )?;
244
245 for sd in &validated.sub_decoders {
247 let strategy = t
248 .subdecoder_dispatch
249 .get(&sd.name)
250 .copied()
251 .unwrap_or(t.dispatch);
252 let sd_handler_mod = t
253 .subdecoder_handler_mods
254 .get(&sd.name)
255 .cloned()
256 .unwrap_or_else(|| t.handler_mod.clone());
257 let sd_invalid = t
258 .subdecoder_invalid_handlers
259 .get(&sd.name)
260 .cloned()
261 .or_else(|| t.invalid_handler.clone());
262 let sd_groups: HashMap<String, String> = t
263 .subdecoder_groups
264 .get(&sd.name)
265 .map(|g| {
266 let mut m = HashMap::new();
267 for (group, instrs) in g {
268 for instr in instrs {
269 m.insert(instr.clone(), group.clone());
270 }
271 }
272 m
273 })
274 .unwrap_or_default();
275 let sd_instr_type = t.subdecoder_instr_types.get(&sd.name).cloned();
276
277 match strategy {
278 config::Dispatch::FlatLut | config::Dispatch::FlatMatch => {
279 code.push('\n');
280 let block = generate_subdecoder_flat_dispatch(
281 sd,
282 &sd_handler_mod,
283 &t.ctx_type,
284 &sd_groups,
285 sd_instr_type.as_deref(),
286 sd_invalid.as_deref(),
287 strategy,
288 &t.handler_consts,
289 )?;
290 code.push_str(&block);
291 }
292 _ => {
293 if !sd_groups.is_empty() || t.subdecoder_dispatch.contains_key(&sd.name) {
295 code.push('\n');
296 code.push_str(&lut_gen::generate_subdecoder_dispatch(
297 &validated,
298 sd,
299 &sd_handler_mod,
300 &t.ctx_type,
301 &sd_groups,
302 sd_instr_type.as_deref(),
303 &t.handler_consts,
304 ));
305 }
306 }
307 }
308 }
309
310 std::fs::write(&t.output, code).map_err(|e| {
311 vec![Error::new(
312 ErrorKind::BindingsParse(format!("failed to write {}: {}", t.output, e)),
313 Span::new("<lower>", 0, 0, 0),
314 )]
315 })?;
316
317 if let Some(it_out) = &t.instr_type_output {
319 let struct_name = t
320 .instr_type
321 .as_deref()
322 .and_then(|p| p.rsplit("::").next())
323 .unwrap_or("Instruction");
324 let (it_code, _warnings) = instr_gen::generate_instr_type(&validated, struct_name);
325 std::fs::write(it_out, it_code).map_err(|e| {
326 vec![Error::new(
327 ErrorKind::BindingsParse(format!("failed to write {}: {}", it_out, e)),
328 Span::new("<lower>", 0, 0, 0),
329 )]
330 })?;
331 }
332
333 for (sd_name, out) in &t.subdecoder_instr_type_outputs {
335 let sd = validated
336 .sub_decoders
337 .iter()
338 .find(|s| &s.name == sd_name)
339 .ok_or_else(|| {
340 vec![Error::new(
341 ErrorKind::UnknownDecoderInBinding {
342 name: sd_name.clone(),
343 suggestion: None,
344 },
345 Span::new("<lower>", 0, 0, 0),
346 )]
347 })?;
348 let (it_code, _warnings) = instr_gen::generate_subdecoder_instr_type(sd, sd_name);
349 std::fs::write(out, it_code).map_err(|e| {
350 vec![Error::new(
351 ErrorKind::BindingsParse(format!("failed to write {}: {}", out, e)),
352 Span::new("<lower>", 0, 0, 0),
353 )]
354 })?;
355 }
356
357 Ok(())
358}
359
360fn run_instr_type(
361 input: &Path,
362 output: &str,
363 struct_name: &str,
364 subdecoder: Option<&str>,
365 base_dir: &Path,
366) -> Result<(), Vec<Error>> {
367 let _ = base_dir;
368 let (def, _) = crate::parser::parse_file_with_deps(input)?;
369 let validated = validate_spec(&def)?;
370 let (code, _warnings) = match subdecoder {
371 Some(name) => {
372 let sd = validated
373 .sub_decoders
374 .iter()
375 .find(|s| s.name == name)
376 .ok_or_else(|| {
377 vec![Error::new(
378 ErrorKind::UnknownDecoderInBinding {
379 name: name.to_string(),
380 suggestion: None,
381 },
382 Span::new("<instr-type>", 0, 0, 0),
383 )]
384 })?;
385 instr_gen::generate_subdecoder_instr_type(sd, struct_name)
386 }
387 None => instr_gen::generate_instr_type(&validated, struct_name),
388 };
389 std::fs::write(output, code).map_err(|e| {
390 vec![Error::new(
391 ErrorKind::BindingsParse(format!("failed to write {}: {}", output, e)),
392 Span::new("<instr-type>", 0, 0, 0),
393 )]
394 })?;
395 Ok(())
396}
397
398fn print_gen_preview(t: &GenTarget) {
399 println!("target: {}", t.lang);
400 println!();
401 println!("decoder:");
402 println!(" input: {}", t.input);
403 println!(" output: {}", t.output);
404 let mut keys: Vec<&String> = t.type_map.keys().collect();
405 keys.sort();
406 for k in keys {
407 println!(" type {} -> {}", k, t.type_map[k]);
408 }
409 match &t.lang_options {
410 LangOptions::Ida(o) => print_ida_preview(o),
411 LangOptions::Binja(o) => print_binja_preview(o),
412 _ => {}
413 }
414 println!();
415}
416
417fn print_ida_preview(o: &IdaOptions) {
418 println!();
419 println!("processor:");
420 println!(" name: {}", o.processor_name);
421 println!(" long name: {}", o.processor_long_name);
422 println!(" id: {:#x}", o.processor_id);
423 println!(" address size: {}", o.address_size);
424 println!(" bytes per unit: {}", o.bytes_per_unit);
425 println!();
426 println!("registers:");
427 for r in &o.register_names {
428 println!(" {}", r);
429 }
430 if !o.segment_registers.is_empty() {
431 println!();
432 println!("segment registers:");
433 for r in &o.segment_registers {
434 println!(" {}", r);
435 }
436 }
437 println!();
438 println!("flow:");
439 println!(" calls: {}", o.flow.calls.join(", "));
440 println!(" returns: {}", o.flow.returns.join(", "));
441 println!(" stops: {}", o.flow.stops.join(", "));
442}
443
444fn print_binja_preview(o: &BinjaOptions) {
445 println!();
446 println!("architecture:");
447 println!(" name: {}", o.architecture_name);
448 println!(" address size: {}", o.address_size);
449 println!(" default int size: {}", o.default_int_size);
450 println!(" endianness: {}", o.endianness);
451 println!();
452 println!("registers:");
453 for r in &o.register_names {
454 println!(" {}", r);
455 }
456}
457
458fn print_lut_preview(t: &LutTarget) {
459 println!("dispatch:");
460 println!(" input: {}", t.input);
461 println!(" output: {}", t.output);
462 println!(" context: {}", t.ctx_type);
463 println!(" handlers: {}", t.handler_mod);
464 println!(" strategy: {:?}", t.dispatch);
465 if let Some(ih) = &t.invalid_handler {
466 println!(" invalid handler: {}", ih);
467 }
468 if let Some(it) = &t.instr_type {
469 println!(" instruction_type: {}", it);
470 }
471 if !t.groups.is_empty() {
472 println!();
473 println!("handlers:");
474 let mut keys: Vec<&String> = t.groups.keys().collect();
475 keys.sort();
476 for g in keys {
477 for instr in &t.groups[g] {
478 println!(
479 " {} -> {}::{}::<{{ OP_{} }}>",
480 instr,
481 t.handler_mod,
482 g,
483 instr.to_uppercase()
484 );
485 }
486 }
487 }
488 println!();
489}
490
491fn _unused(_: &TargetBinding, _: &ValidatedDef, _: Errors) {}