Index: docs/hvsupport.html.in
===================================================================
RCS file: /data/cvs/libvirt/docs/hvsupport.html.in,v
retrieving revision 1.2
diff -u -p -r1.2 hvsupport.html.in
--- docs/hvsupport.html.in 5 Jun 2008 13:17:45 -0000 1.2
+++ docs/hvsupport.html.in 5 Jun 2008 21:26:24 -0000
@@ -145,9 +145,9 @@ updated on 2008-06-05.
virDomainBlockPeek |
0.4.3 |
- x |
- x |
- x |
+ 0.4.3 |
+ 0.4.3 |
+ 0.4.3 |
x |
@@ -487,6 +487,14 @@ updated on 2008-06-05.
not a HV function |
+ virDomainMemoryPeek |
+ 0.4.3 |
+ x |
+ 0.4.3 |
+ 0.4.3 |
+ x |
+
+
virNodeGetInfo |
0.1.0 |
≥ 0.1.0 |
Index: include/libvirt/libvirt.h
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h,v
retrieving revision 1.75
diff -u -p -r1.75 libvirt.h
--- include/libvirt/libvirt.h 5 Jun 2008 13:17:45 -0000 1.75
+++ include/libvirt/libvirt.h 5 Jun 2008 21:26:25 -0000
@@ -537,6 +537,17 @@ int virDomainBlockPe
void *buffer,
unsigned int flags);
+/* Memory peeking flags. */
+typedef enum {
+ VIR_MEMORY_VIRTUAL = 1, /* addresses are virtual addresses */
+} virDomainMemoryFlags;
+
+int virDomainMemoryPeek (virDomainPtr dom,
+ unsigned long long start,
+ size_t size,
+ void *buffer,
+ unsigned int flags);
+
/*
* defined but not running domains
*/
Index: include/libvirt/libvirt.h.in
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h.in,v
retrieving revision 1.50
diff -u -p -r1.50 libvirt.h.in
--- include/libvirt/libvirt.h.in 5 Jun 2008 13:17:45 -0000 1.50
+++ include/libvirt/libvirt.h.in 5 Jun 2008 21:26:26 -0000
@@ -537,6 +537,17 @@ int virDomainBlockPe
void *buffer,
unsigned int flags);
+/* Memory peeking flags. */
+typedef enum {
+ VIR_MEMORY_VIRTUAL = 1, /* addresses are virtual addresses */
+} virDomainMemoryFlags;
+
+int virDomainMemoryPeek (virDomainPtr dom,
+ unsigned long long start,
+ size_t size,
+ void *buffer,
+ unsigned int flags);
+
/*
* defined but not running domains
*/
Index: qemud/remote.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote.c,v
retrieving revision 1.36
diff -u -p -r1.36 remote.c
--- qemud/remote.c 5 Jun 2008 21:12:26 -0000 1.36
+++ qemud/remote.c 5 Jun 2008 21:26:29 -0000
@@ -938,6 +938,52 @@ remoteDispatchDomainBlockPeek (struct qe
}
static int
+remoteDispatchDomainMemoryPeek (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client,
+ remote_message_header *req,
+ remote_domain_memory_peek_args *args,
+ remote_domain_memory_peek_ret *ret)
+{
+ virDomainPtr dom;
+ unsigned long long offset;
+ size_t size;
+ unsigned int flags;
+ CHECK_CONN (client);
+
+ dom = get_nonnull_domain (client->conn, args->dom);
+ if (dom == NULL) {
+ remoteDispatchError (client, req, "%s", _("domain not found"));
+ return -2;
+ }
+ offset = args->offset;
+ size = args->size;
+ flags = args->flags;
+
+ if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) {
+ remoteDispatchError (client, req,
+ "%s", _("size > maximum buffer size"));
+ return -2;
+ }
+
+ ret->buffer.buffer_len = size;
+ ret->buffer.buffer_val = malloc (size);
+ if (!ret->buffer.buffer_val) {
+ remoteDispatchError (client, req, "%s", strerror (errno));
+ return -2;
+ }
+
+ if (virDomainMemoryPeek (dom, offset, size,
+ ret->buffer.buffer_val, flags) == -1) {
+ /* free (ret->buffer.buffer_val); - caller frees */
+ virDomainFree (dom);
+ return -1;
+ }
+ virDomainFree (dom);
+
+ return 0;
+}
+
+static int
remoteDispatchDomainAttachDevice (struct qemud_server *server ATTRIBUTE_UNUSED,
struct qemud_client *client,
remote_message_header *req,
Index: qemud/remote_protocol.x
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote_protocol.x,v
retrieving revision 1.14
diff -u -p -r1.14 remote_protocol.x
--- qemud/remote_protocol.x 5 Jun 2008 21:12:27 -0000 1.14
+++ qemud/remote_protocol.x 5 Jun 2008 21:26:29 -0000
@@ -340,6 +340,17 @@ struct remote_domain_block_peek_ret {
opaque buffer;
};
+struct remote_domain_memory_peek_args {
+ remote_nonnull_domain dom;
+ unsigned hyper offset;
+ unsigned size;
+ unsigned flags;
+};
+
+struct remote_domain_memory_peek_ret {
+ opaque buffer;
+};
+
struct remote_list_domains_args {
int maxids;
};
@@ -1056,7 +1067,8 @@ enum remote_procedure {
REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101,
REMOTE_PROC_NODE_GET_FREE_MEMORY = 102,
- REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103
+ REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103,
+ REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104
};
/* Custom RPC structure. */
Index: src/driver.h
===================================================================
RCS file: /data/cvs/libvirt/src/driver.h,v
retrieving revision 1.49
diff -u -p -r1.49 driver.h
--- src/driver.h 5 Jun 2008 21:12:27 -0000 1.49
+++ src/driver.h 5 Jun 2008 21:26:30 -0000
@@ -234,6 +234,13 @@ typedef int
unsigned int flags);
typedef int
+ (*virDrvDomainMemoryPeek)
+ (virDomainPtr domain,
+ unsigned long long start, size_t size,
+ void *buffer,
+ unsigned int flags);
+
+typedef int
(*virDrvDomainMigratePrepare)
(virConnectPtr dconn,
char **cookie,
@@ -346,6 +353,7 @@ struct _virDriver {
virDrvDomainBlockStats domainBlockStats;
virDrvDomainInterfaceStats domainInterfaceStats;
virDrvDomainBlockPeek domainBlockPeek;
+ virDrvDomainMemoryPeek domainMemoryPeek;
virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory;
virDrvNodeGetFreeMemory getFreeMemory;
};
Index: src/libvirt.c
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt.c,v
retrieving revision 1.145
diff -u -p -r1.145 libvirt.c
--- src/libvirt.c 5 Jun 2008 21:12:27 -0000 1.145
+++ src/libvirt.c 5 Jun 2008 21:26:33 -0000
@@ -2666,6 +2666,92 @@ virDomainBlockPeek (virDomainPtr dom,
return -1;
}
+/**
+ * virDomainMemoryPeek:
+ * @dom: pointer to the domain object
+ * @start: start of memory to peek
+ * @size: size of memory to peek
+ * @buffer: return buffer (must be at least size bytes)
+ * @flags: flags, see below
+ *
+ * This function allows you to read the contents of a domain's
+ * memory.
+ *
+ * The memory which is read is controlled by the 'start', 'size'
+ * and 'flags' parameters.
+ *
+ * If 'flags' is VIR_MEMORY_VIRTUAL then the 'start' and 'size'
+ * parameters are interpreted as virtual memory addresses for
+ * whichever task happens to be running on the domain at the
+ * moment. Although this sounds haphazard it is in fact what
+ * you want in order to read Linux kernel state, because it
+ * ensures that pointers in the kernel image can be interpreted
+ * coherently.
+ *
+ * 'buffer' is the return buffer and must be at least 'size' bytes.
+ * 'size' may be 0 to test if the call would succeed.
+ *
+ * Returns: 0 in case of success or -1 in case of failure.
+ */
+int
+virDomainMemoryPeek (virDomainPtr dom,
+ unsigned long long start /* really 64 bits */,
+ size_t size,
+ void *buffer,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+ DEBUG ("domain=%p, start=%lld, size=%zi, buffer=%p, flags=%d",
+ dom, start, size, buffer, flags);
+
+ if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+ virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ return -1;
+ }
+ conn = dom->conn;
+
+ /* Flags must be VIR_MEMORY_VIRTUAL at the moment.
+ *
+ * Note on access to physical memory: A VIR_MEMORY_PHYSICAL flag is
+ * a possibility. However it isn't really useful unless the caller
+ * can also access registers, particularly CR3 on x86 in order to
+ * get the Page Table Directory. Since registers are different on
+ * every architecture, that would imply another call to get the
+ * machine registers.
+ *
+ * The QEMU driver handles only VIR_MEMORY_VIRTUAL, mapping it
+ * to the qemu 'memsave' command which does the virtual to physical
+ * mapping inside qemu.
+ *
+ * At time of writing there is no Xen driver. However the Xen
+ * hypervisor only lets you map physical pages from other domains,
+ * and so the Xen driver would have to do the virtual to physical
+ * mapping by chasing 2, 3 or 4-level page tables from the PTD.
+ * There is example code in libxc (xc_translate_foreign_address)
+ * which does this, although we cannot copy this code directly
+ * because of incompatible licensing.
+ */
+ if (flags != VIR_MEMORY_VIRTUAL) {
+ virLibDomainError (dom, VIR_ERR_INVALID_ARG,
+ _("flags parameter must be VIR_MEMORY_VIRTUAL"));
+ return -1;
+ }
+
+ /* Allow size == 0 as an access test. */
+ if (size > 0 && !buffer) {
+ virLibDomainError (dom, VIR_ERR_INVALID_ARG,
+ _("buffer is NULL but size is non-zero"));
+ return -1;
+ }
+
+ if (conn->driver->domainMemoryPeek)
+ return conn->driver->domainMemoryPeek (dom, start, size,
+ buffer, flags);
+
+ virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
/************************************************************************
* *
Index: src/libvirt_sym.version
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt_sym.version,v
retrieving revision 1.41
diff -u -p -r1.41 libvirt_sym.version
--- src/libvirt_sym.version 5 Jun 2008 13:17:45 -0000 1.41
+++ src/libvirt_sym.version 5 Jun 2008 21:26:33 -0000
@@ -74,6 +74,7 @@
virDomainBlockStats;
virDomainInterfaceStats;
virDomainBlockPeek;
+ virDomainMemoryPeek;
virDomainAttachDevice;
virDomainDetachDevice;
Index: src/qemu_driver.c
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_driver.c,v
retrieving revision 1.84
diff -u -p -r1.84 qemu_driver.c
--- src/qemu_driver.c 5 Jun 2008 21:12:27 -0000 1.84
+++ src/qemu_driver.c 5 Jun 2008 21:26:35 -0000
@@ -3221,6 +3221,74 @@ found:
return ret;
}
+static int
+qemudDomainMemoryPeek (virDomainPtr dom,
+ unsigned long long offset, size_t size,
+ void *buffer,
+ unsigned int flags)
+{
+ struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
+ struct qemud_vm *vm = qemudFindVMByID (driver, dom->id);
+ char cmd[256], *info;
+ char tmp[] = "/tmp/qemumemXXXXXX";
+ int fd = -1, ret = -1;
+
+ if (flags != VIR_MEMORY_VIRTUAL) {
+ qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
+ _("QEMU driver only supports virtual memory addrs"));
+ return -1;
+ }
+
+ if (!vm) {
+ qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
+ _("no domain with matching id %d"), dom->id);
+ return -1;
+ }
+
+ if (!qemudIsActiveVM(vm)) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+ "%s", _("domain is not running"));
+ return -1;
+ }
+
+ /* Create a temporary filename. */
+ if (mkstemp (tmp) == -1) {
+ qemudReportError (dom->conn, dom, NULL, VIR_ERR_SYSTEM_ERROR,
+ "%s", strerror (errno));
+ return -1;
+ }
+
+ /* Issue the memsave command. */
+ snprintf (cmd, sizeof cmd, "memsave %llu %zi \"%s\"", offset, size, tmp);
+ if (qemudMonitorCommand (driver, vm, cmd, &info) < 0) {
+ qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+ "%s", _("'info blockstats' command failed"));
+ goto done;
+ }
+
+ DEBUG ("memsave reply: %s", info);
+ free (info);
+
+ /* Read the memory file into buffer. */
+ fd = open (tmp, O_RDONLY);
+ if (fd == -1) {
+ qemudReportError (dom->conn, dom, NULL, VIR_ERR_SYSTEM_ERROR,
+ "%s", strerror (errno));
+ goto done;
+ }
+ if (saferead (fd, buffer, size) == (ssize_t) -1) {
+ qemudReportError (dom->conn, dom, NULL, VIR_ERR_SYSTEM_ERROR,
+ "%s", strerror (errno));
+ goto done;
+ }
+
+ ret = 0;
+done:
+ if (fd >= 0) close (fd);
+ unlink (tmp);
+ return ret;
+}
+
static virNetworkPtr qemudNetworkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED,
const unsigned char *uuid) {
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
@@ -3580,6 +3648,7 @@ static virDriver qemuDriver = {
qemudDomainBlockStats, /* domainBlockStats */
qemudDomainInterfaceStats, /* domainInterfaceStats */
qemudDomainBlockPeek, /* domainBlockPeek */
+ qemudDomainMemoryPeek, /* domainMemoryPeek */
#if HAVE_NUMACTL
qemudNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
qemudNodeGetFreeMemory, /* getFreeMemory */
Index: src/remote_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/remote_internal.c,v
retrieving revision 1.77
diff -u -p -r1.77 remote_internal.c
--- src/remote_internal.c 5 Jun 2008 21:12:27 -0000 1.77
+++ src/remote_internal.c 5 Jun 2008 21:26:39 -0000
@@ -2420,6 +2420,50 @@ remoteDomainBlockPeek (virDomainPtr doma
return 0;
}
+static int
+remoteDomainMemoryPeek (virDomainPtr domain,
+ unsigned long long offset,
+ size_t size,
+ void *buffer,
+ unsigned int flags)
+{
+ remote_domain_memory_peek_args args;
+ remote_domain_memory_peek_ret ret;
+ GET_PRIVATE (domain->conn, -1);
+
+ if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) {
+ errorf (domain->conn, VIR_ERR_RPC,
+ _("memory peek request too large for remote protocol, %zi > %d"),
+ size, REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX);
+ return -1;
+ }
+
+ make_nonnull_domain (&args.dom, domain);
+ args.offset = offset;
+ args.size = size;
+ args.flags = flags;
+
+ memset (&ret, 0, sizeof ret);
+ if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_MEMORY_PEEK,
+ (xdrproc_t) xdr_remote_domain_memory_peek_args,
+ (char *) &args,
+ (xdrproc_t) xdr_remote_domain_memory_peek_ret,
+ (char *) &ret) == -1)
+ return -1;
+
+ if (ret.buffer.buffer_len != size) {
+ errorf (domain->conn, VIR_ERR_RPC,
+ _("returned buffer is not same size as requested"));
+ free (ret.buffer.buffer_val);
+ return -1;
+ }
+
+ memcpy (buffer, ret.buffer.buffer_val, size);
+ free (ret.buffer.buffer_val);
+
+ return 0;
+}
+
/*----------------------------------------------------------------------*/
static int
@@ -4831,6 +4875,7 @@ static virDriver driver = {
.domainBlockStats = remoteDomainBlockStats,
.domainInterfaceStats = remoteDomainInterfaceStats,
.domainBlockPeek = remoteDomainBlockPeek,
+ .domainMemoryPeek = remoteDomainMemoryPeek,
.nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory,
.getFreeMemory = remoteNodeGetFreeMemory,
};
Index: src/test.c
===================================================================
RCS file: /data/cvs/libvirt/src/test.c,v
retrieving revision 1.76
diff -u -p -r1.76 test.c
--- src/test.c 5 Jun 2008 13:17:45 -0000 1.76
+++ src/test.c 5 Jun 2008 21:26:40 -0000
@@ -2061,6 +2061,7 @@ static virDriver testDriver = {
NULL, /* domainBlockStats */
NULL, /* domainInterfaceStats */
NULL, /* domainBlockPeek */
+ NULL, /* domainMemoryPeek */
testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
NULL, /* getFreeMemory */
};