Done. Passes manual testing, rerunning regression testing. New patch attached.

Thanks,
Teresa

On Fri, May 23, 2014 at 11:35 AM, Xinliang David Li <davi...@google.com> wrote:
> The change makes gcov_info a variable length array, which is not ideal.
>
> Better just add one more field (instead of two):
>
> struct gcov_info {
>    ...
>   char ** build_info;
> };
>
> For regular case, it is null, for case where the build info is
> available, make it point to a string array (with an null end marker
> string).
>
> David
>
>
>
>
>
> On Fri, May 23, 2014 at 11:08 AM, Teresa Johnson <tejohn...@google.com> wrote:
>> Support for embedding arbitrary build information from the profile-generate
>> compile into the gcda file in a new BUILD_INFO record. Lines from a file
>> passed to the -fprofile-generate compile via a new
>> -fprofile-generate-buildinfo=filename option are embedded as strings
>> in the gcov_info struct and emitted as-is to a new GCOV_TAG_BUILD_INFO
>> record. They are ignored on profile-use compiles, but emitted by gcov-dump.
>> This is useful for recording information about, for example, source revision
>> info that can be helpful for diagnosing profile mis-matches.
>>
>> For example:
>>
>> $ cat buildinfo.txt
>> Build timestamp xxxx
>> Build source revision r12345
>> Other random build data
>>
>> $ g++ foo.cc -fprofile-generate -fprofile-generate-buildinfo=buildinfo.txt
>>
>> $ a.out
>> $ gcov-dump foo.gcda
>> foo.gcda:data:magic `gcda':version `408*'
>> foo.gcda:stamp 708902860
>> foo.gcda: a3000000:  22:PROGRAM_SUMMARY checksum=0x86a3bc55
>> foo.gcda:               counts=1, runs=1, sum_all=1, run_max=1, sum_max=1
>> foo.gcda:               counter histogram:
>> foo.gcda:               1: num counts=1, min counter=1, cum_counter=1
>> foo.gcda: a7000000:  24:BUILD INFO num_strings=3
>> foo.gcda:               Build timestamp xxxx
>> foo.gcda:               Build source revision r12345
>> foo.gcda:               Other random build data
>> foo.gcda: 01000000:   3:FUNCTION ident=1, lineno_checksum=0x17c79156,
>> cfg_checksum=0xdb5de9e8
>> foo.gcda:  01a10000:   2:COUNTERS arcs 1 counts
>>
>> Tested manually, passes regression tests. Ok for Google/4_8?
>>
>> Thanks,
>> Teresa
>>
>> --
>> Teresa Johnson | Software Engineer | tejohn...@google.com | 408-460-2413



-- 
Teresa Johnson | Software Engineer | tejohn...@google.com | 408-460-2413
Support for embedding arbitrary build information from the profile-generate
compile into the gcda file in a new BUILD_INFO record. Lines from a file
passed to the -fprofile-generate compile via a new
-fprofile-generate-buildinfo=filename option are embedded as strings
in the gcov_info struct and emitted as-is to a new GCOV_TAG_BUILD_INFO
record. They are ignored on profile-use compiles, but emitted by gcov-dump.
This is useful for recording information about, for example, source revision
info that can be helpful for diagnosing profile mis-matches.

For example:

$ cat buildinfo.txt 
Build timestamp xxxx
Build source revision r12345
Other random build data

$ g++ foo.cc -fprofile-generate -fprofile-generate-buildinfo=buildinfo.txt

$ a.out

$ gcov-dump foo.gcda
foo.gcda:data:magic `gcda':version `408*'
foo.gcda:stamp 708902860
foo.gcda: a3000000:  22:PROGRAM_SUMMARY checksum=0x86a3bc55
foo.gcda:               counts=1, runs=1, sum_all=1, run_max=1, sum_max=1
foo.gcda:               counter histogram:
foo.gcda:               1: num counts=1, min counter=1, cum_counter=1
foo.gcda: a7000000:  24:BUILD INFO num_strings=3
foo.gcda:               Build timestamp xxxx
foo.gcda:               Build source revision r12345
foo.gcda:               Other random build data
foo.gcda: 01000000:   3:FUNCTION ident=1, lineno_checksum=0x17c79156, 
cfg_checksum=0xdb5de9e8
foo.gcda:  01a10000:   2:COUNTERS arcs 1 counts

