1use idakit::prelude::*;
10
11fn dump(tree: &Ctree, node: idakit::decompiler::ctree::NodeRef, depth: usize) {
15 use idakit::decompiler::ctree::NodeRef;
16 let pad = " ".repeat(depth);
17 let label = match node {
18 NodeRef::Expression(id) => format!("{:?}", tree.kind(id)),
19 NodeRef::Statement(id) => format!("{:?}", tree.statement_kind(id)),
20 };
21 let line: String = label
22 .lines()
23 .next()
24 .unwrap_or("")
25 .chars()
26 .take(90)
27 .collect();
28 println!("{pad}{line}");
29 for c in tree.children(node) {
30 dump(tree, c, depth + 1);
31 }
32}
33
34fn main() -> Result<(), Box<dyn std::error::Error>> {
35 let mut args = std::env::args().skip(1);
36 let bin = args
37 .next()
38 .expect("usage: ctree_dump <binary> [name-substring]");
39 let filter = args.next().unwrap_or_default();
40
41 Ida::run(move |ida| -> Result<(), Error> {
42 ida.call(move |idb| -> Result<(), Error> {
43 idb.open(&bin).run_auto(true).call()?;
44
45 let mut matched = 0;
46 let eas: Vec<_> = idb.functions().map(|f| (f.address(), f.name())).collect();
47 for (address, name) in eas {
48 let name = String::from(name);
49 if !filter.is_empty() && !name.contains(&filter) {
50 continue;
51 }
52 let Ok(cf) = idb.decompile(address) else {
53 continue;
54 };
55 let Ok(tree) = cf.ctree() else { continue };
56 matched += 1;
57 println!("\n========== {name} @ {address:#x} ==========");
58 if let Some(pc) = cf.pseudocode() {
59 println!("--- IDA ---\n{pc}");
60 }
61 println!("--- idakit ---\n{}", tree.to_pseudocode());
62 println!("--- structure ---");
63 dump(
64 &tree,
65 idakit::decompiler::ctree::NodeRef::Statement(tree.root()),
66 0,
67 );
68 }
69 println!("\n[ctree_dump] {matched} function(s) matched filter {filter:?}");
70
71 idb.close(false);
72 Ok(())
73 })?
74 })??;
75
76 Ok(())
77}