@@ -297,6 +297,7 @@ typedef struct GDBState {
uint8_t last_packet[MAX_PACKET_LENGTH + 4];
int last_packet_len;
int signal;
+ int client_connected;
#ifdef CONFIG_USER_ONLY
int fd;
int running_state;
@@ -2505,12 +2506,56 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
return RS_IDLE;
}
+static void gdb_output(GDBState *s, const char *msg, int len)
+{
+ char buf[MAX_PACKET_LENGTH];
+
+ buf[0] = 'O';
+ if (len > (MAX_PACKET_LENGTH/2) - 1) {
+ len = (MAX_PACKET_LENGTH/2) - 1;
+ }
+ memtohex(buf + 1, (uint8_t *)msg, len);
+ put_packet(s, buf);
+}
+
void gdb_set_stop_cpu(CPUArchState *env)
{
gdbserver_state->c_cpu = env;
gdbserver_state->g_cpu = env;
}
+static int gdbserver_has_client(void)
+{
+ return gdbserver_state && gdbserver_state->client_connected;
+}
+
+int gdbserver_break(const char *msg)
+{
+
+ if (!gdbserver_has_client()) {
+ return 1;
+ }
+
+ if (msg) {
+ gdb_output(gdbserver_state, msg, strlen(msg));
+ }
+
+ /* If there's a CPU running, break it's execution. */
+ if (cpu_single_env) {
+ CPUState *cpu = ENV_GET_CPU(cpu_single_env);
+ cpu_single_env->exception_index = EXCP_DEBUG;
+ if (cpu->current_tb) {
+ /* Break out of current TB and request debug action. */
+ cpu_loop_exit(cpu_single_env);
+ }
+ }
+#ifndef CONFIG_USER_ONLY
+ /* Request global debug action. */
+ qemu_system_debug_request();
+#endif
+ return 0;
+}
+
#ifndef CONFIG_USER_ONLY
static void gdb_vm_state_change(void *opaque, int running, RunState state)
{
@@ -2815,6 +2860,7 @@ gdb_handlesig (CPUArchState *env, int sig)
{
/* XXX: Connection closed. Should probably wait for another
connection before continuing. */
+ s->client_connected = false;
return sig;
}
}
@@ -2868,7 +2914,7 @@ static void gdb_accept(void)
gdb_has_xml = 0;
gdbserver_state = s;
-
+ s->client_connected = true;
fcntl(fd, F_SETFL, O_NONBLOCK);
}
@@ -2952,23 +2998,17 @@ static void gdb_chr_event(void *opaque, int event)
case CHR_EVENT_OPENED:
vm_stop(RUN_STATE_PAUSED);
gdb_has_xml = 0;
+ gdbserver_state->client_connected = true;
break;
+ case CHR_EVENT_CLOSED: {
+ gdbserver_state->client_connected = false;
+ break;
+ }
default:
break;
}
}
-static void gdb_monitor_output(GDBState *s, const char *msg, int len)
-{
- char buf[MAX_PACKET_LENGTH];
-
- buf[0] = 'O';
- if (len > (MAX_PACKET_LENGTH/2) - 1)
- len = (MAX_PACKET_LENGTH/2) - 1;
- memtohex(buf + 1, (uint8_t *)msg, len);
- put_packet(s, buf);
-}
-
static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
{
const char *p = (const char *)buf;
@@ -2977,10 +3017,10 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
max_sz = (sizeof(gdbserver_state->last_packet) - 2) / 2;
for (;;) {
if (len <= max_sz) {
- gdb_monitor_output(gdbserver_state, p, len);
+ gdb_output(gdbserver_state, p, len);
break;
}
- gdb_monitor_output(gdbserver_state, p, max_sz);
+ gdb_output(gdbserver_state, p, max_sz);
p += max_sz;
len -= max_sz;
}
@@ -47,6 +47,8 @@ int gdbserver_start(int);
int gdbserver_start(const char *port);
#endif
+int gdbserver_break(const char *msg);
+
/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
extern const char *const xml_builtin[][2];