This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGbff4673b4178: Add a darwin platform setting to specify which 
exceptions debugserver (authored by jingham).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D125434/new/

https://reviews.llvm.org/D125434

Files:
  lldb/include/lldb/Interpreter/OptionValueString.h
  lldb/include/lldb/Target/Platform.h
  lldb/include/lldb/Utility/StringExtractorGDBRemote.h
  lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
  lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
  lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td
  lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
  lldb/source/Target/Platform.cpp
  lldb/source/Utility/StringExtractorGDBRemote.cpp
  lldb/test/API/macosx/ignore_exceptions/Makefile
  lldb/test/API/macosx/ignore_exceptions/TestIgnoredExceptions.py
  lldb/test/API/macosx/ignore_exceptions/main.c
  lldb/tools/debugserver/source/DNB.cpp
  lldb/tools/debugserver/source/DNB.h
  lldb/tools/debugserver/source/MacOSX/MachException.cpp
  lldb/tools/debugserver/source/MacOSX/MachException.h
  lldb/tools/debugserver/source/MacOSX/MachProcess.h
  lldb/tools/debugserver/source/MacOSX/MachProcess.mm
  lldb/tools/debugserver/source/MacOSX/MachTask.h
  lldb/tools/debugserver/source/MacOSX/MachTask.mm
  lldb/tools/debugserver/source/RNBContext.cpp
  lldb/tools/debugserver/source/RNBContext.h
  lldb/tools/debugserver/source/RNBRemote.cpp
  lldb/tools/debugserver/source/RNBRemote.h
  lldb/tools/debugserver/source/debugserver.cpp

Index: lldb/tools/debugserver/source/debugserver.cpp
===================================================================
--- lldb/tools/debugserver/source/debugserver.cpp
+++ lldb/tools/debugserver/source/debugserver.cpp
@@ -368,7 +368,7 @@
   DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__,
                    attach_pid);
   char err_str[1024];
