mib created this revision.
mib added reviewers: JDevlieghere, jingham, jasonmolenda.
mib added a project: LLDB.
Herald added a project: All.
mib requested review of this revision.
Herald added a subscriber: lldb-commits.
This patch improve exception reporting when loading a crash report in a
scripted process. Now, we parse the `exception` dictionary from the
crash report use it the create a higher fidelity `MachException` stop info.
This patch also updates the test to reflect that change.
rdar://97096486
Signed-off-by: Med Ismail Bennani <[email protected]>
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D131086
Files:
lldb/examples/python/scripted_process/crashlog_scripted_process.py
lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
lldb/source/Plugins/Process/Utility/StopInfoMachException.h
lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
lldb/test/Shell/ScriptInterpreter/Python/Crashlog/scripted_crashlog_json.test
lldb/test/Shell/ScriptInterpreter/Python/Crashlog/skipped_status_interactive_crashlog.test
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]
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/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,38 @@
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);
+ uint32_t exc_type =
+ StopInfoMachException::MachException::ExceptionCode(value.data());
+
+ StructuredData::Array *exc_rawcodes;
+ mach_exception->GetValueForKeyAsArray("rawCodes", exc_rawcodes);
+ llvm::SmallVector<uint64_t, 3> 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<bool>(
Index: lldb/source/Plugins/Process/Utility/StopInfoMachException.h
===================================================================
--- lldb/source/Plugins/Process/Utility/StopInfoMachException.h
+++ lldb/source/Plugins/Process/Utility/StopInfoMachException.h
@@ -37,6 +37,11 @@
const char *GetDescription() override;
+ struct MachException {
+ static const char *Name(uint32_t exc_type);
+ static uint32_t 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 <kern/exc_resource.h>
+#include <mach/exception.h>
#endif
#include "lldb/Breakpoint/Watchpoint.h"
@@ -519,6 +520,97 @@
return nullptr;
}
+const char *StopInfoMachException::MachException::Name(uint32_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;
+}
+
+// Returns the exception code for a given exception name.
+// 0 is not a legit code, so we return that in the case of an error.
+uint32_t StopInfoMachException::MachException::ExceptionCode(const char *name) {
+ static const char *exception_prefix = "EXC_";
+ static const int prefix_len = strlen(exception_prefix);
+
+ // All mach exceptions start with this prefix:
+ if (strstr(name, exception_prefix) != name)
+ return 0;
+
+ name += prefix_len;
+ std::string name_str = name;
+ if (name_str == "BAD_ACCESS")
+ return EXC_BAD_ACCESS;
+ if (name_str == "BAD_INSTRUCTION")
+ return EXC_BAD_INSTRUCTION;
+ if (name_str == "ARITHMETIC")
+ return EXC_ARITHMETIC;
+ if (name_str == "EMULATION")
+ return EXC_EMULATION;
+ if (name_str == "SOFTWARE")
+ return EXC_SOFTWARE;
+ if (name_str == "BREAKPOINT")
+ return EXC_BREAKPOINT;
+ if (name_str == "SYSCALL")
+ return EXC_SYSCALL;
+ if (name_str == "MACH_SYSCALL")
+ return EXC_MACH_SYSCALL;
+ if (name_str == "RPC_ALERT")
+ return EXC_RPC_ALERT;
+#ifdef EXC_CRASH
+ if (name_str == "CRASH")
+ return EXC_CRASH;
+#endif
+ if (name_str == "RESOURCE")
+ return EXC_RESOURCE;
+#ifdef EXC_GUARD
+ if (name_str == "GUARD")
+ return EXC_GUARD;
+#endif
+#ifdef EXC_CORPSE_NOTIFY
+ if (name_str == "CORPSE_NOTIFY")
+ return EXC_CORPSE_NOTIFY;
+#endif
+ return 0;
+}
+
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/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
@@ -19,6 +19,8 @@
self.pid = crashlog.process_id
self.addr_mask = crashlog.addr_mask
self.crashed_thread_idx = crashlog.crashed_thread_idx
+ if crashlog_parser.data and 'exception' in crashlog_parser.data:
+ self.exception = crashlog_parser.data['exception']
self.loaded_images = []
def load_images(self, images):
@@ -73,6 +75,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:
@@ -158,9 +161,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:
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits