diff --git a/lldb/examples/python/crashlog.py b/lldb/examples/python/crashlog.py --- a/lldb/examples/python/crashlog.py +++ b/lldb/examples/python/crashlog.py @@ -340,6 +340,7 @@ self.backtraces = list() # For application specific backtraces self.idents = list() # A list of the required identifiers for doing all stack backtraces self.errors = list() + self.exception = dict() self.crashed_thread_idx = -1 self.version = -1 self.target = None @@ -483,6 +484,7 @@ self.crashlog.process_identifier = json_data['procName'] def parse_crash_reason(self, json_exception): + self.crashlog.exception = json_exception exception_type = json_exception['type'] exception_signal = " " if 'signal' in json_exception: @@ -601,7 +603,6 @@ SYSTEM = 4 INSTRS = 5 - class TextCrashLogParser(CrashLogParser): parent_process_regex = re.compile(r'^Parent Process:\s*(.*)\[(\d+)\]') thread_state_regex = re.compile(r'^Thread \d+ crashed with') @@ -624,6 +625,9 @@ r'(?:<([-0-9a-fA-F]+)>\s+)?' # img_uuid r'(/.*)' # img_path ) + exception_type_regex = re.compile(r'^Exception Type:\s+(EXC_[A-Z_]+)(?:\s+\((.*)\))?') + exception_codes_regex = re.compile(r'^Exception Codes:\s+(0x[0-9a-fA-F]+),\s*(0x[0-9a-fA-F]+)') + exception_extra_regex = re.compile(r'^Exception\s+.*:\s+(.*)') def __init__(self, debugger, path, verbose): super().__init__(debugger, path, verbose) @@ -650,9 +654,9 @@ if self.parse_mode == CrashLogParseMode.THREAD: if self.thread.index == self.crashlog.crashed_thread_idx: self.thread.reason = '' - if self.crashlog.thread_exception: + if hasattr(self.crashlog, 'thread_exception'): self.thread.reason += self.crashlog.thread_exception - if self.crashlog.thread_exception_data: + if hasattr(self.crashlog, 'thread_exception_data'): self.thread.reason += " (%s)" % self.crashlog.thread_exception_data if self.app_specific_backtrace: self.crashlog.backtraces.append(self.thread) @@ -670,6 +674,37 @@ return self.crashlog + def parse_exception(self, line): + if not line.startswith('Exception'): + return + if line.startswith('Exception Type:'): + self.crashlog.thread_exception = line[15:].strip() + exception_type_match = self.exception_type_regex.search(line) + if exception_type_match: + exc_type, exc_signal = exception_type_match.groups() + self.crashlog.exception['type'] = exc_type + if exc_signal: + self.crashlog.exception['signal'] = exc_signal + elif line.startswith('Exception Subtype:'): + self.crashlog.thread_exception_subtype = line[18:].strip() + if 'type' in self.crashlog.exception: + self.crashlog.exception['subtype'] = self.crashlog.thread_exception_subtype + elif line.startswith('Exception Codes:'): + self.crashlog.thread_exception_data = line[16:].strip() + if 'type' not in self.crashlog.exception: + return + exception_codes_match = self.exception_codes_regex.search(line) + if exception_codes_match: + self.crashlog.exception['codes'] = self.crashlog.thread_exception_data + code, subcode = exception_codes_match.groups() + self.crashlog.exception['rawCodes'] = [int(code, base=16), + int(subcode, base=16)] + else: + if 'type' not in self.crashlog.exception: + return + exception_extra_match = self.exception_extra_regex.search(line) + if exception_extra_match: + self.crashlog.exception['message'] = exception_extra_match.group(1) def parse_normal(self, line): if line.startswith('Process:'): @@ -693,14 +728,8 @@ line) self.crashlog.parent_process_name = parent_process_match.group(1) self.crashlog.parent_process_id = parent_process_match.group(2) - elif line.startswith('Exception Type:'): - self.crashlog.thread_exception = line[15:].strip() - return - elif line.startswith('Exception Codes:'): - self.crashlog.thread_exception_data = line[16:].strip() - return - elif line.startswith('Exception Subtype:'): # iOS - self.crashlog.thread_exception_data = line[18:].strip() + elif line.startswith('Exception'): + self.parse_exception(line) return elif line.startswith('Crashed Thread:'): self.crashlog.crashed_thread_idx = int(line[15:].strip().split()[0])