From: Jan K. <jan...@we...> - 2008-05-16 16:03:33
|
With this patch applied, kvm is able to ignore breakpoint requests of an attached gdb frontend so that the latter is motivated to insert soft breakpoints into the guest code. All we need to do for this is to catch and forward #BP exceptions which are now provided by the kernel module. Along this, the patch makes vm_stop-on-breakpoint start to work. Limitations: - only takes care of x86 so far - gdbstub state tracking is broken (artificially incrementing nb_breakpoints won't fly, as we'll have no chance to decrement it), we need an enhanced interface to the stub --- libkvm/kvm-common.h | 2 ++ libkvm/libkvm-x86.c | 16 ++++++++++++++++ libkvm/libkvm.c | 5 ----- libkvm/libkvm.h | 8 +++++++- qemu/exec.c | 19 +++++++++++++------ qemu/qemu-kvm.c | 22 +++++++++++++--------- 6 files changed, 51 insertions(+), 21 deletions(-) Index: b/libkvm/kvm-common.h =================================================================== --- a/libkvm/kvm-common.h +++ b/libkvm/kvm-common.h @@ -85,4 +85,6 @@ int handle_io_window(kvm_context_t kvm); int handle_debug(kvm_context_t kvm, int vcpu); int try_push_interrupts(kvm_context_t kvm); +int handle_debug(kvm_context_t kvm, int vcpu); + #endif Index: b/libkvm/libkvm-x86.c =================================================================== --- a/libkvm/libkvm-x86.c +++ b/libkvm/libkvm-x86.c @@ -661,3 +661,19 @@ int kvm_disable_tpr_access_reporting(kvm } #endif + +int handle_debug(kvm_context_t kvm, int vcpu) +{ + struct kvm_run *run = kvm->run[vcpu]; + unsigned long watchpoint = 0; + int break_type; + + if (run->debug.arch.exception == 1) { + /* TODO: fully process run->debug.arch */ + break_type = KVM_GDB_BREAKPOINT_HW; + } else + break_type = KVM_GDB_BREAKPOINT_SW; + + return kvm->callbacks->debug(kvm->opaque, vcpu, break_type, + watchpoint); +} Index: b/libkvm/libkvm.c =================================================================== --- a/libkvm/libkvm.c +++ b/libkvm/libkvm.c @@ -738,11 +738,6 @@ static int handle_io(kvm_context_t kvm, return 0; } -int handle_debug(kvm_context_t kvm, int vcpu) -{ - return kvm->callbacks->debug(kvm->opaque, vcpu); -} - int kvm_get_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs) { return ioctl(kvm->vcpu_fd[vcpu], KVM_GET_REGS, regs); Index: b/qemu/exec.c =================================================================== --- a/qemu/exec.c +++ b/qemu/exec.c @@ -1157,6 +1157,12 @@ int cpu_breakpoint_insert(CPUState *env, #if defined(TARGET_HAS_ICE) int i; + if (kvm_enabled()) { + env->nb_breakpoints++; + kvm_update_debugger(env); + return -ENOSYS; + } + for(i = 0; i < env->nb_breakpoints; i++) { if (env->breakpoints[i] == pc) return 0; @@ -1166,9 +1172,6 @@ int cpu_breakpoint_insert(CPUState *env, return -ENOBUFS; env->breakpoints[env->nb_breakpoints++] = pc; - if (kvm_enabled()) - kvm_update_debugger(env); - breakpoint_invalidate(env, pc); return 0; #else @@ -1182,6 +1185,13 @@ int cpu_breakpoint_remove(CPUState *env, { #if defined(TARGET_HAS_ICE) int i; + + if (kvm_enabled()) { + env->nb_breakpoints--; + kvm_update_debugger(env); + return -ENOSYS; + } + for(i = 0; i < env->nb_breakpoints; i++) { if (env->breakpoints[i] == pc) goto found; @@ -1192,9 +1202,6 @@ int cpu_breakpoint_remove(CPUState *env, if (i < env->nb_breakpoints) env->breakpoints[i] = env->breakpoints[env->nb_breakpoints]; - if (kvm_enabled()) - kvm_update_debugger(env); - breakpoint_invalidate(env, pc); return 0; #else Index: b/qemu/qemu-kvm.c =================================================================== --- a/qemu/qemu-kvm.c +++ b/qemu/qemu-kvm.c @@ -58,6 +58,8 @@ pthread_t io_thread; static int io_thread_fd = -1; static int io_thread_sigfd = -1; +static int kvm_debug_stop_requested; + static inline unsigned long kvm_get_thread_id(void) { return syscall(SYS_gettid); @@ -517,6 +519,10 @@ int kvm_main_loop(void) qemu_system_powerdown(); else if (qemu_reset_requested()) qemu_kvm_system_reset(); + else if (kvm_debug_stop_requested) { + kvm_debug_stop_requested = 0; + vm_stop(EXCP_DEBUG); + } } pause_all_threads(); @@ -525,11 +531,12 @@ int kvm_main_loop(void) return 0; } -static int kvm_debug(void *opaque, int vcpu) +static int kvm_debug(void *opaque, int vcpu, int break_type, + uint64_t watchpoint_addr) { - CPUState *env = cpu_single_env; - - env->exception_index = EXCP_DEBUG; + /* TODO: process break_type */ + kvm_debug_stop_requested = 1; + vcpu_info[vcpu].stopped = 1; return 1; } @@ -748,15 +755,12 @@ int kvm_qemu_init_env(CPUState *cenv) int kvm_update_debugger(CPUState *env) { struct kvm_debug_guest dbg; - int i, r; + int r; dbg.enabled = 0; if (env->nb_breakpoints || env->singlestep_enabled) { dbg.enabled = 1; - for (i = 0; i < 4 && i < env->nb_breakpoints; ++i) { - dbg.breakpoints[i].enabled = 1; - dbg.breakpoints[i].address = env->breakpoints[i]; - } + memset(dbg.breakpoints, 0, sizeof(dbg.breakpoints)); dbg.singlestep = env->singlestep_enabled; } if (vm_running) Index: b/libkvm/libkvm.h =================================================================== --- a/libkvm/libkvm.h +++ b/libkvm/libkvm.h @@ -25,6 +25,12 @@ int kvm_get_msrs(kvm_context_t, int vcpu int kvm_set_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n); #endif +#define KVM_GDB_BREAKPOINT_SW 0 +#define KVM_GDB_BREAKPOINT_HW 1 +#define KVM_GDB_WATCHPOINT_WRITE 2 +#define KVM_GDB_WATCHPOINT_READ 3 +#define KVM_GDB_WATCHPOINT_ACCESS 4 + /*! * \brief KVM callbacks structure * @@ -51,7 +57,7 @@ struct kvm_callbacks { /// generic memory writes to unmapped memory (For MMIO devices) int (*mmio_write)(void *opaque, uint64_t addr, uint8_t *data, int len); - int (*debug)(void *opaque, int vcpu); + int (*debug)(void *opaque, int vcpu, int break_type, uint64_t watchpoint); /*! * \brief Called when the VCPU issues an 'hlt' instruction. * |