llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Hu Jialun (SuibianP)

<details>
<summary>Changes</summary>

`runInTerminal` is currently implemented using JSON messages over FIFOs, which 
feels too clunky for the simple job of passing a PID.

Instead, take advantage of `si_pid` available from `sa_sigaction` handler, and 
send a user signal instead. Both synchronisation and timeout are preserved with 
the protocol below,

1. Debugger waits for `SIGUSR1` under timeout with pselect
2. Launcher forks into child, sends `SIGUSR1` to debugger and suspends
3. Debugger receives `SIGUSR1`, captures the sender (launcher child) PID, 
attaches to and resumes it
4. Launcher child resumes and `exec`'s into target
5. Launcher parent `waitpid`'s and kills irresponsive child after timeout

With this, the entirety of `FifoFiles` and `RunInTerminal` can be dropped.

Refs: https://github.com/llvm/llvm-project/pull/121269#issuecomment-2901401482

---

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


11 Files Affected:

- (modified) 
lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py (-117) 
- (modified) lldb/tools/lldb-dap/CMakeLists.txt (-2) 
- (removed) lldb/tools/lldb-dap/FifoFiles.cpp (-101) 
- (removed) lldb/tools/lldb-dap/FifoFiles.h (-85) 
- (modified) lldb/tools/lldb-dap/Handler/RequestHandler.cpp (+72-27) 
- (modified) lldb/tools/lldb-dap/JSONUtils.cpp (+2-3) 
- (modified) lldb/tools/lldb-dap/JSONUtils.h (+1-4) 
- (modified) lldb/tools/lldb-dap/Options.td (+5-10) 
- (removed) lldb/tools/lldb-dap/RunInTerminal.cpp (-170) 
- (removed) lldb/tools/lldb-dap/RunInTerminal.h (-131) 
- (modified) lldb/tools/lldb-dap/tool/lldb-dap.cpp (+43-44) 


``````````diff
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 65c931210d400..3b6571621e541 100644
--- a/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py
+++ b/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py
@@ -131,120 +131,3 @@ def test_runInTerminalInvalidTarget(self):
             "'INVALIDPROGRAM' does not exist",
             response["body"]["error"]["format"],
         )
