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