aarzilli created this revision.
aarzilli added reviewers: clayborg, jasonmolenda.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
aarzilli requested review of this revision.
Herald added a subscriber: JDevlieghere.

Adds a command line option that makes debugserver propagate the SIGSEGV signal 
to the target process.

Motivation: I'm one of the maintainers of Delve [1] a debugger for Go. We
use debugserver as our backend on macOS and one of the most often reported
bugs is that, on macOS, we don't propagate SIGSEGV back to the target
process [2]. Sometimes some programs will actually cause a SIGSEGV, by
design, and then handle it. Those programs can not be debugged at all.

Since catching signals isn't very important for a Go debugger I'd much
rather have a command line option in debugserver that causes it to let
SIGSEGV go directly to the target process.

[1] https://github.com/go-delve/delve/
[2] https://github.com/go-delve/delve/issues/852


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D89315

Files:
  lldb/tools/debugserver/source/DNB.cpp
  lldb/tools/debugserver/source/DNB.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/RNBRemote.cpp
  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
@@ -195,8 +195,8 @@
 RNBRunLoopMode RNBRunLoopLaunchInferior(RNBRemote *remote,
                                         const char *stdin_path,
                                         const char *stdout_path,
-                                        const char *stderr_path,
-                                        bool no_stdio) {
+                                        const char *stderr_path, bool no_stdio,
+                                        bool unmask_signals) {
   RNBContext &ctx = remote->Context();
 
   // The Process stuff takes a c array, the RNBContext has a vector...
@@ -247,7 +247,7 @@
   nub_process_t pid = DNBProcessLaunch(
       resolved_path, &inferior_argv[0], &inferior_envp[0], cwd, stdin_path,
       stdout_path, stderr_path, no_stdio, launch_flavor, g_disable_aslr,
-      process_event, launch_err_str, sizeof(launch_err_str));
+      process_event, unmask_signals, launch_err_str, sizeof(launch_err_str));
 
   g_pid = pid;
 
@@ -362,13 +362,15 @@
 // or crash process state.
 RNBRunLoopMode RNBRunLoopLaunchAttaching(RNBRemote *remote,
                                          nub_process_t attach_pid,
-                                         nub_process_t &pid) {
+                                         nub_process_t &pid,
+                                         bool unmask_signals) {
   RNBContext &ctx = remote->Context();
 
   DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__,
                    attach_pid);
   char err_str[1024];
-  pid = DNBProcessAttach(attach_pid, NULL, err_str, sizeof(err_str));
+  pid = DNBProcessAttach(attach_pid, NULL, unmask_signals, err_str,
+                         sizeof(err_str));
   g_pid = pid;
 
   if (pid == INVALID_NUB_PROCESS) {
@@ -889,6 +891,10 @@
      'F'}, // When debugserver launches the process, forward debugserver's
            // current environment variables to the child process ("./debugserver
            // -F localhost:1234 -- /bin/ls"
+    {"unmask-signals", no_argument, NULL,
+     'U'}, // debugserver will ignore EXC_MASK_BAD_ACCESS,
+           // EXC_MASK_BAD_INSTRUCTION and EXC_MASK_ARITHMETIC, which results in
+           // SIGSEGV, SIGILL and SIGFPE being propagated to the target process.
     {NULL, 0, NULL, 0}};
 
 int communication_fd = -1;
@@ -979,6 +985,7 @@
   bool reverse_connect = false; // Set to true by an option to indicate we
                                 // should reverse connect to the host:port
                                 // supplied as the first debugserver argument
+  bool unmask_signals = false;
 
 #if !defined(DNBLOG_ENABLED)
   compile_options += "(no-logging) ";
@@ -1260,6 +1267,10 @@
       forward_env = true;
       break;
 
+    case 'U':
+      unmask_signals = true;
+      break;
+
     case '2':
       // File descriptor passed to this process during fork/exec and is already
       // open and ready for communication.
@@ -1513,9 +1524,10 @@
         bool ignore_existing = false;
         RNBLogSTDOUT("Waiting to attach to process %s...\n",
                      waitfor_pid_name.c_str());
