volla-volte-hacks/src/trace-rild/parse_strace.py

154 lines
4.3 KiB
Python
Executable File

#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
# Author: Oliver Smith
# Copyright 2021 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
import argparse
import sys
import datetime
def parse_args():
parser = argparse.ArgumentParser(prog="parse_strace")
parser.add_argument("strace_file",
help="an strace file generated by dump.sh")
args = parser.parse_args()
return args
def parse_iov_str(iov):
"""
:param iov: strace iov string, looks like this:
'[{iov_base="AT\0", iov_len=3}, {iov_base="[0] AT< +EXLCE:...'
:returns: list of iov strings, e.g.:
["AT", "[0] AT< +EXLCE:...", ...]
"""
ret = []
assert iov.startswith("[{")
rest = iov[2:]
while rest:
if rest.startswith("iov_base=\""):
key_value, rest = rest.split(', iov_len', 1)
value = key_value.split('"', 1)[1]
ret += [value]
elif rest.startswith("="):
iov_len, rest = rest.split("}", 1)
elif rest.startswith(", {"):
_, rest = rest.split("{", 1)
elif rest.startswith("]"):
# parts at the end of writev are not interesting: iov count and
# bytes written
break
else:
assert False, f"failed to parse rest of iov:" \
f"\n\niov: {iov}" \
f"\n\nrest: {rest}"
return ret
def parse_at(cmd):
is_at = False
i = 0
for i in range(len(cmd["iov"])):
iov_base = cmd["iov"][i]
if iov_base.startswith("[0] AT"):
is_at = True
break
if not is_at:
return
desc = "\n ".join(cmd["iov"][i:])
# Cut '[0 AT< '
desc = desc[8:]
# Cut suffixes like ' (RIL_URC_READER, tid:502968382704)'
desc = desc.split(" (RIL_URC_", 1)[0]
desc = desc.split(" (RIL_CMD_", 1)[0]
desc = desc.split(" (RIL_ATCI_", 1)[0]
if desc.endswith("\\n\\0"):
desc=desc[:-4]
cmd["type"] = "at"
cmd["desc"] = desc
cmd["towards_modem"] = "AT>" in iov_base
def parse_writev(strace_file):
"""
:param strace_file: path to strace file generated by dump.sh
:returns: a list of writev calls found in the strace file, looks like this:
[{"desc": "AT+EXCLE", # human readable short version
"fd": "74<socket:[8970]>"
"iov": ["AT", "[0 AT< +EXLCE:...", ...],
"pid": 985,
"time": 1632220184.069225,
"time_rel": 0.000077,
"towards_modem": True,
"type": "at"}, ...]
type is one of:
* "at"
* "unknown"
"""
ret = []
failed = 0
with open(strace_file) as handle:
for line in handle:
if "writev(" not in line:
continue
cmd = {}
rest = line.rstrip()
# Cut pid, time, time_rel
# rest = '985 1632220184.068694 (+ 0.000148) writev(...'
# => ['985', '1632220184.068694', '(+', '0.000148)', 'writev(...'
pid, time, _, time_rel, rest = rest.split(None, 4)
cmd["pid"] = int(pid)
cmd["time"] = float(time)
cmd["time_rel"] = time_rel.split(")")[0]
# Cut writev
# rest = 'writev(74<socket:[8970]>, [{iov_base="...'
writev, rest = rest.split("(", 1)
assert writev == "writev"
# Cut fd
# rest = '74<socket:[8970]>, [{iov_base="...'
cmd["fd"], rest = rest.split(", ", 1)
cmd["iov"] = parse_iov_str(rest)
cmd["type"] = "unknown"
cmd["desc"] = cmd["iov"]
cmd["towards_modem"] = True
parse_at(cmd)
ret += [cmd]
return ret
def print_cmds(cmds):
""" :param cmds: return of parse_at_cmds() """
for cmd in cmds:
if cmd["type"] == "unknown":
continue
direction = " ->" if cmd["towards_modem"] else "<- "
time = datetime.datetime.fromtimestamp(cmd["time"]).strftime('%H:%M:%S')
print(f"{time} (ril {direction} modem) {cmd['desc']}")
def main():
args = parse_args()
cmds = parse_writev(args.strace_file)
print_cmds(cmds)
if __name__ == "__main__":
sys.exit(main())