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