xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Add xentrace/xen_crash.
@ 2013-10-14 14:07 Don Slutz
  2013-10-14 14:11 ` Don Slutz
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Don Slutz @ 2013-10-14 14:07 UTC (permalink / raw)
  To: xen-devel
  Cc: Ian Campbell, Stefano Stabellini, George Dunlap, Don Slutz,
	Ian Jackson, Don Slutz

From: Don Slutz <Don@CloudSwitch.com>

This allows crash to connect to a domU. Usage:

usage: xen_crash <domid> [<optional port>]

  xen_crash 1&
  crash localhost:5001 /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux

The domU will be paused while crash is connected.  Currently the code exits when crash disconnects.

Signed-off-by: Don Slutz <dslutz@verizon.com>
---
 .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:
+ */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] Add xentrace/xen_crash.
  2013-10-14 14:07 [PATCH] Add xentrace/xen_crash Don Slutz
@ 2013-10-14 14:11 ` Don Slutz
  2013-10-14 15:03 ` Andrew Cooper
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: Don Slutz @ 2013-10-14 14:11 UTC (permalink / raw)
  To: Don Slutz, xen-devel
  Cc: George Dunlap, Don Slutz, Ian Jackson, Ian Campbell,
	Stefano Stabellini

I am still having smtp mailer issues, and so this did not get set to the CC: list.
    -Don Slutz

On 10/14/13 10:07, Don Slutz wrote:
> From: Don Slutz <Don@CloudSwitch.com>
>
> This allows crash to connect to a domU. Usage:
>
> usage: xen_crash <domid> [<optional port>]
>
>    xen_crash 1&
>    crash localhost:5001 /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux
>
> The domU will be paused while crash is connected.  Currently the code exits when crash disconnects.
>
> Signed-off-by: Don Slutz <dslutz@verizon.com>
> ---
>   .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:
> + */

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Add xentrace/xen_crash.
  2013-10-14 14:07 [PATCH] Add xentrace/xen_crash Don Slutz
  2013-10-14 14:11 ` Don Slutz
@ 2013-10-14 15:03 ` Andrew Cooper
  2013-10-15 14:53   ` Don Slutz
  2013-10-14 15:13 ` Ian Campbell
  2013-10-14 16:56 ` David Vrabel
  3 siblings, 1 reply; 11+ messages in thread
From: Andrew Cooper @ 2013-10-14 15:03 UTC (permalink / raw)
  To: Don Slutz
  Cc: Ian Campbell, Stefano Stabellini, George Dunlap, Don Slutz,
	Ian Jackson, xen-devel

On 14/10/13 15:07, Don Slutz wrote:
> From: Don Slutz <Don@CloudSwitch.com>
>
> This allows crash to connect to a domU. Usage:
>
> usage: xen_crash <domid> [<optional port>]
>
>   xen_crash 1&
>   crash localhost:5001 /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux
>
> The domU will be paused while crash is connected.  Currently the code exits when crash disconnects.
>
> Signed-off-by: Don Slutz <dslutz@verizon.com>

This looks good in principle.

However, I am not sure tools/xentrace/ is an appropriate place for it,
as it is unrelated to xentrace.

Also, the name "xen_crash" is a bit too generic, and implies its purpose
is to crash a guest, rather than to attach `crash` to a guest.

What about xen-crashd, as it is a daemon?

~Andrew

> ---
>  .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:
> + */

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Add xentrace/xen_crash.
  2013-10-14 14:07 [PATCH] Add xentrace/xen_crash Don Slutz
  2013-10-14 14:11 ` Don Slutz
  2013-10-14 15:03 ` Andrew Cooper
