aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-09 20:07:26 +0200
committerblasty <blasty@local>2026-07-09 20:07:26 +0200
commita9546714a18fea954bea2ee12817247697b10d09 (patch)
treeb70ede3bbb132b34cb8666ebe9c28a6132512244
parentfix: xref-select navigated to the wrong place (ordinary-flow contamination) (diff)
downloadida-tui-a9546714a18fea954bea2ee12817247697b10d09.tar.gz
ida-tui-a9546714a18fea954bea2ee12817247697b10d09.tar.xz
ida-tui-a9546714a18fea954bea2ee12817247697b10d09.zip
fix: disasm follow stepped to the next line on a call (fall-through edge)
xrefs_from on a call/branch returns the ordinary fall-through edge (target == the next instruction) as an indistinguishable type=code xref, and _follow_disasm picked the first code edge -> 'follow' just advanced one line instead of entering the callee (e.g. Enter on 'call cs:memset_ptr' stayed in the same function). Plumb the next instruction's ea from the view and drop the edge whose target is that next instruction, so follow lands on the real call/jump target. Mirrors the ordinary-flow fix already applied to the xrefs path (e6375de).
-rw-r--r--idatui/app.py17
1 files changed, 13 insertions, 4 deletions
diff --git a/idatui/app.py b/idatui/app.py
index 76f9943..234cfc8 100644
--- a/idatui/app.py
+++ b/idatui/app.py
@@ -1288,8 +1288,12 @@ class IdaTui(App):
word = view.word_under_cursor()
if isinstance(view, DisasmView):
ea = view._cursor_ea()
+ # The instruction's ordinary fall-through edge (to the next line) is
+ # an indistinguishable 'code' xref; pass it so follow can skip it and
+ # land on a call/jump's real target instead of the next instruction.
+ nxt = view.model.cached_line(view.cursor + 1) if view.model else None
if ea is not None:
- self._follow_disasm(ea, word)
+ self._follow_disasm(ea, word, nxt.ea if nxt else None)
elif isinstance(view, DecompView) and view._texts:
self._follow_decomp(view._texts[view.cursor], word)
@@ -1312,7 +1316,8 @@ class IdaTui(App):
return not all(c in "0123456789abcdefABCDEF" for c in word)
@work(thread=True, group="nav")
- def _follow_disasm(self, ea: int, word: str | None) -> None:
+ def _follow_disasm(self, ea: int, word: str | None,
+ next_ea: int | None = None) -> None:
assert self.program is not None
# Prefer the symbol under the cursor (handles multiple refs on a line).
if self._looks_like_symbol(word):
@@ -1322,8 +1327,12 @@ class IdaTui(App):
except Exception: # noqa: BLE001 -- not a resolvable name; fall back
pass
xr = self.program.xrefs_from(ea)
- tgt = next((x for x in xr if x.type == "code" and x.to), None)
- tgt = tgt or next((x for x in xr if x.to), None)
+ # Drop the ordinary fall-through edge (its target is the next
+ # instruction): on a call/branch it would otherwise be picked before the
+ # real target and 'follow' would just step to the next line.
+ cand = [x for x in xr if x.to and x.to != next_ea]
+ tgt = next((x for x in cand if x.type == "code"), None)
+ tgt = tgt or next((x for x in cand), None)
if tgt is None or tgt.to is None:
self.app.call_from_thread(self._status, "nothing to follow here")
return