Skip to contentSkip to conversation

gcov: Support gcc 4.7

PATCH In review Frediano Ziglio 5 participants 13 messages Jun 17, 2013 – Jun 28, 2013

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 gcov: Support gcc 4.7

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.

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

tools/misc/xencov_split +19 -7
index 2e5aa80..af0f580 100755
@@ -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;
xen/arch/x86/xen.lds.S +1 -0
index d959941..bdc4c91 100644
@@ -112,6 +112,7 @@ SECTIONS
        . = ALIGN(8);
        __ctors_start = .;
        *(.ctors)
+       *(.init_array)
        __ctors_end = .;
   } :text
   . = ALIGN(32);
xen/common/gcov/gcov.c +133 -28

202 lines not on this page · raw message

xen/include/public/gcov.h +15 -1
index 1b29b48..e7573fb 100644
@@ -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
  */
xen/include/xen/gcov.h +67 -1

86 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#1 lore raw

xen/arch/x86/xen.lds.S SECTIONS · line 118

Quoted 11 lines
Quoted 1 line
Quoted 1 line · Frediano Ziglio
xen/arch/x86/xen.lds.S +1 -0
@@ -112,6 +112,7 @@ SECTIONS
        . = ALIGN(8);
        __ctors_start = .;
        *(.ctors)
+       *(.init_array)
        __ctors_end = .;
   } :text
   . = ALIGN(32);

First of all - again an x86 change without a matching ARM one?

