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