---
tools/misc/xencov_split | 26 ++++++--
xen/arch/x86/xen.lds.S | 1 +
xen/common/gcov/gcov.c | 161 +++++++++++++++++++++++++++++++++++++--------
xen/include/public/gcov.h | 16 ++++-
xen/include/xen/gcov.h | 68 ++++++++++++++++++-
5 files changed, 235 insertions(+), 37 deletions(-)
Patch tested with gcc 4.7, x64 with x86 dom0 and lcov 1.10.
diff --git a/tools/misc/xencov_split b/tools/misc/xencov_split
index 2e5aa80..af0f580 100755
--- a/tools/misc/xencov_split
+++ b/tools/misc/xencov_split
@@ -27,7 +27,8 @@ my $magic = 0x67636461;
my $ctrBase = 0x01a10000;
my $xenMagic = 0x58544346; # file header
-my $xenTagFunc = 0x58544366; # functions tag
+my $xenTagFunc = 0x58544366; # functions tag
+my $xenTagFunc2 = 0x58544367; # functions tag2
my $xenTagCount0 = 0x58544330; # counter 0 tag
my $xenTagEnd = 0x5854432e; # end file
@@ -86,9 +87,9 @@ sub getS()
return $res;
}
-sub parseFunctions($)
+sub parseFunctions($$)
{
- my $numCounters = shift;
+ my ($numCounters, $ver) = @_;
my $num = get32();
my @funcs;
@@ -96,10 +97,12 @@ sub parseFunctions($)
my @data;
my $ident = get32();
my $checksum = get32();
+ my $checksum2 = 0;
+ $checksum2 = get32() if $ver > 1;
for my $n (1..$numCounters) {
push @data, get32(); # number of counters for a type
}
- push @funcs, [$ident, $checksum, \@data];
+ push @funcs, [$ver, $ident, $checksum, $checksum2, \@data];
}
align();
return @funcs;
@@ -147,7 +150,12 @@ sub parseFile()
last if ($tag == $xenMagic || $tag == $xenTagEnd);
if ($tag == $xenTagFunc) {
die if scalar(@funcs);
- @funcs = parseFunctions(scalar(@ctrs));
+ @funcs = parseFunctions(scalar(@ctrs), 1);
+ next;
+ }
+ if ($tag == $xenTagFunc2) {
+ die if scalar(@funcs);
+ @funcs = parseFunctions(scalar(@ctrs), 2);
next;
}
@@ -159,10 +167,14 @@ sub parseFile()
# print all functions
for my $f (@funcs) {
# tag tag_len ident checksum
- print OUT pack('VVVV', 0x01000000, 2, $f->[0], $f->[1]);
+ if ($f->[0] == 1) {
+ print OUT pack('VVVV', 0x01000000, 2, $f->[1], $f->[2]);
+ } else {
+ print OUT pack('VVVVV', 0x01000000, 3, $f->[1], $f->[2], $f->[3]);
+ }
# all counts
my $n = 0;
- for my $c (@{$f->[2]}) {
+ for my $c (@{$f->[4]}) {
my ($type, $data) = @{$ctrs[$n]};
print OUT pack('VV', $ctrBase + 0x20000 * $type, $c*2);
die "--$c--$type--$data--" if length($data) < $c * 8;
diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S
index d959941..bdc4c91 100644
--- a/xen/arch/x86/xen.lds.S
+++ b/xen/arch/x86/xen.lds.S
@@ -112,6 +112,7 @@ SECTIONS
. = ALIGN(8);
__ctors_start = .;
*(.ctors)
+ *(.init_array)
__ctors_end = .;
} :text
. = ALIGN(32);
diff --git a/xen/common/gcov/gcov.c b/xen/common/gcov/gcov.c
index b5717b9..1d32d8f 100644
--- a/xen/common/gcov/gcov.c
+++ b/xen/common/gcov/gcov.c
@@ -106,17 +106,120 @@ static int write_string(write_iter_t *iter, const char
*s)
static inline int next_type(const struct gcov_info *info, int *type)
{
- while ( ++*type < XENCOV_COUNTERS && !counter_active(info, *type) )
+ while ( ++*type < XENCOV_COUNTERS_MASK && !counter_active(info, *type) )
continue;
return *type;
}
+static inline const struct gcov_fn_info_407 *
+next_func(const struct gcov_info_407 *info, int *n_func)
+{
+ while ( ++*n_func < info->n_functions ) {
+ const struct gcov_fn_info_407 *fn = info->functions[*n_func];
+
+ /* the test for info member handle common data redefinitions
+ in object files */
+ if ( fn && fn->info == info)
+ return fn;
+ }
+
+ return NULL;
+}
+
+static inline const struct gcov_ctr_info_407 *
+next_ctr(const struct gcov_fn_info_407 *fn, int *n_ctr)
+{
+ while ( ++*n_ctr < XENCOV_COUNTERS_407 )
+ if ( fn->info->merge[*n_ctr] )
+ return &fn->ctrs[*n_ctr];
+
+ return NULL;
+}
+
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_info(write_iter_t *iter, const struct gcov_info* info)
+{
+ const struct gcov_ctr_info *ctr;
+ int type, ret;
+ size_t size_fn = sizeof(struct gcov_fn_info);
+
+ /* dump counters */
+ ctr = info->counts;
+ for ( type = -1; next_type(info, &type) < XENCOV_COUNTERS_MASK; ++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));
+
+ return 0;
+}
+
+static int write_info_407(write_iter_t *iter, const struct gcov_info_407* info)
+{
+ int ret;
+ const struct gcov_fn_info_407 *fn;
+ const struct gcov_ctr_info_407 *ctr;
+ int n_func, n_ctr;
+ unsigned int num_func = 0;
+ unsigned int ctrs[XENCOV_COUNTERS_407];
+
+ for ( n_ctr = 0; n_ctr < XENCOV_COUNTERS_407; ++n_ctr )
+ ctrs[n_ctr] = 0;
+
+ /* scan to total counters */
+ for ( n_func = -1; (fn = next_func(info, &n_func)) != NULL; )
+ {
+ ++num_func;
+ for ( n_ctr = -1; (ctr = next_ctr(fn, &n_ctr)) != NULL; )
+ ctrs[n_ctr] += ctr->num;
+ }
+
+ /* output counters */
+ for ( n_ctr = 0; n_ctr < XENCOV_COUNTERS_407; ++n_ctr )
+ {
+ if ( !ctrs[n_ctr] ) continue;
+ align_iter(iter);
+ chk(write32(iter, XENCOV_TAG_COUNTER(n_ctr)));
+ chk(write32(iter, ctrs[n_ctr]));
+ for ( n_func = -1; (fn = next_func(info, &n_func)) != NULL; )
+ {
+ ctr = &fn->ctrs[n_ctr];
+ chk(write_raw(iter, ctr->values,
+ ctr->num * sizeof(ctr->values[0])));
+ }
+ }
+
+ /* dump all functions together */
+ align_iter(iter);
+ chk(write32(iter, XENCOV_TAG_FUNC2));
+ chk(write32(iter, num_func));
+ for ( n_func = -1; (fn = next_func(info, &n_func)) != NULL; )
+ {
+ chk(write32(iter, fn->ident));
+ chk(write32(iter, fn->lineno_checksum));
+ chk(write32(iter, fn->cfg_checksum));
+ for ( n_ctr = -1; (ctr = next_ctr(fn, &n_ctr)) != NULL; )
+ chk(write32(iter, ctr->num));
+ }
+ return 0;
+}
+
static int write_gcov(write_iter_t *iter)
{
struct gcov_info *info;
@@ -128,10 +231,6 @@ static int write_gcov(write_iter_t *iter)
/* 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));
@@ -139,23 +238,10 @@ static int write_gcov(write_iter_t *iter)
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));
+ if (info->version < XENCOV_VERSION_407)
+ chk(write_info(iter, info));
+ else
+ chk(write_info_407(iter, (struct gcov_info_407 *) info));
}
/* stop tag */
@@ -164,19 +250,38 @@ static int write_gcov(write_iter_t *iter)
return 0;
}
+static void reset_info(struct gcov_info *info)
+{
+ const struct gcov_ctr_info *ctr;
+ int type;
+
+ ctr = info->counts;
+ for ( type = -1; next_type(info, &type) < XENCOV_COUNTERS_MASK; ++ctr )
+ memset(ctr->values, 0, ctr->num * sizeof(ctr->values[0]));
+}
+
+static void reset_info_407(struct gcov_info_407 *info)
+{
+ const struct gcov_fn_info_407 *fn;
+ const struct gcov_ctr_info_407 *ctr;
+ int n_func, n_ctr;
+
+ for ( n_func = -1; (fn = next_func(info, &n_func)) != NULL; )
+ for ( n_ctr = -1; (ctr = next_ctr(fn, &n_ctr)) != NULL; )
+ memset(ctr->values, 0, ctr->num * sizeof(ctr->values[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]));
+ if ( info->version < XENCOV_VERSION_407 )
+ reset_info(info);
+ else
+ reset_info_407((struct gcov_info_407 *) info);
}
return 0;
diff --git a/xen/include/public/gcov.h b/xen/include/public/gcov.h
index 1b29b48..e7573fb 100644
--- a/xen/include/public/gcov.h
+++ b/xen/include/public/gcov.h
@@ -28,10 +28,12 @@
#ifndef __XEN_PUBLIC_GCOV_H__
#define __XEN_PUBLIC_GCOV_H__ __XEN_PUBLIC_GCOV_H__
-#define XENCOV_COUNTERS 5
+#define XENCOV_COUNTERS_MASK 5
+#define XENCOV_COUNTERS 8
#define XENCOV_TAG_BASE 0x58544300u
#define XENCOV_TAG_FILE (XENCOV_TAG_BASE+0x46u)
#define XENCOV_TAG_FUNC (XENCOV_TAG_BASE+0x66u)
+#define XENCOV_TAG_FUNC2 (XENCOV_TAG_BASE+0x67u)
#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) \
@@ -93,6 +95,18 @@ struct xencov_function
};
/**
+ * Information for each function
+ * Number of counter is equal to the number of counter structures got before
+ */
+struct xencov_function2
+{
+ uint32_t ident;
+ uint32_t lineno_checksum;
+ uint32_t cfg_checksum;
+ uint32_t num_counters[1];
+};
+
+/**
* Information for all functions
* Aligned to 8 bytes
*/
diff --git a/xen/include/xen/gcov.h b/xen/include/xen/gcov.h
index 27c5c37..f36388a 100644
--- a/xen/include/xen/gcov.h
+++ b/xen/include/xen/gcov.h
@@ -40,6 +40,8 @@ struct gcov_fn_info
unsigned int n_ctrs[0];
};
+typedef void (*gcov_merge_func)(gcov_type *, unsigned int);
+
/**
* struct gcov_ctr_info - profiling data per counter type
* @num: number of counter values for this type
@@ -53,7 +55,7 @@ struct gcov_ctr_info
{
unsigned int num;
gcov_type *values;
- void (*merge)(gcov_type *, unsigned int);
+ gcov_merge_func merge;
};
/**
@@ -82,6 +84,70 @@ struct gcov_info
struct gcov_ctr_info counts[0];
};
+struct gcov_info_407;
+
+/**
+ * struct gcov_ctr_info_407 - profiling data per counter type
+ * @num: number of counter values for this type
+ * @values: array of counter values for this type
+ * @merge: merge function for counter values of this type (unused)
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time with the exception of the values array.
+ */
+struct gcov_ctr_info_407
+{
+ unsigned int num;
+ gcov_type *values;
+};
+
+
+/**
+ * struct gcov_fn_info_407 - profiling meta data per function
+ * @ident: object file-unique function identifier
+ * @lineno_checksum: function lineno checksum
+ * @cfg_checksum: function cfg checksum
+ * @ctrs: counters for this function
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time.
+ */
+struct gcov_fn_info_407
+{
+ const struct gcov_info_407 *info;
+ unsigned int ident;
+ unsigned int lineno_checksum;
+ unsigned int cfg_checksum;
+ struct gcov_ctr_info_407 ctrs[0];
+};
+
+#define XENCOV_COUNTERS_407 8
+#define XENCOV_VERSION_407 0x34303700
+
+/**
+ * struct gcov_info_407 - profiling data per object file
+ * @version: gcov version magic indicating the gcc version used for compilation
+ * @next: list head for a singly-linked list
+ * @stamp: time stamp
+ * @filename: name of the associated gcov data file
+ * @merge: merge functions
+ * @n_functions: number of instrumented functions
+ * @functions: function data
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time with the exception of the next pointer.
+ */
+struct gcov_info_407
+{
+ unsigned int version;
+ struct gcov_info *next;
+ unsigned int stamp;
+ const char *filename;
+ gcov_merge_func merge[XENCOV_COUNTERS_407];
+ unsigned int n_functions;
+ const struct gcov_fn_info_407 * const *functions;
+};
+
/**
* Sysctl operations for coverage