diff options
| author | blasty <blasty@local> | 2026-07-28 14:55:22 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-07-28 14:55:22 +0200 |
| commit | 3dc262265240a2c63b9e88574feb8952c687ec14 (patch) | |
| tree | 7369a6af04a71d98bc14f2c843857f433e1937d7 | |
| parent | status: name the open file (diff) | |
| download | ida-tui-3dc262265240a2c63b9e88574feb8952c687ec14.tar.gz ida-tui-3dc262265240a2c63b9e88574feb8952c687ec14.tar.xz ida-tui-3dc262265240a2c63b9e88574feb8952c687ec14.zip | |
trace: stepping stays in the view you're reading
Caught while demoing this in a live pane, not by a test: press Tab to read the
pseudocode, press ] once, and you're back in the disassembly.
_seek() follows the trace by navigating to the new PC, and navigating to an
ADDRESS opens the listing unless the decompiler is explicitly preferred. So
every step out of C dropped you out of C — the painting work of the last commit
was unusable in the view it was built for, from the first keypress.
_seek now passes prefer_decomp=(self._active == "decomp"), the same thing the
xref handler already does for the same reason.
Worth noting what it looks like when it works: stepping in pseudocode follows
execution INTO a callee and the view switches to that function's C, which is
what you want and what makes the decompiler painting worth having.
tests: +2 trace UI (23) asserting the view survives a step in both directions.
212/0 scenarios.
| -rw-r--r-- | idatui/app.py | 7 | ||||
| -rw-r--r-- | tests/test_trace_ui.py | 14 |
2 files changed, 20 insertions, 1 deletions
diff --git a/idatui/app.py b/idatui/app.py index cc9cfa3..0fb1030 100644 --- a/idatui/app.py +++ b/idatui/app.py @@ -5495,7 +5495,12 @@ class IdaTui(App): self.query_one(TraceDock).show(t, self._t) self._paint_trail() if follow: - self._goto_ea(t.ip(self._t), push=False) + # Stay in whichever view you're reading. Without prefer_decomp a + # step from the pseudocode navigates to an address, which opens the + # listing — so stepping through C threw you out of C on the first + # keypress. + self._goto_ea(t.ip(self._t), push=False, + prefer_decomp=(self._active == "decomp")) def _paint_trail(self) -> None: """Push the execution trail into the code views. diff --git a/tests/test_trace_ui.py b/tests/test_trace_ui.py index a85c089..a43c11d 100644 --- a/tests/test_trace_ui.py +++ b/tests/test_trace_ui.py @@ -194,6 +194,20 @@ async def run() -> int: t.ip(app._t) in covered, f"pc={t.ip(app._t):#x} line covers {[hex(a) for a in covered][:4]}") + # Stepping must not throw you out of the view you're reading. + # A step navigates to an address, and navigating to an address + # opens the LISTING unless the decompiler is preferred — so + # stepping through C used to drop you into disassembly on the + # first keypress. Found by watching a demo, not by a test. + await pilot.press("]") + await pilot.pause(1.2) + check("stepping in pseudocode stays in pseudocode", + app._active == "decomp", f"active={app._active}") + await pilot.press("[") + await pilot.pause(1.2) + check("and so does stepping backward", + app._active == "decomp", f"active={app._active}") + print(f"\n{PASS} passed, {FAIL} failed") return 1 if FAIL else 0 |