-
-    @skipIfWindows
-    @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
-    def test_missingArgInRunInTerminalLauncher(self):
-        if not self.isTestSupported():
-            return
-        proc = subprocess.run(
-            [self.lldbDAPExec, "--launch-target", "INVALIDPROGRAM"],
-            capture_output=True,
-            universal_newlines=True,
-        )
-        self.assertNotEqual(proc.returncode, 0)
-        self.assertIn(
-            '"--launch-target" requires "--comm-file" to be specified', 
proc.stderr
-        )
-
-    @skipIfWindows
-    @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
-    def test_FakeAttachedRunInTerminalLauncherWithInvalidProgram(self):
-        if not self.isTestSupported():
-            return
-        comm_file = os.path.join(self.getBuildDir(), "comm-file")
-        os.mkfifo(comm_file)
-
-        proc = subprocess.Popen(
-            [
-                self.lldbDAPExec,
-                "--comm-file",
-                comm_file,
-                "--launch-target",
-                "INVALIDPROGRAM",
-            ],
-            universal_newlines=True,
-            stderr=subprocess.PIPE,
-        )
-
-        self.readPidMessage(comm_file)
-        self.sendDidAttachMessage(comm_file)
-        self.assertIn("No such file or directory", 
self.readErrorMessage(comm_file))
-
-        _, stderr = proc.communicate()
-        self.assertIn("No such file or directory", stderr)
-
-    @skipIfWindows
-    @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
-    def test_FakeAttachedRunInTerminalLauncherWithValidProgram(self):
-        if not self.isTestSupported():
-            return
-        comm_file = os.path.join(self.getBuildDir(), "comm-file")
-        os.mkfifo(comm_file)
-
-        proc = subprocess.Popen(
-            [
-                self.lldbDAPExec,
-                "--comm-file",
-                comm_file,
-                "--launch-target",
-                "echo",
-                "foo",
-            ],
-            universal_newlines=True,
-            stdout=subprocess.PIPE,
-        )
-
-        self.readPidMessage(comm_file)
-        self.sendDidAttachMessage(comm_file)
-
-        stdout, _ = proc.communicate()
-        self.assertIn("foo", stdout)
-
-    @skipIfWindows
-    @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
-    def test_FakeAttachedRunInTerminalLauncherAndCheckEnvironment(self):
-        if not self.isTestSupported():
-            return
-        comm_file = os.path.join(self.getBuildDir(), "comm-file")
-        os.mkfifo(comm_file)
-
-        proc = subprocess.Popen(
-            [self.lldbDAPExec, "--comm-file", comm_file, "--launch-target", 
"env"],
-            universal_newlines=True,
-            stdout=subprocess.PIPE,
-            env={**os.environ, "FOO": "BAR"},
-        )
-
-        self.readPidMessage(comm_file)
-        self.sendDidAttachMessage(comm_file)
-
-        stdout, _ = proc.communicate()
-        self.assertIn("FOO=BAR", stdout)
-
-    @skipIfWindows
-    @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
-    def test_NonAttachedRunInTerminalLauncher(self):
-        if not self.isTestSupported():
-            return
-        comm_file = os.path.join(self.getBuildDir(), "comm-file")
-        os.mkfifo(comm_file)
-
-        proc = subprocess.Popen(
-            [
-                self.lldbDAPExec,
-                "--comm-file",
-                comm_file,
-                "--launch-target",
-                "echo",
-                "foo",
-            ],
-            universal_newlines=True,
-            stderr=subprocess.PIPE,
-            env={**os.environ, "LLDB_DAP_RIT_TIMEOUT_IN_MS": "1000"},
-        )
-
-        self.readPidMessage(comm_file)
-
-        _, stderr = proc.communicate()
-        self.assertIn("Timed out trying to get messages from the debug 
adapter", stderr)
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt 
b/lldb/tools/lldb-dap/CMakeLists.txt
index 40cba16c141f0..3e7e88afa9ced 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -14,7 +14,6 @@ add_lldb_library(lldbDAP
   DAPLog.cpp
   EventHelper.cpp
   ExceptionBreakpoint.cpp
-  FifoFiles.cpp
   FunctionBreakpoint.cpp
   InstructionBreakpoint.cpp
   JSONUtils.cpp
@@ -22,7 +21,6 @@ add_lldb_library(lldbDAP
   OutputRedirector.cpp
   ProgressEvent.cpp
   ProtocolUtils.cpp
-  RunInTerminal.cpp
   SourceBreakpoint.cpp
   Transport.cpp
   Variables.cpp
diff --git a/lldb/tools/lldb-dap/FifoFiles.cpp 
b/lldb/tools/lldb-dap/FifoFiles.cpp
deleted file mode 100644
index 1f1bba80bd3b1..0000000000000
--- a/lldb/tools/lldb-dap/FifoFiles.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-//===-- FifoFiles.cpp -------------------------------------------*- 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "FifoFiles.h"
-#include "JSONUtils.h"
-
-#if !defined(_WIN32)
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-
-#include <chrono>
-#include <fstream>
-#include <future>
-#include <optional>
-
-using namespace llvm;
-
-namespace lldb_dap {
-
-FifoFile::FifoFile(StringRef path) : m_path(path) {}
-
-FifoFile::~FifoFile() {
-#if !defined(_WIN32)
-  unlink(m_path.c_str());
-#endif
-}
-
-Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) {
-#if defined(_WIN32)
-  return createStringError(inconvertibleErrorCode(), "Unimplemented");
-#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);
-#endif
-}
-
-FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name)
-    : m_fifo_file(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
-  // would wait for the getline to end, rendering the timeout useless.
-  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;
-      }));
-  if (future->wait_for(timeout) == std::future_status::timeout || !line)
-    // 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
-    //  as a hack to avoid blocking main thread, and adding annotation to
-    //  supress static code inspection warnings
-
-    // coverity[leaked_storage]
-    return createStringError(inconvertibleErrorCode(),
-                             "Timed out trying to get messages from the " +
-                                 m_other_endpoint_name);
-  delete future;
-  return json::parse(*line);
-}
-
-Error FifoFileIO::SendJSON(const json::Value &json,
-                           std::chrono::milliseconds timeout) {
-  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;
-        done = true;
-      }));
-  if (future->wait_for(timeout) == std::future_status::timeout || !done) {
-    // 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 as a hack
-    // to avoid blocking main thread, and adding annotation to supress static
-    // code inspection warnings"
-
-    // coverity[leaked_storage]
-    return createStringError(inconvertibleErrorCode(),
-                             "Timed out trying to send messages to the " +
-                                 m_other_endpoint_name);
-  }
-  delete future;
-  return Error::success();
-}
-
-} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/FifoFiles.h b/lldb/tools/lldb-dap/FifoFiles.h
deleted file mode 100644
index 633ebeb2aedd4..0000000000000
--- a/lldb/tools/lldb-dap/FifoFiles.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//===-- FifoFiles.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_TOOLS_LLDB_DAP_FIFOFILES_H
-#define LLDB_TOOLS_LLDB_DAP_FIFOFILES_H
-
-#include "llvm/Support/Error.h"
-#include "llvm/Support/JSON.h"
-
-#include <chrono>
-
-namespace lldb_dap {
-
-/// Struct that controls the life of a fifo file in the filesystem.
-///
-/// The file is destroyed when the destructor is invoked.
-struct FifoFile {
-  FifoFile(llvm::StringRef path);
-
-  ~FifoFile();
-
-  std::string m_path;
-};
-
-/// Create a fifo file in the filesystem.
-///
-/// \param[in] path
-///     The path for the fifo file.
-///
-/// \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);
-
-class FifoFileIO {
-public:
-  /// \param[in] fifo_file
-  ///     The path to an input fifo file that exists in the file system.
-  ///
-  /// \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);
-
-  /// Read the next JSON object from the underlying input fifo file.
-  ///
-  /// The JSON object is expected to be a single line delimited with \a
-  /// std::endl.
-  ///
-  /// \return
-  ///     An \a llvm::Error object indicating the success or failure of this
-  ///     operation. Failures arise if the timeout is hit, the next line of 
text
-  ///     from the fifo file is not a valid JSON object, or is it impossible to
-  ///     read from the file.
-  llvm::Expected<llvm::json::Value> ReadJSON(std::chrono::milliseconds 
timeout);
-
-  /// Serialize a JSON object and write it to the underlying output fifo file.
-  ///
-  /// \param[in] json
-  ///     The JSON object to send. It will be printed as a single line 
delimited
-  ///     with \a std::endl.
-  ///
-  /// \param[in] timeout
-  ///     A timeout for how long we should until for the data to be consumed.
-  ///
-  /// \return
-  ///     An \a llvm::Error object indicating whether the data was consumed by
-  ///     a reader or not.
-  llvm::Error SendJSON(
-      const llvm::json::Value &json,
-      std::chrono::milliseconds timeout = std::chrono::milliseconds(20000));
-
-private:
-  std::string m_fifo_file;
-  std::string m_other_endpoint_name;
-};
-
-} // namespace lldb_dap
-
-#endif // LLDB_TOOLS_LLDB_DAP_FIFOFILES_H
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 93bc80a38e29d..cfcbabbb16a93 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -14,10 +14,12 @@
 #include "LLDBUtils.h"
 #include "Protocol/ProtocolBase.h"
 #include "Protocol/ProtocolRequests.h"
