Esempio n. 1
0
/*
 * Returns: bytes remaining to be read. 0 => read all bytes, ie, success.
 */
int 
xg_read_mem(uint64_t guestva, char *tobuf, int tobuf_len, uint64_t pgd3val)
{
    struct xen_domctl_gdbsx_memio *iop = &domctl.u.gdbsx_guest_memio;
    union {uint64_t llbuf8; char buf8[8];} u = {0};
    int i, rc;

    XGTRC("E:gva:%llx tobuf:%lx len:%d\n", guestva, tobuf, tobuf_len);

    memset(&domctl.u, 0, sizeof(domctl.u));
    iop->pgd3val = pgd3val;
    iop->gva = guestva;
    iop->uva = (uint64_aligned_t)((unsigned long)tobuf);
    iop->len = tobuf_len;
    iop->gwr = 0;       /* not writing to guest */

    if ( (rc = _domctl_hcall(XEN_DOMCTL_gdbsx_guestmemio, tobuf, tobuf_len)) )
    {
        XGTRC("ERROR: failed to read bytes. errno:%d rc:%d\n", errno, rc);
        return tobuf_len;
    }

    for(i=0; i < XGMIN(8, tobuf_len); u.buf8[i]=tobuf[i], i++);
    XGTRC("X:remain:%d buf8:0x%llx\n", iop->remain, u.llbuf8);

    return iop->remain;
}
Esempio n. 2
0
/*
 * 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;
}
Esempio n. 3
0
/*
 * 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;
}
Esempio n. 4
0
/*
 * Returns: 0 success
 *         -1 failure, errno set.
 */
int 
xg_init()
{
    int flags, saved_errno;

    XGTRC("E\n");
    if ((_dom0_fd=open("/proc/xen/privcmd", O_RDWR)) == -1) {
        perror("Failed to open /proc/xen/privcmd\n");
        return -1;
    }
    /* Although we return the file handle as the 'xc handle' the API
     * does not specify / guarentee that this integer is in fact
     * a file handle. Thus we must take responsiblity to ensure
     * it doesn't propagate (ie leak) outside the process (copied comment)*/
    if ( (flags=fcntl(_dom0_fd, F_GETFD)) < 0 ) {
        perror("Could not get file handle flags (F_GETFD)");
        goto error;
    }
    flags |= FD_CLOEXEC;
    if (fcntl(_dom0_fd, F_SETFD, flags) < 0) {
        perror("Could not set file handle flags");
        goto error;
    }

    XGTRC("X:fd:%d\n", _dom0_fd);
    return _dom0_fd;

 error:
    XGTRC("X:Error: errno:%d\n", errno);
    saved_errno = errno;
    close(_dom0_fd);
    errno = saved_errno;
    return -1;
}
Esempio n. 5
0
/*
 * Returns: bytes that could not be written. 0 => wrote all bytes, ie, success.
 */
int 
xg_write_mem(uint64_t guestva, char *frombuf, int buflen, uint64_t pgd3val)
{
    struct xen_domctl_gdbsx_memio *iop = &domctl.u.gdbsx_guest_memio;
    union {uint64_t llbuf8; char buf8[8];} u = {0};
    int i, rc;

    for(i=0; i < XGMIN(8, buflen); u.buf8[i]=frombuf[i], i++);
    XGTRC("E:gva:%llx frombuf:%lx len:%d buf8:0x%llx\n", guestva, frombuf, 
          buflen, u.llbuf8);

    memset(&domctl.u, 0, sizeof(domctl.u));
    iop->pgd3val = pgd3val;
    iop->gva = guestva;
    iop->uva = (uint64_aligned_t)((unsigned long)frombuf);
    iop->len = buflen;
    iop->gwr = 1;       /* writing to guest */

    if ((rc=_domctl_hcall(XEN_DOMCTL_gdbsx_guestmemio, frombuf, buflen)))
    {
        XGERR("ERROR: failed to write bytes to %llx. errno:%d rc:%d\n",
              guestva, errno, rc);
        return buflen;
    }
    return iop->remain;
}
Esempio n. 6
0
/*
 * write registers for the given vcpu
 * Returns: 0 success, 1 failure with errno
 */
