Skip to content

Commit 1d4949f

Browse files
committed
[lldb] Removed gdbserver ports map from lldb-server
Listen to gdbserver-port, accept the connection and run lldb-server gdbserver --fd on all platforms. Refactored Acceptor to listen on 2 ports in the main thread. Parameters --min-gdbserver-port and --max-gdbserver-port are deprecated now. This is the part 2 of #101283. Fixes #97537, fixes #101475.
1 parent 41f2f1f commit 1d4949f

File tree

21 files changed

+481
-636
lines changed

21 files changed

+481
-636
lines changed

lldb/docs/man/lldb-server.rst

+2-9
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,8 @@ GDB-SERVER CONNECTIONS
147147

148148
.. option:: --gdbserver-port <port>
149149

150-
Define a port to be used for gdb-server connections. Can be specified multiple
151-
times to allow multiple ports. Has no effect if --min-gdbserver-port
152-
and --max-gdbserver-port are specified.
153-
154-
.. option:: --min-gdbserver-port <port>
155-
.. option:: --max-gdbserver-port <port>
156-
157-
Specify the range of ports that can be used for gdb-server connections. Both
158-
options need to be specified simultaneously. Overrides --gdbserver-port.
150+
Define a port to be used for gdb-server connections. This port is used for
151+
multiple connections.
159152

160153
.. option:: --port-offset <offset>
161154

lldb/docs/resources/qemu-testing.rst

