aboutsummaryrefslogtreecommitdiffstats
path: root/idatui
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-09 20:34:16 +0200
committerblasty <blasty@local>2026-07-09 20:34:16 +0200
commit7bac15cc8ca641095c4782d43c9a53fef5b39dba (patch)
tree8ba3dd06a3f856b774ca9b48518df397c5f6a095 /idatui
parenttest: fix stale row/function reuse across filter + xref-select blocks (diff)
downloadida-tui-7bac15cc8ca641095c4782d43c9a53fef5b39dba.tar.gz
ida-tui-7bac15cc8ca641095c4782d43c9a53fef5b39dba.tar.xz
ida-tui-7bac15cc8ca641095c4782d43c9a53fef5b39dba.zip
decompiler: xref-select jumps to the reference line in pseudocode
Selecting an xref (or any address navigation) only positioned the disasm cursor (NavEntry.cursor via index_of_ea); the pseudocode pane's dec_cursor stayed 0, so in the decompiler view the jump landed at the top of the target function instead of on the referencing line. When the decompiler pane is active, resolve the target ea to its pseudocode line via the per-line /*0xEA*/ markers (_decomp_line_for) and seed NavEntry.dec_cursor so _apply_decomp lands + scrolls there. Add a pilot check for it. Also halve the literal pilot.pause() settle delays in the suite (wait_until poll step untouched): 40s -> 34.6s wall, stable across 3 runs.
Diffstat (limited to 'idatui')
-rw-r--r--idatui/app.py31
1 files changed, 29 insertions, 2 deletions
diff --git a/idatui/app.py b/idatui/app.py
index 234cfc8..ba463e2 100644
--- a/idatui/app.py
+++ b/idatui/app.py
@@ -1566,12 +1566,39 @@ class IdaTui(App):
return
model = self.program.disasm(fn.addr, fn.name)
idx = 0 if ea == fn.addr else model.index_of_ea(ea)
- self.app.call_from_thread(self._open_at, fn.addr, fn.name, idx, push)
+ # The disasm cursor alone doesn't position the pseudocode pane. When it's
+ # the active view, also resolve the target address to its pseudocode line
+ # (via the per-line /*0xEA*/ markers) so the jump lands on the reference
+ # there too (e.g. selecting an xref while in the decompiler view).
+ dec_idx = self._decomp_line_for(fn.addr, ea) if self._active == "decomp" else -1
+ self.app.call_from_thread(self._open_at, fn.addr, fn.name, idx, push, dec_idx)
- def _open_at(self, ea: int, name: str, cursor: int, push: bool) -> None:
+ def _decomp_line_for(self, fn_addr: int, ea: int) -> int:
+ """Pseudocode line index best matching address ``ea``: the line whose
+ /*0xEA*/ marker is the largest address <= ``ea``. -1 if unavailable
+ (decompile failed / no markers). Runs in a worker (decompile is sync)."""
+ assert self.program is not None
+ try:
+ dec = self.program.decompile(fn_addr)
+ except Exception: # noqa: BLE001
+ return -1
+ if dec.failed or not dec.code:
+ return -1
+ best_idx, best_ea = -1, -1
+ for i, line in enumerate(dec.code.splitlines()):
+ for m in re.findall(r"/\*\s*0x([0-9A-Fa-f]+)\s*\*/", line):
+ e = int(m, 16)
+ if best_ea < e <= ea:
+ best_ea, best_idx = e, i
+ return best_idx
+
+ def _open_at(self, ea: int, name: str, cursor: int, push: bool,
+ dec_cursor: int = -1) -> None:
if push:
self._save_current_pos()
entry = NavEntry(ea=ea, name=name, cursor=cursor)
+ if dec_cursor >= 0:
+ entry.dec_cursor = dec_cursor
if push:
self._nav.append(entry)
self._open_entry(entry, push=False)