diff options
| author | blasty <blasty@local> | 2026-07-09 15:36:12 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-07-09 15:36:12 +0200 |
| commit | 6a8e022441c973bbdfb1c4ee0f55373ebf1d1456 (patch) | |
| tree | 6075f908ee4c7d0d02aa0a86ca09332a9057cbda /idatui/domain.py | |
| parent | paging: preserve the cursor's viewport-relative row (IDA-style) (diff) | |
| download | ida-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.py | 28 |
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).""" |
