aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/gcov
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 /xen/common/gcov
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>
Diffstat (limited to 'xen/common/gcov')
-rw-r--r--xen/common/gcov/gcov.c153
1 files changed, 153 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