-#include "RunInTerminal.h"
 #include "lldb/API/SBDefines.h"
 #include "lldb/API/SBEnvironment.h"
 #include "llvm/Support/Error.h"
+#include <cerrno>
+#include <csignal>
+#include <limits>
 #include <mutex>
 
 #if !defined(_WIN32)
@@ -51,6 +53,70 @@ static uint32_t SetLaunchFlag(uint32_t flags, bool flag,
   return flags;
 }
 
+// Assume single thread
+class PidReceiver {
+private:
+  inline static volatile std::sig_atomic_t pid;
+  sigset_t oldmask;
+  struct sigaction oldaction;
+
+  static_assert(std::numeric_limits<volatile sig_atomic_t>::max() >=
+                    std::numeric_limits<pid_t>::max(),
+                "sig_atomic_t must be able to hold a pid_t value");
+
+  static void sig_handler(int, siginfo_t *info, void *) {
+    // Store the PID from the signal info
+    pid = info->si_pid;
+  }
+
+  PidReceiver(const PidReceiver &) = delete;
+  PidReceiver &operator=(const PidReceiver &) = delete;
+  PidReceiver(PidReceiver &&) = delete;
+
+public:
+  PidReceiver() {
+    pid = LLDB_INVALID_PROCESS_ID;
+    // sigprocmask and sigaction can only fail by programmer error
+    // Defer SIGUSR1, otherwise we might receive it out of pselect and hang
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGUSR1);
+    assert(!sigprocmask(SIG_BLOCK, &mask, &oldmask));
+
+    // Set up sigaction for SIGUSR1 with SA_SIGINFO
+    struct sigaction sa;
+    std::memset(&sa, 0, sizeof(sa));
+    sa.sa_sigaction = sig_handler;
+    sa.sa_flags = SA_SIGINFO;
+    sigemptyset(&sa.sa_mask);
+    assert(!sigaction(SIGUSR1, &sa, &oldaction));
+  }
+
+  ~PidReceiver() {
+    // Restore the old signal mask
+    assert(!sigprocmask(SIG_SETMASK, &oldmask, nullptr));
+    assert(!sigaction(SIGUSR1, &oldaction, nullptr));
+  }
+
+  llvm::Expected<lldb::pid_t> WaitForPid() {
+    // Wait for the signal to be received
+    while (pid == LLDB_INVALID_PROCESS_ID) {
+      struct timespec timeout;
+      timeout.tv_sec = 5;
+      timeout.tv_nsec = 0;
+      auto ret = pselect(0, nullptr, nullptr, nullptr, &timeout, &oldmask);
+      if (ret == -1 && errno != EINTR) {
+        return llvm::createStringError(
+            std::error_code(errno, std::generic_category()), "pselect failed");
+      } else if (ret == 0) {
+        return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                       "Timed out waiting for signal");
+      }
+    }
+    return pid;
+  }
+};
+
 static llvm::Error
 RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
   if (!dap.clientFeatures.contains(
@@ -65,26 +131,19 @@ RunInTerminal(DAP &dap, const 
protocol::LaunchRequestArguments &arguments) {
   dap.is_attach = true;
   lldb::SBAttachInfo attach_info;
 
-  llvm::Expected<std::shared_ptr<FifoFile>> comm_file_or_err =
-      CreateRunInTerminalCommFile();
-  if (!comm_file_or_err)
-    return comm_file_or_err.takeError();
-  FifoFile &comm_file = *comm_file_or_err.get();
-
-  RunInTerminalDebugAdapterCommChannel comm_channel(comm_file.m_path);
-
   lldb::pid_t debugger_pid = LLDB_INVALID_PROCESS_ID;
 #if !defined(_WIN32)
   debugger_pid = getpid();
 #endif
 
+  auto pid_receiver = PidReceiver();
   llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
       arguments.configuration.program, arguments.args, arguments.env,
-      arguments.cwd, comm_file.m_path, debugger_pid);
+      arguments.cwd, debugger_pid);
   dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
                                                     
std::move(reverse_request));
 
