[Lldb-commits] [lldb] [lldb][windows] add a Windows FifoFile implementation (PR #185894)

Charles Zablit via lldb-commits lldb-commits at lists.llvm.org
Thu Mar 12 04:51:00 PDT 2026


https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/185894

>From 7c6a1d2cea83928bfdb54796feecb09d3602b928 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Wed, 11 Mar 2026 18:27:28 +0000
Subject: [PATCH 1/4] Revert "[lldb] Consolidating platform support checks in
 tests. (#184656)"

This reverts commit 08cef699c4bb2e5236393d73e8ce05ad08a4ccca.
---
 lldb/unittests/DAP/DAPTest.cpp                |  3 +-
 lldb/unittests/DAP/Handler/DisconnectTest.cpp | 11 +--
 lldb/unittests/DAP/TestBase.cpp               | 48 ++++++++++---
 lldb/unittests/DAP/TestBase.h                 | 59 +++++++++++++++-
 lldb/unittests/DAP/TestUtilities.h            | 69 -------------------
 lldb/unittests/DAP/VariablesTest.cpp          | 59 +++++++++++-----
 .../TestingSupport/TestUtilities.cpp          | 53 +-------------
 lldb/unittests/TestingSupport/TestUtilities.h | 15 ----
 8 files changed, 146 insertions(+), 171 deletions(-)
 delete mode 100644 lldb/unittests/DAP/TestUtilities.h

diff --git a/lldb/unittests/DAP/DAPTest.cpp b/lldb/unittests/DAP/DAPTest.cpp
index fcc8ff25446ff..4fd6cd546e6fa 100644
--- a/lldb/unittests/DAP/DAPTest.cpp
+++ b/lldb/unittests/DAP/DAPTest.cpp
@@ -1,4 +1,4 @@
-//===----------------------------------------------------------------------===//
+//===-- DAPTest.cpp -------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -9,7 +9,6 @@
 #include "DAP.h"
 #include "Protocol/ProtocolBase.h"
 #include "TestBase.h"
-#include "TestUtilities.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include <optional>
diff --git a/lldb/unittests/DAP/Handler/DisconnectTest.cpp b/lldb/unittests/DAP/Handler/DisconnectTest.cpp
index 10e1b1ef7b5ab..212c5698feea8 100644
--- a/lldb/unittests/DAP/Handler/DisconnectTest.cpp
+++ b/lldb/unittests/DAP/Handler/DisconnectTest.cpp
@@ -8,9 +8,8 @@
 
 #include "DAP.h"
 #include "Handler/RequestHandler.h"
+#include "Protocol/ProtocolBase.h"
 #include "TestBase.h"
-#include "TestUtilities.h"
-#include "TestingSupport/TestUtilities.h"
 #include "lldb/API/SBDefines.h"
 #include "lldb/lldb-enumerations.h"
 #include "llvm/Testing/Support/Error.h"
@@ -38,10 +37,12 @@ TEST_F(DisconnectRequestHandlerTest, DisconnectTriggersTerminated) {
 // Is flaky on Linux, see https://github.com/llvm/llvm-project/issues/154763.
 #ifndef __linux__
 TEST_F(DisconnectRequestHandlerTest, DisconnectTriggersTerminateCommands) {
-  SKIP_IF_LLVM_TARGET_MISSING("X86");
+  CreateDebugger();
 
-  ConfigureDebugger();
-  LoadCore(k_linux_x86_64_binary, k_linux_x86_64_core);
+  if (!GetDebuggerSupportsTarget("X86"))
+    GTEST_SKIP() << "Unsupported platform";
+
+  LoadCore();
 
   DisconnectRequestHandler handler(*dap);
 
diff --git a/lldb/unittests/DAP/TestBase.cpp b/lldb/unittests/DAP/TestBase.cpp
index cb9596e6f1637..6073aa82a8eb7 100644
--- a/lldb/unittests/DAP/TestBase.cpp
+++ b/lldb/unittests/DAP/TestBase.cpp
@@ -1,4 +1,4 @@
-//===----------------------------------------------------------------------===//
+//===-- TestBase.cpp ------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -13,6 +13,7 @@
 #include "Handler/ResponseHandler.h"
 #include "TestingSupport/TestUtilities.h"
 #include "lldb/API/SBDefines.h"
+#include "lldb/API/SBStructuredData.h"
 #include "lldb/Host/MainLoop.h"
 #include "lldb/Host/Pipe.h"
 #include "llvm/ADT/StringRef.h"
@@ -69,11 +70,26 @@ void DAPTestBase::SetUpTestSuite() {
   lldb::SBError error = SBDebugger::InitializeWithErrorHandling();
   EXPECT_TRUE(error.Success());
 }
-
 void DAPTestBase::TearDownTestSuite() { SBDebugger::Terminate(); }
 
-void DAPTestBase::ConfigureDebugger() {
-  dap->debugger = lldb::SBDebugger::Create(/*source_init_files=*/false);
+bool DAPTestBase::GetDebuggerSupportsTarget(StringRef platform) {
+  EXPECT_TRUE(dap->debugger);
+
+  lldb::SBStructuredData data = dap->debugger.GetBuildConfiguration()
+                                    .GetValueForKey("targets")
+                                    .GetValueForKey("value");
+  for (size_t i = 0; i < data.GetSize(); i++) {
+    char buf[100] = {0};
+    size_t size = data.GetItemAtIndex(i).GetStringValue(buf, sizeof(buf));
+    if (StringRef(buf, size) == platform)
+      return true;
+  }
+
+  return false;
+}
+
+void DAPTestBase::CreateDebugger() {
+  dap->debugger = lldb::SBDebugger::Create();
   ASSERT_TRUE(dap->debugger);
   dap->target = dap->debugger.GetDummyTarget();
 
@@ -95,8 +111,24 @@ void DAPTestBase::ConfigureDebugger() {
   dap->debugger.SetErrorFile(lldb::SBFile(*err_fd, "w", false));
 }
 
-void DAPTestBase::LoadCore(llvm::StringRef binary_path,
-                           llvm::StringRef core_path) {
-  std::tie(dap->target, process) =
-      lldb_private::LoadCore(dap->debugger, binary_path, core_path);
+void DAPTestBase::LoadCore() {
+  ASSERT_TRUE(dap->debugger);
+  llvm::Expected<lldb_private::TestFile> binary_yaml =
+      lldb_private::TestFile::fromYamlFile(k_linux_binary);
+  ASSERT_THAT_EXPECTED(binary_yaml, Succeeded());
+  llvm::Expected<llvm::sys::fs::TempFile> binary_file =
+      binary_yaml->writeToTemporaryFile();
+  ASSERT_THAT_EXPECTED(binary_file, Succeeded());
+  binary = std::move(*binary_file);
+  dap->target = dap->debugger.CreateTarget(binary->TmpName.data());
+  ASSERT_TRUE(dap->target);
+  llvm::Expected<lldb_private::TestFile> core_yaml =
+      lldb_private::TestFile::fromYamlFile(k_linux_core);
+  ASSERT_THAT_EXPECTED(core_yaml, Succeeded());
+  llvm::Expected<llvm::sys::fs::TempFile> core_file =
+      core_yaml->writeToTemporaryFile();
+  ASSERT_THAT_EXPECTED(core_file, Succeeded());
+  this->core = std::move(*core_file);
+  SBProcess process = dap->target.LoadCore(this->core->TmpName.data());
+  ASSERT_TRUE(process);
 }
diff --git a/lldb/unittests/DAP/TestBase.h b/lldb/unittests/DAP/TestBase.h
index ec5595bd61971..7953e0fabfbe5 100644
--- a/lldb/unittests/DAP/TestBase.h
+++ b/lldb/unittests/DAP/TestBase.h
@@ -10,18 +10,44 @@
 #include "DAPLog.h"
 #include "Handler/RequestHandler.h"
 #include "Handler/ResponseHandler.h"
+#include "Protocol/ProtocolBase.h"
 #include "TestingSupport/Host/JSONTransportTestUtilities.h"
 #include "TestingSupport/SubsystemRAII.h"
 #include "Transport.h"
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/HostInfo.h"
 #include "lldb/Host/MainLoop.h"
+#include "lldb/Host/MainLoopBase.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/JSON.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include <memory>
 #include <optional>
 
+/// Helpers for gtest printing.
+namespace lldb_dap::protocol {
+
+inline void PrintTo(const Request &req, std::ostream *os) {
+  *os << llvm::formatv("{0}", toJSON(req)).str();
+}
+
+inline void PrintTo(const Response &resp, std::ostream *os) {
+  *os << llvm::formatv("{0}", toJSON(resp)).str();
+}
+
+inline void PrintTo(const Event &evt, std::ostream *os) {
+  *os << llvm::formatv("{0}", toJSON(evt)).str();
+}
+
+inline void PrintTo(const Message &message, std::ostream *os) {
+  return std::visit([os](auto &&message) { return PrintTo(message, os); },
+                    message);
+}
+
+} // namespace lldb_dap::protocol
+
 namespace lldb_dap_tests {
 
 using TestDAPTransport = TestTransport<lldb_dap::ProtocolDescriptor>;
@@ -48,20 +74,47 @@ class TransportBase : public testing::Test {
   void Run();
 };
 
+/// A matcher for a DAP event.
+template <typename EventMatcher, typename BodyMatcher>
+inline testing::Matcher<const lldb_dap::protocol::Event &>
+IsEvent(const EventMatcher &event_matcher, const BodyMatcher &body_matcher) {
+  return testing::AllOf(
+      testing::Field(&lldb_dap::protocol::Event::event, event_matcher),
+      testing::Field(&lldb_dap::protocol::Event::body, body_matcher));
+}
+
+template <typename EventMatcher>
+inline testing::Matcher<const lldb_dap::protocol::Event &>
+IsEvent(const EventMatcher &event_matcher) {
+  return testing::AllOf(
+      testing::Field(&lldb_dap::protocol::Event::event, event_matcher),
+      testing::Field(&lldb_dap::protocol::Event::body, std::nullopt));
+}
+
+/// Matches an "output" event.
+inline auto Output(llvm::StringRef o, llvm::StringRef cat = "console") {
+  return IsEvent("output",
+                 testing::Optional(llvm::json::Value(
+                     llvm::json::Object{{"category", cat}, {"output", o}})));
+}
+
 /// A base class for tests that interact with a `lldb_dap::DAP` instance.
 class DAPTestBase : public TransportBase {
 protected:
   std::optional<llvm::sys::fs::TempFile> core;
   std::optional<llvm::sys::fs::TempFile> binary;
-  lldb::SBProcess process;
+
+  static constexpr llvm::StringLiteral k_linux_binary = "linux-x86_64.out.yaml";
+  static constexpr llvm::StringLiteral k_linux_core = "linux-x86_64.core.yaml";
 
   static void SetUpTestSuite();
   static void TearDownTestSuite();
   void SetUp() override;
   void TearDown() override;
 
-  void ConfigureDebugger();
-  void LoadCore(llvm::StringRef binary_path, llvm::StringRef core_path);
+  bool GetDebuggerSupportsTarget(llvm::StringRef platform);
+  void CreateDebugger();
+  void LoadCore();
 };
 
 } // namespace lldb_dap_tests
diff --git a/lldb/unittests/DAP/TestUtilities.h b/lldb/unittests/DAP/TestUtilities.h
deleted file mode 100644
index 5b652534cd091..0000000000000
--- a/lldb/unittests/DAP/TestUtilities.h
+++ /dev/null
@@ -1,69 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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 "Protocol/ProtocolBase.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/JSON.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include <optional>
-
-/// Helpers for gtest printing.
-namespace lldb_dap::protocol {
-
-inline void PrintTo(const Request &req, std::ostream *os) {
-  *os << llvm::formatv("{0}", toJSON(req)).str();
-}
-
-inline void PrintTo(const Response &resp, std::ostream *os) {
-  *os << llvm::formatv("{0}", toJSON(resp)).str();
-}
-
-inline void PrintTo(const Event &evt, std::ostream *os) {
-  *os << llvm::formatv("{0}", toJSON(evt)).str();
-}
-
-inline void PrintTo(const Message &message, std::ostream *os) {
-  return std::visit([os](auto &&message) { return PrintTo(message, os); },
-                    message);
-}
-
-} // namespace lldb_dap::protocol
-
-namespace lldb_dap_tests {
-
-static constexpr llvm::StringLiteral k_linux_x86_64_binary =
-    "linux-x86_64.out.yaml";
-static constexpr llvm::StringLiteral k_linux_x86_64_core =
-    "linux-x86_64.core.yaml";
-
-/// A matcher for a DAP event.
-template <typename EventMatcher, typename BodyMatcher>
-inline testing::Matcher<const lldb_dap::protocol::Event &>
-IsEvent(const EventMatcher &event_matcher, const BodyMatcher &body_matcher) {
-  return testing::AllOf(
-      testing::Field(&lldb_dap::protocol::Event::event, event_matcher),
-      testing::Field(&lldb_dap::protocol::Event::body, body_matcher));
-}
-
-template <typename EventMatcher>
-inline testing::Matcher<const lldb_dap::protocol::Event &>
-IsEvent(const EventMatcher &event_matcher) {
-  return testing::AllOf(
-      testing::Field(&lldb_dap::protocol::Event::event, event_matcher),
-      testing::Field(&lldb_dap::protocol::Event::body, std::nullopt));
-}
-
-/// Matches an "output" event.
-inline auto Output(llvm::StringRef o, llvm::StringRef cat = "console") {
-  return IsEvent("output",
-                 testing::Optional(llvm::json::Value(
-                     llvm::json::Object{{"category", cat}, {"output", o}})));
-}
-
-} // namespace lldb_dap_tests
diff --git a/lldb/unittests/DAP/VariablesTest.cpp b/lldb/unittests/DAP/VariablesTest.cpp
index 03f5cbf9cccb5..fe85e92a7fee2 100644
--- a/lldb/unittests/DAP/VariablesTest.cpp
+++ b/lldb/unittests/DAP/VariablesTest.cpp
@@ -10,7 +10,6 @@
 #include "DAPLog.h"
 #include "Protocol/DAPTypes.h"
 #include "Protocol/ProtocolTypes.h"
-#include "TestUtilities.h"
 #include "TestingSupport/TestUtilities.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBFrame.h"
@@ -18,17 +17,13 @@
 #include "lldb/API/SBValue.h"
 #include "llvm/Testing/Support/Error.h"
 #include "gtest/gtest.h"
+#include <optional>
 
 using namespace llvm;
 using namespace lldb;
 using namespace lldb_dap;
-using namespace lldb_dap_tests;
 using namespace lldb_dap::protocol;
 
-static lldb::SBDebugger CreateDebugger() {
-  return lldb::SBDebugger::Create(/*source_init_files*/ false);
-}
-
 class VariablesTest : public ::testing::Test {
 
 public:
@@ -41,6 +36,10 @@ class VariablesTest : public ::testing::Test {
   static void TearDownTestSuite() { SBDebugger::Terminate(); }
 
   void TearDown() override {
+    if (core)
+      ASSERT_THAT_ERROR(core->discard(), Succeeded());
+    if (binary)
+      ASSERT_THAT_ERROR(binary->discard(), Succeeded());
     if (debugger)
       debugger.Clear();
   }
@@ -54,6 +53,39 @@ class VariablesTest : public ::testing::Test {
   lldb::SBTarget target;
   lldb::SBProcess process;
 
+  static constexpr llvm::StringLiteral k_binary = "linux-x86_64.out.yaml";
+  static constexpr llvm::StringLiteral k_core = "linux-x86_64.core.yaml";
+
+  std::optional<llvm::sys::fs::TempFile> core;
+  std::optional<llvm::sys::fs::TempFile> binary;
+
+  void CreateDebugger() { debugger = lldb::SBDebugger::Create(); }
+
+  void LoadCore() {
+    ASSERT_TRUE(debugger);
+
+    llvm::Expected<lldb_private::TestFile> binary_yaml =
+        lldb_private::TestFile::fromYamlFile(k_binary);
+    ASSERT_THAT_EXPECTED(binary_yaml, Succeeded());
+    llvm::Expected<llvm::sys::fs::TempFile> binary_file =
+        binary_yaml->writeToTemporaryFile();
+    ASSERT_THAT_EXPECTED(binary_file, Succeeded());
+    binary = std::move(*binary_file);
+    target = debugger.CreateTarget(binary->TmpName.data());
+    ASSERT_TRUE(target);
+    debugger.SetSelectedTarget(target);
+
+    llvm::Expected<lldb_private::TestFile> core_yaml =
+        lldb_private::TestFile::fromYamlFile(k_core);
+    ASSERT_THAT_EXPECTED(core_yaml, Succeeded());
+    llvm::Expected<llvm::sys::fs::TempFile> core_file =
+        core_yaml->writeToTemporaryFile();
+    ASSERT_THAT_EXPECTED(core_file, Succeeded());
+    this->core = std::move(*core_file);
+    process = target.LoadCore(this->core->TmpName.data());
+    ASSERT_TRUE(process);
+  }
+
   static const protocol::Scope *
   FindScope(const std::vector<protocol::Scope> &scopes,
             const protocol::String &name) {
@@ -66,11 +98,8 @@ class VariablesTest : public ::testing::Test {
 };
 
 TEST_F(VariablesTest, GetNewVariableReference_UniqueAndRanges) {
-  SKIP_IF_LLVM_TARGET_MISSING("X86");
-
-  debugger = CreateDebugger();
-  std::tie(target, process) = lldb_private::LoadCore(
-      debugger, k_linux_x86_64_binary, k_linux_x86_64_core);
+  CreateDebugger();
+  LoadCore();
   auto x15 = target.CreateValueFromExpression("x", "15");
   auto y42 = target.CreateValueFromExpression("y", "42");
   auto gzero = target.CreateValueFromExpression("$0", "42");
@@ -120,12 +149,8 @@ TEST_F(VariablesTest, Clear_RemovesTemporaryKeepsPermanent) {
 }
 
 TEST_F(VariablesTest, VariablesStore) {
-  SKIP_IF_LLVM_TARGET_MISSING("X86");
-
-  debugger = CreateDebugger();
-  std::tie(target, process) = lldb_private::LoadCore(
-      debugger, k_linux_x86_64_binary, k_linux_x86_64_core);
-
+  CreateDebugger();
+  LoadCore();
   lldb::SBFrame frame = process.GetSelectedThread().GetSelectedFrame();
 
   std::vector<protocol::Scope> scopes = vars.Insert(frame);
diff --git a/lldb/unittests/TestingSupport/TestUtilities.cpp b/lldb/unittests/TestingSupport/TestUtilities.cpp
index 13092742a4347..d164c227afb9e 100644
--- a/lldb/unittests/TestingSupport/TestUtilities.cpp
+++ b/lldb/unittests/TestingSupport/TestUtilities.cpp
@@ -7,16 +7,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "TestUtilities.h"
-#include "lldb/API/SBStructuredData.h"
-#include "lldb/API/SBTarget.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ObjectYAML/yaml2obj.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
 #include "llvm/Support/YAMLTraits.h"
-#include "llvm/Testing/Support/Error.h"
 #include "gtest/gtest.h"
-#include <utility>
 
 using namespace lldb_private;
 
@@ -64,51 +61,3 @@ llvm::Expected<llvm::sys::fs::TempFile> TestFile::writeToTemporaryFile() {
   llvm::raw_fd_ostream(Temp->FD, /*shouldClose=*/false) << Buffer;
   return std::move(*Temp);
 }
-
-bool lldb_private::DebuggerSupportsLLVMTarget(llvm::StringRef target) {
-  lldb::SBStructuredData data = lldb::SBDebugger::GetBuildConfiguration()
-                                    .GetValueForKey("targets")
-                                    .GetValueForKey("value");
-  for (size_t i = 0; i < data.GetSize(); i++) {
-    char buf[100] = {0};
-    size_t size = data.GetItemAtIndex(i).GetStringValue(buf, sizeof(buf));
-    if (llvm::StringRef(buf, size) == target)
-      return true;
-  }
-
-  return false;
-}
-
-std::pair<lldb::SBTarget, lldb::SBProcess>
-lldb_private::LoadCore(lldb::SBDebugger &debugger, llvm::StringRef binary_path,
-                       llvm::StringRef core_path) {
-  EXPECT_TRUE(debugger);
-
-  llvm::Expected<lldb_private::TestFile> binary_yaml =
-      lldb_private::TestFile::fromYamlFile(binary_path);
-  EXPECT_THAT_EXPECTED(binary_yaml, llvm::Succeeded());
-  llvm::Expected<llvm::sys::fs::TempFile> binary_file =
-      binary_yaml->writeToTemporaryFile();
-  EXPECT_THAT_EXPECTED(binary_file, llvm::Succeeded());
-  lldb::SBError error;
-  lldb::SBTarget target = debugger.CreateTarget(
-      /*filename=*/binary_file->TmpName.data(), /*target_triple=*/"",
-      /*platform_name=*/"", /*add_dependent_modules=*/false, /*error=*/error);
-  EXPECT_TRUE(target);
-  EXPECT_TRUE(error.Success()) << error.GetCString();
-  debugger.SetSelectedTarget(target);
-
-  llvm::Expected<lldb_private::TestFile> core_yaml =
-      lldb_private::TestFile::fromYamlFile(core_path);
-  EXPECT_THAT_EXPECTED(core_yaml, llvm::Succeeded());
-  llvm::Expected<llvm::sys::fs::TempFile> core_file =
-      core_yaml->writeToTemporaryFile();
-  EXPECT_THAT_EXPECTED(core_file, llvm::Succeeded());
-  lldb::SBProcess process = target.LoadCore(core_file->TmpName.data());
-  EXPECT_TRUE(process);
-
-  EXPECT_THAT_ERROR(binary_file->discard(), llvm::Succeeded());
-  EXPECT_THAT_ERROR(core_file->discard(), llvm::Succeeded());
-
-  return std::make_pair(target, process);
-}
diff --git a/lldb/unittests/TestingSupport/TestUtilities.h b/lldb/unittests/TestingSupport/TestUtilities.h
index 01ecc15c9606d..68b4dbc127a7d 100644
--- a/lldb/unittests/TestingSupport/TestUtilities.h
+++ b/lldb/unittests/TestingSupport/TestUtilities.h
@@ -9,7 +9,6 @@
 #ifndef LLDB_UNITTESTS_TESTINGSUPPORT_TESTUTILITIES_H
 #define LLDB_UNITTESTS_TESTINGSUPPORT_TESTUTILITIES_H
 
-#include "lldb/API/SBDebugger.h"
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Utility/DataBuffer.h"
 #include "llvm/ADT/Twine.h"
@@ -17,7 +16,6 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/JSON.h"
 #include "llvm/Support/raw_ostream.h"
-#include "gtest/gtest.h"
 #include <string>
 
 #define ASSERT_NO_ERROR(x)                                                     \
@@ -67,25 +65,12 @@ class TestFile {
   std::string Buffer;
 };
 
-/// Check if the debugger supports the given platform.
-bool DebuggerSupportsLLVMTarget(llvm::StringRef target);
-
-#define SKIP_IF_LLVM_TARGET_MISSING(platform)                                  \
-  if (!::lldb_private::DebuggerSupportsLLVMTarget(platform)) {                 \
-    GTEST_SKIP() << "Unsupported platform";                                    \
-  }
-
 template <typename T> static llvm::Expected<T> roundtripJSON(const T &input) {
   std::string encoded;
   llvm::raw_string_ostream OS(encoded);
   OS << toJSON(input);
   return llvm::json::parse<T>(encoded);
 }
-
-std::pair<lldb::SBTarget, lldb::SBProcess> LoadCore(lldb::SBDebugger &debugger,
-                                                    llvm::StringRef binary_path,
-                                                    llvm::StringRef core_path);
-
 } // namespace lldb_private
 
 #endif

>From 532c62dcdc08dbf395e813b3474e9ce179bc8f31 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Wed, 11 Mar 2026 14:55:39 +0000
Subject: [PATCH 2/4] [lldb][windows] add a Windows FifoFile implementation

---
 lldb/tools/lldb-dap/FifoFiles.cpp             | 91 ++++++++++++++++---
 lldb/tools/lldb-dap/FifoFiles.h               | 24 ++++-
 .../tools/lldb-dap/Handler/RequestHandler.cpp |  6 +-
 lldb/tools/lldb-dap/RunInTerminal.cpp         |  8 +-
 lldb/tools/lldb-dap/RunInTerminal.h           |  1 +
 lldb/unittests/DAP/FifoFilesTest.cpp          |  8 +-
 6 files changed, 115 insertions(+), 23 deletions(-)

diff --git a/lldb/tools/lldb-dap/FifoFiles.cpp b/lldb/tools/lldb-dap/FifoFiles.cpp
index 1f1bba80bd3b1..a5fa8121260eb 100644
--- a/lldb/tools/lldb-dap/FifoFiles.cpp
+++ b/lldb/tools/lldb-dap/FifoFiles.cpp
@@ -9,7 +9,11 @@
 #include "FifoFiles.h"
 #include "JSONUtils.h"
 
-#if !defined(_WIN32)
+#ifdef _WIN32
+#include "lldb/Host/windows/PipeWindows.h"
+#include "lldb/Host/windows/windows.h"
+#include "llvm/Support/Path.h"
+#else
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -24,17 +28,83 @@ using namespace llvm;
 
 namespace lldb_dap {
 
-FifoFile::FifoFile(StringRef path) : m_path(path) {}
+FifoFile::FifoFile(StringRef path, lldb::pipe_t pipe) : m_path(path) {
+#ifdef _WIN32
+  if (pipe == INVALID_HANDLE_VALUE)
+    pipe = CreateFileA(m_path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                       OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+#endif
+  m_pipe = pipe;
+}
 
 FifoFile::~FifoFile() {
-#if !defined(_WIN32)
+#ifdef _WIN32
+  if (m_pipe != INVALID_HANDLE_VALUE) {
+    DisconnectNamedPipe(m_pipe);
+    CloseHandle(m_pipe);
+  }
+#else
   unlink(m_path.c_str());
 #endif
 }
 
+void FifoFile::WriteLine(std::string line) {
+#ifdef _WIN32
+  DWORD written;
+  line += "\n";
+  WriteFile(m_pipe, line.c_str(), static_cast<DWORD>(line.size()), &written,
+            NULL);
+  FlushFileBuffers(m_pipe);
+#else
+  std::ofstream writer(m_path, std::ofstream::out);
+  writer << line << std::endl;
+#endif
+}
+
+void FifoFile::Connect() {
+#ifdef _WIN32
+  ConnectNamedPipe(m_pipe, NULL);
+#endif
+}
+
+std::string FifoFile::ReadLine() {
+#ifdef _WIN32
+  std::string buffer;
+  char read_buffer[4096];
+  DWORD bytes_read;
+
+  if (ReadFile(m_pipe, read_buffer, sizeof(read_buffer) - 1, &bytes_read,
+               NULL) &&
+      bytes_read > 0) {
+    read_buffer[bytes_read] = '\0';
+    buffer = read_buffer;
+  }
+
+  return buffer;
+#else
+  std::ifstream reader(m_path, std::ifstream::in);
+  std::string buffer;
+  std::getline(reader, buffer);
+  return buffer;
+#endif
+}
+
 Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) {
 #if defined(_WIN32)
-  return createStringError(inconvertibleErrorCode(), "Unimplemented");
+  assert(path.starts_with("\\\\.\\pipe\\") &&
+         "FifoFile path should start with '\\\\.\\pipe\\'");
+  HANDLE pipe_handle =
+      CreateNamedPipeA(path.data(), PIPE_ACCESS_DUPLEX,
+                       PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+                       PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, NULL);
+
+  if (pipe_handle == INVALID_HANDLE_VALUE) {
+    DWORD error = GetLastError();
+    return createStringError(std::error_code(error, std::system_category()),
+                             "Couldn't create named pipe: %s", path.data());
+  }
+
+  return std::make_shared<FifoFile>(path, pipe_handle);
 #else
   if (int err = mkfifo(path.data(), 0600))
     return createStringError(std::error_code(err, std::generic_category()),
@@ -43,8 +113,10 @@ Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) {
 #endif
 }
 
-FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name)
-    : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {}
+FifoFileIO::FifoFileIO(std::shared_ptr<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,9 +124,7 @@ 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);
+        std::string buffer = m_fifo_file->ReadLine();
         if (!buffer.empty())
           line = buffer;
       }));
@@ -78,8 +148,7 @@ 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;
+        m_fifo_file->WriteLine(JSONToString(json));
         done = true;
       }));
   if (future->wait_for(timeout) == std::future_status::timeout || !done) {
diff --git a/lldb/tools/lldb-dap/FifoFiles.h b/lldb/tools/lldb-dap/FifoFiles.h
index 633ebeb2aedd4..87ac2c66e6382 100644
--- a/lldb/tools/lldb-dap/FifoFiles.h
+++ b/lldb/tools/lldb-dap/FifoFiles.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_FIFOFILES_H
 #define LLDB_TOOLS_LLDB_DAP_FIFOFILES_H
 
+#include "lldb/Host/Pipe.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/JSON.h"
 
@@ -20,11 +21,27 @@ namespace lldb_dap {
 ///
 /// The file is destroyed when the destructor is invoked.
 struct FifoFile {
-  FifoFile(llvm::StringRef path);
+  FifoFile(llvm::StringRef path, lldb::pipe_t pipe = LLDB_INVALID_PIPE);
 
   ~FifoFile();
 
+  void Connect();
+
+  void WriteLine(std::string line);
+
+  std::string ReadLine();
+
+  llvm::StringRef GetPath() { return m_path; }
+
+  /// FifoFile is not copyable.
+  /// @{
+  FifoFile(const FifoFile &rhs) = delete;
+  void operator=(const FifoFile &rhs) = delete;
+  /// @}
+
+protected:
   std::string m_path;
+  lldb::pipe_t m_pipe;
 };
 
 /// Create a fifo file in the filesystem.
@@ -45,7 +62,8 @@ 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(std::shared_ptr<FifoFile> fifo_file,
+             llvm::StringRef other_endpoint_name);
 
   /// Read the next JSON object from the underlying input fifo file.
   ///
@@ -76,7 +94,7 @@ class FifoFileIO {
       std::chrono::milliseconds timeout = std::chrono::milliseconds(20000));
 
 private:
-  std::string m_fifo_file;
+  std::shared_ptr<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 5e8c2163c838f..103d1f7beb873 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -103,9 +103,9 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
       CreateRunInTerminalCommFile();
   if (!comm_file_or_err)
     return comm_file_or_err.takeError();
-  FifoFile &comm_file = *comm_file_or_err.get();
+  std::shared_ptr<FifoFile> comm_file = *comm_file_or_err;
 
-  RunInTerminalDebugAdapterCommChannel comm_channel(comm_file.m_path);
+  RunInTerminalDebugAdapterCommChannel comm_channel(comm_file);
 
   lldb::pid_t debugger_pid = LLDB_INVALID_PROCESS_ID;
 #if !defined(_WIN32)
@@ -114,7 +114,7 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
 
   llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
       arguments.configuration.program, arguments.args, arguments.env,
-      arguments.cwd, comm_file.m_path, debugger_pid, arguments.stdio,
+      arguments.cwd, comm_file->GetPath(), debugger_pid, arguments.stdio,
       arguments.console == protocol::eConsoleExternalTerminal);
   dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
                                                     std::move(reverse_request));
diff --git a/lldb/tools/lldb-dap/RunInTerminal.cpp b/lldb/tools/lldb-dap/RunInTerminal.cpp
index 9f309dd78221a..ccdad350cdef7 100644
--- a/lldb/tools/lldb-dap/RunInTerminal.cpp
+++ b/lldb/tools/lldb-dap/RunInTerminal.cpp
@@ -97,7 +97,7 @@ static Error ToError(const RunInTerminalMessage &message) {
 
 RunInTerminalLauncherCommChannel::RunInTerminalLauncherCommChannel(
     StringRef comm_file)
-    : m_io(comm_file, "debug adapter") {}
+    : m_io(std::make_shared<FifoFile>(comm_file), "debug adapter") {}
 
 Error RunInTerminalLauncherCommChannel::WaitUntilDebugAdapterAttaches(
     std::chrono::milliseconds timeout) {
@@ -123,7 +123,11 @@ void RunInTerminalLauncherCommChannel::NotifyError(StringRef error) {
 
 RunInTerminalDebugAdapterCommChannel::RunInTerminalDebugAdapterCommChannel(
     StringRef comm_file)
-    : m_io(comm_file, "runInTerminal launcher") {}
+    : m_io(std::make_shared<FifoFile>(comm_file), "runInTerminal launcher") {}
+
+RunInTerminalDebugAdapterCommChannel::RunInTerminalDebugAdapterCommChannel(
+    std::shared_ptr<FifoFile> comm_file)
+    : m_io(std::move(comm_file), "runInTerminal launcher") {}
 
 // Can't use \a std::future<llvm::Error> because it doesn't compile on Windows
 std::future<lldb::SBError>
diff --git a/lldb/tools/lldb-dap/RunInTerminal.h b/lldb/tools/lldb-dap/RunInTerminal.h
index 457850c8ea538..f6e922e59a095 100644
--- a/lldb/tools/lldb-dap/RunInTerminal.h
+++ b/lldb/tools/lldb-dap/RunInTerminal.h
@@ -99,6 +99,7 @@ class RunInTerminalLauncherCommChannel {
 class RunInTerminalDebugAdapterCommChannel {
 public:
   RunInTerminalDebugAdapterCommChannel(llvm::StringRef comm_file);
+  RunInTerminalDebugAdapterCommChannel(std::shared_ptr<FifoFile> comm_file);
 
   /// Notify the runInTerminal launcher that it was attached.
   ///
diff --git a/lldb/unittests/DAP/FifoFilesTest.cpp b/lldb/unittests/DAP/FifoFilesTest.cpp
index bbc1b608e91bd..e59fc54cc9543 100644
--- a/lldb/unittests/DAP/FifoFilesTest.cpp
+++ b/lldb/unittests/DAP/FifoFilesTest.cpp
@@ -45,8 +45,8 @@ TEST(FifoFilesTest, SendAndReceiveJSON) {
   auto fifo = CreateFifoFile(fifo_path);
   EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded());
 
-  FifoFileIO writer(fifo_path, "writer");
-  FifoFileIO reader(fifo_path, "reader");
+  FifoFileIO writer(*fifo, "writer");
+  FifoFileIO reader(*fifo, "reader");
 
   llvm::json::Object obj;
   obj["foo"] = "bar";
@@ -79,7 +79,7 @@ TEST(FifoFilesTest, ReadTimeout) {
   auto fifo = CreateFifoFile(fifo_path);
   EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded());
 
-  FifoFileIO reader(fifo_path, "reader");
+  FifoFileIO reader(*fifo, "reader");
 
   // No writer, should timeout.
   auto result = reader.ReadJSON(std::chrono::milliseconds(100));
@@ -91,7 +91,7 @@ TEST(FifoFilesTest, WriteTimeout) {
   auto fifo = CreateFifoFile(fifo_path);
   EXPECT_THAT_EXPECTED(fifo, llvm::Succeeded());
 
-  FifoFileIO writer(fifo_path, "writer");
+  FifoFileIO writer(*fifo, "writer");
 
   // No reader, should timeout.
   llvm::json::Object obj;

>From 6d4b045a212835f8f2aa87638b6762ab886fc614 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Wed, 11 Mar 2026 17:35:38 +0000
Subject: [PATCH 3/4] fixup! [lldb][windows] add a Windows FifoFile
 implementation

---
 lldb/tools/lldb-dap/FifoFiles.cpp | 33 ++++++++++++++++++++-----------
 lldb/tools/lldb-dap/FifoFiles.h   |  2 +-
 2 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/lldb/tools/lldb-dap/FifoFiles.cpp b/lldb/tools/lldb-dap/FifoFiles.cpp
index a5fa8121260eb..8d03957b50008 100644
--- a/lldb/tools/lldb-dap/FifoFiles.cpp
+++ b/lldb/tools/lldb-dap/FifoFiles.cpp
@@ -30,9 +30,12 @@ namespace lldb_dap {
 
 FifoFile::FifoFile(StringRef path, lldb::pipe_t pipe) : m_path(path) {
 #ifdef _WIN32
-  if (pipe == INVALID_HANDLE_VALUE)
+  if (pipe == INVALID_HANDLE_VALUE) {
+    assert(path.starts_with("\\\\.\\pipe\\") &&
+           "FifoFile path should start with '\\\\.\\pipe\\'");
     pipe = CreateFileA(m_path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
                        OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+  }
 #endif
   m_pipe = pipe;
 }
@@ -48,16 +51,15 @@ FifoFile::~FifoFile() {
 #endif
 }
 
-void FifoFile::WriteLine(std::string line) {
+void FifoFile::WriteLine(llvm::StringRef line) {
 #ifdef _WIN32
   DWORD written;
-  line += "\n";
-  WriteFile(m_pipe, line.c_str(), static_cast<DWORD>(line.size()), &written,
-            NULL);
+  std::string str = line.str() + "\n";
+  WriteFile(m_pipe, str.data(), static_cast<DWORD>(str.size()), &written, NULL);
   FlushFileBuffers(m_pipe);
 #else
   std::ofstream writer(m_path, std::ofstream::out);
-  writer << line << std::endl;
+  writer << line.data() << std::endl;
 #endif
 }
 
@@ -73,11 +75,20 @@ std::string FifoFile::ReadLine() {
   char read_buffer[4096];
   DWORD bytes_read;
 
-  if (ReadFile(m_pipe, read_buffer, sizeof(read_buffer) - 1, &bytes_read,
-               NULL) &&
-      bytes_read > 0) {
-    read_buffer[bytes_read] = '\0';
-    buffer = read_buffer;
+  while (true) {
+    if (!ReadFile(m_pipe, read_buffer, sizeof(read_buffer), &bytes_read,
+                  NULL) ||
+        bytes_read == 0)
+      break;
+
+    buffer.append(read_buffer, bytes_read);
+
+    if (buffer.back() == '\n') {
+      buffer.pop_back();
+      if (!buffer.empty() && buffer.back() == '\r')
+        buffer.pop_back();
+      break;
+    }
   }
 
   return buffer;
diff --git a/lldb/tools/lldb-dap/FifoFiles.h b/lldb/tools/lldb-dap/FifoFiles.h
index 87ac2c66e6382..96e6b7f640e61 100644
--- a/lldb/tools/lldb-dap/FifoFiles.h
+++ b/lldb/tools/lldb-dap/FifoFiles.h
@@ -27,7 +27,7 @@ struct FifoFile {
 
   void Connect();
 
-  void WriteLine(std::string line);
+  void WriteLine(llvm::StringRef line);
 
   std::string ReadLine();
 

>From 23fbf7d8bcdccd40a37c896882676c953a36986a Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Thu, 12 Mar 2026 11:50:40 +0000
Subject: [PATCH 4/4] read line by line

---
 lldb/tools/lldb-dap/FifoFiles.cpp | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/lldb/tools/lldb-dap/FifoFiles.cpp b/lldb/tools/lldb-dap/FifoFiles.cpp
index 8d03957b50008..1c81c8b503d3a 100644
--- a/lldb/tools/lldb-dap/FifoFiles.cpp
+++ b/lldb/tools/lldb-dap/FifoFiles.cpp
@@ -76,19 +76,11 @@ std::string FifoFile::ReadLine() {
   DWORD bytes_read;
 
   while (true) {
-    if (!ReadFile(m_pipe, read_buffer, sizeof(read_buffer), &bytes_read,
-                  NULL) ||
-        bytes_read == 0)
-      break;
-
+    BOOL success =
+        ReadFile(m_pipe, read_buffer, sizeof(read_buffer), &bytes_read, NULL);
     buffer.append(read_buffer, bytes_read);
-
-    if (buffer.back() == '\n') {
-      buffer.pop_back();
-      if (!buffer.empty() && buffer.back() == '\r')
-        buffer.pop_back();
+    if (success || GetLastError() != ERROR_MORE_DATA)
       break;
-    }
   }
 
   return buffer;
@@ -106,7 +98,7 @@ Expected<std::shared_ptr<FifoFile>> CreateFifoFile(StringRef path) {
          "FifoFile path should start with '\\\\.\\pipe\\'");
   HANDLE pipe_handle =
       CreateNamedPipeA(path.data(), PIPE_ACCESS_DUPLEX,
-                       PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+                       PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
                        PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, NULL);
 
   if (pipe_handle == INVALID_HANDLE_VALUE) {



More information about the lldb-commits mailing list