[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();
----------------
labath wrote:
This isn't very c++-y. Could this be arranged so that the natural c++ destructor order destroys things in the right order. Perhaps by creating the mainloop inside this block (which means that the reaping callback would need to get it via an argument)?
https://github.com/llvm/llvm-project/pull/104238
More information about the lldb-commits
mailing list