/*
* cmd_startswith -> cmd is compared using startswith
*
+ * allow_stop_reply -> true iff the gdbstub can respond to this command with a
+ * "stop reply" packet. The list of commands that accept such response is
+ * defined at the GDB Remote Serial Protocol documentation. see:
+ * https://sourceware.org/gdb/onlinedocs/gdb/Stop-Reply-Packets.html#Stop-Reply-Packets.
*
* schema definitions:
* Each schema parameter entry consists of 2 chars,
const char *cmd;
bool cmd_startswith;
const char *schema;
+ bool allow_stop_reply;
} GdbCmdParseEntry;
static inline int startswith(const char *string, const char *pattern)
}
}
+ gdbserver_state.allow_stop_reply = cmd->allow_stop_reply;
cmd->handler(params, user_ctx);
return 0;
}
gdbserver_state.g_cpu = cpu;
gdbserver_state.c_cpu = cpu;
- g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
- gdb_append_thread_id(cpu, gdbserver_state.str_buf);
- g_string_append_c(gdbserver_state.str_buf, ';');
+ if (gdbserver_state.allow_stop_reply) {
+ g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
+ gdb_append_thread_id(cpu, gdbserver_state.str_buf);
+ g_string_append_c(gdbserver_state.str_buf, ';');
+ gdbserver_state.allow_stop_reply = false;
cleanup:
- gdb_put_strbuf();
+ gdb_put_strbuf();
+ }
}
static void handle_v_kill(GArray *params, void *user_ctx)
.handler = handle_v_cont,
.cmd = "Cont",
.cmd_startswith = 1,
+ .allow_stop_reply = true,
.schema = "s0"
},
{
.handler = handle_v_attach,
.cmd = "Attach;",
.cmd_startswith = 1,
+ .allow_stop_reply = true,
.schema = "l0"
},
{
static void handle_target_halt(GArray *params, void *user_ctx)
{
- g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
- gdb_append_thread_id(gdbserver_state.c_cpu, gdbserver_state.str_buf);
- g_string_append_c(gdbserver_state.str_buf, ';');
- gdb_put_strbuf();
+ if (gdbserver_state.allow_stop_reply) {
+ g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
+ gdb_append_thread_id(gdbserver_state.c_cpu, gdbserver_state.str_buf);
+ g_string_append_c(gdbserver_state.str_buf, ';');
+ gdb_put_strbuf();
+ gdbserver_state.allow_stop_reply = false;
+ }
/*
* Remove all the breakpoints when this query is issued,
* because gdb is doing an initial connect and the state
static const GdbCmdParseEntry target_halted_cmd_desc = {
.handler = handle_target_halt,
.cmd = "?",
- .cmd_startswith = 1
+ .cmd_startswith = 1,
+ .allow_stop_reply = true,
};
cmd_parser = &target_halted_cmd_desc;
}
.handler = handle_continue,
.cmd = "c",
.cmd_startswith = 1,
+ .allow_stop_reply = true,
.schema = "L0"
};
cmd_parser = &continue_cmd_desc;
.handler = handle_cont_with_sig,
.cmd = "C",
.cmd_startswith = 1,
+ .allow_stop_reply = true,
.schema = "l0"
};
cmd_parser = &cont_with_sig_cmd_desc;
.handler = handle_step,
.cmd = "s",
.cmd_startswith = 1,
+ .allow_stop_reply = true,
.schema = "L0"
};
cmd_parser = &step_cmd_desc;
{
uint8_t reply;
+ gdbserver_state.allow_stop_reply = false;
#ifndef CONFIG_USER_ONLY
if (gdbserver_state.last_packet->len) {
/* Waiting for a response to the last packet. If we see the start
g_free(gdbserver_state.processes);
gdbserver_state.processes = NULL;
gdbserver_state.process_num = 0;
+ gdbserver_state.allow_stop_reply = false;
}
/*
return;
}
+ if (!gdbserver_state.allow_stop_reply) {
+ return;
+ }
+
gdb_append_thread_id(cpu, tid);
switch (state) {
send_packet:
gdb_put_packet(buf->str);
+ gdbserver_state.allow_stop_reply = false;
/* disable single step if it was enabled */
cpu_single_step(cpu, 0);
trace_gdbstub_op_exiting((uint8_t)code);
- snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
- gdb_put_packet(buf);
+ if (gdbserver_state.allow_stop_reply) {
+ snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
+ gdb_put_packet(buf);
+ gdbserver_state.allow_stop_reply = false;
+ }
qemu_chr_fe_deinit(&gdbserver_system_state.chr, true);
}
trace_gdbstub_op_exiting((uint8_t)code);
- snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
- gdb_put_packet(buf);
+ if (gdbserver_state.allow_stop_reply) {
+ snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
+ gdb_put_packet(buf);
+ gdbserver_state.allow_stop_reply = false;
+ }
}
int gdb_handlesig(CPUState *cpu, int sig)
if (sig != 0) {
gdb_set_stop_cpu(cpu);
- g_string_printf(gdbserver_state.str_buf,
- "T%02xthread:", gdb_target_signal_to_gdb(sig));
- gdb_append_thread_id(cpu, gdbserver_state.str_buf);
- g_string_append_c(gdbserver_state.str_buf, ';');
- gdb_put_strbuf();
+ if (gdbserver_state.allow_stop_reply) {
+ g_string_printf(gdbserver_state.str_buf,
+ "T%02xthread:", gdb_target_signal_to_gdb(sig));
+ gdb_append_thread_id(cpu, gdbserver_state.str_buf);
+ g_string_append_c(gdbserver_state.str_buf, ';');
+ gdb_put_strbuf();
+ gdbserver_state.allow_stop_reply = false;
+ }
}
/*
* gdb_put_packet() might have detected that the peer terminated the
{
char buf[4];
- if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
+ if (!gdbserver_state.init || gdbserver_user_state.fd < 0 ||
+ !gdbserver_state.allow_stop_reply) {
return;
}
snprintf(buf, sizeof(buf), "X%02x", gdb_target_signal_to_gdb(sig));
gdb_put_packet(buf);
+ gdbserver_state.allow_stop_reply = false;
}
static void gdb_accept_init(int fd)