From 5043f14b5e0043bb6a2c8b794adb440b8b8b3b4a Mon Sep 17 00:00:00 2001 From: Frediano Ziglio Date: Thu, 14 Feb 2013 12:37:15 +0000 Subject: 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 --- xen/common/gcov/gcov.c | 153 ++++++++++++++++++++++++++++++++++++++++++++ xen/common/sysctl.c | 6 ++ xen/include/public/gcov.h | 115 +++++++++++++++++++++++++++++++++ xen/include/public/sysctl.h | 38 +++++++++++ xen/include/xen/gcov.h | 9 +++ 5 files changed, 321 insertions(+) create mode 100644 xen/include/public/gcov.h 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 #include #include +#include +#include +#include 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 #include #include +#include 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 + /* * 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__ */ -- cgit v1.2.3