[Lldb-commits] [lldb] [lldb] Removed gdbserver ports map from lldb-server (PR #104238)
Pavel Labath via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 4 01:12:20 PDT 2024
================
@@ -421,97 +417,210 @@ int main_platform(int argc, char *argv[]) {
return 0;
}
- const bool children_inherit_listen_socket = false;
+ if (gdbserver_port != 0 &&
+ (gdbserver_port < LOW_PORT || gdbserver_port > HIGH_PORT)) {
+ WithColor::error() << llvm::formatv("Port number {0} is not in the "
+ "valid user port range of {1} - {2}\n",
+ gdbserver_port, LOW_PORT, HIGH_PORT);
+ return 1;
+ }
+
// the test suite makes many connections in parallel, let's not miss any.
// The highest this should get reasonably is a function of the number
// of target CPUs. For now, let's just use 100.
const int backlog = 100;
- std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create(
- listen_host_port, children_inherit_listen_socket, error));
- if (error.Fail()) {
- fprintf(stderr, "failed to create acceptor: %s", error.AsCString());
- exit(socket_error);
+ std::unique_ptr<Socket> sock_named;
+ std::unique_ptr<TCPSocket> sock_platform;
+ std::unique_ptr<TCPSocket> sock_gdb;
+ std::string hostname;
+ uint16_t platform_port = 0;
+ Socket::SocketProtocol protocol = Socket::ProtocolUnixDomain;
+
+ // Try to match socket name as URL - e.g., tcp://localhost:5555
+ if (std::optional<URI> uri = URI::Parse(listen_host_port)) {
+ if (!Socket::FindProtocolByScheme(uri->scheme.str().c_str(), protocol)) {
+ fprintf(stderr, "Unknown protocol scheme \"%s\".",
+ uri->scheme.str().c_str());
+ return socket_error;
+ }
+ if (protocol == Socket::ProtocolTcp) {
+ hostname = uri->hostname;
+ if (uri->port) {
+ platform_port = *(uri->port);
+ }
+ } else
+ hostname = listen_host_port.substr(uri->scheme.size() + strlen("://"));
+ } else {
+ // Try to match socket name as $host:port - e.g., localhost:5555
+ llvm::Expected<Socket::HostAndPort> host_port =
+ Socket::DecodeHostAndPort(listen_host_port);
+ if (!llvm::errorToBool(host_port.takeError())) {
+ protocol = Socket::ProtocolTcp;
+ hostname = host_port->hostname;
+ platform_port = host_port->port;
+ } else
+ hostname = listen_host_port;
}
- error = acceptor_up->Listen(backlog);
- if (error.Fail()) {
- printf("failed to listen: %s\n", error.AsCString());
- exit(socket_error);
+ std::string socket_id;
+ if (protocol == Socket::ProtocolTcp) {
+ if (platform_port != 0 && platform_port == gdbserver_port) {
+ fprintf(stderr, "The same platform and gdb ports %u.", platform_port);
+ return socket_error;
+ }
+
+ sock_platform = std::make_unique<TCPSocket>(
+ /*should_close=*/true, /*child_processes_inherit=*/false);
+ error = sock_platform->Listen(
+ llvm::formatv("{0}:{1}", hostname, platform_port).str(), backlog);
+ if (error.Fail()) {
+ printf("Failed to listen platform: %s\n", error.AsCString());
+ return socket_error;
+ }
+ if (platform_port == 0)
+ platform_port = sock_platform->GetLocalPortNumber();
+ if (platform_port != 0)
+ socket_id = llvm::to_string(platform_port);
+
+ sock_gdb = std::make_unique<TCPSocket>(/*should_close=*/true,
+ /*child_processes_inherit=*/false);
+ error = sock_gdb->Listen(
+ llvm::formatv("{0}:{1}", hostname, gdbserver_port).str(), backlog);
+ if (error.Fail()) {
+ printf("Failed to listen gdb: %s\n", error.AsCString());
+ return socket_error;
+ }
+ if (gdbserver_port == 0)
+ gdbserver_port = sock_gdb->GetLocalPortNumber();
+ } else {
+ if (g_server) {
+ fprintf(stderr,
+ "Ambiguous parameters --server --listen %s\n"
+ "The protocol must be tcp for the server mode.",
+ listen_host_port.c_str());
+ return socket_error;
+ }
+ sock_named =
+ Socket::Create(protocol, /*child_processes_inherit=*/false, error);
+ if (error.Fail()) {
+ fprintf(stderr, "Failed to create socket: %s", error.AsCString());
+ return socket_error;
+ }
+ error = sock_named->Listen(hostname, backlog);
+ if (error.Fail()) {
+ printf("Failed to listen: %s\n", error.AsCString());
+ return socket_error;
+ }
+ socket_id = hostname;
}
+
if (socket_file) {
- error =
- save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file);
+ error = save_socket_id_to_file(socket_id, socket_file);
if (error.Fail()) {
fprintf(stderr, "failed to write socket id to %s: %s\n",
socket_file.GetPath().c_str(), error.AsCString());
return 1;
}
}
- GDBRemoteCommunicationServerPlatform platform(
- acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme());
+ lldb_private::Args gdb_inferior_arguments(inferior_arguments);
+ GDBRemoteCommunicationServerPlatform platform(protocol, gdbserver_port);
if (port_offset > 0)
platform.SetPortOffset(port_offset);
- do {
- const bool children_inherit_accept_socket = true;
- Connection *conn = nullptr;
- error = acceptor_up->Accept(children_inherit_accept_socket, conn);
- if (error.Fail()) {
- WithColor::error() << error.AsCString() << '\n';
- exit(socket_error);
+ if (protocol == Socket::ProtocolTcp) {
+ llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> platform_handles =
+ sock_platform->Accept(
+ *g_main_loop,
+ [progname, gdbserver_port, port_offset, inferior_arguments,
+ log_file, log_channels](std::unique_ptr<TCPSocket> sock_up) {
+ // If not running as a server, this process will not accept
+ // connections while a connection is active.
+ if (g_server || g_single_pid == LLDB_INVALID_PROCESS_ID) {
+ printf("Platform connection established.\n");
+ Status error = spawn_process(
+ progname, sock_up.get(), gdbserver_port, port_offset,
+ inferior_arguments, log_file, log_channels);
+ if (error.Fail()) {
+ Log *log = GetLog(LLDBLog::Platform);
+ LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString());
+ WithColor::error()
+ << "spawn_process failed: " << error.AsCString() << "\n";
+ if (!g_server) {
+ g_terminate = true;
+ g_main_loop->AddPendingCallback(
+ [](MainLoopBase &loop) { loop.RequestTermination(); });
+ }
+ }
+ }
+ sock_up.reset();
+ });
+ if (!platform_handles) {
+ printf("Failed to accept platform: %s\n",
+ llvm::toString(platform_handles.takeError()).c_str());
+ return socket_error;
}
- printf("Connection established.\n");
- if (g_server) {
- std::optional<uint16_t> available_port;
- {
- std::lock_guard<std::mutex> guard(gdbserver_portmap_mutex);
- auto port = gdbserver_portmap.GetNextAvailablePort();
- if (port)
- available_port = *port;
- else
- llvm::consumeError(port.takeError());
- }
- if (!available_port) {
- fprintf(stderr,
- "no available gdbserver port for connection - dropping...\n");
- } else {
- const Socket *conn_socket =
- static_cast<const Socket *>(conn->GetReadObject().get());
- error =
- spawn_process(progname, conn_socket, *available_port, port_offset,
- inferior_arguments, log_file, log_channels);
- if (error.Fail()) {
- {
-
- std::lock_guard<std::mutex> guard(gdbserver_portmap_mutex);
- gdbserver_portmap.FreePort(*available_port);
- }
- LLDB_LOGF(GetLog(LLDBLog::Platform), "spawn_process failed: %s",
- error.AsCString());
- WithColor::error()
- << "spawn_process failed: " << error.AsCString() << "\n";
- }
- }
- // Parent doesn't need a connection to the lldb client
- delete conn;
-
- // Parent will continue to listen for new connections.
- continue;
- } else {
- // If not running as a server, this process will not accept
- // connections while a connection is active.
- acceptor_up.reset();
-
- // When not running in server mode, use all available ports
- platform.SetPortMap(std::move(gdbserver_portmap));
+ llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> gdb_handles =
+ sock_gdb->Accept(*g_main_loop, [&platform, &gdb_inferior_arguments](
+ std::unique_ptr<TCPSocket> sock_up) {
+ printf("Gdb connection established.\n");
+ Status error;
+ Log *log = GetLog(LLDBLog::Platform);
+ SharedSocket shared_socket(sock_up.get(), error);
+ if (error.Success()) {
+ lldb::pid_t child_pid = LLDB_INVALID_PROCESS_ID;
+ std::string socket_name;
+ error = platform.LaunchGDBServer(gdb_inferior_arguments, child_pid,
+ socket_name,
+ shared_socket.GetSendableFD());
+ if (error.Success() && child_pid != LLDB_INVALID_PROCESS_ID) {
+ error = shared_socket.CompleteSending(child_pid);
+ if (error.Success()) {
+ // Use gdb inferior arguments once.
+ gdb_inferior_arguments.Clear();
+ } else {
+ Host::Kill(child_pid, SIGTERM);
+ LLDB_LOGF(log, "gdbserver CompleteSending failed: %s",
+ error.AsCString());
+ }
+ }
+ } else
+ LLDB_LOGF(log, "gdbserver SharedSocket failed: %s",
+ error.AsCString());
+
+ sock_up.reset();
+ });
+ if (!gdb_handles) {
+ printf("Failed to accept gdb: %s\n",
+ llvm::toString(gdb_handles.takeError()).c_str());
+ return socket_error;
}
- platform.SetConnection(std::unique_ptr<Connection>(conn));
+ do {
+ g_main_loop->Run();
+ } while (!g_terminate);
+
+ gdb_handles->clear();
+ platform_handles->clear();
+
+ g_main_loop.reset();
+ sock_gdb.reset();
+ sock_platform.reset();
+ } else {
+ Socket *conn_up = nullptr;
+ error = sock_named->Accept(conn_up);
----------------
labath wrote:
This is not in the main loop because unix sockets don't have the MainLoop accept function? Could you add one?
https://github.com/llvm/llvm-project/pull/104238
More information about the lldb-commits
mailing list