From: Meador Inge <meadori@codesourcery.com>
To: qemu-devel@nongnu.org
Cc: peter.maydell@linaro.org
Subject: [Qemu-devel] [PATCH v2 1/1] gdbserver: Don't send a GDB syscall until the system CPU is stopped
Date: Fri, 17 Feb 2012 10:21:21 -0600 [thread overview]
Message-ID: <1329495681-5187-2-git-send-email-meadori@codesourcery.com> (raw)
In-Reply-To: <1329495681-5187-1-git-send-email-meadori@codesourcery.com>
Fix an issue where the GDB server implementation was sending GDB syscall
requests while the system CPU was still running. Syscall requests must
be sent while the CPU is stopped otherwise replies from the GDB client
might get dropped and the GDB server might be incorrectly transitioned
into a 'RUN_STATE_PAUSED' state.
Signed-off-by: Meador Inge <meadori@codesourcery.com>
---
gdbstub.c | 44 ++++++++++++++++++++++++++++----------------
1 files changed, 28 insertions(+), 16 deletions(-)
diff --git a/gdbstub.c b/gdbstub.c
index 7d470b6..a08532f 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -283,8 +283,7 @@ enum RSState {
RS_IDLE,
RS_GETLINE,
RS_CHKSUM1,
- RS_CHKSUM2,
- RS_SYSCALL,
+ RS_CHKSUM2
};
typedef struct GDBState {
CPUState *c_cpu; /* current CPU for step/continue ops */
@@ -304,6 +303,8 @@ typedef struct GDBState {
CharDriverState *chr;
CharDriverState *mon_chr;
#endif
+ char syscall_buf[256];
+ gdb_syscall_complete_cb current_syscall_cb;
} GDBState;
/* By default use no IRQs and no timers while single stepping so as to
@@ -346,8 +347,6 @@ static int get_char(GDBState *s)
}
#endif
-static gdb_syscall_complete_cb gdb_current_syscall_cb;
-
static enum {
GDB_SYS_UNKNOWN,
GDB_SYS_ENABLED,
@@ -2095,8 +2094,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
if (*p == ',')
p++;
type = *p;
- if (gdb_current_syscall_cb)
- gdb_current_syscall_cb(s->c_cpu, ret, err);
+ if (s->current_syscall_cb) {
+ s->current_syscall_cb(s->c_cpu, ret, err);
+ s->current_syscall_cb = NULL;
+ }
if (type == 'C') {
put_packet(s, "T02");
} else {
@@ -2396,7 +2397,12 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
const char *type;
int ret;
- if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
+ if (running || s->state == RS_INACTIVE) {
+ return;
+ }
+ /* Is there a GDB syscall waiting to be sent? */
+ if (s->current_syscall_cb) {
+ put_packet(s, s->syscall_buf);
return;
}
switch (state) {
@@ -2466,8 +2472,8 @@ send_packet:
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
{
va_list va;
- char buf[256];
char *p;
+ char *p_end;
target_ulong addr;
uint64_t i64;
GDBState *s;
@@ -2475,14 +2481,13 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
s = gdbserver_state;
if (!s)
return;
- gdb_current_syscall_cb = cb;
- s->state = RS_SYSCALL;
+ s->current_syscall_cb = cb;
#ifndef CONFIG_USER_ONLY
vm_stop(RUN_STATE_DEBUG);
#endif
- s->state = RS_IDLE;
va_start(va, fmt);
- p = buf;
+ p = s->syscall_buf;
+ p_end = &s->syscall_buf[sizeof(s->syscall_buf)];
*(p++) = 'F';
while (*fmt) {
if (*fmt == '%') {
@@ -2490,17 +2495,17 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
switch (*fmt++) {
case 'x':
addr = va_arg(va, target_ulong);
- p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx, addr);
+ p += snprintf(p, p_end - p, TARGET_FMT_lx, addr);
break;
case 'l':
if (*(fmt++) != 'x')
goto bad_format;
i64 = va_arg(va, uint64_t);
- p += snprintf(p, &buf[sizeof(buf)] - p, "%" PRIx64, i64);
+ p += snprintf(p, p_end - p, "%" PRIx64, i64);
break;
case 's':
addr = va_arg(va, target_ulong);
- p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx "/%x",
+ p += snprintf(p, p_end - p, TARGET_FMT_lx "/%x",
addr, va_arg(va, int));
break;
default:
@@ -2515,10 +2520,16 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
}
*p = 0;
va_end(va);
- put_packet(s, buf);
#ifdef CONFIG_USER_ONLY
+ put_packet(s, s->syscall_buf);
gdb_handlesig(s->c_cpu, 0);
#else
+ /* In this case wait to send the syscall packet until notification that
+ the CPU has stopped. This must be done because if the packet is sent
+ now the reply from the syscall request could be received while the CPU
+ is still in the running state, which can cause packets to be dropped
+ and state transition 'T' packets to be sent while the syscall is still
+ being processed. */
cpu_exit(s->c_cpu);
#endif
}
@@ -2917,6 +2928,7 @@ int gdbserver_start(const char *device)
s->chr = chr;
s->state = chr ? RS_IDLE : RS_INACTIVE;
s->mon_chr = mon_chr;
+ s->current_syscall_cb = NULL;
return 0;
}
--
1.7.7.6
next prev parent reply other threads:[~2012-02-17 16:21 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-02-17 16:21 [Qemu-devel] [PATCH v2 0/1] Fix GDB semihosting Meador Inge
2012-02-17 16:21 ` Meador Inge [this message]
2012-02-20 16:18 ` [Qemu-devel] [PATCH v2 1/1] gdbserver: Don't send a GDB syscall until the system CPU is stopped Peter Maydell
2012-03-06 19:05 ` Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1329495681-5187-2-git-send-email-meadori@codesourcery.com \
--to=meadori@codesourcery.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).