-  if (llvm::Expected<lldb::pid_t> pid = comm_channel.GetLauncherPid())
+  if (llvm::Expected<lldb::pid_t> pid = pid_receiver.WaitForPid())
     attach_info.SetProcessID(*pid);
   else
     return pid.takeError();
@@ -95,13 +154,7 @@ RunInTerminal(DAP &dap, const 
protocol::LaunchRequestArguments &arguments) {
 
   if (error.Fail())
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "Failed to attach to the target process. 
%s",
-                                   comm_channel.GetLauncherError().c_str());
-  // This will notify the runInTerminal launcher that we attached.
-  // We have to make this async, as the function won't return until the 
launcher
-  // resumes and reads the data.
-  std::future<lldb::SBError> did_attach_message_success =
-      comm_channel.NotifyDidAttach();
+                                   "Failed to attach to the target process.");
 
   // We just attached to the runInTerminal launcher, which was waiting to be
   // attached. We now resume it, so it can receive the didAttach notification
@@ -115,15 +168,7 @@ RunInTerminal(DAP &dap, const 
protocol::LaunchRequestArguments &arguments) {
   // we return the debugger to its sync state.
   scope_sync_mode.reset();
 
-  // If sending the notification failed, the launcher should be dead by now and
-  // the async didAttach notification should have an error message, so we
-  // return it. Otherwise, everything was a success.
-  did_attach_message_success.wait();
-  error = did_attach_message_success.get();
-  if (error.Success())
-    return llvm::Error::success();
-  return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                 error.GetCString());
+  return llvm::Error::success();
 }
 
 void BaseRequestHandler::Run(const Request &request) {
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp 
b/lldb/tools/lldb-dap/JSONUtils.cpp
index 573f3eba00f62..bf10742e18bb8 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -1238,15 +1238,14 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit 
&unit) {
 llvm::json::Object CreateRunInTerminalReverseRequest(
     llvm::StringRef program, const std::vector<std::string> &args,
     const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
-    llvm::StringRef comm_file, lldb::pid_t debugger_pid) {
+    lldb::pid_t debugger_pid) {
   llvm::json::Object run_in_terminal_args;
   // This indicates the IDE to open an embedded terminal, instead of opening
   // the terminal in a new window.
   run_in_terminal_args.try_emplace("kind", "integrated");
 
   // The program path must be the first entry in the "args" field
-  std::vector<std::string> req_args = {DAP::debug_adapter_path.str(),
-                                       "--comm-file", comm_file.str()};
+  std::vector<std::string> req_args = {DAP::debug_adapter_path.str()};
   if (debugger_pid != LLDB_INVALID_PROCESS_ID) {
     req_args.push_back("--debugger-pid");
     req_args.push_back(std::to_string(debugger_pid));
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index 08699a94bbd87..4ed66e6992be2 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -466,9 +466,6 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit 
&unit);
 /// \param[in] cwd
 ///     The working directory for the run in terminal request.
 ///
-/// \param[in] comm_file
-///     The fifo file used to communicate the with the target launcher.
-///
 /// \param[in] debugger_pid
 ///     The PID of the lldb-dap instance that will attach to the target. The
 ///     launcher uses it on Linux tell the kernel that it should allow the
@@ -480,7 +477,7 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit 
&unit);
 llvm::json::Object CreateRunInTerminalReverseRequest(
     llvm::StringRef program, const std::vector<std::string> &args,
     const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
-    llvm::StringRef comm_file, lldb::pid_t debugger_pid);
+    lldb::pid_t debugger_pid);
 
 /// Create a "Terminated" JSON object that contains statistics
 ///
diff --git a/lldb/tools/lldb-dap/Options.td b/lldb/tools/lldb-dap/Options.td
index aecf91797ac70..669d6a7c0df05 100644
--- a/lldb/tools/lldb-dap/Options.td
+++ b/lldb/tools/lldb-dap/Options.td
@@ -31,16 +31,11 @@ def connection
           "Connections are specified like 'tcp://[host]:port' or "
           "'unix:///path'.">;
 
-def launch_target: S<"laun...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/142374
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to