[lldb] [llvm] [lldb] [lldb-server] Introduce Host/qnx and NativeProcessQNX (PR #97630)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 3 13:21:04 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Ayush Sahay (ayushsahay1837)

<details>
<summary>Changes</summary>

This change provisions the _QNX_ host and process plugins, and is the fifth and final in a series of changes that look to facilitate remote debug of _AArch64_ targets on _QNX_.

_QNX Neutrino Real-Time Operating System_ is a commercial Unix-like real-time operating system primarily targeting the embedded systems market including automotive, medical devices, robotics, transportation, and industrial embedded systems.

The series of changes in question looks to provision support for –

- Launching a debuggee
- Attaching to a debuggee
- Having the debuggee come up stopped at the entry point
- Setting breakpoints
- Stopping at breakpoints
- Reading/writing contents of/to the debuggee's memory
- Reading/writing contents of/to the debuggee's registers
- Reading/writing contents of/to the debuggee's variables
- Resuming the debuggee's execution
- Single-stepping the debuggee's execution
- Interrupting the debuggee's execution
- Dumping information pertaining to the debuggee's stack trace

Kindly note that _ptrace_ isn't available on _QNX_. Instead, _devctl_ can be leveraged to observe and control the execution of a process under debug on _QNX_.

Any additional support (including the facilitation of execution of tests) will be the subject of future work.

---

Patch is 109.15 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/97630.diff


34 Files Affected:

- (modified) lldb/cmake/modules/LLDBConfig.cmake (+1-1) 
- (modified) lldb/include/lldb/Host/HostInfo.h (+3) 
- (modified) lldb/include/lldb/Host/posix/MainLoopPosix.h (+19-1) 
- (added) lldb/include/lldb/Host/qnx/HostInfoQNX.h (+24) 
- (added) lldb/include/lldb/Host/qnx/Support.h (+33) 
- (modified) lldb/source/Host/CMakeLists.txt (+7) 
- (modified) lldb/source/Host/common/ProcessLaunchInfo.cpp (+3) 
- (modified) lldb/source/Host/common/PseudoTerminal.cpp (+24) 
- (modified) lldb/source/Host/common/TCPSocket.cpp (+3) 
- (modified) lldb/source/Host/posix/MainLoopPosix.cpp (+51-7) 
- (modified) lldb/source/Host/posix/ProcessLauncherPosixFork.cpp (+191-1) 
- (added) lldb/source/Host/qnx/Host.cpp (+183) 
- (added) lldb/source/Host/qnx/HostInfoQNX.cpp (+22) 
- (added) lldb/source/Host/qnx/Support.cpp (+41) 
- (modified) lldb/source/Plugins/Process/CMakeLists.txt (+3) 
- (added) lldb/source/Plugins/Process/QNX/CMakeLists.txt (+16) 
- (added) lldb/source/Plugins/Process/QNX/NativeProcessQNX.cpp (+1066) 
- (added) lldb/source/Plugins/Process/QNX/NativeProcessQNX.h (+157) 
- (added) lldb/source/Plugins/Process/QNX/NativeRegisterContextQNX.cpp (+12) 
- (added) lldb/source/Plugins/Process/QNX/NativeRegisterContextQNX.h (+37) 
- (added) lldb/source/Plugins/Process/QNX/NativeRegisterContextQNX_arm64.cpp (+344) 
- (added) lldb/source/Plugins/Process/QNX/NativeRegisterContextQNX_arm64.h (+66) 
- (added) lldb/source/Plugins/Process/QNX/NativeThreadQNX.cpp (+141) 
- (added) lldb/source/Plugins/Process/QNX/NativeThreadQNX.h (+73) 
- (modified) lldb/source/Plugins/Process/Utility/CMakeLists.txt (+1) 
- (added) lldb/source/Plugins/Process/Utility/QNXSignals.cpp (+140) 
- (added) lldb/source/Plugins/Process/Utility/QNXSignals.h (+27) 
- (modified) lldb/source/Target/UnixSignals.cpp (+3) 
- (modified) lldb/source/Utility/CMakeLists.txt (+4) 
- (modified) lldb/tools/lldb-server/CMakeLists.txt (+4) 
- (modified) lldb/tools/lldb-server/lldb-gdbserver.cpp (+4) 
- (modified) llvm/include/llvm/Support/ExitCodes.h (+5-5) 
- (modified) llvm/lib/Support/Unix/Path.inc (+11-1) 
- (modified) llvm/lib/Support/Unix/Signals.inc (+6) 


``````````diff
diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake
index a60921990cf77..139f1c98bd5a1 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -299,7 +299,7 @@ endif()
 
 # Figure out if lldb could use lldb-server.  If so, then we'll
 # ensure we build lldb-server when an lldb target is being built.
-if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows")
+if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows|QNX")
   set(LLDB_CAN_USE_LLDB_SERVER ON)
 else()
   set(LLDB_CAN_USE_LLDB_SERVER OFF)
diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h
index b7010d69d88e7..82fa911ff1204 100644
--- a/lldb/include/lldb/Host/HostInfo.h
+++ b/lldb/include/lldb/Host/HostInfo.h
@@ -55,6 +55,9 @@
 #elif defined(__APPLE__)
 #include "lldb/Host/macosx/HostInfoMacOSX.h"
 #define HOST_INFO_TYPE HostInfoMacOSX
+#elif defined(__QNX__)
+#include "lldb/Host/qnx/HostInfoQNX.h"
+#define HOST_INFO_TYPE HostInfoQNX
 #else
 #include "lldb/Host/posix/HostInfoPosix.h"
 #define HOST_INFO_TYPE HostInfoPosix
diff --git a/lldb/include/lldb/Host/posix/MainLoopPosix.h b/lldb/include/lldb/Host/posix/MainLoopPosix.h
index 07497b7b8c259..6ff1c71f4d0c0 100644
--- a/lldb/include/lldb/Host/posix/MainLoopPosix.h
+++ b/lldb/include/lldb/Host/posix/MainLoopPosix.h
@@ -63,15 +63,30 @@ class MainLoopPosix : public MainLoopBase {
   class SignalHandle {
   public:
     ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo, m_callback_it); }
+#if defined(__QNX__)
+    std::weak_ptr<siginfo_t> GetSiginfo() const { return m_siginfo; }
+#endif
 
   private:
     SignalHandle(MainLoopPosix &mainloop, int signo,
+#if defined(__QNX__)
+                 std::list<Callback>::iterator callback_it,
+                 std::weak_ptr<siginfo_t> siginfo)
+        : m_mainloop(mainloop), m_signo(signo), m_callback_it(callback_it),
+          m_siginfo(siginfo) {
+    }
+#else
                  std::list<Callback>::iterator callback_it)
