P1-B/C: WM survey — 555K instr/4,422 funcs; negative dispatch-table result recorded (U4); GP/tooling scripts; findings F8
This commit is contained in:
parent
f215c88155
commit
1a1c75ae1d
3 changed files with 81 additions and 0 deletions
|
|
@ -149,6 +149,22 @@ decompiler shows `unaff_gp + imm`) — dispatch found structurally instead:
|
|||
|
||||
Next: same scan on WM; handler-by-handler decompile + naming pass.
|
||||
|
||||
## F8 — mt7981_wm survey (2026-08-20)
|
||||
|
||||
Ghidra project `wm`: forced disassembly to **555,385 instructions / 4,422
|
||||
functions** (import-time analysis alone: 226K/4,355).
|
||||
|
||||
- Code model differs from patch/WA: only **27 GP-relative references** in
|
||||
the whole image → WM uses (near-)absolute global addressing, so GP-base
|
||||
inference is not the unlock it would otherwise be.
|
||||
- Structural dispatch scan (scan_tables.py) across every region pairing
|
||||
found **no absolute function-pointer table** (unlike WA's 65-entry
|
||||
table, F7). WM command dispatch must use another mechanism —
|
||||
FP/register-relative tables, switch jump tables, or runtime handler
|
||||
registration (unknown U4).
|
||||
- Regions: code 0xe003b000 (398KB) + 0xe009c400 (473KB mixed);
|
||||
data 0x0231dc00 (205KB), 0x0041xxxx pair; 0xf0xxxxxx block (feat 0x80)
|
||||
still uncharacterized (U1).
|
||||
## Unknowns registry
|
||||
|
||||
- **U1 — `feature_set` bit 7 (0x80):** observed only on WM regions at
|
||||
|
|
|
|||
28
tools/ghidra_scripts/FindGPInit.py
Normal file
28
tools/ghidra_scripts/FindGPInit.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Headless post-script: find instructions that write the GP register and
|
||||
# report candidate GP base values. Once GP is known, set it as register
|
||||
# context and re-run analysis so GP-relative data references resolve.
|
||||
# Run via pyghidra ghidra_launch ... -postScript FindGPInit.py
|
||||
#@category Analysis
|
||||
|
||||
listing = currentProgram.getListing()
|
||||
reg = currentProgram.getLanguage().getRegisters()
|
||||
gp_regs = [r for r in reg if r.getName().lower() in ('gp', 'r26', 'r11')]
|
||||
print('GP candidates: %s' % [r.getName() for r in gp_regs])
|
||||
|
||||
it = listing.getInstructions(True)
|
||||
hits = 0
|
||||
while it.hasNext() and hits < 80:
|
||||
ins = it.next()
|
||||
n = ins.getNumOperands()
|
||||
for i in range(n):
|
||||
try:
|
||||
ops = ins.getOpObjects(i)
|
||||
except Exception: # noqa: BLE001
|
||||
continue
|
||||
for o in ops:
|
||||
if hasattr(o, 'getName') and o in gp_regs:
|
||||
# operand 0 = destination on NDS32 ALU forms
|
||||
if i == 0:
|
||||
print('%s %s' % (ins.getAddress(), ins))
|
||||
hits += 1
|
||||
print('total gp-writes shown: %d' % hits)
|
||||
37
tools/ghidra_scripts/GPHistogram.py
Normal file
37
tools/ghidra_scripts/GPHistogram.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Headless post-script: collect all GP-relative references (addr, imm).
|
||||
# Dump as CSV lines "GPREF,<insn_addr>,<imm>" for offline base inference.
|
||||
#@category Analysis
|
||||
|
||||
listing = currentProgram.getListing()
|
||||
lang = currentProgram.getLanguage()
|
||||
gp = None
|
||||
for r in lang.getRegisters():
|
||||
if r.getName().lower() == 'gp':
|
||||
gp = r
|
||||
break
|
||||
print('gp register: %s' % (gp.getName() if gp else None))
|
||||
|
||||
from ghidra.program.model.scalar import Scalar # noqa: E402
|
||||
|
||||
it = listing.getInstructions(True)
|
||||
n = 0
|
||||
while it.hasNext():
|
||||
ins = it.next()
|
||||
uses_gp = False
|
||||
for i in range(ins.getNumOperands()):
|
||||
for o in ins.getOpObjects(i):
|
||||
if o == gp:
|
||||
uses_gp = True
|
||||
if not uses_gp:
|
||||
continue
|
||||
imm = None
|
||||
for i in range(ins.getNumOperands()):
|
||||
for o in ins.getOpObjects(i):
|
||||
if isinstance(o, Scalar):
|
||||
imm = o.getSignedValue()
|
||||
break
|
||||
if imm is not None:
|
||||
break
|
||||
print('GPREF,%s,%s' % (ins.getAddress(), imm if imm is not None else ''))
|
||||
n += 1
|
||||
print('total gp-refs: %d' % n)
|
||||
Loading…
Reference in a new issue