probe_ctree_counts/
probe_ctree_counts.rs1use idakit::prelude::*;
8
9fn dump(tree: &Ctree, node: idakit::decompiler::ctree::NodeRef, depth: usize) {
10 use idakit::decompiler::ctree::NodeRef;
11 let pad = " ".repeat(depth);
12 let label = match node {
13 NodeRef::Expression(id) => format!("{:?}", tree.kind(id)),
14 NodeRef::Statement(id) => format!("{:?}", tree.statement_kind(id)),
15 };
16 let line: String = label
17 .lines()
18 .next()
19 .unwrap_or("")
20 .chars()
21 .take(90)
22 .collect();
23 println!("{pad}{line}");
24 for c in tree.children(node) {
25 dump(tree, c, depth + 1);
26 }
27}
28
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30 let bin = std::env::args()
31 .nth(1)
32 .expect("usage: probe_ctree_counts <db.i64>");
33
34 Ida::run(move |ida| -> Result<(), Error> {
35 ida.call(move |idb| -> Result<(), Error> {
36 idb.open(&bin).run_auto(false).call()?;
37
38 let eas: Vec<_> = idb
39 .functions()
40 .map(|f| (f.address(), String::from(f.name())))
41 .collect();
42 let mut checked = 0usize;
43 let mut mismatches = 0usize;
44 let mut first_dumped = false;
45 for (address, name) in eas {
46 let Ok(cf) = idb.decompile(address) else {
47 continue;
48 };
49 let Ok(tree) = cf.ctree() else { continue };
50 checked += 1;
51 let (visitor_total, expected) = cf.expr_extraction_expectation();
52 let extracted = tree.expressions().count() as i32;
53 if extracted != expected {
54 mismatches += 1;
55 println!(
56 "MISMATCH {name} @ {address:#x}: extracted={extracted} expected={expected} \
57 visitor={visitor_total} (elided empties {})",
58 visitor_total - expected
59 );
60 if !first_dumped {
61 first_dumped = true;
62 println!("--- idakit render ---\n{}", tree.to_pseudocode());
63 println!("--- structure ---");
64 dump(
65 &tree,
66 idakit::decompiler::ctree::NodeRef::Statement(tree.root()),
67 0,
68 );
69 }
70 }
71 }
72 println!("\n[probe] {checked} decompiled, {mismatches} mismatched");
73 idb.close(false);
74 Ok(())
75 })?
76 })??;
77 Ok(())
78}