aboutsummaryrefslogtreecommitdiffstats
path: root/fw/verify_gcp_loggates_fault.py
blob: 05a376e9f29221f005d7e3314e8dcde28787a546 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/env python3
"""Offline check of preserved log-gate fault frame against signed GCP .77.

No hardware access. This identifies word2 as the faulting instruction; word0
is a known build-specific constant, not the program counter of this fault.
"""
from pathlib import Path
import struct

from capstone import CS_ARCH_ARM, CS_MODE_ARM, Cs

ELF = Path(__file__).resolve().parents[1] / 'psp_out/versions_win/elf_all/gcp_22.0.0.77_7c426e7f.elf'
FRAME = (0x4055D8, 0x25031016, 0x4011D8, 0x867, 0x42CFA0, 0, 0x8DA7463D)


def file_offset(image: bytes, va: int) -> int:
    assert image[:6] == b'\x7fELF\x01\x01'
    phoff = struct.unpack_from('<I', image, 28)[0]
    size, count = struct.unpack_from('<HH', image, 42)
    for i in range(count):
        typ, off, base, _, length, _, flags, _ = struct.unpack_from(
            '<8I', image, phoff + size * i)
        if typ == 1 and flags & 1 and base <= va < base + length:
            return off + va - base
    raise ValueError(f'VA 0x{va:x} is not in an executable file-backed PT_LOAD')


def main() -> None:
    image = ELF.read_bytes()
    pc, fsr, far = FRAME[2:5]
    off = file_offset(image, pc)
    ins = next(Cs(CS_ARCH_ARM, CS_MODE_ARM).disasm(image[off:off+4], pc, count=1))
    assert (ins.address, ins.mnemonic, ins.op_str) == (
        pc, 'stmmi', 'r0!, {r3, r4}'), (hex(ins.address), ins.mnemonic, ins.op_str)
    status = (fsr & 0xf) | (((fsr >> 10) & 1) << 4)
    assert status == 7 and fsr & (1 << 11) and far == 0x42CFA0
    print(f'word2=0x{pc:08x}: {ins.mnemonic} {ins.op_str}; '
          f'DFSR FS={status} (translation), write=1, FAR=0x{far:08x}')
    print(f'word0=0x{FRAME[0]:08x}: build constant, NOT this faulting PC')


if __name__ == '__main__':
    main()