@ 2013-10-14 15:13 ` Ian Campbell
  2013-10-15 15:25   ` Don Slutz
  2013-10-14 16:56 ` David Vrabel
  3 siblings, 1 reply; 11+ messages in thread
From: Ian Campbell @ 2013-10-14 15:13 UTC (permalink / raw)
  To: Don Slutz
  Cc: George Dunlap, Don Slutz, Stefano Stabellini, Ian Jackson,
	xen-devel

On Mon, 2013-10-14 at 10:07 -0400, Don Slutz wrote:
> From: Don Slutz <Don@CloudSwitch.com>
> 
> This allows crash to connect to a domU. Usage:
> 
> usage: xen_crash <domid> [<optional port>]
> 
>   xen_crash 1&
>   crash localhost:5001 /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux
> 
> The domU will be paused while crash is connected.  Currently the code exits when crash disconnects.

Could you supply some docs please, ideally a simple man page but a txt
would do too. Under docs/ probably so they get published on xenbits etc.

> 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

It appears to be x86 specific, at least right now.

So please do something like:
LIBBIN-$(CONFIG_X86) += xen_crash
...

LIBBIN += $(LIBBIN-y)

> 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"

This looks to be used regardless of the type of the guest?

> +
> +#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 */

I think you could use the strlen calls, which should be statically
evaluated directly and avoid the possibility of having miscounted.

Is this some protocol defined by crash? Can you include a reference to
their specification somewhere please. Is it intended for consumption
externally to the crash tools -- i.e. is it a stable protocol? (it
smells a bit ad-hoc is why I'm asking).

If it's not intended to be consumed like this perhaps the tool would be
better off living in the crash source base?

Ian.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Add xentrace/xen_crash.
  2013-10-14 14:07 [PATCH] Add xentrace/xen_crash Don Slutz
                   ` (2 preceding siblings ...)
  2013-10-14 15:13 ` Ian Campbell
@ 2013-10-14 16:56 ` David Vrabel
  2013-10-15 14:50   ` Don Slutz
  3 siblings, 1 reply; 11+ messages in thread
From: David Vrabel @ 2013-10-14 16:56 UTC (permalink / raw)
  To: Don Slutz
  Cc: Ian Campbell, Stefano Stabellini, George Dunlap, Don Slutz,
	Ian Jackson, xen-devel

On 14/10/13 15:07, Don Slutz wrote:
> From: Don Slutz <Don@CloudSwitch.com>
> 
> This allows crash to connect to a domU. Usage:
> 
> usage: xen_crash <domid> [<optional port>]
> 
>   xen_crash 1&
>   crash localhost:5001 /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux
> 
> The domU will be paused while crash is connected.  Currently the code exits when crash disconnects.
> 
> Signed-off-by: Don Slutz <dslutz@verizon.com>
[...]
> --- a/tools/xentrace/Makefile
> +++ b/tools/xentrace/Makefile
> 
> + * tools/xentrace/xen_crash.c
> + *
> + * Connect crash to DOMu.
> + *
> + * Copyright (C) 2012 by Cloud Switch, Inc.

The copyright holder appears not to be your current employer and there's
no license text.

David

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Add xentrace/xen_crash.
  2013-10-14 16:56 ` David Vrabel
@ 2013-10-15 14:50   ` Don Slutz
  2013-10-23 17:24     ` Konrad Rzeszutek Wilk
  0 siblings, 1 reply; 11+ messages in thread
From: Don Slutz @ 2013-10-15 14:50 UTC (permalink / raw)
  To: David Vrabel
  Cc: Ian Campbell, Stefano Stabellini, George Dunlap, Don Slutz,
	Ian Jackson, Don Slutz, xen-devel

On 10/14/13 12:56, David Vrabel wrote:
> On 14/10/13 15:07, Don Slutz wrote:
>> From: Don Slutz <Don@CloudSwitch.com>
>>
>> This allows crash to connect to a domU. Usage:
>>
>> usage: xen_crash <domid> [<optional port>]
>>
>>    xen_crash 1&
>>    crash localhost:5001 /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux
>>
>> The domU will be paused while crash is connected.  Currently the code exits when crash disconnects.
>>
>> Signed-off-by: Don Slutz <dslutz@verizon.com>
> [...]
>> --- a/tools/xentrace/Makefile
>> +++ b/tools/xentrace/Makefile
>>
>> + * tools/xentrace/xen_crash.c
>> + *
>> + * Connect crash to DOMu.
>> + *
>> + * Copyright (C) 2012 by Cloud Switch, Inc.
> The copyright holder appears not to be your current employer and there's
> no license text.
Not quite right.  Cloud Switch, Inc. now owned by Terremark, which is 
owned by Verizon.