Tested manually, passes regression tests. Ok for Google/4_8?

Thanks,
Teresa

2014-05-23  Teresa Johnson  <tejohn...@google.com>

        Google ref b/14794433

        * gcc/common.opt (flag_profile_generate_buildinfo): New flag.
        * gcc/coverage.c (read_counts_file): Handle build info tag.
        (build_info_type): Initialize new build_info gcov_info field.
        (build_info): Ditto.
        (build_gcov_build_info_value): New function.
        (str_list_append): Move earlier in file.
        (read_buildinfo): New function.
        (coverage_obj_init): Handle flag_profile_generate_buildinfo.
        * gcc/gcov.c (read_count_file): Handle build info tag.
        * gcc/gcov-dump.c (tag_table): Ditto.
        (tag_build_info): New function.
        * gcc/gcov-io.c (gcov_compute_string_array_len): Outline from
        gcov_write_module_info.
        (gcov_write_string_array): Ditto.
        (gcov_read_string_array): Outline from gcov_read_module_info.
        (gcov_read_build_info): New function.
        (gcov_read_module_info): Invoke outlined gcov_read_string_array.
        * gcc/gcov-io.h (GCOV_TAG_BUILD_INFO): New tag.
        (gcov_read_build_info): Declare.
        (gcov_read_string_array): Ditto.
        (gcov_compute_string_array_len): Ditto.
        (gcov_write_string_array): Ditto.
        * libgcc/dyn-ipa.c (gcov_write_module_info): Invoke outlined
        gcov_compute_string_array_len and gcov_write_string_array.
        * libgcc/libgcov-driver.c (gcov_exit_merge_gcda): Read build info.
        (gcov_write_build_info): New function.
        (gcov_exit_write_gcda): Write build info.
        * libgcc/libgcov.h (struct gcov_info): Add new build info fields.

Index: gcc/common.opt
===================================================================
--- gcc/common.opt      (revision 210862)
+++ gcc/common.opt      (working copy)
@@ -1798,6 +1798,10 @@ fprofile-generate-sampling
 Common Var(flag_profile_generate_sampling)
 Turn on instrumentation sampling with -fprofile-generate with rate set by 
--param profile-generate-sampling-rate or environment variable 
GCOV_SAMPLING_RATE
 
+fprofile-generate-buildinfo=
+Common RejectNegative Joined Var(flag_profile_generate_buildinfo)
+-fprofile-generate-buildinfo=filename  Read build info to include in gcda file 
from filename
+
 femit-function-names
 Common Var(flag_emit_function_names)
 Print to stderr the mapping from module name and function id to assembler
Index: gcc/coverage.c
===================================================================
--- gcc/coverage.c      (revision 210862)
+++ gcc/coverage.c      (working copy)
@@ -154,6 +154,10 @@ static unsigned num_cpp_defines = 0;
 static struct str_list *cpp_includes_head = NULL, *cpp_includes_tail = NULL;
 static unsigned num_cpp_includes = 0;
 
+/* List of lines read from -fprofile-generate-buildinfo=filename.  */
+struct str_list *build_info_array_head = NULL, *build_info_array_tail = NULL;
+static unsigned num_build_info = 0;
+
 /* True if the current module has any asm statements.  */
 static bool has_asm_statement;
 
@@ -792,6 +796,15 @@ read_counts_file (const char *da_file_name, unsign
        }
       else if (tag == GCOV_TAG_PARAMETERS)
         gcov_parameter_values = gcov_read_parameters (length);
