aboutsummaryrefslogtreecommitdiffstats
path: root/idatui/drive.py
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-01 17:18:57 +0200
committeruser <user@clank>2026-08-01 17:18:57 +0200
commit14ca7c7e5c56c3fdd059d168957a2b2e3dbe504e (patch)
tree7cc8ea9637b7998fc1da3b4e428a1e39537903fa /idatui/drive.py
parenttests: trace integration over the RPC socket (45 checks) (diff)
downloadida-tui-14ca7c7e5c56c3fdd059d168957a2b2e3dbe504e.tar.gz
ida-tui-14ca7c7e5c56c3fdd059d168957a2b2e3dbe504e.tar.xz
ida-tui-14ca7c7e5c56c3fdd059d168957a2b2e3dbe504e.zip
rpc: make a raw firmware image drivable (load options, define, bulk symbols)
Opening a headerless blob was the one workflow that fell out of the driving surface entirely, and each gap hid the next: - `pane spawn` couldn't pass --processor/--base/--ida-args, so the pane came up "ready" with zero functions (x86 at 0) and the only way through was to hand-write a project file. It now forwards them to idatui.launch. - c/p/t/T (code, function, ARM<->Thumb, vector scan) existed as listing bindings with no verb, so a driver had to guess raw keys -- and raw keys are swallowed by whatever modal happens to be up. `define {kind,target?}` goes through the app's own edit worker and reports what IDA actually did. - every name went through the typed rename prompt: a navigation (listing page + decompile) plus two prompt round-trips each. A 427-symbol map took tens of minutes of driving. `rename_many {items|file}` hands IDA's rename tool the whole list in one call (371 symbols in 3s) and refreshes the caches and the function table once. drive gains `define <kind> [target...]` and `syms <file.json>`. Verified live against a real pane (tests/test_rawimage_rpc.py, 13 checks: spawn load options, define thumb/func + unknown-kind rejection, rename_many from a file and inline, with resolve/functions readback).
Diffstat (limited to 'idatui/drive.py')
-rw-r--r--idatui/drive.py36
1 files changed, 35 insertions, 1 deletions
diff --git a/idatui/drive.py b/idatui/drive.py
index b6fa641..0e82b0d 100644
--- a/idatui/drive.py
+++ b/idatui/drive.py
@@ -233,6 +233,39 @@ def cmd_retype(c, args):
return _fmt_where(st)
+def cmd_define(c, args):
+ """define <kind> [target ...] — the raw-image workflow (thumb/code/func).
+
+ Several targets are common on a firmware image (a list of entry points from
+ a symbol file), so take them all and report per-target.
+ """
+ if not args:
+ raise SystemExit("usage: define <code|func|undef|thumb|thumbscan|data|"
+ "string> [target ...]")
+ kind, targets = args[0], (args[1:] or [None])
+ out = []
+ for t in targets:
+ try:
+ st = c.call("define", kind=kind, **({"target": t} if t else {}))
+ out.append(f" {t or '.'}: {st.get('status', '')}")
+ except RpcError as e:
+ out.append(f" {t or '.'}: FAILED: {e}")
+ return "\n".join(out)
+
+
+def cmd_syms(c, args):
+ """syms <file.json> — bulk-apply a symbol file ([{addr|start|ea, name}])."""
+ if len(args) != 1:
+ raise SystemExit("usage: syms <symbols.json>")
+ r = c.call("rename_many", file=os.path.abspath(os.path.expanduser(args[0])))
+ m = r.get("rename_many", {})
+ out = [f" {m.get('ok', 0)}/{m.get('requested', 0)} renamed"
+ f" (skipped {m.get('skipped', 0)}, failed {m.get('failed', 0)})"]
+ for e in m.get("errors", []):
+ out.append(f" {e.get('addr')}: {e.get('error')}")
+ return "\n".join(out)
+
+
def cmd_save(c, args):
c.call("save")
return " saved"
@@ -256,7 +289,8 @@ COMMANDS = {
"where": cmd_where, "go": cmd_go, "pc": cmd_pc, "dis": cmd_dis,
"callees": cmd_callees, "callers": cmd_callers, "names": cmd_names,
"rename": cmd_rename, "mv": cmd_mv, "note": cmd_note, "retype": cmd_retype,
- "save": cmd_save, "screen": cmd_screen, "raw": cmd_raw,
+ "save": cmd_save, "screen": cmd_screen, "raw": cmd_raw, "define": cmd_define,
+ "syms": cmd_syms,
"binaries": cmd_binaries, "switch": cmd_switch,
}