Will add a GPL v2+ license text.
> David
    -Don Slutz

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Add xentrace/xen_crash.
  2013-10-14 15:03 ` Andrew Cooper
@ 2013-10-15 14:53   ` Don Slutz
  0 siblings, 0 replies; 11+ messages in thread
From: Don Slutz @ 2013-10-15 14:53 UTC (permalink / raw)
  To: Andrew Cooper
  Cc: Ian Campbell, Stefano Stabellini, George Dunlap, Don Slutz,
	Ian Jackson, Don Slutz, xen-devel

On 10/14/13 11:03, Andrew Cooper wrote:
> On 14/10/13 15:07, Don Slutz wrote:
>> From: Don Slutz <Don@CloudSwitch.com>
>>
>> This allows crash to connect to a domU. Usage:
>>
>> usage: xen_crash <domid> [<optional port>]
>>
>>    xen_crash 1&
>>    crash localhost:5001 /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux
>>
>> The domU will be paused while crash is connected.  Currently the code exits when crash disconnects.
>>
>> Signed-off-by: Don Slutz <dslutz@verizon.com>
> This looks good in principle.
>
> However, I am not sure tools/xentrace/ is an appropriate place for it,
> as it is unrelated to xentrace.
I was not sure either.  Parts are based on xenctx which is here.
> Also, the name "xen_crash" is a bit too generic, and implies its purpose
> is to crash a guest, rather than to attach `crash` to a guest.
>
> What about xen-crashd, as it is a daemon?
That would be fine with me.
>
> ~Andrew
   -Don Slutz
>> ---
>>   .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:
>> + */

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Add xentrace/xen_crash.
  2013-10-14 15:13 ` Ian Campbell
@ 2013-10-15 15:25   ` Don Slutz
  2013-10-15 15:47     ` Ian Campbell
  0 siblings, 1 reply; 11+ messages in thread
From: Don Slutz @ 2013-10-15 15:25 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, George Dunlap, Don Slutz, Ian Jackson,
	Don Slutz, xen-devel

On 10/14/13 11:13, Ian Campbell wrote:
> On Mon, 2013-10-14 at 10:07 -0400, Don Slutz wrote:
>> From: Don Slutz <Don@CloudSwitch.com>
>>
>> This allows crash to connect to a domU. Usage:
>>
>> usage: xen_crash <domid> [<optional port>]
>>
>>    xen_crash 1&
>>    crash localhost:5001 /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux
>>
>> The domU will be paused while crash is connected.  Currently the code exits when crash disconnects.
> Could you supply some docs please, ideally a simple man page but a txt
> would do too. Under docs/ probably so they get published on xenbits etc.
Sure.
>> 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
> It appears to be x86 specific, at least right now.
>
> So please do something like:
> LIBBIN-$(CONFIG_X86) += xen_crash
> ...
>
> LIBBIN += $(LIBBIN-y)
Sure.
>> 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"
> This looks to be used regardless of the type of the guest?
Ah, this needs to be changed.  Something I was planning to do but forgot 
about it.
>> +
>> +#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 */
> I think you could use the strlen calls, which should be statically
> evaluated directly and avoid the possibility of having miscounted.
Will change.
> Is this some protocol defined by crash? Can you include a reference to
> their specification somewhere please. Is it intended for consumption
> externally to the crash tools -- i.e. is it a stable protocol? (it
> smells a bit ad-hoc is why I'm asking).
So far I have not found a specification. Will keep looking.  I had 
assumed it was, will work with the crash tools person to see.
> If it's not intended to be consumed like this perhaps the tool would be
> better off living in the crash source base?
Maybe.  Since this has code that needs the XEN headers and crash is 
currently one program with extension modules, it does not fit as well there.
> Ian.
>
   -Don Slutz

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Add xentrace/xen_crash.
  2013-10-15 15:25   ` Don Slutz