+5-14
Original file line numberDiff line numberDiff line change
@@ -149,30 +149,21 @@ to the host (refer to QEMU's manuals for the specific options).
149149
* At least one to connect to the intial ``lldb-server``.
150150
* One more if you want to use ``lldb-server`` in ``platform mode``, and have it
151151
start a ``gdbserver`` instance for you.
152-
* A bunch more if you want to run tests against the ``lldb-server`` platform.
153152

154153
If you are doing either of the latter 2 you should also restrict what ports
155154
``lldb-server tries`` to use, otherwise it will randomly pick one that is almost
156155
certainly not forwarded. An example of this is shown below.
157156

158157
::
159158

160-
$ lldb-server plaform --server --listen 0.0.0.0:54321 \
161-
--min-gdbserver-port 49140 --max-gdbserver-port 49150
159+
$ lldb-server plaform --server --listen 0.0.0.0:54321 --gdbserver-port 49140
162160

163161
The result of this is that:
164162

165163
* ``lldb-server`` platform mode listens externally on port ``54321``.
166164

167-
* When it is asked to start a new gdbserver mode instance, it will use a port
168-
in the range ``49140`` to ``49150``.
165+
* When it is asked to start a new gdbserver mode instance, it will use the port
166+
``49140``.
169167

170-
Your VM configuration should have ports ``54321``, and ``49140`` to ``49150``
171-
forwarded for this to work.
172-
173-
.. note::
174-
These options are used to create a "port map" within ``lldb-server``.
175-
Unfortunately this map is not cleaned up on Windows on connection close,
176-
and across a few uses you may run out of valid ports. To work around this,
177-
restart the platform every so often, especially after running a set of tests.
178-
This is tracked here: https://github.com/llvm/llvm-project/issues/90923
168+
Your VM configuration should have ports ``54321`` and ``49140`` forwarded for
169+
this to work.

lldb/include/lldb/Host/common/TCPSocket.h

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ class TCPSocket : public Socket {
2424
// returns port number or 0 if error
2525
uint16_t GetLocalPortNumber() const;
2626

27+
// returns port numbers of all listening sockets
28+
std::set<uint16_t> GetLocalPortNumbers() const;
29+
2730
// returns ip address string or empty string if error
2831
std::string GetLocalIPAddress() const;
2932

lldb/source/Host/common/TCPSocket.cpp

+71-34
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "lldb/Utility/LLDBLog.h"
1818
#include "lldb/Utility/Log.h"
1919

20+
#include "llvm/ADT/StringExtras.h"
2021
#include "llvm/Config/llvm-config.h"
2122
#include "llvm/Support/Errno.h"
2223
#include "llvm/Support/WindowsError.h"
@@ -94,6 +95,25 @@ uint16_t TCPSocket::GetLocalPortNumber() const {
9495
return 0;
9596
}
9697

98+
// Return all the port numbers that is being used by the socket.
99+
std::set<uint16_t> TCPSocket::GetLocalPortNumbers() const {
100+
std::set<uint16_t> ports;
101+
if (m_socket != kInvalidSocketValue) {
102+
SocketAddress sock_addr;
103+
socklen_t sock_addr_len = sock_addr.GetMaxLength();
104+
if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
105+
ports.insert(sock_addr.GetPort());
106+
} else if (!m_listen_sockets.empty()) {
107+
SocketAddress sock_addr;
108+
socklen_t sock_addr_len = sock_addr.GetMaxLength();
109+
for (auto listen_socket : m_listen_sockets) {
110+
if (::getsockname(listen_socket.first, sock_addr, &sock_addr_len) == 0)
111+
ports.insert(sock_addr.GetPort());
112+
}
113+
}
114+
return ports;
115+
}
116+
97117
std::string TCPSocket::GetLocalIPAddress() const {
98118
// We bound to port zero, so we need to figure out which port we actually
99119
// bound to
@@ -196,49 +216,66 @@ Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
196216
if (!host_port)
197217
return Status(host_port.takeError());
198218

219+
llvm::SmallVector<uint16_t, 2> ports;
220+
ports.push_back(host_port->port);
221+
222+
llvm::SmallVector<llvm::StringRef, 2> extra_ports;
223+
name.split(extra_ports, ',', -1, false);
224+
if (extra_ports.size() > 1) {
225+
for (auto i = extra_ports.begin() + 1; i != extra_ports.end(); ++i) {
226+
uint16_t port;
227+
if (!llvm::to_integer(*i, port, 10))
228+
return Status("invalid extra port number %s", i->str().c_str());
229+
ports.push_back(port);
230+
}
231+
}
232+
199233
if (host_port->hostname == "*")
200234
host_port->hostname = "0.0.0.0";
201235
std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
202236
host_port->hostname.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
203237
for (SocketAddress &address : addresses) {
204-
int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
205-
m_child_processes_inherit, error);
206-
if (error.Fail() || fd < 0)
207-
continue;
208-
209-
// enable local address reuse
210-
int option_value = 1;
211-
set_socket_option_arg_type option_value_p =
212-
reinterpret_cast<set_socket_option_arg_type>(&option_value);
213-
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
214-
sizeof(option_value)) == -1) {
215-
CLOSE_SOCKET(fd);
216-
continue;
217-
}
218-
219-
SocketAddress listen_address = address;
220-
if(!listen_address.IsLocalhost())
221-
listen_address.SetToAnyAddress(address.GetFamily(), host_port->port);
222-
else
223-
listen_address.SetPort(host_port->port);
238+
for (size_t i = 0; i < ports.size(); ++i) {
239+
int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
240+
m_child_processes_inherit, error);
241+
if (error.Fail() || fd < 0)
242+
continue;
243+
244+
// enable local address reuse
245+
int option_value = 1;
246+
set_socket_option_arg_type option_value_p =
247+
reinterpret_cast<set_socket_option_arg_type>(&option_value);
248+
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
249+
sizeof(option_value)) == -1) {
250+
CLOSE_SOCKET(fd);
251+
continue;
252+
}
224253

225-
int err =
226-
::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
227-
if (err != -1)
228-
err = ::listen(fd, backlog);
254+
SocketAddress listen_address = address;
255+
if (!listen_address.IsLocalhost())
256+
listen_address.SetToAnyAddress(address.GetFamily(), ports[i]);
257+
else
258+
listen_address.SetPort(ports[i]);
259+
260+
int err =
261+
::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
262+
if (err != -1)
263+
err = ::listen(fd, backlog);
264+
265+
if (err == -1) {
266+
error = GetLastSocketError();
267+
CLOSE_SOCKET(fd);
268+
continue;
269+
}
229270