+      else if (tag == GCOV_TAG_BUILD_INFO)
+        {
+          gcov_unsigned_t num_strings;
+          char **build_info_strings = gcov_read_build_info (length,
+                                                            &num_strings);
+          for (unsigned i = 0; i < num_strings; i++)
+            free (build_info_strings[i]);
+          free (build_info_strings);
+        }
       else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
        {
          counts_entry_t **slot, *entry, elt;
@@ -1699,6 +1712,7 @@ build_info_type (tree type, tree fn_info_ptr_type)
 {
   tree field, fields = NULL_TREE;
   tree merge_fn_type, mod_type;
+  tree string_type, string_ptr_type;
 
   /* Version ident */
   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
@@ -1766,6 +1780,17 @@ build_info_type (tree type, tree fn_info_ptr_type)
   DECL_CHAIN (field) = fields;
   fields = field;
 
+  /* build_info string array */
+  string_type = build_pointer_type (
+      build_qualified_type (char_type_node,
+                            TYPE_QUAL_CONST));
+  string_ptr_type = build_pointer_type
+    (build_qualified_type (string_type, TYPE_QUAL_CONST));
+  field = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+                      NULL_TREE, string_ptr_type);
+  DECL_CHAIN (field) = fields;
+  fields = field;
+
   finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
 }
 
@@ -2163,6 +2188,40 @@ build_gcov_module_info_value (tree mod_type)
   return mod_info;
 }
 
+/* Returns the value of the build info string read earlier.  */
+
+static tree
+build_gcov_build_info_value (void)
+{
+  tree build_info;
+  tree value = NULL_TREE;
+  tree string_type, index_type, string_array_type;
+  vec<constructor_elt,va_gc> *v = NULL;
+  char name_buf[50];
+
+  string_type = build_pointer_type (
+      build_qualified_type (char_type_node,
+                            TYPE_QUAL_CONST));
+  index_type = build_index_type (build_int_cst (NULL_TREE, num_build_info));
+  string_array_type = build_array_type (string_type, index_type);
+
+  build_str_array_value (string_type, &v,
+                         build_info_array_head);
+  value = build_constructor (string_array_type, v);
+
+  build_info = build_decl (BUILTINS_LOCATION, VAR_DECL,
+                         NULL_TREE, TREE_TYPE (value));
+  TREE_STATIC (build_info) = 1;
+  ASM_GENERATE_INTERNAL_LABEL (name_buf, "BUILDINFO", 0);
+  DECL_NAME (build_info) = get_identifier (name_buf);
+  DECL_INITIAL (build_info) = value;
+
+  /* Build structure.  */
+  varpool_finalize_decl (build_info);
+
+  return build_info;
+}
+
 /* Returns a CONSTRUCTOR for the gcov_info object.  INFO_TYPE is the
    gcov_info structure type, FN_ARY is the array of pointers to
    function info objects.  */
@@ -2174,6 +2233,7 @@ build_info (tree info_type, tree fn_ary)
   tree merge_fn_type, n_funcs;
   unsigned ix;
   tree mod_value = NULL_TREE;
+  tree buildinfo_value = NULL_TREE;
   tree filename_string;
   int da_file_name_len;
   vec<constructor_elt, va_gc> *v1 = NULL;
@@ -2256,6 +2316,18 @@ build_info (tree info_type, tree fn_ary)
                          build1 (ADDR_EXPR, TREE_TYPE (info_fields), fn_ary));
   info_fields = DECL_CHAIN (info_fields);
 
+  /* build_info string array */
+  if (num_build_info)
+    {
+      buildinfo_value = build_gcov_build_info_value ();
+      CONSTRUCTOR_APPEND_ELT (v1, info_fields,
+                              build1 (ADDR_EXPR, TREE_TYPE (info_fields),
+                                      buildinfo_value));
+    }
+  else
+    CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
+  info_fields = DECL_CHAIN (info_fields);
+
   gcc_assert (!info_fields);
   return build_constructor (info_type, v1);
 }
@@ -2286,6 +2358,62 @@ build_init_ctor (tree gcov_info_type)
   cgraph_build_static_cdtor ('I', ctor, DEFAULT_INIT_PRIORITY);
 }
 
