[Lldb-commits] [lldb] [lldb-dap] Refactoring lldb-dap port listening mode to allow multiple connections. (PR #116392)

via lldb-commits lldb-commits at lists.llvm.org
Fri Nov 15 22:28:08 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: John Harrison (ashgti)

<details>
<summary>Changes</summary>

This refactors the port listening mode to allocate a new DAP object for each connection, allowing multiple connections to run concurrently.

---

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


12 Files Affected:

- (modified) lldb/packages/Python/lldbsuite/test/lldbtest.py (+8) 
- (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py (+56-19) 
- (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py (+27-5) 
- (added) lldb/test/API/tools/lldb-dap/server/Makefile (+3) 
- (added) lldb/test/API/tools/lldb-dap/server/TestDAP_server.py (+66) 
- (added) lldb/test/API/tools/lldb-dap/server/main.c (+6) 
- (modified) lldb/tools/lldb-dap/DAP.cpp (+5-18) 
- (modified) lldb/tools/lldb-dap/DAP.h (+27-23) 
- (modified) lldb/tools/lldb-dap/Options.td (+9) 
- (modified) lldb/tools/lldb-dap/OutputRedirector.cpp (+4-3) 
- (modified) lldb/tools/lldb-dap/OutputRedirector.h (+9-3) 
- (modified) lldb/tools/lldb-dap/lldb-dap.cpp (+286-80) 


``````````diff
diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index 8884ef5933ada8..a899854bb5ae14 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -39,6 +39,7 @@
 import signal
 from subprocess import *
 import sys
+import socket
 import time
 import traceback
 
@@ -250,6 +251,13 @@ def which(program):
     return None
 
 
+def pickrandomport():
+    """Returns a random open port."""
+    with socket.socket() as sock:
+        sock.bind(("", 0))
+        return sock.getsockname()[1]
+
+
 class ValueCheck:
     def __init__(
         self,
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index c29992ce9c7848..e4a53fe0d45907 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -903,7 +903,7 @@ def request_setBreakpoints(self, file_path, line_array, data=None):
             "sourceModified": False,
         }
         if line_array is not None:
-            args_dict["lines"] = "%s" % line_array
+            args_dict["lines"] = line_array
             breakpoints = []
             for i, line in enumerate(line_array):
                 breakpoint_data = None
@@ -1154,34 +1154,38 @@ class DebugAdaptorServer(DebugCommunication):
     def __init__(
         self,
         executable=None,
+        launch=True,
         port=None,
+        unix_socket=None,
         init_commands=[],
         log_file=None,
         env=None,
     ):
         self.process = None
-        if executable is not None:
-            adaptor_env = os.environ.copy()
-            if env is not None:
-                adaptor_env.update(env)
-
-            if log_file:
-                adaptor_env["LLDBDAP_LOG"] = log_file
-            self.process = subprocess.Popen(
-                [executable],
-                stdin=subprocess.PIPE,
-                stdout=subprocess.PIPE,
-                stderr=subprocess.PIPE,
-                env=adaptor_env,
+        if launch:
+            self.process = DebugAdaptorServer.launch(
+                executable,
+                port=port,
+                unix_socket=unix_socket,
+                log_file=log_file,
+                env=env,
             )
-            DebugCommunication.__init__(
-                self, self.process.stdout, self.process.stdin, init_commands, log_file
-            )
-        elif port is not None:
+
+        if port:
             s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
             s.connect(("127.0.0.1", port))
             DebugCommunication.__init__(
-                self, s.makefile("r"), s.makefile("w"), init_commands
+                self, s.makefile("rb"), s.makefile("wb"), init_commands, log_file
+            )
+        elif unix_socket:
+            s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            s.connect(unix_socket)
+            DebugCommunication.__init__(
+                self, s.makefile("rb"), s.makefile("wb"), init_commands, log_file
+            )
+        else:
+            DebugCommunication.__init__(
+                self, self.process.stdout, self.process.stdin, init_commands, log_file
             )
 
     def get_pid(self):
@@ -1196,6 +1200,39 @@ def terminate(self):
             self.process.wait()
             self.process = None
 
+    @classmethod
+    def launch(
+        cls, executable: str, /, port=None, unix_socket=None, log_file=None, env=None
+    ) -> subprocess.Popen:
+        adaptor_env = os.environ.copy()
+        if env:
+            adaptor_env.update(env)
+
+        if log_file:
+            adaptor_env["LLDBDAP_LOG"] = log_file
+
+        args = [executable]
+        if port:
+            args.append("--port")
+            args.append(str(port))
+        elif unix_socket:
+            args.append("--unix-socket")
+            args.append(unix_socket)
+
+        proc = subprocess.Popen(
+            args,
+            stdin=subprocess.PIPE,
+            stdout=subprocess.PIPE,
+            stderr=sys.stdout,
+            env=adaptor_env,
+        )
+
+        if port or unix_socket:
+            # Wait for the server to startup.
+            time.sleep(0.1)
+
+        return proc
+
 
 def attach_options_specified(options):
     if options.pid is not None:
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
index a25466f07fa557..3fcc08e9ff55cb 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
@@ -13,7 +13,7 @@ class DAPTestCaseBase(TestBase):
     timeoutval = 10 * (10 if ('ASAN_OPTIONS' in os.environ) else 1)
     NO_DEBUG_INFO_TESTCASE = True
 
-    def create_debug_adaptor(self, lldbDAPEnv=None):
+    def create_debug_adaptor(self, env=None, launch=True, port=None, unix_socket=None):
         """Create the Visual Studio Code debug adaptor"""
         self.assertTrue(
             is_exe(self.lldbDAPExec), "lldb-dap must exist and be executable"
@@ -21,14 +21,28 @@ def create_debug_adaptor(self, lldbDAPEnv=None):
         log_file_path = self.getBuildArtifact("dap.txt")
         self.dap_server = dap_server.DebugAdaptorServer(
             executable=self.lldbDAPExec,
+            launch=launch,
+            port=port,
+            unix_socket=unix_socket,
             init_commands=self.setUpCommands(),
             log_file=log_file_path,
-            env=lldbDAPEnv,
+            env=env,
         )
 
-    def build_and_create_debug_adaptor(self, lldbDAPEnv=None):
+    def build_and_create_debug_adaptor(
+        self,
+        lldbDAPEnv=None,
+        lldbDAPLaunch=True,
+        lldbDAPPort=None,
+        lldbDAPUnixSocket=None,
+    ):
         self.build()
-        self.create_debug_adaptor(lldbDAPEnv)
+        self.create_debug_adaptor(
+            env=lldbDAPEnv,
+            launch=lldbDAPLaunch,
+            port=lldbDAPPort,
+            unix_socket=lldbDAPUnixSocket,
+        )
 
     def set_source_breakpoints(self, source_path, lines, data=None):
         """Sets source breakpoints and returns an array of strings containing
@@ -475,11 +489,19 @@ def build_and_launch(
         customThreadFormat=None,
         launchCommands=None,
         expectFailure=False,
+        lldbDAPPort=None,
+        lldbDAPUnixSocket=None,
+        lldbDAPLaunch=True,
     ):
         """Build the default Makefile target, create the DAP debug adaptor,
         and launch the process.
         """
-        self.build_and_create_debug_adaptor(lldbDAPEnv)
+        self.build_and_create_debug_adaptor(
+            lldbDAPEnv=lldbDAPEnv,
+            lldbDAPLaunch=lldbDAPLaunch,
+            lldbDAPPort=lldbDAPPort,
+            lldbDAPUnixSocket=lldbDAPUnixSocket,
+        )
         self.assertTrue(os.path.exists(program), "executable must exist")
 
         return self.launch(
diff --git a/lldb/test/API/tools/lldb-dap/server/Makefile b/lldb/test/API/tools/lldb-dap/server/Makefile
new file mode 100644
index 00000000000000..10495940055b63
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/server/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py b/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
new file mode 100644
index 00000000000000..46b992a77a4815
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
@@ -0,0 +1,66 @@
+"""
+Test lldb-dap server integration.
+"""
+
+import os
+import tempfile
+
+import dap_server
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbdap_testcase
+
+
+class TestDAP_server(lldbdap_testcase.DAPTestCaseBase):
+    def do_test_server(self, port=None, unix_socket=None):
+        log_file_path = self.getBuildArtifact("dap.txt")
+        server = dap_server.DebugAdaptorServer.launch(
+            self.lldbDAPExec, port=port, unix_socket=unix_socket, log_file=log_file_path
+        )
+
+        def cleanup():
+            server.terminate()
+            server.wait()
+
+        self.addTearDownHook(cleanup)
+
+        self.build()
+        program = self.getBuildArtifact("a.out")
+        source = "main.c"
+        breakpoint_line = line_number(source, "// breakpoint")
+
+        # Initial connection over the port.
+        self.create_debug_adaptor(launch=False, port=port, unix_socket=unix_socket)
+        self.launch(
+            program,
+            disconnectAutomatically=False,
+        )
+        self.set_source_breakpoints(source, [breakpoint_line])
+        self.continue_to_next_stop()
+        self.continue_to_exit()
+        output = self.get_stdout()
+        self.assertEquals(output, "hello world!\r\n")
+        self.dap_server.request_disconnect()
+
+        # Second connection over the port.
+        self.create_debug_adaptor(launch=False, port=port, unix_socket=unix_socket)
+        self.launch(program)
+        self.set_source_breakpoints(source, [breakpoint_line])
+        self.continue_to_next_stop()
+        self.continue_to_exit()
+        output = self.get_stdout()
+        self.assertEquals(output, "hello world!\r\n")
+
+    def test_server_port(self):
+        """
+        Test launching a binary with a lldb-dap in server mode on a specific port.
+        """
+        port = pickrandomport()
+        self.do_test_server(port=port)
+
+    def test_server_unix_socket(self):
+        """
+        Test launching a binary with a lldb-dap in server mode on a unix socket.
+        """
+        dir = tempfile.gettempdir()
+        self.do_test_server(unix_socket=dir + "/dap-connection-" + str(os.getpid()))
diff --git a/lldb/test/API/tools/lldb-dap/server/main.c b/lldb/test/API/tools/lldb-dap/server/main.c
new file mode 100644
index 00000000000000..9a6326f3b57d45
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/server/main.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(int argc, char const *argv[]) {
+  printf("hello world!\n"); // breakpoint 1
+  return 0;
+}
\ No newline at end of file
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 35250d9eef608a..8998036fbedf6b 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -32,10 +32,11 @@ using namespace lldb_dap;
 
 namespace lldb_dap {
 
-DAP::DAP(llvm::StringRef path, ReplMode repl_mode)
+DAP::DAP(llvm::StringRef path, std::shared_ptr<std::ofstream> log,
+         ReplMode repl_mode, std::vector<std::string> pre_init_commands)
     : debug_adaptor_path(path), broadcaster("lldb-dap"),
-      exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID),
-      stop_at_entry(false), is_attach(false),
+      log(log), exception_breakpoints(), pre_init_commands(pre_init_commands),
+      focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false),
       enable_auto_variable_summaries(false),
       enable_synthetic_child_debugging(false),
       display_extended_backtrace(false),
@@ -43,21 +44,7 @@ DAP::DAP(llvm::StringRef path, ReplMode repl_mode)
       configuration_done_sent(false), waiting_for_run_in_terminal(false),
       progress_event_reporter(
           [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
-      reverse_request_seq(0), repl_mode(repl_mode) {
-  const char *log_file_path = getenv("LLDBDAP_LOG");
-#if defined(_WIN32)
-  // Windows opens stdout and stdin in text mode which converts \n to 13,10
-  // while the value is just 10 on Darwin/Linux. Setting the file mode to binary
-  // fixes this.
-  int result = _setmode(fileno(stdout), _O_BINARY);
-  assert(result);
-  result = _setmode(fileno(stdin), _O_BINARY);
-  UNUSED_IF_ASSERT_DISABLED(result);
-  assert(result);
-#endif
-  if (log_file_path)
-    log.reset(new std::ofstream(log_file_path));
-}
+      reverse_request_seq(0), repl_mode(repl_mode) {}
 
 DAP::~DAP() = default;
 
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index ae496236f13369..ec70da67edac14 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -9,36 +9,33 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_DAP_H
 #define LLDB_TOOLS_LLDB_DAP_DAP_H
 
-#include <cstdio>
-#include <iosfwd>
-#include <map>
-#include <optional>
-#include <thread>
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/JSON.h"
-#include "llvm/Support/Threading.h"
-#include "llvm/Support/raw_ostream.h"
-
+#include "ExceptionBreakpoint.h"
+#include "FunctionBreakpoint.h"
+#include "IOStream.h"
+#include "InstructionBreakpoint.h"
+#include "ProgressEvent.h"
+#include "SourceBreakpoint.h"
 #include "lldb/API/SBAttachInfo.h"
 #include "lldb/API/SBCommandInterpreter.h"
 #include "lldb/API/SBCommandReturnObject.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBEvent.h"
+#include "lldb/API/SBFile.h"
 #include "lldb/API/SBFormat.h"
 #include "lldb/API/SBLaunchInfo.h"
 #include "lldb/API/SBTarget.h"
 #include "lldb/API/SBThread.h"
-
-#include "ExceptionBreakpoint.h"
-#include "FunctionBreakpoint.h"
-#include "IOStream.h"
-#include "InstructionBreakpoint.h"
-#include "ProgressEvent.h"
-#include "SourceBreakpoint.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/raw_ostream.h"
+#include <iosfwd>
+#include <map>
+#include <optional>
+#include <thread>
 
 #define VARREF_LOCALS (int64_t)1
 #define VARREF_GLOBALS (int64_t)2
@@ -140,13 +137,16 @@ struct DAP {
   llvm::StringRef debug_adaptor_path;
   InputStream input;
   OutputStream output;
+  lldb::SBFile in;
+  lldb::SBFile out;
+  lldb::SBFile err;
   lldb::SBDebugger debugger;
   lldb::SBTarget target;
   Variables variables;
   lldb::SBBroadcaster broadcaster;
   std::thread event_thread;
   std::thread progress_event_thread;
-  std::unique_ptr<std::ofstream> log;
+  std::shared_ptr<std::ofstream> log;
   llvm::StringMap<SourceBreakpointMap> source_breakpoints;
   FunctionBreakpointMap function_breakpoints;
   InstructionBreakpointMap instruction_breakpoints;
@@ -198,10 +198,14 @@ struct DAP {
   // will contain that expression.
   std::string last_nonempty_var_expression;
 
-  DAP(llvm::StringRef path, ReplMode repl_mode);
+  DAP(llvm::StringRef path, std::shared_ptr<std::ofstream> log,
+      ReplMode repl_mode, std::vector<std::string> pre_init_commands);
   ~DAP();
+
+  DAP() = delete;
   DAP(const DAP &rhs) = delete;
   void operator=(const DAP &rhs) = delete;
+
   ExceptionBreakpoint *GetExceptionBreakpoint(const std::string &filter);
   ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id);
 
diff --git a/lldb/tools/lldb-dap/Options.td b/lldb/tools/lldb-dap/Options.td
index d7b4a065abec01..dfca79b2884ac8 100644
--- a/lldb/tools/lldb-dap/Options.td
+++ b/lldb/tools/lldb-dap/Options.td
@@ -22,8 +22,17 @@ def port: S<"port">,
   HelpText<"Communicate with the lldb-dap tool over the defined port.">;
 def: Separate<["-"], "p">,
   Alias<port>,
+  MetaVarName<"<port>">,
   HelpText<"Alias for --port">;
 
+def unix_socket: S<"unix-socket">,
+  MetaVarName<"<path>">,
+  HelpText<"Communicate with the lldb-dap tool over the unix socket or named pipe.">;
+def: Separate<["-"], "u">,
+  Alias<unix_socket>,
+  MetaVarName<"<path>">,
+  HelpText<"Alias for --unix_socket">;
+
 def launch_target: S<"launch-target">,
   MetaVarName<"<target>">,
   HelpText<"Launch a target for the launchInTerminal request. Any argument "
diff --git a/lldb/tools/lldb-dap/OutputRedirector.cpp b/lldb/tools/lldb-dap/OutputRedirector.cpp
index 2c2f49569869b4..0b725e1901b9fd 100644
--- a/lldb/tools/lldb-dap/OutputRedirector.cpp
+++ b/lldb/tools/lldb-dap/OutputRedirector.cpp
@@ -21,7 +21,8 @@ using namespace llvm;
 
 namespace lldb_dap {
 
-Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) {
+Expected<int> RedirectFd(int fd,
+                         std::function<void(llvm::StringRef)> callback) {
   int new_fd[2];
 #if defined(_WIN32)
   if (_pipe(new_fd, 4096, O_TEXT) == -1) {
@@ -34,7 +35,7 @@ Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) {
                              strerror(error));
   }
 
-  if (dup2(new_fd[1], fd) == -1) {
+  if (fd != -1 && dup2(new_fd[1], fd) == -1) {
     int error = errno;
     return createStringError(inconvertibleErrorCode(),
                              "Couldn't override the fd %d. %s", fd,
@@ -57,7 +58,7 @@ Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) {
     }
   });
   t.detach();
-  return Error::success();
+  return new_fd[1];
 }
 
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/OutputRedirector.h b/lldb/tools/lldb-dap/OutputRedirector.h
index e26d1648b104f9..418b8bac102c7f 100644
--- a/lldb/tools/lldb-dap/OutputRedirector.h
+++ b/lldb/tools/lldb-dap/OutputRedirector.h
@@ -16,10 +16,16 @@ namespace lldb_dap {
 
 /// Redirects the output of a given file descriptor to a callback.
 ///
+/// \param[in] fd
+///     Either -1 or the fd duplicate into the new handle.
+///
+/// \param[in] callback
+///     A callback invoked each time the file is written.
+///
 /// \return
-///     \a Error::success if the redirection was set up correctly, or an error
-///     otherwise.
-llvm::Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback);
+///     A new file handle for the output.
+llvm::Expected<int> RedirectFd(int fd,
+                               std::function<void(llvm::StringRef)> callback);
 
 } // namespace lldb_dap
 
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 3bfc578806021e..51197587ffccec 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -14,6 +14,7 @@
 #include "RunInTerminal.h"
 #include "Watchpoint.h"
 #include "lldb/API/SBDeclaration.h"
+#include "lldb/API/SBFile.h"
 #include "lldb/API/SBInstruction.h"
 #include "lldb/API/SBListener.h"
 #include "lldb/API/SBMemoryRegionInfo.h"
@@ -66,6 +67,7 @@
 #else
 #include <netinet/in.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <unistd.h>
 #endif
 
@@ -116,6 +118,8 @@ enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch };
 /// Page size used for reporting addtional frames in the 'stackTrace' request.
 constexpr int StackPageSize = 20;
 
+void RegisterRequestCallbacks(DAP &dap);
+
 /// Prints a welcome message on the editor if the preprocessor variable
 /// LLDB_DAP_WELCOME_MESSAGE is defined.
 static void PrintWelcomeMessage(DAP &dap) {
@@ -137,42 +141,232 @@ lldb::SBValueList *GetTopLevelScope(DAP &dap, int64_t variablesReference) {
   }
 }
 
-SOCKET AcceptConnection(DAP &dap, int portno) {
-  // Accept a socket connection from any host on "portno".
-  SOCKET newsockfd = -1;
-  struct sockaddr_in serv_addr, cli_addr;
+/// Redirect stdout and stderr fo the IDE's console output.
+///
+/// Errors in this operation will be printed to the log file and the IDE's
+/// console output as well.
+///
+/// \return
+///     A fd pointing to the original stdout.
+void SetupRedirection(DAP &dap, int stdoutfd = -1, int stderrfd = -1) {
+  auto output_callback_stderr = [&dap](llvm::StringRef data) {
+    dap.SendOutput(OutputType::Stderr, data);
+  };
+  auto output_callback_stdout = [&dap](llvm::StringRef data) {
+    dap.SendOutput(OutputType::Stdout, data);
+  };
+
+  llvm::Expected<int> new_stdout_fd =
+      RedirectFd(stdoutfd, output_callback_stdout);
+  if (auto err = new_stdout_fd.takeError()) {
+    std::string error_message = llvm::toString(std::move(err));
+    if (dap.log)
+      *dap.log << error_message << std::endl;
+    output_callback_stderr(error_message);
+  }
+  dap.out = lldb::SBFile(new_stdout_fd.get(), "w", false);
+
+  llvm::Expected<int> new_stderr_fd =
+      RedirectFd(stderrfd, output_callback_stderr);
+  if (auto err = new_stderr_fd.takeError()) {
+    std::string error_message = llvm::toString(std::move(err));
+    if (dap.log)
+      *dap.log << error_message << std::endl;
+    output_callback_stderr(error_message);
+  }
+  dap.err = lldb::SBFile(new_stderr_fd.get(), "w", false);
+}
+
+void HandleClien...
[truncated]

``````````

</details>


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


More information about the lldb-commits mailing list