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

[Xen-devel] [PATCH 3/4] Implement code to read coverage informations



Operations are handled by a sysctl specific operation.

Implement 4 operations
- check if coverage is compiled in
- read size of coverage information
- read coverage information
- reset coverage counters

Information are stored in a single blob in a format specific to Xen designed
to make code that generate coverage as small as possible.

This patch add a public header with the structure of blob exported by Xen.
This avoid problems distributing header which is GPL2.

Signed-off-by: Frediano Ziglio <frediano.ziglio@xxxxxxxxxx>
---
 xen/common/gcov/gcov.c      |  158 ++++++++++++++++++++++++++++++++++++++++++-
 xen/common/sysctl.c         |    5 ++
 xen/include/public/gcov.h   |  115 +++++++++++++++++++++++++++++++
 xen/include/public/sysctl.h |   38 +++++++++++
 xen/include/xen/gcov.h      |   14 ++++
 5 files changed, 328 insertions(+), 2 deletions(-)
 create mode 100644 xen/include/public/gcov.h

diff --git a/xen/common/gcov/gcov.c b/xen/common/gcov/gcov.c
index 733d020..bb85523 100644
--- a/xen/common/gcov/gcov.c
+++ b/xen/common/gcov/gcov.c
@@ -19,9 +19,11 @@
 #include <xen/hypercall.h>
 #include <xen/gcov.h>
 #include <xen/errno.h>
+#include <xen/guest_access.h>
+#include <public/xen.h>
+#include <public/gcov.h>
 
 static struct gcov_info *info_list;
-static unsigned num_info = 0;
 
 /*
  * __gcov_init is called by gcc-generated constructor code for each object
@@ -36,7 +38,6 @@ void __gcov_init(struct gcov_info *info)
     /* add new profiling data structure to list */
     info->next = info_list;
     info_list = info;
-    ++num_info;
 }
 
 /*
@@ -63,6 +64,159 @@ void __gcov_merge_delta(gcov_type *counters, unsigned int 
n_counters)
     /* Unused. */
 }
 
+static inline int counter_active(const struct gcov_info *info, unsigned int 
type)
+{
+    return (1 << type) & info->ctr_mask;
+}
+
+typedef struct write_iter_t
+{
+    XEN_GUEST_HANDLE(uint8) ptr;
+    int real;
+    uint32_t write_offset;
+} write_iter_t;
+
+static int write_raw(struct write_iter_t *iter, const void *data,
+                     size_t data_len)
+{
+    if ( iter->real &&
+        copy_to_guest_offset(iter->ptr, iter->write_offset,
+                             (const unsigned char *) data, data_len) )
+        return -EFAULT;
+
+    iter->write_offset += data_len;
+    return 0;
+}
+
+#define chk(v) do { ret=(v); if ( ret ) return ret; } while(0)
+
+static inline int write32(write_iter_t *iter, uint32_t val)
+{
+    return write_raw(iter, &val, sizeof(val));
+}
+
+static int write_string(write_iter_t *iter, const char *s)
+{
+    int ret;
+    size_t len = strlen(s);
+
+    chk(write32(iter, len));
+    return write_raw(iter, s, len);
+}
+
+static inline int next_type(const struct gcov_info *info, int *type)
+{
+    while ( ++*type < XENCOV_COUNTERS && !counter_active(info, *type) )
+        continue;
+    return *type;
+}
+
+static inline void align_iter(write_iter_t *iter)
+{
+    iter->write_offset =
+        (iter->write_offset + sizeof(uint64_t) - 1) & -sizeof(uint64_t);
+}
+
+static int write_gcov(write_iter_t *iter)
+{
+    struct gcov_info *info;
+    int ret;
+
+    /* reset offset */
+    iter->write_offset = 0;
+
+    /* dump all files */
+    for ( info = info_list ; info; info = info->next )
+    {
+        const struct gcov_ctr_info *ctr;
+        int type;
+        size_t size_fn = sizeof(struct gcov_fn_info);
+
+        align_iter(iter);
+        chk(write32(iter, XENCOV_TAG_FILE));
+        chk(write32(iter, info->version));
+        chk(write32(iter, info->stamp));
+        chk(write_string(iter, info->filename));
+
+        /* dump counters */
+        ctr = info->counts;
+        for ( type = -1; next_type(info, &type) < XENCOV_COUNTERS; ++ctr )
+        {
+            align_iter(iter);
+            chk(write32(iter, XENCOV_TAG_COUNTER(type)));
+            chk(write32(iter, ctr->num));
+            chk(write_raw(iter, ctr->values,
+                          ctr->num * sizeof(ctr->values[0])));
+
+            size_fn += sizeof(unsigned);
+        }
+
+        /* dump all functions together */
+        align_iter(iter);
+        chk(write32(iter, XENCOV_TAG_FUNC));
+        chk(write32(iter, info->n_functions));
+        chk(write_raw(iter, info->functions, info->n_functions * size_fn));
+    }
+
+    /* stop tag */
+    align_iter(iter);
+    chk(write32(iter, XENCOV_TAG_END));
+    return 0;
+}
+
+static int reset_counters(void)
+{
+    struct gcov_info *info;
+
+    for ( info = info_list ; info; info = info->next )
+    {
+        const struct gcov_ctr_info *ctr;
+        int type;
+
+        /* reset counters */
+        ctr = info->counts;
+        for ( type = -1; next_type(info, &type) < XENCOV_COUNTERS; ++ctr )
+            memset(ctr->values, 0, ctr->num * sizeof(ctr->values[0]));
+    }
+
+    return 0;
+}
+
+int sysctl_coverage_op(xen_sysctl_coverage_op_t *op)
+{
+    long ret = 0;
+    write_iter_t iter;
+
+    switch ( op->cmd )
+    {
+    case XEN_SYSCTL_COVERAGE_enabled:
+        break;
+
+    case XEN_SYSCTL_COVERAGE_get_total_size:
+        iter.real = 0;
+
+        write_gcov(&iter);
+        if ( copy_to_guest(op->u.total_size, &iter.write_offset, 1) )
+            ret = -EFAULT;
+        break;
+
+    case XEN_SYSCTL_COVERAGE_read:
+        iter.ptr = op->u.raw_info;
+        iter.real = 1;
+
+        ret = write_gcov(&iter);
+        break;
+
+    case XEN_SYSCTL_COVERAGE_reset:
+        ret = reset_counters();
+        break;
+
+    default:
+        ret = -EINVAL;
+    }
+    return ret;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c
index d663ed7..fa3ef0a 100644
--- a/xen/common/sysctl.c
+++ b/xen/common/sysctl.c
@@ -26,6 +26,7 @@
 #include <xen/nodemask.h>
 #include <xsm/xsm.h>
 #include <xen/pmstat.h>
+#include <xen/gcov.h>
 
 long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl)
 {
@@ -249,6 +250,10 @@ long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) 
u_sysctl)
         ret = sched_adjust_global(&op->u.scheduler_op);
         break;
 
