[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 3/4] Implement code to read coverage informations
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. Check does not check for any permission while other operations require a privileged domain. This cause these statistics can lead to security problems. Signed-off-by: Frediano Ziglio <frediano.ziglio@xxxxxxxxxx> --- xen/common/gcov/gcov.c | 157 +++++++++++++++++++++++++++++++++++++++++++-- xen/include/public/gcov.h | 24 +++++++ 2 files changed, 177 insertions(+), 4 deletions(-) diff --git a/xen/common/gcov/gcov.c b/xen/common/gcov/gcov.c index e208596..d5d74d0 100644 --- a/xen/common/gcov/gcov.c +++ b/xen/common/gcov/gcov.c @@ -19,10 +19,10 @@ #include <xen/hypercall.h> #include <xen/gcov.h> #include <xen/errno.h> +#include <xen/guest_access.h> #include <public/xen.h> static struct gcov_info *info_list; -static unsigned num_info = 0; /* * __gcov_init is called by gcc-generated constructor code for each object @@ -37,7 +37,6 @@ void __gcov_init(struct gcov_info *info) /* add new profiling data structure to list */ info->next = info_list; info_list = info; - ++num_info; } /* @@ -78,15 +77,165 @@ void init_coverage(void) __CTOR_LIST__.funcs[n](); #ifndef NDEBUG - printk(XENLOG_INFO "Initialized %u coverage strucures\n", num_info); if ( info_list ) printk(XENLOG_INFO "First coverage file %s\n", info_list->filename); #endif } +static inline int counter_active(const struct gcov_info *info, unsigned int type) +{ + return (1 << type) & info->ctr_mask; +} + +DEFINE_XEN_GUEST_HANDLE(uint8_t); + +typedef struct write_iter_t +{ + XEN_GUEST_HANDLE(uint8_t) ptr; + int real; + unsigned 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 = + (iter->write_offset + data_len + (sizeof(uint32_t) - 1)) & + -sizeof(uint32_t); + 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 < GCOV_COUNTERS && !counter_active(info, *type) ) + continue; + return *type; +} + +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); + + chk(write32(iter, GCOV_DATA_MAGIC)); + 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) < GCOV_COUNTERS; ++ctr ) + { + chk(write32(iter, GCOV_TAG_FOR_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 */ + chk(write32(iter, GCOV_TAG_FUNCTION)); + chk(write32(iter, info->n_functions)); + chk(write_raw(iter, info->functions, info->n_functions * size_fn)); + } + + /* stop tag */ + chk(write32(iter, 0)); + 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) < GCOV_COUNTERS; ++ctr ) + memset(ctr->values, 0, ctr->num * sizeof(ctr->values[0])); + } + + return 0; +} + long do_coverage_op(int op, XEN_GUEST_HANDLE_PARAM(void) uarg) { - return -EINVAL; + long ret = -EINVAL; + uint32_t len; + write_iter_t iter; + + /* + * just return success to check for coverage support, + * no permission check + */ + if ( op == XEN_COVERAGE_enabled ) + return 0; + + /* + * all other information although statistical one + * are too accurate and could lead to security issues + */ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + + switch ( op ) + { + case XEN_COVERAGE_get_total_size: + iter.real = 0; + + write_gcov(&iter); + len = iter.write_offset; + ret = copy_to_guest(uarg, &len, 1) ? -EFAULT : 0; + break; + + case XEN_COVERAGE_read: + iter.ptr = guest_handle_cast(uarg, uint8_t); + iter.real = 1; + + ret = write_gcov(&iter); + break; + + case XEN_COVERAGE_reset: + ret = reset_counters(); + break; + } + return ret; } #ifdef CONFIG_COMPAT diff --git a/xen/include/public/gcov.h b/xen/include/public/gcov.h index 67aedf6..a2863f7 100644 --- a/xen/include/public/gcov.h +++ b/xen/include/public/gcov.h @@ -90,4 +90,28 @@ struct gcov_info struct gcov_ctr_info counts[0]; }; + +/* + * Check if coverage informations are available + * return just success or error, no parameters + */ +#define XEN_COVERAGE_enabled 0 + +/* + * Get total size of information, to help allocate + * the buffer. The pointer points to a 32 bit value. + */ +#define XEN_COVERAGE_get_total_size 1 + +/* + * Read coverage information in a single run + * You must use a tool to split them + */ +#define XEN_COVERAGE_read 2 + +/* + * Reset all the coverage counters to 0 + */ +#define XEN_COVERAGE_reset 3 + #endif /* XEN_PUBLIC_GCOV_H */ -- 1.7.9.5 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |