Files
UniXNU/scripts/decode-boot-ui-trace.py
T
2026-10-19 18:49:31 +08:00

59 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""Decode the exact integer tokens photographed from the native UI stack probe."""
import argparse
import json
import re
import sys
from pathlib import Path
DIGITS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'
TOKEN = r'[A-Za-z0-9_-]+'
PATTERN = re.compile(
r'(?P<role>[BCLSTU])(?P<index>\d+)x(?P<count>\d+)\s+'
r'(?:(?P<extension>f5)\s+' + r'\s+'.join('(?P<f%d>%s)' % (i, TOKEN) for i in range(5, 9)) +
r'(?: p(?P<peer>-?\d+)/e(?P<peer_error>\d+))?|' +
r'\s+'.join('(?P<a%d>%s)' % (i, TOKEN) for i in range(6)) + r'\s+!(?P<error>\d+))')
DETAIL = re.compile(r'(?P<role>[BCLSTU]) FP(?P<first>01|09|17|25)\s+' + r'\s+'.join('(?P<f%d>%s)' % (i, TOKEN) for i in range(8)))
def address(token):
result = 0
for digit in token:
result = result * 64 + DIGITS.index(digit)
if result >= 1 << 39:
raise ValueError('token exceeds native user address range: ' + token)
return hex(result)
def decode(text):
entries = {}
for m in PATTERN.finditer(text):
role, index, count = m['role'], int(m['index']), int(m['count'])
key = (role, index)
entry = entries.setdefault(key, dict(role=role, index=index, count=count))
if entry['count'] != count:
raise ValueError('mixing different captures for one thread group')
if m['extension']:
entry['frames_5_8'] = [address(m['f%d' % i]) for i in range(5, 9)]
if m['peer'] is not None:
entry.update(peer=int(m['peer']), peer_error=int(m['peer_error']))
else:
entry.update(pc=address(m['a0']), lr=address(m['a1']),
frames_1_4=[address(m['a%d' % i]) for i in range(2, 6)], error=int(m['error']))
for m in DETAIL.finditer(text):
key = (m['role'], 1)
entry = entries.setdefault(key, dict(role=m['role'], index=1))
first = int(m['first'])
entry['frames_%d_%d' % (first, first + 7)] = [address(m['f%d' % i]) for i in range(8)]
return list(entries.values())
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('input', nargs='?', type=Path, help='transcribed screen text; otherwise stdin')
args = parser.parse_args()
results = decode(args.input.read_text() if args.input else sys.stdin.read())
if not results:
parser.error('no complete UI trace rows found')
print(json.dumps(results, indent=2))