kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@web.de>
To: Avi Kivity <avi@redhat.com>
Cc: kvm@vger.kernel.org
Subject: Re: [PATCH 10/17] qemu: Improve debugging of SMP guests
Date: Wed, 08 Oct 2008 22:25:27 +0200	[thread overview]
Message-ID: <48ED1737.80606@web.de> (raw)
In-Reply-To: <48EB5223.6060804@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 20526 bytes --]

Avi Kivity wrote:
> Jan Kiszka wrote:
>> This patch enhances QEMU's built-in debugger for SMP guest debugging.
>> It allows to set the debugger focus explicitly via the monitor command
>> "cpu",
> 
>>  and it automatically switches the focus on breakpoint hit to
>> the reporting CPU.
>>
>>   
> 
> For gdbstub, this should be done through the debugger, using the gdb
> "thread" command, instead of through the monitor.  The monitor may
> belong to a management application which can issue it independently of
> the person using the debugger.

Yeah, I already thought about this a while ago as well, specifically to
allow switching the context directly via the frontend. But I was too
laz^Wbusy to hack it up. However, your remark and my long train ride
yesterday finally enabled this overdue rework.

The following has one cosmetic (=display) issue under KVM:
CPUState.halted is not properly tracked for in-kernel irqchip mode. /me
still has to understand what happens in that case, while I cannot simply
translate mp_state into halted, but all this looks messy on first sight.

------------

This patch enhances QEMU's built-in debugger for SMP guest debugging.
Using the thread support of the gdb remote protocol, each VCPU is mapped
on a pseudo thread and exposed to the gdb frontend. This way you can
easy switch the focus of gdb between the VCPUs and observe their states.
On breakpoint hit, the focus is automatically adjusted just as for
normal multi-threaded application under gdb control.

Furthermore, the patch propagates breakpoint and watchpoint insertions
or removals to all CPUs, not just the current one as it was the case so
far. Without this, SMP guest debugging was practically unfeasible.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 qemu/gdbstub.c |  262 +++++++++++++++++++++++++++++++++++++++++----------------
 qemu/gdbstub.h |    1 
 qemu/vl.c      |    1 
 3 files changed, 191 insertions(+), 73 deletions(-)

Index: b/qemu/gdbstub.c
===================================================================
--- a/qemu/gdbstub.c
+++ b/qemu/gdbstub.c
@@ -18,6 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include "config.h"
+#include "qemu-common.h"
 #ifdef CONFIG_USER_ONLY
 #include <stdlib.h>
 #include <stdio.h>
@@ -29,7 +30,6 @@
 
 #include "qemu.h"
 #else
-#include "qemu-common.h"
 #include "qemu-char.h"
 #include "sysemu.h"
 #include "gdbstub.h"
@@ -59,7 +59,9 @@ enum RSState {
     RS_SYSCALL,
 };
 typedef struct GDBState {
-    CPUState *env; /* current CPU */
+    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[4096];
     int line_buf_index;
@@ -80,13 +82,12 @@ typedef struct GDBState {
  */
 static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
 
+static GDBState *gdbserver_state;
+
 #ifdef CONFIG_USER_ONLY
 /* XXX: This is not thread safe.  Do we care?  */
 static int gdbserver_fd = -1;
 
-/* XXX: remove this hack.  */
-static GDBState gdbserver_state;
-
 static int get_char(GDBState *s)
 {
     uint8_t ch;
@@ -978,49 +979,78 @@ static const int xlat_gdb_type[] = {
 };
 #endif
 
-static int gdb_breakpoint_insert(CPUState *env, target_ulong addr,
-                                 target_ulong len, int type)
+static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
 {
+    CPUState *env;
+    int err = 0;
+
     switch (type) {
     case GDB_BREAKPOINT_SW ... GDB_BREAKPOINT_HW:
-        return cpu_breakpoint_insert(env, addr, BP_GDB, NULL);
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_breakpoint_insert(env, addr, BP_GDB, NULL);
+            if (err)
+                break;
+        }
+        return err;
 #ifndef CONFIG_USER_ONLY
     case GDB_WATCHPOINT_WRITE ... GDB_WATCHPOINT_ACCESS:
-        return cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type],
-                                     NULL);
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type],
+                                        NULL);
+            if (err)
+                break;
+        }
+        return err;
 #endif
     default:
         return -ENOSYS;
     }
 }
 
