Skip to content

Commit 5732bda

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. Added acceptor_gdb and gdb_thread to lldb-platform.cpp SharedSocket has been moved to ConnectionFileDescriptorPosix. Parameters --min-gdbserver-port and --max-gdbserver-port are deprecated now. This is the part 2 of #101283. Fixes #97537, fixes #101475.
1 parent d550ada commit 5732bda

17 files changed

+461
-611
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/posix/ConnectionFileDescriptorPosix.h

+26
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,32 @@ class Status;
2626
class Socket;
2727
class SocketAddress;
2828

29+
#ifdef _WIN32
30+
typedef lldb::pipe_t shared_fd_t;
31+
#else
32+
typedef NativeSocket shared_fd_t;
33+
#endif
34+
35+
class SharedSocket {
36+
public:
37+
static const shared_fd_t kInvalidFD;
38+
39+
SharedSocket(Connection *conn, Status &error);
40+
41+
shared_fd_t GetSendableFD() { return m_fd; }
42+
43+
Status CompleteSending(lldb::pid_t child_pid);
44+
45+
static Status GetNativeSocket(shared_fd_t fd, NativeSocket &socket);
46+
47+
private:
48+
#ifdef _WIN32
49+
Pipe m_socket_pipe;
50+
NativeSocket m_socket;
51+
#endif
52+
shared_fd_t m_fd;
53+
};
54+
2955
class ConnectionFileDescriptor : public Connection {
3056
public:
3157
typedef llvm::function_ref<void(llvm::StringRef local_socket_id)>

lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp

+108-2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,94 @@
5252
using namespace lldb;
5353
using namespace lldb_private;
5454

55+
#ifdef _WIN32
56+
const shared_fd_t SharedSocket::kInvalidFD = LLDB_INVALID_PIPE;
57+
#else
58+
const shared_fd_t SharedSocket::kInvalidFD = Socket::kInvalidSocketValue;
59+
#endif
60+
61+
SharedSocket::SharedSocket(Connection *conn, Status &error) {
62+
m_fd = kInvalidFD;
63+
64+
const Socket *socket =
65+
static_cast<const Socket *>(conn->GetReadObject().get());
66+
if (socket == nullptr) {
67+
error = Status("invalid conn socket");
68+
return;
69+
}
70+
71+
#ifdef _WIN32
72+
m_socket = socket->GetNativeSocket();
73+
74+
// Create a pipe to transfer WSAPROTOCOL_INFO to the child process.
75+
error = m_socket_pipe.CreateNew(true);
76+
if (error.Fail())
77+
return;
78+
79+
m_fd = m_socket_pipe.GetReadPipe();
80+
#else
81+
m_fd = socket->GetNativeSocket();
82+
error = Status();
83+
#endif
84+
}
85+
86+
Status SharedSocket::CompleteSending(lldb::pid_t child_pid) {
87+
#ifdef _WIN32
88+
// Transfer WSAPROTOCOL_INFO to the child process.
89+
m_socket_pipe.CloseReadFileDescriptor();
90+
91+
WSAPROTOCOL_INFO protocol_info;
92+
if (::WSADuplicateSocket(m_socket, child_pid, &protocol_info) ==
93+
SOCKET_ERROR) {
94+
int last_error = ::WSAGetLastError();
95+
return Status("WSADuplicateSocket() failed, error: %d", last_error);
96+
}
97+
98+
size_t num_bytes;
99+
Status error =
100+
m_socket_pipe.WriteWithTimeout(&protocol_info, sizeof(protocol_info),
101+
std::chrono::seconds(10), num_bytes);
102+
if (error.Fail())
103+
return error;
104+
if (num_bytes != sizeof(protocol_info))
105+
return Status("WriteWithTimeout(WSAPROTOCOL_INFO) failed: %d bytes",
106+
num_bytes);
107+
#endif
108+
return Status();
109+
}
110+
111+
Status SharedSocket::GetNativeSocket(shared_fd_t fd, NativeSocket &socket) {
112+
#ifdef _WIN32
113+
socket = Socket::kInvalidSocketValue;
114+
// Read WSAPROTOCOL_INFO from the parent process and create NativeSocket.
115+
WSAPROTOCOL_INFO protocol_info;
116+
{
117+
Pipe socket_pipe(fd, LLDB_INVALID_PIPE);
118+
size_t num_bytes;
119+
Status error =
120+
socket_pipe.ReadWithTimeout(&protocol_info, sizeof(protocol_info),
121+
std::chrono::seconds(10), num_bytes);
122+
if (error.Fail())
123+
return error;
124+
if (num_bytes != sizeof(protocol_info)) {
125+
return Status(
126+
"socket_pipe.ReadWithTimeout(WSAPROTOCOL_INFO) failed: % d bytes",
127+
num_bytes);
128+
}
129+
}
130+
socket = ::WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
131+
FROM_PROTOCOL_INFO, &protocol_info, 0, 0);
132+
if (socket == INVALID_SOCKET) {
133+
return Status("WSASocket(FROM_PROTOCOL_INFO) failed: error %d",
134+
::WSAGetLastError());
135+
}
136+
return Status();
137+
#else
138+
socket = fd;
139+
return Status();
140+
#endif
141+
}
142+
55143
ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit)
56144
: Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
57145

@@ -162,8 +250,10 @@ ConnectionFileDescriptor::Connect(llvm::StringRef path,
162250
.Case("unix-connect", &ConnectionFileDescriptor::ConnectNamedSocket)
163251
.Case("unix-abstract-connect",
164252
&ConnectionFileDescriptor::ConnectAbstractSocket)
165-
#if LLDB_ENABLE_POSIX
253+
#if LLDB_ENABLE_POSIX || defined(_WIN32)
166254
.Case("fd", &ConnectionFileDescriptor::ConnectFD)
255+
#endif
256+
#if LLDB_ENABLE_POSIX
167257
.Case("file", &ConnectionFileDescriptor::ConnectFile)
168258
.Case("serial", &ConnectionFileDescriptor::ConnectSerialPort)
169259
#endif
@@ -666,7 +756,23 @@ ConnectionStatus
666756
ConnectionFileDescriptor::ConnectFD(llvm::StringRef s,
667757
socket_id_callback_type socket_id_callback,
668758
Status *error_ptr) {
669-
#if LLDB_ENABLE_POSIX
759+
#ifdef _WIN32
760+
int64_t fd = -1;
761+
if (!s.getAsInteger(0, fd)) {
762+
// Assume we own fd.
763+
std::unique_ptr<TCPSocket> tcp_socket =
764+
std::make_unique<TCPSocket>((NativeSocket)fd, true, false);
765+
m_io_sp = std::move(tcp_socket);
766+
m_uri = s.str();
767+
return eConnectionStatusSuccess;
768+
}
769+
770+
if (error_ptr)
771+
error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"",
772+
s.str().c_str());
773+
m_io_sp.reset();
774+
return eConnectionStatusError;
775+
#elif LLDB_ENABLE_POSIX
670776
// Just passing a native file descriptor within this current process that
671777
// is already opened (possibly from a service or other source).
672778
int fd = -1;

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

+24-17
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();
@@ -962,13 +966,14 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
962966
if (url)
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
@@ -20,6 +20,7 @@
2020

2121
#include "lldb/Core/Communication.h"
2222
#include "lldb/Host/Config.h"
23+
#include "lldb/Host/ConnectionFileDescriptor.h"
2324
#include "lldb/Host/HostThread.h"
2425
#include "lldb/Utility/Args.h"
2526
#include "lldb/Utility/Listener.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)