gdbstub.c: Getting closer to upstream.
Change-Id: Icb2c92375e48dda780d776dab4faf723bc57aa7e
diff --git a/gdbstub.c b/gdbstub.c
index c684d9a..f44f547 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -28,13 +28,12 @@
#include <fcntl.h>
#include "qemu.h"
-#include "hw/hw.h"
#else
+#include "cpu.h"
#include "monitor/monitor.h"
#include "sysemu/char.h"
#include "sysemu/sysemu.h"
#include "exec/gdbstub.h"
-#include "exec/exec-all.h"
#endif
#define MAX_PACKET_LENGTH 4096
@@ -46,7 +45,12 @@
enum {
GDB_SIGNAL_0 = 0,
GDB_SIGNAL_INT = 2,
+ GDB_SIGNAL_QUIT = 3,
GDB_SIGNAL_TRAP = 5,
+ GDB_SIGNAL_ABRT = 6,
+ GDB_SIGNAL_ALRM = 14,
+ GDB_SIGNAL_IO = 23,
+ GDB_SIGNAL_XCPU = 24,
GDB_SIGNAL_UNKNOWN = 143
};
@@ -274,9 +278,9 @@
RS_SYSCALL,
};
typedef struct GDBState {
- CPUArchState *c_cpu; /* current CPU for step/continue ops */
- CPUArchState *g_cpu; /* current CPU for other ops */
- CPUArchState *query_cpu; /* for q{f|s}ThreadInfo */
+ CPUState *c_cpu; /* current CPU for step/continue ops */
+ CPUState *g_cpu; /* current CPU for other ops */
+ CPUState *query_cpu; /* for q{f|s}ThreadInfo */
enum RSState state; /* parsing state */
char line_buf[MAX_PACKET_LENGTH];
int line_buf_index;
@@ -291,6 +295,8 @@
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
@@ -300,10 +306,7 @@
static GDBState *gdbserver_state;
-/* This is an ugly hack to cope with both new and old gdb.
- If gdb sends qXfer:features:read then assume we're talking to a newish
- gdb that understands target descriptions. */
-static int gdb_has_xml;
+bool gdb_has_xml;
#ifdef CONFIG_USER_ONLY
/* XXX: This is not thread safe. Do we care? */
@@ -315,7 +318,7 @@
int ret;
for(;;) {
- ret = recv(s->fd, &ch, 1, 0);
+ ret = qemu_recv(s->fd, &ch, 1, 0);
if (ret < 0) {
if (errno == ECONNRESET)
s->fd = -1;
@@ -333,7 +336,6 @@
}
#endif
-static gdb_syscall_complete_cb gdb_current_syscall_cb;
static enum {
GDB_SYS_UNKNOWN,
@@ -1355,6 +1357,7 @@
/* Generate the XML description for this CPU. */
if (!target_xml[0]) {
GDBRegisterState *r;
+ CPUState *cpu = first_cpu;
snprintf(target_xml, sizeof(target_xml),
"<?xml version=\"1.0\"?>"
@@ -1363,7 +1366,7 @@
"<xi:include href=\"%s\"/>",
GDB_CORE_XML);
- for (r = QTAILQ_FIRST(&cpus)->gdb_regs; r; r = r->next) {
+ for (r = cpu->gdb_regs; r; r = r->next) {
pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
pstrcat(target_xml, sizeof(target_xml), r->xml);
pstrcat(target_xml, sizeof(target_xml), "\"/>");
@@ -1381,13 +1384,14 @@
}
#endif
-static int gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int reg)
+static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg)
{
+ CPUArchState *env = cpu->env_ptr;
GDBRegisterState *r;
- CPUState *cpu = ENV_GET_CPU(env);
- if (reg < NUM_CORE_REGS)
+ if (reg < NUM_CORE_REGS) {
return cpu_gdb_read_register(env, mem_buf, reg);
+ }
for (r = cpu->gdb_regs; r; r = r->next) {
if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
@@ -1397,13 +1401,14 @@
return 0;
}
-static int gdb_write_register(CPUArchState *env, uint8_t *mem_buf, int reg)
+static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
{
+ CPUArchState *env = cpu->env_ptr;
GDBRegisterState *r;
- CPUState *cpu = ENV_GET_CPU(env);
- if (reg < NUM_CORE_REGS)
+ if (reg < NUM_CORE_REGS) {
return cpu_gdb_write_register(env, mem_buf, reg);
+ }
for (r = cpu->gdb_regs; r; r = r->next) {
if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
@@ -1466,16 +1471,18 @@
CPUState *cpu;
int err = 0;
- if (kvm_enabled())
- return kvm_insert_breakpoint(ENV_GET_CPU(gdbserver_state->c_cpu), addr, len, type);
+ if (kvm_enabled()) {
+ return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+ }
switch (type) {
case GDB_BREAKPOINT_SW:
case GDB_BREAKPOINT_HW:
CPU_FOREACH(cpu) {
err = cpu_breakpoint_insert(cpu->env_ptr, addr, BP_GDB, NULL);
- if (err)
+ if (err) {
break;
+ }
}
return err;
#ifndef CONFIG_USER_ONLY
@@ -1500,16 +1507,18 @@
CPUState *cpu;
int err = 0;
- if (kvm_enabled())
- return kvm_remove_breakpoint(ENV_GET_CPU(gdbserver_state->c_cpu), addr, len, type);
+ if (kvm_enabled()) {
+ return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+ }
switch (type) {
case GDB_BREAKPOINT_SW:
case GDB_BREAKPOINT_HW:
CPU_FOREACH(cpu) {
err = cpu_breakpoint_remove(cpu->env_ptr, addr, BP_GDB);
- if (err)
+ if (err) {
break;
+ }
}
return err;
#ifndef CONFIG_USER_ONLY
@@ -1533,7 +1542,7 @@
CPUState *cpu;
if (kvm_enabled()) {
- kvm_remove_all_breakpoints(ENV_GET_CPU(gdbserver_state->c_cpu));
+ kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
return;
}
@@ -1547,45 +1556,37 @@
static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
{
+ CPUArchState *env = s->c_cpu->env_ptr;
#if defined(TARGET_I386)
- s->c_cpu->eip = pc;
- cpu_synchronize_state(ENV_GET_CPU(s->c_cpu), 1);
+ env->eip = pc;
+ cpu_synchronize_state(s->c_cpu, 1);
#elif defined (TARGET_PPC)
- s->c_cpu->nip = pc;
+ env->nip = pc;
#elif defined (TARGET_SPARC)
- s->c_cpu->pc = pc;
- s->c_cpu->npc = pc + 4;
+ env->pc = pc;
+ env->npc = pc + 4;
#elif defined (TARGET_ARM)
- s->c_cpu->regs[15] = pc;
+ env->regs[15] = pc;
#elif defined (TARGET_SH4)
- s->c_cpu->pc = pc;
+ env->pc = pc;
#elif defined (TARGET_MIPS)
- s->c_cpu->active_tc.PC = pc;
+ env->active_tc.PC = pc;
#elif defined (TARGET_MICROBLAZE)
- s->c_cpu->sregs[SR_PC] = pc;
+ env->sregs[SR_PC] = pc;
#elif defined (TARGET_CRIS)
- s->c_cpu->pc = pc;
+ env->pc = pc;
#elif defined (TARGET_ALPHA)
- s->c_cpu->pc = pc;
+ env->pc = pc;
#endif
}
-static inline int gdb_id(CPUState *cpu)
-{
-#if defined(CONFIG_USER_ONLY) && defined(USE_NPTL)
- return cpu->host_tid;
-#else
- return cpu->cpu_index + 1;
-#endif
-}
-
-static CPUArchState *find_cpu(uint32_t thread_id)
+static CPUState *find_cpu(uint32_t thread_id)
{
CPUState *cpu;
CPU_FOREACH(cpu) {
- if (gdb_id(cpu) == thread_id) {
- return cpu->env_ptr;
+ if (cpu_index(cpu) == thread_id) {
+ return cpu;
}
}
@@ -1594,7 +1595,7 @@
static int gdb_handle_packet(GDBState *s, const char *line_buf)
{
- CPUArchState *env;
+ CPUState *cpu;
const char *p;
uint32_t thread;
int ch, reg_size, type, res;
@@ -1612,7 +1613,7 @@
case '?':
/* TODO: Make this return the correct value for user-mode. */
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
- gdb_id(ENV_GET_CPU(s->c_cpu)));
+ cpu_index(s->c_cpu));
put_packet(s, buf);
/* Remove all the breakpoints when this query is issued,
* because gdb is doing and initial connect and the state
@@ -1635,12 +1636,15 @@
gdb_continue(s);
return RS_IDLE;
case 'k':
+#ifdef CONFIG_USER_ONLY
/* Kill the target */
fprintf(stderr, "\nQEMU: Terminated via GDBstub\n");
exit(0);
+#endif
case 'D':
/* Detach packet */
gdb_breakpoint_remove_all();
+ gdb_syscall_mode = GDB_SYS_DISABLED;
gdb_continue(s);
put_packet(s, "OK");
break;
@@ -1649,7 +1653,7 @@
addr = strtoull(p, (char **)&p, 16);
gdb_set_cpu_pc(s, addr);
}
- cpu_single_step(ENV_GET_CPU(s->c_cpu), sstep_flags);
+ cpu_single_step(s->c_cpu, sstep_flags);
gdb_continue(s);
return RS_IDLE;
case 'F':
@@ -1667,8 +1671,10 @@
if (*p == ',')
p++;
type = *p;
- if (gdb_current_syscall_cb)
- gdb_current_syscall_cb(ENV_GET_CPU(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 {
@@ -1677,7 +1683,7 @@
}
break;
case 'g':
- cpu_synchronize_state(ENV_GET_CPU(s->g_cpu), 0);
+ cpu_synchronize_state(s->g_cpu, 0);
len = 0;
for (addr = 0; addr < num_g_regs; addr++) {
reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
@@ -1687,6 +1693,7 @@
put_packet(s, buf);
break;
case 'G':
+ cpu_synchronize_state(s->g_cpu, 1);
registers = mem_buf;
len = strlen(p) / 2;
hextomem((uint8_t *)registers, p, len);
@@ -1695,7 +1702,6 @@
len -= reg_size;
registers += reg_size;
}
- cpu_synchronize_state(ENV_GET_CPU(s->g_cpu), 1);
put_packet(s, "OK");
break;
case 'm':
@@ -1703,7 +1709,7 @@
if (*p == ',')
p++;
len = strtoull(p, NULL, 16);
- if (cpu_memory_rw_debug(ENV_GET_CPU(s->g_cpu), addr, mem_buf, len, 0) != 0) {
+ if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
put_packet (s, "E14");
} else {
memtohex(buf, mem_buf, len);
@@ -1718,10 +1724,11 @@
if (*p == ':')
p++;
hextomem(mem_buf, p, len);
- if (cpu_memory_rw_debug(ENV_GET_CPU(s->g_cpu), addr, mem_buf, len, 1) != 0)
+ if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) {
put_packet(s, "E14");
- else
+ } else {
put_packet(s, "OK");
+ }
break;
case 'p':
/* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
@@ -1776,18 +1783,18 @@
put_packet(s, "OK");
break;
}
- env = find_cpu(thread);
- if (env == NULL) {
+ cpu = find_cpu(thread);
+ if (cpu == NULL) {
put_packet(s, "E22");
break;
}
switch (type) {
case 'c':
- s->c_cpu = env;
+ s->c_cpu = cpu;
put_packet(s, "OK");
break;
case 'g':
- s->g_cpu = env;
+ s->g_cpu = cpu;
put_packet(s, "OK");
break;
default:
@@ -1797,9 +1804,9 @@
break;
case 'T':
thread = strtoull(p, (char **)&p, 16);
- env = find_cpu(thread);
+ cpu = find_cpu(thread);
- if (env != NULL) {
+ if (cpu != NULL) {
put_packet(s, "OK");
} else {
put_packet(s, "E22");
@@ -1836,25 +1843,25 @@
put_packet(s, "QC1");
break;
} else if (strcmp(p,"fThreadInfo") == 0) {
- s->query_cpu = QTAILQ_FIRST(&cpus)->env_ptr;
+ s->query_cpu = first_cpu;
goto report_cpuinfo;
} else if (strcmp(p,"sThreadInfo") == 0) {
report_cpuinfo:
if (s->query_cpu) {
- snprintf(buf, sizeof(buf), "m%x", gdb_id(ENV_GET_CPU(s->query_cpu)));
+ snprintf(buf, sizeof(buf), "m%x", cpu_index(s->query_cpu));
put_packet(s, buf);
- s->query_cpu = QTAILQ_NEXT(ENV_GET_CPU(s->query_cpu), node)->env_ptr;
+ s->query_cpu = CPU_NEXT(s->query_cpu);
} else
put_packet(s, "l");
break;
} else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
thread = strtoull(p+16, (char **)&p, 16);
- env = find_cpu(thread);
- if (env != NULL) {
- cpu_synchronize_state(ENV_GET_CPU(env), 0);
+ cpu = find_cpu(thread);
+ if (cpu != NULL) {
+ cpu_synchronize_state(cpu, 1);
len = snprintf((char *)mem_buf, sizeof(mem_buf),
- "CPU#%d [%s]", ENV_GET_CPU(env)->cpu_index,
- ENV_GET_CPU(env)->halted ? "halted " : "running");
+ "CPU#%d [%s]", cpu->cpu_index,
+ cpu->halted ? "halted " : "running");
memtohex(buf, mem_buf, len);
put_packet(s, buf);
}
@@ -1902,7 +1909,7 @@
const char *xml;
target_ulong total_len;
- gdb_has_xml = 1;
+ gdb_has_xml = true;
p += 19;
xml = get_feature_xml(p, &p);
if (!xml) {
@@ -1952,16 +1959,16 @@
void gdb_set_stop_cpu(CPUState *cpu)
{
- gdbserver_state->c_cpu = cpu->env_ptr;
- gdbserver_state->g_cpu = cpu->env_ptr;
+ gdbserver_state->c_cpu = cpu;
+ gdbserver_state->g_cpu = cpu;
}
#ifndef CONFIG_USER_ONLY
static void gdb_vm_state_change(void *opaque, int running, int reason)
{
GDBState *s = gdbserver_state;
- CPUArchState *env = s->c_cpu;
- CPUState *cpu = ENV_GET_CPU(env);
+ CPUArchState *env = s->c_cpu->env_ptr;
+ CPUState *cpu = s->c_cpu;
char buf[256];
const char *type;
int ret;
@@ -1970,9 +1977,6 @@
s->state == RS_INACTIVE || s->state == RS_SYSCALL)
return;
- /* disable single step if it was enable */
- cpu_single_step(cpu, 0);
-
if (reason == EXCP_DEBUG) {
if (env->watchpoint_hit) {
switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
@@ -1988,19 +1992,23 @@
}
snprintf(buf, sizeof(buf),
"T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
- GDB_SIGNAL_TRAP, gdb_id(cpu), type,
- env->watchpoint_hit->vaddr);
- put_packet(s, buf);
+ GDB_SIGNAL_TRAP, cpu_index(cpu), type,
+ (target_ulong)env->watchpoint_hit->vaddr);
env->watchpoint_hit = NULL;
- return;
+ goto send_packet;
}
tb_flush(env);
ret = GDB_SIGNAL_TRAP;
} else {
ret = GDB_SIGNAL_INT;
}
- snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, gdb_id(cpu));
+ snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_index(cpu));
+
+send_packet:
put_packet(s, buf);
+
+ /* disable single step if it was enabled */
+ cpu_single_step(cpu, 0);
}
#endif
@@ -2012,8 +2020,8 @@
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;
@@ -2021,14 +2029,13 @@
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(EXCP_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 == '%') {
@@ -2036,17 +2043,17 @@
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:
@@ -2061,11 +2068,17 @@
}
*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
- cpu_exit(ENV_GET_CPU(s->c_cpu));
+ /* 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
}
@@ -2145,6 +2158,32 @@
}
}
+/* Tell the remote gdb that the process has exited. */
+void gdb_exit(CPUArchState *env, int code)
+{
+ GDBState *s;
+ char buf[4];
+
+ s = gdbserver_state;
+ if (!s) {
+ return;
+ }
+#ifdef CONFIG_USER_ONLY
+ if (gdbserver_fd < 0 || s->fd < 0) {
+ return;
+ }
+#endif
+
+ snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
+ put_packet(s, buf);
+
+#ifndef CONFIG_USER_ONLY
+ if (s->chr) {
+ qemu_chr_close(s->chr);
+ s->chr = NULL;
+ }
+#endif
+}
#ifdef CONFIG_USER_ONLY
int
gdb_queuesig (void)
@@ -2162,43 +2201,43 @@
int
gdb_handlesig (CPUState *cpu, int sig)
{
+ CPUArchState *env = cpu->env_ptr;
GDBState *s;
char buf[256];
int n;
s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0)
+ if (gdbserver_fd < 0 || s->fd < 0) {
return sig;
+ }
/* disable single step if it was enabled */
cpu_single_step(cpu, 0);
- tb_flush(cpu->env_ptr);
+ tb_flush(env);
- if (sig != 0)
- {
+ if (sig != 0) {
snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb (sig));
put_packet(s, buf);
}
/* put_packet() might have detected that the peer terminated the
connection. */
- if (s->fd < 0)
+ if (s->fd < 0) {
return sig;
+ }
sig = 0;
s->state = RS_IDLE;
s->running_state = 0;
while (s->running_state == 0) {
n = read (s->fd, buf, 256);
- if (n > 0)
- {
+ if (n > 0) {
int i;
- for (i = 0; i < n; i++)
+ for (i = 0; i < n; i++) {
gdb_read_byte (s, buf[i]);
}
- else if (n == 0 || errno != EAGAIN)
- {
- /* XXX: Connection closed. Should probably wait for annother
+ } else if (n == 0 || errno != EAGAIN) {
+ /* XXX: Connection closed. Should probably wait for another
connection before continuing. */
return sig;
}
@@ -2208,20 +2247,6 @@
return sig;
}
-/* Tell the remote gdb that the process has exited. */
-void gdb_exit(CPUState *cpu, int code)
-{
- GDBState *s;
- char buf[4];
-
- s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0)
- return;
-
- snprintf(buf, sizeof(buf), "W%02x", code);
- put_packet(s, buf);
-}
-
/* Tell the remote gdb that the process has exited due to SIG. */
void gdb_signalled(CPUState *cpu, int sig)
{
@@ -2229,8 +2254,9 @@
char buf[4];
s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0)
+ if (gdbserver_fd < 0 || s->fd < 0) {
return;
+ }
snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig));
put_packet(s, buf);
@@ -2241,7 +2267,7 @@
GDBState *s;
struct sockaddr_in sockaddr;
socklen_t len;
- int val, fd;
+ int fd;
for(;;) {
len = sizeof(sockaddr);
@@ -2250,19 +2276,21 @@
perror("accept");
return;
} else if (fd >= 0) {
+#ifndef _WIN32
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
break;
}
}
/* set short latency */
- val = 1;
- qemu_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+ socket_set_nodelay(fd);
s = g_malloc0(sizeof(GDBState));
- s->c_cpu = QTAILQ_FIRST(&cpus);
- s->g_cpu = QTAILQ_FIRST(&cpus);
+ s->c_cpu = first_cpu;
+ s->g_cpu = first_cpu;
s->fd = fd;
- gdb_has_xml = 0;
+ gdb_has_xml = false;
gdbserver_state = s;
@@ -2272,17 +2300,18 @@
static int gdbserver_open(int port)
{
struct sockaddr_in sockaddr;
- int fd, val, ret;
+ int fd, ret;
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
perror("socket");
return -1;
}
+#ifndef _WIN32
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
- /* allow fast reuse */
- val = 1;
- qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
+ socket_set_fast_reuse(fd);
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
@@ -2290,11 +2319,13 @@
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
if (ret < 0) {
perror("bind");
+ close(fd);
return -1;
}
ret = listen(fd, 0);
if (ret < 0) {
perror("listen");
+ close(fd);
return -1;
}
return fd;
@@ -2314,8 +2345,9 @@
void gdbserver_fork(CPUArchState *env)
{
GDBState *s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0)
+ if (gdbserver_fd < 0 || s->fd < 0) {
return;
+ }
close(s->fd);
s->fd = -1;
cpu_breakpoint_remove_all(env, BP_GDB);
@@ -2343,7 +2375,7 @@
switch (event) {
case CHR_EVENT_OPENED:
vm_stop(EXCP_INTERRUPT);
- gdb_has_xml = 0;
+ gdb_has_xml = false;
break;
default:
break;
@@ -2382,8 +2414,9 @@
#ifndef _WIN32
static void gdb_sigterm_handler(int signal)
{
- if (vm_running)
+ if (vm_running) {
vm_stop(EXCP_INTERRUPT);
+ }
}
#endif
@@ -2437,11 +2470,12 @@
mon_chr = s->mon_chr;
memset(s, 0, sizeof(GDBState));
}
- s->c_cpu = QTAILQ_FIRST(&cpus)->env_ptr;
- s->g_cpu = s->c_cpu;
+ s->c_cpu = first_cpu;
+ s->g_cpu = first_cpu;
s->chr = chr;
s->state = chr ? RS_IDLE : RS_INACTIVE;
s->mon_chr = mon_chr;
+ s->current_syscall_cb = NULL;
return 0;
}
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 4d122d0..7b9a485 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -11,14 +11,12 @@
#define GDB_WATCHPOINT_ACCESS 4
#ifdef NEED_CPU_H
-#include "cpu.h"
-
-typedef void (*gdb_syscall_complete_cb)(CPUState *env,
+typedef void (*gdb_syscall_complete_cb)(CPUState *cpu,
target_ulong ret, target_ulong err);
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...);
int use_gdb_syscalls(void);
-void gdb_set_stop_cpu(CPUState *env);
+void gdb_set_stop_cpu(CPUState *cpu);
void gdb_exit(CPUArchState *, int);
#ifdef CONFIG_USER_ONLY
int gdb_queuesig (void);
@@ -31,6 +29,14 @@
void gdb_register_coprocessor(CPUState *cpu,
gdb_reg_cb get_reg, gdb_reg_cb set_reg,
int num_regs, const char *xml, int g_pos);
+static inline int cpu_index(CPUState *cpu)
+{
+#if defined(CONFIG_USER_ONLY)
+ return cpu->host_tid;
+#else
+ return cpu->cpu_index + 1;
+#endif
+}
#endif
@@ -39,5 +45,15 @@
#else
int gdbserver_start(const char *port);
#endif
+/**
+ * gdb_has_xml:
+ * This is an ugly hack to cope with both new and old gdb.
+ * If gdb sends qXfer:features:read then assume we're talking to a newish
+ * gdb that understands target descriptions.
+ */
+extern bool gdb_has_xml;
+
+/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
+extern const char *const xml_builtin[][2];
#endif