+    case XEN_SYSCTL_coverage_op:
+        ret = sysctl_coverage_op(&op->u.coverage_op);
+        break;
+
     default:
         ret = arch_do_sysctl(op, u_sysctl);
         copyback = 0;
diff --git a/xen/include/public/gcov.h b/xen/include/public/gcov.h
new file mode 100644
index 0000000..53a192c
--- /dev/null
+++ b/xen/include/public/gcov.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * gcov.h
+ *
+ * Coverage structures exported by Xen.
+ * Structure is different from Gcc one.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2013, Frediano Ziglio
+ */
+
+#ifndef __XEN_PUBLIC_GCOV_H__
+#define __XEN_PUBLIC_GCOV_H__ __XEN_PUBLIC_GCOV_H__
+
+#define XENCOV_COUNTERS         5
+#define XENCOV_TAG_BASE         0x58544300u
+#define XENCOV_TAG_FILE         (XENCOV_TAG_BASE+0x46u)
+#define XENCOV_TAG_FUNC         (XENCOV_TAG_BASE+0x66u)
+#define XENCOV_TAG_COUNTER(n)   (XENCOV_TAG_BASE+0x30u+((n)&0xfu))
+#define XENCOV_TAG_END          (XENCOV_TAG_BASE+0x2eu)
+#define XENCOV_IS_TAG_COUNTER(n) \
+    ((n) >= XENCOV_TAG_COUNTER(0) && (n) < XENCOV_TAG_COUNTER(XENCOV_COUNTERS))
+#define XENCOV_COUNTER_NUM(n) ((n)-XENCOV_TAG_COUNTER(0))
+
+/*
+ * The main structure for the blob is
+ * BLOB := FILE.. END
+ * FILE := TAG_FILE VERSION STAMP FILENAME COUNTERS FUNCTIONS
+ * FILENAME := LEN characters
+ *   characters are padded to 32 bit
+ * LEN := 32 bit value
+ * COUNTERS := TAG_COUNTER(n) NUM COUNTER..
+ * NUM := 32 bit valie
+ * COUNTER := 64 bit value
+ * FUNCTIONS := TAG_FUNC NUM FUNCTION..
+ * FUNCTION := IDENT CHECKSUM NUM_COUNTERS
+ *
+ * All tagged structures are aligned to 8 bytes
+ */
+
+/**
+ * File information
+ * Prefixed with XENCOV_TAG_FILE and a string with filename
+ * Aligned to 8 bytes
+ */
+struct xencov_file
+{
+    uint32_t tag; /* XENCOV_TAG_FILE */
+    uint32_t version;
+    uint32_t stamp;
+    uint32_t fn_len;
+    char filename[1];
+};
+
+
+/**
+ * Counters information
+ * Prefixed with XENCOV_TAG_COUNTER(n) where n is 0..(XENCOV_COUNTERS-1)
+ * Aligned to 8 bytes
+ */
+struct xencov_counter
+{
+    uint32_t tag; /* XENCOV_TAG_COUNTER(n) */
+    uint32_t num;
+    uint64_t values[1];
+};
+
+/**
+ * Information for each function
+ * Number of counter is equal to the number of counter structures got before
+ */
+struct xencov_function
+{
+    uint32_t ident;
+    uint32_t checksum;
+    uint32_t num_counters[1];
+};
+
+/**
+ * Information for all functions
+ * Aligned to 8 bytes
+ */
+struct xencov_functions
+{
+    uint32_t tag; /* XENCOV_TAG_FUNC */
+    uint32_t num;
+    struct xencov_function xencov_function[1];
+};
+
+/**
+ * Terminator
+ */
+struct xencov_end
+{
+    uint32_t tag; /* XENCOV_TAG_END */
+};
+
+#endif /* __XEN_PUBLIC_GCOV_H__ */
+
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index 3225b2a..5e80400 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -596,6 +596,42 @@ struct xen_sysctl_scheduler_op {
 typedef struct xen_sysctl_scheduler_op xen_sysctl_scheduler_op_t;
 DEFINE_XEN_GUEST_HANDLE(xen_sysctl_scheduler_op_t);
 
+/* XEN_SYSCTL_coverage_op */
+/*
+ * Check if coverage informations are available
+ * return just success or error, no parameters
+ */
+#define XEN_SYSCTL_COVERAGE_enabled        0
+
+/*
+ * Get total size of information, to help allocate
+ * the buffer. The pointer points to a 32 bit value.
+ */
+#define XEN_SYSCTL_COVERAGE_get_total_size 1
+
+/*
+ * Read coverage information in a single run
+ * You must use a tool to split them
+ */
+#define XEN_SYSCTL_COVERAGE_read           2
+
+/*
+ * Reset all the coverage counters to 0
+ * No parameters.
+ */
+#define XEN_SYSCTL_COVERAGE_reset          3
+
+struct xen_sysctl_coverage_op {
+    uint32_t cmd;        /* XEN_SYSCTL_COVERAGE_* */
+    union {
+        XEN_GUEST_HANDLE_64(uint32) total_size; /* OUT */
+        XEN_GUEST_HANDLE_64(uint8)  raw_info;   /* OUT */
+    } u;
+};
+typedef struct xen_sysctl_coverage_op xen_sysctl_coverage_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_sysctl_coverage_op_t);
+
+
 struct xen_sysctl {
     uint32_t cmd;
 #define XEN_SYSCTL_readconsole                    1
@@ -616,6 +652,7 @@ struct xen_sysctl {
 #define XEN_SYSCTL_numainfo                      17
 #define XEN_SYSCTL_cpupool_op                    18
 #define XEN_SYSCTL_scheduler_op                  19
+#define XEN_SYSCTL_coverage_op                   20
     uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
     union {
         struct xen_sysctl_readconsole       readconsole;
@@ -636,6 +673,7 @@ struct xen_sysctl {
         struct xen_sysctl_lockprof_op       lockprof_op;
         struct xen_sysctl_cpupool_op        cpupool_op;
         struct xen_sysctl_scheduler_op      scheduler_op;
+        struct xen_sysctl_coverage_op       coverage_op;
         uint8_t                             pad[128];
     } u;
 };
diff --git a/xen/include/xen/gcov.h b/xen/include/xen/gcov.h
index d695919..ad5cd9d 100644
--- a/xen/include/xen/gcov.h
+++ b/xen/include/xen/gcov.h
@@ -14,6 +14,8 @@
 #ifndef __XEN_GCOV_H__
 #define __XEN_GCOV_H__ __XEN_GCOV_H__
 
+#include <public/sysctl.h>
+
 /*
  * Profiling data types used for gcc 3.4 and above - these are defined by
  * gcc and need to be kept as close to the original definition as possible to
@@ -81,4 +83,16 @@ struct gcov_info
 };
 
 
+/**
+ * Sysctl operations for coverage
+ */
+#ifdef TEST_COVERAGE
+int sysctl_coverage_op(xen_sysctl_coverage_op_t *op);
+#else
+static inline int sysctl_coverage_op(xen_sysctl_coverage_op_t *op)
+{
+    return -ENOSYS;
+}
+#endif
+
 #endif /* __XEN_GCOV_H__ */
-- 
1.7.9.5


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


 


Rackspace

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