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()
|