gdbstub.c | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-)
When checking whether there is a live gdb connection, code shouldn't
use 'gdbserver_state.init' as that value is set when the
gdbserver_state structure is initialized in init_gdbserver_state, not
when the gdb socket has a valid connection.
I've created two new functions to manage the gdb connection status:
/* Check whether GDB is currently connected */
static int gdb_is_connected(void)
#ifdef CONFIG_USER_ONLY
/* Close GDB connection */
static void gdb_disconnect(void)
#endif
The first checks whether there is an active GDB connection, the second
closes that connection and resets the connection status indication.
The 'handle_detach' function used 'gdbserver_state.c_cpu' as an
indication of whether there is a connection, so I've used the same in
gdb_is_connected as that is independent of CONFIG_USER_ONLY.
This avoids a segfault when qemu is run with the '-s' flag (create a
gdb protocol socket), but without the '-S' flag (delay until 'c'
command is received).
Signed-off-by: Keith Packard <keithp@keithp.com>
---
gdbstub.c | 51 +++++++++++++++++++++++++++++++++------------------
1 file changed, 33 insertions(+), 18 deletions(-)
diff --git a/gdbstub.c b/gdbstub.c
index d99bc0bf2e..8ee7e442d5 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -413,8 +413,28 @@ static void reset_gdbserver_state(void)
bool gdb_has_xml;
+/* Check whether GDB is currently connected */
+static int gdb_is_connected(void)
+{
+ /*
+ * XXX c_cpu is NULL until gdb_accept_init has been called, so use
+ * this as a proxy for whether the gdb connection is active
+ */
+ return gdbserver_state.c_cpu != NULL;
+}
+
#ifdef CONFIG_USER_ONLY
+/* Close GDB connection */
+static void gdb_disconnect(void)
+{
+ if (gdb_is_connected()) {
+ close(gdbserver_state.fd);
+ gdbserver_state.fd = -1;
+ gdbserver_state.c_cpu = NULL;
+ }
+}
+
static int get_char(void)
{
uint8_t ch;
@@ -424,12 +444,11 @@ static int get_char(void)
ret = qemu_recv(gdbserver_state.fd, &ch, 1, 0);
if (ret < 0) {
if (errno == ECONNRESET)
- gdbserver_state.fd = -1;
+ gdb_disconnect();
if (errno != EINTR)
return -1;
} else if (ret == 0) {
- close(gdbserver_state.fd);
- gdbserver_state.fd = -1;
+ gdb_disconnect();
return -1;
} else {
break;
@@ -2796,7 +2815,7 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
target_ulong addr;
uint64_t i64;
- if (!gdbserver_state.init) {
+ if (!gdb_is_connected()) {
return;
}
@@ -3025,9 +3044,9 @@ void gdb_exit(CPUArchState *env, int code)
if (gdbserver_state.socket_path) {
unlink(gdbserver_state.socket_path);
}
- if (gdbserver_state.fd < 0) {
- return;
- }
+ if (!gdb_is_connected()) {
+ return;
+ }
#endif
trace_gdbstub_op_exiting((uint8_t)code);
@@ -3072,7 +3091,7 @@ gdb_handlesig(CPUState *cpu, int sig)
char buf[256];
int n;
- if (!gdbserver_state.init || gdbserver_state.fd < 0) {
+ if (!gdb_is_connected()) {
return sig;
}
@@ -3086,14 +3105,14 @@ gdb_handlesig(CPUState *cpu, int sig)
}
/* put_packet() might have detected that the peer terminated the
connection. */
- if (gdbserver_state.fd < 0) {
+ if (!gdb_is_connected()) {
return sig;
}
sig = 0;
gdbserver_state.state = RS_IDLE;
gdbserver_state.running_state = 0;
- while (gdbserver_state.running_state == 0) {
+ while (gdbserver_state.running_state == 0 && gdb_is_connected()) {
n = read(gdbserver_state.fd, buf, 256);
if (n > 0) {
int i;
@@ -3104,10 +3123,7 @@ gdb_handlesig(CPUState *cpu, int sig)
} else {
/* XXX: Connection closed. Should probably wait for another
connection before continuing. */
- if (n == 0) {
- close(gdbserver_state.fd);
- }
- gdbserver_state.fd = -1;
+ gdb_disconnect();
return sig;
}
}
@@ -3121,7 +3137,7 @@ void gdb_signalled(CPUArchState *env, int sig)
{
char buf[4];
- if (!gdbserver_state.init || gdbserver_state.fd < 0) {
+ if (!gdb_is_connected()) {
return;
}
@@ -3280,11 +3296,10 @@ int gdbserver_start(const char *port_or_path)
/* Disable gdb stub for child processes. */
void gdbserver_fork(CPUState *cpu)
{
- if (!gdbserver_state.init || gdbserver_state.fd < 0) {
+ if (!gdb_is_connected()) {
return;
}
- close(gdbserver_state.fd);
- gdbserver_state.fd = -1;
+ gdb_disconnect();
cpu_breakpoint_remove_all(cpu, BP_GDB);
cpu_watchpoint_remove_all(cpu, BP_GDB);
}
--
2.30.0
© 2016 - 2024 Red Hat, Inc.