aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrediano Ziglio <frediano.ziglio@citrix.com>2013-02-14 12:37:15 +0000
committerKeir <keir.xen@gmail.com>2013-02-21 16:23:57 +0000
commit5043f14b5e0043bb6a2c8b794adb440b8b8b3b4a (patch)
tree6effd876ab42231e2873fc66887309f9ecf78409
parent26c9d03dd4a7356ed697bec98fe8108a5eebd562 (diff)
downloadxen-5043f14b5e0043bb6a2c8b794adb440b8b8b3b4a.tar.gz
xen-5043f14b5e0043bb6a2c8b794adb440b8b8b3b4a.tar.bz2
xen-5043f14b5e0043bb6a2c8b794adb440b8b8b3b4a.zip
gcov: 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@citrix.com>
-rw-r--r--xen/common/gcov/gcov.c153
-rw-r--r--xen/common/sysctl.c6
-rw-r--r--xen/include/public/gcov.h115
-rw-r--r--xen/include/public/sysctl.h38
-rw-r--r--xen/include/xen/gcov.h9
5 files changed, 321 insertions, 0 deletions
diff --git a/xen/common/gcov/gcov.c b/xen/common/gcov/gcov.c
index 4de4b58d3d..01d5b1066e 100644
--- a/xen/common/gcov/gcov.c
+++ b/xen/common/gcov/gcov.c
@@ -19,6 +19,9 @@
#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;
@@ -61,6 +64,156 @@ 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)
+{
+ int ret = -EINVAL;
+ write_iter_t iter;
+
+ switch ( op->cmd )
+ {
+ case XEN_SYSCTL_COVERAGE_get_total_size:
+ iter.real = 0;
+
+ write_gcov(&iter);
+ op->u.total_size = iter.write_offset;
+ ret = 0;
+ break;
+
+ case XEN_SYSCTL_COVERAGE_read_and_reset:
+ case XEN_SYSCTL_COVERAGE_read:
+ iter.ptr = op->u.raw_info;
+ iter.real = 1;
+
+ ret = write_gcov(&iter);
+ if ( ret || op->cmd != XEN_SYSCTL_COVERAGE_read_and_reset )
+ break;
+
+ /* fall through */
+ case XEN_SYSCTL_COVERAGE_reset:
+ ret = reset_counters();
+ break;
+ }
+ return ret;
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c
index b8d2c736f7..31f9650ecc 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)
{
@@ -357,6 +358,11 @@ long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl)
}
break;
+#ifdef TEST_COVERAGE
+ case XEN_SYSCTL_coverage_op:
+ ret = sysctl_coverage_op(&op->u.coverage_op);
+ break;
+#endif
default:
ret = arch_do_sysctl(op, u_sysctl);
diff --git a/xen/include/public/gcov.h b/xen/include/public/gcov.h
new file mode 100644
index 0000000000..1b29b48a7a
--- /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, Citrix Systems R&D Ltd.
+ */
+
+#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 bd33e033e0..3ca51beb95 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 */
+/*
+ * 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 0
+
+/*
+ * Read coverage information in a single run
+ * You must use a tool to split them.
+ */
+#define XEN_SYSCTL_COVERAGE_read 1
+
+/*
+ * Reset all the coverage counters to 0
+ * No parameters.
+ */
+#define XEN_SYSCTL_COVERAGE_reset 2
+
+/*
+ * Like XEN_SYSCTL_COVERAGE_read but reset also
+ * counters to 0 in a single call.
+ */
+#define XEN_SYSCTL_COVERAGE_read_and_reset 3
+
+struct xen_sysctl_coverage_op {
+ uint32_t cmd; /* XEN_SYSCTL_COVERAGE_* */
+ union {
+ uint32_t 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 d695919762..27c5c37a1c 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,11 @@ struct gcov_info
};
+/**
+ * Sysctl operations for coverage
+ */
+#ifdef TEST_COVERAGE
+int sysctl_coverage_op(xen_sysctl_coverage_op_t *op);
+#endif
+
#endif /* __XEN_GCOV_H__ */