[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH 06/16] Visitor: Debug output visitor
From: |
Dr. David Alan Gilbert (git) |
Subject: |
[Qemu-devel] [RFC PATCH 06/16] Visitor: Debug output visitor |
Date: |
Tue, 25 Mar 2014 20:17:17 +0000 |
From: "Dr. David Alan Gilbert" <address@hidden>
A migration visitor whose output is textual and purely for human
consumption for debug.
Signed-off-by: Dr. David Alan Gilbert <address@hidden>
---
include/qapi/qemu-file-debug-output-visitor.h | 26 ++
qapi/Makefile.objs | 1 +
qapi/qemu-file-debug-output-visitor.c | 471 ++++++++++++++++++++++++++
3 files changed, 498 insertions(+)
create mode 100644 include/qapi/qemu-file-debug-output-visitor.h
create mode 100644 qapi/qemu-file-debug-output-visitor.c
diff --git a/include/qapi/qemu-file-debug-output-visitor.h
b/include/qapi/qemu-file-debug-output-visitor.h
new file mode 100644
index 0000000..427d5b2
--- /dev/null
+++ b/include/qapi/qemu-file-debug-output-visitor.h
@@ -0,0 +1,26 @@
+/*
+ * QEMUFile Visitor
+ *
+ * Copyright Red Hat, Corp. 2014
+ *
+ * Authors:
+ * David Gilbert <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_FILE_DEBUG_OUTPUT_VISITOR_H
+#define QEMU_FILE_DEBUG_OUTPUT_VISITOR_H
+
+#include "visitor.h"
+
+typedef struct QemuFileDebugOutputVisitor QemuFileDebugOutputVisitor;
+
+QemuFileDebugOutputVisitor *qemu_file_debug_output_visitor_new(QEMUFile *f);
+void qemu_file_debug_output_visitor_cleanup(QemuFileDebugOutputVisitor *d);
+
+Visitor *qemu_file_debug_output_get_visitor(QemuFileDebugOutputVisitor *v);
+
+#endif
diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs
index a054d52..06c69e6 100644
--- a/qapi/Makefile.objs
+++ b/qapi/Makefile.objs
@@ -2,4 +2,5 @@ util-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o
qmp-input-visitor.o
util-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
util-obj-y += string-input-visitor.o string-output-visitor.o
util-obj-y += qemu-file-binary-output-visitor.o
+util-obj-y += qemu-file-debug-output-visitor.o
util-obj-y += opts-visitor.o
diff --git a/qapi/qemu-file-debug-output-visitor.c
b/qapi/qemu-file-debug-output-visitor.c
new file mode 100644
index 0000000..8694212
--- /dev/null
+++ b/qapi/qemu-file-debug-output-visitor.c
@@ -0,0 +1,471 @@
+/*
+ * QEMUFile Output Visitor
+ *
+ * Copyright Red Hat, 2014
+ *
+ * Authors:
+ * David Gilbert <address@hidden>
+ *
+ * Based on the binary file output visitor
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ * Produce a textual output designed purely for ease of reading
+ */
+
+#include "qapi/qemu-file-binary-output-visitor.h"
+#include "qapi/qemu-file-debug-output-visitor.h"
+#include "qapi/visitor-impl.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/queue.h"
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "migration/migration.h"
+
+struct QemuFileDebugOutputVisitor {
+ Visitor visitor;
+ int depth;
+ QEMUFile *file;
+
+ bool in_binwrapper; /* When true we're in a compat wrapper where everything
+ should be going through the QEMUFile we provide it
*/
+ QEMUFile *binfile; /* Passed to the caller in a compat wrapper */
+};
+
+static void qemufile_printf(QEMUFile *qf, int depth, const char *fmt, ...)
+{
+ char *tmp;
+ va_list va;
+ va_start(va, fmt);
+ assert(vasprintf(&tmp, fmt, va) != -1);
+ va_end(va);
+
+ while (depth--) {
+ qemu_put_buffer(qf, (uint8_t *)" ", 2);
+ }
+
+ qemu_put_buffer(qf, (uint8_t *)tmp, strlen(tmp));
+ qemu_fflush(qf);
+ free(tmp);
+}
+
+#define DPRINTF(fmt, ...) \
+ qemufile_printf(ov->file, ov->depth*2, fmt, __VA_ARGS__)
+
+/*
+ * TDO: This should be shared somewhere, util/hexdump.c has one to output to
+ * FILE*, and util/iov.c uses that to output an iov to FILE*, neither includes
+ * the printables.
+ */
+/* We print the iov upto 'len' bytes because the iov is allocated in chunks */
+static void hexdump_to_qemufile(QEMUFile *qf, size_t len, size_t n_iov,
+ struct iovec *iov, int depth)
+{
+ const unsigned int bytes_per_line = 16;
+ /*
+ * Of the form: 41 42 43 44 45 46 47 48 ABCDEFGH\0
+ * 3 byte> < 1 byte> <
+ */
+ const unsigned int line_buf_len = (bytes_per_line * (3+1)) + 2;
+ char linebuf[line_buf_len];
+ size_t cur_iov, cur_offset;
+ unsigned int line_index = 0;
+
+ memset(linebuf, ' ', bytes_per_line * (3+1)+2);
+ linebuf[line_buf_len-1] = '\0';
+
+ for (cur_iov = 0; len && (cur_iov < n_iov); cur_iov++) {
+ for (cur_offset = 0;
+ len && (cur_offset < iov[cur_iov].iov_len);
+ cur_offset++, len--) {
+ uint8_t cur_byte = ((uint8_t *)iov[cur_iov].iov_base)[cur_offset];
+ const char *hexstring = "0123456789abcdef";
+
+ linebuf[line_index*3] = hexstring[(cur_byte >> 4) & 0xf];
+ linebuf[line_index*3+1] = hexstring[cur_byte & 0xf];
+ linebuf[bytes_per_line*3+1+line_index] =
+ isprint(cur_byte) ? cur_byte : '.';
+ line_index++;
+
+ if (line_index == bytes_per_line) {
+ qemufile_printf(qf, depth, "%s\n", linebuf);
+ line_index = 0;
+ }
+ }
+ }
+ if (line_index) {
+ /* Still some bytes left */
+ if (line_index != bytes_per_line) {
+ memset(linebuf + line_index*3, '#', 3*(bytes_per_line-line_index));
+ memset(linebuf + bytes_per_line*3+1+line_index, '#',
+ bytes_per_line-line_index);
+ qemufile_printf(qf, depth, "%s\n", linebuf);
+ }
+ }
+}
+
+static QemuFileDebugOutputVisitor *to_ov(Visitor *v)
+{
+ return container_of(v, QemuFileDebugOutputVisitor, visitor);
+}
+
+static void qfdo_push(QemuFileDebugOutputVisitor *ov)
+{
+ ov->depth++;
+}
+
+static void qfdo_pop(QemuFileDebugOutputVisitor *ov)
+{
+ ov->depth--;
+ assert(ov >= 0);
+ return;
+}
+
+static void qfdo_start_struct(Visitor *v, void **obj, const char *kind,
+ const char *name, size_t unused,
+ Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+
+ DPRINTF("<struct '%s' of '%s'\n", name, kind);
+ qfdo_push(ov);
+}
+
+static void qfdo_end_struct(Visitor *v, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+
+ qfdo_pop(ov);
+ DPRINTF("struct %s>\n", "");
+}
+
+static void qfdo_start_list(Visitor *v, const char *name,
+ Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("<list '%s'\n", name);
+ qfdo_push(ov);
+}
+
+static GenericList *qfdo_next_list(Visitor *v, GenericList **list,
+ Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+
+ DPRINTF("|list %s\n", "");
+
+ return NULL; /* Not generally valid! */
+}
+
+static void qfdo_end_list(Visitor *v, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+
+ qfdo_pop(ov);
+ DPRINTF("list %s>\n", "");
+}
+
+static void qfdo_start_array(Visitor *v, void **obj,
+ const char *name,
+ size_t elem_count,
+ size_t elem_size, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("<array '%s' [%zd] of %zd\n", name, elem_count, elem_size);
+
+ qfdo_push(ov);
+}
+
+static void qfdo_next_array(Visitor *v, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("|array %s\n", "");
+}
+
+static void qfdo_end_array(Visitor *v, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ qfdo_pop(ov);
+
+ DPRINTF("array %s>\n", "");
+}
+
+static void qfdo_type_str(Visitor *v, char **obj, const char *name,
+ Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+
+ DPRINTF("string: '%s'=%s\n", name, *obj);
+}
+
+/* A string upto 256 bytes in length (including terminator)
+ * output as length byte (not including term) followed by text
+ * (also not including term)
+ */
+static void qfdo_type_str256(Visitor *v, char *obj, const char *name,
+ Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+
+ DPRINTF("str256: '%s'=%s\n", name, obj);
+}
+
+static void qfdo_type_buffer(Visitor *v, void *data, size_t len, bool async,
+ const char *name, Error **errp)
+{
+ struct iovec tmpiov;
+ tmpiov.iov_base = data;
+ tmpiov.iov_len = len;
+
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("Buffer of '%s' len=%zd async=%d\n", name, len, async);
+ hexdump_to_qemufile(ov->file, len, 1, &tmpiov, ov->depth * 2);
+}
+
+static void qfdo_type_uint8(Visitor *v, uint8_t *obj,
+ const char *name, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("uint8_t %s: 0x%2x\n", name, *obj);
+}
+
+static void qfdo_type_uint16(Visitor *v, uint16_t *obj,
+ const char *name, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("uint16_t %s: 0x%4x\n", name, *obj);
+}
+
+static void qfdo_type_uint32(Visitor *v, uint32_t *obj,
+ const char *name, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("uint32_t %s: 0x%8x\n", name, *obj);
+}
+
+static void qfdo_type_uint64(Visitor *v, uint64_t *obj,
+ const char *name, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("uint64_t %s: 0x%16lx\n", name, *obj);
+}
+
+static void qfdo_type_int8(Visitor *v, int8_t *obj,
+ const char *name, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("int8_t %s: 0x%2x\n", name, *obj);
+}
+
+static void qfdo_type_int16(Visitor *v, int16_t *obj,
+ const char *name, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("int16_t %s: 0x%4x\n", name, *obj);
+}
+
+static void qfdo_type_int32(Visitor *v, int32_t *obj,
+ const char *name, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("int32_t %s: 0x%8x\n", name, *obj);
+}
+
+static void qfdo_type_int64(Visitor *v, int64_t *obj,
+ const char *name, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("int64_t %s: 0x%16lx\n", name, *obj);
+}
+
+static void qfdo_type_bool(Visitor *v, bool *obj, const char *name,
+ Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ DPRINTF("bool %s: %d\n", name, *obj);
+}
+
+static QEMUFile *qfdo_get_qemufile(Visitor *v)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+
+ return ov->file;
+}
+
+static void qfdo_get_next_type(Visitor *v, int *kind, const int *qobjects,
+ const char *name, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+
+ DPRINTF("|next_type %s\n", name);
+}
+
+static void qfdo_start_sequence_compat(Visitor *v, const char *name,
+ Visit_seq_compat_mode compat_mode,
+ void *opaque, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+ SectionHeader *sh;
+ ramsecentry_header *rse_hdr;
+ const char *tmps;
+
+ switch (compat_mode) {
+ case VISIT_SEQ_COMPAT_FILE:
+ DPRINTF("<SEQCOMPAT SoF: %s\n", name);
+ break;
+
+ case VISIT_SEQ_COMPAT_SECTION_HEADER:
+ /*
+ * for VM_SECTION_FULL and VM_SECTION_START
+ * 'opaque' points to a struct Sectionheader
+ */
+ sh = opaque;
+ DPRINTF("<SEQCOMPAT Section (%s): %s (%d / %d version %d)\n", name,
+ sh->idstr, sh->section_id, sh->instance_id, sh->version_id);
+ break;
+
+ case VISIT_SEQ_COMPAT_SECTION_MIN:
+ /* VM_SECTION_PART/END where the section name->ID is already known */
+ sh = opaque;
+ DPRINTF("<SEQCOMPAT Section (%s): %d\n", name, sh->section_id);
+ break;
+
+
+ case VISIT_SEQ_COMPAT_BYTE0TERM:
+ DPRINTF("<SEQCOMPAT 0 term list (%s)\n", name);
+ break;
+
+ case VISIT_SEQ_COMPAT_SUBSECLIST:
+ DPRINTF("<SEQCOMPAT Subsection list (%s)\n", name);
+ break;
+
+ case VISIT_SEQ_COMPAT_SUBSECTION:
+ DPRINTF("<SEQCOMPAT Subsection (%s)\n", name);
+ break;
+
+ case VISIT_SEQ_COMPAT_RAMSECLIST:
+ DPRINTF("<SEQCOMPAT RAMseclist (%s)\n", name);
+ break;
+
+ case VISIT_SEQ_COMPAT_VMSTATE:
+ DPRINTF("<SEQCOMPAT VMState (%s)\n", name);
+ break;
+
+ case VISIT_SEQ_COMPAT_RAMSECENTRY:
+ rse_hdr = opaque;
+ if ((rse_hdr->flags &
+ (RAM_SAVE_FLAG_CONTINUE | RAM_SAVE_FLAG_MEM_SIZE |
+ RAM_SAVE_FLAG_HOOK)) == 0) {
+ tmps = rse_hdr->idstr;
+ } else {
+ tmps = "(cont)";
+ }
+ DPRINTF("<SEQCOMPAT RAMsecentry %s for 0x%lx flags=0x%x id=%s\n",
+ name, rse_hdr->addr, rse_hdr->flags, tmps);
+ break;
+
+ case VISIT_SEQ_COMPAT_BLOB:
+ DPRINTF("<SEQCOMPAT Blob (%s)\n", name);
+
+ /* Opaque is given a QEMUFile into which it writes the binary data */
+ ov->in_binwrapper = true;
+ ov->binfile = qemu_bufopen("w", NULL);
+ /* and give that wrapper a binary output visitor so that it keeps
+ * substructures in compatibility mode
+ */
+ QemuFileBinOutputVisitor *qfbov =
+ qemu_file_bin_output_visitor_new(ov->binfile);
+ Visitor *v = qemu_file_bin_output_get_visitor(qfbov);
+ qemu_file_set_tmp_visitor(ov->binfile, v);
+
+ *(QEMUFile **)opaque = ov->binfile;
+ break;
+ }
+
+ qfdo_push(ov);
+}
+
+static void qfdo_end_sequence_compat(Visitor *v, const char *name,
+ Visit_seq_compat_mode compat_mode,
+ Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+
+ /* bin wrappers can't nest - or at least if they did they'd have a new
+ * visitor instance
+ */
+ if (ov->in_binwrapper) {
+ Error *local_err = NULL;
+ Visitor *bv = qemu_file_get_tmp_visitor(ov->binfile);
+
+ visit_destroy(bv, &local_err);
+ const QEMUSizedBuffer *qsb = qemu_buf_get(ov->binfile);
+ size_t len = qsb_get_length(qsb);
+
+ hexdump_to_qemufile(ov->file, len, qsb->n_iov, qsb->iov, ov->depth*2);
+
+ qemu_fclose(ov->binfile);
+ ov->in_binwrapper = false;
+ }
+
+ qfdo_pop(ov);
+ DPRINTF("SEQCOMPAT (%d) %s>\n", compat_mode, name);
+}
+
+static void qfdo_destroy(Visitor *v, Error **errp)
+{
+ QemuFileDebugOutputVisitor *ov = to_ov(v);
+
+ qemu_file_debug_output_visitor_cleanup(ov);
+}
+
+Visitor *qemu_file_debug_output_get_visitor(QemuFileDebugOutputVisitor *v)
+{
+ return &v->visitor;
+}
+
+void qemu_file_debug_output_visitor_cleanup(QemuFileDebugOutputVisitor *ov)
+{
+ g_free(ov);
+}
+
+QemuFileDebugOutputVisitor *qemu_file_debug_output_visitor_new(QEMUFile *f)
+{
+ QemuFileDebugOutputVisitor *v;
+
+ v = g_malloc0(sizeof(*v));
+
+ v->file = f;
+
+ v->visitor.start_struct = qfdo_start_struct;
+ v->visitor.end_struct = qfdo_end_struct;
+ v->visitor.start_list = qfdo_start_list;
+ v->visitor.next_list = qfdo_next_list;
+ v->visitor.end_list = qfdo_end_list;
+ v->visitor.start_array = qfdo_start_array;
+ v->visitor.next_array = qfdo_next_array;
+ v->visitor.end_array = qfdo_end_array;
+ v->visitor.type_buffer = qfdo_type_buffer;
+ v->visitor.type_int = qfdo_type_int64;
+ v->visitor.type_uint8 = qfdo_type_uint8;
+ v->visitor.type_uint16 = qfdo_type_uint16;
+ v->visitor.type_uint32 = qfdo_type_uint32;
+ v->visitor.type_uint64 = qfdo_type_uint64;
+ v->visitor.type_int8 = qfdo_type_int8;
+ v->visitor.type_int16 = qfdo_type_int16;
+ v->visitor.type_int32 = qfdo_type_int32;
+ v->visitor.type_int64 = qfdo_type_int64;
+ v->visitor.type_bool = qfdo_type_bool;
+ v->visitor.type_str = qfdo_type_str;
+ v->visitor.type_str256 = qfdo_type_str256;
+ v->visitor.destroy = qfdo_destroy;
+ v->visitor.start_sequence_compat = qfdo_start_sequence_compat;
+ v->visitor.get_next_type = qfdo_get_next_type;
+ v->visitor.end_sequence_compat = qfdo_end_sequence_compat;
+ v->visitor.get_qemufile = qfdo_get_qemufile;
+
+ v->visitor.flags = VISITOR_SAVING;
+
+ return v;
+}
--
1.8.5.3
- [Qemu-devel] [RFC PATCH 00/16] visitor+BER migration format, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 02/16] QEMUSizedBuffer/QEMUFile, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 05/16] Visitor: Binary compatible output visitor, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 04/16] Header/constant/types fixes for visitors, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 06/16] Visitor: Debug output visitor,
Dr. David Alan Gilbert (git) <=
- [Qemu-devel] [RFC PATCH 08/16] Visitor: Output path, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 09/16] Visitor: Load path, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 12/16] BER Visitor: Create output visitor, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 13/16] BER Visitor: Create input visitor, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 14/16] Start some BER format docs, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 15/16] ASN.1 schema for new migration format, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 01/16] Visitor: Add methods for migration format use, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 03/16] qemu-file: Add set/get tmp_visitor, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 07/16] Visitor: Binary compatible input visitor, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 10/16] Visitor: Common types to use visitors, Dr. David Alan Gilbert (git), 2014/03/25