+/* Add S to the end of the string-list, the head and tail of which are
+   pointed-to by HEAD and TAIL, respectively.  */
+
+static void
+str_list_append (struct str_list **head, struct str_list **tail, const char *s)
+{
+  struct str_list *e = XNEW (struct str_list);
+  e->str = XNEWVEC (char, strlen (s) + 1);
+  strcpy (e->str, s);
+  e->next = NULL;
+  if (*tail)
+    (*tail)->next = e;
+  else
+    *head = e;
+  *tail = e;
+}
+
+/* Read file specified to -fprofile-generate-buildinfo=filename option and
+   create a list of strings to include in build_info array.  */
+
+static void
+read_buildinfo (void)
+{
+  char buf[1024];
+  FILE *buildinfo = fopen (flag_profile_generate_buildinfo, "r");
+  if (!buildinfo)
+    {
+      error ("could not open -fprofile-generate-buildinfo file %qs: %m",
+             flag_profile_generate_buildinfo);
+    }
+
+  while (fgets (buf, sizeof buf, buildinfo) != NULL)
+    {
+      /* Remove end of line.  */
+      int len = strlen (buf);
+      if (len >= 1 && buf[len - 1] =='\n')
+        buf[len - 1] = '\0';
+      str_list_append (&build_info_array_head, &build_info_array_tail, buf);
+      num_build_info++;
+    }
+  /* Terminate with an empty string.  */
+  str_list_append (&build_info_array_head, &build_info_array_tail, "");
+  num_build_info++;
+  if (ferror (buildinfo))
+    {
+      error ("error reading -fprofile-generate-buildinfo file %qs: %m",
+             flag_profile_generate_buildinfo);
+    }
+
+  if (fclose (buildinfo))
+    {
+      error ("could not close -fprofile-generate-buildinfo file %qs: %m",
+             flag_profile_generate_buildinfo);
+    }
+}
+
 /* Create the gcov_info types and object. Does not generate the initializer
    for the object.  Returns TRUE if coverage data is being emitted.  */
 
@@ -2307,6 +2435,9 @@ coverage_obj_init (void)
   if (cgraph_dump_file)
     fprintf (cgraph_dump_file, "Using data file %s\n", da_file_name);
 
+  if (flag_profile_generate_buildinfo)
+    read_buildinfo ();
+
   /* Prune functions.  */
   if (!flag_dyn_ipa)
     /* in lipo mode, coverage_finish is called when function struct is cleared,
@@ -2812,23 +2943,6 @@ set_profile_parameters (struct cpp_reader *parse_i
   dump_finish (pass_profile.pass.static_pass_number);
 }
 
-/* Add S to the end of the string-list, the head and tail of which are
-   pointed-to by HEAD and TAIL, respectively.  */
-
-static void
-str_list_append (struct str_list **head, struct str_list **tail, const char *s)
-{
-  struct str_list *e = XNEW (struct str_list);
-  e->str = XNEWVEC (char, strlen (s) + 1);
-  strcpy (e->str, s);
-  e->next = NULL;
-  if (*tail)
-    (*tail)->next = e;
-  else
-    *head = e;
-  *tail = e;
-}
-
 /* Copies the macro def or undef CPP_DEF and saves the copy
    in a list. IS_DEF is a flag indicating if CPP_DEF represents
    a -D or -U.  */
Index: gcc/gcov.c
===================================================================
--- gcc/gcov.c  (revision 210862)
+++ gcc/gcov.c  (working copy)
@@ -1432,6 +1432,15 @@ read_count_file (function_t *fns)
        }
       else if (tag == GCOV_TAG_PARAMETERS)
         gcov_read_parameters (length);
+      else if (tag == GCOV_TAG_BUILD_INFO)
+        {
+          gcov_unsigned_t num_strings;
+          char **build_info_strings = gcov_read_build_info (length,
+                                                            &num_strings);
+          for (unsigned i = 0; i < num_strings; i++)
+            free (build_info_strings[i]);
+          free (build_info_strings);
+        }
       else if (tag == GCOV_TAG_FUNCTION && !length)
        ; /* placeholder  */
       else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