-  pid = DNBProcessAttach(attach_pid, NULL, ctx.GetUnmaskSignals(), err_str,
+  pid = DNBProcessAttach(attach_pid, NULL, ctx.GetIgnoredExceptions(), err_str,
                          sizeof(err_str));
   g_pid = pid;
 
@@ -1275,7 +1275,7 @@
       break;
 
     case 'U':
-      ctx.SetUnmaskSignals(true);
+      ctx.AddDefaultIgnoredExceptions();
       break;
 
     case '2':
@@ -1574,7 +1574,7 @@
 
         RNBLogSTDOUT("Attaching to process %s...\n", attach_pid_name.c_str());
         nub_process_t pid = DNBProcessAttachByName(
-            attach_pid_name.c_str(), timeout_ptr, ctx.GetUnmaskSignals(),
+            attach_pid_name.c_str(), timeout_ptr, ctx.GetIgnoredExceptions(),
             err_str, sizeof(err_str));
         g_pid = pid;
         if (pid == INVALID_NUB_PROCESS) {
Index: lldb/tools/debugserver/source/RNBRemote.h
===================================================================
--- lldb/tools/debugserver/source/RNBRemote.h
+++ lldb/tools/debugserver/source/RNBRemote.h
@@ -110,6 +110,7 @@
     start_noack_mode,                              // 'QStartNoAckMode'
     prefix_reg_packets_with_tid,        // 'QPrefixRegisterPacketsWithThreadID
     set_logging_mode,                   // 'QSetLogging:'
+    set_ignored_exceptions,             // 'QSetIgnoredExceptions'           
     set_max_packet_size,                // 'QSetMaxPacketSize:'
     set_max_payload_size,               // 'QSetMaxPayloadSize:'
     set_environment_variable,           // 'QEnvironment:'
@@ -197,6 +198,7 @@
   rnb_err_t HandlePacket_QStartNoAckMode(const char *p);
   rnb_err_t HandlePacket_QThreadSuffixSupported(const char *p);
   rnb_err_t HandlePacket_QSetLogging(const char *p);
+  rnb_err_t HandlePacket_QSetIgnoredExceptions(const char *p);
   rnb_err_t HandlePacket_QSetDisableASLR(const char *p);
   rnb_err_t HandlePacket_QSetSTDIO(const char *p);
   rnb_err_t HandlePacket_QSetWorkingDir(const char *p);
Index: lldb/tools/debugserver/source/RNBRemote.cpp
===================================================================
--- lldb/tools/debugserver/source/RNBRemote.cpp
+++ lldb/tools/debugserver/source/RNBRemote.cpp
@@ -394,9 +394,12 @@
                      "'G', 'p', and 'P') support having the thread ID appended "
                      "to the end of the command"));
   t.push_back(Packet(set_logging_mode, &RNBRemote::HandlePacket_QSetLogging,
-                     NULL, "QSetLogging:", "Check if register packets ('g', "
-                                           "'G', 'p', and 'P' support having "
-                                           "the thread ID prefix"));
+                     NULL, "QSetLogging:", "Turn on log channels in debugserver"));
+  t.push_back(Packet(set_ignored_exceptions, &RNBRemote::HandlePacket_QSetIgnoredExceptions,
+                     NULL, "QSetIgnoredExceptions:", "Set the exception types "
+                                           "debugserver won't wait for, allowing "
+                                           "them to be turned into the equivalent "
+                                           "BSD signals by the normal means."));
   t.push_back(Packet(
       set_max_packet_size, &RNBRemote::HandlePacket_QSetMaxPacketSize, NULL,
       "QSetMaxPacketSize:",
@@ -2210,6 +2213,37 @@
   return rnb_success;
 }
 
+rnb_err_t RNBRemote::HandlePacket_QSetIgnoredExceptions(const char *p) {
+  // We can't set the ignored exceptions if we have a running process:
+  if (m_ctx.HasValidProcessID())
+    return SendPacket("E35");
+
+  p += sizeof("QSetIgnoredExceptions:") - 1;
+  bool success = true;
+  while(1) {
+    const char *bar  = strchr(p, '|');
+    if (bar == nullptr) {
+      success = m_ctx.AddIgnoredException(p);
+      break;
+    } else {
+      std::string exc_str(p, bar - p);
+      if (exc_str.empty()) {
+        success = false;
+        break;
+      }
+
+      success = m_ctx.AddIgnoredException(exc_str.c_str());
+      if (!success)
+        break;
+      p = bar + 1;
+    }
+  }
+  if (success)
+    return SendPacket("OK");
+  else
+    return SendPacket("E36");
+}
+
 rnb_err_t RNBRemote::HandlePacket_QThreadSuffixSupported(const char *p) {
   m_thread_suffix_supported = true;
   return SendPacket("OK");
@@ -3791,8 +3825,8 @@
              "'%s'",
              getpid(), attach_name.c_str());
       attach_pid = DNBProcessAttachByName(attach_name.c_str(), NULL,
-                                          Context().GetUnmaskSignals(), err_str,
-                                          sizeof(err_str));
+                                          Context().GetIgnoredExceptions(), 
+                                          err_str, sizeof(err_str));
 
     } else if (strstr(p, "vAttach;") == p) {
       p += strlen("vAttach;");
@@ -3806,7 +3840,8 @@
         DNBLog("[LaunchAttach] START %d vAttach to pid %d", getpid(),
                pid_attaching_to);
         attach_pid = DNBProcessAttach(pid_attaching_to, &attach_timeout_abstime,
-                                      false, err_str, sizeof(err_str));
+                                      m_ctx.GetIgnoredExceptions(), 
+                                      err_str, sizeof(err_str));
       }
     } else {
       return HandlePacket_UNIMPLEMENTED(p);
Index: lldb/tools/debugserver/source/RNBContext.h
===================================================================
--- lldb/tools/debugserver/source/RNBContext.h
+++ lldb/tools/debugserver/source/RNBContext.h
@@ -21,6 +21,7 @@
 
 class RNBContext {
 public:
+  using IgnoredExceptions = std::vector<exception_mask_t>;
   enum {
     event_proc_state_changed = 0x001,
     event_proc_thread_running = 0x002, // Sticky
@@ -118,10 +119,13 @@
   void SetDetachOnError(bool detach) { m_detach_on_error = detach; }
   bool GetDetachOnError() { return m_detach_on_error; }
 
-  void SetUnmaskSignals(bool unmask_signals) {
-    m_unmask_signals = unmask_signals;
+  bool AddIgnoredException(const char *exception_name);
+  
+  void AddDefaultIgnoredExceptions();
+
+  const IgnoredExceptions &GetIgnoredExceptions() {
+    return m_ignored_exceptions;
   }
-  bool GetUnmaskSignals() { return m_unmask_signals; }
 
 protected:
   // Classes that inherit from RNBContext can see and modify these
@@ -144,7 +148,7 @@
   std::string m_working_directory;
   std::string m_process_event;
   bool m_detach_on_error = false;
-  bool m_unmask_signals = false;
+  IgnoredExceptions m_ignored_exceptions;
 
   void StartProcessStatusThread();
   void StopProcessStatusThread();
Index: lldb/tools/debugserver/source/RNBContext.cpp
===================================================================
--- lldb/tools/debugserver/source/RNBContext.cpp
+++ lldb/tools/debugserver/source/RNBContext.cpp
@@ -24,6 +24,7 @@
 #include "DNB.h"
 #include "DNBLog.h"
 #include "RNBRemote.h"
+#include "MacOSX/MachException.h"
 
 // Destructor
 RNBContext::~RNBContext() { SetProcessID(INVALID_NUB_PROCESS); }
@@ -286,3 +287,17 @@
   nub_state_t pid_state = DNBProcessGetState(m_pid);
   return pid_state == eStateRunning || pid_state == eStateStepping;
 }
+
+bool RNBContext::AddIgnoredException(const char *exception_name) {
+  exception_mask_t exc_mask = MachException::ExceptionMask(exception_name);
+  if (exc_mask == 0)
+    return false;
+  m_ignored_exceptions.push_back(exc_mask);
+  return true;
+}
+
+void RNBContext::AddDefaultIgnoredExceptions() {
+  m_ignored_exceptions.push_back(EXC_MASK_BAD_ACCESS);
+  m_ignored_exceptions.push_back(EXC_MASK_BAD_INSTRUCTION);
+  m_ignored_exceptions.push_back(EXC_MASK_ARITHMETIC);
+}
Index: lldb/tools/debugserver/source/MacOSX/MachTask.mm
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachTask.mm
+++ lldb/tools/debugserver/source/MacOSX/MachTask.mm
@@ -602,7 +602,9 @@
   return false;
 }
 
-bool MachTask::StartExceptionThread(bool unmask_signals, DNBError &err) {
+bool MachTask::StartExceptionThread(
+        const RNBContext::IgnoredExceptions &ignored_exceptions, 
+        DNBError &err) {
   DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s ( )", __FUNCTION__);
 
   task_t task = TaskPortForProcessID(err);
@@ -631,10 +633,9 @@
       return false;
     }
 
-    if (unmask_signals) {
-      m_exc_port_info.mask = m_exc_port_info.mask &
-                             ~(EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION |
-                               EXC_MASK_ARITHMETIC);
+    if (!ignored_exceptions.empty()) {
+      for (exception_mask_t mask : ignored_exceptions)
+        m_exc_port_info.mask = m_exc_port_info.mask & ~mask;
     }
 
     // Set the ability to get all exceptions on this port
Index: lldb/tools/debugserver/source/MacOSX/MachTask.h
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachTask.h
+++ lldb/tools/debugserver/source/MacOSX/MachTask.h
@@ -21,6 +21,7 @@
 #include <map>
 #include <string>
 #include "DNBDefs.h"
+#include "RNBContext.h"
 #include "MachException.h"
 #include "MachVMMemory.h"
 #include "PThreadMutex.h"
@@ -67,7 +68,8 @@
   kern_return_t RestoreExceptionPortInfo();
   kern_return_t ShutDownExcecptionThread();
 
-  bool StartExceptionThread(bool unmask_signals, DNBError &err);
+  bool StartExceptionThread(
+      const RNBContext::IgnoredExceptions &ignored_exceptions, DNBError &err);
   nub_addr_t GetDYLDAllImageInfosAddress(DNBError &err);
   kern_return_t BasicInfo(struct task_basic_info *info);
   static kern_return_t BasicInfo(task_t task, struct task_basic_info *info);
Index: lldb/tools/debugserver/source/MacOSX/MachProcess.mm
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachProcess.mm
+++ lldb/tools/debugserver/source/MacOSX/MachProcess.mm
@@ -2590,8 +2590,11 @@
   return NULL;
 }
 
-pid_t MachProcess::AttachForDebug(pid_t pid, bool unmask_signals, char *err_str,
-                                  size_t err_len) {
+pid_t MachProcess::AttachForDebug(
+    pid_t pid, 
+    const RNBContext::IgnoredExceptions &ignored_exceptions, 
+    char *err_str,
+    size_t err_len) {
   // Clear out and clean up from any current state
   Clear();
   if (pid != 0) {
@@ -2608,7 +2611,7 @@
 
     SetState(eStateAttaching);
     m_pid = pid;
-    if (!m_task.StartExceptionThread(unmask_signals, err)) {
+    if (!m_task.StartExceptionThread(ignored_exceptions, err)) {
       const char *err_cstr = err.AsString();
       ::snprintf(err_str, err_len, "%s",
                  err_cstr ? err_cstr : "unable to start the exception thread");
@@ -3112,7 +3115,9 @@
                                    // working directory for inferior to this
     const char *stdin_path, const char *stdout_path, const char *stderr_path,
     bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr,
-    const char *event_data, bool unmask_signals, DNBError &launch_err) {
+    const char *event_data, 
+    const RNBContext::IgnoredExceptions &ignored_exceptions, 
+    DNBError &launch_err) {
   // Clear out and clean up from any current state
   Clear();
 
@@ -3138,7 +3143,7 @@
       m_flags |= (eMachProcessFlagsUsingFBS | eMachProcessFlagsBoardCalculated);
       if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
                                      no_stdio, disable_aslr, event_data,
-                                     unmask_signals, launch_err) != 0)
+                                     ignored_exceptions, launch_err) != 0)
         return m_pid; // A successful SBLaunchForDebug() returns and assigns a
                       // non-zero m_pid.
     }
@@ -3152,7 +3157,7 @@
       m_flags |= (eMachProcessFlagsUsingBKS | eMachProcessFlagsBoardCalculated);
       if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
                                      no_stdio, disable_aslr, event_data,
-                                     unmask_signals, launch_err) != 0)
+                                     ignored_exceptions, launch_err) != 0)
         return m_pid; // A successful SBLaunchForDebug() returns and assigns a
                       // non-zero m_pid.
     }
