aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpus.c47
-rw-r--r--hmp-commands.hx3
-rw-r--r--hmp.c19
-rw-r--r--hmp.h1
-rw-r--r--monitor.c38
-rw-r--r--qapi-schema.json26
-rw-r--r--qmp-commands.hx10
7 files changed, 97 insertions, 47 deletions
diff --git a/cpus.c b/cpus.c
index ca46ec6523..0f2ce60a36 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1136,3 +1136,50 @@ CpuInfoList *qmp_query_cpus(Error **errp)
return head;
}
+
+void qmp_memsave(int64_t addr, int64_t size, const char *filename,
+ bool has_cpu, int64_t cpu_index, Error **errp)
+{
+ FILE *f;
+ uint32_t l;
+ CPUState *env;
+ uint8_t buf[1024];
+
+ if (!has_cpu) {
+ cpu_index = 0;
+ }
+
+ for (env = first_cpu; env; env = env->next_cpu) {
+ if (cpu_index == env->cpu_index) {
+ break;
+ }
+ }
+
+ if (env == NULL) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
+ "a CPU number");
+ return;
+ }
+
+ f = fopen(filename, "wb");
+ if (!f) {
+ error_set(errp, QERR_OPEN_FILE_FAILED, filename);
+ return;
+ }
+
+ while (size != 0) {
+ l = sizeof(buf);
+ if (l > size)
+ l = size;
+ cpu_memory_rw_debug(env, addr, buf, l, 0);
+ if (fwrite(buf, 1, l, f) != l) {
+ error_set(errp, QERR_IO_ERROR);
+ goto exit;
+ }
+ addr += l;
+ size -= l;
+ }
+
+exit:
+ fclose(f);
+}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 79a919526d..dac0b47b80 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -689,8 +689,7 @@ ETEXI
.args_type = "val:l,size:i,filename:s",
.params = "addr size file",
.help = "save to disk virtual memory dump starting at 'addr' of size 'size'",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_memory_save,
+ .mhandler.cmd = hmp_memsave,
},
STEXI
diff --git a/hmp.c b/hmp.c
index dfab7ad9bb..67b3eb394b 100644
--- a/hmp.c
+++ b/hmp.c
@@ -14,6 +14,14 @@
#include "hmp.h"
#include "qmp-commands.h"
+static void hmp_handle_error(Monitor *mon, Error **errp)
+{
+ if (error_is_set(errp)) {
+ monitor_printf(mon, "%s\n", error_get_pretty(*errp));
+ error_free(*errp);
+ }
+}
+
void hmp_info_name(Monitor *mon)
{
NameInfo *info;
@@ -531,3 +539,14 @@ void hmp_cpu(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "invalid CPU index\n");
}
}
+
+void hmp_memsave(Monitor *mon, const QDict *qdict)
+{
+ uint32_t size = qdict_get_int(qdict, "size");
+ const char *filename = qdict_get_str(qdict, "filename");
+ uint64_t addr = qdict_get_int(qdict, "val");
+ Error *errp = NULL;
+
+ qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &errp);
+ hmp_handle_error(mon, &errp);
+}
diff --git a/hmp.h b/hmp.h
index 4422578448..dd8ad0cf41 100644
--- a/hmp.h
+++ b/hmp.h
@@ -37,5 +37,6 @@ void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
void hmp_cpu(Monitor *mon, const QDict *qdict);
+void hmp_memsave(Monitor *mon, const QDict *qdict);
#endif
diff --git a/monitor.c b/monitor.c
index 344b196451..727201441d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1370,44 +1370,6 @@ static void do_print(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "\n");
}
-static int do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- FILE *f;
- uint32_t size = qdict_get_int(qdict, "size");
- const char *filename = qdict_get_str(qdict, "filename");
- target_long addr = qdict_get_int(qdict, "val");
- uint32_t l;
- CPUState *env;
- uint8_t buf[1024];
- int ret = -1;
-
- env = mon_get_cpu();
-
- f = fopen(filename, "wb");
- if (!f) {
- qerror_report(QERR_OPEN_FILE_FAILED, filename);
- return -1;
- }
- while (size != 0) {
- l = sizeof(buf);
- if (l > size)
- l = size;
- cpu_memory_rw_debug(env, addr, buf, l, 0);
- if (fwrite(buf, 1, l, f) != l) {
- monitor_printf(mon, "fwrite() error in do_memory_save\n");
- goto exit;
- }
- addr += l;
- size -= l;
- }
-
- ret = 0;
-
-exit:
- fclose(f);
- return ret;
-}
-
static int do_physical_memory_save(Monitor *mon, const QDict *qdict,
QObject **ret_data)
{
diff --git a/qapi-schema.json b/qapi-schema.json
index fbbdbe0914..dbf617001e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -901,3 +901,29 @@
# Notes: Do not use this command.
##
{ 'command': 'cpu', 'data': {'index': 'int'} }
+
+##
+# @memsave:
+#
+# Save a portion of guest memory to a file.
+#
+# @val: the virtual address of the guest to start from
+#
+# @size: the size of memory region to save
+#
+# @filename: the file to save the memory to as binary data
+#
+# @cpu-index: #optional the index of the virtual CPU to use for translating the
+# virtual address (defaults to CPU 0)
+#
+# Returns: Nothing on success
+# If @cpu is not a valid VCPU, InvalidParameterValue
+# If @filename cannot be opened, OpenFileFailed
+# If an I/O error occurs while writing the file, IOError
+#
+# Since: 0.14.0
+#
+# Notes: Errors were not reliably returned until 1.1
+##
+{ 'command': 'memsave',
+ 'data': {'val': 'int', 'size': 'int', 'filename': 'str', '*cpu-index': 'int'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4fcb92ccfa..0e2f3926e6 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -352,11 +352,8 @@ EQMP
{
.name = "memsave",
- .args_type = "val:l,size:i,filename:s",
- .params = "addr size file",
- .help = "save to disk virtual memory dump starting at 'addr' of size 'size'",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_memory_save,
+ .args_type = "val:l,size:i,filename:s,cpu:i?",
+ .mhandler.cmd_new = qmp_marshal_input_memsave,
},
SQMP
@@ -370,6 +367,7 @@ Arguments:
- "val": the starting address (json-int)
- "size": the memory size, in bytes (json-int)
- "filename": file path (json-string)
+- "cpu": virtual CPU index (json-int, optional)
Example:
@@ -379,8 +377,6 @@ Example:
"filename": "/tmp/virtual-mem-dump" } }
<- { "return": {} }
-Note: Depends on the current CPU.
-
EQMP
{