Index: gcc/gcov-dump.c
===================================================================
--- gcc/gcov-dump.c     (revision 210862)
+++ gcc/gcov-dump.c     (working copy)
@@ -40,6 +40,7 @@ static void tag_lines (const char *, unsigned, uns
 static void tag_counters (const char *, unsigned, unsigned);
 static void tag_summary (const char *, unsigned, unsigned);
 static void tag_parameters (const char *, unsigned, unsigned);
+static void tag_build_info (const char *, unsigned, unsigned);
 static void dump_working_sets (const char *filename ATTRIBUTE_UNUSED,
                                const struct gcov_ctr_summary *summary);
 static void tag_module_info (const char *, unsigned, unsigned);
@@ -80,6 +81,7 @@ static const tag_format_t tag_table[] =
   {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
   {GCOV_TAG_PARAMETERS, "PARAMETERS", tag_parameters},
   {GCOV_TAG_MODULE_INFO, "MODULE INFO", tag_module_info},
+  {GCOV_TAG_BUILD_INFO, "BUILD INFO", tag_build_info},
   {0, NULL, NULL}
 };
 
@@ -596,6 +598,28 @@ tag_module_info (const char *filename ATTRIBUTE_UN
 }
 
 static void
+tag_build_info (const char *filename,
+               unsigned tag ATTRIBUTE_UNUSED, unsigned length)
+{
+  gcov_unsigned_t num_strings = 0;
+  char **build_info_strings = gcov_read_build_info (length, &num_strings);
+  if (!build_info_strings)
+    {
+      printf ("%s:error reading build info\n", filename);
+      return;
+    }
+  printf (" num_strings=%u", num_strings);
+  for (unsigned i = 0; i < num_strings; i++)
+    {
+      printf ("\n");
+      print_prefix (filename, 0, 0);
+      printf ("\t\t%s", build_info_strings[i]);
+      free (build_info_strings[i]);
+    }
+  free (build_info_strings);
+}
+
+static void
 dump_working_sets (const char *filename ATTRIBUTE_UNUSED,
                    const struct gcov_ctr_summary *summary)
 {
Index: gcc/gcov-io.c
===================================================================
--- gcc/gcov-io.c       (revision 210862)
+++ gcc/gcov-io.c       (working copy)
@@ -341,6 +341,47 @@ gcov_write_unsigned (gcov_unsigned_t value)
   buffer[0] = value;
 }
 
+/* Compute the total length in words required to write NUM_STRINGS
+   in STRING_ARRAY as unsigned.  */
+
+GCOV_LINKAGE gcov_unsigned_t
+gcov_compute_string_array_len (char **string_array,
+                               gcov_unsigned_t num_strings)
+{
+  gcov_unsigned_t len = 0, i;
+  for (i = 0; i < num_strings; i++)
+    {
+      gcov_unsigned_t string_len
+          = (strlen (string_array[i]) + sizeof (gcov_unsigned_t))
+          / sizeof (gcov_unsigned_t);
+      len += string_len;
+      len += 1; /* Each string is lead by a length.  */
+    }
+  return len;
+}
+
+/* Write NUM_STRINGS in STRING_ARRAY as unsigned.  */
+
+GCOV_LINKAGE void
+gcov_write_string_array (char **string_array, gcov_unsigned_t num_strings)
+{
+  gcov_unsigned_t i, j;
+  for (j = 0; j < num_strings; j++)
+    {
+      gcov_unsigned_t *aligned_string;
+      gcov_unsigned_t string_len =
+       (strlen (string_array[j]) + sizeof (gcov_unsigned_t)) /
+       sizeof (gcov_unsigned_t);
+      aligned_string = (gcov_unsigned_t *)
+       alloca ((string_len + 1) * sizeof (gcov_unsigned_t));
+      memset (aligned_string, 0, (string_len + 1) * sizeof (gcov_unsigned_t));
+      aligned_string[0] = string_len;
+      strcpy ((char*) (aligned_string + 1), string_array[j]);
+      for (i = 0; i < (string_len + 1); i++)
+        gcov_write_unsigned (aligned_string[i]);
+    }
+}
+
 /* Write counter VALUE to coverage file.  Sets error flag
    appropriately.  */
 
@@ -701,6 +742,44 @@ gcov_read_summary (struct gcov_summary *summary)
     }
 }
 