@@ -3164,7 +3169,7 @@
     std::string app_bundle_path = GetAppBundle(path);
     if (!app_bundle_path.empty()) {
       if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio,
-                           disable_aslr, unmask_signals, launch_err) != 0)
+                           disable_aslr, ignored_exceptions, launch_err) != 0)
         return m_pid; // A successful SBLaunchForDebug() returns and assigns a
                       // non-zero m_pid.
     }
@@ -3198,7 +3203,7 @@
     for (i = 0; (arg = argv[i]) != NULL; i++)
       m_args.push_back(arg);
 
-    m_task.StartExceptionThread(unmask_signals, launch_err);
+    m_task.StartExceptionThread(ignored_exceptions, launch_err);
     if (launch_err.Fail()) {
       if (launch_err.AsString() == NULL)
         launch_err.SetErrorString("unable to start the exception thread");
@@ -3566,7 +3571,9 @@
 
 pid_t MachProcess::SBLaunchForDebug(const char *path, char const *argv[],
                                     char const *envp[], bool no_stdio,
-                                    bool disable_aslr, bool unmask_signals,
+                                    bool disable_aslr, 
+                                    const RNBContext::IgnoredExceptions 
+                                        &ignored_exceptions,
                                     DNBError &launch_err) {
   // Clear out and clean up from any current state
   Clear();
@@ -3583,7 +3590,7 @@
     char const *arg;
     for (i = 0; (arg = argv[i]) != NULL; i++)
       m_args.push_back(arg);
-    m_task.StartExceptionThread(unmask_signals, launch_err);
+    m_task.StartExceptionThread(ignored_exceptions, launch_err);
 
     if (launch_err.Fail()) {
       if (launch_err.AsString() == NULL)
@@ -3784,7 +3791,8 @@
 #if defined(WITH_BKS) || defined(WITH_FBS)
 pid_t MachProcess::BoardServiceLaunchForDebug(
     const char *path, char const *argv[], char const *envp[], bool no_stdio,
-    bool disable_aslr, const char *event_data, bool unmask_signals,
+    bool disable_aslr, const char *event_data, 
+    const RNBContext::IgnoredExceptions &ignored_exceptions,
     DNBError &launch_err) {
   DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path);
 
@@ -3798,7 +3806,7 @@
     char const *arg;
     for (i = 0; (arg = argv[i]) != NULL; i++)
       m_args.push_back(arg);
-    m_task.StartExceptionThread(unmask_signals, launch_err);
+    m_task.StartExceptionThread(ignored_exceptions, launch_err);
 
     if (launch_err.Fail()) {
       if (launch_err.AsString() == NULL)
Index: lldb/tools/debugserver/source/MacOSX/MachProcess.h
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachProcess.h
+++ lldb/tools/debugserver/source/MacOSX/MachProcess.h
@@ -34,6 +34,7 @@
 #include "PThreadCondition.h"
 #include "PThreadEvent.h"
 #include "PThreadMutex.h"
+#include "RNBContext.h"
 #include "ThreadInfo.h"
 
 class DNBThreadResumeActions;
@@ -78,14 +79,17 @@
   };
 
   // Child process control
-  pid_t AttachForDebug(pid_t pid, bool unmask_signals, char *err_str,
+  pid_t AttachForDebug(pid_t pid,
+                       const RNBContext::IgnoredExceptions &ignored_exceptions,
+                       char *err_str,
                        size_t err_len);
   pid_t LaunchForDebug(const char *path, char const *argv[], char const *envp[],
                        const char *working_directory, const char *stdin_path,
                        const char *stdout_path, const char *stderr_path,
                        bool no_stdio, nub_launch_flavor_t launch_flavor,
                        int disable_aslr, const char *event_data,
-                       bool unmask_signals, DNBError &err);
+                       const RNBContext::IgnoredExceptions &ignored_exceptions,
+                       DNBError &err);
 
   static uint32_t GetCPUTypeForLocalProcess(pid_t pid);
   static pid_t ForkChildForPTraceDebugging(const char *path, char const *argv[],
@@ -109,7 +113,8 @@
   pid_t BoardServiceLaunchForDebug(const char *app_bundle_path,
                                    char const *argv[], char const *envp[],
                                    bool no_stdio, bool disable_aslr,
-                                   const char *event_data, bool unmask_signals,
+                                   const char *event_data,
+                                   const RNBContext::IgnoredExceptions &ignored_exceptions,
                                    DNBError &launch_err);
   pid_t BoardServiceForkChildForPTraceDebugging(
       const char *path, char const *argv[], char const *envp[], bool no_stdio,
Index: lldb/tools/debugserver/source/MacOSX/MachException.h
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachException.h
+++ lldb/tools/debugserver/source/MacOSX/MachException.h
@@ -127,6 +127,7 @@
     uint8_t flags; // Action flags describing what to do with the exception
   };
   static const char *Name(exception_type_t exc_type);
+  static exception_mask_t ExceptionMask(const char *name);
 };
 
 #endif
Index: lldb/tools/debugserver/source/MacOSX/MachException.cpp
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachException.cpp
+++ lldb/tools/debugserver/source/MacOSX/MachException.cpp
@@ -512,3 +512,50 @@
   }
   return NULL;
 }
+
+// Returns the exception mask for a given exception name.  
+// 0 is not a legit mask, so we return that in the case of an error.
+exception_mask_t MachException::ExceptionMask(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_MASK_BAD_ACCESS;
+  if (name_str == "BAD_INSTRUCTION")
+    return EXC_MASK_BAD_INSTRUCTION;
+  if (name_str == "ARITHMETIC")
+    return EXC_MASK_ARITHMETIC;
+  if (name_str == "EMULATION")
+    return EXC_MASK_EMULATION;
+  if (name_str == "SOFTWARE")
+    return EXC_MASK_SOFTWARE;
+  if (name_str == "BREAKPOINT")
+    return EXC_MASK_BREAKPOINT;
+  if (name_str == "SYSCALL")
+    return EXC_MASK_SYSCALL;
+  if (name_str == "MACH_SYSCALL")
+    return EXC_MASK_MACH_SYSCALL;
+  if (name_str == "RPC_ALERT")
+    return EXC_MASK_RPC_ALERT;
+#ifdef EXC_CRASH
+  if (name_str == "CRASH")
+    return EXC_MASK_CRASH;
+#endif
+  if (name_str == "RESOURCE")
+    return EXC_MASK_RESOURCE;
+#ifdef EXC_GUARD
+  if (name_str == "GUARD")
+    return EXC_MASK_GUARD;
+#endif
+#ifdef EXC_CORPSE_NOTIFY
+  if (name_str == "CORPSE_NOTIFY")
+    return EXC_MASK_CORPSE_NOTIFY;
+#endif
+  return 0;
+}
Index: lldb/tools/debugserver/source/DNB.h
===================================================================
--- lldb/tools/debugserver/source/DNB.h
+++ lldb/tools/debugserver/source/DNB.h
@@ -51,10 +51,14 @@
 
 nub_process_t DNBProcessGetPIDByName(const char *name);
 nub_process_t DNBProcessAttach(nub_process_t pid, struct timespec *timeout,
-                               bool unmask_signals, char *err_str,
+                               const RNBContext::IgnoredExceptions 
+                                   &ignored_exceptions, 
+                               char *err_str,
                                size_t err_len);
 nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
-                                     bool unmask_signals, char *err_str,
+                                     const RNBContext::IgnoredExceptions 
+                                         &ignored_exceptions, 
+                                     char *err_str,
                                      size_t err_len);
 nub_process_t DNBProcessAttachWait(RNBContext *ctx, const char *wait_name,
                                    bool ignore_existing,
Index: lldb/tools/debugserver/source/DNB.cpp
===================================================================
--- lldb/tools/debugserver/source/DNB.cpp
+++ lldb/tools/debugserver/source/DNB.cpp
@@ -352,7 +352,7 @@
     pid_t pid = processSP->LaunchForDebug(
         path, argv, envp, working_directory, stdin_path, stdout_path,
         stderr_path, no_stdio, ctx->LaunchFlavor(), disable_aslr, event_data,
-        ctx->GetUnmaskSignals(), launch_err);
+        ctx->GetIgnoredExceptions(), launch_err);
     if (err_str) {
       *err_str = '\0';
       if (launch_err.Fail()) {
@@ -412,7 +412,8 @@
 }
 
 nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
-                                     bool unmask_signals, char *err_str,
+                                     const RNBContext::IgnoredExceptions 
+                                             &ignored_exceptions, char *err_str,
                                      size_t err_len) {
   if (err_str && err_len > 0)
     err_str[0] = '\0';
@@ -434,11 +435,13 @@
   }
 
   return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout,
