qcow2: Allow different cluster sizes
[qemu] / gdbstub.c
index d549766..3c34741 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -39,6 +39,7 @@
 #define MAX_PACKET_LENGTH 4096
 
 #include "qemu_socket.h"
+#include "kvm.h"
 
 
 enum {
@@ -264,6 +265,7 @@ typedef struct GDBRegisterState {
 } GDBRegisterState;
 
 enum RSState {
+    RS_INACTIVE,
     RS_IDLE,
     RS_GETLINE,
     RS_CHKSUM1,
@@ -332,7 +334,7 @@ static int get_char(GDBState *s)
 
 static gdb_syscall_complete_cb gdb_current_syscall_cb;
 
-enum {
+static enum {
     GDB_SYS_UNKNOWN,
     GDB_SYS_ENABLED,
     GDB_SYS_DISABLED,
@@ -1331,11 +1333,11 @@ static const char *get_feature_xml(const char *p, const char **newp)
                      GDB_CORE_XML);
 
             for (r = first_cpu->gdb_regs; r; r = r->next) {
-                strcat(target_xml, "<xi:include href=\"");
-                strcat(target_xml, r->xml);
-                strcat(target_xml, "\"/>");
+                pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
+                pstrcat(target_xml, sizeof(target_xml), r->xml);
+                pstrcat(target_xml, sizeof(target_xml), "\"/>");
             }
-            strcat(target_xml, "</target>");
+            pstrcat(target_xml, sizeof(target_xml), "</target>");
         }
         return target_xml;
     }
@@ -1418,13 +1420,6 @@ void gdb_register_coprocessor(CPUState * env,
     }
 }
 
-/* GDB breakpoint/watchpoint types */
-#define GDB_BREAKPOINT_SW        0
-#define GDB_BREAKPOINT_HW        1
-#define GDB_WATCHPOINT_WRITE     2
-#define GDB_WATCHPOINT_READ      3
-#define GDB_WATCHPOINT_ACCESS    4
-
 #ifndef CONFIG_USER_ONLY
 static const int xlat_gdb_type[] = {
     [GDB_WATCHPOINT_WRITE]  = BP_GDB | BP_MEM_WRITE,
@@ -1438,6 +1433,9 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
     CPUState *env;
     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:
@@ -1469,6 +1467,9 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
     CPUState *env;
     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:
@@ -1498,6 +1499,11 @@ static void gdb_breakpoint_remove_all(void)
 {
     CPUState *env;
 
+    if (kvm_enabled()) {
+        kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
+        return;
+    }
+
     for (env = first_cpu; env != NULL; env = env->next_cpu) {
         cpu_breakpoint_remove_all(env, BP_GDB);
 #ifndef CONFIG_USER_ONLY
@@ -1506,6 +1512,29 @@ static void gdb_breakpoint_remove_all(void)
     }
 }
 
+static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
+{
+#if defined(TARGET_I386)
+    s->c_cpu->eip = pc;
+    cpu_synchronize_state(s->c_cpu, 1);
+#elif defined (TARGET_PPC)
+    s->c_cpu->nip = pc;
+#elif defined (TARGET_SPARC)
+    s->c_cpu->pc = pc;
+    s->c_cpu->npc = pc + 4;
+#elif defined (TARGET_ARM)
+    s->c_cpu->regs[15] = pc;
+#elif defined (TARGET_SH4)
+    s->c_cpu->pc = pc;
+#elif defined (TARGET_MIPS)
+    s->c_cpu->active_tc.PC = pc;
+#elif defined (TARGET_CRIS)
+    s->c_cpu->pc = pc;
+#elif defined (TARGET_ALPHA)
+    s->c_cpu->pc = pc;
+#endif
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
     CPUState *env;
@@ -1536,24 +1565,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
     case 'c':
         if (*p != '\0') {
             addr = strtoull(p, (char **)&p, 16);
-#if defined(TARGET_I386)
-            s->c_cpu->eip = addr;
-#elif defined (TARGET_PPC)
-            s->c_cpu->nip = addr;
-#elif defined (TARGET_SPARC)
-            s->c_cpu->pc = addr;
-            s->c_cpu->npc = addr + 4;
-#elif defined (TARGET_ARM)
-            s->c_cpu->regs[15] = addr;
-#elif defined (TARGET_SH4)
-            s->c_cpu->pc = addr;
-#elif defined (TARGET_MIPS)
-            s->c_cpu->active_tc.PC = addr;
-#elif defined (TARGET_CRIS)
-            s->c_cpu->pc = addr;
-#elif defined (TARGET_ALPHA)
-            s->c_cpu->pc = addr;
-#endif
+            gdb_set_cpu_pc(s, addr);
         }
         s->signal = 0;
         gdb_continue(s);
@@ -1577,24 +1589,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
     case 's':
         if (*p != '\0') {
             addr = strtoull(p, (char **)&p, 16);
-#if defined(TARGET_I386)
-            s->c_cpu->eip = addr;
-#elif defined (TARGET_PPC)
-            s->c_cpu->nip = addr;
-#elif defined (TARGET_SPARC)
-            s->c_cpu->pc = addr;
-            s->c_cpu->npc = addr + 4;
-#elif defined (TARGET_ARM)
-            s->c_cpu->regs[15] = addr;
-#elif defined (TARGET_SH4)
-            s->c_cpu->pc = addr;
-#elif defined (TARGET_MIPS)
-            s->c_cpu->active_tc.PC = addr;
-#elif defined (TARGET_CRIS)
-            s->c_cpu->pc = addr;
-#elif defined (TARGET_ALPHA)
-            s->c_cpu->pc = addr;
-#endif
+            gdb_set_cpu_pc(s, addr);
         }
         cpu_single_step(s->c_cpu, sstep_flags);
         gdb_continue(s);
@@ -1624,6 +1619,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         }
         break;
     case 'g':
+        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);
@@ -1641,6 +1637,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             len -= reg_size;
             registers += reg_size;
         }