+/* Read NUM_STRINGS strings (as an unsigned array) in STRING_ARRAY, and return
+   the number of words read.  */
+
+GCOV_LINKAGE gcov_unsigned_t
+gcov_read_string_array (char **string_array, gcov_unsigned_t num_strings)
+{
+  gcov_unsigned_t i, j, len = 0;
+
+  for (j = 0; j < num_strings; j++)
+   {
+     gcov_unsigned_t string_len = gcov_read_unsigned ();
+     string_array[j] =
+       (char *) xmalloc (string_len * sizeof (gcov_unsigned_t));
+     for (i = 0; i < string_len; i++)
+       ((gcov_unsigned_t *) string_array[j])[i] = gcov_read_unsigned ();
+     len += (string_len + 1);
+   }
+  return len;
+}
+
+/* Read LENGTH words (unsigned type) from a build info record with the number
+   of strings read saved in NUM_STRINGS.  Returns the string array, which
+   should be deallocated by caller, or NULL on error.  */
+
+GCOV_LINKAGE char **
+gcov_read_build_info (gcov_unsigned_t length, gcov_unsigned_t *num_strings)
+{
+  gcov_unsigned_t num = gcov_read_unsigned ();
+  char **build_info_strings = (char **)
+      xmalloc (sizeof (char *) * num);
+  gcov_unsigned_t len = gcov_read_string_array (build_info_strings,
+                                                num);
+  if (len != length - 1)
+    return NULL;
+  *num_strings = num;
+  return build_info_strings;
+}
+
 #if IN_GCOV_TOOL || !IN_LIBGCOV && IN_GCOV != 1
 /* Read LEN words (unsigned type) and construct MOD_INFO.  */
 
