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