-static int gdb_breakpoint_remove(CPUState *env, target_ulong addr,
-                                 target_ulong len, int type)
+static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
 {
+    CPUState *env;
+    int err = 0;
+
     switch (type) {
     case GDB_BREAKPOINT_SW ... GDB_BREAKPOINT_HW:
-        return cpu_breakpoint_remove(env, addr, BP_GDB);
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_breakpoint_remove(env, addr, BP_GDB);
+            if (err)
+                break;
+        }
+        return err;
 #ifndef CONFIG_USER_ONLY
     case GDB_WATCHPOINT_WRITE ... GDB_WATCHPOINT_ACCESS:
-        return cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]);
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]);
+            if (err)
+                break;
+        }
+        return err;
 #endif
     default:
         return -ENOSYS;
     }
 }
 
-static void gdb_breakpoint_remove_all(CPUState *env)
+static void gdb_breakpoint_remove_all(void)
 {
-    cpu_breakpoint_remove_all(env, BP_GDB);
+    CPUState *env;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu_breakpoint_remove_all(env, BP_GDB);
 #ifndef CONFIG_USER_ONLY
-    cpu_watchpoint_remove_all(env, BP_GDB);
+        cpu_watchpoint_remove_all(env, BP_GDB);
 #endif
+    }
 }
 
-static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
+static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
+    CPUState *env;
     const char *p;
-    int ch, reg_size, type, res;
+    int ch, reg_size, type, res, thread;
     char buf[4096];
     uint8_t mem_buf[4096];
     uint32_t *registers;
