From d59b46715aa207bd0d7addadc33f00fb257d7fc5 Mon Sep 17 00:00:00 2001 From: blasty Date: Wed, 22 Jul 2026 23:43:16 +0200 Subject: app: ListingView — virtualized flat code+data listing for regions (M2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The real disassembly-listing view. ListingView is a line-virtualized ScrollView (reusing ColumnCursor/SearchMixin/NavMixin) backed by ListingModel, rendering code, data (db/dw/dd, strings, jump tables) and undefined bytes interleaved with per-kind styling. Non-function regions now open in it instead of the M0 DisasmModel stopgap. Integration (IdaTui): a new `listing` active mode. _open_entry routes region entries to ListingView; _show_active/compose add it; follow/xrefs/comment and the c/p/u edit verbs handle it (define_func upgrades a region straight to the function view); backslash reaches hex and returns via _code_mode (so leaving hex from a region lands back on the listing, not a func view); Tab explains there's no pseudocode for a region. rpc._active_widget learns `listing`. Server fix (the important one): the `heads` walker now steps by get_item_end instead of next_head. next_head SKIPS undefined bytes, so after undefining a function its start address wasn't even a listing line and the cursor snapped to the next defined item; stepping by item-end renders undefined bytes as `db ?` lines (IDA-accurate) and makes navigation land exactly on any address — essential for "go to unmarked bytes and hit c". Needs a supervisor restart. Tests: region_define rewritten to assert the ListingView path + segment-wide listing + p-upgrade; new listing_view scenario (data-segment listing renders data heads, cursor reports head ea, backslash->hex->back). Pilot 115 pass / 1 pre-existing flaky (filter); rpc_smoke 29/0; test_domain 27/0. --- server/patch_server.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'server/patch_server.py') diff --git a/server/patch_server.py b/server/patch_server.py index a13e6cd..3e5193b 100644 --- a/server/patch_server.py +++ b/server/patch_server.py @@ -262,18 +262,26 @@ def heads( cursor = {"done": True} if pea == idaapi.BADADDR or pea < lo else {"prev": hex(pea)} return {"addr": str(addr), "heads": rows, "cursor": cursor} + # Walk by item END (not next_head): next_head SKIPS undefined bytes, but a + # flat listing must show them (IDA renders undefined as `db ?` lines, and + # navigating to an unmarked address must land ON it). get_item_end steps by + # the item's size for code/data and by 1 through undefined bytes. + def _step(e): + nxt = ida_bytes.get_item_end(e) + return nxt if nxt > e else e + 1 + ea = ida_bytes.get_item_head(start) for _ in range(offset): if ea >= hi or ea == idaapi.BADADDR: break - ea = ida_bytes.next_head(ea, hi) + ea = _step(ea) more = False while ea != idaapi.BADADDR and ea < hi: if len(rows) >= count: more = True break rows.append(_idatui_head_row(ea)) - ea = ida_bytes.next_head(ea, hi) + ea = _step(ea) cursor = {"next": hex(ea)} if more else {"done": True} return {"addr": str(addr), "heads": rows, "cursor": cursor} ''' -- cgit v1.3.1-sl0p