diff options
| author | blasty <blasty@local> | 2026-07-10 14:03:16 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-07-10 14:03:16 +0200 |
| commit | 636a6cb34e83523c3c513fb62ca39e0f6c10098f (patch) | |
| tree | b89473666f9cb2991b0f42dd105f00de6fb4a863 /tests | |
| parent | retype: set variable/function types with 'y' (IDA-style), via structured tools (diff) | |
| download | ida-tui-636a6cb34e83523c3c513fb62ca39e0f6c10098f.tar.gz ida-tui-636a6cb34e83523c3c513fb62ca39e0f6c10098f.tar.xz ida-tui-636a6cb34e83523c3c513fb62ca39e0f6c10098f.zip | |
hex view: raw image bytes (VA-addressed), synced to the code cursor
New HexView: a line-virtualized 16-bytes/row dump of the whole loaded image,
addressed by virtual address. Format-agnostic — the range/segments come from IDA
(image_range over sections()), not any file header; gaps read back as zeros.
Backslash toggles it, synced to the address under the disasm/pseudocode cursor
(see the naked bytes of some code/data). In hex: hjkl/paging navigate a byte
cursor (status shows the section), Enter jumps the code view to the byte,
Tab/Esc/backslash return to the preferred code view. A third _active state; block
-cached + prefetched like the disasm model.
domain: HexModel + Program.hex_model/read_bytes/image_range (get_bytes regions).
Fixed a self-deadlock (hex_model held _lock while sections() re-locked).
Pilot: sync, actual bytes, byte-step, return. full suite 98/98.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_tui.py | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/tests/test_tui.py b/tests/test_tui.py index 84037a2..6d77fc2 100644 --- a/tests/test_tui.py +++ b/tests/test_tui.py @@ -19,8 +19,8 @@ import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from idatui.app import ( # noqa: E402 - ConfirmScreen, DecompView, DisasmView, FunctionsPanel, IdaTui, StructEditor, - SymbolPalette, XrefsScreen, + ConfirmScreen, DecompView, DisasmView, FunctionsPanel, HexView, IdaTui, + StructEditor, SymbolPalette, XrefsScreen, ) from textual.widgets import DataTable, Input, OptionList, Static, TextArea # noqa: E402 from rich.text import Text # noqa: E402 @@ -310,6 +310,32 @@ async def run(db): check("goto-bottom lands near end", view.cursor >= view.total - 1, f"cursor={view.cursor}/{view.total}") + # Hex view: backslash shows the raw image bytes synced to the code cursor. + view.focus() + code_ea = view._cursor_ea() + await pilot.press("backslash") + await wait_until(pilot, lambda: app._active == "hex", 10) + hx = app.query_one(HexView) + await wait_until( + pilot, lambda: hx.model is not None + and hx.model.row(hx.cursor // 16)[1] is not None, 20) + check("backslash opens the hex view synced to the code cursor", + app._active == "hex" and code_ea is not None and hx.cursor_va() == code_ea, + f"active={app._active} hexva={hx.cursor_va():#x} ea={code_ea}") + want = app.program.read_bytes(code_ea, 1) + _, rb = hx.model.row(hx.cursor // 16) + check("hex shows the actual byte at that address", + rb is not None and rb[hx.cursor % 16] == want[0], + f"got={rb[hx.cursor % 16] if rb else None} want={want[0]}") + await pilot.press("l") + await pilot.pause(0.1) + check("hex cursor steps one byte", hx.cursor_va() == code_ea + 1, + f"va={hx.cursor_va():#x}") + await pilot.press("backslash") # back to the code view + await wait_until(pilot, lambda: app._active != "hex", 10) + check("backslash returns from hex to the code view", + app._active == "disasm", f"active={app._active}") + # Filter round-trip. '/' is context-sensitive: it filters when the # function table is focused (and searches when a code view is focused), # so focus the table first. |
