Skip to content

Commit

Permalink
Support IPv6
Browse files Browse the repository at this point in the history
This includes support for specifying IPv6 addresses (and actual hostnames) in --dbghost.
It also supports falling back to IPv6 when IPv4 is disabled.
We produce the correct command lines for gdb and lldb depending on which protocol is in use.
  • Loading branch information
rocallahan committed May 11, 2024
1 parent d2e03fd commit 25063eb
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 61 deletions.
19 changes: 7 additions & 12 deletions src/GdbServer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ const int DIVERSION_SAVED_REGISTER_STATE = 1;

GdbServer::ConnectionFlags::ConnectionFlags()
: dbg_port(-1),
dbg_host(localhost_addr),
keep_listening(false),
serve_files(false),
debugger_params_write_pipe(nullptr) {}
Expand Down Expand Up @@ -1778,12 +1777,6 @@ void GdbServer::restart_session(const GdbRequest& req) {
activate_debugger();
}

struct DebuggerParams {
char exe_image[PATH_MAX];
char host[16]; // INET_ADDRSTRLEN, omitted for header churn
short port;
};

void GdbServer::serve_replay(std::shared_ptr<ReplaySession> session,
const Target& target,
volatile bool* stop_replaying_to_target,
Expand All @@ -1807,20 +1800,22 @@ void GdbServer::serve_replay(std::shared_ptr<ReplaySession> session,
// place). So fail with a clearer error message.
auto probe = flags.dbg_port > 0 ? DONT_PROBE : PROBE_PORT;
Task* t = timeline.current_session().current_task();
ScopedFd listen_fd = open_socket(flags.dbg_host.c_str(), &port, probe);
OpenedSocket listen_socket = open_socket(flags.dbg_host, port, probe);
if (flags.debugger_params_write_pipe) {
DebuggerParams params;
memset(&params, 0, sizeof(params));
strncpy(params.exe_image, t->vm()->exe_image().c_str(),
sizeof(params.exe_image) - 1);
strncpy(params.host, flags.dbg_host.c_str(), sizeof(params.host) - 1);
params.port = port;
params.socket_domain = listen_socket.domain;
strncpy(params.host, listen_socket.host.c_str(), sizeof(params.host) - 1);
params.port = listen_socket.port;

ssize_t nwritten =
write(*flags.debugger_params_write_pipe, &params, sizeof(params));
DEBUG_ASSERT(nwritten == sizeof(params));
} else {
vector<string> cmd = debugger_launch_command(t, flags.dbg_host, port,
vector<string> cmd = debugger_launch_command(t, listen_socket.domain,
listen_socket.host, listen_socket.port,
flags.serve_files, flags.debugger_name);
fprintf(stderr, "Launch debugger with\n %s\n", to_shell_string(cmd).c_str());
}
Expand All @@ -1837,7 +1832,7 @@ void GdbServer::serve_replay(std::shared_ptr<ReplaySession> session,

do {
LOG(debug) << "initializing debugger connection";
auto connection = GdbServerConnection::await_connection(t, listen_fd);
auto connection = GdbServerConnection::await_connection(t, listen_socket.fd);

GdbServer server(connection, timeline.current_session().current_task(),
&timeline, target);
Expand Down
1 change: 0 additions & 1 deletion src/ReplayCommand.cc
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ struct ReplayFlags {
process_created_how(CREATED_NONE),
dont_launch_debugger(false),
dbg_port(-1),
dbg_host(localhost_addr),
keep_listening(false),
gdb_binary_file_path("gdb"),
redirect(true),
Expand Down
66 changes: 42 additions & 24 deletions src/launch_debugger.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>

#include <limits.h>
#include <memory>
Expand Down Expand Up @@ -151,12 +152,6 @@ static const string& lldb_rr_macros() {
return s;
}

struct DebuggerParams {
char exe_image[PATH_MAX];
char host[16]; // INET_ADDRSTRLEN, omitted for header churn
short port;
};

static void push_default_gdb_options(vector<string>& vec, bool serve_files) {
// The gdb protocol uses the "vRun" packet to reload
// remote targets. The packet is specified to be like
Expand Down Expand Up @@ -187,27 +182,48 @@ static void push_default_gdb_options(vector<string>& vec, bool serve_files) {
}
}

static void push_gdb_target_remote_cmd(vector<string>& vec, const string& host,
static void push_gdb_target_remote_cmd(vector<string>& vec, int socket_domain,
const string& host,
unsigned short port) {
vec.push_back("-ex");
stringstream ss;
// If we omit the address, then gdb can try to resolve "localhost" which
// in some broken environments may not actually resolve to the local host
ss << "target extended-remote " << host << ":" << port;
switch (socket_domain) {
case AF_INET:
// If we omit the address, then gdb can try to resolve "localhost" which
// in some broken environments may not actually resolve to the local host
ss << "target extended-remote " << host << ":" << port;
break;
case AF_INET6:
ss << "target extended-remote tcp6:[" << host << "]:" << port;
break;
default:
FATAL() << "Unknown socket domain " << socket_domain;
break;
}
vec.push_back(ss.str());
}

static void push_lldb_target_remote_cmd(vector<string>& vec, const string& host,
static void push_lldb_target_remote_cmd(vector<string>& vec, int socket_domain,
const string& host,
unsigned short port) {
vec.push_back("-o");
stringstream ss;
ss << "gdb-remote " << host << ":" << port;
switch (socket_domain) {
case AF_INET:
case AF_INET6:
ss << "gdb-remote [" << host << "]:" << port;
break;
default:
FATAL() << "Unknown socket domain " << socket_domain;
break;
}
vec.push_back(ss.str());
}

string saved_debugger_launch_command;

vector<string> debugger_launch_command(Task* t, const string& host,
vector<string> debugger_launch_command(Task* t, int socket_domain,
const string& host,
unsigned short port,
bool serve_files,
const string& debugger_name) {
Expand All @@ -216,11 +232,11 @@ vector<string> debugger_launch_command(Task* t, const string& host,
switch (identify_debugger(debugger_name)) {
case DebuggerType::GDB:
push_default_gdb_options(cmd, serve_files);
push_gdb_target_remote_cmd(cmd, host, port);
push_gdb_target_remote_cmd(cmd, socket_domain, host, port);
break;
case DebuggerType::LLDB:
cmd.push_back("--source-quietly");
push_lldb_target_remote_cmd(cmd, host, port);
push_lldb_target_remote_cmd(cmd, socket_domain, host, port);
break;
default:
FATAL() << "Unknown debugger type";
Expand Down Expand Up @@ -283,7 +299,8 @@ void launch_debugger(ScopedFd& params_pipe_fd,
}
DEBUG_ASSERT(nread == sizeof(params));

string host(params.host);
const string& host(params.host);
int socket_domain(params.socket_domain);
uint16_t port(params.port);

vector<string> cmd;
Expand All @@ -301,13 +318,13 @@ void launch_debugger(ScopedFd& params_pipe_fd,
for (size_t i = 0; i < options.size(); ++i) {
if (!did_set_remote && options[i] == "-ex" &&
i + 1 < options.size() && needs_target(options[i + 1])) {
push_gdb_target_remote_cmd(cmd, host, port);
push_gdb_target_remote_cmd(cmd, socket_domain, host, port);
did_set_remote = true;
}
cmd.push_back(options[i]);
}
if (!did_set_remote) {
push_gdb_target_remote_cmd(cmd, host, port);
push_gdb_target_remote_cmd(cmd, socket_domain, host, port);
}

env.push_back("GDB_UNDER_RR=1");
Expand All @@ -319,7 +336,7 @@ void launch_debugger(ScopedFd& params_pipe_fd,
cmd.push_back("--source-before-file");
cmd.push_back(lldb_command_file);
cmd.insert(cmd.end(), options.begin(), options.end());
push_lldb_target_remote_cmd(cmd, host, port);
push_lldb_target_remote_cmd(cmd, socket_domain, host, port);
env.push_back("LLDB_UNDER_RR=1");
break;
}
Expand Down Expand Up @@ -356,8 +373,7 @@ void emergency_debug(Task* t) {
// b) some gdb versions will fail if the user doesn't turn off async
// mode (and we don't want to require users to do that)
features.reverse_execution = false;
unsigned short port = t->tid;
ScopedFd listen_fd = open_socket(localhost_addr, &port, PROBE_PORT);
OpenedSocket listen_socket = open_socket(string(), t->tid, PROBE_PORT);

dump_rr_stack();

Expand All @@ -369,17 +385,19 @@ void emergency_debug(Task* t) {
FILE* gdb_cmd = fopen("gdb_cmd", "w");
if (gdb_cmd) {
fputs(to_shell_string(
debugger_launch_command(t, localhost_addr, port, false, "gdb")).c_str(), gdb_cmd);
debugger_launch_command(t, listen_socket.domain,
listen_socket.host, listen_socket.port, false, "gdb")).c_str(), gdb_cmd);
fclose(gdb_cmd);
}
kill(pid, SIGURG);
} else {
vector<string> cmd = debugger_launch_command(t, localhost_addr, port,
vector<string> cmd = debugger_launch_command(t,
listen_socket.domain, listen_socket.host, listen_socket.port,
false, "gdb");
fprintf(stderr, "Launch debugger with\n %s\n", to_shell_string(cmd).c_str());
}
unique_ptr<GdbServerConnection> dbg =
GdbServerConnection::await_connection(t, listen_fd, features);
GdbServerConnection::await_connection(t, listen_socket.fd, features);
GdbServer::serve_emergency_debugger(std::move(dbg), t);
}

Expand Down
12 changes: 11 additions & 1 deletion src/launch_debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#ifndef RR_LAUNCH_DEBUGGER_H_
#define RR_LAUNCH_DEBUGGER_H_

#include <limits.h>

#include <string>
#include <vector>

Expand All @@ -11,6 +13,13 @@

namespace rr {

struct DebuggerParams {
char exe_image[PATH_MAX];
int socket_domain;
char host[128];
short port;
};

/**
* exec()'s the debuger using parameters read from params_pipe_fd.
*/
Expand All @@ -20,7 +29,8 @@ void launch_debugger(ScopedFd& params_pipe_fd, const std::string& debugger_file_
/**
* Produces the command line needed to launch the debugger.
*/
std::vector<std::string> debugger_launch_command(Task* t, const std::string& host,
std::vector<std::string> debugger_launch_command(Task* t, int socket_domain,
const std::string& host,
unsigned short port,
bool serve_files,
const std::string& debugger_name);
Expand Down
Loading

0 comments on commit 25063eb

Please sign in to comment.