|
[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 |