@@ -1040,28 +1070,28 @@ static int gdb_handle_packet(GDBState *s
          * because gdb is doing and initial connect and the state
          * should be cleaned up.
          */
-        gdb_breakpoint_remove_all(env);
+        gdb_breakpoint_remove_all();
         break;
     case 'c':
         if (*p != '\0') {
             addr = strtoull(p, (char **)&p, 16);
 #if defined(TARGET_I386)
-            env->eip = addr;
-            kvm_load_registers(env);
+            s->c_cpu->eip = addr;
+            kvm_load_registers(s->c_cpu);
 #elif defined (TARGET_PPC)
-            env->nip = addr;
-            kvm_load_registers(env);
+            s->c_cpu->nip = addr;
+            kvm_load_registers(s->c_cpu);
 #elif defined (TARGET_SPARC)
-            env->pc = addr;
-            env->npc = addr + 4;
+            s->c_cpu->pc = addr;
+            s->c_cpu->npc = addr + 4;
 #elif defined (TARGET_ARM)
-            env->regs[15] = addr;
+            s->c_cpu->regs[15] = addr;
 #elif defined (TARGET_SH4)
-            env->pc = addr;
+            s->c_cpu->pc = addr;
 #elif defined (TARGET_MIPS)
-            env->active_tc.PC = addr;
+            s->c_cpu->active_tc.PC = addr;
 #elif defined (TARGET_CRIS)
-            env->pc = addr;
+            s->c_cpu->pc = addr;
 #endif
         }
         gdb_continue(s);
@@ -1076,7 +1106,7 @@ static int gdb_handle_packet(GDBState *s
         exit(0);
     case 'D':
         /* Detach packet */
-        gdb_breakpoint_remove_all(env);
+        gdb_breakpoint_remove_all();
         gdb_continue(s);
         put_packet(s, "OK");
         break;
@@ -1084,25 +1114,25 @@ static int gdb_handle_packet(GDBState *s
         if (*p != '\0') {
             addr = strtoull(p, (char **)&p, 16);
 #if defined(TARGET_I386)
-            env->eip = addr;
-            kvm_load_registers(env);
+            s->c_cpu->eip = addr;
+            kvm_load_registers(s->c_cpu);
 #elif defined (TARGET_PPC)
-            env->nip = addr;
-            kvm_load_registers(env);
+            s->c_cpu->nip = addr;
+            kvm_load_registers(s->c_cpu);
 #elif defined (TARGET_SPARC)
-            env->pc = addr;
-            env->npc = addr + 4;
+            s->c_cpu->pc = addr;
+            s->c_cpu->npc = addr + 4;
 #elif defined (TARGET_ARM)
-            env->regs[15] = addr;
+            s->c_cpu->regs[15] = addr;
 #elif defined (TARGET_SH4)
-            env->pc = addr;
+            s->c_cpu->pc = addr;
 #elif defined (TARGET_MIPS)
-            env->active_tc.PC = addr;
+            s->c_cpu->active_tc.PC = addr;
 #elif defined (TARGET_CRIS)
-            env->pc = addr;
+            s->c_cpu->pc = addr;
 #endif
         }
-        cpu_single_step(env, sstep_flags);
+        cpu_single_step(s->c_cpu, sstep_flags);
         gdb_continue(s);
 	return RS_IDLE;
     case 'F':
@@ -1121,7 +1151,7 @@ static int gdb_handle_packet(GDBState *s
                 p++;
             type = *p;
             if (gdb_current_syscall_cb)
-                gdb_current_syscall_cb(s->env, ret, err);
+                gdb_current_syscall_cb(s->c_cpu, ret, err);
             if (type == 'C') {
                 put_packet(s, "T02");
             } else {
@@ -1130,8 +1160,8 @@ static int gdb_handle_packet(GDBState *s
         }
         break;
     case 'g':
-        kvm_save_registers(env);
-        reg_size = cpu_gdb_read_registers(env, mem_buf);
+        kvm_save_registers(s->g_cpu);
+        reg_size = cpu_gdb_read_registers(s->g_cpu, mem_buf);
         memtohex(buf, mem_buf, reg_size);
         put_packet(s, buf);
         break;
@@ -1139,8 +1169,8 @@ static int gdb_handle_packet(GDBState *s
         registers = (void *)mem_buf;
         len = strlen(p) / 2;
         hextomem((uint8_t *)registers, p, len);
-        cpu_gdb_write_registers(env, mem_buf, len);
-        kvm_load_registers(env);
+        cpu_gdb_write_registers(s->g_cpu, mem_buf, len);
+        kvm_load_registers(s->g_cpu);
         put_packet(s, "OK");
         break;
     case 'm':
@@ -1148,7 +1178,7 @@ static int gdb_handle_packet(GDBState *s
         if (*p == ',')
             p++;
         len = strtoull(p, NULL, 16);
-        if (cpu_memory_rw_debug(env, 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);
@@ -1163,7 +1193,7 @@ static int gdb_handle_packet(GDBState *s
         if (*p == ':')
             p++;
         hextomem(mem_buf, p, len);
-        if (cpu_memory_rw_debug(env, 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
             put_packet(s, "OK");
@@ -1178,9 +1208,9 @@ static int gdb_handle_packet(GDBState *s
             p++;
         len = strtoull(p, (char **)&p, 16);
         if (ch == 'Z')
-            res = gdb_breakpoint_insert(env, addr, len, type);
+            res = gdb_breakpoint_insert(addr, len, type);
         else
-            res = gdb_breakpoint_remove(env, addr, len, type);
+            res = gdb_breakpoint_remove(addr, len, type);
         if (res >= 0)
              put_packet(s, "OK");
         else if (res == -ENOSYS)
@@ -1188,6 +1218,45 @@ static int gdb_handle_packet(GDBState *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;
+        }
+        for (env = first_cpu; env != NULL; env = env->next_cpu)
+            if (env->cpu_index + 1 == thread)
+                break;
+        if (env == NULL) {
+            put_packet(s, "E22");
+            break;
+        }
+        switch (type) {
+        case 'c':
+            s->c_cpu = env;
+            put_packet(s, "OK");
+            break;
+        case 'g':
+            s->g_cpu = env;
+            put_packet(s, "OK");
+            break;
+        default:
+             put_packet(s, "E22");
+             break;
+        }
+        break;
+    case 'T':
+        thread = strtoull(p, (char **)&p, 16);
+#ifndef CONFIG_USER_ONLY
+        if (thread > 0 && thread < smp_cpus + 1)
+#else
+        if (thread == 1)
+#endif
+             put_packet(s, "OK");
+        else
+            put_packet(s, "E22");
+        break;
     case 'q':
     case 'Q':
         /* parse any 'q' packets here */
@@ -1213,10 +1282,39 @@ static int gdb_handle_packet(GDBState *s
             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", s->query_cpu->cpu_index+1);
+                put_packet(s, buf);
+                s->query_cpu = s->query_cpu->next_cpu;
+            } else
+                put_packet(s, "l");
+            break;
+        } else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
+            thread = strtoull(p+16, (char **)&p, 16);
+            for (env = first_cpu; env != NULL; env = env->next_cpu)
+                if (env->cpu_index + 1 == thread) {
+                    len = snprintf((char *)mem_buf, sizeof(mem_buf),
+                                   "CPU#%d [%s]", env->cpu_index,
+                                   env->halted ? "halted " : "running");
+                    memtohex(buf, mem_buf, len);
+                    put_packet(s, buf);
+                    break;
+                }
+            break;
         }
 #ifdef CONFIG_LINUX_USER
         else if (strncmp(p, "Offsets", 7) == 0) {
-            TaskState *ts = env->opaque;
+            TaskState *ts = s->c_cpu->opaque;
 
             snprintf(buf, sizeof(buf),
                      "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
@@ -1240,10 +1338,17 @@ static int gdb_handle_packet(GDBState *s
 
 extern void tb_flush(CPUState *env);
 
+void gdb_set_stop_cpu(CPUState *env)
+{
+    gdbserver_state->c_cpu = env;
+    gdbserver_state->g_cpu = env;
+}
+
 #ifndef CONFIG_USER_ONLY
 static void gdb_vm_stopped(void *opaque, int reason)
 {
-    GDBState *s = opaque;
+    GDBState *s = gdbserver_state;
+    CPUState *env = s->c_cpu;
     char buf[256];
     const char *type;
     int ret;
@@ -1252,11 +1357,11 @@ static void gdb_vm_stopped(void *opaque,
         return;
 
     /* disable single step if it was enable */
-    cpu_single_step(s->env, 0);
+    cpu_single_step(env, 0);
 
     if (reason == EXCP_DEBUG) {
-        if (s->env->watchpoint_hit) {
-            switch (s->env->watchpoint_hit->flags & BP_MEM_ACCESS) {
+        if (env->watchpoint_hit) {
+            switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
             case BP_MEM_READ:
                 type = "r";
                 break;
@@ -1267,20 +1372,22 @@ static void gdb_vm_stopped(void *opaque,
                 type = "";
                 break;
             }
-            snprintf(buf, sizeof(buf), "T%02x%swatch:" TARGET_FMT_lx ";",
-                     SIGTRAP, type, s->env->watchpoint_hit->vaddr);
+            snprintf(buf, sizeof(buf),
+                     "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
+                     SIGTRAP, env->cpu_index+1, type,
+                     env->watchpoint_hit->vaddr);
             put_packet(s, buf);
-            s->env->watchpoint_hit = NULL;
+            env->watchpoint_hit = NULL;
             return;
         }
-	tb_flush(s->env);
+	tb_flush(env);
         ret = SIGTRAP;
     } else if (reason == EXCP_INTERRUPT) {
         ret = SIGINT;
     } else {
         ret = 0;
     }
-    snprintf(buf, sizeof(buf), "S%02x", ret);
+    snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, env->cpu_index+1);
     put_packet(s, buf);
 }
 #endif
@@ -1344,15 +1451,14 @@ void gdb_do_syscall(gdb_syscall_complete
     va_end(va);
     put_packet(s, buf);
 #ifdef CONFIG_USER_ONLY
-    gdb_handlesig(s->env, 0);
+    gdb_handlesig(s->c_cpu, 0);
 #else
-    cpu_interrupt(s->env, CPU_INTERRUPT_EXIT);
+    cpu_interrupt(s->c_cpu, CPU_INTERRUPT_EXIT);
 #endif
 }
 
 static void gdb_read_byte(GDBState *s, int ch)
 {
-    CPUState *env = s->env;
     int i, csum;
     uint8_t reply;
 
@@ -1418,7 +1524,7 @@ static void gdb_read_byte(GDBState *s, i
             } else {
                 reply = '+';
                 put_buffer(s, &reply, 1);
-                s->state = gdb_handle_packet(s, env, s->line_buf);
+                s->state = gdb_handle_packet(s, s->line_buf);
             }
             break;
         default:
@@ -1435,7 +1541,7 @@ gdb_handlesig (CPUState *env, int sig)
   char buf[256];
   int n;
 
-  s = &gdbserver_state;
+  s = gdbserver_state;
   if (gdbserver_fd < 0 || s->fd < 0)
     return sig;
 
@@ -1483,7 +1589,7 @@ void gdb_exit(CPUState *env, int code)
   GDBState *s;
   char buf[4];
 
-  s = &gdbserver_state;
+  s = gdbserver_state;
   if (gdbserver_fd < 0 || s->fd < 0)
     return;
 
@@ -1492,7 +1598,7 @@ void gdb_exit(CPUState *env, int code)
 }
 
 
-static void gdb_accept(void *opaque)
+static void gdb_accept(void)
 {
     GDBState *s;
     struct sockaddr_in sockaddr;
@@ -1514,11 +1620,19 @@ static void gdb_accept(void *opaque)
     val = 1;
     setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
 
-    s = &gdbserver_state;
+    s = qemu_mallocz(sizeof(GDBState));
+    if (!s) {
+        errno = ENOMEM;
+        perror("accept");
+        return;
+    }
+
     memset (s, 0, sizeof (GDBState));
-    s->env = first_cpu; /* XXX: allow to change CPU */
+    s->c_cpu = first_cpu;
+    s->g_cpu = first_cpu;
     s->fd = fd;
 
+    gdbserver_state = s;
     gdb_syscall_state = s;
 
     fcntl(fd, F_SETFL, O_NONBLOCK);
@@ -1561,7 +1675,7 @@ int gdbserver_start(int port)
     if (gdbserver_fd < 0)
         return -1;
     /* accept connections */
-    gdb_accept (NULL);
+    gdb_accept();
     return 0;
 }
 #else
@@ -1619,11 +1733,13 @@ int gdbserver_start(const char *port)
     if (!s) {
         return -1;
     }
-    s->env = first_cpu; /* XXX: allow to change CPU */
+    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, s);
-    qemu_add_vm_stop_handler(gdb_vm_stopped, s);
+    qemu_add_vm_stop_handler(gdb_vm_stopped, NULL);
     return 0;
 }
 #endif
Index: b/qemu/gdbstub.h
===================================================================
--- a/qemu/gdbstub.h
+++ b/qemu/gdbstub.h
@@ -8,6 +8,7 @@ typedef void (*gdb_syscall_complete_cb)(
 
 void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...);
 int use_gdb_syscalls(void);
+void gdb_set_stop_cpu(CPUState *env);
 #ifdef CONFIG_USER_ONLY
 int gdb_handlesig (CPUState *, int);
 void gdb_exit(CPUState *, int);
Index: b/qemu/vl.c
===================================================================
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -8408,6 +8408,7 @@ static int main_loop(void)
                 ret = EXCP_INTERRUPT;
             }
             if (unlikely(ret == EXCP_DEBUG)) {
+                gdb_set_stop_cpu(cur_cpu);
                 vm_stop(EXCP_DEBUG);
             }
             /* If all cpus are halted then wait until the next IRQ */


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 257 bytes --]

  reply	other threads:[~2008-10-08 20:25 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-10-06  9:14 [PATCH 00/17] kvm-userspace: Fix and improve guest debugging and x86 debug registers Jan Kiszka
2008-10-06  9:14 ` [PATCH 01/17] kvm-userspace: Remove old guest debugging hooks Jan Kiszka
2008-10-06  9:14 ` [PATCH 02/17] qemu: Return appropriate watch message to gdb Jan Kiszka
2008-10-06  9:14 ` [PATCH 03/17] qemu: Refactor and enhance break/watchpoint API Jan Kiszka
2008-10-06  9:14 ` [PATCH 04/17] qemu: Set mem_io_vaddr on io_read Jan Kiszka
2008-10-06  9:14 ` [PATCH 05/17] qemu: Respect length of watchpoints Jan Kiszka
2008-10-07 12:04   ` Avi Kivity
2008-10-08 20:22     ` Jan Kiszka
2008-10-06  9:14 ` [PATCH 06/17] qemu: Introduce next_cflags Jan Kiszka
2008-10-07 12:07   ` Avi Kivity
2008-10-06  9:14 ` [PATCH 07/17] qemu: Switch self-modified code recompilation to next_cflags Jan Kiszka
2008-10-06  9:14 ` [PATCH 08/17] qemu: Restore pc on watchpoint hits - v3 Jan Kiszka
2008-10-06  9:14 ` [PATCH 09/17] qemu: Remove premature memop TB terminations Jan Kiszka
2008-10-06  9:14 ` [PATCH 10/17] qemu: Improve debugging of SMP guests Jan Kiszka
2008-10-07 12:12   ` Avi Kivity
2008-10-08 20:25     ` Jan Kiszka [this message]
2008-10-06  9:14 ` [PATCH 11/17] qemu: Introduce BP_WATCHPOINT_HIT flag Jan Kiszka
2008-10-06  9:14 ` [PATCH 12/17] qemu: Add debug exception hook Jan Kiszka
2008-10-06  9:14 ` [PATCH 13/17] qemu: Introduce BP_CPU as a breakpoint type Jan Kiszka
2008-10-06  9:14 ` [PATCH 14/17] qemu: x86: Debug register emulation Jan Kiszka
2008-10-07 12:15   ` Avi Kivity
2008-10-08 20:25     ` Jan Kiszka
2008-10-06  9:14 ` [PATCH 15/17] kvm-userspace: Switch to new guest debug interface Jan Kiszka
2008-10-06  9:14 ` [PATCH 16/17] kvm-userspace: Provide compat wrapper for set_debugreg Jan Kiszka
2008-10-07 12:17   ` Avi Kivity
2008-10-08 20:25     ` Jan Kiszka
2008-10-06  9:14 ` [PATCH 17/17] kvm-userspace: remove obsolete special_reload_dr7 hack Jan Kiszka
2008-10-07 12:18 ` [PATCH 00/17] kvm-userspace: Fix and improve guest debugging and x86 debug registers Avi Kivity
2008-10-07 12:20   ` Jan Kiszka
2008-11-17 22:44 ` Markus Armbruster
2008-11-18  9:08   ` Jan Kiszka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=48ED1737.80606@web.de \
    --to=jan.kiszka@web.de \
    --cc=avi@redhat.com \
    --cc=kvm@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).