And then this is different from how binutils deals with these in a number of aspects:
- .init_array.* not handled (raises the question why .ctors.* didn't get handled already)
- .init_array following .ctors here, while binutils has it the other way around
- final section being .init_array instead of .ctors
- enclosing symbols prefixed with __init_array_ instead of __ctors_

Some or all of these may not matter, but I think any difference to how binutils deals with these sections needs to be explained in the patch description.

xen/arch/x86/xen.lds.S

Quoted 2 lines
xen/arch/x86/xen.lds.S +2 -0
+static inline const struct gcov_fn_info_407 *
+next_func(const struct gcov_info_407 *info, int *n_func)

What are these "_407" suffixes intended to mean? They look rather arbitrary, and to me aren't connected to the gcc version talked about here.

xen/arch/x86/xen.lds.S

Quoted 2 lines
xen/arch/x86/xen.lds.S +2 -0
+{
+    while ( ++*n_func < info->n_functions ) {

Coding style.

xen/arch/x86/xen.lds.S

Quoted 4 lines
xen/arch/x86/xen.lds.S +4 -0
+        const struct gcov_fn_info_407 *fn = info->functions[*n_func];
+
+        /* the test for info member handle common data redefinitions
+           in object files */

Again. Stopping here; there are more.

xen/include/public/gcov.h line 31

Quoted 8 lines
xen/include/public/gcov.h +1 -1
@@ -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

Misnamed manifest constant? It's never being used as a mask and also doesn't look like one.

xen/include/public/gcov.h line 32

Quoted 1 line
xen/include/public/gcov.h +1 -0
+#define XENCOV_COUNTERS         8

And this one doesn't appear to get used anywhere, so why are these changes being done in the first place?

Quoted 11 lines
xen/include/public/gcov.h +1 -0
 #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
 };
 
 /**

xen/include/public/gcov.h struct xencov_function · line 107

Quoted 10 lines
xen/include/public/gcov.h +10 -0
+ * 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];
+};

Nor can I seem to be able to spot a use of this structure.

Jan

#2 lore raw
Quoted 23 lines · Jan Beulich

xen/arch/x86/xen.lds.S SECTIONS · line 118

Quoted 11 lines
Quoted 1 line
Quoted 1 line · Frediano Ziglio
xen/arch/x86/xen.lds.S +1 -0
@@ -112,6 +112,7 @@ SECTIONS
        . = ALIGN(8);
        __ctors_start = .;
        *(.ctors)
+       *(.init_array)
        __ctors_end = .;
   } :text
   . = ALIGN(32);

First of all - again an x86 change without a matching ARM one?

And then this is different from how binutils deals with these in a number of aspects:
- .init_array.* not handled (raises the question why .ctors.* didn't get handled already)
- .init_array following .ctors here, while binutils has it the other way around
- final section being .init_array instead of .ctors
- enclosing symbols prefixed with __init_array_ instead of __ctors_

Quoted 4 lines

Some or all of these may not matter, but I think any difference to how binutils deals with these sections needs to be explained in the patch description.

I don't know why gcc changed from .ctors to .init_array, I found some reference for some architectural coherency (it seems other architectures use init_array, for instance arm already used init_array, the structure is the same).

I'm looking at binutils scripts:

...
.init_array :

  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
    KEEP (*(.init_array))
    KEEP (*(EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
    PROVIDE_HIDDEN (__init_array_end = .);

}
...
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
..

quite complicated. Can you read it ?

Quoted 7 lines

xen/arch/x86/xen.lds.S

Quoted 2 lines
xen/arch/x86/xen.lds.S +2 -0
+static inline const struct gcov_fn_info_407 *
+next_func(const struct gcov_info_407 *info, int *n_func)

What are these "_407" suffixes intended to mean? They look rather arbitrary, and to me aren't connected to the gcc version talked about here.

Do you prefer 4_7, perhaps is more readable.

Quoted 12 lines

xen/arch/x86/xen.lds.S

Quoted 2 lines
xen/arch/x86/xen.lds.S +2 -0
+{
+    while ( ++*n_func < info->n_functions ) {

Coding style.

xen/arch/x86/xen.lds.S

Quoted 4 lines
xen/arch/x86/xen.lds.S +4 -0
+        const struct gcov_fn_info_407 *fn = info->functions[*n_func];
+
+        /* the test for info member handle common data redefinitions
+           in object files */

Again. Stopping here; there are more.

Fixed, found some others.

Quoted 6 lines
Quoted 6 lines
xen/include/public/gcov.h +0 -0
@@ -28,10 +28,12 @@
 #ifndef __XEN_PUBLIC_GCOV_H__
 #define __XEN_PUBLIC_GCOV_H__ __XEN_PUBLIC_GCOV_H__
 
Quoted 6 lines

xen/include/public/gcov.h line 31

Quoted 2 lines
xen/include/public/gcov.h +1 -1
-#define XENCOV_COUNTERS         5
+#define XENCOV_COUNTERS_MASK    5

Misnamed manifest constant? It's never being used as a mask and also doesn't look like one.

Possibly is better to use XENCOV_COUNTERS_3_4 then. I used _MASK cause 3.4 used a strange mask field.

Quoted 5 lines

xen/include/public/gcov.h line 32

Quoted 1 line
xen/include/public/gcov.h +1 -0
+#define XENCOV_COUNTERS         8

And this one doesn't appear to get used anywhere, so why are these changes being done in the first place?

It's used in the macro some lines below.

Quoted 24 lines
Quoted 11 lines
xen/include/public/gcov.h +1 -0
 #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
 };
 
 /**

xen/include/public/gcov.h struct xencov_function · line 107

Quoted 10 lines
xen/include/public/gcov.h +10 -0
+ * 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];
+};

Nor can I seem to be able to spot a use of this structure.

Quoted 2 lines

Jan

Yes, cause actually there is no C program that use these information (perl is used)

Frediano

#3 lore raw
Quoted 70 lines
Quoted 1 line
Quoted 1 line · Frediano Ziglio
Quoted 23 lines · Jan Beulich

xen/arch/x86/xen.lds.S SECTIONS · line 118

Quoted 11 lines
Quoted 1 line
Quoted 1 line · Frediano Ziglio
xen/arch/x86/xen.lds.S +1 -0
@@ -112,6 +112,7 @@ SECTIONS
        . = ALIGN(8);
        __ctors_start = .;
        *(.ctors)
+       *(.init_array)
        __ctors_end = .;
   } :text
   . = ALIGN(32);

First of all - again an x86 change without a matching ARM one?

And then this is different from how binutils deals with these in a number of aspects:
- .init_array.* not handled (raises the question why .ctors.* didn't get handled already)
- .init_array following .ctors here, while binutils has it the other way around
- final section being .init_array instead of .ctors
- enclosing symbols prefixed with __init_array_ instead of __ctors_

Quoted 4 lines

Some or all of these may not matter, but I think any difference to how binutils deals with these sections needs to be explained in the patch description.

I don't know why gcc changed from .ctors to .init_array, I found some reference for some architectural coherency (it seems other architectures use init_array, for instance arm already used init_array, the structure is the same).

I'm looking at binutils scripts:

...
.init_array :

  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
    KEEP (*(.init_array))
    KEEP (*(EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
    PROVIDE_HIDDEN (__init_array_end = .);

}
...
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
..

Quoted 1 line

quite complicated. Can you read it ?

It's not _that_ difficult, but yes, this is what I looked at when putting together the earlier response.

Quoted 9 lines
Quoted 7 lines

xen/arch/x86/xen.lds.S

Quoted 2 lines
xen/arch/x86/xen.lds.S +2 -0
+static inline const struct gcov_fn_info_407 *
+next_func(const struct gcov_info_407 *info, int *n_func)

What are these "_407" suffixes intended to mean? They look rather arbitrary, and to me aren't connected to the gcc version talked about here.

Do you prefer 4_7, perhaps is more readable.

Unless 4.7 is the gcov version number, please call it gcc_4_7 or gcc4_7, so that it's clear the version number of what you're referring to.

Quoted 13 lines
Quoted 6 lines
Quoted 6 lines
xen/include/public/gcov.h +0 -0
@@ -28,10 +28,12 @@
 #ifndef __XEN_PUBLIC_GCOV_H__
 #define __XEN_PUBLIC_GCOV_H__ __XEN_PUBLIC_GCOV_H__
 
Quoted 6 lines

xen/include/public/gcov.h line 31

Quoted 2 lines
xen/include/public/gcov.h +1 -1
-#define XENCOV_COUNTERS         5
+#define XENCOV_COUNTERS_MASK    5

Misnamed manifest constant? It's never being used as a mask and also doesn't look like one.

Quoted 2 lines

Possibly is better to use XENCOV_COUNTERS_3_4 then. I used _MASK cause 3.4 used a strange mask field.

Same here - if this is a gcc version, include gcc in the name.

Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
xen/include/public/gcov.h +4 -0
+ * Information for each function
+ * Number of counter is equal to the number of counter structures got before
+ */
+struct xencov_function2
Quoted 8 lines

xen/include/public/gcov.h struct xencov_function · line 107

Quoted 6 lines
xen/include/public/gcov.h +6 -0
+{
+    uint32_t ident;
+    uint32_t lineno_checksum;
+    uint32_t cfg_checksum;
+    uint32_t num_counters[1];
+};

Nor can I seem to be able to spot a use of this structure.

Quoted 2 lines

Yes, cause actually there is no C program that use these information (perl is used)

Okay, so it's here then just for documentation purposes. That should be said in the preceding comment, or else you risk it getting removed by some cleanup patch. Even better would be to end the comment only after the structure declaration, to avoid cluttering the name space.

Jan

#4 lore raw
In reply to Frediano Ziglio
Quoted 8 lines · Frediano Ziglio

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.

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

Quoted 433 lines
---
  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.

tools/misc/xencov_split +19 -7
index 2e5aa80..af0f580 100755
@@ -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;
xen/arch/x86/xen.lds.S +1 -0
index d959941..bdc4c91 100644
@@ -112,6 +112,7 @@ SECTIONS
         . = ALIGN(8);
         __ctors_start = .;
         *(.ctors)
+       *(.init_array)
         __ctors_end = .;
    } :text
    . = ALIGN(32);