-        nub_process_t pid = DNBProcessAttachWait(
-            waitfor_pid_name.c_str(), launch_flavor, ignore_existing,
-            timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
+        nub_process_t pid =
+            DNBProcessAttachWait(waitfor_pid_name.c_str(), launch_flavor,
+                                 ignore_existing, timeout_ptr, waitfor_interval,
+                                 unmask_signals, err_str, sizeof(err_str));
         g_pid = pid;
 
         if (pid == INVALID_NUB_PROCESS) {
@@ -1533,7 +1545,8 @@
 
         RNBLogSTDOUT("Attaching to process %i...\n", attach_pid);
         nub_process_t attached_pid;
-        mode = RNBRunLoopLaunchAttaching(remote, attach_pid, attached_pid);
+        mode = RNBRunLoopLaunchAttaching(remote, attach_pid, attached_pid,
+                                         unmask_signals);
         if (mode != eRNBRunLoopModeInferiorExecuting) {
           const char *error_str = remote->Context().LaunchStatus().AsString();
           RNBLogSTDERR("error: failed to attach process %i: %s\n", attach_pid,
@@ -1549,8 +1562,9 @@
         }
 
         RNBLogSTDOUT("Attaching to process %s...\n", attach_pid_name.c_str());
-        nub_process_t pid = DNBProcessAttachByName(
-            attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
+        nub_process_t pid =
+            DNBProcessAttachByName(attach_pid_name.c_str(), timeout_ptr,
+                                   unmask_signals, err_str, sizeof(err_str));
         g_pid = pid;
         if (pid == INVALID_NUB_PROCESS) {
           ctx.LaunchStatus().SetError(-1, DNBError::Generic);
@@ -1597,7 +1611,7 @@
     case eRNBRunLoopModeInferiorLaunching: {
       mode = RNBRunLoopLaunchInferior(remote, ctx.GetSTDINPath(),
                                       ctx.GetSTDOUTPath(), ctx.GetSTDERRPath(),
-                                      no_stdio);
+                                      no_stdio, unmask_signals);
 
       if (mode == eRNBRunLoopModeInferiorExecuting) {
         if (port != INT32_MAX) {
Index: lldb/tools/debugserver/source/RNBRemote.cpp
===================================================================
--- lldb/tools/debugserver/source/RNBRemote.cpp
+++ lldb/tools/debugserver/source/RNBRemote.cpp
@@ -3928,7 +3928,7 @@
       const bool ignore_existing = true;
       attach_pid = DNBProcessAttachWait(
           attach_name.c_str(), m_ctx.LaunchFlavor(), ignore_existing, NULL,
-          1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
+          1000, false, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
 
     } else if (strstr(p, "vAttachOrWait;") == p) {
       p += strlen("vAttachOrWait;");
@@ -3940,7 +3940,7 @@
       const bool ignore_existing = false;
       attach_pid = DNBProcessAttachWait(
           attach_name.c_str(), m_ctx.LaunchFlavor(), ignore_existing, NULL,
-          1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
+          1000, false, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
     } else if (strstr(p, "vAttachName;") == p) {
       p += strlen("vAttachName;");
       if (!GetProcessNameFrom_vAttach(p, attach_name)) {
@@ -3948,8 +3948,8 @@
             __FILE__, __LINE__, p, "non-hex char in arg on 'vAttachName' pkt");
       }
 
-      attach_pid = DNBProcessAttachByName(attach_name.c_str(), NULL, err_str,
-                                          sizeof(err_str));
+      attach_pid = DNBProcessAttachByName(attach_name.c_str(), NULL, false,
+                                          err_str, sizeof(err_str));
 
     } else if (strstr(p, "vAttach;") == p) {
       p += strlen("vAttach;");
@@ -3961,7 +3961,7 @@
         struct timespec attach_timeout_abstime;
         DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, 30, 0);
         attach_pid = DNBProcessAttach(pid_attaching_to, &attach_timeout_abstime,
-                                      err_str, sizeof(err_str));
+                                      false, err_str, sizeof(err_str));
       }
     } else {
       return HandlePacket_UNIMPLEMENTED(p);
Index: lldb/tools/debugserver/source/MacOSX/MachTask.mm
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachTask.mm
+++ lldb/tools/debugserver/source/MacOSX/MachTask.mm
@@ -595,7 +595,7 @@
   return false;
 }
 
-bool MachTask::StartExceptionThread(DNBError &err) {
+bool MachTask::StartExceptionThread(bool unmask_signals, DNBError &err) {
   DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s ( )", __FUNCTION__);
 
   task_t task = TaskPortForProcessID(err);
@@ -624,6 +624,12 @@
       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);
+    }
+
     // Set the ability to get all exceptions on this port
     err = ::task_set_exception_ports(
         task, m_exc_port_info.mask, m_exception_port,
Index: lldb/tools/debugserver/source/MacOSX/MachTask.h
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachTask.h
+++ lldb/tools/debugserver/source/MacOSX/MachTask.h
@@ -67,7 +67,7 @@
   kern_return_t RestoreExceptionPortInfo();
   kern_return_t ShutDownExcecptionThread();
 
-  bool StartExceptionThread(DNBError &err);
+  bool StartExceptionThread(bool unmask_signals, 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
@@ -2589,7 +2589,8 @@
   return NULL;
 }
 
-pid_t MachProcess::AttachForDebug(pid_t pid, char *err_str, size_t err_len) {
+pid_t MachProcess::AttachForDebug(pid_t pid, bool unmask_signals, char *err_str,
+                                  size_t err_len) {
   // Clear out and clean up from any current state
   Clear();
   if (pid != 0) {
@@ -2606,7 +2607,7 @@
 
     SetState(eStateAttaching);
     m_pid = pid;
-    if (!m_task.StartExceptionThread(err)) {
+    if (!m_task.StartExceptionThread(unmask_signals, err)) {
       const char *err_cstr = err.AsString();
       ::snprintf(err_str, err_len, "%s",
                  err_cstr ? err_cstr : "unable to start the exception thread");
@@ -3066,7 +3067,7 @@
                                    // 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, DNBError &launch_err) {
+    const char *event_data, bool unmask_signals, DNBError &launch_err) {
   // Clear out and clean up from any current state
   Clear();
 
@@ -3171,7 +3172,7 @@
     for (i = 0; (arg = argv[i]) != NULL; i++)
       m_args.push_back(arg);
 
-    m_task.StartExceptionThread(launch_err);
+    m_task.StartExceptionThread(unmask_signals, launch_err);
     if (launch_err.Fail()) {
       if (launch_err.AsString() == NULL)
         launch_err.SetErrorString("unable to start the exception thread");
@@ -3514,7 +3515,8 @@
 
 pid_t MachProcess::SBLaunchForDebug(const char *path, char const *argv[],
                                     char const *envp[], bool no_stdio,
-                                    bool disable_aslr, DNBError &launch_err) {
+                                    bool disable_aslr, bool unmask_signals,
+                                    DNBError &launch_err) {
   // Clear out and clean up from any current state
   Clear();
 
@@ -3530,7 +3532,7 @@
     char const *arg;
     for (i = 0; (arg = argv[i]) != NULL; i++)
       m_args.push_back(arg);
-    m_task.StartExceptionThread(launch_err);
+    m_task.StartExceptionThread(unmask_signals, launch_err);
 
     if (launch_err.Fail()) {
       if (launch_err.AsString() == NULL)
@@ -3727,7 +3729,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, DNBError &launch_err) {
+    bool disable_aslr, const char *event_data, bool unmask_signals,
+    DNBError &launch_err) {
   DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path);
 
   // Fork a child process for debugging
@@ -3740,7 +3743,7 @@
     char const *arg;
     for (i = 0; (arg = argv[i]) != NULL; i++)
       m_args.push_back(arg);
-    m_task.StartExceptionThread(launch_err);
+    m_task.StartExceptionThread(unmask_signals, 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
@@ -78,12 +78,14 @@
   };
 
   // Child process control
-  pid_t AttachForDebug(pid_t pid, char *err_str, size_t err_len);
+  pid_t AttachForDebug(pid_t pid, bool unmask_signals, 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, DNBError &err);
+                       int disable_aslr, const char *event_data,
+                       bool unmask_signals, DNBError &err);
 
   static uint32_t GetCPUTypeForLocalProcess(pid_t pid);
   static pid_t ForkChildForPTraceDebugging(const char *path, char const *argv[],
@@ -107,7 +109,7 @@
   pid_t BoardServiceLaunchForDebug(const char *app_bundle_path,
                                    char const *argv[], char const *envp[],
                                    bool no_stdio, bool disable_aslr,
-                                   const char *event_data,
+                                   const char *event_data, bool unmask_signals,
                                    DNBError &launch_err);
   pid_t BoardServiceForkChildForPTraceDebugging(
       const char *path, char const *argv[], char const *envp[], bool no_stdio,
@@ -128,7 +130,7 @@
 #ifdef WITH_SPRINGBOARD
   pid_t SBLaunchForDebug(const char *app_bundle_path, char const *argv[],
                          char const *envp[], bool no_stdio, bool disable_aslr,
-                         DNBError &launch_err);
+                         bool unmask_signals, DNBError &launch_err);
   static pid_t SBForkChildForPTraceDebugging(const char *path,
                                              char const *argv[],
                                              char const *envp[], bool no_stdio,
Index: lldb/tools/debugserver/source/DNB.h
===================================================================
--- lldb/tools/debugserver/source/DNB.h
+++ lldb/tools/debugserver/source/DNB.h
@@ -47,19 +47,20 @@
                                    // 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, char *err_str, size_t err_len);
+    const char *event_data, bool unmask_signals, char *err_str, size_t err_len);
 
 nub_process_t DNBProcessGetPIDByName(const char *name);
 nub_process_t DNBProcessAttach(nub_process_t pid, struct timespec *timeout,
-                               char *err_str, size_t err_len);
+                               bool unmask_signals, char *err_str,
+                               size_t err_len);
 nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
-                                     char *err_str, size_t err_len);
-nub_process_t
-DNBProcessAttachWait(const char *wait_name, nub_launch_flavor_t launch_flavor,
-                     bool ignore_existing, struct timespec *timeout,
-                     useconds_t interval, char *err_str, size_t err_len,
-                     DNBShouldCancelCallback should_cancel = NULL,
-                     void *callback_data = NULL);
+                                     bool unmask_signals, char *err_str,
+                                     size_t err_len);
+nub_process_t DNBProcessAttachWait(
+    const char *wait_name, nub_launch_flavor_t launch_flavor,
+    bool ignore_existing, struct timespec *timeout, useconds_t interval,
+    bool unmask_signals, char *err_str, size_t err_len,
+    DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL);
 // Resume a process with exact instructions on what to do with each thread:
 // - If no thread actions are supplied (actions is NULL or num_actions is zero),
 //   then all threads are continued.
Index: lldb/tools/debugserver/source/DNB.cpp
===================================================================
--- lldb/tools/debugserver/source/DNB.cpp
+++ lldb/tools/debugserver/source/DNB.cpp
@@ -324,7 +324,8 @@
                                    // 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, char *err_str, size_t err_len) {
+    const char *event_data, bool unmask_signals, char *err_str,
+    size_t err_len) {
   DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, "
                                 "working_dir=%s, stdin=%s, stdout=%s, "
                                 "stderr=%s, no-stdio=%i, launch_flavor = %u, "
@@ -349,10 +350,10 @@
   MachProcessSP processSP(new MachProcess);
   if (processSP.get()) {
     DNBError launch_err;
-    pid_t pid = processSP->LaunchForDebug(path, argv, envp, working_directory,
-                                          stdin_path, stdout_path, stderr_path,
-                                          no_stdio, launch_flavor, disable_aslr,
-                                          event_data, launch_err);
+    pid_t pid = processSP->LaunchForDebug(
+        path, argv, envp, working_directory, stdin_path, stdout_path,
+        stderr_path, no_stdio, launch_flavor, disable_aslr, event_data,
+        unmask_signals, launch_err);
     if (err_str) {
       *err_str = '\0';
       if (launch_err.Fail()) {
@@ -412,7 +413,8 @@
 }
 
 nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
-                                     char *err_str, size_t err_len) {
+                                     bool unmask_signals, char *err_str,
+                                     size_t err_len) {
   if (err_str && err_len > 0)
     err_str[0] = '\0';
   std::vector<struct kinfo_proc> matching_proc_infos;
@@ -433,12 +435,12 @@
   }
 
   return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout,
-                          err_str, err_len);
+                          unmask_signals, err_str, err_len);
 }
 
 nub_process_t DNBProcessAttach(nub_process_t attach_pid,
-                               struct timespec *timeout, char *err_str,
-                               size_t err_len) {
+                               struct timespec *timeout, bool unmask_signals,
+                               char *err_str, size_t err_len) {
   if (err_str && err_len > 0)
     err_str[0] = '\0';
 
@@ -480,7 +482,8 @@
   if (processSP.get()) {
     DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...",
                      attach_pid);
-    pid = processSP->AttachForDebug(attach_pid, err_str, err_len);
+    pid =
+        processSP->AttachForDebug(attach_pid, unmask_signals, err_str, err_len);
 
     if (pid != INVALID_NUB_PROCESS) {
       bool res = AddProcessToMap(pid, processSP);
@@ -670,8 +673,9 @@
 nub_process_t DNBProcessAttachWait(
     const char *waitfor_process_name, nub_launch_flavor_t launch_flavor,
     bool ignore_existing, struct timespec *timeout_abstime,
-    useconds_t waitfor_interval, char *err_str, size_t err_len,
-    DNBShouldCancelCallback should_cancel_callback, void *callback_data) {
+    useconds_t waitfor_interval, bool unmask_signals, char *err_str,
+    size_t err_len, DNBShouldCancelCallback should_cancel_callback,
+    void *callback_data) {
   DNBError prepare_error;
   std::vector<struct kinfo_proc> exclude_proc_infos;
   size_t num_exclude_proc_infos;
@@ -771,8 +775,8 @@
   if (waitfor_pid != INVALID_NUB_PROCESS) {
     DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n",
                      waitfor_process_name, waitfor_pid);
-    waitfor_pid =
-        DNBProcessAttach(waitfor_pid, timeout_abstime, err_str, err_len);
+    waitfor_pid = DNBProcessAttach(waitfor_pid, timeout_abstime, unmask_signals,
+                                   err_str, err_len);
   }
 
   bool success = waitfor_pid != INVALID_NUB_PROCESS;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to