[Lldb-commits] [lldb] 9a95dd1 - [lldb] Let the host platform write to pipes
via lldb-commits
lldb-commits at lists.llvm.org
Thu Oct 15 07:58:23 PDT 2026
Author: Andrew Gontarek
Date: 2026-10-15T14:58:15Z
New Revision: 9a95dd1e4323bc4c439c2e9eb1128d089b63a29f
URL: https://github.com/llvm/llvm-project/commit/9a95dd1e4323bc4c439c2e9eb1128d089b63a29f
DIFF: https://github.com/llvm/llvm-project/commit/9a95dd1e4323bc4c439c2e9eb1128d089b63a29f.diff
LOG: [lldb] Let the host platform write to pipes
`Platform::WriteFile` on the host platform could not write to a pipe: it
goes to `FileCache::WriteFile`, which seeks to the offset before
writing, and a pipe refuses the seek with ESPIPE. The offset means
nothing for a pipe, so `FileCache::WriteFile` now writes at the pipe's
end when the seek fails that way.
This is the host-side counterpart of #232045, which does the same for
lldb-server's `vFile:pwrite`. With both, writing to a pipe through a
platform works the same whether the platform is the host or a remote
one. Downstream, NVIDIA's GPU support writes a byte to a pipe in the
debugged process through the target's platform, to ask the CUDA driver
to attach.
The new FileCacheTest opens a named pipe through `FileCache`, writes to
it at a nonzero offset, and reads back exactly the bytes sent. Without
the fix, the write fails with ESPIPE. The test is POSIX-only, since
named pipes are files only there.
Added:
lldb/unittests/Host/FileCacheTest.cpp
Modified:
lldb/source/Host/common/FileCache.cpp
lldb/unittests/Host/CMakeLists.txt
Removed:
################################################################################
diff --git a/lldb/source/Host/common/FileCache.cpp b/lldb/source/Host/common/FileCache.cpp
index b8aaa0f88f1efa..40275f0b34981e 100644
--- a/lldb/source/Host/common/FileCache.cpp
+++ b/lldb/source/Host/common/FileCache.cpp
@@ -11,6 +11,8 @@
#include "lldb/Host/File.h"
#include "lldb/Host/FileSystem.h"
+#include <cerrno>
+
using namespace lldb;
using namespace lldb_private;
@@ -80,8 +82,13 @@ uint64_t FileCache::WriteFile(lldb::user_id_t fd, uint64_t offset,
return UINT64_MAX;
}
if (static_cast<uint64_t>(file_up->SeekFromStart(offset, &error)) != offset ||
- error.Fail())
- return UINT64_MAX;
+ error.Fail()) {
+ // A pipe cannot seek, so the seek fails on it with ESPIPE. The offset
+ // means nothing there, so write at the pipe's end instead.
+ if (error.GetError() != ESPIPE)
+ return UINT64_MAX;
+ error.Clear();
+ }
size_t bytes_written = src_len;
error = file_up->Write(src, bytes_written);
if (error.Fail())
diff --git a/lldb/unittests/Host/CMakeLists.txt b/lldb/unittests/Host/CMakeLists.txt
index 285f93de58c60e..7ecc9c76f6d399 100644
--- a/lldb/unittests/Host/CMakeLists.txt
+++ b/lldb/unittests/Host/CMakeLists.txt
@@ -1,6 +1,7 @@
set (FILES
ConnectionFileDescriptorTest.cpp
FileActionTest.cpp
+ FileCacheTest.cpp
FileSystemTest.cpp
FileTest.cpp
HostInfoTest.cpp
diff --git a/lldb/unittests/Host/FileCacheTest.cpp b/lldb/unittests/Host/FileCacheTest.cpp
new file mode 100644
index 00000000000000..e7a5942cc7fa5f
--- /dev/null
+++ b/lldb/unittests/Host/FileCacheTest.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "lldb/Host/FileCache.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/Pipe.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+
+class FileCacheTest : public testing::Test {
+public:
+ SubsystemRAII<FileSystem, HostInfo> subsystems;
+};
+
+// Named pipes are files only on POSIX.
+#ifndef _WIN32
+TEST_F(FileCacheTest, WriteToPipe) {
+ Pipe pipe;
+ llvm::SmallString<0> name;
+ ASSERT_THAT_ERROR(
+ pipe.CreateWithUniqueName("FileCacheTest-WriteToPipe", name).ToError(),
+ llvm::Succeeded());
+ llvm::scope_exit delete_pipe([&] { pipe.Delete(name); });
+ // With the read end open, opening the write end does not block.
+ ASSERT_THAT_ERROR(pipe.OpenAsReader(name).ToError(), llvm::Succeeded());
+
+ FileCache &cache = FileCache::GetInstance();
+ Status error;
+ lldb::user_id_t fd =
+ cache.OpenFile(FileSpec(name), File::eOpenOptionWriteOnly, 0, error);
+ ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
+ // A pipe cannot seek, so the bytes go to its end whatever the offset.
+ EXPECT_EQ(cache.WriteFile(fd, /*offset=*/1, "abc", 3, error), 3u);
+ EXPECT_THAT_ERROR(error.ToError(), llvm::Succeeded());
+ EXPECT_TRUE(cache.CloseFile(fd, error));
+
+ char buffer[3];
+ ASSERT_THAT_EXPECTED(pipe.Read(buffer, sizeof(buffer)), llvm::HasValue(3));
+ EXPECT_EQ(llvm::StringRef(buffer, sizeof(buffer)), "abc");
+}
+#endif
More information about the lldb-commits
mailing list