Index: lldb/examples/python/crashlog.py =================================================================== --- lldb/examples/python/crashlog.py +++ lldb/examples/python/crashlog.py @@ -26,6 +26,7 @@ # PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash #---------------------------------------------------------------------- +import abc import concurrent.futures import contextlib import datetime @@ -415,19 +416,44 @@ pass class CrashLogParser: - def parse(self, debugger, path, verbose): + "CrashLog parser base class and factory." + + def __new__(cls, debugger, path, verbose): + # When `__new__` is overriden, if the returned type is the same + # as the class type, or related to it, the `__init__` method is + # automatically called after `__new__`. If the return type is not + # related, then the `__init__` method is not called. + + # We don't need to propagate `__new__`'s aguments because both + # `JSONCrashLogParser` & `TextCrashLogParser` are sub-classes of + # `CrashLogParser`, so they will automagically be passed to the + # sub-class `__init__` method. try: - return JSONCrashLogParser(debugger, path, verbose).parse() + return JSONCrashLogParser.__new__(cls, debugger, path, verbose) except CrashLogFormatException: - return TextCrashLogParser(debugger, path, verbose).parse() + return object().__new__(TextCrashLogParser) - -class JSONCrashLogParser: def __init__(self, debugger, path, verbose): self.path = os.path.expanduser(path) self.verbose = verbose self.crashlog = CrashLog(debugger, self.path, self.verbose) + @abc.abstractmethod + def parse(self): + pass + + +class JSONCrashLogParser(CrashLogParser): + def __new__(cls, debugger, path, verbose): + with open(path, 'r') as f: + buffer = f.read() + try: + self = object().__new__(JSONCrashLogParser) + self.data = self.parse_json(buffer) + return self + except: + raise CrashLogFormatException() + def parse_json(self, buffer): try: return json.loads(buffer) @@ -438,14 +464,6 @@ return json.loads(tail) def parse(self): - with open(self.path, 'r') as f: - buffer = f.read() - - try: - self.data = self.parse_json(buffer) - except: - raise CrashLogFormatException() - try: self.parse_process_info(self.data) self.parse_images(self.data['usedImages']) @@ -592,7 +610,7 @@ INSTRS = 5 -class TextCrashLogParser: +class TextCrashLogParser(CrashLogParser): parent_process_regex = re.compile('^Parent Process:\s*(.*)\[(\d+)\]') thread_state_regex = re.compile('^Thread ([0-9]+) crashed with') thread_instrs_regex = re.compile('^Thread ([0-9]+) instruction stream') @@ -615,13 +633,10 @@ r'(/.*)' # img_path ) - def __init__(self, debugger, path, verbose): - self.path = os.path.expanduser(path) - self.verbose = verbose + super().__init__(debugger, path, verbose) self.thread = None self.app_specific_backtrace = False - self.crashlog = CrashLog(debugger, self.path, self.verbose) self.parse_mode = CrashLogParseMode.NORMAL self.parsers = { CrashLogParseMode.NORMAL : self.parse_normal, @@ -1012,7 +1027,7 @@ if not os.path.exists(crashlog_path): raise InteractiveCrashLogException("crashlog file %s does not exist" % crashlog_path) - crashlog = CrashLogParser().parse(debugger, crashlog_path, False) + crashlog = CrashLogParser(debugger, crashlog_path, False).parse() target = lldb.SBTarget() # 1. Try to use the user-provided target @@ -1257,7 +1272,7 @@ except InteractiveCrashLogException as e: result.SetError(str(e)) else: - crash_log = CrashLogParser().parse(debugger, crash_log_file, options.verbose) + crash_log = CrashLogParser(debugger, crash_log_file, options.verbose).parse() SymbolicateCrashLog(crash_log, options) if __name__ == '__main__': Index: lldb/examples/python/scripted_process/crashlog_scripted_process.py =================================================================== --- lldb/examples/python/scripted_process/crashlog_scripted_process.py +++ lldb/examples/python/scripted_process/crashlog_scripted_process.py @@ -10,10 +10,8 @@ class CrashLogScriptedProcess(ScriptedProcess): def parse_crashlog(self): - try: - crash_log = CrashLogParser().parse(self.dbg, self.crashlog_path, False) - except Exception as e: - raise e + crashlog_parser = CrashLogParser(self.dbg, self.crashlog_path, False) + crash_log = crashlog_parser.parse() self.pid = crash_log.process_id self.addr_mask = crash_log.addr_mask