strace-rild: add
Add scripts used to figure out IMS related AT commands.
This commit is contained in:
parent
17a3f47f06
commit
acadfc8cb5
|
@ -0,0 +1,11 @@
|
||||||
|
Scripts to run strace + tcpdump on mtkfusionrild and to extract AT commands
|
||||||
|
from the strace dump.
|
||||||
|
|
||||||
|
Preparation:
|
||||||
|
- Rooted Android
|
||||||
|
- Termux installed, sshd enabled and running
|
||||||
|
- strace, tsu, tcpdump installed
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
1. run dump.sh
|
||||||
|
2. run parse_strace.py to get AT commands form the strace dump
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/sh -ex
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# Author: Oliver Smith
|
||||||
|
# Copyright 2021 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
|
|
||||||
|
dump_name="$(date "+%Y-%m-%d_%H%M%S")"
|
||||||
|
|
||||||
|
adb push dump_run_on_phone.sh /mnt/sdcard/Download/
|
||||||
|
adb forward tcp:8022 tcp:8022
|
||||||
|
ssh -p 8022 localhost \
|
||||||
|
sh -e /mnt/sdcard/Download/dump_run_on_phone.sh "$dump_name"
|
||||||
|
|
||||||
|
mkdir -p dump
|
||||||
|
adb pull /mnt/sdcard/Download/dump/"$dump_name" dump/"$dump_name"
|
|
@ -0,0 +1,66 @@
|
||||||
|
#!/bin/sh -e
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# Author: Oliver Smith
|
||||||
|
# Copyright 2021 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
|
#
|
||||||
|
# dump.sh copies this file to Android and runs it
|
||||||
|
|
||||||
|
rild="mtkfusionrild"
|
||||||
|
strsize="1000"
|
||||||
|
dump_name="$1"
|
||||||
|
pid="$(sudo ps ax | grep "$rild" | grep -v grep | head -n1 | awk '{print $1}')"
|
||||||
|
outdir="/mnt/sdcard/Download/dump/$1"
|
||||||
|
|
||||||
|
clean_up() {
|
||||||
|
sudo killall -9 strace tcpdump || true 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -d "$outdir" ]; then
|
||||||
|
echo "ERROR: outdir already exists: $outdir"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$pid" ]; then
|
||||||
|
echo "ERROR: failed to get pid of $rild"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$outdir"
|
||||||
|
set -x
|
||||||
|
|
||||||
|
clean_up
|
||||||
|
|
||||||
|
sudo tcpdump \
|
||||||
|
-U \
|
||||||
|
-i any \
|
||||||
|
-n not port 8022 \
|
||||||
|
-s0 \
|
||||||
|
-w "$outdir/$1.pcap" \
|
||||||
|
&
|
||||||
|
|
||||||
|
sudo strace \
|
||||||
|
-f \
|
||||||
|
-o "$outdir/$1_$rild.strace" \
|
||||||
|
-p "$pid" \
|
||||||
|
-r \
|
||||||
|
-s "$strsize" \
|
||||||
|
-ttt \
|
||||||
|
-v \
|
||||||
|
-y \
|
||||||
|
&
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
set +x
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo "rild: $rild (pid: $pid)"
|
||||||
|
echo "Capturing to: $outdir"
|
||||||
|
echo "Press return to stop capturing"
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
read foo
|
||||||
|
|
||||||
|
set -x
|
||||||
|
clean_up
|
||||||
|
echo "Capture stopped"
|
|
@ -0,0 +1,153 @@
|
||||||
|
#!/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())
|
Loading…
Reference in New Issue