-                          unmask_signals, err_str, err_len);
+                          ignored_exceptions, err_str, err_len);
 }
 
 nub_process_t DNBProcessAttach(nub_process_t attach_pid,
-                               struct timespec *timeout, bool unmask_signals,
+                               struct timespec *timeout, 
+                               const RNBContext::IgnoredExceptions 
+                                       &ignored_exceptions,
                                char *err_str, size_t err_len) {
   if (err_str && err_len > 0)
     err_str[0] = '\0';
@@ -487,7 +490,8 @@
     DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...",
                      attach_pid);
     pid =
-        processSP->AttachForDebug(attach_pid, unmask_signals, err_str, err_len);
+        processSP->AttachForDebug(attach_pid, ignored_exceptions, err_str, 
+                                  err_len);
 
     if (pid != INVALID_NUB_PROCESS) {
       bool res = AddProcessToMap(pid, processSP);
@@ -782,7 +786,8 @@
     DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n",
                      waitfor_process_name, waitfor_pid);
     waitfor_pid = DNBProcessAttach(waitfor_pid, timeout_abstime,
-                                   ctx->GetUnmaskSignals(), err_str, err_len);
+                                   ctx->GetIgnoredExceptions(), err_str, 
+                                   err_len);
   }
 
   bool success = waitfor_pid != INVALID_NUB_PROCESS;
