[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v2 6/9] gcov: userspace tools to extract and split gcov data



Provide two tools: a small C program to extract data from hypervisor and
a python script to split data into multiple files.

The file xencov.c is salvaged and modified from the original xencov.c.

Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx>
---
v2: fix INSTALL_BIN typo

Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
---
 tools/misc/Makefile     |   6 ++
 tools/misc/xencov.c     | 148 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/misc/xencov_split | 100 ++++++++++++++++++++++++++++++++
 3 files changed, 254 insertions(+)
 create mode 100644 tools/misc/xencov.c
 create mode 100755 tools/misc/xencov_split

diff --git a/tools/misc/Makefile b/tools/misc/Makefile
index 5ba6672..8152f7b 100644
--- a/tools/misc/Makefile
+++ b/tools/misc/Makefile
@@ -13,6 +13,7 @@ CFLAGS += $(CFLAGS_libxenstore)
 INSTALL_BIN-$(CONFIG_X86)      += xen-cpuid
 INSTALL_BIN-$(CONFIG_X86)      += xen-detect
 INSTALL_BIN                    += xencons
+INSTALL_BIN                    += xencov_split
 INSTALL_BIN += $(INSTALL_BIN-y)
 
 # Everything to be installed in regular sbin/
@@ -24,6 +25,7 @@ INSTALL_SBIN-$(CONFIG_X86)     += xen-lowmemd
 INSTALL_SBIN-$(CONFIG_X86)     += xen-mfndump
 INSTALL_SBIN                   += xen-ringwatch
 INSTALL_SBIN                   += xen-tmem-list-parse
+INSTALL_SBIN                   += xencov
 INSTALL_SBIN                   += xenlockprof
 INSTALL_SBIN                   += xenperf
 INSTALL_SBIN                   += xenpm
@@ -41,6 +43,7 @@ TARGETS_ALL := $(INSTALL_BIN) $(INSTALL_SBIN) 
$(INSTALL_PRIVBIN)
 TARGETS_COPY += xen-bugtool
 TARGETS_COPY += xen-ringwatch
 TARGETS_COPY += xencons
+TARGETS_COPY += xencov_split
 TARGETS_COPY += xenpvnetboot
 
 # Everything which needs to be built
@@ -102,4 +105,7 @@ xen-livepatch: xen-livepatch.o
 xen-lowmemd: xen-lowmemd.o
        $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenevtchn) $(LDLIBS_libxenctrl) 
$(LDLIBS_libxenstore) $(APPEND_LDFLAGS)
 
+xencov: xencov.o
+       $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS)
+
 -include $(DEPS)
