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 @@ -70,6 +70,7 @@ self.pid = super().get_process_id() self.crashed_thread_idx = 0 + self.exception = None self.parse_crashlog() def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo: @@ -155,9 +156,12 @@ def get_stop_reason(self) -> Dict[str, Any]: if not self.has_crashed: - return { "type": lldb.eStopReasonNone, "data": { }} + return { "type": lldb.eStopReasonNone } # TODO: Investigate what stop reason should be reported when crashed - return { "type": lldb.eStopReasonException, "data": { "desc": "EXC_BAD_ACCESS" }} + stop_reason = { "type": lldb.eStopReasonException, "data": { }} + if self.scripted_process.exception: + stop_reason['data']['mach_exception'] = self.scripted_process.exception + return stop_reason def get_register_context(self) -> str: if not self.register_ctx: Index: lldb/source/Plugins/Process/Utility/StopInfoMachException.h =================================================================== --- lldb/source/Plugins/Process/Utility/StopInfoMachException.h +++ lldb/source/Plugins/Process/Utility/StopInfoMachException.h @@ -13,6 +13,11 @@ #include "lldb/Target/StopInfo.h" +#if defined(__APPLE__) +// Needed for the EXC_* defines +#include +#endif + namespace lldb_private { class StopInfoMachException : public StopInfo { @@ -37,6 +42,11 @@ const char *GetDescription() override; + struct MachException { + static const char *Name(exception_type_t exc_type); + static llvm::Optional ExceptionCode(const char *name); + }; + // Since some mach exceptions will be reported as breakpoints, signals, // or trace, we use this static accessor which will translate the mach // exception into the correct StopInfo. Index: lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp =================================================================== --- lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -13,6 +13,7 @@ #if defined(__APPLE__) // Needed for the EXC_RESOURCE interpretation macros #include +#include #endif #include "lldb/Breakpoint/Watchpoint.h" @@ -519,6 +520,76 @@ return nullptr; } +const char * +StopInfoMachException::MachException::Name(exception_type_t exc_type) { + switch (exc_type) { + case EXC_BAD_ACCESS: + return "EXC_BAD_ACCESS"; + case EXC_BAD_INSTRUCTION: + return "EXC_BAD_INSTRUCTION"; + case EXC_ARITHMETIC: + return "EXC_ARITHMETIC"; + case EXC_EMULATION: + return "EXC_EMULATION"; + case EXC_SOFTWARE: + return "EXC_SOFTWARE"; + case EXC_BREAKPOINT: + return "EXC_BREAKPOINT"; + case EXC_SYSCALL: + return "EXC_SYSCALL"; + case EXC_MACH_SYSCALL: + return "EXC_MACH_SYSCALL"; + case EXC_RPC_ALERT: + return "EXC_RPC_ALERT"; +#ifdef EXC_CRASH + case EXC_CRASH: + return "EXC_CRASH"; +#endif + case EXC_RESOURCE: + return "EXC_RESOURCE"; +#ifdef EXC_GUARD + case EXC_GUARD: + return "EXC_GUARD"; +#endif +#ifdef EXC_CORPSE_NOTIFY + case EXC_CORPSE_NOTIFY: + return "EXC_CORPSE_NOTIFY"; +#endif +#ifdef EXC_CORPSE_VARIANT_BIT + case EXC_CORPSE_VARIANT_BIT: + return "EXC_CORPSE_VARIANT_BIT"; +#endif + default: + break; + } + return NULL; +} + +llvm::Optional +StopInfoMachException::MachException::ExceptionCode(const char *name) { + return llvm::StringSwitch>(name) + .Case("EXC_BAD_ACCESS", EXC_BAD_ACCESS) + .Case("EXC_BAD_INSTRUCTION", EXC_BAD_INSTRUCTION) + .Case("EXC_ARITHMETIC", EXC_ARITHMETIC) + .Case("EXC_EMULATION", EXC_EMULATION) + .Case("EXC_SOFTWARE", EXC_SOFTWARE) + .Case("EXC_BREAKPOINT", EXC_BREAKPOINT) + .Case("EXC_SYSCALL", EXC_SYSCALL) + .Case("EXC_MACH_SYSCALL", EXC_MACH_SYSCALL) + .Case("EXC_RPC_ALERT", EXC_RPC_ALERT) +#ifdef EXC_CRASH + .Case("EXC_CRASH", EXC_CRASH) +#endif + .Case("EXC_RESOURCE", EXC_RESOURCE) +#ifdef EXC_GUARD + .Case("EXC_GUARD", EXC_GUARD) +#endif +#ifdef EXC_CORPSE_NOTIFY + .Case("EXC_CORPSE_NOTIFY", EXC_CORPSE_NOTIFY) +#endif + .Default(llvm::None); +} + StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( Thread &thread, uint32_t exc_type, uint32_t exc_data_count, uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code, Index: lldb/source/Plugins/Process/scripted/ScriptedThread.cpp =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedThread.cpp +++ lldb/source/Plugins/Process/scripted/ScriptedThread.cpp @@ -9,6 +9,7 @@ #include "ScriptedThread.h" #include "Plugins/Process/Utility/RegisterContextThreadMemory.h" +#include "Plugins/Process/Utility/StopInfoMachException.h" #include "lldb/Target/OperatingSystem.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -259,11 +260,42 @@ StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); } break; case lldb::eStopReasonException: { - llvm::StringRef description; - data_dict->GetValueForKeyAsString("desc", description); + StructuredData::Dictionary *mach_exception; + if (!data_dict->GetValueForKeyAsDictionary("mach_exception", + mach_exception)) { + stop_info_sp = + StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS"); + } else { + llvm::StringRef value; + mach_exception->GetValueForKeyAsString("type", value); + auto exc_type = + StopInfoMachException::MachException::ExceptionCode(value.data()); + + if (!exc_type) + return false; + + StructuredData::Array *exc_rawcodes; + mach_exception->GetValueForKeyAsArray("rawCodes", exc_rawcodes); + llvm::SmallVector raw_codes; + + auto fetch_data = [&raw_codes](StructuredData::Object *obj) { + if (!obj) + return false; + raw_codes.push_back(obj->GetIntegerValue()); + return true; + }; + + exc_rawcodes->ForEach(fetch_data); + + uint32_t exc_data_size = raw_codes.size(); + + stop_info_sp = StopInfoMachException::CreateStopReasonWithMachException( + *this, *exc_type, exc_data_size, + exc_data_size >= 1 ? raw_codes[0] : 0, + exc_data_size >= 2 ? raw_codes[1] : 0, + exc_data_size >= 3 ? raw_codes[2] : 0); + } - stop_info_sp = - StopInfo::CreateStopReasonWithException(*this, description.data()); } break; default: return ScriptedInterface::ErrorWithMessage( Index: lldb/test/Shell/ScriptInterpreter/Python/Crashlog/scripted_crashlog_json.test =================================================================== --- lldb/test/Shell/ScriptInterpreter/Python/Crashlog/scripted_crashlog_json.test +++ lldb/test/Shell/ScriptInterpreter/Python/Crashlog/scripted_crashlog_json.test @@ -10,11 +10,11 @@ # CHECK: (lldb) process status # CHECK-NEXT: Process 22511 stopped -# CHECK-NEXT: * thread #3, stop reason = EXC_BAD_ACCESS +# 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 +# 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] @@ -23,7 +23,7 @@ # CHECK-NEXT: Process 22511 stopped # CHECK-NEXT: thread #1: tid = 0x23c7fe, 0x000000019cc40b84 libsystem_kernel.dylib`__ulock_wait{{.*}}, queue = 'com.apple.main-thread' # CHECK-NEXT: thread #2: tid = 0x23c800, 0x000000019cc42c9c libsystem_kernel.dylib`{{.*}} -# CHECK-NEXT: * thread #3: tid = 0x23c801, 0x0000000100ec58f4 multithread-test`bar{{.*}}, stop reason = EXC_BAD_ACCESS +# CHECK-NEXT: * thread #3: tid = 0x23c801, 0x0000000100ec58f4 multithread-test`bar{{.*}}, stop reason = EXC_BAD_ACCESS (code=1, address=0x0) # CHECK: (lldb) bt all # CHECK: thread #1, queue = 'com.apple.main-thread' @@ -35,7 +35,7 @@ # CHECK: frame #{{[0-9]+}}: 0x0000000100ec5957 multithread-test`call_and_wait{{.*}} [artificial] # CHECK: frame #{{[0-9]+}}: 0x000000019cc7e06b libsystem_pthread.dylib`_pthread_start{{.*}} [artificial] # CHECK: frame #{{[0-9]+}}: 0x000000019cc78e2b libsystem_pthread.dylib`thread_start{{.*}} [artificial] -# CHECK-NEXT:* thread #3, stop reason = EXC_BAD_ACCESS +# 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] Index: lldb/test/Shell/ScriptInterpreter/Python/Crashlog/skipped_status_interactive_crashlog.test =================================================================== --- lldb/test/Shell/ScriptInterpreter/Python/Crashlog/skipped_status_interactive_crashlog.test +++ lldb/test/Shell/ScriptInterpreter/Python/Crashlog/skipped_status_interactive_crashlog.test @@ -11,11 +11,11 @@ process status # CHECK: Process 22511 stopped -# CHECK-NEXT: * thread #3, stop reason = EXC_BAD_ACCESS +# CHECK-NEXT: * thread #3, stop reason = EXC_BAD_ACCESS (code=1, address=0x0) # CHECK-NEXT: frame #0: 0x0000000100ec58f4 multithread-test`bar thread backtrace -# CHECK: * thread #3, stop reason = EXC_BAD_ACCESS +# CHECK: * 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] @@ -24,7 +24,7 @@ # CHECK: Process 22511 stopped # CHECK-NEXT: thread #1: tid = 0x23c7fe, 0x000000019cc40b84 libsystem_kernel.dylib`__ulock_wait{{.*}}, queue = 'com.apple.main-thread' # CHECK-NEXT: thread #2: tid = 0x23c800, 0x000000019cc42c9c libsystem_kernel.dylib`{{.*}} -# CHECK-NEXT: * thread #3: tid = 0x23c801, 0x0000000100ec58f4 multithread-test`bar{{.*}}, stop reason = EXC_BAD_ACCESS +# CHECK-NEXT: * thread #3: tid = 0x23c801, 0x0000000100ec58f4 multithread-test`bar{{.*}}, stop reason = EXC_BAD_ACCESS (code=1, address=0x0) bt all # CHECK: thread #1, queue = 'com.apple.main-thread' @@ -36,7 +36,7 @@ # CHECK: frame #{{[0-9]+}}: 0x0000000100ec5957 multithread-test`call_and_wait{{.*}} [artificial] # CHECK: frame #{{[0-9]+}}: 0x000000019cc7e06b libsystem_pthread.dylib`_pthread_start{{.*}} [artificial] # CHECK: frame #{{[0-9]+}}: 0x000000019cc78e2b libsystem_pthread.dylib`thread_start{{.*}} [artificial] -# CHECK-NEXT:* thread #3, stop reason = EXC_BAD_ACCESS +# 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]