diff options
| author | blasty <blasty@local> | 2026-07-24 23:38:30 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-07-24 23:38:30 +0200 |
| commit | de2fa194278bb132e23edddd65bdad84f32ec37d (patch) | |
| tree | 67d18789676b3377892d3edf4a6fbe4d497967af /idatui/domain.py | |
| parent | split-view phase 2: cursor sync + linked-row highlight (diff) | |
| download | ida-tui-de2fa194278bb132e23edddd65bdad84f32ec37d.tar.gz ida-tui-de2fa194278bb132e23edddd65bdad84f32ec37d.tar.xz ida-tui-de2fa194278bb132e23edddd65bdad84f32ec37d.zip | |
split-view phase 3: rich per-line instruction region highlight
The Ghidra "region band": moving the pseudocode cursor now lights up EVERY
instruction that C line owns, not just one.
* server/patch_server.py: new decomp_map tool — sweeps cfunc.get_line_item across
each pseudocode line's columns and collects the ea from each item's dstr()
('EA: desc', matching the /*ea*/ marker source so it aligns with the display
lines). Returns {addr, lines:[{ea, eas:[...]}]}. (First tried item.get_ea(),
which reports a different ea and didn't align — dstr() is the right source.)
* domain: Program.decomp_map(ea) -> per-line ea lists, cached by name-gen.
* app: _load_split_map fetches it off-thread into _split_eamap/_split_ea2line;
_sync_split bands the full instruction region for a C line (decomp drives) and
uses the exact ea->line inverse (listing drives), falling back to the single
marker until the map lands. Maps cleared on leaving split.
Pilot split_view gains: decomp_map returns/aligns with the markers, and a
multi-instruction C line bands >1 listing row (13/13). Full suite 154/2-flake.
The idalib spike ran on the pilot's own worker (the standalone worker kept
getting reaped in this sandbox).
Diffstat (limited to 'idatui/domain.py')
| -rw-r--r-- | idatui/domain.py | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/idatui/domain.py b/idatui/domain.py index 8a127d7..1bf62ed 100644 --- a/idatui/domain.py +++ b/idatui/domain.py @@ -807,6 +807,7 @@ class Program: self._disasm: dict[int, DisasmModel] = {} self._listings: dict[int, ListingModel] = {} # keyed by segment start self._decomp: dict[int, tuple[Decompilation, int]] = {} + self._decomp_maps: dict[int, tuple[list[list[int]], int]] = {} # line->ea sets self._name_gen = 0 # bumped on rename; invalidates stale name caches self._segments_cache: list[tuple[int, int, int, str]] | None = None self._sections: list[tuple[int, int, str]] | None = None @@ -1245,6 +1246,27 @@ class Program: except Exception: # noqa: BLE001 -- fall back to the truncated preview return None + def decomp_map(self, ea: int) -> list[list[int]]: + """Per-pseudocode-line instruction coverage for the split-view region + highlight: a list aligned to the decompiled lines, each the EAs the + decompiler attributes to that line (may be empty). Cached per function + + name generation; ``[]`` if the tool is unavailable.""" + with self._lock: + hit = self._decomp_maps.get(ea) + gen = self._name_gen + if hit is not None and hit[1] == gen: + return hit[0] + try: + payload = self.client.call("decomp_map", addr=hex(ea)) + except IDAToolError: + return [] + lines = payload.get("lines", []) if isinstance(payload, dict) else [] + out = [[_as_int(e) for e in (ln.get("eas") or [])] + for ln in lines if isinstance(ln, dict)] + with self._lock: + self._decomp_maps[ea] = (out, gen) + return out + # -- cross-references & containing function --------------------------- # def function_of(self, ea: int) -> Func | None: """Return the function containing ``ea`` (resolves mid-function addrs).""" |