-        : m_mainloop(mainloop), m_signo(signo), m_callback_it(callback_it) {}
+        : m_mainloop(mainloop), m_signo(signo), m_callback_it(callback_it) {
+    }
+#endif
 
     MainLoopPosix &m_mainloop;
     int m_signo;
     std::list<Callback>::iterator m_callback_it;
+#if defined(__QNX__)
+    std::weak_ptr<siginfo_t> m_siginfo;
+#endif
 
     friend class MainLoopPosix;
     SignalHandle(const SignalHandle &) = delete;
@@ -81,6 +96,9 @@ class MainLoopPosix : public MainLoopBase {
   struct SignalInfo {
     std::list<Callback> callbacks;
     struct sigaction old_action;
+#if defined(__QNX__)
+    std::shared_ptr<siginfo_t> siginfo;
+#endif
     bool was_blocked : 1;
   };
   class RunImpl;
diff --git a/lldb/include/lldb/Host/qnx/HostInfoQNX.h b/lldb/include/lldb/Host/qnx/HostInfoQNX.h
new file mode 100644
index 0000000000000..94fd51279ed53
--- /dev/null
+++ b/lldb/include/lldb/Host/qnx/HostInfoQNX.h
@@ -0,0 +1,24 @@
+//===-- HostInfoQNX.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Host_qnx_HostInfoQNX_h_
+#define lldb_Host_qnx_HostInfoQNX_h_
+
+#include "lldb/Host/posix/HostInfoPosix.h"
+
+namespace lldb_private {
+
+class HostInfoQNX : public HostInfoPosix {
+public:
+  static llvm::VersionTuple GetOSVersion();
+  static std::optional<std::string> GetOSBuildString();
+  static FileSpec GetProgramFileSpec();
+};
+} // namespace lldb_private
+
+#endif
diff --git a/lldb/include/lldb/Host/qnx/Support.h b/lldb/include/lldb/Host/qnx/Support.h
new file mode 100644
index 0000000000000..975c45c4d2ba6
--- /dev/null
+++ b/lldb/include/lldb/Host/qnx/Support.h
@@ -0,0 +1,33 @@
+//===-- Support.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_HOST_QNX_SUPPORT_H
+#define LLDB_HOST_QNX_SUPPORT_H
+
+#include <memory>
+
+#include "lldb/Host/File.h"
+#include "lldb/lldb-forward.h"
+
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace lldb_private {
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+getProcFile(::pid_t pid, const llvm::Twine &file);
+
+llvm::Expected<lldb::FileUP>
+openProcFile(::pid_t pid, const llvm::Twine &file, File::OpenOptions options,
+             uint32_t permissions = lldb::eFilePermissionsFileDefault,
+             bool should_close_fd = true);
+
+} // namespace lldb_private
+
+#endif // #ifndef LLDB_HOST_QNX_SUPPORT_H
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index c2e091ee8555b..205705a9a28df 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -133,6 +133,13 @@ else()
       openbsd/Host.cpp
       openbsd/HostInfoOpenBSD.cpp
       )