Index: lldb/test/API/macosx/ignore_exceptions/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/ignore_exceptions/main.c
@@ -0,0 +1,27 @@
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <stdio.h>
+
+int g_ints[] = {10, 20, 30, 40, 50, 60};
+
+void
+saction_handler(int signo, siginfo_t info, void *baton) {
+  printf("Got into handler.\n");
+  mprotect(g_ints, sizeof(g_ints), PROT_READ|PROT_WRITE); // stop here in the signal handler
+  g_ints[0] = 20;
+}
+int
+main()
+{
+  mprotect(g_ints, 10*sizeof(int) , PROT_NONE);
+  struct sigaction my_action;
+  sigemptyset(&my_action.sa_mask);
+  my_action.sa_handler = (void (*)(int)) saction_handler;
+  my_action.sa_flags = SA_SIGINFO;
+
+  sigaction(SIGBUS, &my_action, NULL); // Stop here to get things going.
+  int local_value = g_ints[1];
+  return local_value; // Break here to make sure we got past the signal handler
+}
Index: lldb/test/API/macosx/ignore_exceptions/TestIgnoredExceptions.py
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/ignore_exceptions/TestIgnoredExceptions.py
@@ -0,0 +1,60 @@
+"""
+Test that by turning off EXC_BAD_ACCESS catching, we can
+debug into and out of a signal handler.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+
+class TestDarwinSignalHandlers(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipUnlessDarwin
+    def test_ignored_thread(self):
+        """It isn't possible to convert an EXC_BAD_ACCESS to a signal when
+        running under the debugger, which makes debugging SIGBUS handlers
+        and so forth difficult.  This test sends QIgnoreExceptions and that
+        should get us into the signal handler and out again. """
+        self.build()
+        self.main_source_file = lldb.SBFileSpec("main.c")
+        self.suspended_thread_test()
+
+    def suspended_thread_test(self):
+        # Make sure that we don't accept bad values:
+        self.match("settings set platform.plugin.darwin.ignored-exceptions EXC_BAD_AXESS", "EXC_BAD_AXESS", error=True)
+        # Now set ourselves to ignore some exceptions.  The test depends on ignoring EXC_BAD_ACCESS, but I passed a couple
+        # to make sure they parse:
+        self.runCmd("settings set platform.plugin.darwin.ignored-exceptions EXC_BAD_ACCESS|EXC_ARITHMETIC")
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
+                                   "Stop here to get things going", self.main_source_file)
+
+        sig_bkpt = target.BreakpointCreateBySourceRegex("stop here in the signal handler",
+                                                        self.main_source_file)
+        self.assertEqual(sig_bkpt.GetNumLocations(), 1, "Found sig handler breakpoint")
+        return_bkpt = target.BreakpointCreateBySourceRegex("Break here to make sure we got past the signal handler",
+                                                        self.main_source_file)
+        self.assertEqual(return_bkpt.GetNumLocations(), 1, "Found return breakpoint")
+        # Now continue, and we should stop with a stop reason of SIGBUS:
+        process.Continue()
+        self.assertEqual(process.state, lldb.eStateStopped, "Stopped after continue to SIGBUS")
+        self.assertEqual(thread.stop_reason, lldb.eStopReasonSignal)
+        self.assertEqual(thread.GetStopReasonDataAtIndex(0), 10, "Got a SIGBUS")
+
+        # Now when we continue, we'll find our way into the signal handler:
+        threads = lldbutil.continue_to_breakpoint(process, sig_bkpt)
+        self.assertEqual(len(threads), 1, "Stopped at sig breakpoint")
+
+        threads = lldbutil.continue_to_breakpoint(process, return_bkpt)
+        self.assertEqual(len(threads), 1, "Stopped at return breakpoint")
+
+        # Make sure we really changed the value:
+        
+        process.Continue()
+        self.assertEqual(process.state, lldb.eStateExited, "Process exited")
+        self.assertEqual(process.exit_state, 20, "Got the right exit status")
+                         
Index: lldb/test/API/macosx/ignore_exceptions/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/ignore_exceptions/Makefile
@@ -0,0 +1,4 @@
+C_SOURCES := main.c
+CFLAGS_EXTRAS := -std=c99
+
+include Makefile.rules
Index: lldb/source/Utility/StringExtractorGDBRemote.cpp
===================================================================
--- lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -126,6 +126,8 @@
         return eServerPacketType_QSetWorkingDir;
       if (PACKET_STARTS_WITH("QSetLogging:"))
         return eServerPacketType_QSetLogging;
+      if (PACKET_STARTS_WITH("QSetIgnoredExceptions"))
+        return eServerPacketType_QSetIgnoredExceptions;
       if (PACKET_STARTS_WITH("QSetMaxPacketSize:"))
         return eServerPacketType_QSetMaxPacketSize;
       if (PACKET_STARTS_WITH("QSetMaxPayloadSize:"))
Index: lldb/source/Target/Platform.cpp
===================================================================
--- lldb/source/Target/Platform.cpp
+++ lldb/source/Target/Platform.cpp
@@ -1945,6 +1945,10 @@
   return CompilerType();
 }
 
+Args Platform::GetExtraStartupCommands() {
+  return {};
+}
+
 PlatformSP PlatformList::GetOrCreate(llvm::StringRef name) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   for (const PlatformSP &platform_sp : m_platforms) {
Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -954,12 +954,23 @@
   m_gdb_comm.GetVAttachOrWaitSupported();
   m_gdb_comm.EnableErrorStringInPacket();
 
-  size_t num_cmds = GetExtraStartupCommands().GetArgumentCount();
-  for (size_t idx = 0; idx < num_cmds; idx++) {
-    StringExtractorGDBRemote response;
-    m_gdb_comm.SendPacketAndWaitForResponse(
-        GetExtraStartupCommands().GetArgumentAtIndex(idx), response);
+  // First dispatch any commands from the platform:
+  auto handle_cmds = [&] (const Args &args) ->  void {
+    for (const Args::ArgEntry &entry : args) {
+      StringExtractorGDBRemote response;
+      m_gdb_comm.SendPacketAndWaitForResponse(
+          entry.c_str(), response);
+    }
+  };
+  
+  PlatformSP platform_sp = GetTarget().GetPlatform();
+  if (platform_sp) {
+    handle_cmds(platform_sp->GetExtraStartupCommands());
   }
+  
+  // Then dispatch any process commands:
+  handle_cmds(GetExtraStartupCommands());
+
   return error;
 }
 
Index: lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td
===================================================================
--- lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td
+++ lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td
@@ -5,3 +5,12 @@
     DefaultStringValue<"">,
     Desc<"Directories/KDKs to search for kexts in when starting a kernel debug session.">;
 }
+
+let Definition = "platformdarwin" in {
+  def IgnoredExceptions: Property<"ignored-exceptions", "String">,
+    DefaultStringValue<"">,
+    Desc<"List the mach exceptions to ignore, separated by '|' "
+         "(e.g. 'EXC_BAD_ACCESS|EXC_BAD_INSTRUCTION'). "
+         "lldb will instead stop on the BSD signal the exception was converted "
+         "into, if there is one.">;
+}
Index: lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
===================================================================
--- lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
+++ lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
@@ -48,6 +48,18 @@
 
   ~PlatformDarwin() override;
 
+  static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
+
+  static void DebuggerInitialize(lldb_private::Debugger &debugger);
+  
+  static void Initialize();
+
+  static void Terminate();
+
+  static llvm::StringRef GetPluginNameStatic() { return "darwin"; }
+
+  static llvm::StringRef GetDescriptionStatic();
+
   Status PutFile(const FileSpec &source, const FileSpec &destination,
                  uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX) override;
 
@@ -96,6 +108,8 @@
   FileSpec LocateExecutable(const char *basename) override;
 
   Status LaunchProcess(ProcessLaunchInfo &launch_info) override;
+  
+  Args GetExtraStartupCommands() override;
 
   static std::tuple<llvm::VersionTuple, llvm::StringRef>
   ParseVersionBuildDir(llvm::StringRef str);
Index: lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
===================================================================
--- lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -19,11 +19,15 @@
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/HostInfo.h"
 #include "lldb/Host/XML.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Interpreter/Options.h"
 #include "lldb/Symbol/LocateSymbolFile.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/SymbolFile.h"
@@ -48,12 +52,137 @@
 using namespace lldb;
 using namespace lldb_private;
 
+static Status ExceptionMaskValidator(const char *string, void *unused) {
+  Status error;
+  llvm::StringRef str_ref(string);
+  llvm::SmallVector<llvm::StringRef> candidates;
+  str_ref.split(candidates, '|');
+  for (auto candidate : candidates) {
+    if (!(candidate == "EXC_BAD_ACCESS"
+          || candidate == "EXC_BAD_INSTRUCTION"
+          || candidate == "EXC_ARITHMETIC"
+          || candidate == "EXC_RESOURCE"
+          || candidate == "EXC_GUARD")) {
+      error.SetErrorStringWithFormat("invalid exception type: '%s'", 
+          candidate.str().c_str());
+      return error;
+    }
+  }
+  return {};
+}
+
 /// Destructor.
 ///
 /// The destructor is virtual since this class is designed to be
 /// inherited from by the plug-in instance.
 PlatformDarwin::~PlatformDarwin() = default;
 
+// Static Variables
+static uint32_t g_initialize_count = 0;
+
+void PlatformDarwin::Initialize() {
+  Platform::Initialize();
+
+  if (g_initialize_count++ == 0) {
+    PluginManager::RegisterPlugin(PlatformDarwin::GetPluginNameStatic(),
+                                  PlatformDarwin::GetDescriptionStatic(),
+                                  PlatformDarwin::CreateInstance,
+                                  PlatformDarwin::DebuggerInitialize);
+  }
+}
+
+void PlatformDarwin::Terminate() {
+  if (g_initialize_count > 0) {
+    if (--g_initialize_count == 0) {
+      PluginManager::UnregisterPlugin(PlatformDarwin::CreateInstance);
+    }
+  }
+
+  Platform::Terminate();
+}
+
+llvm::StringRef PlatformDarwin::GetDescriptionStatic() {
+  return "Darwin platform plug-in.";
+}
+
+PlatformSP PlatformDarwin::CreateInstance(bool force, const ArchSpec *arch) {
+   // We only create subclasses of the PlatformDarwin plugin.
+   return PlatformSP();
+}
+
+#define LLDB_PROPERTIES_platformdarwin
+#include "PlatformMacOSXProperties.inc"
+
+#define LLDB_PROPERTIES_platformdarwin
+enum {
+#include "PlatformMacOSXPropertiesEnum.inc"
+};
+
+class PlatformDarwinProperties : public Properties {
+public:
+  static ConstString &GetSettingName() {
+    static ConstString g_setting_name("darwin");
+    return g_setting_name;
+  }
+
+  PlatformDarwinProperties() : Properties() {
+    m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
+    m_collection_sp->Initialize(g_platformdarwin_properties);
+  }
+
+  ~PlatformDarwinProperties() override = default;
+
+  const char *GetIgnoredExceptions() const {
+    const uint32_t idx = ePropertyIgnoredExceptions;
+    const OptionValueString *option_value =
+        m_collection_sp->GetPropertyAtIndexAsOptionValueString(
+            NULL, false, idx);
+    assert(option_value);
+    return option_value->GetCurrentValue();
+  }
+    
+  OptionValueString *GetIgnoredExceptionValue() {
+    const uint32_t idx = ePropertyIgnoredExceptions;
+    OptionValueString *option_value =
+        m_collection_sp->GetPropertyAtIndexAsOptionValueString(
+            NULL, false, idx);
+    assert(option_value);
+    return option_value;
+  }
+};
+
+static PlatformDarwinProperties &GetGlobalProperties() {
+  static PlatformDarwinProperties g_settings;
+  return g_settings;
+}
+
+void PlatformDarwin::DebuggerInitialize(
+    lldb_private::Debugger &debugger) {
+  if (!PluginManager::GetSettingForPlatformPlugin(
+          debugger, PlatformDarwinProperties::GetSettingName())) {
+    const bool is_global_setting = false;
+    PluginManager::CreateSettingForPlatformPlugin(
+        debugger, GetGlobalProperties().GetValueProperties(),
+        ConstString("Properties for the Darwin platform plug-in."),
+        is_global_setting);
+    OptionValueString *value = GetGlobalProperties().GetIgnoredExceptionValue();
+    value->SetValidator(ExceptionMaskValidator);
+  }
+}
+
+Args
+PlatformDarwin::GetExtraStartupCommands() {
+  std::string ignored_exceptions 
+      = GetGlobalProperties().GetIgnoredExceptions();
+  if (ignored_exceptions.empty())
+    return {};
+  Args ret_args;
+  std::string packet = "QSetIgnoredExceptions:";
+  packet.append(ignored_exceptions);
+  ret_args.AppendArgument(packet);
+  return ret_args;
+}
+
 lldb_private::Status
 PlatformDarwin::PutFile(const lldb_private::FileSpec &source,
                         const lldb_private::FileSpec &destination, uint32_t uid,
Index: lldb/include/lldb/Utility/StringExtractorGDBRemote.h
===================================================================
--- lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -174,6 +174,7 @@
     eServerPacketType_QMemTags, // write memory tags
 
     eServerPacketType_qLLDBSaveCore,
+    eServerPacketType_QSetIgnoredExceptions
   };
 
   ServerPacketType GetServerPacketType() const;
Index: lldb/include/lldb/Target/Platform.h
===================================================================
--- lldb/include/lldb/Target/Platform.h
+++ lldb/include/lldb/Target/Platform.h
@@ -847,6 +847,8 @@
   }
 
   virtual CompilerType GetSiginfoType(const llvm::Triple &triple);
+  
+  virtual Args GetExtraStartupCommands();
 
 protected:
   /// Create a list of ArchSpecs with the given OS and a architectures. The
Index: lldb/include/lldb/Interpreter/OptionValueString.h
===================================================================
--- lldb/include/lldb/Interpreter/OptionValueString.h
+++ lldb/include/lldb/Interpreter/OptionValueString.h
@@ -109,6 +109,11 @@
   bool IsCurrentValueEmpty() const { return m_current_value.empty(); }
 
   bool IsDefaultValueEmpty() const { return m_default_value.empty(); }
+  
+  void SetValidator(ValidatorCallback validator, void *baton = nullptr) {
+    m_validator = validator;
+    m_validator_baton = baton;
+  }
 
 protected:
   std::string m_current_value;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to