@ 2013-10-15 15:47     ` Ian Campbell
  2013-10-15 16:26       ` Don Slutz
  0 siblings, 1 reply; 11+ messages in thread
From: Ian Campbell @ 2013-10-15 15:47 UTC (permalink / raw)
  To: Don Slutz
  Cc: George Dunlap, Don Slutz, Stefano Stabellini, Ian Jackson,
	xen-devel

On Tue, 2013-10-15 at 11:25 -0400, Don Slutz wrote:
> > Is this some protocol defined by crash? Can you include a reference to
> > their specification somewhere please. Is it intended for consumption
> > externally to the crash tools -- i.e. is it a stable protocol? (it
> > smells a bit ad-hoc is why I'm asking).
> So far I have not found a specification. Will keep looking.  I had 
> assumed it was, will work with the crash tools person to see.

Thanks.

> > If it's not intended to be consumed like this perhaps the tool would be
> > better off living in the crash source base?
> Maybe.  Since this has code that needs the XEN headers and crash is 
> currently one program with extension modules, it does not fit as well there.

I had it in my mind that crash already had some level of Xen support and
therefore already dependended on the headers. I don't know why I think
that so it may be a fantasy.

Don't these extension modules have all sorts of random dependencies? In
which case adding the Xen ones doesn't seem too horrible, assuming they
are smart enough to only enable the ones whose dependencies are
available.

Ian.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Add xentrace/xen_crash.
  2013-10-15 15:47     ` Ian Campbell
@ 2013-10-15 16:26       ` Don Slutz
  0 siblings, 0 replies; 11+ messages in thread
From: Don Slutz @ 2013-10-15 16:26 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, George Dunlap, Don Slutz, Ian Jackson,
	Don Slutz, xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 3474 bytes --]

