[Lldb-commits] [lldb] [lldb][Windows] Support AF_UNIX domain sockets (PR #205618)
Charles Zablit via lldb-commits
lldb-commits at lists.llvm.org
Wed Jun 24 10:53:38 PDT 2026
https://github.com/charles-zablit created https://github.com/llvm/llvm-project/pull/205618
Windows 10 1803+ provides `AF_UNIX` sockets via `<afunix.h>`. This patch compiles `DomainSocket.cpp` on Windows and port it to the Win32 `sockaddr_un`.
There is no `sun_len` and no `SUN_LEN` macro, so lldb must compute the address length explicitly. It must also emulate the missing `socketpair()` in `DomainSocket::CreatePair`
Also remove the gate on the `ProtocolUnixDomain` paths in `Socket::Create/CreatePair` and the lldb-platform child-socket path so they build with `LLDB_ENABLE_POSIX` off on Windows.
This is part of a longer set of patches to fix tests on `LLDB_USE_LLDB_SERVER=1`.
>From 1ecdcb57a873070e2e19e6d41a978405ae5db9da Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Wed, 24 Jun 2026 18:49:32 +0100
Subject: [PATCH] [lldb][Windows] Support AF_UNIX domain sockets
---
lldb/source/Host/CMakeLists.txt | 2 +-
lldb/source/Host/common/Socket.cpp | 13 +++--
lldb/source/Host/posix/DomainSocket.cpp | 51 +++++++++++++++----
lldb/tools/lldb-server/lldb-platform.cpp | 4 +-
lldb/unittests/Host/SocketTest.cpp | 11 +++-
.../Host/SocketTestUtilities.cpp | 7 +--
.../TestingSupport/Host/SocketTestUtilities.h | 6 +--
7 files changed, 70 insertions(+), 24 deletions(-)
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index 28c639ee38215..c4836adb8f59b 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -73,6 +73,7 @@ endif()
add_host_subdirectory(posix
posix/ConnectionFileDescriptorPosix.cpp
+ posix/DomainSocket.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
@@ -100,7 +101,6 @@ if (CMAKE_SYSTEM_NAME MATCHES "Windows")
endif()
else()
add_host_subdirectory(posix
- posix/DomainSocket.cpp
posix/FilePosix.cpp
posix/FileSystemPosix.cpp
posix/HostInfoPosix.cpp
diff --git a/lldb/source/Host/common/Socket.cpp b/lldb/source/Host/common/Socket.cpp
index 810d63fc0390d..6c15d5ebf5ed4 100644
--- a/lldb/source/Host/common/Socket.cpp
+++ b/lldb/source/Host/common/Socket.cpp
@@ -24,9 +24,9 @@
#include "llvm/Support/Regex.h"
#include "llvm/Support/WindowsError.h"
-#if LLDB_ENABLE_POSIX
#include "lldb/Host/posix/DomainSocket.h"
+#if LLDB_ENABLE_POSIX
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
@@ -211,7 +211,7 @@ std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol,
socket_up = std::make_unique<UDPSocket>(should_close);
break;
case ProtocolUnixDomain:
-#if LLDB_ENABLE_POSIX
+#if LLDB_ENABLE_POSIX || defined(_WIN32)
socket_up = std::make_unique<DomainSocket>(should_close);
#else
error = Status::FromErrorString(
@@ -241,10 +241,17 @@ Socket::CreatePair(std::optional<SocketProtocol> protocol) {
switch (protocol.value_or(kBestProtocol)) {
case ProtocolTcp:
return TCPSocket::CreatePair();
-#if LLDB_ENABLE_POSIX
case ProtocolUnixDomain:
+#if LLDB_ENABLE_POSIX || defined(_WIN32)
+ return DomainSocket::CreatePair();
+#else
+ return llvm::createStringError("unsupported protocol");
+#endif
case ProtocolUnixAbstract:
+#if LLDB_ENABLE_POSIX
return DomainSocket::CreatePair();
+#else
+ return llvm::createStringError("unsupported protocol");
#endif
default:
return llvm::createStringError("unsupported protocol");
diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp
index 4f08c372d43cf..1893b4aa9de59 100644
--- a/lldb/source/Host/posix/DomainSocket.cpp
+++ b/lldb/source/Host/posix/DomainSocket.cpp
@@ -15,12 +15,23 @@
#include "llvm/Support/Errno.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include <chrono>
#include <cstddef>
-#include <fcntl.h>
#include <memory>
+
+#ifdef _WIN32
+// DomainSocket.h pulls in Socket.h, which includes winsock2.h on Windows.
+// afunix.h must be included after winsock2.h.
+// clang-format off
+#include <afunix.h>
+// clang-format on
+#else
+#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
+#endif
using namespace lldb;
using namespace lldb_private;
@@ -38,14 +49,8 @@ static bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
memcpy(saddr_un->sun_path + name_offset, name.data(), name.size());
- // For domain sockets we can use SUN_LEN in order to calculate size of
- // sockaddr_un, but for abstract sockets we have to calculate size manually
- // because of leading null symbol.
- if (name_offset == 0)
- saddr_un_len = SUN_LEN(saddr_un);
- else
- saddr_un_len =
- offsetof(struct sockaddr_un, sun_path) + name_offset + name.size();
+ saddr_un_len =
+ offsetof(struct sockaddr_un, sun_path) + name_offset + name.size();
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
defined(__OpenBSD__)
@@ -79,6 +84,7 @@ DomainSocket::DomainSocket(SocketProtocol protocol, NativeSocket socket,
}
llvm::Expected<DomainSocket::Pair> DomainSocket::CreatePair() {
+#ifndef _WIN32
int sockets[2];
int type = SOCK_STREAM;
#ifdef SOCK_CLOEXEC
@@ -111,6 +117,33 @@ llvm::Expected<DomainSocket::Pair> DomainSocket::CreatePair() {
std::unique_ptr<DomainSocket>(
new DomainSocket(ProtocolUnixDomain, sockets[1],
/*should_close=*/true)));
+#else // _WIN32
+ llvm::SmallString<128> model;
+ llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/true, model);
+ llvm::sys::path::append(model, "lldb-domain-socketpair-%%%%%%%%.sock");
+ llvm::SmallString<128> path;
+ llvm::sys::fs::createUniquePath(model, path, /*MakeAbsolute=*/false);
+
+ auto listen_socket = std::make_unique<DomainSocket>(/*should_close=*/true);
+ if (Status error = listen_socket->Listen(path, /*backlog=*/1); error.Fail())
+ return error.takeError();
+
+ auto connect_socket = std::make_unique<DomainSocket>(/*should_close=*/true);
+ if (Status error = connect_socket->Connect(path); error.Fail())
+ return error.takeError();
+
+ // The connection is already queued, so a short timeout is sufficient.
+ Socket *accept_socket = nullptr;
+ Status error = listen_socket->Accept(std::chrono::seconds(1), accept_socket);
+ // Once both ends are connected the bound socket file is no longer needed.
+ llvm::sys::fs::remove(path);
+ if (error.Fail())
+ return error.takeError();
+
+ return Pair(std::move(connect_socket),
+ std::unique_ptr<DomainSocket>(
+ static_cast<DomainSocket *>(accept_socket)));
+#endif // _WIN32
}
Status DomainSocket::Connect(llvm::StringRef name) {
diff --git a/lldb/tools/lldb-server/lldb-platform.cpp b/lldb/tools/lldb-server/lldb-platform.cpp
index ec2ef053241ca..5e1bf651cfd67 100644
--- a/lldb/tools/lldb-server/lldb-platform.cpp
+++ b/lldb/tools/lldb-server/lldb-platform.cpp
@@ -40,9 +40,7 @@
#include "lldb/Host/OptionParser.h"
#include "lldb/Host/Socket.h"
#include "lldb/Host/common/TCPSocket.h"
-#if LLDB_ENABLE_POSIX
#include "lldb/Host/posix/DomainSocket.h"
-#endif
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Status.h"
@@ -539,7 +537,7 @@ int main_platform(int argc, char *argv[]) {
if (gdbserver_port) {
socket = std::make_unique<TCPSocket>(sockfd, /*should_close=*/true);
} else {
-#if LLDB_ENABLE_POSIX
+#if LLDB_ENABLE_POSIX || defined(_WIN32)
llvm::Expected<std::unique_ptr<DomainSocket>> domain_socket =
DomainSocket::FromBoundNativeSocket(sockfd, /*should_close=*/true);
if (!domain_socket) {
diff --git a/lldb/unittests/Host/SocketTest.cpp b/lldb/unittests/Host/SocketTest.cpp
index 45dcce83ca0a7..d080946108028 100644
--- a/lldb/unittests/Host/SocketTest.cpp
+++ b/lldb/unittests/Host/SocketTest.cpp
@@ -93,6 +93,11 @@ TEST_F(SocketTest, CreatePair) {
functional_protocols.push_back(Socket::ProtocolUnixDomain);
functional_protocols.push_back(Socket::ProtocolUnixAbstract);
}
+#elif defined(_WIN32)
+ // Windows supports AF_UNIX domain sockets (Windows 10 1803+) but not the
+ // Linux abstract-namespace variant.
+ if (HostSupportsDomainSockets())
+ functional_protocols.push_back(Socket::ProtocolUnixDomain);
#endif
for (auto p : functional_protocols) {
@@ -111,7 +116,7 @@ TEST_F(SocketTest, CreatePair) {
std::vector<Socket::SocketProtocol> erroring_protocols = {
#if !LLDB_ENABLE_POSIX
- Socket::ProtocolUnixDomain,
+ // Windows has AF_UNIX domain sockets but no abstract-namespace sockets.
Socket::ProtocolUnixAbstract,
#endif
};
@@ -121,7 +126,7 @@ TEST_F(SocketTest, CreatePair) {
}
}
-#if LLDB_ENABLE_POSIX
+#if LLDB_ENABLE_POSIX || defined(_WIN32)
TEST_F(SocketTest, DomainListenConnectAccept) {
if (!HostSupportsDomainSockets())
GTEST_SKIP() << "Domain sockets unavailable";
@@ -397,7 +402,9 @@ TEST_F(SocketTest, DomainGetConnectURI) {
EXPECT_EQ(socket_b_up->GetRemoteConnectionURI(), "");
}
+#endif
+#if LLDB_ENABLE_POSIX || defined(_WIN32)
TEST_F(SocketTest, DomainSocketFromBoundNativeSocket) {
if (!HostSupportsDomainSockets())
GTEST_SKIP() << "Domain sockets unavailable";
diff --git a/lldb/unittests/TestingSupport/Host/SocketTestUtilities.cpp b/lldb/unittests/TestingSupport/Host/SocketTestUtilities.cpp
index 2c5e310ea9a9b..5b66004a7a33e 100644
--- a/lldb/unittests/TestingSupport/Host/SocketTestUtilities.cpp
+++ b/lldb/unittests/TestingSupport/Host/SocketTestUtilities.cpp
@@ -71,7 +71,7 @@ bool lldb_private::CreateTCPConnectedSockets(
return true;
}
-#if LLDB_ENABLE_POSIX
+#if LLDB_ENABLE_POSIX || defined(_WIN32)
void lldb_private::CreateDomainConnectedSockets(
llvm::StringRef path, std::unique_ptr<DomainSocket> *socket_a_up,
std::unique_ptr<DomainSocket> *socket_b_up) {
@@ -148,16 +148,17 @@ llvm::Expected<std::string> lldb_private::GetLocalhostIP() {
"Neither IPv4 nor IPv6 appear to be supported");
}
-#if LLDB_ENABLE_POSIX
+#if LLDB_ENABLE_POSIX || defined(_WIN32)
bool lldb_private::HostSupportsDomainSockets() {
llvm::SmallString<64> Path;
if (llvm::sys::fs::createUniqueDirectory("SocketTestCanary", Path))
return false;
+ auto cleanup_dir = Path;
llvm::sys::path::append(Path, "test");
DomainSocket sock(true);
Status status = sock.Listen(Path, 1);
llvm::sys::fs::remove(Path);
- llvm::sys::fs::remove(Path.str().rsplit('/').first);
+ llvm::sys::fs::remove(cleanup_dir);
return status.Success();
}
#endif
diff --git a/lldb/unittests/TestingSupport/Host/SocketTestUtilities.h b/lldb/unittests/TestingSupport/Host/SocketTestUtilities.h
index a7c9aee162e65..1dc57b7992863 100644
--- a/lldb/unittests/TestingSupport/Host/SocketTestUtilities.h
+++ b/lldb/unittests/TestingSupport/Host/SocketTestUtilities.h
@@ -21,7 +21,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Testing/Support/Error.h"
-#if LLDB_ENABLE_POSIX
+#if LLDB_ENABLE_POSIX || defined(_WIN32)
#include "lldb/Host/posix/DomainSocket.h"
#endif
@@ -34,7 +34,7 @@ void CreateConnectedSockets(
bool CreateTCPConnectedSockets(std::string listen_remote_ip,
std::unique_ptr<TCPSocket> *a_up,
std::unique_ptr<TCPSocket> *b_up);
-#if LLDB_ENABLE_POSIX
+#if LLDB_ENABLE_POSIX || defined(_WIN32)
void CreateDomainConnectedSockets(llvm::StringRef path,
std::unique_ptr<DomainSocket> *a_up,
std::unique_ptr<DomainSocket> *b_up);
@@ -42,7 +42,7 @@ void CreateDomainConnectedSockets(llvm::StringRef path,
bool HostSupportsIPv6();
bool HostSupportsIPv4();
-#if LLDB_ENABLE_POSIX
+#if LLDB_ENABLE_POSIX || defined(_WIN32)
bool HostSupportsDomainSockets();
#endif
More information about the lldb-commits
mailing list