aboutsummaryrefslogtreecommitdiffstats
path: root/idatui/domain.py
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-10 14:53:20 +0200
committerblasty <blasty@local>2026-07-10 14:53:20 +0200
commitb8d0335682758ef51eab1c6dea6435b11d4e0bd2 (patch)
treeb37fdb91e74dbe136f2d0d757c2062937be82b1c /idatui/domain.py
parenthex view: raw image bytes (VA-addressed), synced to the code cursor (diff)
downloadida-tui-b8d0335682758ef51eab1c6dea6435b11d4e0bd2.tar.gz
ida-tui-b8d0335682758ef51eab1c6dea6435b11d4e0bd2.tar.xz
ida-tui-b8d0335682758ef51eab1c6dea6435b11d4e0bd2.zip
hex view: file offsets + 'g' goto (dedicated input)
Add a file_regions server tool (get_fileregion_offset per segment) and Program.file_regions/file_offset so a virtual address maps to its raw on-disk offset without a format-specific header parser. The hex view now shows a VA column and a file-offset column side by side, and the status line reports file+off. Goto moves to its own top-level #goto Input instead of overloading the function-filter box (which is hidden with the names pane, so goto was unreachable there). In the hex view 'g' jumps the cursor to an address (bounds-checked against the image); elsewhere it navigates as before.
Diffstat (limited to 'idatui/domain.py')
-rw-r--r--idatui/domain.py31
1 files changed, 31 insertions, 0 deletions
diff --git a/idatui/domain.py b/idatui/domain.py
index 602d54d..826d0f7 100644
--- a/idatui/domain.py
+++ b/idatui/domain.py
@@ -418,6 +418,9 @@ class HexModel:
def total_rows(self) -> int:
return (self.size + 15) // 16
+ def file_offset(self, va: int) -> int | None:
+ return self._prog.file_offset(va)
+
def _fetch_block(self, b: int) -> bytes:
addr = self.start + b * self.BLOCK
n = min(self.BLOCK, self.end - addr)
@@ -492,6 +495,7 @@ class Program:
self._decomp: dict[int, tuple[Decompilation, int]] = {}
self._name_gen = 0 # bumped on rename; invalidates stale name caches
self._sections: list[tuple[int, int, str]] | None = None
+ self._fileregions: list[tuple[int, int, int]] | None = None
self._hexmodel: "HexModel | None" = None
self._lock = threading.Lock()
@@ -553,6 +557,33 @@ class Program:
self._hexmodel = HexModel(self, rng[0], rng[1])
return self._hexmodel
+ def file_regions(self) -> list[tuple[int, int, int]]:
+ """Sorted [(start, end, file_off)] mapping loaded segments to raw file
+ offsets (file_off == -1 for non-file-backed, e.g. .bss). Cached; needs
+ the injected ``file_regions`` server tool."""
+ if self._fileregions is not None:
+ return self._fileregions
+ regions: list[tuple[int, int, int]] = []
+ try:
+ r = self.client.call("file_regions")
+ for d in (r.get("regions", []) if isinstance(r, dict) else []):
+ if isinstance(d, dict) and "start" in d:
+ regions.append((_as_int(d["start"]), _as_int(d["end"]),
+ int(d.get("file_off", -1))))
+ except IDAToolError:
+ regions = []
+ regions.sort()
+ with self._lock:
+ self._fileregions = regions
+ return regions
+
+ def file_offset(self, va: int) -> int | None:
+ """Raw on-disk file offset for ``va``, or None if not file-backed."""
+ for start, end, fo in self.file_regions():
+ if start <= va < end:
+ return (fo + (va - start)) if fo >= 0 else None
+ return None
+
def read_bytes(self, ea: int, n: int) -> bytes:
"""Raw bytes [ea, ea+n) from IDA (gaps read as zero)."""
if n <= 0: