summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Snow <jsnow@redhat.com>2015-05-22 14:13:44 -0400
committerJohn Snow <jsnow@redhat.com>2015-05-22 15:58:22 -0400
commit7a6a740d8dcc02f5693315d7935b5de9b963bb96 (patch)
treea2e267889145f6cff4d1af159684568d19bd16a8
parent332cc7e9b39ddb2feacb4c71dcd18c3e5b0c3147 (diff)
downloadqemu-7a6a740d8dcc02f5693315d7935b5de9b963bb96.tar.gz
qtest: Add base64 encoded read/write
For larger pieces of data that won't need to be debugged and viewing the hex nibbles is unlikely to be useful, we can encode data using base64 instead of encoding each byte as %02x, which leads to some space savings and faster reads/writes. For now, the default is left as hex nibbles in memwrite() and memread(). For the purposes of making qtest io easier to read and debug, some callers may want to specify using the old encoding format for small patches of data where the savings from base64 wouldn't be that profound. memwrite/memread use a data encoding that takes 2x the size of the original buffer, but base64 uses "only" (4/3)x, so for larger buffers we can save a decent amount of time and space. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 1430864578-22072-3-git-send-email-jsnow@redhat.com
-rw-r--r--qtest.c69
-rw-r--r--tests/libqtest.c31
-rw-r--r--tests/libqtest.h49
3 files changed, 149 insertions, 0 deletions
diff --git a/qtest.c b/qtest.c
index 3738eae377..73b7a0f9b8 100644
--- a/qtest.c
+++ b/qtest.c
@@ -119,12 +119,21 @@ static bool qtest_opened;
* > write ADDR SIZE DATA
* < OK
*
+ * > b64read ADDR SIZE
+ * < OK B64_DATA
+ *
+ * > b64write ADDR SIZE B64_DATA
+ * < OK
+ *
* ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
*
* DATA is an arbitrarily long hex number prefixed with '0x'. If it's smaller
* than the expected size, the value will be zero filled at the end of the data
* sequence.
*
+ * B64_DATA is an arbitrarily long base64 encoded string.
+ * If the sizes do not match, the data will be truncated.
+ *
* IRQ management:
*
* > irq_intercept_in QOM-PATH
@@ -182,6 +191,21 @@ static void qtest_send_prefix(CharDriverState *chr)
(long) tv.tv_sec, (long) tv.tv_usec);
}
+static void GCC_FMT_ATTR(1, 2) qtest_log_send(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!qtest_log_fp || !qtest_opened) {
+ return;
+ }
+
+ qtest_send_prefix(NULL);
+
+ va_start(ap, fmt);
+ vfprintf(qtest_log_fp, fmt, ap);
+ va_end(ap);
+}
+
static void do_qtest_send(CharDriverState *chr, const char *str, size_t len)
{
qemu_chr_fe_write_all(chr, (uint8_t *)str, len);
@@ -403,6 +427,23 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
qtest_send(chr, "\n");
g_free(data);
+ } else if (strcmp(words[0], "b64read") == 0) {
+ uint64_t addr, len;
+ uint8_t *data;
+ gchar *b64_data;
+
+ g_assert(words[1] && words[2]);
+ addr = strtoull(words[1], NULL, 0);
+ len = strtoull(words[2], NULL, 0);
+
+ data = g_malloc(len);
+ cpu_physical_memory_read(addr, data, len);
+ b64_data = g_base64_encode(data, len);
+ qtest_send_prefix(chr);
+ qtest_sendf(chr, "OK %s\n", b64_data);
+
+ g_free(data);
+ g_free(b64_data);
} else if (strcmp(words[0], "write") == 0) {
uint64_t addr, len, i;
uint8_t *data;
@@ -432,6 +473,34 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
+ } else if (strcmp(words[0], "b64write") == 0) {
+ uint64_t addr, len;
+ uint8_t *data;
+ size_t data_len;
+ gsize out_len;
+
+ g_assert(words[1] && words[2] && words[3]);
+ addr = strtoull(words[1], NULL, 0);
+ len = strtoull(words[2], NULL, 0);
+
+ data_len = strlen(words[3]);
+ if (data_len < 3) {
+ qtest_send(chr, "ERR invalid argument size\n");
+ return;
+ }
+
+ data = g_base64_decode_inplace(words[3], &out_len);
+ if (out_len != len) {
+ qtest_log_send("b64write: data length mismatch (told %"PRIu64", "
+ "found %zu)\n",
+ len, out_len);
+ out_len = MIN(out_len, len);
+ }
+
+ cpu_physical_memory_write(addr, data, out_len);
+
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK\n");
} else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
int64_t ns;
diff --git a/tests/libqtest.c b/tests/libqtest.c
index a525dc532c..5f57005447 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -695,6 +695,37 @@ void qtest_add_data_func(const char *str, const void *data, void (*fn))
g_free(path);
}
+void qtest_bufwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
+{
+ gchar *bdata;
+
+ bdata = g_base64_encode(data, size);
+ qtest_sendf(s, "b64write 0x%" PRIx64 " 0x%zx ", addr, size);
+ socket_send(s->fd, bdata, strlen(bdata));
+ socket_send(s->fd, "\n", 1);
+ qtest_rsp(s, 0);
+ g_free(bdata);
+}
+
+void qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size)
+{
+ gchar **args;
+ size_t len;
+
+ qtest_sendf(s, "b64read 0x%" PRIx64 " 0x%zx\n", addr, size);
+ args = qtest_rsp(s, 2);
+
+ g_base64_decode_inplace(args[1], &len);
+ if (size != len) {
+ fprintf(stderr, "bufread: asked for %zu bytes but decoded %zu\n",
+ size, len);
+ len = MIN(len, size);
+ }
+
+ memcpy(data, args[1], len);
+ g_strfreev(args);
+}
+
void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
{
const uint8_t *ptr = data;
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 4b54b5da9e..ec42031523 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -301,6 +301,17 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr);
void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
/**
+ * qtest_bufread:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer and receive using a base64 encoding.
+ */
+void qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size);
+
+/**
* qtest_memwrite:
* @s: #QTestState instance to operate on.
* @addr: Guest address to write to.
@@ -312,6 +323,18 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size);
/**
+ * qtest_bufwrite:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory and transmit using a base64 encoding.
+ */
+void qtest_bufwrite(QTestState *s, uint64_t addr,
+ const void *data, size_t size);
+
+/**
* qtest_memset:
* @s: #QTestState instance to operate on.
* @addr: Guest address to write to.
@@ -699,6 +722,19 @@ static inline void memread(uint64_t addr, void *data, size_t size)
}
/**
+ * bufread:
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer, receive using a base64 encoding.
+ */
+static inline void bufread(uint64_t addr, void *data, size_t size)
+{
+ qtest_bufread(global_qtest, addr, data, size);
+}
+
+/**
* memwrite:
* @addr: Guest address to write to.
* @data: Pointer to the bytes that will be written to guest memory.
@@ -712,6 +748,19 @@ static inline void memwrite(uint64_t addr, const void *data, size_t size)
}
/**
+ * bufwrite:
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory, transmit using a base64 encoding.
+ */
+static inline void bufwrite(uint64_t addr, const void *data, size_t size)
+{
+ qtest_bufwrite(global_qtest, addr, data, size);
+}
+
+/**
* qmemset:
* @addr: Guest address to write to.
* @patt: Byte pattern to fill the guest memory region with.