https://github.com/SuibianP updated https://github.com/llvm/llvm-project/pull/121269
>From babc347b5ad20d9d155c717323dc9796fce6b756 Mon Sep 17 00:00:00 2001 From: Jialun Hu <jialun...@razer.com> Date: Mon, 24 Feb 2025 22:10:17 +0800 Subject: [PATCH] [lldb-dap] Implement runInTerminal for Windows Currently, the named pipe is passed by name and a transient ofstream is constructed at each I/O request. This assumes, - Blocking semantics: FIFO I/O waits for the other side to connect. - Buffered semantics: Closing one side does not discard existing data. The former can be replaced by WaitNamedPipe/ConnectNamedPipe on Win32, but the second cannot be easily worked around. It is also impossible to have another "keep-alive" pipe server instance, as server-client pairs are fixed on connection on Win32 and the client may get connected to it instead of the real one. Refactor FifoFile[IO] to use an open file handles rather than file name. --- Win32 provides no way to replace the process image. Under the hood exec* actually creates a new process with a new PID. DebugActiveProcess also cannot get notified of process creations. Create the new process in a suspended state and resume it after attach. --- lldb/packages/Python/lldbsuite/test/dotest.py | 2 +- .../API/tools/lldb-dap/runInTerminal/Makefile | 2 +- .../runInTerminal/TestDAP_runInTerminal.py | 5 +- .../API/tools/lldb-dap/runInTerminal/main.c | 11 -- .../API/tools/lldb-dap/runInTerminal/main.cpp | 13 ++ lldb/tools/lldb-dap/FifoFiles.cpp | 131 +++++++++++++++--- lldb/tools/lldb-dap/FifoFiles.h | 35 +++-- .../tools/lldb-dap/Handler/RequestHandler.cpp | 8 +- lldb/tools/lldb-dap/RunInTerminal.cpp | 45 +++--- lldb/tools/lldb-dap/RunInTerminal.h | 11 +- lldb/tools/lldb-dap/lldb-dap.cpp | 63 +++++++-- 11 files changed, 243 insertions(+), 83 deletions(-) delete mode 100644 lldb/test/API/tools/lldb-dap/runInTerminal/main.c create mode 100644 lldb/test/API/tools/lldb-dap/runInTerminal/main.cpp diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py index 7cc8f2985043e..01b161733d62e 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/lldb/packages/Python/lldbsuite/test/dotest.py @@ -547,7 +547,7 @@ def setupSysPath(): lldbDir = os.path.dirname(lldbtest_config.lldbExec) - lldbDAPExec = os.path.join(lldbDir, "lldb-dap") + lldbDAPExec = os.path.join(lldbDir, "lldb-dap.exe" if os.name == "nt" else "lldb-dap") if is_exe(lldbDAPExec): os.environ["LLDBDAP_EXEC"] = lldbDAPExec diff --git a/lldb/test/API/tools/lldb-dap/runInTerminal/Makefile b/lldb/test/API/tools/lldb-dap/runInTerminal/Makefile index 10495940055b6..99998b20bcb05 100644 --- a/lldb/test/API/tools/lldb-dap/runInTerminal/Makefile +++ b/lldb/test/API/tools/lldb-dap/runInTerminal/Makefile @@ -1,3 +1,3 @@ -C_SOURCES := main.c +CXX_SOURCES := main.cpp include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py b/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py index 9aab7ca3293db..3a47202c5e0b6 100644 --- a/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py +++ b/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py @@ -43,7 +43,6 @@ def isTestSupported(self): except: return False - @skipIfWindows @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_runInTerminal(self): if not self.isTestSupported(): @@ -53,7 +52,7 @@ def test_runInTerminal(self): launch the inferior with the correct environment variables and arguments. """ program = self.getBuildArtifact("a.out") - source = "main.c" + source = "main.cpp" self.build_and_launch( program, runInTerminal=True, args=["foobar"], env=["FOO=bar"] ) @@ -113,7 +112,6 @@ def test_runInTerminalWithObjectEnv(self): self.assertIn("FOO", request_envs) self.assertEqual("BAR", request_envs["FOO"]) - @skipIfWindows @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_runInTerminalInvalidTarget(self): if not self.isTestSupported(): @@ -132,7 +130,6 @@ def test_runInTerminalInvalidTarget(self): response["message"], ) - @skipIfWindows @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_missingArgInRunInTerminalLauncher(self): if not self.isTestSupported(): diff --git a/lldb/test/API/tools/lldb-dap/runInTerminal/main.c b/lldb/test/API/tools/lldb-dap/runInTerminal/main.c deleted file mode 100644 index 676bd830e657b..0000000000000 --- a/lldb/test/API/tools/lldb-dap/runInTerminal/main.c +++ /dev/null @@ -1,11 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -int main(int argc, char *argv[]) { - const char *foo = getenv("FOO"); - for (int counter = 1;; counter++) { - sleep(1); // breakpoint - } - return 0; -} diff --git a/lldb/test/API/tools/lldb-dap/runInTerminal/main.cpp b/lldb/test/API/tools/lldb-dap/runInTerminal/main.cpp new file mode 100644 index 0000000000000..4e7812a3b6398 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/runInTerminal/main.cpp @@ -0,0 +1,13 @@ +#include <chrono> +#include <cstdlib> +#include <thread> + +using namespace std; + +int main(int argc, char *argv[]) { + const char *foo = getenv("FOO"); + for (int counter = 1;; counter++) { + this_thread::sleep_for(chrono::seconds(1)); // breakpoint + } + return 0; +} diff --git a/lldb/tools/lldb-dap/FifoFiles.cpp b/lldb/tools/lldb-dap/FifoFiles.cpp index 1f1bba80bd3b1..8069049d78519 100644 --- a/lldb/tools/lldb-dap/FifoFiles.cpp +++ b/lldb/tools/lldb-dap/FifoFiles.cpp @@ -8,8 +8,15 @@ #include "FifoFiles.h" #include "JSONUtils.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/WindowsError.h" -#if !defined(_WIN32) +#if defined(_WIN32) +#include <Windows.h> +#include <fcntl.h> +#include <io.h> +#else #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> @@ -24,27 +31,76 @@ using namespace llvm; namespace lldb_dap { -FifoFile::FifoFile(StringRef path) : m_path(path) {} +FifoFile::FifoFile(std::string path, FILE *f) : m_path(path), m_file(f) {} + +Expected<FifoFile> FifoFile::create(StringRef path) { + auto file = fopen(path.data(), "r+"); + if (file == nullptr) + return createStringError(inconvertibleErrorCode(), + "Failed to open fifo file " + path); + if (setvbuf(file, NULL, _IONBF, 0)) + return createStringError(inconvertibleErrorCode(), + "Failed to setvbuf on fifo file " + path); + return FifoFile(path, file); +} + +FifoFile::FifoFile(StringRef path, FILE *f) : m_path(path), m_file(f) {} +FifoFile::FifoFile(FifoFile &&other) + : m_path(other.m_path), m_file(other.m_file) { + other.m_path.clear(); + other.m_file = nullptr; +} FifoFile::~FifoFile() { + if (m_file) + fclose(m_file); #if !defined(_WIN32) + // Unreferenced named pipes are deleted automatically on Win32 unlink(m_path.c_str()); #endif } -Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) { -#if defined(_WIN32) - return createStringError(inconvertibleErrorCode(), "Unimplemented"); +// This probably belongs to llvm::sys::fs as another FSEntity type +Error createUniqueNamedPipe(const Twine &prefix, StringRef suffix, + int &result_fd, + SmallVectorImpl<char> &result_path) { + std::error_code EC; +#ifdef _WIN32 + const char *middle = suffix.empty() ? "-%%%%%%" : "-%%%%%%."; + EC = sys::fs::getPotentiallyUniqueFileName( + "\\\\.\\pipe\\LOCAL\\" + prefix + middle + suffix, result_path); +#else + EC = sys::fs::getPotentiallyUniqueTempFileName(prefix, suffix, result_path); +#endif + if (EC) + return errorCodeToError(EC); + result_path.push_back(0); + const char *path = result_path.data(); +#ifdef _WIN32 + HANDLE h = ::CreateNamedPipeA( + path, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 512, 512, 0, NULL); + if (h == INVALID_HANDLE_VALUE) + return createStringError(mapLastWindowsError(), "CreateNamedPipe"); + result_fd = _open_osfhandle((intptr_t)h, _O_TEXT | _O_RDWR); + if (result_fd == -1) + return createStringError(mapLastWindowsError(), "_open_osfhandle"); #else - if (int err = mkfifo(path.data(), 0600)) - return createStringError(std::error_code(err, std::generic_category()), - "Couldn't create fifo file: %s", path.data()); - return std::make_shared<FifoFile>(path); + if (mkfifo(path, 0600) == -1) + return createStringError(std::error_code(errno, std::generic_category()), + "mkfifo"); + EC = openFileForWrite(result_path, result_fd, sys::fs::CD_OpenExisting, + sys::fs::OF_None, 0600); + if (EC) + return errorCodeToError(EC); #endif + result_path.pop_back(); + return Error::success(); } -FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name) - : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {} +FifoFileIO::FifoFileIO(FifoFile &&fifo_file, StringRef other_endpoint_name) + : m_fifo_file(std::move(fifo_file)), + m_other_endpoint_name(other_endpoint_name) {} Expected<json::Value> FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) { // We use a pointer for this future, because otherwise its normal destructor @@ -52,13 +108,28 @@ Expected<json::Value> FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) { std::optional<std::string> line; std::future<void> *future = new std::future<void>(std::async(std::launch::async, [&]() { - std::ifstream reader(m_fifo_file, std::ifstream::in); - std::string buffer; - std::getline(reader, buffer); - if (!buffer.empty()) - line = buffer; + rewind(m_fifo_file.m_file); + /* + * The types of messages passing through the fifo are: + * {"kind": "pid", "pid": 9223372036854775807} + * {"kind": "didAttach"} + * {"kind": "error", "error": "error message"} + * + * 512 characters should be more than enough. + */ + constexpr size_t buffer_size = 512; + char buffer[buffer_size]; + char *ptr = fgets(buffer, buffer_size, m_fifo_file.m_file); + if (ptr == nullptr || *ptr == 0) + return; + size_t len = strlen(buffer); + if (len <= 1) + return; + buffer[len - 1] = '\0'; // remove newline + line = buffer; })); - if (future->wait_for(timeout) == std::future_status::timeout || !line) + + if (future->wait_for(timeout) == std::future_status::timeout) // Indeed this is a leak, but it's intentional. "future" obj destructor // will block on waiting for the worker thread to join. And the worker // thread might be stuck in blocking I/O. Intentionally leaking the obj @@ -69,6 +140,11 @@ Expected<json::Value> FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) { return createStringError(inconvertibleErrorCode(), "Timed out trying to get messages from the " + m_other_endpoint_name); + if (!line) { + return createStringError(inconvertibleErrorCode(), + "Failed to get messages from the " + + m_other_endpoint_name); + } delete future; return json::parse(*line); } @@ -78,8 +154,12 @@ Error FifoFileIO::SendJSON(const json::Value &json, bool done = false; std::future<void> *future = new std::future<void>(std::async(std::launch::async, [&]() { - std::ofstream writer(m_fifo_file, std::ofstream::out); - writer << JSONToString(json) << std::endl; + rewind(m_fifo_file.m_file); + auto payload = JSONToString(json); + if (fputs(payload.c_str(), m_fifo_file.m_file) == EOF || + fputc('\n', m_fifo_file.m_file) == EOF) { + return; + } done = true; })); if (future->wait_for(timeout) == std::future_status::timeout || !done) { @@ -98,4 +178,17 @@ Error FifoFileIO::SendJSON(const json::Value &json, return Error::success(); } +Error FifoFileIO::WaitForPeer() { +#ifdef _WIN32 + if (!::ConnectNamedPipe((HANDLE)_get_osfhandle(fileno(m_fifo_file.m_file)), + NULL) && + GetLastError() != ERROR_PIPE_CONNECTED) { + return createStringError(mapLastWindowsError(), + "Failed to connect to the " + + m_other_endpoint_name); + } +#endif + return Error::success(); +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/FifoFiles.h b/lldb/tools/lldb-dap/FifoFiles.h index 633ebeb2aedd4..99cb75e1343d2 100644 --- a/lldb/tools/lldb-dap/FifoFiles.h +++ b/lldb/tools/lldb-dap/FifoFiles.h @@ -11,8 +11,10 @@ #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" +#include "llvm/Support/raw_ostream.h" #include <chrono> +#include <fstream> namespace lldb_dap { @@ -20,22 +22,33 @@ namespace lldb_dap { /// /// The file is destroyed when the destructor is invoked. struct FifoFile { - FifoFile(llvm::StringRef path); + FifoFile(FifoFile &&other); + + FifoFile(const FifoFile &) = delete; + FifoFile &operator=(const FifoFile &) = delete; ~FifoFile(); + static llvm::Expected<FifoFile> create(llvm::StringRef path); + FifoFile(llvm::StringRef path, FILE *f); + std::string m_path; + FILE *m_file; + +private: + FifoFile(std::string path, FILE *f); }; -/// Create a fifo file in the filesystem. +/// Create and open a named pipe with a unique name. /// -/// \param[in] path -/// The path for the fifo file. +/// The arguments have identical meanings to those of +/// llvm::sys::fs::createTemporaryFile. /// -/// \return -/// A \a std::shared_ptr<FifoFile> if the file could be created, or an -/// \a llvm::Error in case of failures. -llvm::Expected<std::shared_ptr<FifoFile>> CreateFifoFile(llvm::StringRef path); +/// Note that the resulting filename is further prepended by \c \\.\pipe\\LOCAL\ +/// on Windows and the native temp directory on other platforms. +llvm::Error createUniqueNamedPipe(const llvm::Twine &prefix, + llvm::StringRef suffix, int &result_fd, + llvm::SmallVectorImpl<char> &result_path); class FifoFileIO { public: @@ -45,7 +58,7 @@ class FifoFileIO { /// \param[in] other_endpoint_name /// A human readable name for the other endpoint that will communicate /// using this file. This is used for error messages. - FifoFileIO(llvm::StringRef fifo_file, llvm::StringRef other_endpoint_name); + FifoFileIO(FifoFile &&fifo_file, llvm::StringRef other_endpoint_name); /// Read the next JSON object from the underlying input fifo file. /// @@ -75,8 +88,10 @@ class FifoFileIO { const llvm::json::Value &json, std::chrono::milliseconds timeout = std::chrono::milliseconds(20000)); + llvm::Error WaitForPeer(); + private: - std::string m_fifo_file; + FifoFile m_fifo_file; std::string m_other_endpoint_name; }; diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index f067dfc5544fe..7c9bbaa9fb2d6 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -111,18 +111,22 @@ static llvm::Error RunInTerminal(DAP &dap, if (!comm_file_or_err) return comm_file_or_err.takeError(); FifoFile &comm_file = *comm_file_or_err.get(); + std::string comm_filename = comm_file.m_path; - RunInTerminalDebugAdapterCommChannel comm_channel(comm_file.m_path); + RunInTerminalDebugAdapterCommChannel comm_channel(comm_file); lldb::pid_t debugger_pid = LLDB_INVALID_PROCESS_ID; #if !defined(_WIN32) debugger_pid = getpid(); #endif llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest( - launch_request, dap.debug_adapter_path, comm_file.m_path, debugger_pid); + launch_request, dap.debug_adapter_path, comm_filename, debugger_pid); dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal", std::move(reverse_request)); + auto err = comm_channel.WaitForLauncher(); + if (err) + return err; if (llvm::Expected<lldb::pid_t> pid = comm_channel.GetLauncherPid()) attach_info.SetProcessID(*pid); else diff --git a/lldb/tools/lldb-dap/RunInTerminal.cpp b/lldb/tools/lldb-dap/RunInTerminal.cpp index 9f309dd78221a..8cee9456e2ba2 100644 --- a/lldb/tools/lldb-dap/RunInTerminal.cpp +++ b/lldb/tools/lldb-dap/RunInTerminal.cpp @@ -9,12 +9,6 @@ #include "RunInTerminal.h" #include "JSONUtils.h" -#if !defined(_WIN32) -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#endif - #include <chrono> #include <future> @@ -96,8 +90,8 @@ static Error ToError(const RunInTerminalMessage &message) { } RunInTerminalLauncherCommChannel::RunInTerminalLauncherCommChannel( - StringRef comm_file) - : m_io(comm_file, "debug adapter") {} + FifoFile &comm_file) + : m_io(std::move(comm_file), "debug adapter") {} Error RunInTerminalLauncherCommChannel::WaitUntilDebugAdapterAttaches( std::chrono::milliseconds timeout) { @@ -111,8 +105,8 @@ Error RunInTerminalLauncherCommChannel::WaitUntilDebugAdapterAttaches( return message.takeError(); } -Error RunInTerminalLauncherCommChannel::NotifyPid() { - return m_io.SendJSON(RunInTerminalMessagePid(getpid()).ToJSON()); +Error RunInTerminalLauncherCommChannel::NotifyPid(lldb::pid_t pid) { + return m_io.SendJSON(RunInTerminalMessagePid(pid).ToJSON()); } void RunInTerminalLauncherCommChannel::NotifyError(StringRef error) { @@ -122,8 +116,12 @@ void RunInTerminalLauncherCommChannel::NotifyError(StringRef error) { } RunInTerminalDebugAdapterCommChannel::RunInTerminalDebugAdapterCommChannel( - StringRef comm_file) - : m_io(comm_file, "runInTerminal launcher") {} + FifoFile &comm_file) + : m_io(std::move(comm_file), "runInTerminal launcher") {} + +Error RunInTerminalDebugAdapterCommChannel::WaitForLauncher() { + return m_io.WaitForPeer(); +} // Can't use \a std::future<llvm::Error> because it doesn't compile on Windows std::future<lldb::SBError> @@ -158,13 +156,24 @@ std::string RunInTerminalDebugAdapterCommChannel::GetLauncherError() { } Expected<std::shared_ptr<FifoFile>> CreateRunInTerminalCommFile() { + int comm_fd; SmallString<256> comm_file; - if (std::error_code EC = sys::fs::getPotentiallyUniqueTempFileName( - "lldb-dap-run-in-terminal-comm", "", comm_file)) - return createStringError(EC, "Error making unique file name for " - "runInTerminal communication files"); - - return CreateFifoFile(comm_file.str()); + if (auto error = createUniqueNamedPipe("lldb-dap-run-in-terminal-comm", "", + comm_fd, comm_file)) + return error; + FILE *cf = fdopen(comm_fd, "r+"); + // There is no portable way to conjure an ofstream from HANDLE, so use FILE * + // llvm::raw_fd_stream does not support getline() and there is no + // llvm::buffer_istream + + if (cf == NULL) + return createStringError(std::error_code(errno, std::generic_category()), + "Error converting file descriptor to C FILE for " + "runInTerminal comm-file"); + if (setvbuf(cf, NULL, _IONBF, 0)) + return createStringError(std::error_code(errno, std::generic_category()), + "Error setting unbuffered mode on C FILE"); + return std::make_shared<FifoFile>(comm_file, cf); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/RunInTerminal.h b/lldb/tools/lldb-dap/RunInTerminal.h index 457850c8ea538..827d556dfc8e7 100644 --- a/lldb/tools/lldb-dap/RunInTerminal.h +++ b/lldb/tools/lldb-dap/RunInTerminal.h @@ -70,7 +70,7 @@ struct RunInTerminalMessageDidAttach : RunInTerminalMessage { class RunInTerminalLauncherCommChannel { public: - RunInTerminalLauncherCommChannel(llvm::StringRef comm_file); + RunInTerminalLauncherCommChannel(FifoFile &comm_file); /// Wait until the debug adapter attaches. /// @@ -84,10 +84,13 @@ class RunInTerminalLauncherCommChannel { /// Notify the debug adapter this process' pid. /// + /// \param[in] pid + /// The PID to be sent to the debug adapter + /// /// \return /// An \a llvm::Error object in case of errors or if this operation times /// out. - llvm::Error NotifyPid(); + llvm::Error NotifyPid(lldb::pid_t pid); /// Notify the debug adapter that there's been an error. void NotifyError(llvm::StringRef error); @@ -98,7 +101,7 @@ class RunInTerminalLauncherCommChannel { class RunInTerminalDebugAdapterCommChannel { public: - RunInTerminalDebugAdapterCommChannel(llvm::StringRef comm_file); + RunInTerminalDebugAdapterCommChannel(FifoFile &comm_file); /// Notify the runInTerminal launcher that it was attached. /// @@ -118,6 +121,8 @@ class RunInTerminalDebugAdapterCommChannel { /// default error message if a certain timeout if reached. std::string GetLauncherError(); + llvm::Error WaitForLauncher(); + private: FifoFileIO m_io; }; diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index ec87db6aab330..345c265a8712d 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -39,6 +39,7 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/WindowsError.h" #include "llvm/Support/raw_ostream.h" #include <condition_variable> #include <cstdio> @@ -207,11 +208,6 @@ static llvm::Error LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg, llvm::StringRef comm_file, lldb::pid_t debugger_pid, char *argv[]) { -#if defined(_WIN32) - return llvm::createStringError( - "runInTerminal is only supported on POSIX systems"); -#else - // On Linux with the Yama security module enabled, a process can only attach // to its descendants by default. In the runInTerminal case the target // process is launched by the client so we need to allow tracing explicitly. @@ -220,9 +216,46 @@ static llvm::Error LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg, (void)prctl(PR_SET_PTRACER, debugger_pid, 0, 0, 0); #endif - RunInTerminalLauncherCommChannel comm_channel(comm_file); - if (llvm::Error err = comm_channel.NotifyPid()) + const char *target = target_arg.getValue(); + +#ifdef _WIN32 + /* Win32 provides no way to replace the process image. exec* are misnomers. + Neither is the adapter notified of new processes due to DebugActiveProcess + semantics. Hence, we create the new process in a suspended state and resume + it after attach. + */ + std::string cmdline; + for (char **arg = argv; *arg != nullptr; ++arg) { + cmdline += *arg; + cmdline += ' '; + } + STARTUPINFOA si = {}; + si.cb = sizeof(si); + PROCESS_INFORMATION pi = {}; + bool res = CreateProcessA(target, cmdline.data(), NULL, NULL, FALSE, + CREATE_SUSPENDED, NULL, NULL, &si, &pi); + if (!res) { + llvm::errs() << "Failed to create process: " << GetLastError() << "\n"; + exit(EXIT_FAILURE); + } +#endif + + auto comm_fifo_file = FifoFile::create(comm_file); + if (!comm_fifo_file) { + llvm::errs() << "Failed to create fifo file: " << comm_fifo_file.takeError() + << "\n"; + exit(EXIT_FAILURE); + } + RunInTerminalLauncherCommChannel comm_channel(*comm_fifo_file); + if (llvm::Error err = comm_channel.NotifyPid( +#ifdef _WIN32 + pi.dwProcessId +#else + getpid() +#endif + )) { return err; + } // We will wait to be attached with a timeout. We don't wait indefinitely // using a signal to prevent being paused forever. @@ -235,15 +268,17 @@ static llvm::Error LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg, std::chrono::milliseconds(timeout_in_ms))) { return err; } - - const char *target = target_arg.getValue(); +#ifdef _WIN32 + if (ResumeThread(pi.hThread) != -1) + exit(EXIT_SUCCESS); + auto error = llvm::mapLastWindowsError(); +#else execvp(target, argv); - - std::string error = std::strerror(errno); - comm_channel.NotifyError(error); - return llvm::createStringError(llvm::inconvertibleErrorCode(), - std::move(error)); + std::error_code error(errno, std::generic_category()); #endif + + comm_channel.NotifyError(error.message()); + return llvm::createStringError(error, "Failed to exec target"); } /// used only by TestVSCode_redirection_to_console.py _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits