mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
654 lines
17 KiB
C
654 lines
17 KiB
C
#include <sys/ptrace.h>
|
|
#include <sys/wait.h>
|
|
#include <time.h>
|
|
|
|
#include "xc_private.h"
|
|
#include "xg_private.h"
|
|
#include "xc_ptrace.h"
|
|
|
|
#ifdef DEBUG
|
|
static char *ptrace_names[] = {
|
|
"PTRACE_TRACEME",
|
|
"PTRACE_PEEKTEXT",
|
|
"PTRACE_PEEKDATA",
|
|
"PTRACE_PEEKUSER",
|
|
"PTRACE_POKETEXT",
|
|
"PTRACE_POKEDATA",
|
|
"PTRACE_POKEUSER",
|
|
"PTRACE_CONT",
|
|
"PTRACE_KILL",
|
|
"PTRACE_SINGLESTEP",
|
|
"PTRACE_INVALID",
|
|
"PTRACE_INVALID",
|
|
"PTRACE_GETREGS",
|
|
"PTRACE_SETREGS",
|
|
"PTRACE_GETFPREGS",
|
|
"PTRACE_SETFPREGS",
|
|
"PTRACE_ATTACH",
|
|
"PTRACE_DETACH",
|
|
"PTRACE_GETFPXREGS",
|
|
"PTRACE_SETFPXREGS",
|
|
"PTRACE_INVALID",
|
|
"PTRACE_INVALID",
|
|
"PTRACE_INVALID",
|
|
"PTRACE_INVALID",
|
|
"PTRACE_SYSCALL",
|
|
};
|
|
#endif
|
|
|
|
static int current_domid = -1;
|
|
static int current_isfile;
|
|
static int current_is_hvm;
|
|
|
|
static uint64_t online_cpumap;
|
|
static uint64_t regs_valid;
|
|
static vcpu_guest_context_t ctxt[MAX_VIRT_CPUS];
|
|
|
|
extern int ffsll(long long int);
|
|
#define FOREACH_CPU(cpumap, i) for ( cpumap = online_cpumap; (i = ffsll(cpumap)); cpumap &= ~(1 << (index - 1)) )
|
|
|
|
static int
|
|
fetch_regs(int xc_handle, int cpu, int *online)
|
|
{
|
|
xc_vcpuinfo_t info;
|
|
int retval = 0;
|
|
|
|
if (online)
|
|
*online = 0;
|
|
if ( !(regs_valid & (1 << cpu)) )
|
|
{
|
|
retval = xc_vcpu_getcontext(xc_handle, current_domid,
|
|
cpu, &ctxt[cpu]);
|
|
if ( retval )
|
|
goto done;
|
|
regs_valid |= (1 << cpu);
|
|
|
|
}
|
|
if ( online == NULL )
|
|
goto done;
|
|
|
|
retval = xc_vcpu_getinfo(xc_handle, current_domid, cpu, &info);
|
|
*online = info.online;
|
|
|
|
done:
|
|
return retval;
|
|
}
|
|
|
|
static struct thr_ev_handlers {
|
|
thr_ev_handler_t td_create;
|
|
thr_ev_handler_t td_death;
|
|
} handlers;
|
|
|
|
void
|
|
xc_register_event_handler(thr_ev_handler_t h,
|
|
td_event_e e)
|
|
{
|
|
switch (e) {
|
|
case TD_CREATE:
|
|
handlers.td_create = h;
|
|
break;
|
|
case TD_DEATH:
|
|
handlers.td_death = h;
|
|
break;
|
|
default:
|
|
abort(); /* XXX */
|
|
}
|
|
}
|
|
|
|
static inline int
|
|
paging_enabled(vcpu_guest_context_t *v)
|
|
{
|
|
unsigned long cr0 = v->ctrlreg[0];
|
|
return (cr0 & X86_CR0_PE) && (cr0 & X86_CR0_PG);
|
|
}
|
|
|
|
/*
|
|
* Fetch registers for all online cpus and set the cpumap
|
|
* to indicate which cpus are online
|
|
*
|
|
*/
|
|
|
|
static int
|
|
get_online_cpumap(int xc_handle, struct xen_domctl_getdomaininfo *d,
|
|
uint64_t *cpumap)
|
|
{
|
|
int i, online, retval;
|
|
|
|
*cpumap = 0;
|
|
for (i = 0; i <= d->max_vcpu_id; i++) {
|
|
if ((retval = fetch_regs(xc_handle, i, &online)))
|
|
return retval;
|
|
if (online)
|
|
*cpumap |= (1 << i);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Notify GDB of any vcpus that have come online or gone offline
|
|
* update online_cpumap
|
|
*
|
|
*/
|
|
|
|
static void
|
|
online_vcpus_changed(uint64_t cpumap)
|
|
{
|
|
uint64_t changed_cpumap = cpumap ^ online_cpumap;
|
|
int index;
|
|
|
|
while ( (index = ffsll(changed_cpumap)) ) {
|
|
if ( cpumap & (1 << (index - 1)) )
|
|
{
|
|
if (handlers.td_create) handlers.td_create(index - 1);
|
|
} else {
|
|
IPRINTF("thread death: %d\n", index - 1);
|
|
if (handlers.td_death) handlers.td_death(index - 1);
|
|
}
|
|
changed_cpumap &= ~(1 << (index - 1));
|
|
}
|
|
online_cpumap = cpumap;
|
|
|
|
}
|
|
|
|
/* --------------------- */
|
|
/* XXX application state */
|
|
static long nr_pages = 0;
|
|
static unsigned long *page_array = NULL;
|
|
|
|
|
|
/*
|
|
* Translates physical addresses to machine addresses for HVM
|
|
* guests. For paravirtual domains the function will just return the
|
|
* given address.
|
|
*
|
|
* This function should be used when reading page directories/page
|
|
* tables.
|
|
*
|
|
*/
|
|
static uint64_t
|
|
to_ma(int cpu, uint64_t maddr)
|
|
{
|
|
if ( current_is_hvm && paging_enabled(&ctxt[cpu]) )
|
|
maddr = (uint64_t)page_array[maddr >> PAGE_SHIFT] << PAGE_SHIFT;
|
|
return maddr;
|
|
}
|
|
|
|
static void *
|
|
map_domain_va_32(
|
|
int xc_handle,
|
|
int cpu,
|
|
void *guest_va,
|
|
int perm)
|
|
{
|
|
unsigned long l2e, l1e, l1p, p, va = (unsigned long)guest_va;
|
|
uint32_t *l2, *l1;
|
|
static void *v[MAX_VIRT_CPUS];
|
|
|
|
l2 = xc_map_foreign_range(
|
|
xc_handle, current_domid, PAGE_SIZE, PROT_READ,
|
|
xen_cr3_to_pfn(ctxt[cpu].ctrlreg[3]));
|
|
if ( l2 == NULL )
|
|
return NULL;
|
|
|
|
l2e = l2[l2_table_offset_i386(va)];
|
|
munmap(l2, PAGE_SIZE);
|
|
if ( !(l2e & _PAGE_PRESENT) )
|
|
return NULL;
|
|
l1p = to_ma(cpu, l2e);
|
|
l1 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, PROT_READ, l1p >> PAGE_SHIFT);
|
|
if ( l1 == NULL )
|
|
return NULL;
|
|
|
|
l1e = l1[l1_table_offset_i386(va)];
|
|
munmap(l1, PAGE_SIZE);
|
|
if ( !(l1e & _PAGE_PRESENT) )
|
|
return NULL;
|
|
p = to_ma(cpu, l1e);
|
|
if ( v[cpu] != NULL )
|
|
munmap(v[cpu], PAGE_SIZE);
|
|
v[cpu] = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, perm, p >> PAGE_SHIFT);
|
|
if ( v[cpu] == NULL )
|
|
return NULL;
|
|
|
|
return (void *)((unsigned long)v[cpu] | (va & (PAGE_SIZE - 1)));
|
|
}
|
|
|
|
|
|
static void *
|
|
map_domain_va_pae(
|
|
int xc_handle,
|
|
int cpu,
|
|
void *guest_va,
|
|
int perm)
|
|
{
|
|
uint64_t l3e, l2e, l1e, l2p, l1p, p;
|
|
unsigned long va = (unsigned long)guest_va;
|
|
uint64_t *l3, *l2, *l1;
|
|
static void *v[MAX_VIRT_CPUS];
|
|
|
|
l3 = xc_map_foreign_range(
|
|
xc_handle, current_domid, PAGE_SIZE, PROT_READ,
|
|
xen_cr3_to_pfn(ctxt[cpu].ctrlreg[3]));
|
|
if ( l3 == NULL )
|
|
return NULL;
|
|
|
|
l3e = l3[l3_table_offset_pae(va)];
|
|
munmap(l3, PAGE_SIZE);
|
|
if ( !(l3e & _PAGE_PRESENT) )
|
|
return NULL;
|
|
l2p = to_ma(cpu, l3e);
|
|
l2 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, PROT_READ, l2p >> PAGE_SHIFT);
|
|
if ( l2 == NULL )
|
|
return NULL;
|
|
|
|
l2e = l2[l2_table_offset_pae(va)];
|
|
munmap(l2, PAGE_SIZE);
|
|
if ( !(l2e & _PAGE_PRESENT) )
|
|
return NULL;
|
|
l1p = to_ma(cpu, l2e);
|
|
l1 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, PROT_READ, l1p >> PAGE_SHIFT);
|
|
if ( l1 == NULL )
|
|
return NULL;
|
|
|
|
l1e = l1[l1_table_offset_pae(va)];
|
|
munmap(l1, PAGE_SIZE);
|
|
if ( !(l1e & _PAGE_PRESENT) )
|
|
return NULL;
|
|
p = to_ma(cpu, l1e);
|
|
if ( v[cpu] != NULL )
|
|
munmap(v[cpu], PAGE_SIZE);
|
|
v[cpu] = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, perm, p >> PAGE_SHIFT);
|
|
if ( v[cpu] == NULL )
|
|
return NULL;
|
|
|
|
return (void *)((unsigned long)v[cpu] | (va & (PAGE_SIZE - 1)));
|
|
}
|
|
|
|
#ifdef __x86_64__
|
|
static void *
|
|
map_domain_va_64(
|
|
int xc_handle,
|
|
int cpu,
|
|
void *guest_va,
|
|
int perm)
|
|
{
|
|
unsigned long l4e, l3e, l2e, l1e, l3p, l2p, l1p, p, va = (unsigned long)guest_va;
|
|
uint64_t *l4, *l3, *l2, *l1;
|
|
static void *v[MAX_VIRT_CPUS];
|
|
|
|
if ((ctxt[cpu].ctrlreg[4] & 0x20) == 0 ) /* legacy ia32 mode */
|
|
return map_domain_va_32(xc_handle, cpu, guest_va, perm);
|
|
|
|
l4 = xc_map_foreign_range(
|
|
xc_handle, current_domid, PAGE_SIZE, PROT_READ,
|
|
xen_cr3_to_pfn(ctxt[cpu].ctrlreg[3]));
|
|
if ( l4 == NULL )
|
|
return NULL;
|
|
|
|
l4e = l4[l4_table_offset(va)];
|
|
munmap(l4, PAGE_SIZE);
|
|
if ( !(l4e & _PAGE_PRESENT) )
|
|
return NULL;
|
|
l3p = to_ma(cpu, l4e);
|
|
l3 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, PROT_READ, l3p >> PAGE_SHIFT);
|
|
if ( l3 == NULL )
|
|
return NULL;
|
|
|
|
l3e = l3[l3_table_offset(va)];
|
|
munmap(l3, PAGE_SIZE);
|
|
if ( !(l3e & _PAGE_PRESENT) )
|
|
return NULL;
|
|
l2p = to_ma(cpu, l3e);
|
|
l2 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, PROT_READ, l2p >> PAGE_SHIFT);
|
|
if ( l2 == NULL )
|
|
return NULL;
|
|
|
|
l2e = l2[l2_table_offset(va)];
|
|
munmap(l2, PAGE_SIZE);
|
|
if ( !(l2e & _PAGE_PRESENT) )
|
|
return NULL;
|
|
l1p = to_ma(cpu, l2e);
|
|
if (l2e & 0x80) { /* 2M pages */
|
|
p = to_ma(cpu, (l1p + l1_table_offset(va)) << PAGE_SHIFT);
|
|
} else { /* 4K pages */
|
|
l1 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, PROT_READ, l1p >> PAGE_SHIFT);
|
|
if ( l1 == NULL )
|
|
return NULL;
|
|
|
|
l1e = l1[l1_table_offset(va)];
|
|
munmap(l1, PAGE_SIZE);
|
|
if ( !(l1e & _PAGE_PRESENT) )
|
|
return NULL;
|
|
p = to_ma(cpu, l1e);
|
|
}
|
|
if ( v[cpu] != NULL )
|
|
munmap(v[cpu], PAGE_SIZE);
|
|
v[cpu] = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, perm, p >> PAGE_SHIFT);
|
|
if ( v[cpu] == NULL )
|
|
return NULL;
|
|
|
|
return (void *)((unsigned long)v[cpu] | (va & (PAGE_SIZE - 1)));
|
|
}
|
|
#endif
|
|
|
|
static void *
|
|
map_domain_va(
|
|
int xc_handle,
|
|
int cpu,
|
|
void *guest_va,
|
|
int perm)
|
|
{
|
|
unsigned long va = (unsigned long) guest_va;
|
|
long npgs = xc_get_tot_pages(xc_handle, current_domid);
|
|
static enum { MODE_UNKNOWN, MODE_64, MODE_32, MODE_PAE } mode;
|
|
|
|
if ( mode == MODE_UNKNOWN )
|
|
{
|
|
xen_capabilities_info_t caps;
|
|
(void)xc_version(xc_handle, XENVER_capabilities, caps);
|
|
if ( strstr(caps, "-x86_64") )
|
|
mode = MODE_64;
|
|
else if ( strstr(caps, "-x86_32p") )
|
|
mode = MODE_PAE;
|
|
else if ( strstr(caps, "-x86_32") )
|
|
mode = MODE_32;
|
|
}
|
|
|
|
if ( nr_pages != npgs )
|
|
{
|
|
if ( nr_pages > 0 )
|
|
free(page_array);
|
|
nr_pages = npgs;
|
|
if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
|
|
{
|
|
IPRINTF("Could not allocate memory\n");
|
|
return NULL;
|
|
}
|
|
if ( xc_get_pfn_list(xc_handle, current_domid,
|
|
page_array, nr_pages) != nr_pages )
|
|
{
|
|
IPRINTF("Could not get the page frame list\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (fetch_regs(xc_handle, cpu, NULL))
|
|
return NULL;
|
|
|
|
if (!paging_enabled(&ctxt[cpu])) {
|
|
static void * v;
|
|
uint64_t page;
|
|
|
|
if ( v != NULL )
|
|
munmap(v, PAGE_SIZE);
|
|
|
|
page = to_ma(cpu, va);
|
|
|
|
v = xc_map_foreign_range( xc_handle, current_domid, PAGE_SIZE,
|
|
perm, page >> PAGE_SHIFT);
|
|
|
|
if ( v == NULL )
|
|
return NULL;
|
|
|
|
return (void *)(((unsigned long)v) | (va & BSD_PAGE_MASK));
|
|
}
|
|
#ifdef __x86_64__
|
|
if ( mode == MODE_64 )
|
|
return map_domain_va_64(xc_handle, cpu, guest_va, perm);
|
|
#endif
|
|
if ( mode == MODE_PAE )
|
|
return map_domain_va_pae(xc_handle, cpu, guest_va, perm);
|
|
/* else ( mode == MODE_32 ) */
|
|
return map_domain_va_32(xc_handle, cpu, guest_va, perm);
|
|
}
|
|
|
|
int control_c_pressed_flag = 0;
|
|
|
|
static int
|
|
__xc_waitdomain(
|
|
int xc_handle,
|
|
int domain,
|
|
int *status,
|
|
int options)
|
|
{
|
|
DECLARE_DOMCTL;
|
|
int retval;
|
|
struct timespec ts;
|
|
uint64_t cpumap;
|
|
|
|
ts.tv_sec = 0;
|
|
ts.tv_nsec = 10*1000*1000;
|
|
|
|
domctl.cmd = XEN_DOMCTL_getdomaininfo;
|
|
domctl.domain = domain;
|
|
|
|
retry:
|
|
retval = do_domctl(xc_handle, &domctl);
|
|
if ( retval || (domctl.domain != domain) )
|
|
{
|
|
IPRINTF("getdomaininfo failed\n");
|
|
goto done;
|
|
}
|
|
*status = domctl.u.getdomaininfo.flags;
|
|
|
|
if ( options & WNOHANG )
|
|
goto done;
|
|
|
|
if (control_c_pressed_flag) {
|
|
xc_domain_pause(xc_handle, domain);
|
|
control_c_pressed_flag = 0;
|
|
goto done;
|
|
}
|
|
|
|
if ( !(domctl.u.getdomaininfo.flags & XEN_DOMINF_paused) )
|
|
{
|
|
nanosleep(&ts,NULL);
|
|
goto retry;
|
|
}
|
|
done:
|
|
if (get_online_cpumap(xc_handle, &domctl.u.getdomaininfo, &cpumap))
|
|
IPRINTF("get_online_cpumap failed\n");
|
|
if (online_cpumap != cpumap)
|
|
online_vcpus_changed(cpumap);
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
long
|
|
xc_ptrace(
|
|
int xc_handle,
|
|
enum __ptrace_request request,
|
|
uint32_t domid_tid,
|
|
long eaddr,
|
|
long edata)
|
|
{
|
|
DECLARE_DOMCTL;
|
|
struct gdb_regs pt;
|
|
long retval = 0;
|
|
unsigned long *guest_va;
|
|
uint64_t cpumap;
|
|
int cpu, index;
|
|
void *addr = (char *)eaddr;
|
|
void *data = (char *)edata;
|
|
|
|
cpu = (request != PTRACE_ATTACH) ? domid_tid : 0;
|
|
|
|
switch ( request )
|
|
{
|
|
case PTRACE_PEEKTEXT:
|
|
case PTRACE_PEEKDATA:
|
|
if (current_isfile)
|
|
guest_va = (unsigned long *)map_domain_va_core(
|
|
current_domid, cpu, addr, ctxt);
|
|
else
|
|
guest_va = (unsigned long *)map_domain_va(
|
|
xc_handle, cpu, addr, PROT_READ);
|
|
if ( guest_va == NULL )
|
|
goto out_error;
|
|
retval = *guest_va;
|
|
break;
|
|
|
|
case PTRACE_POKETEXT:
|
|
case PTRACE_POKEDATA:
|
|
/* XXX assume that all CPUs have the same address space */
|
|
if (current_isfile)
|
|
guest_va = (unsigned long *)map_domain_va_core(
|
|
current_domid, cpu, addr, ctxt);
|
|
else
|
|
guest_va = (unsigned long *)map_domain_va(
|
|
xc_handle, cpu, addr, PROT_READ|PROT_WRITE);
|
|
if ( guest_va == NULL )
|
|
goto out_error;
|
|
*guest_va = (unsigned long)data;
|
|
break;
|
|
|
|
case PTRACE_GETREGS:
|
|
if (!current_isfile && fetch_regs(xc_handle, cpu, NULL))
|
|
goto out_error;
|
|
SET_PT_REGS(pt, ctxt[cpu].user_regs);
|
|
memcpy(data, &pt, sizeof(struct gdb_regs));
|
|
break;
|
|
|
|
case PTRACE_GETFPREGS:
|
|
if (!current_isfile && fetch_regs(xc_handle, cpu, NULL))
|
|
goto out_error;
|
|
memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof (elf_fpregset_t));
|
|
break;
|
|
|
|
case PTRACE_GETFPXREGS:
|
|
if (!current_isfile && fetch_regs(xc_handle, cpu, NULL))
|
|
goto out_error;
|
|
memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt));
|
|
break;
|
|
|
|
case PTRACE_SETREGS:
|
|
if (current_isfile)
|
|
goto out_unsupported; /* XXX not yet supported */
|
|
SET_XC_REGS(((struct gdb_regs *)data), ctxt[cpu].user_regs);
|
|
if ((retval = xc_vcpu_setcontext(xc_handle, current_domid, cpu,
|
|
&ctxt[cpu])))
|
|
goto out_error_domctl;
|
|
break;
|
|
|
|
case PTRACE_SINGLESTEP:
|
|
if (current_isfile)
|
|
goto out_unsupported; /* XXX not yet supported */
|
|
/* XXX we can still have problems if the user switches threads
|
|
* during single-stepping - but that just seems retarded
|
|
*/
|
|
ctxt[cpu].user_regs.eflags |= PSL_T;
|
|
if ((retval = xc_vcpu_setcontext(xc_handle, current_domid, cpu,
|
|
&ctxt[cpu])))
|
|
goto out_error_domctl;
|
|
/* FALLTHROUGH */
|
|
|
|
case PTRACE_CONT:
|
|
case PTRACE_DETACH:
|
|
if (current_isfile)
|
|
goto out_unsupported; /* XXX not yet supported */
|
|
if ( request != PTRACE_SINGLESTEP )
|
|
{
|
|
FOREACH_CPU(cpumap, index) {
|
|
cpu = index - 1;
|
|
if (fetch_regs(xc_handle, cpu, NULL))
|
|
goto out_error;
|
|
/* Clear trace flag */
|
|
if ( ctxt[cpu].user_regs.eflags & PSL_T )
|
|
{
|
|
ctxt[cpu].user_regs.eflags &= ~PSL_T;
|
|
if ((retval = xc_vcpu_setcontext(xc_handle, current_domid,
|
|
cpu, &ctxt[cpu])))
|
|
goto out_error_domctl;
|
|
}
|
|
}
|
|
}
|
|
if ( request == PTRACE_DETACH )
|
|
{
|
|
domctl.cmd = XEN_DOMCTL_setdebugging;
|
|
domctl.domain = current_domid;
|
|
domctl.u.setdebugging.enable = 0;
|
|
if ((retval = do_domctl(xc_handle, &domctl)))
|
|
goto out_error_domctl;
|
|
}
|
|
regs_valid = 0;
|
|
if ((retval = xc_domain_unpause(xc_handle, current_domid > 0 ?
|
|
current_domid : -current_domid)))
|
|
goto out_error_domctl;
|
|
break;
|
|
|
|
case PTRACE_ATTACH:
|
|
current_domid = domid_tid;
|
|
current_isfile = (int)edata;
|
|
if (current_isfile)
|
|
break;
|
|
domctl.cmd = XEN_DOMCTL_getdomaininfo;
|
|
domctl.domain = current_domid;
|
|
retval = do_domctl(xc_handle, &domctl);
|
|
if ( retval || (domctl.domain != current_domid) )
|
|
goto out_error_domctl;
|
|
if ( domctl.u.getdomaininfo.flags & XEN_DOMINF_paused )
|
|
IPRINTF("domain currently paused\n");
|
|
else if ((retval = xc_domain_pause(xc_handle, current_domid)))
|
|
goto out_error_domctl;
|
|
current_is_hvm = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_hvm_guest);
|
|
domctl.cmd = XEN_DOMCTL_setdebugging;
|
|
domctl.domain = current_domid;
|
|
domctl.u.setdebugging.enable = 1;
|
|
if ((retval = do_domctl(xc_handle, &domctl)))
|
|
goto out_error_domctl;
|
|
|
|
if (get_online_cpumap(xc_handle, &domctl.u.getdomaininfo, &cpumap))
|
|
IPRINTF("get_online_cpumap failed\n");
|
|
if (online_cpumap != cpumap)
|
|
online_vcpus_changed(cpumap);
|
|
break;
|
|
|
|
case PTRACE_TRACEME:
|
|
IPRINTF("PTRACE_TRACEME is an invalid request under Xen\n");
|
|
goto out_error;
|
|
|
|
default:
|
|
goto out_unsupported; /* XXX not yet supported */
|
|
}
|
|
|
|
return retval;
|
|
|
|
out_error_domctl:
|
|
perror("domctl failed");
|
|
out_error:
|
|
errno = EINVAL;
|
|
return retval;
|
|
|
|
out_unsupported:
|
|
#ifdef DEBUG
|
|
IPRINTF("unsupported xc_ptrace request %s\n", ptrace_names[request]);
|
|
#endif
|
|
errno = ENOSYS;
|
|
return -1;
|
|
|
|
}
|
|
|
|
int
|
|
xc_waitdomain(
|
|
int xc_handle,
|
|
int domain,
|
|
int *status,
|
|
int options)
|
|
{
|
|
if (current_isfile)
|
|
return xc_waitdomain_core(xc_handle, domain, status, options, ctxt);
|
|
return __xc_waitdomain(xc_handle, domain, status, options);
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-set-style: "BSD"
|
|
* c-basic-offset: 4
|
|
* tab-width: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|