aboutsummaryrefslogtreecommitdiffstats
path: root/idatui/domain.py
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-25 00:51:28 +0200
committerblasty <blasty@local>2026-07-25 00:51:28 +0200
commitbe23d13852f4efd062641957b4dcec10622fc0c6 (patch)
treeb2f020fca47fc0afb472d317e91e60ba468a514f /idatui/domain.py
parentsplit: follow the decomp across functions as the listing cursor crosses bounds (diff)
downloadida-tui-be23d13852f4efd062641957b4dcec10622fc0c6.tar.gz
ida-tui-be23d13852f4efd062641957b4dcec10622fc0c6.tar.xz
ida-tui-be23d13852f4efd062641957b4dcec10622fc0c6.zip
strings: browse every string in the binary and jump to it (IDA's Shift+F12)
ida-pro-mcp exposes no full strings list (only a filtered/capped "interesting" survey), so this is a new injected tool plus a filterable browser. * server/patch_server.py: list_strings(offset,count,min_len,refresh) — every literal from idautils.Strings() as {addr,text,len,type}, paginated, with a module-level cache keyed by min_len (rebuilding is O(n) and the browser pages the whole list). * domain: StrLit dataclass + Program.strings() — pages the full list once and caches it. * app: StringsPalette modal (mirrors SymbolPalette) — case-insensitive substring filter with the match highlighted, addr/len/text columns, ↑↓/Enter/Esc. Bodies are sanitized to one printable line (\n/\r/\t escaped, non-printables dropped, long strings clipped) so control chars can't break the layout; display strings are pre-rendered+pre-lowered once since filtering runs per keystroke. Enter jumps to the literal in the unified listing via _goto_ea. Bound to '"' and Shift+F12, plus a "Strings…" command-palette entry. Verified on echo: 150 strings listed with addr/len/text, filtering 'usage' narrows to 2 (case-insensitive), Enter lands the listing cursor on the literal. Pilot `strings` scenario 6/6; full suite 165/2-flake.
Diffstat (limited to 'idatui/domain.py')
-rw-r--r--idatui/domain.py45
1 files changed, 45 insertions, 0 deletions
diff --git a/idatui/domain.py b/idatui/domain.py
index 1bf62ed..33c44b6 100644
--- a/idatui/domain.py
+++ b/idatui/domain.py
@@ -167,6 +167,15 @@ class Struct:
)
+@dataclass(frozen=True)
+class StrLit:
+ """A string literal IDA found in the binary (the Shift+F12 list)."""
+ addr: int
+ text: str
+ length: int
+ type: str = ""
+
+
@dataclass
class Decompilation:
ea: int
@@ -808,6 +817,7 @@ class Program:
self._listings: dict[int, ListingModel] = {} # keyed by segment start
self._decomp: dict[int, tuple[Decompilation, int]] = {}
self._decomp_maps: dict[int, tuple[list[list[int]], int]] = {} # line->ea sets
+ self._strings: list["StrLit"] | None = None # whole-binary string literals
self._name_gen = 0 # bumped on rename; invalidates stale name caches
self._segments_cache: list[tuple[int, int, int, str]] | None = None
self._sections: list[tuple[int, int, str]] | None = None
@@ -1246,6 +1256,41 @@ class Program:
except Exception: # noqa: BLE001 -- fall back to the truncated preview
return None
+ def strings(self, min_len: int = 4, refresh: bool = False) -> list[StrLit]:
+ """Every string literal in the binary (IDA's Shift+F12 list), paged in
+ full and cached. ``[]`` if the tool is unavailable."""
+ if not refresh:
+ with self._lock:
+ hit = self._strings
+ if hit is not None:
+ return hit
+ out: list[StrLit] = []
+ offset, page = 0, 2000
+ while True:
+ try:
+ payload = self.client.call(
+ "list_strings", offset=offset, count=page, min_len=min_len,
+ refresh=(refresh and offset == 0))
+ except IDAToolError:
+ return []
+ rows = payload.get("strings", []) if isinstance(payload, dict) else []
+ for r in rows:
+ if not isinstance(r, dict):
+ continue
+ out.append(StrLit(
+ addr=_as_int(r.get("addr", 0)),
+ text=r.get("text", ""),
+ length=int(r.get("len", 0) or 0),
+ type=r.get("type", "") or "",
+ ))
+ total = int(payload.get("total", 0) or 0) if isinstance(payload, dict) else 0
+ if len(rows) < page or len(out) >= total:
+ break
+ offset += len(rows)
+ with self._lock:
+ self._strings = out
+ return out
+
def decomp_map(self, ea: int) -> list[list[int]]:
"""Per-pseudocode-line instruction coverage for the split-view region
highlight: a list aligned to the decompiled lines, each the EAs the