diff --git a/tools/misc/xencov.c b/tools/misc/xencov.c
new file mode 100644
index 0000000..d83bc66
--- /dev/null
+++ b/tools/misc/xencov.c
@@ -0,0 +1,148 @@
+/*
+ * xencov: extract test coverage information from Xen.
+ *
+ * Copyright (c) 2013, 2016, Citrix Systems R&D Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <xenctrl.h>
+
+static xc_interface *xch = NULL;
+
+int gcov_sysctl(int op, struct xen_sysctl *sysctl,
+                struct xc_hypercall_buffer *buf, uint32_t buf_size)
+{
+    DECLARE_HYPERCALL_BUFFER_ARGUMENT(buf);
+
+    memset(sysctl, 0, sizeof(*sysctl));
+    sysctl->cmd = XEN_SYSCTL_gcov_op;
+
+    sysctl->u.gcov_op.cmd = op;
+    sysctl->u.gcov_op.size = buf_size;
+    set_xen_guest_handle(sysctl->u.gcov_op.buffer, buf);
+
+    return xc_sysctl(xch, sysctl);
+}
+
+static void gcov_read(const char *fn)
+{
+    struct xen_sysctl sys;
+    uint32_t total_len;
+    DECLARE_HYPERCALL_BUFFER(uint8_t, p);
+    FILE *f;
+
+    if (gcov_sysctl(XEN_SYSCTL_GCOV_get_size, &sys, NULL, 0) < 0)
+        err(1, "getting total length");
+    total_len = sys.u.gcov_op.size;
+
+    /* Shouldn't exceed a few hundred kilobytes */
+    if (total_len > 8u * 1024u * 1024u)
+        errx(1, "gcov data too big %u bytes\n", total_len);
+
+    p = xc_hypercall_buffer_alloc(xch, p, total_len);
+    if (!p)
+        err(1, "allocating buffer");
+
+    memset(p, 0, total_len);
+    if (gcov_sysctl(XEN_SYSCTL_GCOV_read, &sys, HYPERCALL_BUFFER(p),
+                    total_len) < 0)
+        err(1, "getting gcov data");
+
+    if (!strcmp(fn, "-"))
+        f = stdout;
+    else
+        f = fopen(fn, "w");
+
+    if (!f)
+        err(1, "opening output file");
+
+    if (fwrite(p, 1, total_len, f) != total_len)
+        err(1, "writing gcov data to file");
+
+    if (f != stdout)
+        fclose(f);
+
+    xc_hypercall_buffer_free(xch, p);
+}
+
+static void gcov_reset(void)
+{
+    struct xen_sysctl sys;
+
+    if (gcov_sysctl(XEN_SYSCTL_GCOV_reset, &sys, NULL, 0) < 0)
+        err(1, "resetting gcov information");
+}
+
+static void usage(int exit_code)
+{
+    FILE *out = exit_code ? stderr : stdout;
+
+    fprintf(out, "xencov {reset|read} [<filename>]\n"
+        "\treset       reset information\n"
+        "\tread        read information from xen to filename\n"
+        "\tfilename    optional filename (default output)\n"
+        );
+    exit(exit_code);
+}
+
+int main(int argc, char **argv)
+{
+    int opt;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            usage(0);
+            break;
+        default:
+            usage(1);
+        }
+    }
+
+    argv += optind;
+    argc -= optind;
+    if (argc <= 0)
+        usage(1);
+
+    xch = xc_interface_open(NULL, NULL, 0);
+    if (!xch)
+        err(1, "opening xc interface");
+
+    if (strcmp(argv[0], "reset") == 0)
+        gcov_reset();
+    else if ( strcmp(argv[0], "read") == 0 )
+        gcov_read(argc > 1 ? argv[1] : "-");
+    else
+        usage(1);
+
+    xc_interface_close(xch);
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/misc/xencov_split b/tools/misc/xencov_split
new file mode 100755
index 0000000..2c06f49
--- /dev/null
+++ b/tools/misc/xencov_split
@@ -0,0 +1,100 @@
+#!/usr/bin/python
+
+import sys, os, os.path as path, struct, errno
+from optparse import OptionParser
+
+def xencov_split(opts):
+    """Split input into multiple gcda files"""
+
+    # Check native byte order and explicitly specify it.  The "native"
+    # byte order in struct module takes into account padding while the
+    # data is always packed.
+    if sys.byteorder == 'little':
+        bo_prefix = '<'
+    else:
+        bo_prefix = '>'
+
+    input_file = opts.args[0]
+
+    f = open(input_file)
+
+    # Magic number
+    s = f.read(4)
+    magic, = struct.unpack(bo_prefix + "I", s)
+    # See public/sysctl.h for magic number -- "XCOV"
+    if magic != 0x58434f56:
+        raise Exception("Invalid magic number")
+
+    # The rest is zero or more records
+    content = f.read()
+
+    f.close()
+
+    while content:
+        off = content.find('\x00')
+        fmt = bo_prefix + str(off) + 's'
+        fn, = struct.unpack_from(fmt, content)
+        content = content[off+1:]
+
+        fmt = bo_prefix + 'I'
+        sz, = struct.unpack_from(fmt, content)
+        content = content[struct.calcsize(fmt):]
+
+        fmt = bo_prefix + str(sz) + 's'
+        payload, = struct.unpack_from(fmt, content)
+        content = content[sz:]
+
+        # Create and store files
+        if opts.output_dir == '.':
+            opts.output_dir = os.getcwd()
+
+        dir = opts.output_dir + path.dirname(fn)
+        try:
+            os.makedirs(dir)
+        except OSError, e:
+            if e.errno == errno.EEXIST and os.path.isdir(dir):
+                pass
+            else:
+                raise
+
+        full_path = dir + '/' + path.basename(fn)
+        f = open(full_path, "w")
+        f.write(payload)
+        f.close()
+
+def main():
+    """ Main entrypoint """
+
+    # Change stdout to be line-buffered.
+    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)
+
+    # Normalise $CWD to the directory this script is in
+    # os.chdir(path.dirname(path.abspath(sys.argv[0])))
+
+    parser = OptionParser(
+        usage = "%prog [OPTIONS] <INPUT>",
+        description = "Utility to split xencov data file",
+        )
+
+    parser.add_option("--output-dir", action = "store",
+                      dest = "output_dir", default = ".",
+                      type = "string",
+                      help = ('Specify the directory to place output files, '
+                              'defaults to current directory'),
+                      )
+
+    opts, args = parser.parse_args()
+    opts.args = args
+
+    xencov_split(opts)
+
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except Exception, e:
+        print >>sys.stderr, "Error:", e
+        sys.exit(1)
+    except KeyboardInterrupt:
+        sys.exit(1)
+
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.