230-
if (err == -1) {
231-
error = GetLastSocketError();
232-
CLOSE_SOCKET(fd);
233-
continue;
234-
}
271+
if (ports[i] == 0) {
272+
socklen_t sa_len = address.GetLength();
273+
if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
274+
ports[i] = address.GetPort();
275+
}
235276

236-
if (host_port->port == 0) {
237-
socklen_t sa_len = address.GetLength();
238-
if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
239-
host_port->port = address.GetPort();
277+
m_listen_sockets[fd] = address;
240278
}
241-
m_listen_sockets[fd] = address;
242279
}
243280

244281
if (m_listen_sockets.empty()) {

lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp

+20-2
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,10 @@ ConnectionFileDescriptor::Connect(llvm::StringRef path,
162162
.Case("unix-connect", &ConnectionFileDescriptor::ConnectNamedSocket)
163163
.Case("unix-abstract-connect",
164164
&ConnectionFileDescriptor::ConnectAbstractSocket)
165-
#if LLDB_ENABLE_POSIX
165+
#if LLDB_ENABLE_POSIX || defined(_WIN32)
166166
.Case("fd", &ConnectionFileDescriptor::ConnectFD)
167+
#endif
168+
#if LLDB_ENABLE_POSIX
167169
.Case("file", &ConnectionFileDescriptor::ConnectFile)
168170
.Case("serial", &ConnectionFileDescriptor::ConnectSerialPort)
169171
#endif
@@ -666,7 +668,23 @@ ConnectionStatus
666668
ConnectionFileDescriptor::ConnectFD(llvm::StringRef s,
667669
socket_id_callback_type socket_id_callback,
668670
Status *error_ptr) {
669-
#if LLDB_ENABLE_POSIX
671+
#ifdef _WIN32
672+
int64_t fd = -1;
673+
if (!s.getAsInteger(0, fd)) {
674+
// Assume we own fd.
675+
std::unique_ptr<TCPSocket> tcp_socket =
676+
std::make_unique<TCPSocket>((NativeSocket)fd, true, false);
677+
m_io_sp = std::move(tcp_socket);
678+
m_uri = s.str();
679+
return eConnectionStatusSuccess;
680+
}
681+
682+
if (error_ptr)
683+
error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"",
684+
s.str().c_str());
685+
m_io_sp.reset();
686+
return eConnectionStatusError;
687+
#elif LLDB_ENABLE_POSIX
670688
// Just passing a native file descriptor within this current process that
671689
// is already opened (possibly from a service or other source).
672690
int fd = -1;

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp

+25-18
Original file line numberDiff line numberDiff line change
@@ -879,20 +879,12 @@ lldb::thread_result_t GDBRemoteCommunication::ListenThread() {
879879
return {};
880880
}
881881

882-
Status GDBRemoteCommunication::StartDebugserverProcess(
883-
const char *url, Platform *platform, ProcessLaunchInfo &launch_info,
884-
uint16_t *port, const Args *inferior_args, int pass_comm_fd) {
882+
bool GDBRemoteCommunication::GetDebugserverPath(
883+
Platform *platform, FileSpec &debugserver_file_spec) {
885884
Log *log = GetLog(GDBRLog::Process);
886-
LLDB_LOGF(log, "GDBRemoteCommunication::%s(url=%s, port=%" PRIu16 ")",
887-
__FUNCTION__, url ? url : "<empty>", port ? *port : uint16_t(0));
888-
889-
Status error;
890885
// If we locate debugserver, keep that located version around
891886
static FileSpec g_debugserver_file_spec;
892887

893-
char debugserver_path[PATH_MAX];
894-
FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
895-
896888
Environment host_env = Host::GetEnvironment();
897889

898890
// Always check to see if we have an environment override for the path to the
@@ -943,8 +935,20 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
943935
}
944936
}
945937
}
938+
return debugserver_exists;
939+
}
946940

