summaryrefslogtreecommitdiff
path: root/99-playground/unstrace.py
diff options
context:
space:
mode:
Diffstat (limited to '99-playground/unstrace.py')
-rw-r--r--99-playground/unstrace.py119
1 files changed, 119 insertions, 0 deletions
diff --git a/99-playground/unstrace.py b/99-playground/unstrace.py
new file mode 100644
index 0000000000..d74fb7d4b8
--- /dev/null
+++ b/99-playground/unstrace.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+
+import re, os
+
+def split_args(args):
+ a = args.split('"', 1)[1]
+ a = a.split('"')[0]
+ return a
+
+
+cmd_map = {
+ "statx": "stat",
+ "lstat": "stat",
+ "openat": "open",
+ "access": "stat",
+}
+
+seen = set()
+
+def stage1(cmds):
+ last_cmd, last_path, last_rc = None, None, None
+ for cmd, path, rc in cmds:
+ if (cmd, path, rc) in seen:
+ continue
+ seen.add((cmd, path, rc))
+ if (last_cmd == "open" and last_rc == False and
+ cmd == "stat" and rc == False and
+ os.path.dirname(last_path) == path):
+ # stat on dir after trying to access file
+ last_path = path
+ continue
+ if rc == last_rc:
+ # unchanged status
+ if path == last_path:
+ last_cmd, last_path, last_rc = cmd, path, rc
+ elif path.startswith(path):
+ last_path = path
+ last_cmd, last_path, last_rc = cmd, path, rc
+ else:
+ last_cmd, last_path, last_rc = cmd, path, rc
+ yield(cmd, path, rc)
+ else:
+ last_cmd, last_path, last_rc = cmd, path, rc
+ yield(cmd, path, rc)
+
+LIB_SEARCH = 1
+PLUGIN_SEARCH = 2
+
+def stage2(cmds):
+ last_cmd, last_path, last_rc = None, None, None
+ state = None
+ for cmd, path, rc in cmds:
+ #breakpoint()
+ if (state == LIB_SEARCH):
+ if rc == True:
+ # found
+ searched_dirs = []
+ yield cmd, path, rc
+ continue
+ elif os.path.basename(path) == last_path:
+ # still seeking
+ searched_dirs.append(os.path.dirname(path))
+ continue
+ else:
+ #breakpoint()
+ # next library
+ for p in searched_dirs:
+ yield cmd, last_path + " " + p, False
+ searched_dirs = []
+
+ if (cmd == "open" and rc == False and
+ re.search(r'\.so(\.[0-9]+)?', path)):
+ # library, access failed here
+ state = LIB_SEARCH
+ searched_dirs = [os.path.dirname(path)]
+ last_path = os.path.basename(path)
+ else:
+ yield cmd, path, rc
+
+
+def strip_store_names(cmds):
+ import pathlib
+ HOME = str(pathlib.Path.home())
+ PWD = str(pathlib.Path.cwd())
+ pwd_first = len(PWD) > len(HOME)
+ for cmd, path, result in cmds:
+ if path.startswith("/gnu/store/"):
+ path = "/gnu/store/…" + path[43:]
+ elif pwd_first and path.startswith(PWD):
+ path = "$PWD" + path[len(PWD):]
+ elif path.startswith(HOME):
+ path = "~" + path[len(HOME):]
+ elif path.startswith(PWD):
+ path = "$PWD" + path[len(PWD):]
+ yield cmd, path, result
+
+
+def main(filename):
+ with open(filename) as fh:
+ lines = fh.readlines()
+ matches = (re.match(r"^(\w+)\(([^)]+)\) = (\S+).*", l)
+ for l in lines)
+ cmds = (m.groups() for m in matches if m)
+ cmds = ((cmd_map.get(cmd, cmd), split_args(path), int(result) >= 0)
+ for cmd, path, result in cmds
+ if not "/share/locale/" in path)
+ cmds = strip_store_names(cmds)
+ cmds = stage1(cmds)
+ cmds = stage2(cmds)
+ for cmd, path, rc in cmds:
+ print(cmd, path, "" if rc else "***")
+
+
+
+import argparse
+parser = argparse.ArgumentParser()
+parser.add_argument("filename")
+args = parser.parse_args()
+main(args.filename)