@@ -708,7 +787,7 @@ GCOV_LINKAGE void
 gcov_read_module_info (struct gcov_module_info *mod_info,
                        gcov_unsigned_t len)
 {
-  gcov_unsigned_t src_filename_len, filename_len, i, j, num_strings;
+  gcov_unsigned_t src_filename_len, filename_len, i, num_strings;
   mod_info->ident = gcov_read_unsigned ();
   mod_info->is_primary = gcov_read_unsigned ();
   mod_info->flags = gcov_read_unsigned ();
@@ -740,16 +819,7 @@ gcov_read_module_info (struct gcov_module_info *mo
     + mod_info->num_system_paths
     + mod_info->num_cpp_defines + mod_info->num_cpp_includes
     + mod_info->num_cl_args;
-  for (j = 0; j < num_strings; j++)
-   {
-     gcov_unsigned_t string_len = gcov_read_unsigned ();
-     mod_info->string_array[j] =
-       (char *) xmalloc (string_len * sizeof (gcov_unsigned_t));
-     for (i = 0; i < string_len; i++)
-       ((gcov_unsigned_t *) mod_info->string_array[j])[i] =
-        gcov_read_unsigned ();
-     len -= (string_len + 1);
-   }
+  len -= gcov_read_string_array (mod_info->string_array, num_strings);
   gcc_assert (!len);
 }
 #endif
Index: gcc/gcov-io.h
===================================================================
--- gcc/gcov-io.h       (revision 210862)
+++ gcc/gcov-io.h       (working copy)
@@ -129,7 +129,7 @@ see the files COPYING3 and COPYING.RUNTIME respect
    blocks they are for.
 
    The data file contains the following records.
-        data: {unit summary:program* parameter-data function-data*}*
+        data: {unit summary:program* build_info parameter-data function-data*}*
        unit: header int32:checksum
         function-data: announce_function present counts
        announce_function: header int32:ident
@@ -143,6 +143,7 @@ see the files COPYING3 and COPYING.RUNTIME respect
         histogram-buckets: int32:num int64:min int64:sum
         parameter-data: header parm-value*
         parm-value: string:macro_name int64:value
+        build_info: string:info*
 
    The ANNOUNCE_FUNCTION record is the same as that in the note file,
    but without the source location.  The COUNTS gives the
@@ -153,6 +154,11 @@ see the files COPYING3 and COPYING.RUNTIME respect
    each with a unique checksum.  Note that the data file might contain
    information from several runs concatenated, or the data might be merged.
 
+   BUILD_INFO record contains a list of strings that is used
+   to include in the data file information about the profile generate
+   build.  For example, it can be used to include source revision
+   information that is useful in diagnosing profile mis-matches.
+
    This file is included by both the compiler, gcov tools and the
    runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to
    distinguish which case is which.  If IN_LIBGCOV is nonzero,
@@ -259,6 +265,7 @@ typedef unsigned HOST_WIDEST_INT gcov_type_unsigne
 #define GCOV_TAG_SUMMARY_LENGTH(NUM)  \
         (1 + GCOV_COUNTERS_SUMMABLE * (10 + 3 * 2) + (NUM) * 5)
 #define GCOV_TAG_PARAMETERS    ((gcov_unsigned_t)0xa5000000)
+#define GCOV_TAG_BUILD_INFO ((gcov_unsigned_t)0xa7000000)
 #define GCOV_TAG_MODULE_INFO ((gcov_unsigned_t)0xab000000)
 #define GCOV_TAG_AFDO_FILE_NAMES ((gcov_unsigned_t)0xaa000000)
 #define GCOV_TAG_AFDO_FUNCTION ((gcov_unsigned_t)0xac000000)
@@ -468,11 +475,15 @@ GCOV_LINKAGE int gcov_close (void) ATTRIBUTE_HIDDE
 GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE gcov_type gcov_read_counter (void) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE void gcov_read_summary (struct gcov_summary *) ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE char **gcov_read_build_info (gcov_unsigned_t, gcov_unsigned_t *)
+  ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE struct gcov_parameter_value *gcov_read_parameters 
(gcov_unsigned_t)
   ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE const char *gcov_read_string (void);
 GCOV_LINKAGE void gcov_sync (gcov_position_t /*base*/,
                             gcov_unsigned_t /*length */);
+GCOV_LINKAGE gcov_unsigned_t gcov_read_string_array (char **, gcov_unsigned_t)
+  ATTRIBUTE_HIDDEN;
 
 #if !IN_LIBGCOV && IN_GCOV != 1
 GCOV_LINKAGE void gcov_read_module_info (struct gcov_module_info *mod_info,
@@ -482,6 +493,11 @@ GCOV_LINKAGE void gcov_read_module_info (struct gc
 #if !IN_GCOV
 /* Available outside gcov */
 GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t) ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE gcov_unsigned_t gcov_compute_string_array_len (char **,
+                                                            gcov_unsigned_t)
+  ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE void gcov_write_string_array (char **, gcov_unsigned_t)
+  ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE void gcov_write_string (const char *);
 #endif
 
Index: libgcc/dyn-ipa.c
===================================================================
--- libgcc/dyn-ipa.c    (revision 210862)
+++ libgcc/dyn-ipa.c    (working copy)
@@ -2233,7 +2233,7 @@ static void
 gcov_write_module_info (const struct gcov_info *mod_info,
                         unsigned is_primary)
 {
-  gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i, j;
+  gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i;
   gcov_unsigned_t num_strings;
   gcov_unsigned_t *aligned_fname;
   struct gcov_module_info  *module_info = mod_info->mod_info;
@@ -2248,14 +2248,8 @@ gcov_write_module_info (const struct gcov_info *mo
     + module_info->num_system_paths
     + module_info->num_cpp_defines + module_info->num_cpp_includes
     + module_info->num_cl_args;
-  for (i = 0; i < num_strings; i++)
-    {
-      gcov_unsigned_t string_len
-          = (strlen (module_info->string_array[i]) + sizeof (gcov_unsigned_t))
-          / sizeof (gcov_unsigned_t);
-      len += string_len;
-      len += 1; /* Each string is lead by a length.  */
-    }
+  len += gcov_compute_string_array_len (module_info->string_array,
+                                        num_strings);
 
   len += 11; /* 11 more fields */
 
@@ -2288,20 +2282,7 @@ gcov_write_module_info (const struct gcov_info *mo
     gcov_write_unsigned (aligned_fname[i]);
 
   /* Now write the string array.  */
-  for (j = 0; j < num_strings; j++)
-    {
-      gcov_unsigned_t *aligned_string;
-      gcov_unsigned_t string_len =
-       (strlen (module_info->string_array[j]) + sizeof (gcov_unsigned_t)) /
-       sizeof (gcov_unsigned_t);
-      aligned_string = (gcov_unsigned_t *)
-       alloca ((string_len + 1) * sizeof (gcov_unsigned_t));
-      memset (aligned_string, 0, (string_len + 1) * sizeof (gcov_unsigned_t));
-      aligned_string[0] = string_len;
-      strcpy ((char*) (aligned_string + 1), module_info->string_array[j]);
-      for (i = 0; i < (string_len + 1); i++)
-        gcov_write_unsigned (aligned_string[i]);
-    }
+  gcov_write_string_array (module_info->string_array, num_strings);
 }
 
 /* Write out MOD_INFO and its imported modules into gcda file.  */
Index: libgcc/libgcov-driver.c
===================================================================
--- libgcc/libgcov-driver.c     (revision 210862)
+++ libgcc/libgcov-driver.c     (working copy)
@@ -482,7 +482,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
                       struct gcov_parameter_value **merged_parameters)
 {
   gcov_unsigned_t tag, length, version, stamp;
-  unsigned t_ix, f_ix;
+  unsigned t_ix, f_ix, i;
   int error = 0;
   struct gcov_summary_buffer **sum_tail = &sum_buffer;
 
@@ -535,6 +535,36 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
     next_summary:;
     }
 
+  if (tag == GCOV_TAG_BUILD_INFO)
+    {
+      length = gcov_read_unsigned ();
+      gcov_unsigned_t num_strings = 0;
+      char **build_info_strings = gcov_read_build_info (length, &num_strings);
+      if (!build_info_strings)
+        {
+          gcov_error ("profiling:%s:Error reading build info\n", gi_filename);
+          return -1;
+        }
+
+      for (i = 0; i < num_strings; i++)
+        {
+          if (strcmp (build_info_strings[i], gi_ptr->build_info[i]))
+            {
+              gcov_error ("profiling:%s:Mismatched build info string "
+                          "(expected %s, read %s)\n",
+                          gi_filename, gi_ptr->build_info[i],
+                          build_info_strings[i]);
+              return -1;
+            }
+          free (build_info_strings[i]);
+        }
+      free (build_info_strings);
+
+      /* Since the stamps matched if we got here, this should be from
+         the same compilation and the build info strings should match.  */
+      tag = gcov_read_unsigned ();
+    }
+
   if (tag == GCOV_TAG_PARAMETERS)
     {
       length = gcov_read_unsigned ();
@@ -607,6 +637,28 @@ read_error:;
 }
 
 
+/* Write build_info strings from GI_PTR to a gcda file starting from its 
current
+   location.  */
+
+static void
+gcov_write_build_info (struct gcov_info *gi_ptr)
+{
+  gcov_unsigned_t num = 0;
+  gcov_unsigned_t len = 1;
+
+  if (!gi_ptr->build_info)
+    return;
+
+  /* Count the number of strings, which is terminated with an empty string.  */
+  while (gi_ptr->build_info[num][0])
+    num++;
+
+  len += gcov_compute_string_array_len (gi_ptr->build_info, num);
+  gcov_write_tag_length (GCOV_TAG_BUILD_INFO, len);
+  gcov_write_unsigned (num);
+  gcov_write_string_array (gi_ptr->build_info, num);
+}
+
 /* Write counters in GI_PTR to a gcda file starting from its current
    location.  */
 
@@ -693,6 +745,8 @@ gcov_exit_write_gcda (struct gcov_info *gi_ptr,
       sum_buffer = next_sum_buffer;
     }
 
+  gcov_write_build_info (gi_ptr);
+
   if (merged_parameters)
     {
       gcov_write_parameters (merged_parameters);
Index: libgcc/libgcov.h
===================================================================
--- libgcc/libgcov.h    (revision 210862)
+++ libgcc/libgcov.h    (working copy)
@@ -172,6 +172,7 @@ typedef unsigned gcov_type_unsigned __attribute__
 #define gcov_read_counter __gcov_read_counter
 #define gcov_read_summary __gcov_read_summary
 #define gcov_read_parameters __gcov_read_parameters
+#define gcov_read_buildinfo __gcov_read_buildinfo
 #define gcov_read_string __gcov_read_string
 #define gcov_read_module_info __gcov_read_module_info
 #define gcov_sort_n_vals __gcov_sort_n_vals
@@ -237,6 +238,8 @@ struct gcov_info
 #else
   const struct gcov_fn_info **functions;
 #endif /* !IN_GCOV_TOOL */
+  char **build_info;            /* strings to include in BUILD_INFO
+                                   section of gcda file.  */
 };
 
 /* Information about a single imported module.  */

Reply via email to