947-
if (debugserver_exists) {
941+
Status GDBRemoteCommunication::StartDebugserverProcess(
942+
const char *url, Platform *platform, ProcessLaunchInfo &launch_info,
943+
uint16_t *port, const Args *inferior_args, shared_fd_t pass_comm_fd) {
944+
Log *log = GetLog(GDBRLog::Process);
945+
LLDB_LOGF(log, "GDBRemoteCommunication::%s(url=%s, port=%" PRIu16 ")",
946+
__FUNCTION__, url ? url : "<empty>", port ? *port : uint16_t(0));
947+
948+
Status error;
949+
FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
950+
if (GetDebugserverPath(platform, debugserver_file_spec)) {
951+
char debugserver_path[PATH_MAX];
948952
debugserver_file_spec.GetPath(debugserver_path, sizeof(debugserver_path));
949953

950954
Args &debugserver_args = launch_info.GetArguments();
@@ -959,16 +963,17 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
959963
#endif
960964

961965
// If a url is supplied then use it
962-
if (url)
966+
if (url && url[0])
963967
debugserver_args.AppendArgument(llvm::StringRef(url));
964968

965-
if (pass_comm_fd >= 0) {
969+
if (pass_comm_fd != SharedSocket::kInvalidFD) {
966970
StreamString fd_arg;
967-
fd_arg.Printf("--fd=%i", pass_comm_fd);
971+
fd_arg.Printf("--fd=%" PRIi64, (int64_t)pass_comm_fd);
968972
debugserver_args.AppendArgument(fd_arg.GetString());
969973
// Send "pass_comm_fd" down to the inferior so it can use it to
970-
// communicate back with this process
971-
launch_info.AppendDuplicateFileAction(pass_comm_fd, pass_comm_fd);
974+
// communicate back with this process. Ignored on Windows.
975+
launch_info.AppendDuplicateFileAction((int)pass_comm_fd,
976+
(int)pass_comm_fd);
972977
}
973978

974979
// use native registers, not the GDB registers
@@ -988,7 +993,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
988993
// port is null when debug server should listen on domain socket - we're
989994
// not interested in port value but rather waiting for debug server to
990995
// become available.
991-
if (pass_comm_fd == -1) {
996+
if (pass_comm_fd == SharedSocket::kInvalidFD) {
992997
if (url) {
993998
// Create a temporary file to get the stdout/stderr and redirect the output of
994999
// the command into this file. We will later read this file if all goes well
@@ -1059,6 +1064,8 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
10591064
}
10601065
}
10611066
}
1067+
1068+
Environment host_env = Host::GetEnvironment();
10621069
std::string env_debugserver_log_file =
10631070
host_env.lookup("LLDB_DEBUGSERVER_LOG_FILE");
10641071
if (!env_debugserver_log_file.empty()) {
@@ -1132,7 +1139,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
11321139

11331140
if (error.Success() &&
11341141
(launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) &&
1135-
pass_comm_fd == -1) {
1142+
pass_comm_fd == SharedSocket::kInvalidFD) {
11361143
if (named_pipe_path.size() > 0) {
11371144
error = socket_pipe.OpenAsReader(named_pipe_path, false);
11381145
if (error.Fail())

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "lldb/Core/Communication.h"
2222
#include "lldb/Host/Config.h"
2323
#include "lldb/Host/HostThread.h"
24+
#include "lldb/Host/Socket.h"
2425
#include "lldb/Utility/Args.h"
2526
#include "lldb/Utility/Listener.h"
2627
#include "lldb/Utility/Predicate.h"
@@ -146,15 +147,18 @@ class GDBRemoteCommunication : public Communication {
146147

147148
std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; }
148149

150+
// Get the debugserver path and check that it exist.
151+
bool GetDebugserverPath(Platform *platform, FileSpec &debugserver_file_spec);
152+
149153
// Start a debugserver instance on the current host using the
150154
// supplied connection URL.
151155
Status StartDebugserverProcess(
152156
const char *url,
153157
Platform *platform, // If non nullptr, then check with the platform for
154158
// the GDB server binary if it can't be located
155159
ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args,
156-
int pass_comm_fd); // Communication file descriptor to pass during
157-
// fork/exec to avoid having to connect/accept
160+
shared_fd_t pass_comm_fd); // Communication file descriptor to pass during
161+
// fork/exec to avoid having to connect/accept
158162

159163
void DumpHistory(Stream &strm);
160164

0 commit comments

Comments
 (0)