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 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 fields. (build_info): Ditto. (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, index_type, string_array_type; /* Version ident */ field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, @@ -1766,6 +1780,23 @@ build_info_type (tree type, tree fn_info_ptr_type) DECL_CHAIN (field) = fields; fields = field; + /* n_build_info */ + field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, + get_gcov_unsigned_t ()); + DECL_CHAIN (field) = fields; + fields = field; + + /* build_info string array */ + index_type = build_index_type (build_int_cst (NULL_TREE, num_build_info)); + string_type = build_pointer_type ( + build_qualified_type (char_type_node, + TYPE_QUAL_CONST)); + string_array_type = build_array_type (string_type, index_type); + field = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, string_array_type); + DECL_CHAIN (field) = fields; + fields = field; + finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE); } @@ -2178,6 +2209,7 @@ build_info (tree info_type, tree fn_ary) int da_file_name_len; vec *v1 = NULL; vec *v2 = NULL; + tree string_type, string_array_type; /* Version ident */ CONSTRUCTOR_APPEND_ELT (v1, info_fields, @@ -2204,6 +2236,7 @@ build_info (tree info_type, tree fn_ary) info_fields = DECL_CHAIN (info_fields); /* Filename */ + string_type = TREE_TYPE (info_fields); da_file_name_len = strlen (da_file_name); filename_string = build_string (da_file_name_len + 1, da_file_name); TREE_TYPE (filename_string) = build_array_type @@ -2256,6 +2289,21 @@ build_info (tree info_type, tree fn_ary) build1 (ADDR_EXPR, TREE_TYPE (info_fields), fn_ary)); info_fields = DECL_CHAIN (info_fields); + /* n_build_info */ + CONSTRUCTOR_APPEND_ELT (v1, info_fields, + build_int_cstu (TREE_TYPE (info_fields), + num_build_info)); + info_fields = DECL_CHAIN (info_fields); + + /* build_info string array */ + string_array_type = TREE_TYPE (info_fields); + vec *path_v = NULL; + build_str_array_value (string_type, &path_v, + build_info_array_head); + CONSTRUCTOR_APPEND_ELT (v1, info_fields, + build_constructor (string_array_type, path_v)); + info_fields = DECL_CHAIN (info_fields); + gcc_assert (!info_fields); return build_constructor (info_type, v1); } @@ -2286,6 +2334,59 @@ 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++; + } + 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 +2408,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 +2916,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,44 @@ 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; + } + /* The build info should match since the compile stamps matched above. */ + if (num_strings != gi_ptr->n_build_info) + { + gcov_error ("profiling:%s:Mismatched build info count (expected %u " + "strings, read %u)\n", + gi_filename, gi_ptr->n_build_info, num_strings); + 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 +645,23 @@ 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) +{ + if (gi_ptr->n_build_info) + { + gcov_unsigned_t len = 1; /* Number of strings. */ + len += gcov_compute_string_array_len (gi_ptr->build_info, + gi_ptr->n_build_info); + gcov_write_tag_length (GCOV_TAG_BUILD_INFO, len); + gcov_write_unsigned (gi_ptr->n_build_info); + gcov_write_string_array (gi_ptr->build_info, gi_ptr->n_build_info); + } +} + /* Write counters in GI_PTR to a gcda file starting from its current location. */ @@ -693,6 +748,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,9 @@ struct gcov_info #else const struct gcov_fn_info **functions; #endif /* !IN_GCOV_TOOL */ + unsigned n_build_info; /* number of build_info strings. */ + char *build_info[1]; /* strings to include in BUILD_INFO + section of gcda file. */ }; /* Information about a single imported module. */