From 2edef80bf562bfb3ae098dad313a8814d173d525 Mon Sep 17 00:00:00 2001 From: Don Slutz Date: Thu, 14 Nov 2013 17:20:28 -0500 Subject: [PATCH v3 1/2] xen-crashd: Connect crash with domain This allows crash to connect to a domU. Usage: usage: /usr/lib/xen/bin/xen-crashd [] xen-crashd 1& crash localhost:5001 /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux Note: "crash localhost:5001,/dev/mem" and "crash localhost:5001,/dev/xenmem" are now supported, the 2nd version needs a newer version of crash to work. This 2nd is to change crash from live mode to pasued (almost crashed) mode. The domU will be paused while crash is connected. Currently the code exits when crash disconnects. Important: The domain running crash must be the same architecture as the domU. Like both x86_64. Also the crash version must be new enough to understand the domU's kernel. If the kernel version are different, additional arguments maybe need to get crash to work. Best results will be had using the same version of linux while running crash as the domU is running. Signed-off-by: Don Slutz --- .gitignore | 1 + docs/misc/crash-remote.txt | 190 +++++++++ tools/Makefile | 1 + tools/xen-crashd/Makefile | 32 ++ tools/xen-crashd/xen-crashd.8 | 48 +++ tools/xen-crashd/xen-crashd.c | 891 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1163 insertions(+) create mode 100644 docs/misc/crash-remote.txt create mode 100644 tools/xen-crashd/Makefile create mode 100644 tools/xen-crashd/xen-crashd.8 create mode 100644 tools/xen-crashd/xen-crashd.c diff --git a/.gitignore b/.gitignore index 3253675..452209b 100644 --- a/.gitignore +++ b/.gitignore @@ -279,6 +279,7 @@ tools/xentrace/xentrace_setsize tools/xentrace/tbctl tools/xentrace/xenctx tools/xentrace/xentrace +tools/xen-crashd/xen-crashd tools/xm-test/ramdisk/buildroot tools/xm-test/aclocal.m4 tools/xm-test/autom4te diff --git a/docs/misc/crash-remote.txt b/docs/misc/crash-remote.txt new file mode 100644 index 0000000..4dc1336 --- /dev/null +++ b/docs/misc/crash-remote.txt @@ -0,0 +1,190 @@ +crash remote protocol + Written by Don Slutz Nov. 2013 + +Introduction +------------ +The utility crash supports looking at a domain using the tool +xen-crashd. It does this by using the "crash remote protocol" which +is described here. + +This protocol is over a TCP/IP connection. It is mostly text based +with options seperated by a space. The one exception is that the +data is return in raw following some text. At most 1 page of data +is returned at one time. It is expected that a request will come as +1 packet (which is not a valid TCP/IP statement, but works in 99.9% +of the cases). A new mode (nil_mode) modifies the protocol to +require a 0 byte on the end of all requests and responses. This is +100% compatable with older versions, just allows newer code to do +more then 1 recv() to get a request or response. + +Known commands: + +MACHINE_PID +OPEN +CLOSE +READ_LIVE
[] +PROC_VERSION +PAGESIZE +EXIT +FIND_BOOTED_KERNEL +READ_NETDUMP
+READ_MCLXCD
+READ
+TYPE +LINUX_VERSION +READ_GZIP +DEBUGGING_SYMBOLS +FIND_MODULE +SUM +MEMORY +MEMORY_DUMP +NETDUMP_INIT +LKCD_DUMP_INIT +READ_LKCD
+S390_DUMP_INIT +S390X_DUMP_INIT +READ_S390D
+EXECUTE +FETCH_LIVE_IP_SP_BP +FETCH_LIVE_CR3 +VTOP
+NIL + +Most commands the return is an echo of the command but with the +result(s) appended as text. If the command fails you return command +with "". I.E. "OPEN " is a valid return. + +Command notes: + +MACHINE_PID: + + Return the that crash understands and . + For Xen the server_pid is returned as 0. + +OPEN: + + Currently only /dev/mem, /dev/kmem, and /dev/vmem are supported. + The return is: + OPEN filename fid O_RDONLY filesize + + Note: only read access is supported. + +CLOSE: + + Not currently supported. + +READ_LIVE: + + This is the most complex. The optional argument will force +
to be a virtual one and will be translated to a physical + one. Otherwise a read from /dev/vmem will also select
+ as virtual. For both /dev/mem and /dev/kmem
is a + physical one. + + The return is also special in that it starts with either FAIL or + DONE, a space and a 7 digit errno (fail) or a 7 digit length + of data. Since the max size is one page the 7 digit number should + not overflow. For DONE, right after the 7 digit number the raw + data starts for bytes. If any part of the data is not + mappable, the whole request fails. + + errno is from #include + +PROC_VERSION: + + Return the value of "/proc/version". Has a special return where + "" is used for errors. Not currently supported. + +PAGESIZE: + + Return the page size. Also returns info on server and number of + VCPUs (PAGESIZE XEN ). + +EXIT: + + Close the connection. The return is also different in that it + will be "EXIT OK". + + +Not currently supported. + +FIND_BOOTED_KERNEL: + + Try to find the booted kernel. Returns the file name of the + booted vmlinux. + +READ_NETDUMP: + + +READ_MCLXCD: + + +READ: + + +TYPE: + + +LINUX_VERSION: + + +READ_GZIP: + + +DEBUGGING_SYMBOLS: + + +FIND_MODULE: + + +SUM: + + +MEMORY: + + +MEMORY_DUMP: + + +NETDUMP_INIT: + + +LKCD_DUMP_INIT: + + +READ_LKCD: + + +S390_DUMP_INIT: + + +S390X_DUMP_INIT: + + +READ_S390D: + + +EXECUTE: + + +The following are an extersion to crash. + +FETCH_LIVE_IP_SP_BP: + + Return the current values of SP, IP, and BP. For x86 this is eip + or rip, etc. Also switches the default vcpu for READ_LIVE without + a . + +FETCH_LIVE_CR3: + + Return the current ctrlreg[3] value. Also switches the default + vcpu for READ_LIVE without a . + +VTOP: + + Return the convert of virtual address to physical address. + Physical page 0 means a convertion error. + +NIL: + + Switch to NIL mode. I.E. require a - byte on the end. diff --git a/tools/Makefile b/tools/Makefile index 00c69ee..e0de80c 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -25,6 +25,7 @@ SUBDIRS-$(CONFIG_NetBSD) += xenbackendd SUBDIRS-y += libfsimage SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen SUBDIRS-$(CONFIG_Linux) += libvchan +SUBDIRS-$(CONFIG_Linux) += xen-crashd # do not recurse in to a dir we are about to delete ifneq "$(MAKECMDGOALS)" "distclean" diff --git a/tools/xen-crashd/Makefile b/tools/xen-crashd/Makefile new file mode 100644 index 0000000..5557450 --- /dev/null +++ b/tools/xen-crashd/Makefile @@ -0,0 +1,32 @@ +XEN_ROOT=$(CURDIR)/../.. +include $(XEN_ROOT)/tools/Rules.mk + +CFLAGS += -Werror -g -O0 + +CFLAGS += $(CFLAGS_libxenctrl) +LDLIBS += $(LDLIBS_libxenctrl) + +LIBBIN = xen-crashd +MAN8 = $(wildcard *.8) + +.PHONY: all +all: build + +.PHONY: build +build: $(BIN) $(LIBBIN) + +.PHONY: install +install: build + [ -z "$(LIBBIN)" ] || $(INSTALL_DIR) $(DESTDIR)$(PRIVATE_BINDIR) + $(INSTALL_DIR) $(DESTDIR)$(MAN8DIR) + [ -z "$(LIBBIN)" ] || $(INSTALL_PROG) $(LIBBIN) $(DESTDIR)$(PRIVATE_BINDIR) + $(INSTALL_DATA) $(MAN8) $(DESTDIR)$(MAN8DIR) + +.PHONY: clean +clean: + $(RM) *.a *.so *.o *.rpm $(BIN) $(LIBBIN) $(DEPS) + +xen-crashd: xen-crashd.o + $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS) $(APPEND_LDFLAGS) + +-include $(DEPS) diff --git a/tools/xen-crashd/xen-crashd.8 b/tools/xen-crashd/xen-crashd.8 new file mode 100644 index 0000000..464f407 --- /dev/null +++ b/tools/xen-crashd/xen-crashd.8 @@ -0,0 +1,48 @@ +.TH XEN-CRASHD 8 "15 November 2013" "Xen domain 0 utils" +.SH NAME +xen-crashd \- connect a Xen domain to +.B crash +.SH SYNOPSIS +.B xen-crashd +.I domain +[ +.I PORT +] +.SH DESCRIPTION +.B xen-crashd +is used to connect +.B crash +to a \fIdomain\fR. The \fIdomain\fR will be paused while +.B crash +is connected. Currently the code exits when +.B crash +disconnects. The default +.I PORT +is 5001. + +.SH EXAMPLE + /usr/lib/xen/bin/xen-crashd +.I 1 +& + \fBcrash\fR localhost:\fI5001\fR /usr/lib/debug/lib/modules/3.8.11-100.fc17.x86_64/vmlinux + +.SH IMPORTANT +The linux running +.B crash +must be the same architecture as the \fIdomain\fR. Like both +x86_64. Also the +.B crash +version must be new enough to understand the \fIdomain\fR's kernel. +If the kernel version are different, additional arguments maybe need +to get +.B crash +to work. Best results will be had using the same version of linux +while running +.B crash +as the \fIdomain\fR is running. + +.SH AUTHOR +Don Slutz + +.SH "SEE ALSO" +crash(8) diff --git a/tools/xen-crashd/xen-crashd.c b/tools/xen-crashd/xen-crashd.c new file mode 100644 index 0000000..dabab39 --- /dev/null +++ b/tools/xen-crashd/xen-crashd.c @@ -0,0 +1,891 @@ +/****************************************************************************** + * tools/xen-crashd/xen-crashd.c + * + * Connect crash to DOMu. + * + * Copyright (C) 2012 by Cloud Switch, Inc. + * Copyright (C) 2013 by Terremark. + * Copyright (C) 2013 by Verizon. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xenctrl.h" +#include +#include +#include + +xc_interface *xc_handle = 0; +int domid = 0; +int debug = 0; + +#if defined (__i386__) || defined (__x86_64__) +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; +#elif defined(__arm__) +#define NO_TRANSLATION +typedef uint64_t guest_word_t; +#define FMT_32B_WORD "%08llx" +#define FMT_64B_WORD "%016llx" +#elif defined(__aarch64__) +#define NO_TRANSLATION +typedef uint64_t guest_word_t; +#define FMT_32B_WORD "%08lx" +#define FMT_64B_WORD "%016lx" +#endif + +#define STRNEQ(A, B) (B && \ + (strncmp((char *)(A), (char *)(B), strlen((char *)(B))) == 0)) +#define FAILMSG "FAIL " +#define DONEMSG "DONE " + +#define DATA_HDRSIZE (strlen("XXXX ") + strlen("1234567") + 1) + +#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 +tcp_read(int sock, const char *pv_buffer, size_t cb_buffer, int nil_mode) +{ + size_t cb_total = 0; + + do + { + ssize_t cb_read = recv(sock, (void*)pv_buffer, cb_buffer, MSG_NOSIGNAL); + + if (cb_read <= 0) + return cb_read; + cb_total += cb_read; + if (!nil_mode && cb_total >= 4) + return cb_total; + if (!pv_buffer[cb_read - 1]) + return cb_total; + cb_buffer -= cb_read; + pv_buffer = (char *)pv_buffer + cb_read; + } while (cb_buffer); + + return cb_total; +} + +int +tcp_write(int sock, const void *pv_buffer, size_t cb_buffer) +{ + if (debug & 0x002) { + print_now(); + printf("rtn: %s\n", (char*)pv_buffer); + } + do + { + size_t cb_now = cb_buffer; + ssize_t cb_written = send(sock, (const char *)pv_buffer, cb_now, MSG_NOSIGNAL); + + if (cb_written < 0) + return 1; + cb_buffer -= cb_written; + pv_buffer = (char *)pv_buffer + cb_written; + } while (cb_buffer); + + return 0; +} + +int +tcp_write_string(int sock, const char *pv_buffer) +{ + if (debug & 0x020) { + print_now(); + printf("rtn: %s\n", (char*)pv_buffer); + } + return tcp_write(sock, pv_buffer, strlen(pv_buffer) + 1); +} + +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 & 0x044) { + 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 * pv_dst, size_t cb, guest_word_t phys) +{ + void * local_addr; + size_t cb_page = XC_PAGE_SIZE - (phys & ~XC_PAGE_MASK); + + /* optimize for the case where access is completely within the first page. */ + local_addr = map_page(vcpu, phys); + if (!local_addr) { + return ENXIO; + } + if (cb <= cb_page) { + memcpy(pv_dst, local_addr, cb); + return 0; + } + memcpy(pv_dst, local_addr, cb_page); + pv_dst += cb_page; + phys += cb_page; + cb -= cb_page; + + /* Max transfer is XC_PAGE_SIZE... */ + if (cb > XC_PAGE_SIZE) + return EINVAL; + local_addr = map_page(vcpu, phys); + if (!local_addr) { + return ENXIO; + } + memcpy(pv_dst, local_addr, 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; + + if (mfn == 0) + return 0; + else + return (mfn << XC_PAGE_SHIFT) + offset; +} + +static int +copy_virt(int vcpu, char * pv_dst, size_t cb, guest_word_t virt) +{ + void * local_addr; + 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 cb_page = XC_PAGE_SIZE - offset; + + if (mfn == 0) + return EFAULT; + /* optimize for the case where access is completely within the first page. */ + + local_addr = map_page(vcpu, phys); + if (!local_addr) { + return ENXIO; + } + if (cb <= cb_page) { + memcpy(pv_dst, local_addr, cb); + return 0; + } + memcpy(pv_dst, local_addr, cb_page); + pv_dst += cb_page; + phys += cb_page; + cb -= cb_page; + + /* Max transfer is XC_PAGE_SIZE... */ + if (cb > XC_PAGE_SIZE) + return EINVAL; + local_addr = map_page(vcpu, phys); + if (!local_addr) { + return ENXIO; + } + memcpy(pv_dst, local_addr, 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 cb_read = 0; + + int ret; + int vcpu; + int nil_mode = 0; + vcpu_guest_context_any_t ctx; + xc_dominfo_t dominfo; + struct hvm_hw_cpu cpuctx; + + if (argc < 2 || argc > 4) { + printf("usage: xen-crashd []\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 = strtol(argv[3], NULL, 0); + if (debug) + printf("xen-crashd: debug=%d(0x%x)\n", debug, debug); + + 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 */ + if (!xc_handle) { + perror("xc_interface_open"); + exit(-1); + } + + 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 { + cb_read = tcp_read(msgsock, recvbuf, BUFSIZE, nil_mode); + if (cb_read <= 0) { + close(msgsock); + msgsock = -1; + break; + } + recvbuf[cb_read] = 0; + + if (debug & 0x001) { + print_now(); + printf("req: %s\n", recvbuf); + } + + if (STRNEQ(recvbuf, "READ_LIVE")) + { + char *p1, *p2, *p3, *p4; + int rc2; + 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 = EINVAL; + } + + if (len) + { + if (p4) { + int my_cpu = atoi(p4); + + if (debug & 0x004) { + guest_word_t p_addr = convert_to_phys(my_cpu, addr); + print_now(); + printf("copy_virt(%d,,%d, 0x%llx)[%s %s %s %s] p_addr=0x%lx\n", + my_cpu, len, addr, p1, p2, p3, p4, (long)p_addr); + } + rc2 = copy_virt(my_cpu, &sendbuf[DATA_HDRSIZE], len, addr); + } else if (fds[fid] == 3) { + if (debug & 0x004) { + guest_word_t p_addr = convert_to_phys(vcpu, addr); + + print_now(); + printf("copy_virt(%d,,%d, 0x%llx)[%s %s %s] p_addr=0x%lx\n", + vcpu, len, addr, p1, p2, p3, (long)p_addr); + } + rc2 = copy_virt(vcpu, &sendbuf[DATA_HDRSIZE], len, addr); + } else { + if (debug & 0x004) { + 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 & 0x044) { + print_now(); + printf("Failed rc2=%d\n", rc2); + } + len = 0; + } + } + + if (!len) { + snprintf(sendbuf, sizeof(sendbuf), "%s%07u", FAILMSG, rc2); + } else { + snprintf(sendbuf, sizeof(sendbuf), "%s%07u", DONEMSG, len); + } + if (tcp_write(msgsock, sendbuf, len + DATA_HDRSIZE)) + break; + } + else if (STRNEQ(recvbuf, "FETCH_LIVE_IP_SP_BP ")) + { + char *p1, *p2; + int cpu; + long domu_ip = 0; + short domu_cs = 0; + short domu_ss = 0; + long domu_sp = 0; + long domu_bp = 0; + + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + 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); + + domu_ip = regs->eip; + domu_sp = regs->esp; + domu_bp = regs->ebp; + domu_cs = regs->cs; + domu_ss = regs->ss; + } else { + struct cpu_user_regs_x86_64 * regs = &(ctx.x64.user_regs); + + if (dominfo.hvm) { + domu_ip = cpuctx.rip; + domu_sp = cpuctx.rsp; + domu_bp = cpuctx.rbp; + domu_cs = cpuctx.cs_sel; + domu_ss = cpuctx.ss_sel; + if (debug & 0x100) { + if (domu_ip != regs->rip) { + printf("domu_ip(%lx) != rip(%lx)\n", domu_ip, regs->rip); + } + if (domu_sp != regs->rsp) { + printf("domu_sp(%lx) != rsp(%lx)\n", domu_sp, regs->rsp); + } + if (domu_bp != regs->rbp) { + printf("domu_bp(%lx) != rbp(%lx)\n", domu_bp, regs->rbp); + } + if (domu_cs != regs->cs) { + printf("domu_cs(%x) != cs(%x)\n", domu_cs, regs->cs); + } + if (domu_ss != regs->ss) { + printf("domu_ss(%x) != ss(%x)\n", domu_ss, regs->ss); + } + } + } else { + domu_ip = regs->rip; + domu_sp = regs->rsp; + domu_bp = regs->rbp; + domu_cs = regs->cs; + domu_ss = regs->ss; + } + } + + snprintf(sendbuf, sizeof(sendbuf), "%s %d %04x:%lx %04x:%lx %lx", + p1, cpu, domu_cs, domu_ip, domu_ss, domu_sp, domu_bp); + if (tcp_write_string(msgsock, sendbuf)) + break; + } + else if (STRNEQ(recvbuf, "FETCH_LIVE_CR3 ")) + { + char *p1, *p2; + int cpu; + long domu_cr3 = 0; + + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + 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) { + domu_cr3 = ctx.x32.ctrlreg[3]; + } else { + if (dominfo.hvm) { + domu_cr3 = cpuctx.cr3; + if (debug & 0x100) { + if (domu_cr3 != ctx.x64.ctrlreg[3]) { + printf("domu_cr3(%lx) != cr3(%lx)\n", domu_cr3, ctx.x64.ctrlreg[3]); + } + } + } else { + domu_cr3 = ctx.x64.ctrlreg[3]; + } + } + + snprintf(sendbuf, sizeof(sendbuf), "%s %d %lx", + p1, cpu, domu_cr3); + if (tcp_write_string(msgsock, sendbuf)) + break; + } + else if (STRNEQ(recvbuf, "MACHINE_PID")) + { + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } +#if defined (__i386__) || defined (__x86_64__) + if (guest_word_size == 8) + snprintf(sendbuf, sizeof(sendbuf), "%s %s %d", + recvbuf, "X86_64", 0); + else + snprintf(sendbuf, sizeof(sendbuf), "%s %s %d", + recvbuf, "X86", 0); +#elif defined(__arm__) + snprintf(sendbuf, sizeof(sendbuf), "%s %s %d", + recvbuf, "ARM", 0); +#elif defined(__aarch64__) + snprintf(sendbuf, sizeof(sendbuf), "%s %s %d", + recvbuf, "ARM64", 0); +#endif + if (tcp_write_string(msgsock, sendbuf)) + break; + } + else if (STRNEQ(recvbuf, "TYPE ")) + { + char *p1; + char *file; + + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + p1 = strtok(recvbuf, " "); /* TYPE */ + file = strtok(NULL, " "); /* filename */ + if (STRNEQ(file, "/dev/mem")) + { + snprintf(sendbuf, sizeof(sendbuf), "%s %s DEVMEM", p1, file); + } + else if (STRNEQ(file, "/dev/kmem")) + { + snprintf(sendbuf, sizeof(sendbuf), "%s %s DEVMEM", p1, file); + } + else if (STRNEQ(file, "/dev/vmem")) + { + snprintf(sendbuf, sizeof(sendbuf), "%s %s DEVMEM", p1, file); + } + else if (STRNEQ(file, "/dev/xenmem")) + { + snprintf(sendbuf, sizeof(sendbuf), "%s %s DEVMEM", p1, file); + } + else + { + snprintf(sendbuf, sizeof(sendbuf), "%s %s ", p1, file); + } + if (tcp_write_string(msgsock, sendbuf)) + break; + } + else if (STRNEQ(recvbuf, "VTOP")) + { + char *p1, *p2, *p3; + int cpu; + guest_word_t v_addr, p_addr; + + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + p1 = strtok(recvbuf, " "); /* VTOP */ + p2 = strtok(NULL, " "); /* cpu */ + p3 = strtok(NULL, " "); /* vaddress */ + + cpu = atoi(p2); + v_addr = strtoull(p3, NULL, 16); + + p_addr = convert_to_phys(cpu, v_addr); + + snprintf(sendbuf, sizeof(sendbuf), "%s %d %lx %lx", + p1, cpu, (long)v_addr, (long)p_addr); + if (tcp_write_string(msgsock, sendbuf)) + break; + } + else if (STRNEQ(recvbuf, "OPEN ")) + { + char *p1; + char *file; + + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + 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 * 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 * 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 * 1024LL * 1024LL); + } + else if (STRNEQ(file, "/dev/xenmem")) + { + fds[i] = 4; + snprintf(sendbuf, sizeof(sendbuf), "%s %s %d O_RDONLY %lld", p1, file, i, 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL); + } + else + { + snprintf(sendbuf, sizeof(sendbuf), "%s %s ", p1, file); + } + } + else + { + snprintf(sendbuf, sizeof(sendbuf), "%s %s ", p1, file); + } + if (tcp_write_string(msgsock, sendbuf)) + break; + } + else if (STRNEQ(recvbuf, "CLOSE ")) + { + char *p1, *p2; + + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + p1 = strtok(recvbuf, " "); /* CLOSE */ + p2 = strtok(NULL, " "); /* filename id */ + snprintf(sendbuf, sizeof(sendbuf), "%s %s ", p1, p2); + if (tcp_write_string(msgsock, sendbuf)) + break; + } + else if (STRNEQ(recvbuf, "PROC_VERSION")) + { + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + /* + * Perform the detection. + */ + snprintf(sendbuf, sizeof(sendbuf), ""); + if (tcp_write_string(msgsock, sendbuf)) + break; + } + else if (STRNEQ(recvbuf, "PAGESIZE ")) + { + char *p1, *p2; + + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + p1 = strtok(recvbuf, " "); /* PAGESIZE */ + p2 = strtok(NULL, " "); /* type */ + if (STRNEQ(p2, "LIVE")) + { + snprintf(sendbuf, sizeof(sendbuf), "%s %s %ld XEN %d", + p1, p2, XC_PAGE_SIZE, dominfo.max_vcpu_id + 1); + } + else if (STRNEQ(p2, "NIL")) + { + snprintf(sendbuf, sizeof(sendbuf), "%s %s %ld XEN %d", + p1, p2, XC_PAGE_SIZE, dominfo.max_vcpu_id + 1); + } + else + { + snprintf(sendbuf, sizeof(sendbuf), "%s %s ", p1, p2); + } + if (tcp_write_string(msgsock, sendbuf)) + break; + } + else if (STRNEQ(recvbuf, "EXIT")) + { + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + snprintf(sendbuf, sizeof(sendbuf), "%s OK", recvbuf); + tcp_write_string(msgsock, sendbuf); + break; + } + else if (STRNEQ(recvbuf, "NIL")) + { + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + nil_mode = 1; + snprintf(sendbuf, sizeof(sendbuf), "%s XEN OK", recvbuf); + if (tcp_write_string(msgsock, sendbuf)) + break; + } + else + { + if (debug & 0x010) { + print_now(); + printf("req: %s\n", recvbuf); + } + print_now(); + printf("unknown: %s\n", recvbuf); + snprintf(sendbuf, sizeof(sendbuf), "%s ", recvbuf); + if (tcp_write_string(msgsock, 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.11.7