Skip to main content

actor/
actor.rs

1//! Executor proof from the idiomatic API: kernel on its own thread, app on the
2//! caller, calls (including from sub-workers) marshaled to the kernel.
3//! Run: cargo run -p idakit --example actor -- path/to/database.i64
4
5use std::thread;
6
7use idakit::prelude::*;
8
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    let db = std::env::args().nth(1).expect("usage: actor <db.i64>");
11
12    // `run` -> Err on kernel setup; the app closure -> Err on an operational failure.
13    Ida::run(move |ida| -> Result<(), Error> {
14        {
15            let db = db;
16            ida.call(move |idb| idb.open(&db).call())??;
17        }
18
19        let n = ida.call(|idb| idb.functions().count())?;
20        let segs = ida.call(|idb| idb.segments().count())?;
21        println!("[app] func_count={n}  segments={segs}");
22
23        // Sig scan: build a hex pattern from the first function's opening bytes and count
24        // how often that exact sequence recurs across the image. A `Pattern` borrows the
25        // `Database`, so it is built, searched, and dropped inside a single kernel call.
26        let hits = ida.call(|idb| {
27            let Some(address) = idb.functions().next().map(|f| f.address()) else {
28                return 0;
29            };
30            let sig = idb
31                .bytes(address, 8)
32                .iter()
33                .map(|b| format!("{b:02X}"))
34                .collect::<Vec<_>>()
35                .join(" ");
36            match Pattern::hex(idb, &sig) {
37                Ok(pat) => idb.search(&pat).count(),
38                Err(_) => 0,
39            }
40        })?;
41        println!("[app] first function's opening 8 bytes recur {hits} time(s) in the image");
42
43        // Sub-workers each hold a handle clone; their calls serialize onto the kernel.
44        let mut hs = vec![];
45        for t in 0..4usize {
46            let ida = ida.clone();
47            hs.push(thread::spawn(move || {
48                let idx = t * 1000;
49                let found = ida
50                    .call(move |idb| idb.functions().nth(idx).map(|f| (f.address(), f.name())))
51                    .expect("kernel call");
52                let (address, name) = match found {
53                    Some((address, name)) => (format!("{address:#012x}"), String::from(name)),
54                    None => ("<none>".into(), "<unnamed>".into()),
55                };
56                println!("[worker {t}] function[{idx}] @ {address}  {name}");
57            }));
58        }
59        for h in hs {
60            h.join().unwrap();
61        }
62
63        ida.call(|idb| idb.close(false))?;
64        Ok(())
65    })??;
66
67    println!("\nACTOR OK (kernel on its own thread; calls marshaled from app + 4 workers)");
68    Ok(())
69}