+
+  elseif (CMAKE_SYSTEM_NAME MATCHES "QNX")
+    add_host_subdirectory(qnx
+      qnx/Host.cpp
+      qnx/HostInfoQNX.cpp
+      qnx/Support.cpp
+      )
   endif()
 endif()
 
diff --git a/lldb/source/Host/common/ProcessLaunchInfo.cpp b/lldb/source/Host/common/ProcessLaunchInfo.cpp
index a1866b2a99fd8..d43b55ba0b3e6 100644
--- a/lldb/source/Host/common/ProcessLaunchInfo.cpp
+++ b/lldb/source/Host/common/ProcessLaunchInfo.cpp
@@ -213,7 +213,10 @@ llvm::Error ProcessLaunchInfo::SetUpPtyRedirection() {
   // We really shouldn't be specifying platform specific flags that are
   // intended for a system call in generic code.  But this will have to
   // do for now.
+#if !defined(__QNX__)
+  // O_CLOEXEC is NOT a valid flag for posix_openpt on QNX.
   open_flags |= O_CLOEXEC;
+#endif
 #endif
   if (llvm::Error Err = m_pty->OpenFirstAvailablePrimary(open_flags))
     return Err;
diff --git a/lldb/source/Host/common/PseudoTerminal.cpp b/lldb/source/Host/common/PseudoTerminal.cpp
index d53327973eb27..bd183679655d2 100644
--- a/lldb/source/Host/common/PseudoTerminal.cpp
+++ b/lldb/source/Host/common/PseudoTerminal.cpp
@@ -72,6 +72,24 @@ llvm::Error PseudoTerminal::OpenFirstAvailablePrimary(int oflag) {
         std::error_code(errno, std::generic_category()));
   }
 
