Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/gdb.c
| Show First 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | |||||
| static struct io_buffer cur_comm, cur_resp; | static struct io_buffer cur_comm, cur_resp; | ||||
| static uint8_t cur_csum; | static uint8_t cur_csum; | ||||
| static struct vmctx *ctx; | static struct vmctx *ctx; | ||||
| static int cur_fd = -1; | static int cur_fd = -1; | ||||
| static TAILQ_HEAD(, breakpoint) breakpoints; | static TAILQ_HEAD(, breakpoint) breakpoints; | ||||
| static struct vcpu_state *vcpu_state; | static struct vcpu_state *vcpu_state; | ||||
| static int cur_vcpu, stopped_vcpu; | static int cur_vcpu, stopped_vcpu; | ||||
| static bool gdb_active = false; | |||||
| const int gdb_regset[] = { | const int gdb_regset[] = { | ||||
| VM_REG_GUEST_RAX, | VM_REG_GUEST_RAX, | ||||
| VM_REG_GUEST_RBX, | VM_REG_GUEST_RBX, | ||||
| VM_REG_GUEST_RCX, | VM_REG_GUEST_RCX, | ||||
| VM_REG_GUEST_RDX, | VM_REG_GUEST_RDX, | ||||
| VM_REG_GUEST_RSI, | VM_REG_GUEST_RSI, | ||||
| VM_REG_GUEST_RDI, | VM_REG_GUEST_RDI, | ||||
| ▲ Show 20 Lines • Show All 583 Lines • ▼ Show 20 Lines | |||||
| * vCPU threads invoke this function whenever the vCPU enters the | * vCPU threads invoke this function whenever the vCPU enters the | ||||
| * debug server to pause or report an event. vCPU threads wait here | * debug server to pause or report an event. vCPU threads wait here | ||||
| * as long as the debug server keeps them suspended. | * as long as the debug server keeps them suspended. | ||||
| */ | */ | ||||
| static void | static void | ||||
| _gdb_cpu_suspend(int vcpu, bool report_stop) | _gdb_cpu_suspend(int vcpu, bool report_stop) | ||||
| { | { | ||||
| if (!gdb_active) | |||||
| return; | |||||
| debug("$vCPU %d suspending\n", vcpu); | debug("$vCPU %d suspending\n", vcpu); | ||||
| CPU_SET(vcpu, &vcpus_waiting); | CPU_SET(vcpu, &vcpus_waiting); | ||||
| if (report_stop && CPU_CMP(&vcpus_waiting, &vcpus_suspended) == 0) | if (report_stop && CPU_CMP(&vcpus_waiting, &vcpus_suspended) == 0) | ||||
| gdb_finish_suspend_vcpus(); | gdb_finish_suspend_vcpus(); | ||||
| while (CPU_ISSET(vcpu, &vcpus_suspended)) | while (CPU_ISSET(vcpu, &vcpus_suspended)) | ||||
| pthread_cond_wait(&idle_vcpus, &gdb_lock); | pthread_cond_wait(&idle_vcpus, &gdb_lock); | ||||
| CPU_CLR(vcpu, &vcpus_waiting); | CPU_CLR(vcpu, &vcpus_waiting); | ||||
| debug("$vCPU %d resuming\n", vcpu); | debug("$vCPU %d resuming\n", vcpu); | ||||
| } | } | ||||
| /* | /* | ||||
| * Invoked at the start of a vCPU thread's execution to inform the | * Invoked at the start of a vCPU thread's execution to inform the | ||||
| * debug server about the new thread. | * debug server about the new thread. | ||||
| */ | */ | ||||
| void | void | ||||
| gdb_cpu_add(int vcpu) | gdb_cpu_add(int vcpu) | ||||
| { | { | ||||
| if (!gdb_active) | |||||
| return; | |||||
| debug("$vCPU %d starting\n", vcpu); | debug("$vCPU %d starting\n", vcpu); | ||||
| pthread_mutex_lock(&gdb_lock); | pthread_mutex_lock(&gdb_lock); | ||||
| assert(vcpu < guest_ncpus); | assert(vcpu < guest_ncpus); | ||||
| CPU_SET(vcpu, &vcpus_active); | CPU_SET(vcpu, &vcpus_active); | ||||
| if (!TAILQ_EMPTY(&breakpoints)) { | if (!TAILQ_EMPTY(&breakpoints)) { | ||||
| vm_set_capability(ctx, vcpu, VM_CAP_BPT_EXIT, 1); | vm_set_capability(ctx, vcpu, VM_CAP_BPT_EXIT, 1); | ||||
| debug("$vCPU %d enabled breakpoint exits\n", vcpu); | debug("$vCPU %d enabled breakpoint exits\n", vcpu); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
| * Handler for VM_EXITCODE_MTRAP reported when a vCPU single-steps via | * Handler for VM_EXITCODE_MTRAP reported when a vCPU single-steps via | ||||
| * the VT-x-specific MTRAP exit. | * the VT-x-specific MTRAP exit. | ||||
| */ | */ | ||||
| void | void | ||||
| gdb_cpu_mtrap(int vcpu) | gdb_cpu_mtrap(int vcpu) | ||||
| { | { | ||||
| struct vcpu_state *vs; | struct vcpu_state *vs; | ||||
| if (!gdb_active) | |||||
| return; | |||||
| debug("$vCPU %d MTRAP\n", vcpu); | debug("$vCPU %d MTRAP\n", vcpu); | ||||
| pthread_mutex_lock(&gdb_lock); | pthread_mutex_lock(&gdb_lock); | ||||
| vs = &vcpu_state[vcpu]; | vs = &vcpu_state[vcpu]; | ||||
| if (vs->stepping) { | if (vs->stepping) { | ||||
| vs->stepping = false; | vs->stepping = false; | ||||
| vs->stepped = true; | vs->stepped = true; | ||||
| vm_set_capability(ctx, vcpu, VM_CAP_MTRAP_EXIT, 0); | vm_set_capability(ctx, vcpu, VM_CAP_MTRAP_EXIT, 0); | ||||
| while (vs->stepped) { | while (vs->stepped) { | ||||
| Show All 24 Lines | |||||
| void | void | ||||
| gdb_cpu_breakpoint(int vcpu, struct vm_exit *vmexit) | gdb_cpu_breakpoint(int vcpu, struct vm_exit *vmexit) | ||||
| { | { | ||||
| struct breakpoint *bp; | struct breakpoint *bp; | ||||
| struct vcpu_state *vs; | struct vcpu_state *vs; | ||||
| uint64_t gpa; | uint64_t gpa; | ||||
| int error; | int error; | ||||
| if (!gdb_active) { | |||||
| fprintf(stderr, "vm_loop: unexpected VMEXIT_DEBUG\n"); | |||||
| exit(4); | |||||
| } | |||||
| pthread_mutex_lock(&gdb_lock); | pthread_mutex_lock(&gdb_lock); | ||||
| error = guest_vaddr2paddr(vcpu, vmexit->rip, &gpa); | error = guest_vaddr2paddr(vcpu, vmexit->rip, &gpa); | ||||
| assert(error == 1); | assert(error == 1); | ||||
| bp = find_breakpoint(gpa); | bp = find_breakpoint(gpa); | ||||
| if (bp != NULL) { | if (bp != NULL) { | ||||
| vs = &vcpu_state[vcpu]; | vs = &vcpu_state[vcpu]; | ||||
| assert(vs->stepping == false); | assert(vs->stepping == false); | ||||
| assert(vs->stepped == false); | assert(vs->stepped == false); | ||||
| ▲ Show 20 Lines • Show All 974 Lines • ▼ Show 20 Lines | init_gdb(struct vmctx *_ctx, int sport, bool wait) | ||||
| flags = fcntl(s, F_GETFL); | flags = fcntl(s, F_GETFL); | ||||
| if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) | if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) | ||||
| err(1, "Failed to mark gdb socket non-blocking"); | err(1, "Failed to mark gdb socket non-blocking"); | ||||
| #ifndef WITHOUT_CAPSICUM | #ifndef WITHOUT_CAPSICUM | ||||
| limit_gdb_socket(s); | limit_gdb_socket(s); | ||||
| #endif | #endif | ||||
| mevent_add(s, EVF_READ, new_connection, NULL); | mevent_add(s, EVF_READ, new_connection, NULL); | ||||
| gdb_active = true; | |||||
| } | } | ||||