From: Jack Lange Date: Wed, 20 Jun 2012 19:28:38 +0000 (-0400) Subject: added dedicated debugging framework with associated interface X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=e784113618800cede961f9a86084a96d20179e1c added dedicated debugging framework with associated interface --- diff --git a/linux_module/palacios.h b/linux_module/palacios.h index 11d3314..4933028 100644 --- a/linux_module/palacios.h +++ b/linux_module/palacios.h @@ -70,7 +70,12 @@ struct v3_mem_region { unsigned long long num_pages; } __attribute__((packed)); -struct v3_core_move_cmd{ +struct v3_debug_cmd { + unsigned int core; + unsigned int cmd; +} __attribute__((packed)); + +struct v3_core_move_cmd { unsigned short vcore_id; unsigned short pcore_id; } __attribute__((packed)); diff --git a/linux_module/vm.c b/linux_module/vm.c index 88e3bef..40cfa06 100644 --- a/linux_module/vm.c +++ b/linux_module/vm.c @@ -19,6 +19,7 @@ #include #include +#include #include "palacios.h" #include "vm.h" @@ -208,6 +209,30 @@ static long v3_vm_ioctl(struct file * filp, break; } #endif + case V3_VM_DEBUG: { + struct v3_debug_cmd cmd; + struct v3_debug_event evt; + void __user * argp = (void __user *)arg; + + memset(&cmd, 0, sizeof(struct v3_debug_cmd)); + + if (copy_from_user(&cmd, argp, sizeof(struct v3_debug_cmd))) { + printk("Error: Could not copy debug command from user space\n"); + return -EFAULT; + } + + evt.core_id = cmd.core; + evt.cmd = cmd.cmd; + + printk("Debugging VM\n"); + + if (v3_deliver_debug_event(guest->v3_ctx, &evt) == -1) { + printk("Error could not deliver debug cmd\n"); + return -EFAULT; + } + + break; + } case V3_VM_MOVE_CORE: { struct v3_core_move_cmd cmd; void __user * argp = (void __user *)arg; diff --git a/linux_usr/v3_ctrl.h b/linux_usr/v3_ctrl.h index e904263..97cb0fd 100644 --- a/linux_usr/v3_ctrl.h +++ b/linux_usr/v3_ctrl.h @@ -56,6 +56,11 @@ struct v3_core_move_cmd{ } __attribute__((packed)); +struct v3_debug_cmd { + unsigned int core; + unsigned int cmd; +} __attribute__((packed)); + struct v3_chkpt_info { char store[128]; char url[256]; /* This might need to be bigger... */ diff --git a/linux_usr/v3_debug.c b/linux_usr/v3_debug.c new file mode 100644 index 0000000..b609646 --- /dev/null +++ b/linux_usr/v3_debug.c @@ -0,0 +1,54 @@ +/* + * V3 debug interface + * (c) Jack Lange, 2012 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "v3_ctrl.h" + + +int main(int argc, char* argv[]) { + int vm_fd; + char * vm_dev = NULL; + struct v3_debug_cmd cmd; + + if (argc < 4) { + printf("Usage: v3_core_migrate \n"); + return -1; + } + + vm_dev = argv[1]; + cmd.core = atoi(argv[2]); + cmd.cmd = atoi(argv[3]); + + printf("Debug Virtual Core %d with Command %d\n", cmd.core, cmd.cmd); + + vm_fd = open(vm_dev, O_RDONLY); + + if (vm_fd == -1) { + printf("Error opening VM device: %s\n", vm_dev); + return -1; + } + + int err = ioctl(vm_fd, V3_VM_DEBUG, &cmd); + + if (err < 0) { + printf("Error write core migrating command to vm\n"); + return -1; + } + + close(vm_fd); + + return 0; +} + + diff --git a/palacios/include/palacios/vm_guest.h b/palacios/include/palacios/vm_guest.h index 49e8598..fb91c1d 100644 --- a/palacios/include/palacios/vm_guest.h +++ b/palacios/include/palacios/vm_guest.h @@ -219,19 +219,10 @@ v3_mem_mode_t v3_get_vm_mem_mode(struct guest_info * info); const uchar_t * v3_cpu_mode_to_str(v3_cpu_mode_t mode); const uchar_t * v3_mem_mode_to_str(v3_mem_mode_t mode); -int v3_translate_segment(struct guest_info * info, uint16_t selector, struct v3_segment * seg); -void v3_print_guest_state(struct guest_info * info); - -void v3_print_segments(struct v3_segments * segs); -void v3_print_ctrl_regs(struct guest_info * info); -void v3_print_GPRs(struct guest_info * info); - -void v3_print_stack(struct guest_info * info); - #endif /* ! __V3VEE__ */ -void v3_print_guest_state_all(struct v3_vm_info * vm); + #endif diff --git a/palacios/include/palacios/vmm_debug.h b/palacios/include/palacios/vmm_debug.h index 9d68359..bbb253e 100644 --- a/palacios/include/palacios/vmm_debug.h +++ b/palacios/include/palacios/vmm_debug.h @@ -18,112 +18,28 @@ */ -#ifndef __VMM_DEBUG_H -#define __VMM_DEBUG_H +#ifndef __VMM_DEBUG_H__ +#define __VMM_DEBUG_H__ #ifdef __V3VEE__ #include +#include -struct dbg_bp32 { - uint_t breakpoint : 32; -}; +int v3_init_vm_debugging(struct v3_vm_info * vm); -struct dbg_bp64 { - ullong_t breakpoint; -}; -struct dr6_32 { - uint_t bp0 : 1; - uint_t bp1 : 1; - uint_t bp2 : 1; - uint_t bp3 : 1; - uint_t rsvd1 : 8; // read as ones - uint_t rsvd2 : 1; // read as zero - uint_t bd : 1; - uint_t bs : 1; - uint_t bt : 1; - uint_t rsvd3 : 16; // read as one -}; - - -struct dr6_64 { - uint_t bp0 : 1; - uint_t bp1 : 1; - uint_t bp2 : 1; - uint_t bp3 : 1; - uint_t rsvd1 : 8; // read as ones - uint_t rsvd2 : 1; // read as zero - uint_t bd : 1; - uint_t bs : 1; - uint_t bt : 1; - uint_t rsvd3 : 16; // read as one - uint_t rsvd4 : 32; // MBZ -}; - - -struct dr7_32 { - uint_t L0 : 1; - uint_t G0 : 1; - uint_t L1 : 1; - uint_t G1 : 1; - uint_t L2 : 1; - uint_t G2 : 1; - uint_t L3 : 1; - uint_t G3 : 1; - uint_t LE : 1; - uint_t GE : 1; - uint_t rsvd1 : 1; // Read as one - uint_t rsvd2 : 2; // Read as zero - uint_t GD : 1; - uint_t rsvd3 : 2; // Read as zero - uint_t rw0 : 1; - uint_t len0 : 1; - uint_t rw1 : 1; - uint_t len1 : 1; - uint_t rw2 : 1; - uint_t len2 : 1; - uint_t rw3 : 1; - uint_t len3 : 1; -}; - - -struct dr7_64 { - uint_t L0 : 1; - uint_t G0 : 1; - uint_t L1 : 1; - uint_t G1 : 1; - uint_t L2 : 1; - uint_t G2 : 1; - uint_t L3 : 1; - uint_t G3 : 1; - uint_t LE : 1; - uint_t GE : 1; - uint_t rsvd1 : 1; // Read as one - uint_t rsvd2 : 2; // Read as zero - uint_t GD : 1; - uint_t rsvd3 : 2; // Read as zero - uint_t rw0 : 1; - uint_t len0 : 1; - uint_t rw1 : 1; - uint_t len1 : 1; - uint_t rw2 : 1; - uint_t len2 : 1; - uint_t rw3 : 1; - uint_t len3 : 1; - uint_t rsvd4 : 32; // MBZ -}; - - - - - - -void PrintDebugHex(uchar_t x); -void PrintDebugMemDump(uchar_t * start, int n); +void v3_print_guest_state(struct guest_info * core); +void v3_print_arch_state(struct guest_info * core); +void v3_print_segments(struct v3_segments * segs); +void v3_print_ctrl_regs(struct guest_info * core); +void v3_print_GPRs(struct guest_info * core); +void v3_print_backtrace(struct guest_info * core); +void v3_print_stack(struct guest_info * core); +void v3_print_guest_state_all(struct v3_vm_info * vm); #endif // !__V3VEE__ diff --git a/palacios/include/palacios/vmm_decoder.h b/palacios/include/palacios/vmm_decoder.h index 03c5edb..b1e87c2 100644 --- a/palacios/include/palacios/vmm_decoder.h +++ b/palacios/include/palacios/vmm_decoder.h @@ -204,12 +204,10 @@ static inline v3_reg_t get_gpr_mask(struct guest_info * info) { static inline addr_t get_addr_linear(struct guest_info * info, addr_t addr, struct v3_segment * seg) { switch (info->cpu_mode) { - case REAL: - // It appears that the segment values are computed and cached in the vmcb structure - // We Need to check this for Intel - /* return addr + (seg->selector << 4); - break;*/ - + case REAL: { + return ((seg->selector & 0xffff) << 4) + (addr & 0xffff); + break; + } case PROTECTED: case PROTECTED_PAE: case LONG_32_COMPAT: diff --git a/palacios/include/palacios/vmm_host_events.h b/palacios/include/palacios/vmm_host_events.h index 47c6715..21d4c01 100644 --- a/palacios/include/palacios/vmm_host_events.h +++ b/palacios/include/palacios/vmm_host_events.h @@ -43,9 +43,11 @@ struct v3_console_event { unsigned int cmd; }; -struct v3_packet_event { - unsigned char * pkt; - unsigned int size; + +struct v3_debug_event { + unsigned int core_id; + unsigned int cmd; + }; #ifdef __V3VEE__ @@ -58,7 +60,8 @@ typedef enum { HOST_KEYBOARD_EVT, HOST_MOUSE_EVT, HOST_TIMER_EVT, HOST_CONSOLE_EVT, - HOST_SERIAL_EVT} v3_host_evt_type_t; + HOST_SERIAL_EVT, + HOST_DEBUG_EVT} v3_host_evt_type_t; union v3_host_event_handler { @@ -67,6 +70,7 @@ union v3_host_event_handler { int (*timer_handler)(struct v3_vm_info * vm, struct v3_timer_event * evt, void * priv_data); int (*serial_handler)(struct v3_vm_info * vm, struct v3_serial_event * evt, void * priv_data); int (*console_handler)(struct v3_vm_info * vm, struct v3_console_event * evt, void * priv_data); + int (*debug_handler)(struct v3_vm_info * vm, struct v3_debug_event * evt, void * priv_data); }; @@ -84,6 +88,7 @@ struct v3_host_events { struct list_head timer_events; struct list_head serial_events; struct list_head console_events; + struct list_head debug_events; }; @@ -107,6 +112,7 @@ int v3_deliver_mouse_event(struct v3_vm_info * vm, struct v3_mouse_event * evt); int v3_deliver_timer_event(struct v3_vm_info * vm, struct v3_timer_event * evt); int v3_deliver_serial_event(struct v3_vm_info * vm, struct v3_serial_event * evt); int v3_deliver_console_event(struct v3_vm_info * vm, struct v3_console_event * evt); +int v3_deliver_debug_event(struct v3_vm_info * vm, struct v3_debug_event * evt); #endif diff --git a/palacios/src/devices/keyboard.c b/palacios/src/devices/keyboard.c index 039db76..b451e2e 100644 --- a/palacios/src/devices/keyboard.c +++ b/palacios/src/devices/keyboard.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifndef V3_CONFIG_DEBUG_KEYBOARD diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 434e3bd..c98a48b 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -36,6 +36,7 @@ #include #include +#include #ifdef V3_CONFIG_CHECKPOINT #include diff --git a/palacios/src/palacios/vm_guest.c b/palacios/src/palacios/vm_guest.c index df30d1d..e17feb9 100644 --- a/palacios/src/palacios/vm_guest.c +++ b/palacios/src/palacios/vm_guest.c @@ -31,6 +31,7 @@ #include #include #include +#include v3_cpu_mode_t v3_get_vm_cpu_mode(struct guest_info * info) { @@ -162,326 +163,9 @@ const uchar_t * v3_mem_mode_to_str(v3_mem_mode_t mode) { } -void v3_print_segments(struct v3_segments * segs) { - int i = 0; - struct v3_segment * seg_ptr; - seg_ptr=(struct v3_segment *)segs; - - char *seg_names[] = {"CS", "DS" , "ES", "FS", "GS", "SS" , "LDTR", "GDTR", "IDTR", "TR", NULL}; - V3_Print("Segments\n"); - for (i = 0; seg_names[i] != NULL; i++) { - V3_Print("\t%s: Sel=%x, base=%p, limit=%x (long_mode=%d, db=%d)\n", seg_names[i], seg_ptr[i].selector, - (void *)(addr_t)seg_ptr[i].base, seg_ptr[i].limit, - seg_ptr[i].long_mode, seg_ptr[i].db); - - } -} - -// -// We don't handle those fancy 64 bit system segments... -// -int v3_translate_segment(struct guest_info * info, uint16_t selector, struct v3_segment * seg) { - struct v3_segment * gdt = &(info->segments.gdtr); - addr_t gdt_addr = 0; - uint16_t seg_offset = (selector & ~0x7); - addr_t seg_addr = 0; - struct gen_segment * gen_seg = NULL; - struct seg_selector sel; - - memset(seg, 0, sizeof(struct v3_segment)); - - sel.value = selector; - - if (sel.ti == 1) { - PrintError("LDT translations not supported\n"); - return -1; - } - - if (v3_gva_to_hva(info, gdt->base, &gdt_addr) == -1) { - PrintError("Unable to translate GDT address\n"); - return -1; - } - - seg_addr = gdt_addr + seg_offset; - gen_seg = (struct gen_segment *)seg_addr; - - //translate - seg->selector = selector; - - seg->limit = gen_seg->limit_hi; - seg->limit <<= 16; - seg->limit += gen_seg->limit_lo; - - seg->base = gen_seg->base_hi; - seg->base <<= 24; - seg->base += gen_seg->base_lo; - - if (gen_seg->granularity == 1) { - seg->limit <<= 12; - seg->limit |= 0xfff; - } - - seg->type = gen_seg->type; - seg->system = gen_seg->system; - seg->dpl = gen_seg->dpl; - seg->present = gen_seg->present; - seg->avail = gen_seg->avail; - seg->long_mode = gen_seg->long_mode; - seg->db = gen_seg->db; - seg->granularity = gen_seg->granularity; - - return 0; -} - - - - -void v3_print_ctrl_regs(struct guest_info * info) { - struct v3_ctrl_regs * regs = &(info->ctrl_regs); - int i = 0; - v3_reg_t * reg_ptr; - char * reg_names[] = {"CR0", "CR2", "CR3", "CR4", "CR8", "FLAGS", "EFER", NULL}; - - - reg_ptr = (v3_reg_t *)regs; - - V3_Print("Ctrl Regs:\n"); - - for (i = 0; reg_names[i] != NULL; i++) { - V3_Print("\t%s=0x%p (at %p)\n", reg_names[i], (void *)(addr_t)reg_ptr[i], &(reg_ptr[i])); - } - - -} - -#if 0 -static int safe_gva_to_hva(struct guest_info * info, addr_t linear_addr, addr_t * host_addr) { - /* select the proper translation based on guest mode */ - if (info->mem_mode == PHYSICAL_MEM) { - if (v3_gpa_to_hva(info, linear_addr, host_addr) == -1) return -1; - } else if (info->mem_mode == VIRTUAL_MEM) { - if (v3_gva_to_hva(info, linear_addr, host_addr) == -1) return -1; - } - return 0; -} - -static int v3_print_disassembly(struct guest_info * info) { - int passed_rip = 0; - addr_t rip, rip_linear, rip_host; - - /* we don't know where the instructions preceding RIP start, so we just take - * a guess and hope the instruction stream synced up with our disassembly - * some time before RIP; if it has not we correct RIP at that point - */ - - /* start disassembly 64 bytes before current RIP, continue 32 bytes after */ - rip = (addr_t) info->rip - 64; - while ((int) (rip - info->rip) < 32) { - V3_Print("disassembly step\n"); - - /* always print RIP, even if the instructions before were bad */ - if (!passed_rip && rip >= info->rip) { - if (rip != info->rip) { - V3_Print("***** bad disassembly up to this point *****\n"); - rip = info->rip; - } - passed_rip = 1; - } - - /* look up host virtual address for this instruction */ - rip_linear = get_addr_linear(info, rip, &(info->segments.cs)); - if (safe_gva_to_hva(info, rip_linear, &rip_host) < 0) { - rip++; - continue; - } - - /* print disassembled instrcution (updates rip) */ - if (v3_disasm(info, (void *) rip_host, &rip, rip == info->rip) < 0) { - rip++; - continue; - } - - } - - return 0; -} - -#endif - -void v3_print_guest_state(struct guest_info * info) { - addr_t linear_addr = 0; - - V3_Print("RIP: %p\n", (void *)(addr_t)(info->rip)); - linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs)); - V3_Print("RIP Linear: %p\n", (void *)linear_addr); - - V3_Print("NumExits: %u\n", (uint32_t)info->num_exits); - - V3_Print("IRQ STATE: started=%d, pending=%d\n", - info->intr_core_state.irq_started, - info->intr_core_state.irq_pending); - V3_Print("EXCP STATE: err_code_valid=%d, err_code=%x\n", - info->excp_state.excp_error_code_valid, - info->excp_state.excp_error_code); - - - v3_print_segments(&(info->segments)); - v3_print_ctrl_regs(info); - - if (info->shdw_pg_mode == SHADOW_PAGING) { - V3_Print("Shadow Paging Guest Registers:\n"); - V3_Print("\tGuest CR0=%p\n", (void *)(addr_t)(info->shdw_pg_state.guest_cr0)); - V3_Print("\tGuest CR3=%p\n", (void *)(addr_t)(info->shdw_pg_state.guest_cr3)); - V3_Print("\tGuest EFER=%p\n", (void *)(addr_t)(info->shdw_pg_state.guest_efer.value)); - // CR4 - } - v3_print_GPRs(info); - - v3_print_mem_map(info->vm_info); - - v3_print_stack(info); - - // v3_print_disassembly(info); -} - -void v3_print_guest_state_all(struct v3_vm_info * vm) { - int i = 0; - - V3_Print("VM Core states for %s\n", vm->name); - - for (i = 0; i < 80; i++) { - V3_Print("-"); - } - - for (i = 0; i < vm->num_cores; i++) { - v3_print_guest_state(&vm->cores[i]); - } - - for (i = 0; i < 80; i++) { - V3_Print("-"); - } - - V3_Print("\n"); -} - -static void print_real_mode_stack(struct guest_info *info) -{ - uint16_t ss; - uint16_t sp; - addr_t addr; - addr_t host_addr; - int i; - - - ss = info->segments.ss.selector & 0xffff; - sp = info->vm_regs.rsp & 0xffff; - addr = (((uint32_t)ss)<<4) + sp; - - - V3_Print("Real Mode Stack starting at 0x%x:0x%x (0x%p):\n",ss,sp,(void*)addr); - - if (info->mem_mode!=PHYSICAL_MEM) { - PrintError("Cannot print real mode stack when virtual memory active\n"); - return; - } - - for (i=0;i<=24;i++,sp+=2) { - // note that it's correct for this to wrap around - addr = (((uint32_t)ss)<<4) + sp; - if (v3_gpa_to_hva(info,addr,&host_addr)) { - PrintError("Could not translate physical stack address 0x%p\n",(void*)addr); - return; - } - V3_Print("\t0x%.4x\n",*((uint16_t*)host_addr)); - } -} - - - - -void v3_print_stack(struct guest_info * info) { - addr_t linear_addr = 0; - addr_t host_addr = 0; - int i = 0; - v3_cpu_mode_t cpu_mode = v3_get_vm_cpu_mode(info); - - - if (cpu_mode==REAL) { - print_real_mode_stack(info); - return; - } - - // protected mode, 32 or 64 bit - - linear_addr = get_addr_linear(info, info->vm_regs.rsp, &(info->segments.ss)); - - V3_Print("Stack at %p:\n", (void *)linear_addr); - - if (info->mem_mode == PHYSICAL_MEM) { - if (v3_gpa_to_hva(info, linear_addr, &host_addr) == -1) { - PrintError("Could not translate Stack address\n"); - return; - } - } else if (info->mem_mode == VIRTUAL_MEM) { - if (v3_gva_to_hva(info, linear_addr, &host_addr) == -1) { - PrintError("Could not translate Virtual Stack address\n"); - return; - } - } - - V3_Print("Host Address of rsp = 0x%p\n", (void *)host_addr); - - // We start i at one because the current stack pointer points to an unused stack element - for (i = 0; i <= 24; i++) { - if (cpu_mode == LONG) { - V3_Print("\t%p\n", (void *)*(addr_t *)(host_addr + (i * 8))); - } else { - // 32 bit stacks... - V3_Print("\t%.8x\n", *(uint32_t *)(host_addr + (i * 4))); - } - } - -} - -#ifdef __V3_32BIT__ - -void v3_print_GPRs(struct guest_info * info) { - struct v3_gprs * regs = &(info->vm_regs); - int i = 0; - v3_reg_t * reg_ptr; - char * reg_names[] = { "RDI", "RSI", "RBP", "RSP", "RBX", "RDX", "RCX", "RAX", NULL}; - - reg_ptr = (v3_reg_t *)regs; - - V3_Print("32 bit GPRs:\n"); - - for (i = 0; reg_names[i] != NULL; i++) { - V3_Print("\t%s=0x%p (at %p)\n", reg_names[i], (void *)(addr_t)reg_ptr[i], &(reg_ptr[i])); - } -} - -#elif __V3_64BIT__ - -void v3_print_GPRs(struct guest_info * info) { - struct v3_gprs * regs = &(info->vm_regs); - int i = 0; - v3_reg_t * reg_ptr; - char * reg_names[] = { "RDI", "RSI", "RBP", "RSP", "RBX", "RDX", "RCX", "RAX", \ - "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", NULL}; - - reg_ptr = (v3_reg_t *)regs; - - V3_Print("64 bit GPRs:\n"); - - for (i = 0; reg_names[i] != NULL; i++) { - V3_Print("\t%s=0x%p (at %p)\n", reg_names[i], (void *)(addr_t)reg_ptr[i], &(reg_ptr[i])); - } -} - -#endif #include @@ -564,6 +248,8 @@ int v3_init_vm(struct v3_vm_info * vm) { v3_init_time_vm(vm); + v3_init_vm_debugging(vm); + #ifdef V3_CONFIG_SYMBIOTIC v3_init_symbiotic_vm(vm); diff --git a/palacios/src/palacios/vmcs.c b/palacios/src/palacios/vmcs.c index 67c6f69..85ee7a7 100644 --- a/palacios/src/palacios/vmcs.c +++ b/palacios/src/palacios/vmcs.c @@ -24,6 +24,7 @@ #include #include #include +#include diff --git a/palacios/src/palacios/vmm_checkpoint.c b/palacios/src/palacios/vmm_checkpoint.c index ef99cdf..f1ac18d 100644 --- a/palacios/src/palacios/vmm_checkpoint.c +++ b/palacios/src/palacios/vmm_checkpoint.c @@ -27,6 +27,7 @@ #include #include #include +#include #include diff --git a/palacios/src/palacios/vmm_debug.c b/palacios/src/palacios/vmm_debug.c index 51f1c0f..9b2eb6a 100644 --- a/palacios/src/palacios/vmm_debug.c +++ b/palacios/src/palacios/vmm_debug.c @@ -17,41 +17,384 @@ * redistribute, and modify it as specified in the file "V3VEE_LICENSE". */ + #include #include +#include +#include +#include +#include + +#define PRINT_TELEMETRY 1 +#define PRINT_CORE_STATE 2 +#define PRINT_ARCH_STATE 3 +#define PRINT_STACK 4 +#define PRINT_BACKTRACE 5 + + +#define PRINT_ALL 100 // Absolutely everything +#define PRINT_STATE 101 // telemetry, core state, arch state + + + + +static int core_handler(struct guest_info * core, uint32_t cmd) { + + + switch (cmd) { + case PRINT_TELEMETRY: + v3_print_core_telemetry(core); + break; + + case PRINT_CORE_STATE: + v3_raise_barrier(core->vm_info, NULL); + + v3_print_guest_state(core); + + v3_lower_barrier(core->vm_info); + break; + case PRINT_ARCH_STATE: + v3_raise_barrier(core->vm_info, NULL); + + v3_print_arch_state(core); + + v3_lower_barrier(core->vm_info); + break; + case PRINT_STACK: + v3_raise_barrier(core->vm_info, NULL); + + v3_print_stack(core); + + v3_lower_barrier(core->vm_info); + break; + case PRINT_BACKTRACE: + v3_raise_barrier(core->vm_info, NULL); + + v3_print_backtrace(core); + + v3_lower_barrier(core->vm_info); + break; + + case PRINT_STATE: + v3_raise_barrier(core->vm_info, NULL); + + v3_print_core_telemetry(core); + v3_print_guest_state(core); + v3_print_arch_state(core); + + v3_lower_barrier(core->vm_info); + break; + + } + + return 0; +} + + +static int evt_handler(struct v3_vm_info * vm, struct v3_debug_event * evt, void * priv_data) { + + V3_Print("Debug Event Handler for core %d\n", evt->core_id); + + if (evt->core_id == -1) { + int i = 0; + for (i = 0; i < vm->num_cores; i++) { + core_handler(&(vm->cores[i]), evt->cmd); + } + } else { + return core_handler(&vm->cores[evt->core_id], evt->cmd); + } + + + return 0; +} -void PrintDebugHex(uchar_t x) { - unsigned char z; +int v3_init_vm_debugging(struct v3_vm_info * vm) { + v3_hook_host_event(vm, HOST_DEBUG_EVT, + V3_HOST_EVENT_HANDLER(evt_handler), + NULL); + + + return 0; +} + + + + + +void v3_print_segments(struct v3_segments * segs) { + int i = 0; + struct v3_segment * seg_ptr; + + seg_ptr=(struct v3_segment *)segs; - z = (x >> 4) & 0xf ; - PrintDebug("%x", z); - z = x & 0xf; - PrintDebug("%x", z); + char *seg_names[] = {"CS", "DS" , "ES", "FS", "GS", "SS" , "LDTR", "GDTR", "IDTR", "TR", NULL}; + V3_Print("Segments\n"); + + for (i = 0; seg_names[i] != NULL; i++) { + + V3_Print("\t%s: Sel=%x, base=%p, limit=%x (long_mode=%d, db=%d)\n", seg_names[i], seg_ptr[i].selector, + (void *)(addr_t)seg_ptr[i].base, seg_ptr[i].limit, + seg_ptr[i].long_mode, seg_ptr[i].db); + + } } -void PrintDebugMemDump(uchar_t *start, int n) { - int i, j; - for (i = 0; i < n; i += 16) { - PrintDebug("%p", (void *)(start + i)); - for (j = i; (j < (i + 16)) && (j < n); j += 2) { - PrintDebug(" "); - PrintDebugHex(*((uchar_t *)(start + j))); +void v3_print_ctrl_regs(struct guest_info * core) { + struct v3_ctrl_regs * regs = &(core->ctrl_regs); + int i = 0; + v3_reg_t * reg_ptr; + char * reg_names[] = {"CR0", "CR2", "CR3", "CR4", "CR8", "FLAGS", "EFER", NULL}; + - if ((j + 1) < n) { - PrintDebugHex(*((uchar_t *)(start + j + 1))); - } + reg_ptr = (v3_reg_t *)regs; + + V3_Print("Ctrl Regs:\n"); + + for (i = 0; reg_names[i] != NULL; i++) { + V3_Print("\t%s=0x%p (at %p)\n", reg_names[i], (void *)(addr_t)reg_ptr[i], &(reg_ptr[i])); + } + + +} + +#if 0 +static int safe_gva_to_hva(struct guest_info * core, addr_t linear_addr, addr_t * host_addr) { + /* select the proper translation based on guest mode */ + if (core->mem_mode == PHYSICAL_MEM) { + if (v3_gpa_to_hva(core, linear_addr, host_addr) == -1) return -1; + } else if (core->mem_mode == VIRTUAL_MEM) { + if (v3_gva_to_hva(core, linear_addr, host_addr) == -1) return -1; + } + return 0; +} + +static int v3_print_disassembly(struct guest_info * core) { + int passed_rip = 0; + addr_t rip, rip_linear, rip_host; + + /* we don't know where the instructions preceding RIP start, so we just take + * a guess and hope the instruction stream synced up with our disassembly + * some time before RIP; if it has not we correct RIP at that point + */ + + /* start disassembly 64 bytes before current RIP, continue 32 bytes after */ + rip = (addr_t) core->rip - 64; + while ((int) (rip - core->rip) < 32) { + V3_Print("disassembly step\n"); + + /* always print RIP, even if the instructions before were bad */ + if (!passed_rip && rip >= core->rip) { + if (rip != core->rip) { + V3_Print("***** bad disassembly up to this point *****\n"); + rip = core->rip; + } + passed_rip = 1; + } + + /* look up host virtual address for this instruction */ + rip_linear = get_addr_linear(core, rip, &(core->segments.cs)); + if (safe_gva_to_hva(core, rip_linear, &rip_host) < 0) { + rip++; + continue; + } + + /* print disassembled instrcution (updates rip) */ + if (v3_disasm(core, (void *) rip_host, &rip, rip == core->rip) < 0) { + rip++; + continue; + } + + } + return 0; +} + +#endif + +void v3_print_guest_state(struct guest_info * core) { + addr_t linear_addr = 0; + + V3_Print("RIP: %p\n", (void *)(addr_t)(core->rip)); + linear_addr = get_addr_linear(core, core->rip, &(core->segments.cs)); + V3_Print("RIP Linear: %p\n", (void *)linear_addr); + + V3_Print("NumExits: %u\n", (uint32_t)core->num_exits); + + V3_Print("IRQ STATE: started=%d, pending=%d\n", + core->intr_core_state.irq_started, + core->intr_core_state.irq_pending); + V3_Print("EXCP STATE: err_code_valid=%d, err_code=%x\n", + core->excp_state.excp_error_code_valid, + core->excp_state.excp_error_code); + + + v3_print_segments(&(core->segments)); + v3_print_ctrl_regs(core); + + if (core->shdw_pg_mode == SHADOW_PAGING) { + V3_Print("Shadow Paging Guest Registers:\n"); + V3_Print("\tGuest CR0=%p\n", (void *)(addr_t)(core->shdw_pg_state.guest_cr0)); + V3_Print("\tGuest CR3=%p\n", (void *)(addr_t)(core->shdw_pg_state.guest_cr3)); + V3_Print("\tGuest EFER=%p\n", (void *)(addr_t)(core->shdw_pg_state.guest_efer.value)); + // CR4 + } + v3_print_GPRs(core); + + v3_print_mem_map(core->vm_info); + + v3_print_stack(core); + + // v3_print_disassembly(core); +} + + +void v3_print_arch_state(struct guest_info * core) { + + +} + + +void v3_print_guest_state_all(struct v3_vm_info * vm) { + int i = 0; + + V3_Print("VM Core states for %s\n", vm->name); + + for (i = 0; i < 80; i++) { + V3_Print("-"); + } + + for (i = 0; i < vm->num_cores; i++) { + v3_print_guest_state(&vm->cores[i]); + } + + for (i = 0; i < 80; i++) { + V3_Print("-"); + } + + V3_Print("\n"); +} + + + +void v3_print_stack(struct guest_info * core) { + addr_t linear_addr = 0; + addr_t host_addr = 0; + int i = 0; + v3_cpu_mode_t cpu_mode = v3_get_vm_cpu_mode(core); + + linear_addr = get_addr_linear(core, core->vm_regs.rsp, &(core->segments.ss)); + + V3_Print("Stack at %p:\n", (void *)linear_addr); + + if (core->mem_mode == PHYSICAL_MEM) { + if (v3_gpa_to_hva(core, linear_addr, &host_addr) == -1) { + PrintError("Could not translate Stack address\n"); + return; + } + } else if (core->mem_mode == VIRTUAL_MEM) { + if (v3_gva_to_hva(core, linear_addr, &host_addr) == -1) { + PrintError("Could not translate Virtual Stack address\n"); + return; + } + } + + V3_Print("Host Address of rsp = 0x%p\n", (void *)host_addr); + + // We start i at one because the current stack pointer points to an unused stack element + for (i = 0; i <= 24; i++) { + + if (cpu_mode == REAL) { + V3_Print("\t0x%.4x\n", *((uint16_t *)host_addr + (i * 2))); + } else if (cpu_mode == LONG) { + V3_Print("\t%p\n", (void *)*(addr_t *)(host_addr + (i * 8))); + } else { + // 32 bit stacks... + V3_Print("\t0x%.8x\n", *(uint32_t *)(host_addr + (i * 4))); } + } + +} + - PrintDebug(" "); +void v3_print_backtrace(struct guest_info * core) { + addr_t gla_rbp = 0; + int i = 0; + v3_cpu_mode_t cpu_mode = v3_get_vm_cpu_mode(core); - for (j = i; (j < (i + 16)) && (j < n); j++) { - PrintDebug("%c", ((start[j] >= 32) && (start[j] <= 126)) ? start[j] : '.'); + V3_Print("Performing Backtrace for Core %d\n", core->vcpu_id); + V3_Print("\tRSP=%p, RBP=%p\n", (void *)core->vm_regs.rsp, (void *)core->vm_regs.rbp); + + gla_rbp = get_addr_linear(core, core->vm_regs.rbp, &(core->segments.ss)); + + for (i = 0; i < 10; i++) { + addr_t hva_rbp = 0; + addr_t hva_rip = 0; + + if (core->mem_mode == PHYSICAL_MEM) { + if (v3_gpa_to_hva(core, gla_rbp, &hva_rbp) == -1) { + PrintError("Could not translate Stack address\n"); + return; + } + } else if (core->mem_mode == VIRTUAL_MEM) { + if (v3_gva_to_hva(core, gla_rbp, &hva_rbp) == -1) { + PrintError("Could not translate Virtual Stack address\n"); + return; + } } - PrintDebug("\n"); + hva_rip = hva_rbp + v3_get_addr_width(core); + + + if (cpu_mode == REAL) { + V3_Print("Next RBP=0x%.4x, RIP=0x%.4x\n", *(uint16_t *)hva_rbp,*(uint16_t *)hva_rip); + gla_rbp = *(uint16_t *)hva_rbp; + } else if (cpu_mode == LONG) { + V3_Print("Next RBP=%p, RIP=%p\n", (void *)*(uint64_t *)hva_rbp, (void *)*(uint64_t *)hva_rip); + gla_rbp = *(uint64_t *)hva_rbp; + } else { + V3_Print("Next RBP=0x%.8x, RIP=0x%.8x\n", *(uint32_t *)hva_rbp, *(uint32_t *)hva_rip); + gla_rbp = *(uint32_t *)hva_rbp; + } } } + + +#ifdef __V3_32BIT__ + +void v3_print_GPRs(struct guest_info * core) { + struct v3_gprs * regs = &(core->vm_regs); + int i = 0; + v3_reg_t * reg_ptr; + char * reg_names[] = { "RDI", "RSI", "RBP", "RSP", "RBX", "RDX", "RCX", "RAX", NULL}; + + reg_ptr = (v3_reg_t *)regs; + + V3_Print("32 bit GPRs:\n"); + + for (i = 0; reg_names[i] != NULL; i++) { + V3_Print("\t%s=0x%p (at %p)\n", reg_names[i], (void *)(addr_t)reg_ptr[i], &(reg_ptr[i])); + } +} + +#elif __V3_64BIT__ + +void v3_print_GPRs(struct guest_info * core) { + struct v3_gprs * regs = &(core->vm_regs); + int i = 0; + v3_reg_t * reg_ptr; + char * reg_names[] = { "RDI", "RSI", "RBP", "RSP", "RBX", "RDX", "RCX", "RAX", \ + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", NULL}; + + reg_ptr = (v3_reg_t *)regs; + + V3_Print("64 bit GPRs:\n"); + + for (i = 0; reg_names[i] != NULL; i++) { + V3_Print("\t%s=0x%p (at %p)\n", reg_names[i], (void *)(addr_t)reg_ptr[i], &(reg_ptr[i])); + } +} + +#endif diff --git a/palacios/src/palacios/vmm_host_events.c b/palacios/src/palacios/vmm_host_events.c index 28543f7..9d834d6 100644 --- a/palacios/src/palacios/vmm_host_events.c +++ b/palacios/src/palacios/vmm_host_events.c @@ -29,6 +29,7 @@ int v3_init_host_events(struct v3_vm_info * vm) { INIT_LIST_HEAD(&(host_evts->timer_events)); INIT_LIST_HEAD(&(host_evts->serial_events)); INIT_LIST_HEAD(&(host_evts->console_events)); + INIT_LIST_HEAD(&(host_evts->debug_events)); return 0; } @@ -66,6 +67,12 @@ int v3_deinit_host_events(struct v3_vm_info * vm) { V3_Free(hook); } + + list_for_each_entry_safe(hook, tmp, &(host_evts->debug_events), link) { + list_del(&(hook->link)); + V3_Free(hook); + } + return 0; } @@ -103,6 +110,9 @@ int v3_hook_host_event(struct v3_vm_info * vm, case HOST_CONSOLE_EVT: list_add(&(hook->link), &(host_evts->console_events)); break; + case HOST_DEBUG_EVT: + list_add(&(hook->link), &(host_evts->debug_events)); + break; } return 0; @@ -218,3 +228,26 @@ int v3_deliver_console_event(struct v3_vm_info * vm, return 0; } + + +int v3_deliver_debug_event(struct v3_vm_info * vm, + struct v3_debug_event * evt) { + struct v3_host_events * host_evts = NULL; + struct v3_host_event_hook * hook = NULL; + + + host_evts = &(vm->host_event_hooks); + + if (vm->run_state != VM_RUNNING) { + return -1; + } + + list_for_each_entry(hook, &(host_evts->debug_events), link) { + if (hook->cb.debug_handler(vm, evt, hook->private_data) == -1) { + return -1; + } + } + + return 0; +} + diff --git a/palacios/src/palacios/vmm_mem.c b/palacios/src/palacios/vmm_mem.c index 3753a93..ee99811 100644 --- a/palacios/src/palacios/vmm_mem.c +++ b/palacios/src/palacios/vmm_mem.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/palacios/src/palacios/vmm_symcall.c b/palacios/src/palacios/vmm_symcall.c index c78fe88..7044e9a 100644 --- a/palacios/src/palacios/vmm_symcall.c +++ b/palacios/src/palacios/vmm_symcall.c @@ -161,6 +161,64 @@ static int execute_symcall(struct guest_info * core) { } +// +// We don't handle those fancy 64 bit system segments... +// +static int translate_segment(struct guest_info * info, uint16_t selector, struct v3_segment * seg) { + struct v3_segment * gdt = &(info->segments.gdtr); + addr_t gdt_addr = 0; + uint16_t seg_offset = (selector & ~0x7); + addr_t seg_addr = 0; + struct gen_segment * gen_seg = NULL; + struct seg_selector sel; + + memset(seg, 0, sizeof(struct v3_segment)); + + sel.value = selector; + + if (sel.ti == 1) { + PrintError("LDT translations not supported\n"); + return -1; + } + + if (v3_gva_to_hva(info, gdt->base, &gdt_addr) == -1) { + PrintError("Unable to translate GDT address\n"); + return -1; + } + + seg_addr = gdt_addr + seg_offset; + gen_seg = (struct gen_segment *)seg_addr; + + //translate + seg->selector = selector; + + seg->limit = gen_seg->limit_hi; + seg->limit <<= 16; + seg->limit += gen_seg->limit_lo; + + seg->base = gen_seg->base_hi; + seg->base <<= 24; + seg->base += gen_seg->base_lo; + + if (gen_seg->granularity == 1) { + seg->limit <<= 12; + seg->limit |= 0xfff; + } + + seg->type = gen_seg->type; + seg->system = gen_seg->system; + seg->dpl = gen_seg->dpl; + seg->present = gen_seg->present; + seg->avail = gen_seg->avail; + seg->long_mode = gen_seg->long_mode; + seg->db = gen_seg->db; + seg->granularity = gen_seg->granularity; + + return 0; +} + + + int v3_sym_call(struct guest_info * core, uint64_t call_num, sym_arg_t * arg0, sym_arg_t * arg1, sym_arg_t * arg2, @@ -200,10 +258,10 @@ int v3_sym_call(struct guest_info * core, core->rip = state->sym_call_rip; core->vm_regs.rsp = state->sym_call_rsp; // old contest rsp is saved in vm_regs - v3_translate_segment(core, state->sym_call_cs, &sym_cs); + translate_segment(core, state->sym_call_cs, &sym_cs); memcpy(&(core->segments.cs), &sym_cs, sizeof(struct v3_segment)); - v3_translate_segment(core, state->sym_call_cs + 8, &sym_ss); + translate_segment(core, state->sym_call_cs + 8, &sym_ss); memcpy(&(core->segments.ss), &sym_ss, sizeof(struct v3_segment)); core->segments.gs.base = state->sym_call_gs; diff --git a/palacios/src/palacios/vmx.c b/palacios/src/palacios/vmx.c index 0950045..d9fc081 100644 --- a/palacios/src/palacios/vmx.c +++ b/palacios/src/palacios/vmx.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef V3_CONFIG_CHECKPOINT #include diff --git a/palacios/src/palacios/vmx_handler.c b/palacios/src/palacios/vmx_handler.c index 51bf62d..0cf500f 100644 --- a/palacios/src/palacios/vmx_handler.c +++ b/palacios/src/palacios/vmx_handler.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ #include #include + #ifndef V3_CONFIG_DEBUG_VMX #undef PrintDebug #define PrintDebug(fmt, args...)