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
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: > + */
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: > + */
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_crashIt 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.
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
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
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: >> + */
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
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.
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 --------------040709020400020407010402 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: 8bit <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"> </head> <body bgcolor="#FFFFFF" text="#000000"> <div class="moz-cite-prefix">On 10/15/13 11:47, Ian Campbell wrote:<br> </div> <blockquote cite="mid:1381852054.21901.44.camel@kazak.uk.xensource.com" type="cite"> <pre wrap="">On Tue, 2013-10-15 at 11:25 -0400, Don Slutz wrote: </pre> <blockquote type="cite"> <blockquote type="cite"> <pre wrap="">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). </pre> </blockquote> <pre wrap="">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. </pre> </blockquote> <pre wrap=""> Thanks. </pre> <blockquote type="cite"> <blockquote type="cite"> <pre wrap="">If it''s not intended to be consumed like this perhaps the tool would be better off living in the crash source base? </pre> </blockquote> <pre wrap="">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. </pre> </blockquote> <pre wrap=""> 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. </pre> </blockquote> 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.<br> <br> For example:<br> <blockquote><tt>dcs-xen-50:~/dump2>crash vmcore xenrpm/boot/xen-syms-4.2.2 </tt><tt><br> </tt><tt><br> </tt><tt>crash 6.1.4</tt><tt><br> </tt><tt>Copyright (C) 2002-2013 Red Hat, Inc.</tt><tt><br> </tt><tt>Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation</tt><tt><br> </tt><tt>Copyright (C) 1999-2006 Hewlett-Packard Co</tt><tt><br> </tt><tt>Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited</tt><tt><br> </tt><tt>Copyright (C) 2006, 2007 VA Linux Systems Japan K.K.</tt><tt><br> </tt><tt>Copyright (C) 2005, 2011 NEC Corporation</tt><tt><br> </tt><tt>Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc.</tt><tt><br> </tt><tt>Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.</tt><tt><br> </tt><tt>This program is free software, covered by the GNU General Public License,</tt><tt><br> </tt><tt>and you are welcome to change it and/or distribute copies of it under</tt><tt><br> </tt><tt>certain conditions. Enter "help copying" to see the conditions.</tt><tt><br> </tt><tt>This program has absolutely no warranty. Enter "help warranty" for details.</tt><tt><br> </tt><tt> </tt><tt><br> </tt><tt>GNU gdb (GDB) 7.3.1</tt><tt><br> </tt><tt>Copyright (C) 2011 Free Software Foundation, Inc.</tt><tt><br> </tt><tt>License GPLv3+: GNU GPL version 3 or later <a class="moz-txt-link-rfc2396E" href="http://gnu.org/licenses/gpl.html"><http://gnu.org/licenses/gpl.html></a></tt><tt><br> </tt><tt>This is free software: you are free to change and redistribute it.</tt><tt><br> </tt><tt>There is NO WARRANTY, to the extent permitted by law. Type "show copying"</tt><tt><br> </tt><tt>and "show warranty" for details.</tt><tt><br> </tt><tt>This GDB was configured as "x86_64-unknown-linux-gnu"...</tt><tt><br> </tt><tt><br> </tt><tt> KERNEL: xenrpm/boot/xen-syms-4.2.2</tt><tt><br> </tt><tt> DUMPFILE: vmcore</tt><tt><br> </tt><tt> CPUS: 8</tt><tt><br> </tt><tt> DOMAINS: 5</tt><tt><br> </tt><tt> UPTIME: --:--:--</tt><tt><br> </tt><tt> MACHINE: Intel(R) Xeon(R) CPU E31265L @ 2.40GHz (2400 Mhz)</tt><tt><br> </tt><tt> MEMORY: 32 GB</tt><tt><br> </tt><tt> PCPU-ID: 0</tt><tt><br> </tt><tt> PCPU: ffff82c4802bff18</tt><tt><br> </tt><tt> VCPU-ID: 0</tt><tt><br> </tt><tt> VCPU: ffff8300bf2fa000 (VCPU_RUNNING)</tt><tt><br> </tt><tt>DOMAIN-ID: 0</tt><tt><br> </tt><tt> DOMAIN: ffff830823fb6000 (DOMAIN_RUNNING)</tt><tt><br> </tt><tt> STATE: CRASH</tt><tt><br> </tt><tt><br> </tt><tt>crash> quit</tt><br> </blockquote> <br> <blockquote cite="mid:1381852054.21901.44.camel@kazak.uk.xensource.com" type="cite"> <pre wrap=""> 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. </pre> </blockquote> 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.<br> <br> Since this is changing the way that crash gets to the data, I know of no way to do it as an extension module.<br> <blockquote cite="mid:1381852054.21901.44.camel@kazak.uk.xensource.com" type="cite"> <pre wrap=""> Ian. </pre> </blockquote> -Don Slutz<br> </body> </html> --------------040709020400020407010402-- --===============7510609271659773723=Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel --===============7510609271659773723==--
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.