Index: lldb/examples/python/crashlog.py =================================================================== --- lldb/examples/python/crashlog.py +++ lldb/examples/python/crashlog.py @@ -432,6 +432,8 @@ self.path = os.path.expanduser(path) self.verbose = verbose self.crashlog = CrashLog(debugger, self.path, self.verbose) + # List of DarwinImages sorted by their index. + self.images = list() @abc.abstractmethod def parse(self): @@ -459,8 +461,6 @@ def __init__(self, debugger, path, verbose): super().__init__(debugger, path, verbose) - # List of DarwinImages sorted by their index. - self.images = list() def parse(self): try: @@ -603,14 +603,45 @@ print("error: can't parse application specific backtrace.") return False - (frame_id, frame_img_name, frame_addr, - frame_ofs) = frame_match.groups() + frame_id = frame_img_name = frame_addr = frame_symbol = frame_offset = frame_file = frame_line = frame_column = None + + if len(frame_match.groups()) == 3: + # Get the image UUID from the frame image name. + (frame_id, frame_img_name, frame_addr) = frame_match.groups() + elif len(frame_match.groups()) == 5: + (frame_id, frame_img_name, frame_addr, + frame_symbol, frame_offset) = frame_match.groups() + elif len(frame_match.groups()) == 7: + (frame_id, frame_img_name, frame_addr, + frame_symbol, frame_offset, + frame_file, frame_line) = frame_match.groups() + elif len(frame_match.groups()) == 8: + (frame_id, frame_img_name, frame_addr, + frame_symbol, frame_offset, + frame_file, frame_line, frame_column) = frame_match.groups() thread.add_ident(frame_img_name) if frame_img_name not in self.crashlog.idents: self.crashlog.idents.append(frame_img_name) - thread.frames.append(self.crashlog.Frame(int(frame_id), int( - frame_addr, 0), frame_ofs)) + + description = "" + if frame_img_name and frame_addr and frame_symbol: + description = frame_symbol + frame_offset_value = 0 + if frame_offset: + description += " + " + frame_offset + frame_offset_value = int(frame_offset, 0) + for image in self.images: + if image.identifier == frame_img_name: + image.symbols[frame_symbol] = { + "name": frame_symbol, + "type": "code", + "address": int(frame_addr, 0) - frame_offset_value, + } + + thread.frames.append( + self.crashlog.Frame(int(frame_id), int(frame_addr, 0), description) + ) return True @@ -657,19 +688,48 @@ thread_instrs_regex = re.compile(r'^Thread \d+ instruction stream') thread_regex = re.compile(r'^Thread (\d+).*:') app_backtrace_regex = re.compile(r'^Application Specific Backtrace (\d+).*:') - version = r'\(.+\)|(?:arm|x86_)[0-9a-z]+' - frame_regex = re.compile(r'^(\d+)\s+' # id - r'(.+?)\s+' # img_name - r'(?:' +version+ r'\s+)?' # img_version - r'(0x[0-9a-fA-F]{4,})' # addr (4 chars or more) - r'(?: +(.*))?' # offs + + class VersionRegex: + version = r'\(.+\)|(?:arm|x86_)[0-9a-z]+' + + class FrameRegex(VersionRegex): + @classmethod + def get(cls): + index = r'^(\d+)\s+' + img_name = r'(.+?)\s+' + version = r'(?:' + super().version + r'\s+)?' + address = r'(0x[0-9a-fA-F]{4,})' # 4 digits or more + + symbol = """ + (?: + [ ]+ + (?P.+) + (?: + [ ]\+[ ] + (?P\d+) ) + (?: + [ ]\( + (?P[^:]+):(?P\d+) + (?: + :(?P\d+) + )? + )? + )? + """ + + return re.compile(index + img_name + version + address + symbol, + flags=re.VERBOSE) + + frame_regex = FrameRegex.get() null_frame_regex = re.compile(r'^\d+\s+\?\?\?\s+0{4,} +') image_regex_uuid = re.compile(r'(0x[0-9a-fA-F]+)' # img_lo r'\s+-\s+' # - r'(0x[0-9a-fA-F]+)\s+' # img_hi r'[+]?(.+?)\s+' # img_name - r'(?:(' +version+ r')\s+)?' # img_version + r'(?:(' + + VersionRegex.version + # img_version + r')\s+)?' r'(?:<([-0-9a-fA-F]+)>\s+)?' # img_uuid r'(\?+|/.*)' # img_path ) @@ -690,6 +750,7 @@ CrashLogParseMode.SYSTEM : self.parse_system, CrashLogParseMode.INSTRS : self.parse_instructions, } + self.symbols = {} def parse(self): with open(self.path,'r', encoding='utf-8') as f: @@ -844,29 +905,76 @@ print('warning: thread parser ignored null-frame: "%s"' % line) return frame_match = self.frame_regex.search(line) - if frame_match: - (frame_id, frame_img_name, frame_addr, - frame_ofs) = frame_match.groups() - ident = frame_img_name - self.thread.add_ident(ident) - if ident not in self.crashlog.idents: - self.crashlog.idents.append(ident) - self.thread.frames.append(self.crashlog.Frame(int(frame_id), int( - frame_addr, 0), frame_ofs)) - else: + if not frame_match: print('error: frame regex failed for line: "%s"' % line) + return + + frame_id = frame_img_name = frame_addr = frame_symbol = frame_offset = frame_file = frame_line = frame_column = None + + if len(frame_match.groups()) == 3: + # Get the image UUID from the frame image name. + (frame_id, frame_img_name, frame_addr) = frame_match.groups() + elif len(frame_match.groups()) == 5: + (frame_id, frame_img_name, frame_addr, + frame_symbol, frame_offset) = frame_match.groups() + elif len(frame_match.groups()) == 7: + (frame_id, frame_img_name, frame_addr, + frame_symbol, frame_offset, + frame_file, frame_line) = frame_match.groups() + elif len(frame_match.groups()) == 8: + (frame_id, frame_img_name, frame_addr, + frame_symbol, frame_offset, + frame_file, frame_line, frame_column) = frame_match.groups() + + self.thread.add_ident(frame_img_name) + if frame_img_name not in self.crashlog.idents: + self.crashlog.idents.append(frame_img_name) + + description = "" + # Since images are parsed after threads, we need to build a + # map for every image with a list of all the symbols and addresses + if frame_img_name and frame_addr and frame_symbol: + description = frame_symbol + frame_offset_value = 0 + if frame_offset: + description += " + " + frame_offset + frame_offset_value = int(frame_offset, 0) + if frame_img_name not in self.symbols: + self.symbols[frame_img_name] = list() + self.symbols[frame_img_name].append( + { + "name": frame_symbol, + "address": int(frame_addr, 0) - frame_offset_value, + } + ) + + self.thread.frames.append( + self.crashlog.Frame(int(frame_id), int(frame_addr, 0), description) + ) def parse_images(self, line): image_match = self.image_regex_uuid.search(line) if image_match: (img_lo, img_hi, img_name, img_version, img_uuid, img_path) = image_match.groups() + image = self.crashlog.DarwinImage(int(img_lo, 0), int(img_hi, 0), img_name.strip(), img_version.strip() if img_version else "", uuid.UUID(img_uuid), img_path, self.verbose) + unqualified_img_name = os.path.basename(img_path) + if unqualified_img_name in self.symbols: + for symbol in self.symbols[unqualified_img_name]: + image.symbols[symbol["name"]] = { + "name": symbol["name"], + "type": "code", + # NOTE: "address" is actually the symbol image offset + "address": symbol["address"] - int(img_lo, 0), + } + + self.images.append(image) self.crashlog.images.append(image) else: print("error: image regex failed for: %s" % line) Index: lldb/test/Shell/ScriptInterpreter/Python/Crashlog/Inputs/interactive_crashlog/multithread-test.crash =================================================================== --- /dev/null +++ lldb/test/Shell/ScriptInterpreter/Python/Crashlog/Inputs/interactive_crashlog/multithread-test.crash @@ -0,0 +1,140 @@ +Process: multithread-test [22511] +Path: /Users/USER/*/multithread-test +Identifier: multithread-test +Version: ??? +Code Type: ARM-64 (Native) +Parent Process: zsh [59146] +Responsible: Terminal [1640] +User ID: 501 + +Date/Time: 2022-07-28 11:10:19.4194 -0700 +OS Version: macOS 13.0 () +Report Version: 12 +Anonymous UUID: CDC11418-EDBF-2A49-0D83-8B441A5004B0 + +Sleep/Wake UUID: 7B2A0D73-8966-4B8D-98E9-CC6EC1B44967 + +Time Awake Since Boot: 110000 seconds +Time Since Wake: 214 seconds + +System Integrity Protection: disabled + +Crashed Thread: 2 + +Exception Type: EXC_BAD_ACCESS (SIGSEGV) +Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000 +Exception Codes: 0x0000000000000001, 0x0000000000000000 + +Termination Reason: Namespace SIGNAL, Code 11 Segmentation fault: 11 +Terminating Process: exc handler [22511] + +VM Region Info: 0 is not in any region. Bytes before following region: 4310450176 + REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL + UNUSED SPACE AT START +---> + __TEXT 100ec4000-100ec8000 [ 16K] r-x/r-x SM=COW ...tithread-test + +Thread 0:: Dispatch queue: com.apple.main-thread +0 libsystem_kernel.dylib 0x19cc40b84 __ulock_wait + 8 +1 libsystem_pthread.dylib 0x19cc80394 _pthread_join + 444 +2 libc++.1.dylib 0x19cbd8274 std::__1::thread::join() + 36 +3 multithread-test 0x100ec5b3c main + 160 (multithread-test.cpp:31) +4 dyld 0x2230f8da8 start + 2376 + +Thread 1: +0 libsystem_kernel.dylib 0x19cc42c9c __write_nocancel + 8 +1 libsystem_c.dylib 0x19cb719a8 __swrite + 24 +2 libsystem_c.dylib 0x19cb50ac8 _swrite + 108 +3 libsystem_c.dylib 0x19cb4ec2c __sflush + 232 +4 libsystem_c.dylib 0x19cb42f20 __sfvwrite + 792 +5 libsystem_c.dylib 0x19cb61f64 fwrite + 152 +6 libc++.1.dylib 0x19cbed084 std::__1::__stdoutbuf::overflow(int) + 96 +7 libc++.1.dylib 0x19cbe06b4 std::__1::ostreambuf_iterator >::operator=(char) + 96 +8 libc++.1.dylib 0x19cbe0798 std::__1::basic_ostream >::put(char) + 200 +9 multithread-test 0x100ec5a54 std::__1::basic_ostream >& std::__1::endl >(std::__1::basic_ostream >&) + 64 (ostream:994) +10 multithread-test 0x100ec5a08 std::__1::basic_ostream >::operator<<(std::__1::basic_ostream >& (*)(std::__1::basic_ostream >&)) + 32 (ostream:189) +11 multithread-test 0x100ec5958 call_and_wait(int&) + 48 (multithread-test.cpp:14) +12 multithread-test 0x100ec7684 decltype(static_cast(fp)(static_cast>(fp0))) std::__1::__invoke >(void (*&&)(int&), std::__1::reference_wrapper&&) + 48 (type_traits:3918) +13 multithread-test 0x100ec7608 void std::__1::__thread_execute >, void (*)(int&), std::__1::reference_wrapper, 2ul>(std::__1::tuple >, void (*)(int&), std::__1::reference_wrapper >&, std::__1::__tuple_indices<2ul>) + 56 (thread:287) +14 multithread-test 0x100ec6d58 void* std::__1::__thread_proxy >, void (*)(int&), std::__1::reference_wrapper > >(void*) + 84 (thread:298) +15 libsystem_pthread.dylib 0x19cc7e06c _pthread_start + 148 +16 libsystem_pthread.dylib 0x19cc78e2c thread_start + 8 + +Thread 2 Crashed: +0 multithread-test 0x100ec58f4 bar(int) + 20 (multithread-test.cpp:7) +1 multithread-test 0x100ec591c foo(int) + 24 (multithread-test.cpp:11) +2 multithread-test 0x100ec5a88 compute_pow(int&) + 28 (multithread-test.cpp:20) +3 multithread-test 0x100ec7684 decltype(static_cast(fp)(static_cast>(fp0))) std::__1::__invoke >(void (*&&)(int&), std::__1::reference_wrapper&&) + 48 (type_traits:3918) +4 multithread-test 0x100ec7608 void std::__1::__thread_execute >, void (*)(int&), std::__1::reference_wrapper, 2ul>(std::__1::tuple >, void (*)(int&), std::__1::reference_wrapper >&, std::__1::__tuple_indices<2ul>) + 56 (thread:287) +5 multithread-test 0x100ec6d58 void* std::__1::__thread_proxy >, void (*)(int&), std::__1::reference_wrapper > >(void*) + 84 (thread:298) +6 libsystem_pthread.dylib 0x19cc7e06c _pthread_start + 148 +7 libsystem_pthread.dylib 0x19cc78e2c thread_start + 8 + + +Thread 2 crashed with ARM Thread State (64-bit): + x0: 0x000000000000002a x1: 0x0000600001d291b0 x2: 0x000000019cbbf000 x3: 0x0000000000000000 + x4: 0x00000000000030a0 x5: 0x00000000190008ff x6: 0x0000000000000000 x7: 0x0000000000000000 + x8: 0x0000000000000001 x9: 0x0000000000000000 x10: 0xfffffffe634277cf x11: 0x0000010000000102 + x12: 0x0000010000000102 x13: 0x0000010000000100 x14: 0x0000010000000000 x15: 0x0000000000000001 + x16: 0x000000019cc78ea8 x17: 0x00000001fd0a7698 x18: 0x0000000000000000 x19: 0x000000016f04f000 + x20: 0x0000000000000000 x21: 0x0000000000000000 x22: 0x0000000000000000 x23: 0x0000000000000000 + x24: 0x0000000000000000 x25: 0x0000000000000000 x26: 0x0000000000000000 x27: 0x0000000000000000 + x28: 0x0000000000000000 fp: 0x000000016f04ef00 lr: 0x0000000100ec591c + sp: 0x000000016f04eee0 pc: 0x0000000100ec58f4 cpsr: 0x80001000 + far: 0x0000000000000000 esr: 0x92000046 (Data Abort) byte write Translation fault + +Binary Images: + 0x19cc3e000 - 0x19cc76feb libsystem_kernel.dylib (*) /usr/lib/system/libsystem_kernel.dylib + 0x19cc77000 - 0x19cc83ffb libsystem_pthread.dylib (*) /usr/lib/system/libsystem_pthread.dylib + 0x19cbbf000 - 0x19cc25ff3 libc++.1.dylib (*) /usr/lib/libc++.1.dylib + 0x100ec4000 - 0x100ec7fff multithread-test (*) /Users/USER/*/multithread-test + 0x2230f3000 - 0x22317be4b dyld (*) /usr/lib/dyld + 0x19cb3e000 - 0x19cbbefff libsystem_c.dylib (*) /usr/lib/system/libsystem_c.dylib + 0x0 - 0xffffffffffffffff ??? (*) <00000000-0000-0000-0000-000000000000> ??? + 0x3039 - 0x3420 bogus.dylib (*) <11111111-2222-3333-4444-555555555555> /usr/lib/system/bogus.dylib + +External Modification Summary: + Calls made by other processes targeting this process: + task_for_pid: 0 + thread_create: 0 + thread_set_state: 0 + Calls made by this process: + task_for_pid: 0 + thread_create: 0 + thread_set_state: 0 + Calls made by all processes on this machine: + task_for_pid: 23 + thread_create: 0 + thread_set_state: 812 + +VM Region Summary: +ReadOnly portion of Libraries: Total=762.9M resident=0K(0%) swapped_out_or_unallocated=762.9M(100%) +Writable regions: Total=538.2M written=0K(0%) resident=0K(0%) swapped_out=0K(0%) unallocated=538.2M(100%) + + VIRTUAL REGION +REGION TYPE SIZE COUNT (non-coalesced) +=========== ======= ======= +Kernel Alloc Once 32K 1 +MALLOC 145.2M 12 +MALLOC guard page 96K 5 +MALLOC_NANO (reserved) 384.0M 1 reserved VM address space (unallocated) +STACK GUARD 56.0M 3 +Stack 9264K 3 +__AUTH 46K 11 +__AUTH_CONST 70K 38 +__DATA 169K 36 +__DATA_CONST 187K 40 +__DATA_DIRTY 78K 22 +__LINKEDIT 758.0M 2 +__OBJC_CONST 11K 5 +__OBJC_RO 64.7M 1 +__OBJC_RW 1971K 1 +__TEXT 5076K 42 +dyld private memory 256K 1 +shared memory 64K 3 +=========== ======= ======= +TOTAL 1.4G 227 +TOTAL, minus reserved VM space 1.0G 227 + + + Index: lldb/test/Shell/ScriptInterpreter/Python/Crashlog/interactive_crashlog_legacy.test =================================================================== --- /dev/null +++ lldb/test/Shell/ScriptInterpreter/Python/Crashlog/interactive_crashlog_legacy.test @@ -0,0 +1,43 @@ +# REQUIRES: python, native && target-aarch64 && system-darwin + +# RUN: mkdir -p %t.dir +# RUN: yaml2obj %S/Inputs/interactive_crashlog/multithread-test.yaml > %t.dir/multithread-test +# RUN: %lldb -o 'command script import lldb.macosx.crashlog' \ +# RUN: -o 'crashlog -a -i -t %t.dir/multithread-test %S/Inputs/interactive_crashlog/multithread-test.crash' \ +# RUN: -o "thread list" -o "bt all" 2>&1 | FileCheck %s + +# CHECK: "crashlog" {{.*}} commands have been installed, use the "--help" options on these commands + +# CHECK: (lldb) process status +# CHECK-NEXT: Process 22511 stopped +# CHECK-NEXT: * thread #3, stop reason = EXC_BAD_ACCESS (code=1, address=0x0) +# CHECK-NEXT: frame #0: 0x0000000100ec58f4 multithread-test`bar + +# CHECK: (lldb) thread backtrace +# CHECK-NEXT: * thread #3, stop reason = EXC_BAD_ACCESS (code=1, address=0x0) +# CHECK-NEXT: * frame #0: 0x0000000100ec58f4 multithread-test`bar{{.*}} [artificial] +# CHECK-NEXT: frame #1: 0x0000000100ec591b multithread-test`foo{{.*}} [artificial] +# CHECK-NEXT: frame #2: 0x0000000100ec5a87 multithread-test`compute_pow{{.*}} [artificial] + +# CHECK: (lldb) thread list +# CHECK-NEXT: Process 22511 stopped +# CHECK-NEXT: thread #1: tid = 0x0000, 0x000000019cc40b84{{.*}} +# CHECK-NEXT: thread #2: tid = 0x0001, 0x000000019cc42c9c{{.*}} +# CHECK-NEXT: * thread #3: tid = 0x0002, 0x0000000100ec58f4 multithread-test`bar{{.*}}, stop reason = EXC_BAD_ACCESS (code=1, address=0x0) + +# CHECK: (lldb) bt all +# CHECK: thread #1 +# CHECK: frame #{{[0-9]+}}: 0x000000019cc40b84{{.*}} [artificial] +# CHECK: frame #{{[0-9]+}}: 0x0000000100ec5b3b multithread-test`main{{.*}} [artificial] +# CHECK: frame #{{[0-9]+}}: 0x00000002230f8da7{{.*}} [artificial] +# CHECK-NEXT: thread #2 +# CHECK-NEXT: frame #0: 0x000000019cc42c9c{{.*}} [artificial] +# CHECK: frame #{{[0-9]+}}: 0x0000000100ec5957 multithread-test`call_and_wait{{.*}} [artificial] +# CHECK: frame #{{[0-9]+}}: 0x000000019cc7e06b{{.*}} [artificial] +# CHECK: frame #{{[0-9]+}}: 0x000000019cc78e2b{{.*}} [artificial] +# CHECK-NEXT:* thread #3, stop reason = EXC_BAD_ACCESS (code=1, address=0x0) +# CHECK-NEXT: * frame #0: 0x0000000100ec58f4 multithread-test`bar{{.*}} [artificial] +# CHECK-NEXT: frame #1: 0x0000000100ec591b multithread-test`foo{{.*}} [artificial] +# CHECK-NEXT: frame #2: 0x0000000100ec5a87 multithread-test`compute_pow{{.*}} [artificial] +# CHECK: frame #{{[0-9]+}}: 0x000000019cc7e06b{{.*}} [artificial] +# CHECK: frame #{{[0-9]+}}: 0x000000019cc78e2b{{.*}} [artificial]