+        cpu_synchronize_state(s->g_cpu, 1);
         put_packet(s, "OK");
         break;
     case 'm':
@@ -1799,6 +1796,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             thread = strtoull(p+16, (char **)&p, 16);
             for (env = first_cpu; env != NULL; env = env->next_cpu)
                 if (env->cpu_index + 1 == thread) {
+                    cpu_synchronize_state(env, 0);
                     len = snprintf((char *)mem_buf, sizeof(mem_buf),
                                    "CPU#%d [%s]", env->cpu_index,
                                    env->halted ? "halted " : "running");
@@ -1840,7 +1838,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         if (strncmp(p, "Supported", 9) == 0) {
             snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH);
 #ifdef GDB_CORE_XML
-            strcat(buf, ";qXfer:features:read+");
+            pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
 #endif
             put_packet(s, buf);
             break;
@@ -1914,7 +1912,7 @@ static void gdb_vm_state_change(void *opaque, int running, int reason)
     int ret;
 
     if (running || (reason != EXCP_DEBUG && reason != EXCP_INTERRUPT) ||
-        s->state == RS_SYSCALL)
+        s->state == RS_INACTIVE || s->state == RS_SYSCALL)
         return;
 
     /* disable single step if it was enable */
@@ -2012,7 +2010,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
 #ifdef CONFIG_USER_ONLY
     gdb_handlesig(s->c_cpu, 0);
 #else
-    cpu_interrupt(s->c_cpu, CPU_INTERRUPT_EXIT);
+    cpu_exit(s->c_cpu);
 #endif
 }
 
@@ -2206,8 +2204,6 @@ static void gdb_accept(void)
     setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
 
     s = qemu_mallocz(sizeof(GDBState));
-
-    memset (s, 0, sizeof (GDBState));
     s->c_cpu = first_cpu;
     s->g_cpu = first_cpu;
     s->fd = fd;
@@ -2328,42 +2324,69 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
     return len;
 }
 
-int gdbserver_start(const char *port)
+#ifndef _WIN32
+static void gdb_sigterm_handler(int signal)
+{
+    if (vm_running)
+        vm_stop(EXCP_INTERRUPT);
+}
+#endif
+
+int gdbserver_start(const char *device)
 {
     GDBState *s;
-    char gdbstub_port_name[128];
-    int port_num;
-    char *p;
-    CharDriverState *chr;
+    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;
 
-    if (!port || !*port)
-      return -1;
+            memset(&act, 0, sizeof(act));
+            act.sa_handler = gdb_sigterm_handler;
+            sigaction(SIGINT, &act, NULL);
+        }
+#endif
+        chr = qemu_chr_open("gdb", device, NULL);
+        if (!chr)
+            return -1;
 
-    port_num = strtol(port, &p, 10);
-    if (*p == 0) {
-        /* A numeric value is interpreted as a port number.  */
-        snprintf(gdbstub_port_name, sizeof(gdbstub_port_name),
-                 "tcp::%d,nowait,nodelay,server", port_num);
-        port = gdbstub_port_name;
+        qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
+                              gdb_chr_event, NULL);
     }
 
-    chr = qemu_chr_open("gdb", port, NULL);
-    if (!chr)
-        return -1;
+    s = gdbserver_state;
+    if (!s) {
+        s = qemu_mallocz(sizeof(GDBState));
+        gdbserver_state = s;
 
-    s = qemu_mallocz(sizeof(GDBState));
+        qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
+
+        /* Initialize a monitor terminal for gdb */
+        mon_chr = qemu_mallocz(sizeof(*mon_chr));
+        mon_chr->chr_write = gdb_monitor_write;
+        monitor_init(mon_chr, 0);
+    } else {
+        if (s->chr)
+            qemu_chr_close(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;
-    gdbserver_state = s;
-    qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
-                          gdb_chr_event, NULL);
-    qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
-
-    /* Initialize a monitor terminal for gdb */
-    s->mon_chr = qemu_mallocz(sizeof(*s->mon_chr));
-    s->mon_chr->chr_write = gdb_monitor_write;
-    monitor_init(s->mon_chr, 0);
+    s->state = chr ? RS_IDLE : RS_INACTIVE;
+    s->mon_chr = mon_chr;
 
     return 0;
 }