aboutsummaryrefslogtreecommitdiffstats
path: root/docs/CODEMODE_PORT.md
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-08-07 12:39:54 +0200
committerblasty <blasty@local>2026-08-07 12:40:14 +0200
commitc9208de05d8583b677117fe43c9d3567e89eb2ce (patch)
tree8f7b7487d9939be31b7c2b1a7932ee3a16c7403d /docs/CODEMODE_PORT.md
parentStop tracking 157MB of core dumps, and ignore them (diff)
downloadida-tui-c9208de05d8583b677117fe43c9d3567e89eb2ce.tar.gz
ida-tui-c9208de05d8583b677117fe43c9d3567e89eb2ce.tar.xz
ida-tui-c9208de05d8583b677117fe43c9d3567e89eb2ce.zip
Rebase MISTER EXO's ida-codemode port onto the current tree
Mechanical part of the port: the 27-file patch was cut against a base ~148 commits behind us, so it did not apply. Resolved 11 conflicts (all of them diff drift, not semantic clashes) and the three file deletions: - app.py: the patch re-inserted _do_rename/_do_name_addr/_seek_split etc. as "theirs" because our tree moved them to edit_ctl.py/trace_ctl.py. Kept ours and applied the real intent (WorkerClient->CodeModeClient, .call->.invoke, _open_worker_client->_open_database_client) at their current homes. - domain.py: kept Head as a NamedTuple -- the patch reverted it to a frozen dataclass, which the perf work measured at 2.9us vs 1.9us per row on a quarter-million-row walk. Dropped _fetch_output (no download_url under Code Mode) and its now-dead urllib/json imports. - pane.py: the patch's deletion swallowed our zellij support along with the worker-reaping block it meant to remove. Kept zellij, removed the reaping. - test_scenarios.py: the idb_save->save_database teardown hunk belongs to tests/_fixtures.py in our tree; applied it there and kept our pc_num_format scenario that the drift landed on. Three defects in the patch itself, fixed here: - It made "import idatui" hard-require ida_codemode, so every offline suite died at import -- including the pure ones (graph/index/trace) that are the house rule for "tests/run.py --fast". The import is now deferred and gated on the binding, which is also what lets the port's own contract tests inject a fake DatabaseHandle. - project.stage() inlined an ida_codemode.registry import and treated "library not installed" as "someone owns this database", which broke IDA-free project staging. Ownership lookup moved to codemode_client.database_owner(). - tests/test_codemode_client.py had no NEEDS_IDA marker, which tests/run.py rejects outright. Offline suite: 301 passed, 0 failed. Against master's 344 the whole delta is accounted for: -40 worker_client (module deleted), -18 launch sweep checks (behaviour deliberately removed) +3 guarding that it stays removed, +2 pool (GUI-save semantics), +13 new codemode_client contract tests. NOT yet done, and the port is not functional without it: the adapter is missing five operations our tree grew since the patch's base (flowchart, op_format, pc_nums, pc_num_format, survey_binary) and its "heads" predates back-walking and digest/expect.
Diffstat (limited to 'docs/CODEMODE_PORT.md')
-rw-r--r--docs/CODEMODE_PORT.md175
1 files changed, 175 insertions, 0 deletions
diff --git a/docs/CODEMODE_PORT.md b/docs/CODEMODE_PORT.md
new file mode 100644
index 0000000..4b4bc45
--- /dev/null
+++ b/docs/CODEMODE_PORT.md
@@ -0,0 +1,175 @@
+# ida-tui → IDA Code Mode port
+
+This port is an experiment: can ida-tui be implemented as an ordinary client of
+`ida_codemode`, sharing GUI databases and managed idalib workers instead of
+owning a private worker and depending on ida-pro-mcp tool functions?
+
+## Result
+
+Yes for the database lifecycle and the complete current TUI feature set, with a
+small number of operations implemented using IDAPython inside Code Mode's
+`execute_python` sandbox because ida-domain does not yet expose the required
+behavior.
+
+The old components are gone:
+
+- `idatui/worker.py` (private pickle/socket idalib process)
+- `idatui/worker_client.py`
+- `server/patch_server.py` (ida-pro-mcp tool injection)
+
+The replacement is `idatui/codemode_client.py`.
+
+## Lifecycle mapping
+
+`CodeModeClient.connect()` calls `ida_codemode.client.DatabaseHandle.open()`.
+Resolution is therefore Code Mode's resolution, not ida-tui's:
+
+1. Match a registered GUI by executable path.
+2. Otherwise match the owner of the expected IDB.
+3. Otherwise serialize creation and start a managed `ida-codemode-worker`.
+4. Establish an authenticated SSE lease.
+5. Wait through the public autoanalysis route.
+
+The handle's registry entry supplies the backend, PID, executable path, IDB path,
+and record ID used by the status/pool layers.
+
+Closing ida-tui closes only its lease. It never closes a GUI or kills an idalib
+process. A managed worker saves and exits under Code Mode's own policy after its
+last lease disappears. A second agent or TUI can keep using the same instance.
+
+This also changes project pooling semantics. `DatabasePool` is an LRU pool of
+leases, not process ownership. Managed-IDB save-on-evict remains; budget eviction
+does not implicitly save a GUI. Eviction cannot force a shared worker to exit,
+and GUI process memory is only advisory.
+
+## ida-domain coverage
+
+The remote snippets receive Code Mode's preloaded `db` (`ida_domain.Database`).
+The following TUI needs map to public ida-domain entities:
+
+| TUI need | ida-domain surface |
+|---|---|
+| Function paging, lookup, names, sizes | `db.functions` |
+| Segments and names | `db.segments` |
+| Instructions and plain disassembly | `db.instructions`, `db.functions.get_instructions()` |
+| Heads and item classification | `db.heads`, `db.bytes` |
+| Bytes and strings | `db.bytes`, `db.strings` |
+| Symbol resolution and rename | `db.names`, `db.functions` |
+| Comments | `db.comments` |
+| Imports and exports | `db.imports`, `db.entries` |
+| Xrefs and fine type predicates | `db.xrefs` / `XrefInfo` |
+| Named types, members, parse/apply | `db.types` |
+| Function prototypes and local variables | `db.pseudocode`, `PseudocodeFunction.local_variables` |
+| Decompilation text and object references | `db.pseudocode` |
+
+All values are reduced to JSON primitives inside the database process. No SWIG
+or ida-domain object crosses the Code Mode boundary.
+
+## Remaining IDAPython gaps
+
+Code Mode intentionally allows regular Python imports, so these features still
+work, but they identify useful additions to ida-domain:
+
+1. **Rich continuous listing**
+ - ida-domain enumerates defined heads and renders plain disassembly.
+ - ida-tui also needs coalesced undefined runs, IDA colour-tag spans, function
+ banners, code-label rows, file-region offsets, and expanded struct members.
+ - The `heads` operation uses `ida_bytes`, `ida_lines`, and related modules for
+ this presentation model.
+
+2. **Instruction/function carving**
+ - Creating an instruction and walking a speculative decode run requires
+ `ida_ua.create_insn` and processor flow/return checks.
+ - Function creation exists in ida-domain; the explicit-end fallback still
+ needs lower-level item boundaries.
+
+3. **ARM/Thumb state**
+ - T-register ranges and segment addressing use `ida_segregs`, `ida_idp`, and
+ `ida_segment`. There is no equivalent ida-domain operation.
+
+4. **Detailed decompiler diagnostics and line maps**
+ - Pseudocode text, ctree objects, and the address map are available through
+ ida-domain.
+ - Reproducing IDA's per-rendered-line coverage uses
+ `cfunc.get_line_item`; obtaining the exact Hex-Rays failure description
+ uses `hexrays_failure_t`.
+
+5. **A few type/item primitives**
+ - Deleting a named local type and some exact item-undefinition/data-creation
+ behavior still use `ida_typeinf`/`ida_bytes` directly.
+
+These uses are isolated in `idatui/codemode_client.py`; the paging and Textual
+layers do not import IDAPython.
+
+## API limitations exposed by the port
+
+### No rollback or close-without-save
+
+A Code Mode lease has no rollback operation. Closing a GUI handle leaves the GUI
+state as-is. A managed idalib worker currently saves when its final lease closes.
+Consequently ida-tui's old “discard & quit” guarantee cannot be implemented.
+The UI now labels this choice “leave as-is & quit” and does not explicitly save,
+but managed-worker policy may still persist the changes.
+
+A true discard action would need a Code Mode/database API for transaction-like
+rollback, a close policy on a newly-owned worker, or a TUI-managed disposable DB
+copy.
+
+### Typed loader options only
+
+`DatabaseHandle.open()` supports processor, natural loading address, file type,
+output database, and fresh-database selection. It does not support ida-tui's
+arbitrary `ida_args` escape hatch. The adapter rejects unsupported switches
+rather than silently loading at the wrong architecture/base.
+
+### No database-change notification stream
+
+The lease reports liveness, not mutations. If a GUI user or another Code Mode
+client renames/retypes content while ida-tui is open, already-materialized TUI
+caches are not invalidated automatically. TUI-originated edits invalidate their
+own caches correctly. A database revision counter or change feed would make
+shared interactive editing robust.
+
+### Discovery requires a path for ambiguity
+
+`ida-tui` with no path attaches automatically when exactly one database is
+registered. With several registrations it lists them and requires an explicit
+executable/IDB path. There is not yet a pre-connection database picker in the
+Textual UI.
+
+### `DatabaseHandle` import stability
+
+The usable library primitive currently lives at
+`ida_codemode.client.DatabaseHandle`; `ida_codemode.__init__` exports nothing.
+The port therefore depends on a submodule path. Exporting the handle and public
+client exceptions from the package root would make the supported library API
+clearer.
+
+## Safety differences
+
+ida-tui no longer removes `.id0/.id1/.id2/.nam/.til` files before opening. That
+was only defensible when the TUI exclusively owned a private process; it is
+unsafe when a GUI or another client may own the database. Code Mode registry
+locks, health probes, and IDA itself now arbitrate ownership.
+
+The old pane “reap private workers” behavior is obsolete. A TUI crash closes its
+lease at the socket/kernel boundary; Code Mode decides whether a managed worker
+still has clients and when it should stop.
+
+## Verification surfaces
+
+The non-IDA suite verifies project staging, LRU lease behavior, load-option
+translation, and adapter response/error normalization. The existing live suites
+remain the end-to-end contract:
+
+```sh
+uv run python tests/test_codemode_client.py
+uv run python tests/test_pool.py
+uv run python tests/test_project.py
+uv run python tests/test_scenarios.py /path/to/binary
+```
+
+For GUI reuse, open the same binary in an IDA with the Code Mode plugin, confirm
+it appears in `ida_codemode.registry.discover_instances()`, then launch
+`ida-tui /path/to/binary`. The TUI status/`CodeModeClient.backend` should report
+`gui`, and closing the TUI must leave IDA open.