/* * Resume the domain if no pending events. If there are pending events, like * another vcpu in a BP, report it. Otherwise, continue, and wait till an * event, like bp or user doing xm pause, occurs. * * Returns: vcpuid : if a vcpu hits a breakpoint or end of step * -1 : either an error (msg printed on terminal), or non-bp * event, like "xm pause domid", to enter debugger */ vcpuid_t xg_resume_n_wait(int guest_bitness) { vcpuid_t vcpu; XGTRC("E:\n"); assert(_domain_is_paused()); if ((vcpu=_vcpu_in_bp()) != -1) { /* another vcpu in breakpoint. return it's id */ return vcpu; } XGTRC("unpausing domain\n"); if (_unpause_domain()) return -1; /* now wait for domain to pause */ _wait_domain_pause(); /* check again if any vcpu in BP, or user thru "xm pause" */ vcpu = _vcpu_in_bp(); XGTRC("X:vcpu:%d\n", vcpu); return vcpu; }
/* * Single step the given vcpu. This is achieved by pausing all but given vcpus, * setting the TF flag, let the domain run and pause, unpause all vcpus, and * clear TF flag on given vcpu. * Returns: 0 success */ int xg_step(vcpuid_t which_vcpu, int guest_bitness) { int rc; XGTRC("E:vcpu:%d\n", (int)which_vcpu); if (_allbutone_vcpu(XEN_DOMCTL_gdbsx_pausevcpu, which_vcpu)) return 1; if ((rc=_change_TF(which_vcpu, guest_bitness, 1))) return rc; XGTRC("unpausing domain\n"); /* now unpause the domain so our vcpu can execute */ if (_unpause_domain()) return 1; /* wait for our vcpu to finish step */ _wait_domain_pause(); _allbutone_vcpu(XEN_DOMCTL_gdbsx_unpausevcpu, which_vcpu); rc = _change_TF(which_vcpu, guest_bitness, 0); return rc; }
/* * Attach to the given domid for debugging. * Returns: max vcpu id : Success * -1 : Failure */ int xg_attach(int domid, int guest_bitness) { XGTRC("E:domid:%d\n", domid); _dom_id = domctl.domain = domid; domctl.interface_version = XEN_DOMCTL_INTERFACE_VERSION; if (mlock(&domctl, sizeof(domctl))) { XGERR("Unable to pin domctl in memory. errno:%d\n", errno); return -1; } if (_check_hyp(guest_bitness)) return -1; if (_domctl_hcall(XEN_DOMCTL_pausedomain, NULL, 0)) { XGERR("Unable to pause domain:%d\n", _dom_id); return -1; } memset(&domctl.u, 0, sizeof(domctl.u)); domctl.u.setdebugging.enable = 1; if (_domctl_hcall(XEN_DOMCTL_setdebugging, NULL, 0)) { XGERR("Unable to set domain to debug mode: errno:%d\n", errno); _unpause_domain(); return -1; } memset(&domctl.u, 0, sizeof(domctl.u)); if (_domctl_hcall(XEN_DOMCTL_getdomaininfo, NULL, 0)) { XGERR("Unable to get domain info: domid:%d errno:%d\n", domid, errno); _unpause_domain(); return -1; } if (!_domain_ok(&domctl.u.getdomaininfo)) { _unpause_domain(); return -1; } _max_vcpu_id = domctl.u.getdomaininfo.max_vcpu_id; _hvm_guest = (domctl.u.getdomaininfo.flags & XEN_DOMINF_hvm_guest); _pvh_guest = (domctl.u.getdomaininfo.flags & XEN_DOMINF_pvh_guest); return _max_vcpu_id; }
/* Detach from guest for debugger exit */ void xg_detach_deinit(void) { memset(&domctl.u, 0, sizeof(domctl.u)); domctl.u.setdebugging.enable = 0; if (_domctl_hcall(XEN_DOMCTL_setdebugging, NULL, 0)) { XGERR("Unable to reset domain debug mode: errno:%d\n", errno); } if (_domain_is_paused()) _unpause_domain(); close(_dom0_fd); }