On 10/15/13 11:47, Ian Campbell wrote:
> On Tue, 2013-10-15 at 11:25 -0400, Don Slutz wrote:
>>> Is this some protocol defined by crash? Can you include a reference to
>>> their specification somewhere please. Is it intended for consumption
>>> externally to the crash tools -- i.e. is it a stable protocol? (it
>>> smells a bit ad-hoc is why I'm asking).
>> So far I have not found a specification. Will keep looking.  I had
>> assumed it was, will work with the crash tools person to see.
> Thanks.
>
>>> If it's not intended to be consumed like this perhaps the tool would be
>>> better off living in the crash source base?
>> Maybe.  Since this has code that needs the XEN headers and crash is
>> currently one program with extension modules, it does not fit as well there.
> I had it in my mind that crash already had some level of Xen support and
> therefore already dependended on the headers. I don't know why I think
> that so it may be a fantasy.
Crash does have support for XEN crash dumps.  I do not think it supports 
live access to the hypervisor (crash live on dom0 allows you to look at 
dom0, not the hypervisor).  Most of the data structures are fetched out 
of the debug info in ELF files.  So to build crash, xen does not need to 
be installed.

For example:

    dcs-xen-50:~/dump2>crash vmcore xenrpm/boot/xen-syms-4.2.2

    crash 6.1.4
    Copyright (C) 2002-2013  Red Hat, Inc.
    Copyright (C) 2004, 2005, 2006, 2010  IBM Corporation
    Copyright (C) 1999-2006  Hewlett-Packard Co
    Copyright (C) 2005, 2006, 2011, 2012  Fujitsu Limited
    Copyright (C) 2006, 2007  VA Linux Systems Japan K.K.
    Copyright (C) 2005, 2011  NEC Corporation
    Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc.
    Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, Inc.
    This program is free software, covered by the GNU General Public
    License,
    and you are welcome to change it and/or distribute copies of it under
    certain conditions.  Enter "help copying" to see the conditions.
    This program has absolutely no warranty.  Enter "help warranty" for
    details.

    GNU gdb (GDB) 7.3.1
    Copyright (C) 2011 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later
    <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law. Type "show
    copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-unknown-linux-gnu"...

        KERNEL: xenrpm/boot/xen-syms-4.2.2
      DUMPFILE: vmcore
          CPUS: 8
       DOMAINS: 5
        UPTIME: --:--:--
       MACHINE: Intel(R) Xeon(R) CPU E31265L @ 2.40GHz  (2400 Mhz)
        MEMORY: 32 GB
       PCPU-ID: 0
          PCPU: ffff82c4802bff18
       VCPU-ID: 0
          VCPU: ffff8300bf2fa000  (VCPU_RUNNING)
    DOMAIN-ID: 0
        DOMAIN: ffff830823fb6000  (DOMAIN_RUNNING)
         STATE: CRASH

    crash> quit


> Don't these extension modules have all sorts of random dependencies? In
> which case adding the Xen ones doesn't seem too horrible, assuming they
> are smart enough to only enable the ones whose dependencies are
> available.
I think that they do, but not sure.  The ones I have looked at are ways 
to process the data in a dump in a more easy way for a user to use.

Since this is changing the way that crash gets to the data, I know of no 
way to do it as an extension module.
> Ian.
>
   -Don Slutz

[-- Attachment #1.2: Type: text/html, Size: 5685 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] Add xentrace/xen_crash.
  2013-10-15 14:50   ` Don Slutz
@ 2013-10-23 17:24     ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 11+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-10-23 17:24 UTC (permalink / raw)
  To: Don Slutz
  Cc: Ian Campbell, Stefano Stabellini, George Dunlap, Don Slutz,
	Ian Jackson, xen-devel, David Vrabel

On Tue, Oct 15, 2013 at 10:50:22AM -0400, Don Slutz wrote:
> On 10/14/13 12:56, David Vrabel wrote:
> >On 14/10/13 15:07, Don Slutz wrote:
> >>From: Don Slutz <Don@CloudSwitch.com>
> >>
> >>This allows crash to connect to a domU. Usage:
> >>
> >>usage: xen_crash <domid> [<optional port>]
> >>
> >>   xen_crash 1&
> >>   crash localhost:5001 /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux
> >>
> >>The domU will be paused while crash is connected.  Currently the code exits when crash disconnects.
> >>
> >>Signed-off-by: Don Slutz <dslutz@verizon.com>
> >[...]
> >>--- a/tools/xentrace/Makefile
> >>+++ b/tools/xentrace/Makefile
> >>
> >>+ * tools/xentrace/xen_crash.c
> >>+ *
> >>+ * Connect crash to DOMu.
> >>+ *
> >>+ * Copyright (C) 2012 by Cloud Switch, Inc.
> >The copyright holder appears not to be your current employer and there's
> >no license text.
> Not quite right.  Cloud Switch, Inc. now owned by Terremark, which
> is owned by Verizon.

So I think the usual is that you say:

Copyright (C) 2012 by Cloud Switch, Inc.
Copyright (C) 2013 by Terremark.
Copyright (C) 2013 by Verizon.

etc. That way it is clear throught which hands the copyright has passed.

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2013-10-23 17:24 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-10-14 14:07 [PATCH] Add xentrace/xen_crash Don Slutz
2013-10-14 14:11 ` Don Slutz
2013-10-14 15:03 ` Andrew Cooper
2013-10-15 14:53   ` Don Slutz
2013-10-14 15:13 ` Ian Campbell
2013-10-15 15:25   ` Don Slutz
2013-10-15 15:47     ` Ian Campbell
2013-10-15 16:26       ` Don Slutz
2013-10-14 16:56 ` David Vrabel
2013-10-15 14:50   ` Don Slutz
2013-10-23 17:24     ` Konrad Rzeszutek Wilk

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).