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 <medismail.benn...@gmail.com>


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
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to