Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 55 additions & 90 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3447,115 +3447,80 @@ ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) {
}
return error;
}
#if !defined(_WIN32)
#define USE_SOCKETPAIR_FOR_LOCAL_CONNECTION 1
#endif

#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION
static bool SetCloexecFlag(int fd) {
#if defined(FD_CLOEXEC)
int flags = ::fcntl(fd, F_GETFD);
if (flags == -1)
return false;
return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
#else
return false;
#endif
}
#endif

Status ProcessGDBRemote::LaunchAndConnectToDebugserver(
const ProcessInfo &process_info) {
using namespace std::placeholders; // For _1, _2, etc.

Status error;
if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) {
// If we locate debugserver, keep that located version around
static FileSpec g_debugserver_file_spec;
if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
return Status();

ProcessLaunchInfo debugserver_launch_info;
// Make debugserver run in its own session so signals generated by special
// terminal key sequences (^C) don't affect debugserver.
debugserver_launch_info.SetLaunchInSeparateProcessGroup(true);
ProcessLaunchInfo debugserver_launch_info;
// Make debugserver run in its own session so signals generated by special
// terminal key sequences (^C) don't affect debugserver.
debugserver_launch_info.SetLaunchInSeparateProcessGroup(true);

const std::weak_ptr<ProcessGDBRemote> this_wp =
std::static_pointer_cast<ProcessGDBRemote>(shared_from_this());
debugserver_launch_info.SetMonitorProcessCallback(
std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3));
debugserver_launch_info.SetUserID(process_info.GetUserID());
const std::weak_ptr<ProcessGDBRemote> this_wp =
std::static_pointer_cast<ProcessGDBRemote>(shared_from_this());
debugserver_launch_info.SetMonitorProcessCallback(
std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3));
debugserver_launch_info.SetUserID(process_info.GetUserID());

#if defined(__APPLE__)
// On macOS 11, we need to support x86_64 applications translated to
// arm64. We check whether a binary is translated and spawn the correct
// debugserver accordingly.
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
static_cast<int>(process_info.GetProcessID()) };
struct kinfo_proc processInfo;
size_t bufsize = sizeof(processInfo);
if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo,
&bufsize, NULL, 0) == 0 && bufsize > 0) {
if (processInfo.kp_proc.p_flag & P_TRANSLATED) {
FileSpec rosetta_debugserver("/Library/Apple/usr/libexec/oah/debugserver");
debugserver_launch_info.SetExecutableFile(rosetta_debugserver, false);
}
// On macOS 11, we need to support x86_64 applications translated to
// arm64. We check whether a binary is translated and spawn the correct
// debugserver accordingly.
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID,
static_cast<int>(process_info.GetProcessID())};
struct kinfo_proc processInfo;
size_t bufsize = sizeof(processInfo);
if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, &bufsize,
NULL, 0) == 0 &&
bufsize > 0) {
if (processInfo.kp_proc.p_flag & P_TRANSLATED) {
FileSpec rosetta_debugserver(
"/Library/Apple/usr/libexec/oah/debugserver");
debugserver_launch_info.SetExecutableFile(rosetta_debugserver, false);
}
}
#endif

shared_fd_t communication_fd = SharedSocket::kInvalidFD;
#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION
// Use a socketpair on non-Windows systems for security and performance
// reasons.
int sockets[2]; /* the pair of socket descriptors */
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
error = Status::FromErrno();
return error;
}
llvm::Expected<Socket::Pair> socket_pair = Socket::CreatePair();
if (!socket_pair)
return Status::FromError(socket_pair.takeError());

int our_socket = sockets[0];
int gdb_socket = sockets[1];
auto cleanup_our = llvm::make_scope_exit([&]() { close(our_socket); });
auto cleanup_gdb = llvm::make_scope_exit([&]() { close(gdb_socket); });
Status error;
SharedSocket shared_socket(socket_pair->first.get(), error);
if (error.Fail())
return error;

// Don't let any child processes inherit our communication socket
SetCloexecFlag(our_socket);
communication_fd = gdb_socket;
#endif
error = m_gdb_comm.StartDebugserverProcess(
nullptr, GetTarget().GetPlatform().get(), debugserver_launch_info,
nullptr, nullptr, shared_socket.GetSendableFD());

error = m_gdb_comm.StartDebugserverProcess(
nullptr, GetTarget().GetPlatform().get(), debugserver_launch_info,
nullptr, nullptr, communication_fd);
if (error.Fail()) {
Log *log = GetLog(GDBRLog::Process);

if (error.Success())
m_debugserver_pid = debugserver_launch_info.GetProcessID();
else
m_debugserver_pid = LLDB_INVALID_PROCESS_ID;

if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) {
#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION
// Our process spawned correctly, we can now set our connection to use
// our end of the socket pair
cleanup_our.release();
m_gdb_comm.SetConnection(
std::make_unique<ConnectionFileDescriptor>(our_socket, true));
#endif
StartAsyncThread();
}
LLDB_LOGF(log, "failed to start debugserver process: %s",
error.AsCString());
return error;
}

if (error.Fail()) {
Log *log = GetLog(GDBRLog::Process);
m_debugserver_pid = debugserver_launch_info.GetProcessID();
shared_socket.CompleteSending(m_debugserver_pid);

LLDB_LOGF(log, "failed to start debugserver process: %s",
error.AsCString());
return error;
}
// Our process spawned correctly, we can now set our connection to use
// our end of the socket pair
m_gdb_comm.SetConnection(std::make_unique<ConnectionFileDescriptor>(
socket_pair->second.release()));
StartAsyncThread();

if (m_gdb_comm.IsConnected()) {
// Finish the connection process by doing the handshake without
// connecting (send NULL URL)
error = ConnectToDebugserver("");
} else {
error = Status::FromErrorString("connection failed");
}
if (m_gdb_comm.IsConnected()) {
// Finish the connection process by doing the handshake without
// connecting (send NULL URL)
error = ConnectToDebugserver("");
} else {
error = Status::FromErrorString("connection failed");
}
return error;
}
Expand Down
Loading