+#if defined(FD_CLOEXEC)
+  // Enable the close-on-exec flag for the primary file descriptor if it hasn't
+  // already been enabled.
+  // NB: In multithreaded programs, using fcntl to set the close-on-exec flag at
+  // the same time as another thread performs a fork plus execve risks a race
+  // condition that may unintentionally leak the file descriptor to the program
+  // executed in the child process but, apparently, we don't launch processes
+  // for debugging from within multithreaded contexts at the moment.
+  int flags = ::fcntl(m_primary_fd, F_GETFD);
+  if (flags == -1)
+    return llvm::errorCodeToError(
+        std::error_code(errno, std::generic_category()));
+  if (!(flags & FD_CLOEXEC))
+    if (::fcntl(m_primary_fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+      return llvm::errorCodeToError(
+          std::error_code(errno, std::generic_category()));
+#endif
+
   // Grant access to the secondary pseudo terminal
   if (::grantpt(m_primary_fd) < 0) {
     std::error_code EC(errno, std::generic_category());
@@ -124,7 +142,13 @@ std::string PseudoTerminal::GetSecondaryName() const {
     buf[0] = '\0';
     int r = ptsname_r(m_primary_fd, buf, sizeof(buf));
     UNUSED_IF_ASSERT_DISABLED(r);
+#if defined(__QNX__)
+    // ptsname_r returns a pointer to a null-terminated string containing the
+    // pathname of the corresponding slave device on success on QNX.
+    assert(r != 0);
+#else
     assert(r == 0);
+#endif
     return buf;
 #if defined(__APPLE__)
   } else {
diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp
index df4737216ed3a..5efcffbb29d0f 100644
--- a/lldb/source/Host/common/TCPSocket.cpp
+++ b/lldb/source/Host/common/TCPSocket.cpp
@@ -26,6 +26,9 @@
 #include <arpa/inet.h>
 #include <netinet/tcp.h>
 #include <sys/socket.h>
+#if defined(__QNX__)
+#include <sys/select.h>
+#endif
 #endif
 
 #if defined(_WIN32)
diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp
index 5fe4d015251c8..37edc016e99b8 100644
--- a/lldb/source/Host/posix/MainLoopPosix.cpp
+++ b/lldb/source/Host/posix/MainLoopPosix.cpp
@@ -20,12 +20,14 @@
 #include <vector>
 
 // Multiplexing is implemented using kqueue on systems that support it (BSD
-// variants including OSX). On linux we use ppoll, while android uses pselect
-// (ppoll is present but not implemented properly). On windows we use WSApoll
-// (which does not support signals).
+// variants including OSX). On linux we use ppoll, while android and QNX use
+// pselect (ppoll is present on Android but not implemented properly). On
+// windows we use WSApoll (which does not support signals).
 
 #if HAVE_SYS_EVENT_H
 #include <sys/event.h>
+#elif defined(__QNX__)
+#include <sys/select.h>
 #elif defined(__ANDROID__)
 #include <sys/syscall.h>
 #else
@@ -36,10 +38,17 @@ using namespace lldb;
 using namespace lldb_private;
 
 static sig_atomic_t g_signal_flags[NSIG];
+#if defined(__QNX__)
+static llvm::DenseMap<int, siginfo_t> g_signal_info;
+#endif
 
 static void SignalHandler(int signo, siginfo_t *info, void *) {
   assert(signo < NSIG);
   g_signal_flags[signo] = 1;
+#if defined(__QNX__)
+  siginfo_t siginfo(*info);
+  g_signal_info.insert({signo, siginfo});
+#endif
 }
 
 class MainLoopPosix::RunImpl {
@@ -59,7 +68,7 @@ class MainLoopPosix::RunImpl {
   int num_events = -1;
 
 #else
-#ifdef __ANDROID__
+#if defined(__ANDROID__) || defined(__QNX__)
   fd_set read_fd_set;
 #else
   std::vector<struct pollfd> read_fds;
@@ -113,7 +122,7 @@ void MainLoopPosix::RunImpl::ProcessEvents() {
 }
 #else
 MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
-#ifndef __ANDROID__
+#if !defined(__ANDROID__) && !defined(__QNX__)
   read_fds.reserve(loop.m_read_fds.size());
 #endif
 }
@@ -129,7 +138,7 @@ sigset_t MainLoopPosix::RunImpl::get_sigmask() {
   return sigmask;
 }
 
-#ifdef __ANDROID__
+#if defined(__ANDROID__) || defined(__QNX__)
 Status MainLoopPosix::RunImpl::Poll() {
   // ppoll(2) is not supported on older all android versions. Also, older
   // versions android (API <= 19) implemented pselect in a non-atomic way, as a
@@ -144,6 +153,7 @@ Status MainLoopPosix::RunImpl::Poll() {
     nfds = std::max(nfds, fd.first + 1);
   }
 
+#if defined(__ANDROID__)
   union {
     sigset_t set;
     uint64_t pad;
@@ -157,6 +167,11 @@ Status MainLoopPosix::RunImpl::Poll() {
   } extra_data = {&kernel_sigset, sizeof(kernel_sigset)};
   if (syscall(__NR_pselect6, nfds, &read_fd_set, nullptr, nullptr, nullptr,
               &extra_data) == -1) {
+#else
+  // QNX.
+  sigset_t sigmask = get_sigmask();
+  if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1) {
+#endif
     if (errno != EINTR)
       return Status(errno, eErrorTypePOSIX);
     else
@@ -188,7 +203,7 @@ Status MainLoopPosix::RunImpl::Poll() {
 #endif
 
 void MainLoopPosix::RunImpl::ProcessEvents() {
-#ifdef __ANDROID__
+#if defined(__ANDROID__) || defined(__QNX__)
   // Collect first all readable file descriptors into a separate vector and
   // then iterate over it to invoke callbacks. Iterating directly over
   // loop.m_read_fds is not possible because the callbacks can modify the
@@ -213,14 +228,28 @@ void MainLoopPosix::RunImpl::ProcessEvents() {
 
   std::vector<int> signals;
   for (const auto &entry : loop.m_signals)
+#if defined(__QNX__)
+    if (g_signal_flags[entry.first] != 0) {
+      signals.push_back(entry.first);
+      *(entry.second.siginfo.get()) = g_signal_info.find(entry.first)->second;
+    }
+#else
     if (g_signal_flags[entry.first] != 0)
       signals.push_back(entry.first);
+#endif
 
   for (const auto &signal : signals) {
     if (loop.m_terminate_request)
       return;
     g_signal_flags[signal] = 0;
+#if defined(__QNX__)
+    g_signal_info.erase(signal);
+#endif
     loop.ProcessSignal(signal);
+#if defined(__QNX__)
+    memset(loop.m_signals.find(signal)->second.siginfo.get(), 0,
+           sizeof(siginfo_t));
+#endif
   }
 }
 #endif
@@ -282,7 +311,12 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback,
   if (signal_it != m_signals.end()) {
     auto callback_it = signal_it->second.callbacks.insert(
         signal_it->second.callbacks.end(), callback);
+#if defined(__QNX__)
+    std::weak_ptr<siginfo_t> siginfo = signal_it->second.siginfo;
+    return SignalHandleUP(new SignalHandle(*this, signo, callback_it, siginfo));
+#else
     return SignalHandleUP(new SignalHandle(*this, signo, callback_it));
+#endif
   }
 
   SignalInfo info;
@@ -315,11 +349,21 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback,
   ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK,
                         &new_action.sa_mask, &old_set);
   assert(ret == 0 && "pthread_sigmask failed");
+#if defined(__QNX__)
+  info.siginfo = std::make_shared<siginfo_t>();
+#endif
   info.was_blocked = sigismember(&old_set, signo);
   auto insert_ret = m_signals.insert({signo, info});
+#if defined(__QNX__)
+  std::weak_ptr<siginfo_t> siginfo = info.siginfo;
+#endif
 
   return SignalHandleUP(new SignalHandle(
+#if defined(__QNX__)
+      *this, signo, insert_ret.first->second.callbacks.begin(), siginfo));
+#else
       *this, signo, insert_ret.first->second.callbacks.begin()));
+#endif
 }
 
 void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) {
diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
index 0a832ebad13a7..b539dedcb8bcf 100644
--- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
+++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
@@ -17,7 +17,11 @@
 #include "llvm/Support/Errno.h"
 
 #include <climits>
+#if defined(__QNX__)
+#include <spawn.h>
+#else
 #include <sys/ptrace.h>
+#endif
 #include <sys/wait.h>
 #include <unistd.h>
 
@@ -35,6 +39,10 @@
 #include <sys/personality.h>
 #endif
 
+#if !defined(EOK)
+#define EOK 0 /* No error */
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -193,7 +201,9 @@ struct ForkLaunchInfo {
     }
 
     // Start tracing this child that is about to exec.
+#if !defined(__QNX__)
     if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1)
+#endif
       ExitWithError(error_fd, "ptrace");
   }
 
@@ -222,6 +232,148 @@ struct ForkLaunchInfo {
 
 // End of code running in the child process.
 
+#if defined(__QNX__)
+static ::pid_t PosixSpawn(const ForkLaunchInfo &info,
+                          posix_spawn_file_actions_t &file_actions,
+                          posix_spawnattr_t &attr, Status &error) {
+  uint32_t flags = 0;
+  sigset_t set;
+  ::pid_t pid;
+  int ret;
+
+  if (info.separate_process_group) {
+    flags |= POSIX_SPAWN_SETPGROUP;
+    if (::posix_spawnattr_setpgroup(&attr, 0) != EOK) {
+      error.SetErrorStringWithFormatv("posix_spawnattr_setpgroup failed with "
+                                      "error message: {0}",
+                                      llvm::sys::StrError());
+      return LLDB_INVALID_PROCESS_ID;
+    }
+  }
+
+  for (const ForkFileAction &action : info.actions) {
+    switch (action.action) {
+    case FileAction::eFileActionClose:
+      if (::posix_spawn_file_actions_addclose(&file_actions, action.fd) !=
+          EOK) {
+        error.SetErrorStringWithFormatv("posix_spawn_file_actions_addclose "
+                                        "failed with error message: {0}",
+                                        llvm::sys::StrError());
+        return LLDB_INVALID_PROCESS_ID;
+      }
+      break;
+    case FileAction::eFileActionDuplicate:
+      if (::posix_spawn_file_actions_adddup2(&file_actions, action.fd,
+                                             action.arg) != EOK) {
+        error.SetErrorStringWithFormatv("posix_spawn_file_actions_adddup2 "
+                                        "failed with error message: {0}",
+                                        llvm::sys::StrError());
+        return LLDB_INVALID_PROCESS_ID;
+      }
+      break;
+    case FileAction::eFileActionOpen:
+      if (::posix_spawn_file_actions_addopen(&file_actions, action.fd,
+                                             action.path.c_str(), action.arg,
+                                             0666) != EOK) {
+        error.SetErrorStringWithFormatv("posix_spawn_file_actions_addopen "
+                                        "failed with error message: {0}",
+                                        llvm::sys::StrError());
+        return LLDB_INVALID_PROCESS_ID;
+      }
+      break;
+    case FileAction::eFileActionNone:
+      break;
+    }
+  }
+
+  // Change the working directory.
+  if (!info.wd.empty()) {
+    flags |= POSIX_SPAWN_SETCWD;
+
+    int dirfd =
+        llvm::sys::RetryAfterSignal(-1, ::open, info.wd.c_str(), O_DIRECTORY);
+
+    if (dirfd == -1) {
+      error.SetErrorStringWithFormatv("open failed with error message: {0}",
+                                      llvm::sys::StrError());
+      return LLDB_INVALID_PROCESS_ID;
+    }
+
+    if (::posix_spawnattr_setcwd_np(&attr, dirfd) != EOK) {
+      error.SetErrorStringWithFormatv("posix_spawnattr_setcwd_np failed with "
+                                      "error message: {0}",
+                                      llvm::sys::StrError());
+      return LLDB_INVALID_PROCESS_ID;
+    }
+  }
+
+  if (info.disable_aslr) {
+    if (::posix_spawnattr_setaslr(&attr, POSIX_SPAWN_ASLR_DISABLE) != EOK) {
+      error.SetErrorStringWithFormatv("posix_spawnattr_setaslr failed with "
+                                      "error message: {0}",
+                                      llvm::sys::StrError());
+      return LLDB_INVALID_PROCESS_ID;
+    }
+  }
+
+  // Clear the signal mask to prevent the child from being affected by any
+  // masking done by the parent.
+  flags |= POSIX_SPAWN_SETSIGMASK;
+
+  if (sigemptyset(&set) != 0) {
+    error.SetErrorStringWithFormatv("sigemptyset failed with error message: "
+                                    "{0}",
+                                    llvm::sys::StrError());
+    return LLDB_INVALID_PROCESS_ID;
+  }
+
+  if (::posix_spawnattr_setsigmask(&attr, &set) != EOK) {
+    error.SetErrorStringWithFormatv("posix_spawnattr_setsigmask failed with "
+                                    "error message: {0}",
+                                    llvm::sys::StrError());
+    return LLDB_INVALID_PROCESS_ID;
+  }
+
+  if (info.debug) {
+    // Hold the child process as if it had received a SIGSTOP as soon as it was
+    // spawned.
+    flags |= POSIX_SPAWN_HOLD;
+
+    // Do not inherit setgid powers.
+    flags |= POSIX_SPAWN_RESETIDS;
+
+    // posix_spawn returns EBADF when requested to close all open file
+    // descriptors other than STDIN, STDOUT, and STDERR.
+    // TODO: Close everything besides STDIN, STDOUT, and STDERR that doesn't
+    // have any file action to avoid leaking descriptors.
+  }
+
+  if (::posix_spawnattr_setxflags(&attr, flags) != EOK) {
+    error.SetErrorStringWithFormatv("posix_spawnattr_setxflags failed with "
+                                    "error message: {0}",
+                                    llvm::sys::StrError());
+    return LLDB_INVALID_PROCESS_ID;
+  }
+
+  ret = ::posix_spawn(&pid, info.argv[0], &file_actions, &attr,
+                      const_cast<char *const *>(info.argv), info.envp);
+
+  if (ret != EOK) {
+    // posix_spawn failed.
+    error.SetErrorStringWithFormatv("posix_spawn failed with error message: "
+                                    "{0}",
+                                    llvm::sys::StrError());
+    return LLDB_INVALID_PROCESS_ID;
+  }
+
+  // If an error occurs after posix_spawn returns successfully, then the child
+  // process exits with status 127.
+  // TODO: Wait for the child process if it exits on account of any error.
+
+  return pid; // No error. We're done.
+}
+#endif
+
 Fo...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/97630


More information about the llvm-commits mailing list