Add qemu 2.4.0
[kvmfornfv.git] / qemu / gdbstub.c
diff --git a/qemu/gdbstub.c b/qemu/gdbstub.c
new file mode 100644 (file)
index 0000000..ffe7e6e
--- /dev/null
@@ -0,0 +1,1769 @@
+/*
+ * gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#ifdef CONFIG_USER_ONLY
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "qemu.h"
+#else
+#include "monitor/monitor.h"
+#include "sysemu/char.h"
+#include "sysemu/sysemu.h"
+#include "exec/gdbstub.h"
+#endif
+
+#define MAX_PACKET_LENGTH 4096
+
+#include "cpu.h"
+#include "qemu/sockets.h"
+#include "sysemu/kvm.h"
+#include "exec/semihost.h"
+
+#ifdef CONFIG_USER_ONLY
+#define GDB_ATTACHED "0"
+#else
+#define GDB_ATTACHED "1"
+#endif
+
+static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
+                                         uint8_t *buf, int len, bool is_write)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+
+    if (cc->memory_rw_debug) {
+        return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
+    }
+    return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
+}
+
+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
+};
+
+#ifdef CONFIG_USER_ONLY
+
+/* Map target signal numbers to GDB protocol signal numbers and vice
+ * versa.  For user emulation's currently supported systems, we can
+ * assume most signals are defined.
+ */
+
+static int gdb_signal_table[] = {
+    0,
+    TARGET_SIGHUP,
+    TARGET_SIGINT,
+    TARGET_SIGQUIT,
+    TARGET_SIGILL,
+    TARGET_SIGTRAP,
+    TARGET_SIGABRT,
+    -1, /* SIGEMT */
+    TARGET_SIGFPE,
+    TARGET_SIGKILL,
+    TARGET_SIGBUS,
+    TARGET_SIGSEGV,
+    TARGET_SIGSYS,
+    TARGET_SIGPIPE,
+    TARGET_SIGALRM,
+    TARGET_SIGTERM,
+    TARGET_SIGURG,
+    TARGET_SIGSTOP,
+    TARGET_SIGTSTP,
+    TARGET_SIGCONT,
+    TARGET_SIGCHLD,
+    TARGET_SIGTTIN,
+    TARGET_SIGTTOU,
+    TARGET_SIGIO,
+    TARGET_SIGXCPU,
+    TARGET_SIGXFSZ,
+    TARGET_SIGVTALRM,
+    TARGET_SIGPROF,
+    TARGET_SIGWINCH,
+    -1, /* SIGLOST */
+    TARGET_SIGUSR1,
+    TARGET_SIGUSR2,
+#ifdef TARGET_SIGPWR
+    TARGET_SIGPWR,
+#else
+    -1,
+#endif
+    -1, /* SIGPOLL */
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+#ifdef __SIGRTMIN
+    __SIGRTMIN + 1,
+    __SIGRTMIN + 2,
+    __SIGRTMIN + 3,
+    __SIGRTMIN + 4,
+    __SIGRTMIN + 5,
+    __SIGRTMIN + 6,
+    __SIGRTMIN + 7,
+    __SIGRTMIN + 8,
+    __SIGRTMIN + 9,
+    __SIGRTMIN + 10,
+    __SIGRTMIN + 11,
+    __SIGRTMIN + 12,
+    __SIGRTMIN + 13,
+    __SIGRTMIN + 14,
+    __SIGRTMIN + 15,
+    __SIGRTMIN + 16,
+    __SIGRTMIN + 17,
+    __SIGRTMIN + 18,
+    __SIGRTMIN + 19,
+    __SIGRTMIN + 20,
+    __SIGRTMIN + 21,
+    __SIGRTMIN + 22,
+    __SIGRTMIN + 23,
+    __SIGRTMIN + 24,
+    __SIGRTMIN + 25,
+    __SIGRTMIN + 26,
+    __SIGRTMIN + 27,
+    __SIGRTMIN + 28,
+    __SIGRTMIN + 29,
+    __SIGRTMIN + 30,
+    __SIGRTMIN + 31,
+    -1, /* SIGCANCEL */
+    __SIGRTMIN,
+    __SIGRTMIN + 32,
+    __SIGRTMIN + 33,
+    __SIGRTMIN + 34,
+    __SIGRTMIN + 35,
+    __SIGRTMIN + 36,
+    __SIGRTMIN + 37,
+    __SIGRTMIN + 38,
+    __SIGRTMIN + 39,
+    __SIGRTMIN + 40,
+    __SIGRTMIN + 41,
+    __SIGRTMIN + 42,
+    __SIGRTMIN + 43,
+    __SIGRTMIN + 44,
+    __SIGRTMIN + 45,
+    __SIGRTMIN + 46,
+    __SIGRTMIN + 47,
+    __SIGRTMIN + 48,
+    __SIGRTMIN + 49,
+    __SIGRTMIN + 50,
+    __SIGRTMIN + 51,
+    __SIGRTMIN + 52,
+    __SIGRTMIN + 53,
+    __SIGRTMIN + 54,
+    __SIGRTMIN + 55,
+    __SIGRTMIN + 56,
+    __SIGRTMIN + 57,
+    __SIGRTMIN + 58,
+    __SIGRTMIN + 59,
+    __SIGRTMIN + 60,
+    __SIGRTMIN + 61,
+    __SIGRTMIN + 62,
+    __SIGRTMIN + 63,
+    __SIGRTMIN + 64,
+    __SIGRTMIN + 65,
+    __SIGRTMIN + 66,
+    __SIGRTMIN + 67,
+    __SIGRTMIN + 68,
+    __SIGRTMIN + 69,
+    __SIGRTMIN + 70,
+    __SIGRTMIN + 71,
+    __SIGRTMIN + 72,
+    __SIGRTMIN + 73,
+    __SIGRTMIN + 74,
+    __SIGRTMIN + 75,
+    __SIGRTMIN + 76,
+    __SIGRTMIN + 77,
+    __SIGRTMIN + 78,
+    __SIGRTMIN + 79,
+    __SIGRTMIN + 80,
+    __SIGRTMIN + 81,
+    __SIGRTMIN + 82,
+    __SIGRTMIN + 83,
+    __SIGRTMIN + 84,
+    __SIGRTMIN + 85,
+    __SIGRTMIN + 86,
+    __SIGRTMIN + 87,
+    __SIGRTMIN + 88,
+    __SIGRTMIN + 89,
+    __SIGRTMIN + 90,
+    __SIGRTMIN + 91,
+    __SIGRTMIN + 92,
+    __SIGRTMIN + 93,
+    __SIGRTMIN + 94,
+    __SIGRTMIN + 95,
+    -1, /* SIGINFO */
+    -1, /* UNKNOWN */
+    -1, /* DEFAULT */
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1
+#endif
+};
+#else
+/* In system mode we only need SIGINT and SIGTRAP; other signals
+   are not yet supported.  */
+
+enum {
+    TARGET_SIGINT = 2,
+    TARGET_SIGTRAP = 5
+};
+
+static int gdb_signal_table[] = {
+    -1,
+    -1,
+    TARGET_SIGINT,
+    -1,
+    -1,
+    TARGET_SIGTRAP
+};
+#endif
+
+#ifdef CONFIG_USER_ONLY
+static int target_signal_to_gdb (int sig)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE (gdb_signal_table); i++)
+        if (gdb_signal_table[i] == sig)
+            return i;
+    return GDB_SIGNAL_UNKNOWN;
+}
+#endif
+
+static int gdb_signal_to_target (int sig)
+{
+    if (sig < ARRAY_SIZE (gdb_signal_table))
+        return gdb_signal_table[sig];
+    else
+        return -1;
+}
+
+//#define DEBUG_GDB
+
+typedef struct GDBRegisterState {
+    int base_reg;
+    int num_regs;
+    gdb_reg_cb get_reg;
+    gdb_reg_cb set_reg;
+    const char *xml;
+    struct GDBRegisterState *next;
+} GDBRegisterState;
+
+enum RSState {
+    RS_INACTIVE,
+    RS_IDLE,
+    RS_GETLINE,
+    RS_CHKSUM1,
+    RS_CHKSUM2,
+};
+typedef struct GDBState {
+    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;
+    int line_csum;
+    uint8_t last_packet[MAX_PACKET_LENGTH + 4];
+    int last_packet_len;
+    int signal;
+#ifdef CONFIG_USER_ONLY
+    int fd;
+    int running_state;
+#else
+    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
+ * make single stepping like an ICE HW step.
+ */
+static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
+
+static GDBState *gdbserver_state;
+
+bool gdb_has_xml;
+
+#ifdef CONFIG_USER_ONLY
+/* XXX: This is not thread safe.  Do we care?  */
+static int gdbserver_fd = -1;
+
+static int get_char(GDBState *s)
+{
+    uint8_t ch;
+    int ret;
+
+    for(;;) {
+        ret = qemu_recv(s->fd, &ch, 1, 0);
+        if (ret < 0) {
+            if (errno == ECONNRESET)
+                s->fd = -1;
+            if (errno != EINTR && errno != EAGAIN)
+                return -1;
+        } else if (ret == 0) {
+            close(s->fd);
+            s->fd = -1;
+            return -1;
+        } else {
+            break;
+        }
+    }
+    return ch;
+}
+#endif
+
+static enum {
+    GDB_SYS_UNKNOWN,
+    GDB_SYS_ENABLED,
+    GDB_SYS_DISABLED,
+} gdb_syscall_mode;
+
+/* Decide if either remote gdb syscalls or native file IO should be used. */
+int use_gdb_syscalls(void)
+{
+    SemihostingTarget target = semihosting_get_target();
+    if (target == SEMIHOSTING_TARGET_NATIVE) {
+        /* -semihosting-config target=native */
+        return false;
+    } else if (target == SEMIHOSTING_TARGET_GDB) {
+        /* -semihosting-config target=gdb */
+        return true;
+    }
+
+    /* -semihosting-config target=auto */
+    /* On the first call check if gdb is connected and remember. */
+    if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
+        gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
+                                            : GDB_SYS_DISABLED);
+    }
+    return gdb_syscall_mode == GDB_SYS_ENABLED;
+}
+
+/* Resume execution.  */
+static inline void gdb_continue(GDBState *s)
+{
+#ifdef CONFIG_USER_ONLY
+    s->running_state = 1;
+#else
+    if (!runstate_needs_reset()) {
+        vm_start();
+    }
+#endif
+}
+
+static void put_buffer(GDBState *s, const uint8_t *buf, int len)
+{
+#ifdef CONFIG_USER_ONLY
+    int ret;
+
+    while (len > 0) {
+        ret = send(s->fd, buf, len, 0);
+        if (ret < 0) {
+            if (errno != EINTR && errno != EAGAIN)
+                return;
+        } else {
+            buf += ret;
+            len -= ret;
+        }
+    }
+#else
+    qemu_chr_fe_write(s->chr, buf, len);
+#endif
+}
+
+static inline int fromhex(int v)
+{
+    if (v >= '0' && v <= '9')
+        return v - '0';
+    else if (v >= 'A' && v <= 'F')
+        return v - 'A' + 10;
+    else if (v >= 'a' && v <= 'f')
+        return v - 'a' + 10;
+    else
+        return 0;
+}
+
+static inline int tohex(int v)
+{
+    if (v < 10)
+        return v + '0';
+    else
+        return v - 10 + 'a';
+}
+
+static void memtohex(char *buf, const uint8_t *mem, int len)
+{
+    int i, c;
+    char *q;
+    q = buf;
+    for(i = 0; i < len; i++) {
+        c = mem[i];
+        *q++ = tohex(c >> 4);
+        *q++ = tohex(c & 0xf);
+    }
+    *q = '\0';
+}
+
+static void hextomem(uint8_t *mem, const char *buf, int len)
+{
+    int i;
+
+    for(i = 0; i < len; i++) {
+        mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
+        buf += 2;
+    }
+}
+
+/* return -1 if error, 0 if OK */
+static int put_packet_binary(GDBState *s, const char *buf, int len)
+{
+    int csum, i;
+    uint8_t *p;
+
+    for(;;) {
+        p = s->last_packet;
+        *(p++) = '$';
+        memcpy(p, buf, len);
+        p += len;
+        csum = 0;
+        for(i = 0; i < len; i++) {
+            csum += buf[i];
+        }
+        *(p++) = '#';
+        *(p++) = tohex((csum >> 4) & 0xf);
+        *(p++) = tohex((csum) & 0xf);
+
+        s->last_packet_len = p - s->last_packet;
+        put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+
+#ifdef CONFIG_USER_ONLY
+        i = get_char(s);
+        if (i < 0)
+            return -1;
+        if (i == '+')
+            break;
+#else
+        break;
+#endif
+    }
+    return 0;
+}
+
+/* return -1 if error, 0 if OK */
+static int put_packet(GDBState *s, const char *buf)
+{
+#ifdef DEBUG_GDB
+    printf("reply='%s'\n", buf);
+#endif
+
+    return put_packet_binary(s, buf, strlen(buf));
+}
+
+/* Encode data using the encoding for 'x' packets.  */
+static int memtox(char *buf, const char *mem, int len)
+{
+    char *p = buf;
+    char c;
+
+    while (len--) {
+        c = *(mem++);
+        switch (c) {
+        case '#': case '$': case '*': case '}':
+            *(p++) = '}';
+            *(p++) = c ^ 0x20;
+            break;
+        default:
+            *(p++) = c;
+            break;
+        }
+    }
+    return p - buf;
+}
+
+static const char *get_feature_xml(const char *p, const char **newp,
+                                   CPUClass *cc)
+{
+    size_t len;
+    int i;
+    const char *name;
+    static char target_xml[1024];
+
+    len = 0;
+    while (p[len] && p[len] != ':')
+        len++;
+    *newp = p + len;
+
+    name = NULL;
+    if (strncmp(p, "target.xml", len) == 0) {
+        /* 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\"?>"
+                     "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+                     "<target>"
+                     "<xi:include href=\"%s\"/>",
+                     cc->gdb_core_xml_file);
+
+            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), "\"/>");
+            }
+            pstrcat(target_xml, sizeof(target_xml), "</target>");
+        }
+        return target_xml;
+    }
+    for (i = 0; ; i++) {
+        name = xml_builtin[i][0];
+        if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len))
+            break;
+    }
+    return name ? xml_builtin[i][1] : NULL;
+}
+
+static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+    CPUArchState *env = cpu->env_ptr;
+    GDBRegisterState *r;
+
+    if (reg < cc->gdb_num_core_regs) {
+        return cc->gdb_read_register(cpu, mem_buf, reg);
+    }
+
+    for (r = cpu->gdb_regs; r; r = r->next) {
+        if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+            return r->get_reg(env, mem_buf, reg - r->base_reg);
+        }
+    }
+    return 0;
+}
+
+static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+    CPUArchState *env = cpu->env_ptr;
+    GDBRegisterState *r;
+
+    if (reg < cc->gdb_num_core_regs) {
+        return cc->gdb_write_register(cpu, mem_buf, reg);
+    }
+
+    for (r = cpu->gdb_regs; r; r = r->next) {
+        if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+            return r->set_reg(env, mem_buf, reg - r->base_reg);
+        }
+    }
+    return 0;
+}
+
+/* Register a supplemental set of CPU registers.  If g_pos is nonzero it
+   specifies the first register number and these registers are included in
+   a standard "g" packet.  Direction is relative to gdb, i.e. get_reg is
+   gdb reading a CPU register, and set_reg is gdb modifying a CPU register.
+ */
+
+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)
+{
+    GDBRegisterState *s;
+    GDBRegisterState **p;
+
+    p = &cpu->gdb_regs;
+    while (*p) {
+        /* Check for duplicates.  */
+        if (strcmp((*p)->xml, xml) == 0)
+            return;
+        p = &(*p)->next;
+    }
+
+    s = g_new0(GDBRegisterState, 1);
+    s->base_reg = cpu->gdb_num_regs;
+    s->num_regs = num_regs;
+    s->get_reg = get_reg;
+    s->set_reg = set_reg;
+    s->xml = xml;
+
+    /* Add to end of list.  */
+    cpu->gdb_num_regs += num_regs;
+    *p = s;
+    if (g_pos) {
+        if (g_pos != s->base_reg) {
+            fprintf(stderr, "Error: Bad gdb register numbering for '%s'\n"
+                    "Expected %d got %d\n", xml, g_pos, s->base_reg);
+        } else {
+            cpu->gdb_num_g_regs = cpu->gdb_num_regs;
+        }
+    }
+}
+
+#ifndef CONFIG_USER_ONLY
+/* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */
+static inline int xlat_gdb_type(CPUState *cpu, int gdbtype)
+{
+    static const int xlat[] = {
+        [GDB_WATCHPOINT_WRITE]  = BP_GDB | BP_MEM_WRITE,
+        [GDB_WATCHPOINT_READ]   = BP_GDB | BP_MEM_READ,
+        [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS,
+    };
+
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+    int cputype = xlat[gdbtype];
+
+    if (cc->gdb_stop_before_watchpoint) {
+        cputype |= BP_STOP_BEFORE_ACCESS;
+    }
+    return cputype;
+}
+#endif
+
+static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
+{
+    CPUState *cpu;
+    int err = 0;
+
+    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, addr, BP_GDB, NULL);
+            if (err) {
+                break;
+            }
+        }
+        return err;
+#ifndef CONFIG_USER_ONLY
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_ACCESS:
+        CPU_FOREACH(cpu) {
+            err = cpu_watchpoint_insert(cpu, addr, len,
+                                        xlat_gdb_type(cpu, type), NULL);
+            if (err) {
+                break;
+            }
+        }
+        return err;
+#endif
+    default:
+        return -ENOSYS;
+    }
+}
+
+static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
+{
+    CPUState *cpu;
+    int err = 0;
+
+    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, addr, BP_GDB);
+            if (err) {
+                break;
+            }
+        }
+        return err;
+#ifndef CONFIG_USER_ONLY
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_ACCESS:
+        CPU_FOREACH(cpu) {
+            err = cpu_watchpoint_remove(cpu, addr, len,
+                                        xlat_gdb_type(cpu, type));
+            if (err)
+                break;
+        }
+        return err;
+#endif
+    default:
+        return -ENOSYS;
+    }
+}
+
+static void gdb_breakpoint_remove_all(void)
+{
+    CPUState *cpu;
+
+    if (kvm_enabled()) {
+        kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
+        return;
+    }
+
+    CPU_FOREACH(cpu) {
+        cpu_breakpoint_remove_all(cpu, BP_GDB);
+#ifndef CONFIG_USER_ONLY
+        cpu_watchpoint_remove_all(cpu, BP_GDB);
+#endif
+    }
+}
+
+static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
+{
+    CPUState *cpu = s->c_cpu;
+
+    cpu_synchronize_state(cpu);
+    cpu_set_pc(cpu, pc);
+}
+
+static CPUState *find_cpu(uint32_t thread_id)
+{
+    CPUState *cpu;
+
+    CPU_FOREACH(cpu) {
+        if (cpu_index(cpu) == thread_id) {
+            return cpu;
+        }
+    }
+
+    return NULL;
+}
+
+static int is_query_packet(const char *p, const char *query, char separator)
+{
+    unsigned int query_len = strlen(query);
+
+    return strncmp(p, query, query_len) == 0 &&
+        (p[query_len] == '\0' || p[query_len] == separator);
+}
+
+static int gdb_handle_packet(GDBState *s, const char *line_buf)
+{
+    CPUState *cpu;
+    CPUClass *cc;
+    const char *p;
+    uint32_t thread;
+    int ch, reg_size, type, res;
+    char buf[MAX_PACKET_LENGTH];
+    uint8_t mem_buf[MAX_PACKET_LENGTH];
+    uint8_t *registers;
+    target_ulong addr, len;
+
+#ifdef DEBUG_GDB
+    printf("command='%s'\n", line_buf);
+#endif
+    p = line_buf;
+    ch = *p++;
+    switch(ch) {
+    case '?':
+        /* TODO: Make this return the correct value for user-mode.  */
+        snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
+                 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
+         * should be cleaned up.
+         */
+        gdb_breakpoint_remove_all();
+        break;
+    case 'c':
+        if (*p != '\0') {
+            addr = strtoull(p, (char **)&p, 16);
+            gdb_set_cpu_pc(s, addr);
+        }
+        s->signal = 0;
+        gdb_continue(s);
+       return RS_IDLE;
+    case 'C':
+        s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
+        if (s->signal == -1)
+            s->signal = 0;
+        gdb_continue(s);
+        return RS_IDLE;
+    case 'v':
+        if (strncmp(p, "Cont", 4) == 0) {
+            int res_signal, res_thread;
+
+            p += 4;
+            if (*p == '?') {
+                put_packet(s, "vCont;c;C;s;S");
+                break;
+            }
+            res = 0;
+            res_signal = 0;
+            res_thread = 0;
+            while (*p) {
+                int action, signal;
+
+                if (*p++ != ';') {
+                    res = 0;
+                    break;
+                }
+                action = *p++;
+                signal = 0;
+                if (action == 'C' || action == 'S') {
+                    signal = gdb_signal_to_target(strtoul(p, (char **)&p, 16));
+                    if (signal == -1) {
+                        signal = 0;
+                    }
+                } else if (action != 'c' && action != 's') {
+                    res = 0;
+                    break;
+                }
+                thread = 0;
+                if (*p == ':') {
+                    thread = strtoull(p+1, (char **)&p, 16);
+                }
+                action = tolower(action);
+                if (res == 0 || (res == 'c' && action == 's')) {
+                    res = action;
+                    res_signal = signal;
+                    res_thread = thread;
+                }
+            }
+            if (res) {
+                if (res_thread != -1 && res_thread != 0) {
+                    cpu = find_cpu(res_thread);
+                    if (cpu == NULL) {
+                        put_packet(s, "E22");
+                        break;
+                    }
+                    s->c_cpu = cpu;
+                }
+                if (res == 's') {
+                    cpu_single_step(s->c_cpu, sstep_flags);
+                }
+                s->signal = res_signal;
+                gdb_continue(s);
+                return RS_IDLE;
+            }
+            break;
+        } else {
+            goto unknown_command;
+        }
+    case 'k':
+        /* Kill the target */
+        fprintf(stderr, "\nQEMU: Terminated via GDBstub\n");
+        exit(0);
+    case 'D':
+        /* Detach packet */
+        gdb_breakpoint_remove_all();
+        gdb_syscall_mode = GDB_SYS_DISABLED;
+        gdb_continue(s);
+        put_packet(s, "OK");
+        break;
+    case 's':
+        if (*p != '\0') {
+            addr = strtoull(p, (char **)&p, 16);
+            gdb_set_cpu_pc(s, addr);
+        }
+        cpu_single_step(s->c_cpu, sstep_flags);
+        gdb_continue(s);
+       return RS_IDLE;
+    case 'F':
+        {
+            target_ulong ret;
+            target_ulong err;
+
+            ret = strtoull(p, (char **)&p, 16);
+            if (*p == ',') {
+                p++;
+                err = strtoull(p, (char **)&p, 16);
+            } else {
+                err = 0;
+            }
+            if (*p == ',')
+                p++;
+            type = *p;
+            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 {
+                gdb_continue(s);
+            }
+        }
+        break;
+    case 'g':
+        cpu_synchronize_state(s->g_cpu);
+        len = 0;
+        for (addr = 0; addr < s->g_cpu->gdb_num_g_regs; addr++) {
+            reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
+            len += reg_size;
+        }
+        memtohex(buf, mem_buf, len);
+        put_packet(s, buf);
+        break;
+    case 'G':
+        cpu_synchronize_state(s->g_cpu);
+        registers = mem_buf;
+        len = strlen(p) / 2;
+        hextomem((uint8_t *)registers, p, len);
+        for (addr = 0; addr < s->g_cpu->gdb_num_g_regs && len > 0; addr++) {
+            reg_size = gdb_write_register(s->g_cpu, registers, addr);
+            len -= reg_size;
+            registers += reg_size;
+        }
+        put_packet(s, "OK");
+        break;
+    case 'm':
+        addr = strtoull(p, (char **)&p, 16);
+        if (*p == ',')
+            p++;
+        len = strtoull(p, NULL, 16);
+        if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, false) != 0) {
+            put_packet (s, "E14");
+        } else {
+            memtohex(buf, mem_buf, len);
+            put_packet(s, buf);
+        }
+        break;
+    case 'M':
+        addr = strtoull(p, (char **)&p, 16);
+        if (*p == ',')
+            p++;
+        len = strtoull(p, (char **)&p, 16);
+        if (*p == ':')
+            p++;
+        hextomem(mem_buf, p, len);
+        if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len,
+                                   true) != 0) {
+            put_packet(s, "E14");
+        } else {
+            put_packet(s, "OK");
+        }
+        break;
+    case 'p':
+        /* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
+           This works, but can be very slow.  Anything new enough to
+           understand XML also knows how to use this properly.  */
+        if (!gdb_has_xml)
+            goto unknown_command;
+        addr = strtoull(p, (char **)&p, 16);
+        reg_size = gdb_read_register(s->g_cpu, mem_buf, addr);
+        if (reg_size) {
+            memtohex(buf, mem_buf, reg_size);
+            put_packet(s, buf);
+        } else {
+            put_packet(s, "E14");
+        }
+        break;
+    case 'P':
+        if (!gdb_has_xml)
+            goto unknown_command;
+        addr = strtoull(p, (char **)&p, 16);
+        if (*p == '=')
+            p++;
+        reg_size = strlen(p) / 2;
+        hextomem(mem_buf, p, reg_size);
+        gdb_write_register(s->g_cpu, mem_buf, addr);
+        put_packet(s, "OK");
+        break;
+    case 'Z':
+    case 'z':
+        type = strtoul(p, (char **)&p, 16);
+        if (*p == ',')
+            p++;
+        addr = strtoull(p, (char **)&p, 16);
+        if (*p == ',')
+            p++;
+        len = strtoull(p, (char **)&p, 16);
+        if (ch == 'Z')
+            res = gdb_breakpoint_insert(addr, len, type);
+        else
+            res = gdb_breakpoint_remove(addr, len, type);
+        if (res >= 0)
+             put_packet(s, "OK");
+        else if (res == -ENOSYS)
+            put_packet(s, "");
+        else
+            put_packet(s, "E22");
+        break;
+    case 'H':
+        type = *p++;
+        thread = strtoull(p, (char **)&p, 16);
+        if (thread == -1 || thread == 0) {
+            put_packet(s, "OK");
+            break;
+        }
+        cpu = find_cpu(thread);
+        if (cpu == NULL) {
+            put_packet(s, "E22");
+            break;
+        }
+        switch (type) {
+        case 'c':
+            s->c_cpu = cpu;
+            put_packet(s, "OK");
+            break;
+        case 'g':
+            s->g_cpu = cpu;
+            put_packet(s, "OK");
+            break;
+        default:
+             put_packet(s, "E22");
+             break;
+        }
+        break;
+    case 'T':
+        thread = strtoull(p, (char **)&p, 16);
+        cpu = find_cpu(thread);
+
+        if (cpu != NULL) {
+            put_packet(s, "OK");
+        } else {
+            put_packet(s, "E22");
+        }
+        break;
+    case 'q':
+    case 'Q':
+        /* parse any 'q' packets here */
+        if (!strcmp(p,"qemu.sstepbits")) {
+            /* Query Breakpoint bit definitions */
+            snprintf(buf, sizeof(buf), "ENABLE=%x,NOIRQ=%x,NOTIMER=%x",
+                     SSTEP_ENABLE,
+                     SSTEP_NOIRQ,
+                     SSTEP_NOTIMER);
+            put_packet(s, buf);
+            break;
+        } else if (is_query_packet(p, "qemu.sstep", '=')) {
+            /* Display or change the sstep_flags */
+            p += 10;
+            if (*p != '=') {
+                /* Display current setting */
+                snprintf(buf, sizeof(buf), "0x%x", sstep_flags);
+                put_packet(s, buf);
+                break;
+            }
+            p++;
+            type = strtoul(p, (char **)&p, 16);
+            sstep_flags = type;
+            put_packet(s, "OK");
+            break;
+        } else if (strcmp(p,"C") == 0) {
+            /* "Current thread" remains vague in the spec, so always return
+             *  the first CPU (gdb returns the first thread). */
+            put_packet(s, "QC1");
+            break;
+        } else if (strcmp(p,"fThreadInfo") == 0) {
+            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", cpu_index(s->query_cpu));
+                put_packet(s, buf);
+                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);
+            cpu = find_cpu(thread);
+            if (cpu != NULL) {
+                cpu_synchronize_state(cpu);
+                len = snprintf((char *)mem_buf, sizeof(mem_buf),
+                               "CPU#%d [%s]", cpu->cpu_index,
+                               cpu->halted ? "halted " : "running");
+                memtohex(buf, mem_buf, len);
+                put_packet(s, buf);
+            }
+            break;
+        }
+#ifdef CONFIG_USER_ONLY
+        else if (strcmp(p, "Offsets") == 0) {
+            TaskState *ts = s->c_cpu->opaque;
+
+            snprintf(buf, sizeof(buf),
+                     "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
+                     ";Bss=" TARGET_ABI_FMT_lx,
+                     ts->info->code_offset,
+                     ts->info->data_offset,
+                     ts->info->data_offset);
+            put_packet(s, buf);
+            break;
+        }
+#else /* !CONFIG_USER_ONLY */
+        else if (strncmp(p, "Rcmd,", 5) == 0) {
+            int len = strlen(p + 5);
+
+            if ((len % 2) != 0) {
+                put_packet(s, "E01");
+                break;
+            }
+            hextomem(mem_buf, p + 5, len);
+            len = len / 2;
+            mem_buf[len++] = 0;
+            qemu_chr_be_write(s->mon_chr, mem_buf, len);
+            put_packet(s, "OK");
+            break;
+        }
+#endif /* !CONFIG_USER_ONLY */
+        if (is_query_packet(p, "Supported", ':')) {
+            snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH);
+            cc = CPU_GET_CLASS(first_cpu);
+            if (cc->gdb_core_xml_file != NULL) {
+                pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
+            }
+            put_packet(s, buf);
+            break;
+        }
+        if (strncmp(p, "Xfer:features:read:", 19) == 0) {
+            const char *xml;
+            target_ulong total_len;
+
+            cc = CPU_GET_CLASS(first_cpu);
+            if (cc->gdb_core_xml_file == NULL) {
+                goto unknown_command;
+            }
+
+            gdb_has_xml = true;
+            p += 19;
+            xml = get_feature_xml(p, &p, cc);
+            if (!xml) {
+                snprintf(buf, sizeof(buf), "E00");
+                put_packet(s, buf);
+                break;
+            }
+
+            if (*p == ':')
+                p++;
+            addr = strtoul(p, (char **)&p, 16);
+            if (*p == ',')
+                p++;
+            len = strtoul(p, (char **)&p, 16);
+
+            total_len = strlen(xml);
+            if (addr > total_len) {
+                snprintf(buf, sizeof(buf), "E00");
+                put_packet(s, buf);
+                break;
+            }
+            if (len > (MAX_PACKET_LENGTH - 5) / 2)
+                len = (MAX_PACKET_LENGTH - 5) / 2;
+            if (len < total_len - addr) {
+                buf[0] = 'm';
+                len = memtox(buf + 1, xml + addr, len);
+            } else {
+                buf[0] = 'l';
+                len = memtox(buf + 1, xml + addr, total_len - addr);
+            }
+            put_packet_binary(s, buf, len + 1);
+            break;
+        }
+        if (is_query_packet(p, "Attached", ':')) {
+            put_packet(s, GDB_ATTACHED);
+            break;
+        }
+        /* Unrecognised 'q' command.  */
+        goto unknown_command;
+
+    default:
+    unknown_command:
+        /* put empty packet */
+        buf[0] = '\0';
+        put_packet(s, buf);
+        break;
+    }
+    return RS_IDLE;
+}
+
+void gdb_set_stop_cpu(CPUState *cpu)
+{
+    gdbserver_state->c_cpu = cpu;
+    gdbserver_state->g_cpu = cpu;
+}
+
+#ifndef CONFIG_USER_ONLY
+static void gdb_vm_state_change(void *opaque, int running, RunState state)
+{
+    GDBState *s = gdbserver_state;
+    CPUState *cpu = s->c_cpu;
+    char buf[256];
+    const char *type;
+    int ret;
+
+    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) {
+    case RUN_STATE_DEBUG:
+        if (cpu->watchpoint_hit) {
+            switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) {
+            case BP_MEM_READ:
+                type = "r";
+                break;
+            case BP_MEM_ACCESS:
+                type = "a";
+                break;
+            default:
+                type = "";
+                break;
+            }
+            snprintf(buf, sizeof(buf),
+                     "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
+                     GDB_SIGNAL_TRAP, cpu_index(cpu), type,
+                     (target_ulong)cpu->watchpoint_hit->vaddr);
+            cpu->watchpoint_hit = NULL;
+            goto send_packet;
+        }
+        tb_flush(cpu);
+        ret = GDB_SIGNAL_TRAP;
+        break;
+    case RUN_STATE_PAUSED:
+        ret = GDB_SIGNAL_INT;
+        break;
+    case RUN_STATE_SHUTDOWN:
+        ret = GDB_SIGNAL_QUIT;
+        break;
+    case RUN_STATE_IO_ERROR:
+        ret = GDB_SIGNAL_IO;
+        break;
+    case RUN_STATE_WATCHDOG:
+        ret = GDB_SIGNAL_ALRM;
+        break;
+    case RUN_STATE_INTERNAL_ERROR:
+        ret = GDB_SIGNAL_ABRT;
+        break;
+    case RUN_STATE_SAVE_VM:
+    case RUN_STATE_RESTORE_VM:
+        return;
+    case RUN_STATE_FINISH_MIGRATE:
+        ret = GDB_SIGNAL_XCPU;
+        break;
+    default:
+        ret = GDB_SIGNAL_UNKNOWN;
+        break;
+    }
+    gdb_set_stop_cpu(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
+
+/* Send a gdb syscall request.
+   This accepts limited printf-style format specifiers, specifically:
+    %x  - target_ulong argument printed in hex.
+    %lx - 64-bit argument printed in hex.
+    %s  - string pointer (target_ulong) and length (int) pair.  */
+void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
+{
+    va_list va;
+    char *p;
+    char *p_end;
+    target_ulong addr;
+    uint64_t i64;
+    GDBState *s;
+
+    s = gdbserver_state;
+    if (!s)
+        return;
+    s->current_syscall_cb = cb;
+#ifndef CONFIG_USER_ONLY
+    vm_stop(RUN_STATE_DEBUG);
+#endif
+    va_start(va, fmt);
+    p = s->syscall_buf;
+    p_end = &s->syscall_buf[sizeof(s->syscall_buf)];
+    *(p++) = 'F';
+    while (*fmt) {
+        if (*fmt == '%') {
+            fmt++;
+            switch (*fmt++) {
+            case 'x':
+                addr = va_arg(va, target_ulong);
+                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, p_end - p, "%" PRIx64, i64);
+                break;
+            case 's':
+                addr = va_arg(va, target_ulong);
+                p += snprintf(p, p_end - p, TARGET_FMT_lx "/%x",
+                              addr, va_arg(va, int));
+                break;
+            default:
+            bad_format:
+                fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n",
+                        fmt - 1);
+                break;
+            }
+        } else {
+            *(p++) = *(fmt++);
+        }
+    }
+    *p = 0;
+    va_end(va);
+#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
+}
+
+static void gdb_read_byte(GDBState *s, int ch)
+{
+    int i, csum;
+    uint8_t reply;
+
+#ifndef CONFIG_USER_ONLY
+    if (s->last_packet_len) {
+        /* Waiting for a response to the last packet.  If we see the start
+           of a new command then abandon the previous response.  */
+        if (ch == '-') {
+#ifdef DEBUG_GDB
+            printf("Got NACK, retransmitting\n");
+#endif
+            put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+        }
+#ifdef DEBUG_GDB
+        else if (ch == '+')
+            printf("Got ACK\n");
+        else
+            printf("Got '%c' when expecting ACK/NACK\n", ch);
+#endif
+        if (ch == '+' || ch == '$')
+            s->last_packet_len = 0;
+        if (ch != '$')
+            return;
+    }
+    if (runstate_is_running()) {
+        /* when the CPU is running, we cannot do anything except stop
+           it when receiving a char */
+        vm_stop(RUN_STATE_PAUSED);
+    } else
+#endif
+    {
+        switch(s->state) {
+        case RS_IDLE:
+            if (ch == '$') {
+                s->line_buf_index = 0;
+                s->state = RS_GETLINE;
+            }
+            break;
+        case RS_GETLINE:
+            if (ch == '#') {
+            s->state = RS_CHKSUM1;
+            } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+                s->state = RS_IDLE;
+            } else {
+            s->line_buf[s->line_buf_index++] = ch;
+            }
+            break;
+        case RS_CHKSUM1:
+            s->line_buf[s->line_buf_index] = '\0';
+            s->line_csum = fromhex(ch) << 4;
+            s->state = RS_CHKSUM2;
+            break;
+        case RS_CHKSUM2:
+            s->line_csum |= fromhex(ch);
+            csum = 0;
+            for(i = 0; i < s->line_buf_index; i++) {
+                csum += s->line_buf[i];
+            }
+            if (s->line_csum != (csum & 0xff)) {
+                reply = '-';
+                put_buffer(s, &reply, 1);
+                s->state = RS_IDLE;
+            } else {
+                reply = '+';
+                put_buffer(s, &reply, 1);
+                s->state = gdb_handle_packet(s, s->line_buf);
+            }
+            break;
+        default:
+            abort();
+        }
+    }
+}
+
+/* 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;
+  }
+#else
+  if (!s->chr) {
+      return;
+  }
+#endif
+
+  snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
+  put_packet(s, buf);
+
+#ifndef CONFIG_USER_ONLY
+  qemu_chr_delete(s->chr);
+#endif
+}
+
+#ifdef CONFIG_USER_ONLY
+int
+gdb_queuesig (void)
+{
+    GDBState *s;
+
+    s = gdbserver_state;
+
+    if (gdbserver_fd < 0 || s->fd < 0)
+        return 0;
+    else
+        return 1;
+}
+
+int
+gdb_handlesig(CPUState *cpu, int sig)
+{
+    GDBState *s;
+    char buf[256];
+    int n;
+
+    s = gdbserver_state;
+    if (gdbserver_fd < 0 || s->fd < 0) {
+        return sig;
+    }
+
+    /* disable single step if it was enabled */
+    cpu_single_step(cpu, 0);
+    tb_flush(cpu);
+
+    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) {
+        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) {
+            int 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 another
+               connection before continuing.  */
+            return sig;
+        }
+    }
+    sig = s->signal;
+    s->signal = 0;
+    return sig;
+}
+
+/* Tell the remote gdb that the process has exited due to SIG.  */
+void gdb_signalled(CPUArchState *env, int sig)
+{
+    GDBState *s;
+    char buf[4];
+
+    s = gdbserver_state;
+    if (gdbserver_fd < 0 || s->fd < 0) {
+        return;
+    }
+
+    snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb(sig));
+    put_packet(s, buf);
+}
+
+static void gdb_accept(void)
+{
+    GDBState *s;
+    struct sockaddr_in sockaddr;
+    socklen_t len;
+    int fd;
+
+    for(;;) {
+        len = sizeof(sockaddr);
+        fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len);
+        if (fd < 0 && errno != EINTR) {
+            perror("accept");
+            return;
+        } else if (fd >= 0) {
+#ifndef _WIN32
+            fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+            break;
+        }
+    }
+
+    /* set short latency */
+    socket_set_nodelay(fd);
+
+    s = g_malloc0(sizeof(GDBState));
+    s->c_cpu = first_cpu;
+    s->g_cpu = first_cpu;
+    s->fd = fd;
+    gdb_has_xml = false;
+
+    gdbserver_state = s;
+
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+}
+
+static int gdbserver_open(int port)
+{
+    struct sockaddr_in sockaddr;
+    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
+
+    socket_set_fast_reuse(fd);
+
+    sockaddr.sin_family = AF_INET;
+    sockaddr.sin_port = htons(port);
+    sockaddr.sin_addr.s_addr = 0;
+    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;
+}
+
+int gdbserver_start(int port)
+{
+    gdbserver_fd = gdbserver_open(port);
+    if (gdbserver_fd < 0)
+        return -1;
+    /* accept connections */
+    gdb_accept();
+    return 0;
+}
+
+/* Disable gdb stub for child processes.  */
+void gdbserver_fork(CPUState *cpu)
+{
+    GDBState *s = gdbserver_state;
+
+    if (gdbserver_fd < 0 || s->fd < 0) {
+        return;
+    }
+    close(s->fd);
+    s->fd = -1;
+    cpu_breakpoint_remove_all(cpu, BP_GDB);
+    cpu_watchpoint_remove_all(cpu, BP_GDB);
+}
+#else
+static int gdb_chr_can_receive(void *opaque)
+{
+  /* We can handle an arbitrarily large amount of data.
+   Pick the maximum packet size, which is as good as anything.  */
+  return MAX_PACKET_LENGTH;
+}
+
+static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
+{
+    int i;
+
+    for (i = 0; i < size; i++) {
+        gdb_read_byte(gdbserver_state, buf[i]);
+    }
+}
+
+static void gdb_chr_event(void *opaque, int event)
+{
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        vm_stop(RUN_STATE_PAUSED);
+        gdb_has_xml = 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;
+    int max_sz;
+
+    max_sz = (sizeof(gdbserver_state->last_packet) - 2) / 2;
+    for (;;) {
+        if (len <= max_sz) {
+            gdb_monitor_output(gdbserver_state, p, len);
+            break;
+        }
+        gdb_monitor_output(gdbserver_state, p, max_sz);
+        p += max_sz;
+        len -= max_sz;
+    }
+    return len;
+}
+
+#ifndef _WIN32
+static void gdb_sigterm_handler(int signal)
+{
+    if (runstate_is_running()) {
+        vm_stop(RUN_STATE_PAUSED);
+    }
+}
+#endif
+
+int gdbserver_start(const char *device)
+{
+    GDBState *s;
+    char gdbstub_device_name[128];
+    CharDriverState *chr = NULL;
+    CharDriverState *mon_chr;
+
+    if (!device)
+        return -1;
+    if (strcmp(device, "none") != 0) {
+        if (strstart(device, "tcp:", NULL)) {
+            /* enforce required TCP attributes */
+            snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
+                     "%s,nowait,nodelay,server", device);
+            device = gdbstub_device_name;
+        }
+#ifndef _WIN32
+        else if (strcmp(device, "stdio") == 0) {
+            struct sigaction act;
+
+            memset(&act, 0, sizeof(act));
+            act.sa_handler = gdb_sigterm_handler;
+            sigaction(SIGINT, &act, NULL);
+        }
+#endif
+        chr = qemu_chr_new("gdb", device, NULL);
+        if (!chr)
+            return -1;
+
+        qemu_chr_fe_claim_no_fail(chr);
+        qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
+                              gdb_chr_event, NULL);
+    }
+
+    s = gdbserver_state;
+    if (!s) {
+        s = g_malloc0(sizeof(GDBState));
+        gdbserver_state = s;
+
+        qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
+
+        /* Initialize a monitor terminal for gdb */
+        mon_chr = qemu_chr_alloc();
+        mon_chr->chr_write = gdb_monitor_write;
+        monitor_init(mon_chr, 0);
+    } else {
+        if (s->chr)
+            qemu_chr_delete(s->chr);
+        mon_chr = s->mon_chr;
+        memset(s, 0, sizeof(GDBState));
+    }
+    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;
+}
+#endif