From mboxrd@z Thu Jan 1 00:00:00 1970 From: George Dunlap Subject: Re: [PATCH] gcov: Support gcc 4.7 Date: Mon, 17 Jun 2013 10:50:08 +0100 Message-ID: <51BEDBD0.9010409@eu.citrix.com> References: <1371457748.9654.3.camel@hamster.uk.xensource.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii"; Format="flowed" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1371457748.9654.3.camel@hamster.uk.xensource.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: Frediano Ziglio Cc: Matthew Daley , Christoph Egger , Ian Campbell , Miguel Clara , xen-devel@lists.xen.org List-Id: xen-devel@lists.xenproject.org On 17/06/13 09:29, Frediano Ziglio wrote: > gcc 4.7 changed format used internally for coverage data. > This patch address these changes. > The information that gcc generate are mostly the same but to support common > sections. > The only difference in the blob exported by Xen is that functions have 2 > different checksums instead of one. > > Signed-off-by: Frediano Ziglio At this point we'd like to completely freeze the tree except for critical bugfixes. I think this will have to wait for 4.4. -George > --- > 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