int 
xg_regs_write(regstype_t which_regs, vcpuid_t which_vcpu, 
              union xg_gdb_regs *regsp, int guest_bitness)
{
    union vcpu_guest_context_any anyc;
    struct cpu_user_regs_x86_32 *cr32p = &anyc.ctxt32.user_regs;
    struct cpu_user_regs_x86_64 *cr64p = &anyc.ctxt64.user_regs;
    struct xg_gdb_regs32 *r32p = &regsp->gregs_32;
    struct xg_gdb_regs64 *r64p = &regsp->gregs_64;
    int rc, sz = sizeof(anyc);

    if (which_regs != XG_GPRS) {
        errno = EINVAL;
        XGERR("regs got: %d. Expected GPRS:%d\n", which_regs, XG_GPRS);
        return 1;
    }
    if ((rc=_get_vcpu_ctxt(which_vcpu, &anyc)))
        return rc;

    if (guest_bitness == 32) {
        if (_32bit_hyp || !_hvm_guest)
            _cp_32gdb_to_32ctxt(r32p, cr32p);
        else 
            _cp_32gdb_to_64ctxt(r32p, cr64p);
    } else
        _cp_64gdb_to_64ctxt(r64p, cr64p);

    /* set vcpu context back */
    if ((rc =_domctl_hcall(XEN_DOMCTL_setvcpucontext, &anyc, sz))) {
        XGERR("Failed hcall to set vcpu ctxt. errno:%d\n", errno);
        return rc;
    }
    XGTRC("X:vcpu:%d bitness:%d rc:%d\n", which_vcpu, guest_bitness, rc);
    return rc;
}
Esempio n. 7
0
/*
 * read regs for a particular vcpu. For now only GPRs, no FPRs.
 * Returns: 0 success,  else failure with errno set
 */
int 
xg_regs_read(regstype_t which_regs, vcpuid_t which_vcpu, 
             union xg_gdb_regs *regsp, int guest_bitness)
{
    union vcpu_guest_context_any anyc;
    struct cpu_user_regs_x86_32 *cr32p = &anyc.ctxt32.user_regs;
    struct cpu_user_regs_x86_64 *cr64p = &anyc.ctxt64.user_regs;
    struct xg_gdb_regs32 *r32p = &regsp->gregs_32;
    struct xg_gdb_regs64 *r64p = &regsp->gregs_64;
    int rc;

    if (which_regs != XG_GPRS) {
        errno = EINVAL;
        XGERR("regs got: %d. Expected GPRS:%d\n", which_regs, XG_GPRS);
        return 1;
    }
    if ((rc=_get_vcpu_ctxt(which_vcpu, &anyc)))
        return rc;

    /* 64bit hyp: only 32bit PV returns 32bit context, all others 64bit.
     * 32bit hyp: all contexts returned are 32bit */
    if (guest_bitness == 32) {
        if (_32bit_hyp || !_hvm_guest)
            _cp_32ctxt_to_32gdb(cr32p, r32p);
        else 
            _cp_64ctxt_to_32gdb(cr64p, r32p);
    } else
        _cp_64ctxt_to_64gdb(cr64p, r64p);
                
    XGTRC("X:vcpu:%d bitness:%d rc:%d\n", which_vcpu, guest_bitness, rc);
    return rc;
}
Esempio n. 8
0
/*
 * Change the TF flag for single step.   TF = (setit ? 1 : 0);
 * Returns: 0 Success
 */
