Skip to content

Commit

Permalink
gdbstub/linux-user: support debugging over a unix socket
Browse files Browse the repository at this point in the history
While debugging over TCP is fairly straightforward now we have test
cases that want to orchestrate via make and currently a parallel build
fails as two processes can't use the same listening port. While system
emulation offers a wide cornucopia of connection methods thanks to the
chardev abstraction we are a little more limited for linux user.
Thankfully the programming API for a TCP socket and a local UNIX
socket is pretty much the same once it's set up.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20200430190122.4592-7-alex.bennee@linaro.org>
  • Loading branch information
stsquad committed May 6, 2020
1 parent e0a1e20 commit fcedd92
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 31 deletions.
8 changes: 4 additions & 4 deletions bsd-user/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ int main(int argc, char **argv)
CPUState *cpu;
int optind;
const char *r;
int gdbstub_port = 0;
const char *gdbstub = NULL;
char **target_environ, **wrk;
envlist_t *envlist = NULL;
char *trace_file = NULL;
Expand Down Expand Up @@ -814,7 +814,7 @@ int main(int argc, char **argv)
exit(1);
}
} else if (!strcmp(r, "g")) {
gdbstub_port = atoi(argv[optind++]);
gdbstub = g_strdup(argv[optind++]);
} else if (!strcmp(r, "r")) {
qemu_uname_release = argv[optind++];
} else if (!strcmp(r, "cpu")) {
Expand Down Expand Up @@ -1124,8 +1124,8 @@ int main(int argc, char **argv)
#error unsupported target CPU
#endif

if (gdbstub_port) {
gdbserver_start (gdbstub_port);
if (gdbstub) {
gdbserver_start(gdbstub);
gdb_handlesig(cpu, 0);
}
cpu_loop(env);
Expand Down
103 changes: 87 additions & 16 deletions gdbstub.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ typedef struct GDBState {
int signal;
#ifdef CONFIG_USER_ONLY
int fd;
char *socket_path;
int running_state;
#else
CharBackend chr;
Expand Down Expand Up @@ -2962,6 +2963,9 @@ void gdb_exit(CPUArchState *env, int code)
return;
}
#ifdef CONFIG_USER_ONLY
if (gdbserver_state.socket_path) {
unlink(gdbserver_state.socket_path);
}
if (gdbserver_state.fd < 0) {
return;
}
Expand Down Expand Up @@ -3066,7 +3070,66 @@ void gdb_signalled(CPUArchState *env, int sig)
put_packet(buf);
}

static bool gdb_accept(int gdb_fd)
static void gdb_accept_init(int fd)
{
init_gdbserver_state();
create_default_process(&gdbserver_state);
gdbserver_state.processes[0].attached = true;
gdbserver_state.c_cpu = gdb_first_attached_cpu();
gdbserver_state.g_cpu = gdbserver_state.c_cpu;
gdbserver_state.fd = fd;
gdb_has_xml = false;
}

static bool gdb_accept_socket(int gdb_fd)
{
int fd;

for(;;) {
fd = accept(gdb_fd, NULL, NULL);
if (fd < 0 && errno != EINTR) {
perror("accept socket");
return false;
} else if (fd >= 0) {
qemu_set_cloexec(fd);
break;
}
}

gdb_accept_init(fd);
return true;
}

static int gdbserver_open_socket(const char *path)
{
struct sockaddr_un sockaddr;
int fd, ret;

fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
perror("create socket");
return -1;
}

sockaddr.sun_family = AF_UNIX;
pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path);
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
if (ret < 0) {
perror("bind socket");
close(fd);
return -1;
}
ret = listen(fd, 1);
if (ret < 0) {
perror("listen socket");
close(fd);
return -1;
}

return fd;
}

static bool gdb_accept_tcp(int gdb_fd)
{
struct sockaddr_in sockaddr;
socklen_t len;
Expand All @@ -3091,17 +3154,11 @@ static bool gdb_accept(int gdb_fd)
return false;
}

init_gdbserver_state();
create_default_process(&gdbserver_state);
gdbserver_state.processes[0].attached = true;
gdbserver_state.c_cpu = gdb_first_attached_cpu();
gdbserver_state.g_cpu = gdbserver_state.c_cpu;
gdbserver_state.fd = fd;
gdb_has_xml = false;
gdb_accept_init(fd);
return true;
}

static int gdbserver_open(int port)
static int gdbserver_open_port(int port)
{
struct sockaddr_in sockaddr;
int fd, ret;
Expand Down Expand Up @@ -3130,21 +3187,35 @@ static int gdbserver_open(int port)
close(fd);
return -1;
}

return fd;
}

int gdbserver_start(int port)
int gdbserver_start(const char *port_or_path)
{
int gdb_fd = gdbserver_open(port);
int port = g_ascii_strtoull(port_or_path, NULL, 10);
int gdb_fd;

if (port > 0) {
gdb_fd = gdbserver_open_port(port);
} else {
gdb_fd = gdbserver_open_socket(port_or_path);
}

if (gdb_fd < 0) {
return -1;
}
/* accept connections */
if (!gdb_accept(gdb_fd)) {
close(gdb_fd);
return -1;

if (port > 0 && gdb_accept_tcp(gdb_fd)) {
return 0;
} else if (gdb_accept_socket(gdb_fd)) {
gdbserver_state.socket_path = g_strdup(port_or_path);
return 0;
}
return 0;

/* gone wrong */
close(gdb_fd);
return -1;
}

/* Disable gdb stub for child processes. */
Expand Down
14 changes: 9 additions & 5 deletions include/exec/gdbstub.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,15 @@ static inline uint8_t * gdb_get_reg_ptr(GByteArray *buf, int len)

#endif

#ifdef CONFIG_USER_ONLY
int gdbserver_start(int);
#else
int gdbserver_start(const char *port);
#endif
/**
* gdbserver_start: start the gdb server
* @port_or_device: connection spec for gdb
*
* For CONFIG_USER this is either a tcp port or a path to a fifo. For
* system emulation you can use a full chardev spec for your gdbserver
* port.
*/
int gdbserver_start(const char *port_or_device);

void gdbserver_cleanup(void);

Expand Down
12 changes: 6 additions & 6 deletions linux-user/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ char *exec_path;

int singlestep;
static const char *argv0;
static int gdbstub_port;
static const char *gdbstub;
static envlist_t *envlist;
static const char *cpu_model;
static const char *cpu_type;
Expand Down Expand Up @@ -310,7 +310,7 @@ static void handle_arg_seed(const char *arg)

static void handle_arg_gdb(const char *arg)
{
gdbstub_port = atoi(arg);
gdbstub = g_strdup(arg);
}

static void handle_arg_uname(const char *arg)
Expand Down Expand Up @@ -861,10 +861,10 @@ int main(int argc, char **argv, char **envp)

target_cpu_copy_regs(env, regs);

if (gdbstub_port) {
if (gdbserver_start(gdbstub_port) < 0) {
fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
gdbstub_port);
if (gdbstub) {
if (gdbserver_start(gdbstub) < 0) {
fprintf(stderr, "qemu: could not open gdbserver on %s\n",
gdbstub);
exit(EXIT_FAILURE);
}
gdb_handlesig(cpu, 0);
Expand Down

0 comments on commit fcedd92

Please sign in to comment.