xen/common/gcov/gcov.c +133 -28
index b5717b9..1d32d8f 100644
@@ -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;
xen/include/public/gcov.h +15 -1
index 1b29b48..e7573fb 100644
@@ -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
   */
xen/include/xen/gcov.h +67 -1
index 27c5c37..f36388a 100644
@@ -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
#5 lore raw
In reply to Frediano Ziglio
Quoted 6 lines · Frediano Ziglio

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.

Do we really need to reflect that in the Xen public API though? Could we condense it into the things we want/need and try and keep our API relatively stable?

I'm a bit concerned that we are going to end up with dozens of variants of the API (and the internal code) supporting each new variant of this internal-to-gcc ABI.

I think you explained before why this couldn't be exported from the hypervisor as an opaque set of bytes to be interpreted by a userspace tool, which is a shame. I wonder if it is worth asking upstream if they have any advice.

Ian.

#6 lore raw
Quoted 16 lines · Ian Campbell
Quoted 6 lines · Frediano Ziglio

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.

Do we really need to reflect that in the Xen public API though? Could we condense it into the things we want/need and try and keep our API relatively stable?

I'm a bit concerned that we are going to end up with dozens of variants of the API (and the internal code) supporting each new variant of this internal-to-gcc ABI.

Quoted 8 lines

