Skip to content

[lldb-dap] Make connection URLs match lldb #144770

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lldb/include/lldb/Host/Socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class Socket : public IOObject {
ProtocolUnixAbstract
};

enum SocketMode {
ModeAccept,
ModeConnect,
};

struct HostAndPort {
std::string hostname;
uint16_t port;
Expand All @@ -83,6 +88,10 @@ class Socket : public IOObject {
}
};

using ProtocolModePair = std::pair<SocketProtocol, SocketMode>;
static std::optional<ProtocolModePair>
GetProtocolAndMode(llvm::StringRef scheme);

static const NativeSocket kInvalidSocketValue;

~Socket() override;
Expand Down
32 changes: 29 additions & 3 deletions lldb/source/Host/common/Socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ Socket::UdpConnect(llvm::StringRef host_and_port) {
return UDPSocket::CreateConnected(host_and_port);
}

llvm::Expected<Socket::HostAndPort> Socket::DecodeHostAndPort(llvm::StringRef host_and_port) {
llvm::Expected<Socket::HostAndPort>
Socket::DecodeHostAndPort(llvm::StringRef host_and_port) {
static llvm::Regex g_regex("([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)");
HostAndPort ret;
llvm::SmallVector<llvm::StringRef, 3> matches;
Expand Down Expand Up @@ -347,8 +348,8 @@ Status Socket::Write(const void *buf, size_t &num_bytes) {
", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64
" (error = %s)",
static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf,
static_cast<uint64_t>(src_len),
static_cast<int64_t>(bytes_sent), error.AsCString());
static_cast<uint64_t>(src_len), static_cast<int64_t>(bytes_sent),
error.AsCString());
}

return error;
Expand Down Expand Up @@ -476,3 +477,28 @@ llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &OS,
const Socket::HostAndPort &HP) {
return OS << '[' << HP.hostname << ']' << ':' << HP.port;
}

std::optional<Socket::ProtocolModePair>
Socket::GetProtocolAndMode(llvm::StringRef scheme) {
// Keep in sync with ConnectionFileDescriptor::Connect.
return llvm::StringSwitch<std::optional<ProtocolModePair>>(scheme)
.Case("listen", ProtocolModePair{SocketProtocol::ProtocolTcp,
SocketMode::ModeAccept})
.Cases("accept", "unix-accept",
ProtocolModePair{SocketProtocol::ProtocolUnixDomain,
SocketMode::ModeAccept})
.Case("unix-abstract-accept",
ProtocolModePair{SocketProtocol::ProtocolUnixAbstract,
SocketMode::ModeAccept})
.Cases("connect", "tcp-connect",
ProtocolModePair{SocketProtocol::ProtocolTcp,
SocketMode::ModeConnect})
.Case("udp", ProtocolModePair{SocketProtocol::ProtocolTcp,
SocketMode::ModeConnect})
.Case("unix-connect", ProtocolModePair{SocketProtocol::ProtocolUnixDomain,
SocketMode::ModeConnect})
.Case("unix-abstract-connect",
ProtocolModePair{SocketProtocol::ProtocolUnixAbstract,
SocketMode::ModeConnect})
.Default(std::nullopt);
}
6 changes: 3 additions & 3 deletions lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def test_server_port(self):
Test launching a binary with a lldb-dap in server mode on a specific port.
"""
self.build()
(_, connection) = self.start_server(connection="tcp://localhost:0")
(_, connection) = self.start_server(connection="listen://localhost:0")
self.run_debug_session(connection, "Alice")
self.run_debug_session(connection, "Bob")

Expand All @@ -72,7 +72,7 @@ def cleanup():
self.addTearDownHook(cleanup)

self.build()
(_, connection) = self.start_server(connection="unix://" + name)
(_, connection) = self.start_server(connection="accept://" + name)
self.run_debug_session(connection, "Alice")
self.run_debug_session(connection, "Bob")

Expand All @@ -82,7 +82,7 @@ def test_server_interrupt(self):
Test launching a binary with lldb-dap in server mode and shutting down the server while the debug session is still active.
"""
self.build()
(process, connection) = self.start_server(connection="tcp://localhost:0")
(process, connection) = self.start_server(connection="listen://localhost:0")
self.dap_server = dap_server.DebugAdapterServer(
connection=connection,
)
Expand Down
4 changes: 2 additions & 2 deletions lldb/tools/lldb-dap/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def connection
MetaVarName<"<connection>">,
HelpText<
"Communicate with the lldb-dap tool over the specified connection. "
"Connections are specified like 'tcp://[host]:port' or "
"'unix:///path'.">;
"Connections are specified like 'listen://[host]:port' or "
"'accept:///path'.">;

def launch_target: S<"launch-target">,
MetaVarName<"<target>">,
Expand Down
2 changes: 1 addition & 1 deletion lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class LLDBDapServer implements vscode.Disposable {
args: string[],
options?: child_process.SpawnOptionsWithoutStdio,
): Promise<{ host: string; port: number } | undefined> {
const dapArgs = [...args, "--connection", "connect://localhost:0"];
const dapArgs = [...args, "--connection", "listen://localhost:0" ];
if (!(await this.shouldContinueStartup(dapPath, dapArgs))) {
return undefined;
}
Expand Down
29 changes: 19 additions & 10 deletions lldb/tools/lldb-dap/tool/lldb-dap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ static void PrintHelp(LLDBDAPOptTable &table, llvm::StringRef tool_name) {
parent over stdio. Passing a --connection URI will cause lldb-dap to listen
for a connection in the specified mode.
lldb-dap --connection connection://localhost:<port>
lldb-dap --connection listen://localhost:<port>
Passing --wait-for-debugger will pause the process at startup and wait for a
debugger to attach to the process.
Expand Down Expand Up @@ -226,23 +226,32 @@ static llvm::Expected<std::pair<Socket::SocketProtocol, std::string>>
validateConnection(llvm::StringRef conn) {
auto uri = lldb_private::URI::Parse(conn);

if (uri && (uri->scheme == "tcp" || uri->scheme == "connect" ||
!uri->hostname.empty() || uri->port)) {
auto make_error = [conn]() -> llvm::Error {
return llvm::createStringError(
"Unsupported connection specifier, expected 'accept:///path' or "
"'listen://[host]:port', got '%s'.",
conn.str().c_str());
};

if (!uri)
return make_error();

std::optional<Socket::ProtocolModePair> protocol_and_mode =
Socket::GetProtocolAndMode(uri->scheme);
if (!protocol_and_mode || protocol_and_mode->second != Socket::ModeAccept)
return make_error();

if (protocol_and_mode->first == Socket::ProtocolTcp) {
return std::make_pair(
Socket::ProtocolTcp,
formatv("[{0}]:{1}", uri->hostname.empty() ? "0.0.0.0" : uri->hostname,
uri->port.value_or(0)));
}

if (uri && (uri->scheme == "unix" || uri->scheme == "unix-connect" ||
uri->path != "/")) {
if (protocol_and_mode->first == Socket::ProtocolUnixDomain)
return std::make_pair(Socket::ProtocolUnixDomain, uri->path.str());
}

return llvm::createStringError(
"Unsupported connection specifier, expected 'unix-connect:///path' or "
"'connect://[host]:port', got '%s'.",
conn.str().c_str());
return make_error();
}

static llvm::Error
Expand Down
Loading