[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v1 10/14] gdbstub/linux-user: support debugging over a unix socke
From: |
Alex Bennée |
Subject: |
[PATCH v1 10/14] gdbstub/linux-user: support debugging over a unix socket |
Date: |
Thu, 23 Apr 2020 18:05:53 +0100 |
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 <address@hidden>
---
include/exec/gdbstub.h | 14 ++++--
bsd-user/main.c | 8 +--
gdbstub.c | 107 ++++++++++++++++++++++++++++++++++-------
linux-user/main.c | 12 ++---
4 files changed, 108 insertions(+), 33 deletions(-)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 4a2b8e3089..94d8f83e92 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -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);
diff --git a/bsd-user/main.c b/bsd-user/main.c
index aef5531628..0bfe46cff9 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -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;
@@ -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")) {
@@ -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);
diff --git a/gdbstub.c b/gdbstub.c
index 8c53cc0e1c..51e2ab9110 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -355,6 +355,7 @@ typedef struct GDBState {
int signal;
#ifdef CONFIG_USER_ONLY
int fd;
+ char *socket_path;
int running_state;
#else
CharBackend chr;
@@ -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;
}
@@ -3034,7 +3038,6 @@ gdb_handlesig(CPUState *cpu, int sig)
n = read(gdbserver_state.fd, buf, 256);
if (n > 0) {
int i;
-
for (i = 0; i < n; i++) {
gdb_read_byte(buf[i]);
}
@@ -3066,7 +3069,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;
@@ -3091,17 +3153,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;
@@ -3130,20 +3186,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);
- if (gdb_fd < 0)
- return -1;
- /* accept connections */
- if (!gdb_accept(gdb_fd)) {
- close(gdb_fd);
+ 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;
}
- return 0;
+
+ 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;
+ }
+
+ /* gone wrong */
+ close(gdb_fd);
+ return -1;
}
/* Disable gdb stub for child processes. */
diff --git a/linux-user/main.c b/linux-user/main.c
index 90ad365b43..3597e99bb1 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -52,7 +52,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;
@@ -311,7 +311,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)
@@ -840,10 +840,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);
--
2.20.1
- [PATCH v1 09/14] gdbstub: eliminate gdbserver_fd global, (continued)
- [PATCH v1 09/14] gdbstub: eliminate gdbserver_fd global, Alex Bennée, 2020/04/23
- [PATCH v1 07/14] tests/tcg: better trap gdb failures, Alex Bennée, 2020/04/23
- [PATCH v1 08/14] tests/tcg: drop inferior.was_attached() test, Alex Bennée, 2020/04/23
- [PATCH v1 11/14] tests/guest-debug: use the unix socket for linux-user tests, Alex Bennée, 2020/04/23
- [PATCH v1 14/14] .travis.yml: drop MacOSX, Alex Bennée, 2020/04/23
- [PATCH v1 12/14] tests/tcg: add a multiarch linux-user gdb test, Alex Bennée, 2020/04/23
- [PATCH v1 13/14] .travis.yml: show free disk space at end of run, Alex Bennée, 2020/04/23
- [PATCH v1 10/14] gdbstub/linux-user: support debugging over a unix socket,
Alex Bennée <=
- Re: [PATCH for 5.1 v1 00/14] guest_base, gdbstub and Travis, no-reply, 2020/04/23
- Re: [PATCH for 5.1 v1 00/14] guest_base, gdbstub and Travis, no-reply, 2020/04/23