79 lines
3 KiB
Python
79 lines
3 KiB
Python
|
|
"""ELF emitter tests: structural validity + segment fidelity.
|
||
|
|
|
||
|
|
Validates with readelf where available and always with a programmatic
|
||
|
|
re-parse against the container's own region table.
|
||
|
|
"""
|
||
|
|
import os
|
||
|
|
import struct
|
||
|
|
import subprocess
|
||
|
|
import sys
|
||
|
|
import unittest
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
REPO = Path(__file__).resolve().parent.parent
|
||
|
|
sys.path.insert(0, str(REPO / 'tools'))
|
||
|
|
import mtk_fw_elf as E # noqa: E402
|
||
|
|
|
||
|
|
FW = Path(os.environ.get('MTK_FW_DIR', '/lib/firmware/mediatek'))
|
||
|
|
|
||
|
|
|
||
|
|
def blobs():
|
||
|
|
return sorted(FW.glob('mt79*_wm.bin')) + sorted(FW.glob('mt79*_wa.bin')) \
|
||
|
|
+ sorted(FW.glob('mt79*_rom_patch.bin'))
|
||
|
|
|
||
|
|
|
||
|
|
class Emitter(unittest.TestCase):
|
||
|
|
|
||
|
|
def test_structure_and_fidelity(self):
|
||
|
|
found = blobs()
|
||
|
|
if not found:
|
||
|
|
self.skipTest('no mediatek blobs')
|
||
|
|
for p in found:
|
||
|
|
with self.subTest(blob=p.name):
|
||
|
|
d = p.read_bytes()
|
||
|
|
if 'patch' in p.name:
|
||
|
|
regions = list(E.patch_regions(d))
|
||
|
|
else:
|
||
|
|
regions = list(E.ram_regions(d))
|
||
|
|
regions = [(a, dat) for a, dat in regions if dat]
|
||
|
|
elf = E.build_elf(regions)
|
||
|
|
# ehdr sanity
|
||
|
|
self.assertEqual(elf[:4], b'\x7fELF')
|
||
|
|
etype, mach, _, entry, phoff = struct.unpack_from('<HHIII', elf, 16)
|
||
|
|
self.assertEqual((etype, mach), (2, 167))
|
||
|
|
self.assertEqual(phoff, 52)
|
||
|
|
phentsize, phnum = struct.unpack_from('<HH', elf, 42)
|
||
|
|
self.assertEqual((phentsize, phnum), (32, len(regions)))
|
||
|
|
# segment fidelity
|
||
|
|
for i, (addr, dat) in enumerate(regions):
|
||
|
|
p_type, p_off, p_va, p_pa, p_filesz, p_memsz = \
|
||
|
|
struct.unpack_from('<IIIIII', elf, phoff + i * 32)
|
||
|
|
self.assertEqual((p_type, p_va, p_pa), (1, addr, addr))
|
||
|
|
self.assertEqual((p_filesz, p_memsz), (len(dat),) * 2)
|
||
|
|
self.assertEqual(elf[p_off:p_off + p_filesz], dat)
|
||
|
|
|
||
|
|
def test_readelf_accepts(self):
|
||
|
|
found = blobs()
|
||
|
|
if not found:
|
||
|
|
self.skipTest('no mediatek blobs')
|
||
|
|
if subprocess.run(['which', 'readelf'], capture_output=True).returncode:
|
||
|
|
self.skipTest('readelf unavailable')
|
||
|
|
import tempfile
|
||
|
|
for p in found[:4]:
|
||
|
|
with self.subTest(blob=p.name):
|
||
|
|
d = p.read_bytes()
|
||
|
|
regs = list(E.patch_regions(d) if 'patch' in p.name
|
||
|
|
else E.ram_regions(d))
|
||
|
|
elf = E.build_elf(regs)
|
||
|
|
with tempfile.NamedTemporaryFile(suffix='.elf') as f:
|
||
|
|
f.write(elf)
|
||
|
|
f.flush()
|
||
|
|
r = subprocess.run(['readelf', '-l', f.name],
|
||
|
|
capture_output=True, text=True)
|
||
|
|
self.assertEqual(r.returncode, 0, r.stderr)
|
||
|
|
self.assertIn('LOAD', r.stdout)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
unittest.main()
|