I think you explained before why this couldn't be exported from the hypervisor as an opaque set of bytes to be interpreted by a userspace tool, which is a shame. I wonder if it is worth asking upstream if they have any advice.

Ian.

Perhaps a simple easy solution would be to allow privileged domains to read/write arbitrary memory from Xen (write to reset counters).

Frediano

#7 lore raw
Quoted 2 lines · Frediano Ziglio

Perhaps a simple easy solution would be to allow privileged domains to read/write arbitrary memory from Xen (write to reset counters).

"Arbitrary memory" would be a very hard sell.

If all these counters could be constrained to pages which contains these counters and nothing else then that might be a possibility to consider.

Ian.

#8 lore raw
Quoted 11 lines · Ian Campbell
Quoted 2 lines · Frediano Ziglio

Perhaps a simple easy solution would be to allow privileged domains to read/write arbitrary memory from Xen (write to reset counters).

"Arbitrary memory" would be a very hard sell.

If all these counters could be constrained to pages which contains these counters and nothing else then that might be a possibility to consider.

Ian.

It would be very good if gcc could provide some options to move all counter in a given separate section and another for all coverage data (structures and strings). Actually there are no such options. I tried to change generated .s file but with no success (I don't know how to generate a common section in a new section, .comm/.lcomm generate always in .bss section).

I'll write to gcc ML.

Frediano

#9 lore raw
In reply to Ian Campbell
Quoted 11 lines · Ian Campbell
Quoted 2 lines · Frediano Ziglio

Perhaps a simple easy solution would be to allow privileged domains to read/write arbitrary memory from Xen (write to reset counters).

"Arbitrary memory" would be a very hard sell.

If all these counters could be constrained to pages which contains these counters and nothing else then that might be a possibility to consider.

Ian.

It depends on how this would be implemented. A future option of gcc could help at least having everything in contiguous memory regions.

The fact that these information are generated by the compiler does not help that much. Every version could change the format "slightly" but enough to make Xen core when such information are requested!

Actually they changed format for these version of gcc:
- 3.3
- 3.4
- 4.7

And honestly I still don't understand clearly why they changed for gcc 4.7! Probably not for a C feature but to support C++ templates and comdat. A "smart" preprocessor sit in the middle of gcc and gas that process assembly generated, check for structures and put everything in different sections could really help... but is not that easy project! Another similar way would be to parse the xen-syms output file and generate needed blob/code. Quite interesting challenge (I did more terrible things then this) but I don't thing that Citrix would agree. Possibly a safe thing to do would be in the code to check that compiler is really gcc and that we can support the version that is compiling, just to make sure. But is also true that this feature is a debug one disabled on production so I don't know how worth would be.

Not speaking of clang support, currently quite hard (the structures are less documented, the code hooks destructors path which is not safe to call from Xen code which is not expected to terminate).

Frediano

#10 lore raw
Quoted 38 lines · Frediano Ziglio
Quoted 11 lines · Ian Campbell
Quoted 2 lines · Frediano Ziglio

Perhaps a simple easy solution would be to allow privileged domains to read/write arbitrary memory from Xen (write to reset counters).

"Arbitrary memory" would be a very hard sell.

If all these counters could be constrained to pages which contains these counters and nothing else then that might be a possibility to consider.

Ian.

It depends on how this would be implemented. A future option of gcc could help at least having everything in contiguous memory regions.

The fact that these information are generated by the compiler does not help that much. Every version could change the format "slightly" but enough to make Xen core when such information are requested!

Actually they changed format for these version of gcc:
- 3.3
- 3.4
- 4.7

And honestly I still don't understand clearly why they changed for gcc 4.7! Probably not for a C feature but to support C++ templates and comdat. A "smart" preprocessor sit in the middle of gcc and gas that process assembly generated, check for structures and put everything in different sections could really help... but is not that easy project! Another similar way would be to parse the xen-syms output file and generate needed blob/code. Quite interesting challenge (I did more terrible things then this) but I don't thing that Citrix would agree. Possibly a safe thing to do would be in the code to check that compiler is really gcc and that we can support the version that is compiling, just to make sure. But is also true that this feature is a debug one disabled on production so I don't know how worth would be.

Quoted 3 lines

Not speaking of clang support, currently quite hard (the structures are less documented, the code hooks destructors path which is not safe to call from Xen code which is not expected to terminate).

Doesn't Linux have gcov support via lcov? Do they have to deal with this stuff as well, or is there a generic way to deal with it?

-George

#11 lore raw
Quoted 39 lines · George Dunlap
Quoted 38 lines · Frediano Ziglio
Quoted 11 lines · Ian Campbell
Quoted 2 lines · Frediano Ziglio

Perhaps a simple easy solution would be to allow privileged domains to read/write arbitrary memory from Xen (write to reset counters).

"Arbitrary memory" would be a very hard sell.

If all these counters could be constrained to pages which contains these counters and nothing else then that might be a possibility to consider.

Ian.

It depends on how this would be implemented. A future option of gcc could help at least having everything in contiguous memory regions.

The fact that these information are generated by the compiler does not help that much. Every version could change the format "slightly" but enough to make Xen core when such information are requested!

Actually they changed format for these version of gcc:
- 3.3
- 3.4
- 4.7

And honestly I still don't understand clearly why they changed for gcc 4.7! Probably not for a C feature but to support C++ templates and comdat. A "smart" preprocessor sit in the middle of gcc and gas that process assembly generated, check for structures and put everything in different sections could really help... but is not that easy project! Another similar way would be to parse the xen-syms output file and generate needed blob/code. Quite interesting challenge (I did more terrible things then this) but I don't thing that Citrix would agree. Possibly a safe thing to do would be in the code to check that compiler is really gcc and that we can support the version that is compiling, just to make sure. But is also true that this feature is a debug one disabled on production so I don't know how worth would be.

Quoted 8 lines
Quoted 3 lines

Not speaking of clang support, currently quite hard (the structures are less documented, the code hooks destructors path which is not safe to call from Xen code which is not expected to terminate).

Doesn't Linux have gcov support via lcov? Do they have to deal with this stuff as well, or is there a generic way to deal with it?

-George

They only support gcc 3.4 format (the one we currently support without my new patch which add support for 4.7 format)

Frediano

#12 lore raw
In reply to Ian Campbell
Quoted 12 lines · Ian Campbell
Quoted 6 lines · Frediano Ziglio

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.

Do we really need to reflect that in the Xen public API though? Could we condense it into the things we want/need and try and keep our API relatively stable?

Quoted 7 lines

I'm a bit concerned that we are going to end up with dozens of variants of the API (and the internal code) supporting each new variant of this internal-to-gcc ABI.

I think you explained before why this couldn't be exported from the hypervisor as an opaque set of bytes to be interpreted by a userspace tool, which is a shame.

I think this is possible the same way the hypervisor exports machine check error telemetry.

Christoph