---
.gitignore | 1 +
tools/xentrace/Makefile | 5 +-
tools/xentrace/xen_crash.c | 697 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 702 insertions(+), 1 deletions(-)
create mode 100644 tools/xentrace/xen_crash.c
diff --git a/.gitignore b/.gitignore
index 3253675..51226f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -278,6 +278,7 @@ tools/xenstore/xs_watch_stress
tools/xentrace/xentrace_setsize
tools/xentrace/tbctl
tools/xentrace/xenctx
+tools/xentrace/xen_crash
tools/xentrace/xentrace
tools/xm-test/ramdisk/buildroot
tools/xm-test/aclocal.m4
diff --git a/tools/xentrace/Makefile b/tools/xentrace/Makefile
index 63b09c0..a2313c6 100644
--- a/tools/xentrace/Makefile
+++ b/tools/xentrace/Makefile
@@ -7,7 +7,7 @@ CFLAGS += $(CFLAGS_libxenctrl)
LDLIBS += $(LDLIBS_libxenctrl)
BIN = xentrace xentrace_setsize
-LIBBIN = xenctx
+LIBBIN = xenctx xen_crash
SCRIPTS = xentrace_format
MAN1 = $(wildcard *.1)
MAN8 = $(wildcard *.8)
@@ -40,6 +40,9 @@ xentrace: xentrace.o
xenctx: xenctx.o
$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS) $(APPEND_LDFLAGS)
+xen_crash: xen_crash.o
+ $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS) $(APPEND_LDFLAGS)
+
xentrace_setsize: setsize.o
$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS) $(APPEND_LDFLAGS)
diff --git a/tools/xentrace/xen_crash.c b/tools/xentrace/xen_crash.c
new file mode 100644
index 0000000..6a4bb34
--- /dev/null
+++ b/tools/xentrace/xen_crash.c
@@ -0,0 +1,697 @@
+/******************************************************************************
+ * tools/xentrace/xen_crash.c
+ *
+ * Connect crash to DOMu.
+ *
+ * Copyright (C) 2012 by Cloud Switch, Inc.
+ *
+ */
+
+#include <ctype.h>
+#include <time.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getopt.h>
+
+#include "xenctrl.h"
+#include <xen/foreign/x86_32.h>
+#include <xen/foreign/x86_64.h>
+#include <xen/hvm/save.h>
+
+xc_interface *xc_handle = 0;
+int domid = 0;
+int debug = 0;
+
+typedef unsigned long long guest_word_t;
+#define FMT_32B_WORD "%08llx"
+#define FMT_64B_WORD "%016llx"
+
+/* Word-length of the guest's own data structures */
+int guest_word_size = sizeof (unsigned long);
+/* Word-length of the context record we get from xen */
+int ctxt_word_size = sizeof (unsigned long);
+int guest_protected_mode = 1;
+
+#define MACHINE_TYPE "X86_64"
+
+#define STRNEQ(A, B) (B && \
+ (strncmp((char *)(A), (char *)(B), strlen((char *)(B))) == 0))
+#define FAILMSG "FAIL "
+#define DONEMSG "DONE "
+#define DATAMSG "DATA "
+
+#define DATA_HDRSIZE 13 /* strlen("XXXX ") + strlen("0131072") + NULL */
+
+#define BUFSIZE 127
+#define READBUFSIZE DATA_HDRSIZE + XC_PAGE_SIZE
+
+#define MAX_REMOTE_FDS 10
+
+void
+print_now(void)
+{
+ struct timeval tp;
+ struct timezone tzp;
+ char *timeout;
+ int imil;
+
+ gettimeofday(&tp, &tzp);
+ timeout = ctime(&tp.tv_sec);
+ imil = tp.tv_usec / 1000;
+ timeout += 4; /* Skip day of week */
+ *(timeout + 3) = 0; /* Trim at space after month */
+ *(timeout + 6) = 0; /* Trim at space after day */
+ *(timeout + 15) = 0; /* Trim at seconds. */
+ *(timeout + 20) = 0; /* Trim after year. */
+ printf("%s %s %s %s.%.3d ", timeout + 4, timeout, timeout + 18,
+ timeout + 7, imil);
+}
+
+int
+RTTcpWrite(int Sock, const void *pvBuffer, size_t cbBuffer)
+{
+ if (debug & 4) {
+ print_now();
+ printf("rtn: %s\n", (char*)pvBuffer);
+ }
+ do
+ {
+ size_t cbNow = cbBuffer;
+ ssize_t cbWritten = send(Sock, (const char *)pvBuffer, cbNow,
MSG_NOSIGNAL);
+
+ if (cbWritten < 0)
+ return 1;
+ cbBuffer -= cbWritten;
+ pvBuffer = (char *)pvBuffer + cbWritten;
+ } while (cbBuffer);
+
+ return 0;
+}
+
+
+static void *
+map_page(int vcpu, guest_word_t phys)
+{
+ static unsigned long previous_mfn = 0;
+ static void *mapped = NULL;
+
+ unsigned long mfn = phys >> XC_PAGE_SHIFT;
+ unsigned long offset = phys & ~XC_PAGE_MASK;
+
+ if (mapped && mfn == previous_mfn)
+ goto out;
+
+ if (mapped)
+ munmap(mapped, XC_PAGE_SIZE);
+
+ previous_mfn = mfn;
+
+ mapped = xc_map_foreign_range(xc_handle, domid, XC_PAGE_SIZE, PROT_READ,
mfn);
+
+ if (mapped == NULL) {
+ if (debug & 2) {
+ print_now();
+ printf("failed to map page for %08llx.\n", phys);
+ }
+ return NULL;
+ }
+
+ out:
+ return (void *)(mapped + offset);
+}
+
+static int
+copy_phys(int vcpu, char * pvDst, size_t cb, guest_word_t phys)
+{
+ void * localAddr;
+ size_t cbPage = XC_PAGE_SIZE - (phys & ~XC_PAGE_MASK);
+
+ /* optimize for the case where access is completely within the first page.
*/
+ localAddr = map_page(vcpu, phys);
+ if (!localAddr) {
+ return 2;
+ }
+ if (cb <= cbPage) {
+ memcpy(pvDst, localAddr, cb);
+ return 0;
+ }
+ memcpy(pvDst, localAddr, cbPage);
+ pvDst += cbPage;
+ phys += cbPage;
+ cb -= cbPage;
+
+ /* Max transfer is XC_PAGE_SIZE... */
+ if (cb > XC_PAGE_SIZE)
+ return 1;
+ localAddr = map_page(vcpu, phys);
+ if (!localAddr) {
+ return 3;
+ }
+ memcpy(pvDst, localAddr, cb);
+ return 0;
+}
+
+static guest_word_t
+convert_to_phys(int vcpu, guest_word_t virt)
+{
+ unsigned long mfn = xc_translate_foreign_address(xc_handle, domid, vcpu,
virt);
+ unsigned long offset = virt & ~XC_PAGE_MASK;
+
+ return (mfn << XC_PAGE_SHIFT) + offset;
+}
+
+static int
+copy_virt(int vcpu, char * pvDst, size_t cb, guest_word_t virt)
+{
+ void * localAddr;
+ unsigned long mfn = xc_translate_foreign_address(xc_handle, domid, vcpu,
virt);
+ unsigned long offset = virt & ~XC_PAGE_MASK;
+ guest_word_t phys = (mfn << XC_PAGE_SHIFT) + offset;
+ size_t cbPage = XC_PAGE_SIZE - offset;
+
+ /* optimize for the case where access is completely within the first page.
*/
+
+ localAddr = map_page(vcpu, phys);
+ if (!localAddr) {
+ return 2;
+ }
+ if (cb <= cbPage) {
+ memcpy(pvDst, localAddr, cb);
+ return 0;
+ }
+ memcpy(pvDst, localAddr, cbPage);
+ pvDst += cbPage;
+ phys += cbPage;
+ cb -= cbPage;
+
+ /* Max transfer is XC_PAGE_SIZE... */
+ if (cb > XC_PAGE_SIZE)
+ return 1;
+ localAddr = map_page(vcpu, phys);
+ if (!localAddr) {
+ return 3;
+ }
+ memcpy(pvDst, localAddr, cb);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int port=5001;
+ int sock;
+ unsigned int length;
+ struct sockaddr_in server;
+ int msgsock;
+ int nfds;
+ int reuseaddr;
+ int count;
+ int pass;
+ int i;
+ char recvbuf[BUFSIZE + 1];
+ char sendbuf[READBUFSIZE + 1];
+ int fds[MAX_REMOTE_FDS];
+ size_t cbRead = 0;
+
+ int ret;
+ int vcpu;
+ vcpu_guest_context_any_t ctx;
+ xc_dominfo_t dominfo;
+ struct hvm_hw_cpu cpuctx;
+
+ if (argc < 2 || argc > 4) {
+ printf("usage: xen_crash <domid> [<optional port>]\n");
+ exit(-1);
+ }
+
+ domid = atoi(argv[1]);
+ if (domid==0) {
+ fprintf(stderr, "cannot trace dom0\n");
+ exit(-1);
+ }
+
+ if (argc > 2)
+ port = atoi(argv[2]);
+ if (argc > 3)
+ debug = atoi(argv[3]);
+
+ signal(SIGPIPE, SIG_IGN);
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ perror("socket()");
+ exit(1);
+ }
+ reuseaddr = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr,
+ sizeof reuseaddr) < 0) {
+ perror("setsockopt()");
+ exit(2);
+ }
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+ server.sin_port = htons(port);
+ count = -1;
+ errno = EADDRINUSE;
+ for (pass=0; (errno == EADDRINUSE) && (count < 0); pass++) {
+ if ((count = bind(sock, (struct sockaddr *) & server, sizeof server)) <
+ 0) {
+ if (errno != EADDRINUSE) {
+ /* printf("Errno is %d\n", errno); */
+ perror("bind()");
+ exit(3);
+ }
+ sleep(1); /* Waiting for kernel... */
+ }
+ }
+ length = sizeof server;
+ if (getsockname(sock, (struct sockaddr *) & server, &length) < 0) {
+ perror("getsockname()");
+ exit(4);
+ }
+ print_now();
+ if (pass == 1)
+ printf("Socket ready on port %d after 1 bind call\n", port);
+ else
+ printf("Socket ready on port %d after %d bind calls\n", port, pass);
+ listen(sock, 1);
+ msgsock = accept(sock, NULL, NULL);
+ if (msgsock == -1)
+ perror("accept()");
+ else {
+ print_now();
+ printf("Accepted a connection.\n");
+ close(sock); /* All done for now */
+ errno = 0; /* Just in case */
+ nfds = msgsock + 1;
+ }
+
+ xc_handle = xc_interface_open(0,0,0); /* for accessing control interface */
+
+ ret = xc_domain_getinfo(xc_handle, domid, 1, &dominfo);
+ if (ret < 0) {
+ perror("xc_domain_getinfo");
+ exit(-1);
+ }
+
+ ret = xc_domain_pause(xc_handle, domid);
+ if (ret < 0) {
+ perror("xc_domain_pause");
+ exit(-1);
+ }
+
+ vcpu = 0;
+ ret = xc_vcpu_getcontext(xc_handle, domid, vcpu, &ctx);
+ if (ret < 0) {
+ if (!dominfo.paused)
+ xc_domain_unpause(xc_handle, domid);
+ perror("xc_vcpu_getcontext");
+ exit(-1);
+ }
+
+ if (dominfo.hvm) {
+ xen_capabilities_info_t xen_caps = "";
+ if (xc_domain_hvm_getcontext_partial(
+ xc_handle, domid, HVM_SAVE_CODE(CPU),
+ vcpu, &cpuctx, sizeof cpuctx) != 0) {
+ perror("xc_domain_hvm_getcontext_partial");
+ exit(-1);
+ }
+ guest_word_size = (cpuctx.msr_efer & 0x400) ? 8 : 4;
+ guest_protected_mode = (cpuctx.cr0 & 0x1);
+ /* HVM guest context records are always host-sized */
+ if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0) {
+ perror("xc_version");
+ exit(-1);
+ }
+ ctxt_word_size = (strstr(xen_caps, "xen-3.0-x86_64")) ? 8 : 4;
+ } else {
+ struct xen_domctl domctl;
+ memset(&domctl, 0, sizeof domctl);
+ domctl.domain = domid;
+ domctl.cmd = XEN_DOMCTL_get_address_size;
+ if (xc_domctl(xc_handle, &domctl) == 0)
+ ctxt_word_size = guest_word_size = domctl.u.address_size.size
/ 8;
+ }
+
+ for (i = 0; i < MAX_REMOTE_FDS; i++)
+ fds[i] = -1;
+
+ do {
+ cbRead = recv(msgsock, recvbuf, BUFSIZE, MSG_NOSIGNAL);
+ if (cbRead <= 0) {
+ close(msgsock);
+ msgsock = -1;
+ break;
+ }
+ recvbuf[cbRead] = 0;
+
+ if (debug & 1) {
+ print_now();
+ printf("req: %s\n", recvbuf);
+ }
+
+ if (STRNEQ(recvbuf, "READ_LIVE"))
+ {
+ char *p1, *p2, *p3, *p4;
+ int rc2 = 0;
+ guest_word_t addr;
+ int fid;
+ int len;
+
+ p1 = strtok(recvbuf, " "); /* READ_LIVE */
+ p1 = strtok(NULL, " "); /* fid */
+ p2 = strtok(NULL, " "); /* paddress or vaddress */
+ p3 = strtok(NULL, " "); /* length */
+ p4 = strtok(NULL, " "); /* vaddress or vcpu */
+
+ fid = atoi(p1);
+ addr = strtoull(p2, NULL, 16);
+ len = atoi(p3);
+ if (len < 0 || len > XC_PAGE_SIZE)
+ {
+ print_now();
+ printf("bad len=%d page_size=%ld;%s %s %s %s %s\n",
+ len, XC_PAGE_SIZE, recvbuf, p1, p2, p3, p4);
+ len = 0;
+ rc2 = 4;
+ }
+
+ if (len)
+ {
+ if (p4 && (fds[fid] == 3)) {
+ int myCpu = atoi(p4);
+ guest_word_t pAddr = convert_to_phys(myCpu, addr);
+
+ if (debug & 2) {
+ print_now();
+ printf("copy_virt(%d,,%d, 0x%llx)[%s %s %s %s]
pAddr=0x%lx\n",
+ myCpu, len, addr, p1, p2, p3, p4, (long)pAddr);
+ }
+ rc2 = copy_virt(myCpu, &sendbuf[DATA_HDRSIZE], len, addr);
+ } else {
+ if (debug & 2) {
+ print_now();
+ printf("copy_phys(%d,,%d, 0x%llx)[%s %s %s]\n",
+ vcpu, len, addr, p1, p2, p3);
+ }
+ rc2 = copy_phys(vcpu, &sendbuf[DATA_HDRSIZE], len, addr);
+ }
+ if (rc2) {
+ if (debug & 2) {
+ print_now();
+ printf("Failed rc2=%d\n", rc2);
+ }
+ len = 0;
+ }
+ }
+
+ if (!len) {
+ snprintf(sendbuf, sizeof(sendbuf), "%s%07ld", FAILMSG,
(ulong)rc2);
+ } else {
+ snprintf(sendbuf, sizeof(sendbuf), "%s%07ld", DONEMSG,
(ulong)len);
+ }
+ if (RTTcpWrite(msgsock, sendbuf, len + DATA_HDRSIZE))
+ break;
+ }
+ else if (STRNEQ(recvbuf, "FETCH_LIVE_IP_SP_BP "))
+ {
+ char *p1, *p2;
+ int cpu;
+ long g2ip = 0;
+ short g2cs = 0;
+ short g2ss = 0;
+ long g2sp = 0;
+ long g2bp = 0;
+
+ p1 = strtok(recvbuf, " "); /* FETCH_LIVE_IP_SP_BP */
+ p2 = strtok(NULL, " "); /* cpu */
+
+ cpu = atoi(p2);
+ if (cpu != vcpu) {
+ vcpu = cpu;
+ ret = xc_vcpu_getcontext(xc_handle, domid, vcpu, &ctx);
+ if (ret < 0) {
+ if (!dominfo.paused)
+ xc_domain_unpause(xc_handle, domid);
+ perror("xc_vcpu_getcontext");
+ exit(-1);
+ }
+ if (dominfo.hvm) {
+ if (xc_domain_hvm_getcontext_partial(
+ xc_handle, domid, HVM_SAVE_CODE(CPU),
+ vcpu, &cpuctx, sizeof cpuctx) != 0) {
+ perror("xc_domain_hvm_getcontext_partial");
+ exit(-1);
+ }
+ }
+ }
+
+ if (ctxt_word_size == 4) {
+ struct cpu_user_regs_x86_32 * regs = &(ctx.x32.user_regs);
+
+ g2ip = regs->eip;
+ g2sp = regs->esp;
+ g2bp = regs->ebp;
+ g2cs = regs->cs;
+ g2ss = regs->ss;
+ } else {
+ struct cpu_user_regs_x86_64 * regs = &(ctx.x64.user_regs);
+
+ if (dominfo.hvm) {
+ g2ip = cpuctx.rip;
+ g2sp = cpuctx.rsp;
+ g2bp = cpuctx.rbp;
+ g2cs = cpuctx.cs_sel;
+ g2ss = cpuctx.ss_sel;
+ if (debug & 0x100) {
+ if (g2ip != regs->rip) {
+ printf("g2ip(%lx) != rip(%lx)\n", g2ip, regs->rip);
+ }
+ if (g2sp != regs->rsp) {
+ printf("g2sp(%lx) != rsp(%lx)\n", g2sp, regs->rsp);
+ }
+ if (g2bp != regs->rbp) {
+ printf("g2bp(%lx) != rbp(%lx)\n", g2bp, regs->rbp);
+ }
+ if (g2cs != regs->cs) {
+ printf("g2cs(%x) != cs(%x)\n", g2cs, regs->cs);
+ }
+ if (g2ss != regs->ss) {
+ printf("g2ss(%x) != ss(%x)\n", g2ss, regs->ss);
+ }
+ }
+ } else {
+ g2ip = regs->rip;
+ g2sp = regs->rsp;
+ g2bp = regs->rbp;
+ g2cs = regs->cs;
+ g2ss = regs->ss;
+ }
+ }
+
+ snprintf(sendbuf, sizeof(sendbuf), "%s %d %04x:%lx %04x:%lx %lx",
+ p1, cpu, g2cs, g2ip, g2ss, g2sp, g2bp);
+ if (RTTcpWrite(msgsock, sendbuf, strlen(sendbuf)))
+ break;
+ }
+ else if (STRNEQ(recvbuf, "FETCH_LIVE_CR3 "))
+ {
+ char *p1, *p2;
+ int cpu;
+ long g2cr3 = 0;
+
+ p1 = strtok(recvbuf, " "); /* FETCH_LIVE_CR3 */
+ p2 = strtok(NULL, " "); /* cpu */
+
+ cpu = atoi(p2);
+ if (cpu != vcpu) {
+ vcpu = cpu;
+ ret = xc_vcpu_getcontext(xc_handle, domid, vcpu, &ctx);
+ if (ret < 0) {
+ if (!dominfo.paused)
+ xc_domain_unpause(xc_handle, domid);
+ perror("xc_vcpu_getcontext");
+ exit(-1);
+ }
+ if (dominfo.hvm) {
+ if (xc_domain_hvm_getcontext_partial(
+ xc_handle, domid, HVM_SAVE_CODE(CPU),
+ vcpu, &cpuctx, sizeof cpuctx) != 0) {
+ perror("xc_domain_hvm_getcontext_partial");
+ exit(-1);
+ }
+ }
+ }
+
+ if (ctxt_word_size == 4) {
+ g2cr3 = ctx.x32.ctrlreg[3];
+ } else {
+ if (dominfo.hvm) {
+ g2cr3 = cpuctx.cr3;
+ if (debug & 0x100) {
+ if (g2cr3 != ctx.x64.ctrlreg[3]) {
+ printf("g2cr3(%lx) != cr3(%lx)\n", g2cr3,
ctx.x64.ctrlreg[3]);
+ }
+ }
+ } else {
+ g2cr3 = ctx.x64.ctrlreg[3];
+ }
+ }
+
+ snprintf(sendbuf, sizeof(sendbuf), "%s %d %lx",
+ p1, cpu, g2cr3);
+ if (RTTcpWrite(msgsock, sendbuf, strlen(sendbuf)))
+ break;
+ }
+ else if (STRNEQ(recvbuf, "MACHINE_PID"))
+ {
+ snprintf(sendbuf, sizeof(sendbuf), "%s %s %d",
+ recvbuf, MACHINE_TYPE, 0);
+ if (RTTcpWrite(msgsock, sendbuf, strlen(sendbuf)))
+ break;
+ }
+ else if (STRNEQ(recvbuf, "VTOP"))
+ {
+ char *p1, *p2, *p3;
+ int cpu;
+ guest_word_t vAddr, pAddr;
+
+ p1 = strtok(recvbuf, " "); /* VTOP */
+ p2 = strtok(NULL, " "); /* cpu */
+ p3 = strtok(NULL, " "); /* vaddress */
+
+ cpu = atoi(p2);
+ vAddr = strtoull(p3, NULL, 16);
+
+ pAddr = convert_to_phys(cpu, vAddr);
+
+ snprintf(sendbuf, sizeof(sendbuf), "%s %d %lx %lx",
+ p1, cpu, (long)vAddr, (long)pAddr);
+ if (RTTcpWrite(msgsock, sendbuf, strlen(sendbuf)))
+ break;
+ }
+ else if (STRNEQ(recvbuf, "OPEN "))
+ {
+ char *p1;
+ char *file;
+
+ p1 = strtok(recvbuf, " "); /* OPEN */
+ file = strtok(NULL, " "); /* filename */
+
+ for (i = 0; i < MAX_REMOTE_FDS; i++) {
+ if (fds[i] == -1)
+ break;
+ }
+
+ if (i < MAX_REMOTE_FDS) {
+ if (STRNEQ(file, "/dev/mem"))
+ {
+ fds[i] = 1;
+ snprintf(sendbuf, sizeof(sendbuf), "%s %s %d O_RDONLY
%lld", p1, file, i, 1024LL * 1024LL * 1024LL * 1024LL);
+ }
+ else if (STRNEQ(file, "/dev/kmem"))
+ {
+ fds[i] = 2;
+ snprintf(sendbuf, sizeof(sendbuf), "%s %s %d O_RDONLY
%lld", p1, file, i, 1024LL * 1024LL * 1024LL * 1024LL);
+ }
+ else if (STRNEQ(file, "/dev/vmem"))
+ {
+ fds[i] = 3;
+ snprintf(sendbuf, sizeof(sendbuf), "%s %s %d O_RDONLY
%lld", p1, file, i, 1024LL * 1024LL * 1024LL * 1024LL);
+ }
+ else
+ {
+ snprintf(sendbuf, sizeof(sendbuf), "%s %s <FAIL>", p1,
file);
+ }
+ }
+ else
+ {
+ snprintf(sendbuf, sizeof(sendbuf), "%s %s <FAIL>", p1, file);
+ }
+ if (RTTcpWrite(msgsock, sendbuf, strlen(sendbuf)))
+ break;
+ }
+ else if (STRNEQ(recvbuf, "CLOSE "))
+ {
+ char *p1, *p2;
+
+ p1 = strtok(recvbuf, " "); /* SIZE */
+ p2 = strtok(NULL, " "); /* filename id */
+ snprintf(sendbuf, sizeof(sendbuf), "%s %s <FAIL>", p1, p2);
+ if (RTTcpWrite(msgsock, sendbuf, strlen(sendbuf)))
+ break;
+ }
+ else if (STRNEQ(recvbuf, "PROC_VERSION"))
+ {
+ /*
+ * Perform the detection.
+ */
+ snprintf(sendbuf, sizeof(sendbuf), "<FAIL>");
+ if (RTTcpWrite(msgsock, sendbuf, strlen(sendbuf)))
+ break;
+ }
+ else if (STRNEQ(recvbuf, "PAGESIZE LIVE"))
+ {
+ snprintf(sendbuf, sizeof(sendbuf), "%s %ld XEN %d",
+ recvbuf, XC_PAGE_SIZE, dominfo.max_vcpu_id + 1);
+ if (RTTcpWrite(msgsock, sendbuf, strlen(sendbuf)))
+ break;
+ }
+ else if (STRNEQ(recvbuf, "EXIT"))
+ {
+ snprintf(sendbuf, sizeof(sendbuf), "%s OK", recvbuf);
+ RTTcpWrite(msgsock, sendbuf, strlen(sendbuf));
+ break;
+ }
+ else
+ {
+ print_now();
+ printf("unknown: %s\n", recvbuf);
+ snprintf(sendbuf, sizeof(sendbuf), "%s <FAIL>", recvbuf);
+ if(RTTcpWrite(msgsock, sendbuf, strlen(sendbuf)))
+ break;
+ }
+ } while (msgsock >= 0);
+ if (msgsock >= 0)
+ close(msgsock);
+
+ if (!dominfo.paused) {
+ ret = xc_domain_unpause(xc_handle, domid);
+ if (ret < 0) {
+ perror("xc_domain_unpause");
+ exit(-1);
+ }
+ }
+
+ xc_interface_close(xc_handle);
+ if (ret < 0) {
+ perror("xc_interface_close");
+ exit(-1);
+ }
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */