xref: /llvm-project/lldb/test/Shell/ScriptInterpreter/Python/Crashlog/patch-crashlog.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
1#!/usr/bin/env python
2
3import json
4import os
5import re
6import subprocess
7import sys
8import argparse
9
10
11class CrashLogPatcher:
12    SYMBOL_REGEX = re.compile(r"^([0-9a-fA-F]+) T _(.*)$")
13    UUID_REGEX = re.compile(r"UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*")
14
15    def __init__(self, data, binary, offsets, json):
16        self.data = data
17        self.binary = binary
18        self.offsets = offsets
19        self.json = json
20
21    def patch_executable(self):
22        self.data = self.data.replace("@EXEC@", self.binary)
23        self.data = self.data.replace("@NAME@", os.path.basename(self.binary))
24
25    def patch_uuid(self):
26        output = subprocess.check_output(["dwarfdump", "--uuid", self.binary]).decode(
27            "utf-8"
28        )
29        m = self.UUID_REGEX.match(output)
30        if m:
31            self.data = self.data.replace("@UUID@", m.group(1))
32
33    def patch_addresses(self):
34        if not self.offsets:
35            return
36        output = subprocess.check_output(["nm", self.binary]).decode("utf-8")
37        for line in output.splitlines():
38            m = self.SYMBOL_REGEX.match(line)
39            if m:
40                address = m.group(1)
41                symbol = m.group(2)
42                if symbol in self.offsets:
43                    patch_addr = int(m.group(1), 16) + int(self.offsets[symbol])
44                    if self.json:
45                        patch_addr = patch_addr - 0x100000000
46                        representation = int
47                    else:
48                        representation = hex
49                    self.data = self.data.replace(
50                        "@{}@".format(symbol), str(representation(patch_addr))
51                    )
52
53    def remove_metadata(self):
54        self.data = self.data[self.data.index("\n") + 1 :]
55
56
57if __name__ == "__main__":
58    parser = argparse.ArgumentParser(description="Crashlog Patcher")
59    parser.add_argument("--binary", required=True)
60    parser.add_argument("--crashlog", required=True)
61    parser.add_argument("--offsets", required=True)
62    parser.add_argument("--json", default=False, action="store_true")
63    parser.add_argument("--no-metadata", default=False, action="store_true")
64    args = parser.parse_args()
65
66    offsets = json.loads(args.offsets)
67
68    with open(args.crashlog, "r") as file:
69        data = file.read()
70
71    p = CrashLogPatcher(data, args.binary, offsets, args.json)
72    p.patch_executable()
73    p.patch_uuid()
74    p.patch_addresses()
75
76    if args.no_metadata:
77        p.remove_metadata()
78
79    with open(args.crashlog, "w") as file:
80        file.write(p.data)
81