[Lldb-commits] [lldb] [lldb] Removed gdbserver ports map from lldb-server (PR #104238)

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Thu Sep 5 02:39:18 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:

Yes, I think it'd be better as a preparatory patch. (really, is it that hard? It should be a couple of lines of code. And it would make this patch look much nicer..)

https://github.com/llvm/llvm-project/pull/104238


More information about the lldb-commits mailing list