Skip to content

Commit 0512d11

Browse files
authored
[lldb] Clean up GDBRemoteCommunication::StartDebugserverProcess (#145021)
The function was extremely messy in that it, depending on the set of arguments, it could either modify the Connection object in `this` or not. It had a lot of arguments, with each call site passing a different combination of null values. This PR: - packs "url" and "comm_fd" arguments into a variant as they are mutually exclusive - removes the (surprising) "null url *and* null comm_fd" code path which is not used as of #145017 - marks the function as `static` to make it clear it (now) does not operate on the `this` object. Depends on #145017
1 parent 888f84f commit 0512d11

File tree

4 files changed

+78
-137
lines changed

4 files changed

+78
-137
lines changed

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

Lines changed: 56 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <climits>
3232
#include <cstring>
3333
#include <sys/stat.h>
34+
#include <variant>
3435

3536
#if defined(__APPLE__)
3637
#define DEBUGSERVER_BASENAME "debugserver"
@@ -894,11 +895,9 @@ FileSpec GDBRemoteCommunication::GetDebugserverPath(Platform *platform) {
894895
}
895896

896897
Status GDBRemoteCommunication::StartDebugserverProcess(
897-
const char *url, Platform *platform, ProcessLaunchInfo &launch_info,
898-
uint16_t *port, const Args *inferior_args, shared_fd_t pass_comm_fd) {
898+
std::variant<llvm::StringRef, shared_fd_t> comm, Platform *platform,
899+
ProcessLaunchInfo &launch_info, const Args *inferior_args) {
899900
Log *log = GetLog(GDBRLog::Process);
900-
LLDB_LOG(log, "Starting debug server: url={0}, port={1}",
901-
url ? url : "<empty>", port ? *port : uint16_t(0));
902901

903902
FileSpec debugserver_file_spec = GetDebugserverPath(platform);
904903
if (!debugserver_file_spec)
@@ -911,89 +910,58 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
911910

912911
#if !defined(__APPLE__)
913912
// First argument to lldb-server must be mode in which to run.
914-
debugserver_args.AppendArgument(llvm::StringRef("gdbserver"));
913+
debugserver_args.AppendArgument("gdbserver");
915914
#endif
916915

917-
// If a url is supplied then use it
918-
if (url && url[0])
919-
debugserver_args.AppendArgument(llvm::StringRef(url));
920-
921-
if (pass_comm_fd != SharedSocket::kInvalidFD) {
922-
StreamString fd_arg;
923-
fd_arg.Printf("--fd=%" PRIi64, (int64_t)pass_comm_fd);
924-
debugserver_args.AppendArgument(fd_arg.GetString());
925-
// Send "pass_comm_fd" down to the inferior so it can use it to
926-
// communicate back with this process. Ignored on Windows.
927-
launch_info.AppendDuplicateFileAction((int64_t)pass_comm_fd,
928-
(int64_t)pass_comm_fd);
929-
}
930-
931916
// use native registers, not the GDB registers
932-
debugserver_args.AppendArgument(llvm::StringRef("--native-regs"));
917+
debugserver_args.AppendArgument("--native-regs");
933918

934919
if (launch_info.GetLaunchInSeparateProcessGroup())
935-
debugserver_args.AppendArgument(llvm::StringRef("--setsid"));
920+
debugserver_args.AppendArgument("--setsid");
936921

937922
llvm::SmallString<128> named_pipe_path;
938923
// socket_pipe is used by debug server to communicate back either
939-
// TCP port or domain socket name which it listens on.
940-
// The second purpose of the pipe to serve as a synchronization point -
924+
// TCP port or domain socket name which it listens on. However, we're not
925+
// interested in the actualy value here.
926+
// The only reason for using the pipe is to serve as a synchronization point -
941927
// once data is written to the pipe, debug server is up and running.
942928
Pipe socket_pipe;
943929

944-
std::unique_ptr<TCPSocket> sock_up;
930+
// If a url is supplied then use it
931+
if (shared_fd_t *comm_fd = std::get_if<shared_fd_t>(&comm)) {
932+
LLDB_LOG(log, "debugserver communicates over fd {0}", comm_fd);
933+
assert(*comm_fd != SharedSocket::kInvalidFD);
934+
debugserver_args.AppendArgument(llvm::formatv("--fd={0}", *comm_fd).str());
935+
// Send "comm_fd" down to the inferior so it can use it to communicate back
936+
// with this process.
937+
launch_info.AppendDuplicateFileAction((int64_t)*comm_fd, (int64_t)*comm_fd);
938+
} else {
939+
llvm::StringRef url = std::get<llvm::StringRef>(comm);
940+
LLDB_LOG(log, "debugserver listens on: {0}", url);
941+
debugserver_args.AppendArgument(url);
945942

946-
// port is null when debug server should listen on domain socket - we're
947-
// not interested in port value but rather waiting for debug server to
948-
// become available.
949-
if (pass_comm_fd == SharedSocket::kInvalidFD) {
950-
if (url) {
951-
// Create a temporary file to get the stdout/stderr and redirect the output of
952-
// the command into this file. We will later read this file if all goes well
953-
// and fill the data into "command_output_ptr"
954943
#if defined(__APPLE__)
955-
// Binding to port zero, we need to figure out what port it ends up
956-
// using using a named pipe...
957-
Status error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe",
958-
false, named_pipe_path);
959-
if (error.Fail()) {
960-
LLDB_LOG(log, "named pipe creation failed: {0}", error);
961-
return error;
962-
}
963-
debugserver_args.AppendArgument(llvm::StringRef("--named-pipe"));
964-
debugserver_args.AppendArgument(named_pipe_path);
944+
// Using a named pipe as debugserver does not support --pipe.
945+
Status error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe",
946+
false, named_pipe_path);
947+
if (error.Fail()) {
948+
LLDB_LOG(log, "named pipe creation failed: {0}", error);
949+
return error;
950+
}
951+
debugserver_args.AppendArgument(llvm::StringRef("--named-pipe"));
952+
debugserver_args.AppendArgument(named_pipe_path);
965953
#else
966-
// Binding to port zero, we need to figure out what port it ends up
967-
// using using an unnamed pipe...
968-
Status error = socket_pipe.CreateNew(true);
969-
if (error.Fail()) {
970-
LLDB_LOG(log, "unnamed pipe creation failed: {0}", error);
971-
return error;
972-
}
973-
pipe_t write = socket_pipe.GetWritePipe();
974-
debugserver_args.AppendArgument(llvm::StringRef("--pipe"));
975-
debugserver_args.AppendArgument(llvm::to_string(write));
976-
launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor());
977-
#endif
978-
} else {
979-
// No host and port given, so lets listen on our end and make the
980-
// debugserver connect to us..
981-
if (llvm::Expected<std::unique_ptr<TCPSocket>> expected_sock =
982-
Socket::TcpListen("127.0.0.1:0"))
983-
sock_up = std::move(*expected_sock);
984-
else
985-
return Status::FromError(expected_sock.takeError());
986-
987-
uint16_t port_ = sock_up->GetLocalPortNumber();
988-
// Send the host and port down that debugserver and specify an option
989-
// so that it connects back to the port we are listening to in this
990-
// process
991-
debugserver_args.AppendArgument(llvm::StringRef("--reverse-connect"));
992-
debugserver_args.AppendArgument(
993-
llvm::formatv("127.0.0.1:{0}", port_).str());
994-
if (port)
995-
*port = port_;
954+
// Using an unnamed pipe as it's simpler.
955+
Status error = socket_pipe.CreateNew(true);
956+
if (error.Fail()) {
957+
LLDB_LOG(log, "unnamed pipe creation failed: {0}", error);
958+
return error;
996959
}
960+
pipe_t write = socket_pipe.GetWritePipe();
961+
debugserver_args.AppendArgument(llvm::StringRef("--pipe"));
962+
debugserver_args.AppendArgument(llvm::to_string(write));
963+
launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor());
964+
#endif
997965
}
998966

