aboutsummaryrefslogtreecommitdiffstats
path: root/idatui/domain.py
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-09 15:36:12 +0200
committerblasty <blasty@local>2026-07-09 15:36:12 +0200
commit6a8e022441c973bbdfb1c4ee0f55373ebf1d1456 (patch)
tree6075f908ee4c7d0d02aa0a86ca09332a9057cbda /idatui/domain.py
parentpaging: preserve the cursor's viewport-relative row (IDA-style) (diff)
downloadida-tui-6a8e022441c973bbdfb1c4ee0f55373ebf1d1456.tar.gz
ida-tui-6a8e022441c973bbdfb1c4ee0f55373ebf1d1456.tar.xz
ida-tui-6a8e022441c973bbdfb1c4ee0f55373ebf1d1456.zip
fix input visibility (search/rename) + refresh stale names across history
- Visibility: #search/#rename/#status were dock:bottom like the Footer and got placed on the SAME row (y=39) as the Footer, which drew over them, so the typed text was invisible. Drop the docking; they now sit in normal flow just above the Footer (y=38). Verified: input region is above the footer. - Stale names on 'back': a rename only invalidated the current function, so popping back to a caller (cached earlier) showed the old name. Add Program.bump_names(): a rename bumps a name-generation, clears all disasm block caches (disasm names are live), and decompilation is generation-checked and force-recompiled lazily on next view. _after_rename now invalidates globally. - verified: rename a callee, 'back' to the caller shows the new name. - pilot suite 51/51.
Diffstat (limited to 'idatui/domain.py')
-rw-r--r--idatui/domain.py28
1 files changed, 24 insertions, 4 deletions
diff --git a/idatui/domain.py b/idatui/domain.py
index b219bbe..1f52be6 100644
--- a/idatui/domain.py
+++ b/idatui/domain.py
@@ -374,7 +374,8 @@ class Program:
)
self._indices: dict[str | None, FunctionIndex] = {}
self._disasm: dict[int, DisasmModel] = {}
- self._decomp: dict[int, Decompilation] = {}
+ self._decomp: dict[int, tuple[Decompilation, int]] = {}
+ self._name_gen = 0 # bumped on rename; invalidates stale name caches
self._lock = threading.Lock()
# -- prefetch plumbing ------------------------------------------------- #
@@ -417,8 +418,17 @@ class Program:
if not refresh:
with self._lock:
hit = self._decomp.get(ea)
- if hit is not None:
- return hit
+ gen = self._name_gen
+ if hit is not None:
+ dec, hit_gen = hit
+ if hit_gen == gen:
+ return dec
+ # Cached before a rename: names may be stale. Drop the server's
+ # Hex-Rays cache so the refetch reflects the new names.
+ try:
+ self.client.call("force_recompile", addr=hex(ea))
+ except Exception: # noqa: BLE001
+ pass
envelope = self.client.call_envelope("decompile", addr=hex(ea))
result = envelope.get("result", {})
payload = result.get("structuredContent")
@@ -431,9 +441,19 @@ class Program:
payload = full
dec = _parse_decompilation(ea, payload)
with self._lock:
- self._decomp[ea] = dec
+ self._decomp[ea] = (dec, self._name_gen)
return dec
+ def bump_names(self) -> None:
+ """Signal that symbol names changed (a rename). Disasm names are live in
+ the IDB, so clearing the block caches is enough for those; decompilation
+ is generation-checked and force-recompiled lazily on next access."""
+ with self._lock:
+ self._name_gen += 1
+ models = list(self._disasm.values())
+ for m in models:
+ m.invalidate()
+
@staticmethod
def _fetch_output(url: str, timeout: float = 15.0):
"""GET the server's cached full-output blob (plain HTTP, not MCP)."""