static int
_change_TF(vcpuid_t which_vcpu, int guest_bitness, int setit)
{
    union vcpu_guest_context_any anyc;
    int sz = sizeof(anyc);

    /* first try the MTF for hvm guest. otherwise do manually */
    if (_hvm_guest) {
        domctl.u.debug_op.vcpu = which_vcpu;
        domctl.u.debug_op.op = setit ? XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON :
                                       XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF;

        if (_domctl_hcall(XEN_DOMCTL_debug_op, NULL, 0) == 0) {
            XGTRC("vcpu:%d:MTF success setit:%d\n", which_vcpu, setit);
            return 0;
        }
        XGTRC("vcpu:%d:MTF failed. setit:%d\n", which_vcpu, setit);
    }

    memset(&anyc, 0, sz);
    domctl.u.vcpucontext.vcpu = (uint16_t)which_vcpu;
    set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &anyc.ctxt);

    if (_domctl_hcall(XEN_DOMCTL_getvcpucontext, &anyc, sz)) {
        XGERR("Failed hcall to get vcpu ctxt for TF. errno:%d\n",errno);
        return 1;
    }
    if (_32bit_hyp || (guest_bitness == 32 && !_hvm_guest)) {
        if (setit)
            anyc.ctxt32.user_regs.eflags |= X86_EFLAGS_TF;
        else
            anyc.ctxt32.user_regs.eflags &= ~X86_EFLAGS_TF;
    } else {
        if (setit)
            anyc.ctxt64.user_regs.rflags |= X86_EFLAGS_TF;
        else
            anyc.ctxt64.user_regs.rflags &= ~X86_EFLAGS_TF;
    }

    if (_domctl_hcall(XEN_DOMCTL_setvcpucontext, &anyc, sz)) {
        XGERR("Failed hcall to set vcpu ctxt for TF. errno:%d\n",errno);
        return 1;
    }
    return 0;
}
Esempio n. 9
0
/* 
 * Returns : 0 success. 
 *           1 error, with errno set (hopefully :))
 */
static int 
_wait_domain_pause(void)
{
    int dom_paused;
    struct timespec ts={0, 10*1000*1000};

    XGTRC("E:\n");
    do {
        dom_paused = _domain_is_paused();
        nanosleep(&ts, NULL);
    } while(!dom_paused);
    return 0;
}
Esempio n. 10
0
/*
 * 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;
}
Esempio n. 11
0
/* 
 * Make sure we are running on hyp enabled for gdbsx. Also, note whether
 * its 32bit. Fail if user typed 64bit for guest in case of 32bit hyp.
 *
 * RETURNS: 0 : everything OK. 
 */
static int
_check_hyp(int guest_bitness)
{
    xen_capabilities_info_t xen_caps = "";
    privcmd_hypercall_t hypercall;
    int rc;

    /*
     * Try to unpause an invalid vcpu. If hypervisor supports gdbsx then
     * this should fail with an error other than ENOSYS.
     */
    domctl.u.gdbsx_pauseunp_vcpu.vcpu = ~0u;
    (void)_domctl_hcall(XEN_DOMCTL_gdbsx_unpausevcpu, NULL, 0);
    if (errno == ENOSYS) {
        XGERR("Hyp is NOT enabled for gdbsx\n");
        return -1;
    } 

    if (mlock(&xen_caps, sizeof(xen_caps))) {
        XGERR("Unable to pin xen_caps in memory. errno:%d\n", errno);
        return -1;
    }
    memset(&xen_caps, 0, sizeof(xen_caps));

    hypercall.op = __HYPERVISOR_xen_version;
    hypercall.arg[0] = (unsigned long)XENVER_capabilities;
    hypercall.arg[1] = (unsigned long)&xen_caps;

    rc = ioctl(_dom0_fd, IOCTL_PRIVCMD_HYPERCALL, &hypercall);
    munlock(&xen_caps, sizeof(xen_caps));
    XGTRC("XENCAPS:%s\n", xen_caps);

    if (rc != 0) {
        XGERR("Failed xen_version hcall. errno:%d\n", errno);
        return -1;
    }

    _32bit_hyp = (strstr(xen_caps, "x86_64") == NULL);
    if (_32bit_hyp && guest_bitness !=32) {
        XGERR("32bit hyp can only run 32bit guests\n");
        return -1;
    }
    return 0;
}