mtk-wifi-fw/tools/scan_tables.py

60 lines
1.9 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
"""Scan firmware regions for consecutive function-pointer tables.
Finds runs of >= min_run consecutive little-endian dwords that all fall in a
given code range — the shape of MCU command-handler dispatch tables.
Usage: scan_tables.py <region.bin> <code_lo> <code_hi> [min_run] [tolerance]
tolerance = max absolute non-code dwords allowed inside a run (0/NULL counted).
"""
import struct
import sys
from pathlib import Path
path = Path(sys.argv[1])
lo, hi = int(sys.argv[2], 0), int(sys.argv[3], 0)
min_run = int(sys.argv[4]) if len(sys.argv) > 4 else 8
tol = int(sys.argv[5]) if len(sys.argv) > 5 else 0
d = path.read_bytes()
base = 0
# If the region file corresponds to a load address, pass that as lo bound
# via argv; region offsets here are file offsets, so also print file offset.
words = struct.unpack_from('<%dI' % (len(d) // 4), d)
run_start = None
run = []
tables = []
def flush(end):
global run, run_start
code = sum(1 for w in run if lo <= w < hi)
if len(run) >= min_run and code >= min_run:
tables.append((run_start, end, len(run), code))
run = []
run_start = None
for i, w in enumerate(words):
ok = lo <= w < hi or w == 0
if ok:
if run_start is None:
run_start = i * 4
run.append(w)
else:
if run_start is not None and tol:
run.append(w) # tolerate, next check trims
if sum(1 for x in run[-3:] if not (lo <= x < hi or x == 0)) >= 2:
flush(i * 4)
else:
flush(i * 4)
for t in tables:
start_off, end_off, n, code = t
print('table @ file+0x%x..0x%x (%d words, %d code ptrs)'
% (start_off, end_off, n, code))
vals = words[start_off // 4:end_off // 4]
for j, w in enumerate(vals[:64]):
mark = '' if lo <= w < hi else ('(0)' if w == 0 else '(?)')
print(' [%2d] 0x%08x %s' % (j, w, mark))