999967
Environment host_env = Host::GetEnvironment();
@@ -1070,7 +1038,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
10701038
return error;
10711039
}
10721040

1073-
if (pass_comm_fd != SharedSocket::kInvalidFD)
1041+
if (std::holds_alternative<shared_fd_t>(comm))
10741042
return Status();
10751043

10761044
Status error;
@@ -1084,55 +1052,30 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
10841052

10851053
if (socket_pipe.CanWrite())
10861054
socket_pipe.CloseWriteFileDescriptor();
1087-
if (socket_pipe.CanRead()) {
1088-
// Read port from pipe with 10 second timeout.
1089-
std::string port_str;
1090-
while (error.Success()) {
1091-
char buf[10];
1092-
if (llvm::Expected<size_t> num_bytes =
1093-
socket_pipe.Read(buf, std::size(buf), std::chrono::seconds(10))) {
1094-
if (*num_bytes == 0)
1095-
break;
1096-
port_str.append(buf, *num_bytes);
1097-
} else {
1098-
error = Status::FromError(num_bytes.takeError());
1099-
}
1100-
}
1101-
if (error.Success() && (port != nullptr)) {
1102-
// NB: Deliberately using .c_str() to stop at embedded '\0's
1103-
llvm::StringRef port_ref = port_str.c_str();
1104-
uint16_t child_port = 0;
1105-
// FIXME: improve error handling
1106-
llvm::to_integer(port_ref, child_port);
1107-
if (*port == 0 || *port == child_port) {
1108-
*port = child_port;
1109-
LLDB_LOG(log, "debugserver listens on port {0}", *port);
1110-
} else {
1111-
LLDB_LOG(log,
1112-
"debugserver listening on port {0} but requested port was {1}",
1113-
child_port, (*port));
1114-
}
1055+
assert(socket_pipe.CanRead());
1056+
1057+
// Read data from the pipe -- and ignore it (see comment above).
1058+
while (error.Success()) {
1059+
char buf[10];
1060+
if (llvm::Expected<size_t> num_bytes =
1061+
socket_pipe.Read(buf, std::size(buf), std::chrono::seconds(10))) {
1062+
if (*num_bytes == 0)
1063+
break;
11151064
} else {
1116-
LLDB_LOG(log, "failed to read a port value from pipe {0}: {1}",
1117-
named_pipe_path, error);
1065+
error = Status::FromError(num_bytes.takeError());
11181066
}
1119-
socket_pipe.Close();
11201067
}
1068+
if (error.Fail()) {
1069+
LLDB_LOG(log, "failed to synchronize on pipe {0}: {1}", named_pipe_path,
1070+
error);
1071+
}
1072+
socket_pipe.Close();
11211073

11221074
if (named_pipe_path.size() > 0) {
11231075
if (Status err = socket_pipe.Delete(named_pipe_path); err.Fail())
11241076
LLDB_LOG(log, "failed to delete pipe {0}: {1}", named_pipe_path, err);
11251077
}
11261078

1127-
if (error.Success() && sock_up) {
1128-
Socket *accepted_socket = nullptr;
1129-
error = sock_up->Accept(/*timeout=*/std::nullopt, accepted_socket);
1130-
if (accepted_socket) {
1131-
SetConnection(std::make_unique<ConnectionFileDescriptor>(
1132-
std::unique_ptr<Socket>(accepted_socket)));
1133-
}
1134-
}
1135-
11361079
return error;
11371080
}
11381081

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,17 +135,15 @@ class GDBRemoteCommunication : public Communication {
135135
std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; }
136136

137137
// Get the debugserver path and check that it exist.
138-
FileSpec GetDebugserverPath(Platform *platform);
138+
static FileSpec GetDebugserverPath(Platform *platform);
139139

140140
// Start a debugserver instance on the current host using the
141141
// supplied connection URL.
142-
Status StartDebugserverProcess(
143-
const char *url,
142+
static Status StartDebugserverProcess(
143+
std::variant<llvm::StringRef, shared_fd_t> comm,
144144
Platform *platform, // If non nullptr, then check with the platform for
145145
// the GDB server binary if it can't be located
146-
ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args,
147-
shared_fd_t pass_comm_fd); // Communication file descriptor to pass during
148-
// fork/exec to avoid having to connect/accept
146+
ProcessLaunchInfo &launch_info, const Args *inferior_args);
149147

150148
void DumpHistory(Stream &strm);
151149

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

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,16 @@ GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() =
9494
Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
9595
const lldb_private::Args &args, lldb::pid_t &pid, std::string &socket_name,
9696
shared_fd_t fd) {
97-
std::ostringstream url;
97+
Log *log = GetLog(LLDBLog::Platform);
98+
99+
ProcessLaunchInfo debugserver_launch_info;
100+
// Do not run in a new session so that it can not linger after the platform
101+
// closes.
102+
debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
103+
debugserver_launch_info.SetMonitorProcessCallback(
104+
[](lldb::pid_t, int, int) {});
105+
106+
Status error;
98107
if (fd == SharedSocket::kInvalidFD) {
99108
if (m_socket_protocol == Socket::ProtocolTcp) {
100109
// Just check that GDBServer exists. GDBServer must be launched after
@@ -104,31 +113,22 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
104113
return Status();
105114
}
106115

116+
std::ostringstream url;
107117
// debugserver does not accept the URL scheme prefix.
108118
#if !defined(__APPLE__)
109119
url << Socket::FindSchemeByProtocol(m_socket_protocol) << "://";
110120
#endif
111121
socket_name = GetDomainSocketPath("gdbserver").GetPath();
112122
url << socket_name;
123+
error = StartDebugserverProcess(url.str(), nullptr, debugserver_launch_info,
124+
&args);
113125
} else {
114126
if (m_socket_protocol != Socket::ProtocolTcp)
115127
return Status::FromErrorString("protocol must be tcp");
128+
error =
129+
StartDebugserverProcess(fd, nullptr, debugserver_launch_info, &args);
116130
}
117131

118-
// Spawn a debugserver and try to get the port it listens to.
119-
ProcessLaunchInfo debugserver_launch_info;
120-
Log *log = GetLog(LLDBLog::Platform);
121-
LLDB_LOG(log, "Launching debugserver url='{0}', fd={1}...", url.str(), fd);
122-
123-
// Do not run in a new session so that it can not linger after the platform
124-
// closes.
125-
debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
126-
debugserver_launch_info.SetMonitorProcessCallback(
127-
[](lldb::pid_t, int, int) {});
128-
129-
Status error = StartDebugserverProcess(
130-
url.str().c_str(), nullptr, debugserver_launch_info, nullptr, &args, fd);
131-
132132
if (error.Success()) {
133133
pid = debugserver_launch_info.GetProcessID();
134134
AddSpawnedProcess(pid);

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3494,9 +3494,9 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver(
34943494
if (error.Fail())
34953495
return error;
34963496

3497-
error = m_gdb_comm.StartDebugserverProcess(
3498-
nullptr, GetTarget().GetPlatform().get(), debugserver_launch_info,
3499-
nullptr, nullptr, shared_socket.GetSendableFD());
3497+
error = m_gdb_comm.StartDebugserverProcess(shared_socket.GetSendableFD(),
3498+
GetTarget().GetPlatform().get(),
3499+
debugserver_launch_info, nullptr);
35003500

35013501
if (error.Fail()) {
35023502
Log *log = GetLog(GDBRLog::Process);

0 commit comments

Comments
 (0)