X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=libgcc%2Flibgcov-driver.c;h=e53e4dc392a0cd6c4d0d90ff79385c1d5bb9086f;hb=1e9f339d946b8296e3785bec77e03d71b487d689;hp=9c4eeca0163714c4275b355bfb23d6007f515da4;hpb=818ab71a415cd234be092111a0aa5e812ec56434;p=gcc.git diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c index 9c4eeca0163..e53e4dc392a 100644 --- a/libgcc/libgcov-driver.c +++ b/libgcc/libgcov-driver.c @@ -1,6 +1,6 @@ /* Routines required for instrumenting a program. */ /* Compile this one with gcc. */ -/* Copyright (C) 1989-2016 Free Software Foundation, Inc. +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. This file is part of GCC. @@ -24,6 +24,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ #include "libgcov.h" +#include "gcov-io.h" #if defined(inhibit_libc) /* If libc and its header files are not available, provide dummy functions. */ @@ -43,11 +44,17 @@ void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {} #ifdef L_gcov -/* A utility function for outputing errors. */ +/* A utility function for outputting errors. */ static int gcov_error (const char *, ...); +#if !IN_GCOV_TOOL +static void gcov_error_exit (void); +#endif + #include "gcov-io.c" +#define GCOV_PROF_PREFIX "libgcov profiling error:%s:" + struct gcov_fn_buffer { struct gcov_fn_buffer *next; @@ -68,9 +75,8 @@ struct gcov_summary_buffer struct gcov_filename { char *filename; /* filename buffer */ - size_t max_length; /* maximum filename length */ int strip; /* leading chars to strip from filename */ - size_t prefix; /* chars to prepend to filename */ + char *prefix; /* prefix string */ }; static struct gcov_fn_buffer * @@ -147,29 +153,31 @@ buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr, return &fn_buffer->next; fail: - gcov_error ("profiling:%s:Function %u %s %u \n", filename, fn_ix, + gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix, len ? "cannot allocate" : "counter mismatch", len ? len : ix); return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix); } -/* Add an unsigned value to the current crc */ +/* Convert VERSION into a string description and return the it. + BUFFER is used for storage of the string. The code should be + aligned wit gcov-iov.c. */ -static gcov_unsigned_t -crc32_unsigned (gcov_unsigned_t crc32, gcov_unsigned_t value) +static char * +gcov_version_string (char *buffer, char version[4]) { - unsigned ix; - - for (ix = 32; ix--; value <<= 1) + if (version[0] < 'A' || version[0] > 'Z' + || version[1] < '0' || version[1] > '9' + || version[2] < '0' || version[2] > '9') + sprintf (buffer, "(unknown)"); + else { - unsigned feedback; - - feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0; - crc32 <<= 1; - crc32 ^= feedback; + unsigned major = 10 * (version[0] - 'A') + (version[1] - '0'); + unsigned minor = version[2] - '0'; + sprintf (buffer, "%u.%u (%s)", major, minor, + version[3] == '*' ? "release" : "experimental"); } - - return crc32; + return buffer; } /* Check if VERSION of the info block PTR matches libgcov one. @@ -184,160 +192,23 @@ gcov_version (struct gcov_info *ptr, gcov_unsigned_t version, if (version != GCOV_VERSION) { char v[4], e[4]; + char version_string[128], expected_string[128]; GCOV_UNSIGNED2STRING (v, version); GCOV_UNSIGNED2STRING (e, GCOV_VERSION); - gcov_error ("profiling:%s:Version mismatch - expected %.4s got %.4s\n", - filename? filename : ptr->filename, e, v); + gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) " + "got %s (%.4s)\n", + filename? filename : ptr->filename, + gcov_version_string (expected_string, e), e, + gcov_version_string (version_string, v), v); return 0; } return 1; } -/* Insert counter VALUE into HISTOGRAM. */ - -static void -gcov_histogram_insert(gcov_bucket_type *histogram, gcov_type value) -{ - unsigned i; - - i = gcov_histo_index(value); - histogram[i].num_counters++; - histogram[i].cum_value += value; - if (value < histogram[i].min_value) - histogram[i].min_value = value; -} - -/* Computes a histogram of the arc counters to place in the summary SUM. */ - -static void -gcov_compute_histogram (struct gcov_info *list, struct gcov_summary *sum) -{ - struct gcov_info *gi_ptr; - const struct gcov_fn_info *gfi_ptr; - const struct gcov_ctr_info *ci_ptr; - struct gcov_ctr_summary *cs_ptr; - unsigned t_ix, f_ix, ctr_info_ix, ix; - int h_ix; - - /* This currently only applies to arc counters. */ - t_ix = GCOV_COUNTER_ARCS; - - /* First check if there are any counts recorded for this counter. */ - cs_ptr = &(sum->ctrs[t_ix]); - if (!cs_ptr->num) - return; - - for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++) - { - cs_ptr->histogram[h_ix].num_counters = 0; - cs_ptr->histogram[h_ix].min_value = cs_ptr->run_max; - cs_ptr->histogram[h_ix].cum_value = 0; - } - - /* Walk through all the per-object structures and record each of - the count values in histogram. */ - for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) - { - if (!gi_ptr->merge[t_ix]) - continue; - - /* Find the appropriate index into the gcov_ctr_info array - for the counter we are currently working on based on the - existence of the merge function pointer for this object. */ - for (ix = 0, ctr_info_ix = 0; ix < t_ix; ix++) - { - if (gi_ptr->merge[ix]) - ctr_info_ix++; - } - for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++) - { - gfi_ptr = gi_ptr->functions[f_ix]; - - if (!gfi_ptr || gfi_ptr->key != gi_ptr) - continue; - - ci_ptr = &gfi_ptr->ctrs[ctr_info_ix]; - for (ix = 0; ix < ci_ptr->num; ix++) - gcov_histogram_insert (cs_ptr->histogram, ci_ptr->values[ix]); - } - } -} - /* buffer for the fn_data from another program. */ static struct gcov_fn_buffer *fn_buffer; -/* buffer for summary from other programs to be written out. */ -static struct gcov_summary_buffer *sum_buffer; - -/* This function computes the program level summary and the histo-gram. - It computes and returns CRC32 and stored summary in THIS_PRG. - Also determines the longest filename length of the info files. */ - -#if !IN_GCOV_TOOL -static -#endif -gcov_unsigned_t -compute_summary (struct gcov_info *list, struct gcov_summary *this_prg, - size_t *max_length) -{ - struct gcov_info *gi_ptr; - const struct gcov_fn_info *gfi_ptr; - struct gcov_ctr_summary *cs_ptr; - const struct gcov_ctr_info *ci_ptr; - int f_ix; - unsigned t_ix; - gcov_unsigned_t c_num; - gcov_unsigned_t crc32 = 0; - - /* Find the totals for this execution. */ - memset (this_prg, 0, sizeof (*this_prg)); - *max_length = 0; - for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) - { - size_t len = strlen (gi_ptr->filename); - if (len > *max_length) - *max_length = len; - - crc32 = crc32_unsigned (crc32, gi_ptr->stamp); - crc32 = crc32_unsigned (crc32, gi_ptr->n_functions); - - for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++) - { - gfi_ptr = gi_ptr->functions[f_ix]; - - if (gfi_ptr && gfi_ptr->key != gi_ptr) - gfi_ptr = 0; - - crc32 = crc32_unsigned (crc32, gfi_ptr ? gfi_ptr->cfg_checksum : 0); - crc32 = crc32_unsigned (crc32, - gfi_ptr ? gfi_ptr->lineno_checksum : 0); - if (!gfi_ptr) - continue; - - ci_ptr = gfi_ptr->ctrs; - for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++) - { - if (!gi_ptr->merge[t_ix]) - continue; - - cs_ptr = &(this_prg->ctrs[t_ix]); - cs_ptr->num += ci_ptr->num; - crc32 = crc32_unsigned (crc32, ci_ptr->num); - - for (c_num = 0; c_num < ci_ptr->num; c_num++) - { - cs_ptr->sum_all += ci_ptr->values[c_num]; - if (cs_ptr->run_max < ci_ptr->values[c_num]) - cs_ptr->run_max = ci_ptr->values[c_num]; - } - ci_ptr++; - } - } - } - gcov_compute_histogram (list, this_prg); - return crc32; -} /* Including system dependent components. */ #include "libgcov-driver-system.c" @@ -349,18 +220,13 @@ compute_summary (struct gcov_info *list, struct gcov_summary *this_prg, static int merge_one_data (const char *filename, struct gcov_info *gi_ptr, - struct gcov_summary *prg_p, - struct gcov_summary *this_prg, - gcov_position_t *summary_pos_p, - gcov_position_t *eof_pos_p, - gcov_unsigned_t crc32) + struct gcov_summary *summary) { gcov_unsigned_t tag, length; unsigned t_ix; - int f_ix; + int f_ix = -1; int error = 0; struct gcov_fn_buffer **fn_tail = &fn_buffer; - struct gcov_summary_buffer **sum_tail = &sum_buffer; length = gcov_read_unsigned (); if (!gcov_version (gi_ptr, length, filename)) @@ -368,50 +234,21 @@ merge_one_data (const char *filename, length = gcov_read_unsigned (); if (length != gi_ptr->stamp) - /* Read from a different compilation. Overwrite the file. */ - return 0; - - /* Look for program summary. */ - for (f_ix = 0;;) { - struct gcov_summary tmp; - - *eof_pos_p = gcov_position (); - tag = gcov_read_unsigned (); - if (tag != GCOV_TAG_PROGRAM_SUMMARY) - break; - - f_ix--; - length = gcov_read_unsigned (); - gcov_read_summary (&tmp); - if ((error = gcov_is_error ())) - goto read_error; - if (*summary_pos_p) - { - /* Save all summaries after the one that will be - merged into below. These will need to be rewritten - as histogram merging may change the number of non-zero - histogram entries that will be emitted, and thus the - size of the merged summary. */ - (*sum_tail) = (struct gcov_summary_buffer *) - xmalloc (sizeof(struct gcov_summary_buffer)); - (*sum_tail)->summary = tmp; - (*sum_tail)->next = 0; - sum_tail = &((*sum_tail)->next); - goto next_summary; - } - if (tmp.checksum != crc32) - goto next_summary; - - for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++) - if (tmp.ctrs[t_ix].num != this_prg->ctrs[t_ix].num) - goto next_summary; - *prg_p = tmp; - *summary_pos_p = *eof_pos_p; - - next_summary:; + /* Read from a different compilation. Overwrite the file. */ + gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data " + "with a different timestamp\n", filename); + return 0; } + tag = gcov_read_unsigned (); + if (tag != GCOV_TAG_OBJECT_SUMMARY) + goto read_mismatch; + length = gcov_read_unsigned (); + gcc_assert (length > 0); + gcov_read_summary (summary); + + tag = gcov_read_unsigned (); /* Merge execution counts for each function. */ for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++, tag = gcov_read_unsigned ()) @@ -464,22 +301,27 @@ merge_one_data (const char *filename, if (!merge) continue; - tag = gcov_read_unsigned (); - length = gcov_read_unsigned (); - if (tag != GCOV_TAG_FOR_COUNTER (t_ix) - || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num)) - goto read_mismatch; - (*merge) (ci_ptr->values, ci_ptr->num); - ci_ptr++; - } + tag = gcov_read_unsigned (); + int read_length = (int)gcov_read_unsigned (); + length = abs (read_length); + if (tag != GCOV_TAG_FOR_COUNTER (t_ix) + || (length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num) + && t_ix != GCOV_COUNTER_V_TOPN + && t_ix != GCOV_COUNTER_V_INDIR)) + goto read_mismatch; + /* Merging with all zero counters does not make sense. */ + if (read_length > 0) + (*merge) (ci_ptr->values, ci_ptr->num); + ci_ptr++; + } if ((error = gcov_is_error ())) - goto read_error; + goto read_error; } if (tag) { read_mismatch:; - gcov_error ("profiling:%s:Merge mismatch for %s %u\n", + gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n", filename, f_ix >= 0 ? "function" : "summary", f_ix < 0 ? -1 - f_ix : f_ix); return -1; @@ -487,49 +329,57 @@ merge_one_data (const char *filename, return 0; read_error: - gcov_error ("profiling:%s:%s merging\n", filename, + gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename, error < 0 ? "Overflow": "Error"); return -1; } +/* Store all TOP N counters where each has a dynamic length. */ + +static void +write_top_counters (const struct gcov_ctr_info *ci_ptr, + unsigned t_ix, + gcov_unsigned_t n_counts) +{ + unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS; + gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0); + unsigned pair_total = 0; + for (unsigned i = 0; i < counters; i++) + pair_total += ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 1]; + unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_total; + gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix), + GCOV_TAG_COUNTER_LENGTH (disk_size)); + + for (unsigned i = 0; i < counters; i++) + { + gcov_type pair_count = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 1]; + gcov_write_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i]); + gcov_write_counter (pair_count); + gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2]; + for (struct gcov_kvp *node = (struct gcov_kvp *)(intptr_t)start; + node != NULL; node = node->next) + { + gcov_write_counter (node->value); + gcov_write_counter (node->count); + } + } +} + /* Write counters in GI_PTR and the summary in PRG to a gcda file. In the case of appending to an existing file, SUMMARY_POS will be non-zero. We will write the file starting from SUMMAY_POS. */ static void write_one_data (const struct gcov_info *gi_ptr, - const struct gcov_summary *prg_p, - const gcov_position_t eof_pos, - const gcov_position_t summary_pos) + const struct gcov_summary *prg_p) { unsigned f_ix; - struct gcov_summary_buffer *next_sum_buffer; - - /* Write out the data. */ - if (!eof_pos) - { - gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION); - gcov_write_unsigned (gi_ptr->stamp); - } - if (summary_pos) - gcov_seek (summary_pos); + gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION); + gcov_write_unsigned (gi_ptr->stamp); /* Generate whole program statistics. */ - gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, prg_p); - - /* Rewrite all the summaries that were after the summary we merged - into. This is necessary as the merged summary may have a different - size due to the number of non-zero histogram entries changing after - merging. */ - - while (sum_buffer) - { - gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary); - next_sum_buffer = sum_buffer->next; - free (sum_buffer); - sum_buffer = next_sum_buffer; - } + gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p); /* Write execution counts for each function. */ for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++) @@ -567,20 +417,40 @@ write_one_data (const struct gcov_info *gi_ptr, ci_ptr = gfi_ptr->ctrs; for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) { - gcov_unsigned_t n_counts; - gcov_type *c_ptr; + gcov_position_t n_counts; - if (!gi_ptr->merge[t_ix]) - continue; + if (!gi_ptr->merge[t_ix]) + continue; - n_counts = ci_ptr->num; - gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix), - GCOV_TAG_COUNTER_LENGTH (n_counts)); - c_ptr = ci_ptr->values; - while (n_counts--) - gcov_write_counter (*c_ptr++); - ci_ptr++; - } + n_counts = ci_ptr->num; + + if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR) + write_top_counters (ci_ptr, t_ix, n_counts); + else + { + /* Do not stream when all counters are zero. */ + int all_zeros = 1; + for (unsigned i = 0; i < n_counts; i++) + if (ci_ptr->values[i] != 0) + { + all_zeros = 0; + break; + } + + if (all_zeros) + gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix), + GCOV_TAG_COUNTER_LENGTH (-n_counts)); + else + { + gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix), + GCOV_TAG_COUNTER_LENGTH (n_counts)); + for (unsigned i = 0; i < n_counts; i++) + gcov_write_counter (ci_ptr->values[i]); + } + } + + ci_ptr++; + } if (buffered) fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); } @@ -588,165 +458,6 @@ write_one_data (const struct gcov_info *gi_ptr, gcov_write_unsigned (0); } -/* Helper function for merging summary. - Return -1 on error. Return 0 on success. */ - -static int -merge_summary (const char *filename, int run_counted, - const struct gcov_info *gi_ptr, struct gcov_summary *prg, - struct gcov_summary *this_prg, gcov_unsigned_t crc32, - struct gcov_summary *all_prg __attribute__ ((unused))) -{ - struct gcov_ctr_summary *cs_prg, *cs_tprg; - unsigned t_ix; -#if !GCOV_LOCKED - /* summary for all instances of program. */ - struct gcov_ctr_summary *cs_all; -#endif - - /* Merge the summaries. */ - for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) - { - cs_prg = &(prg->ctrs[t_ix]); - cs_tprg = &(this_prg->ctrs[t_ix]); - - if (gi_ptr->merge[t_ix]) - { - int first = !cs_prg->runs; - - if (!run_counted) - cs_prg->runs++; - if (first) - cs_prg->num = cs_tprg->num; - cs_prg->sum_all += cs_tprg->sum_all; - if (cs_prg->run_max < cs_tprg->run_max) - cs_prg->run_max = cs_tprg->run_max; - cs_prg->sum_max += cs_tprg->run_max; - if (first) - memcpy (cs_prg->histogram, cs_tprg->histogram, - sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE); - else - gcov_histogram_merge (cs_prg->histogram, cs_tprg->histogram); - } - else if (cs_prg->runs) - { - gcov_error ("profiling:%s:Merge mismatch for summary.\n", - filename); - return -1; - } -#if !GCOV_LOCKED - cs_all = &all_prg->ctrs[t_ix]; - if (!cs_all->runs && cs_prg->runs) - { - cs_all->num = cs_prg->num; - cs_all->runs = cs_prg->runs; - cs_all->sum_all = cs_prg->sum_all; - cs_all->run_max = cs_prg->run_max; - cs_all->sum_max = cs_prg->sum_max; - } - else if (!all_prg->checksum - /* Don't compare the histograms, which may have slight - variations depending on the order they were updated - due to the truncating integer divides used in the - merge. */ - && (cs_all->num != cs_prg->num - || cs_all->runs != cs_prg->runs - || cs_all->sum_all != cs_prg->sum_all - || cs_all->run_max != cs_prg->run_max - || cs_all->sum_max != cs_prg->sum_max)) - { - gcov_error ("profiling:%s:Data file mismatch - some " - "data files may have been concurrently " - "updated without locking support\n", filename); - all_prg->checksum = ~0u; - } -#endif - } - - prg->checksum = crc32; - - return 0; -} - - -/* Sort N entries in VALUE_ARRAY in descending order. - Each entry in VALUE_ARRAY has two values. The sorting - is based on the second value. */ - -GCOV_LINKAGE void -gcov_sort_n_vals (gcov_type *value_array, int n) -{ - int j, k; - - for (j = 2; j < n; j += 2) - { - gcov_type cur_ent[2]; - - cur_ent[0] = value_array[j]; - cur_ent[1] = value_array[j + 1]; - k = j - 2; - while (k >= 0 && value_array[k + 1] < cur_ent[1]) - { - value_array[k + 2] = value_array[k]; - value_array[k + 3] = value_array[k+1]; - k -= 2; - } - value_array[k + 2] = cur_ent[0]; - value_array[k + 3] = cur_ent[1]; - } -} - -/* Sort the profile counters for all indirect call sites. Counters - for each call site are allocated in array COUNTERS. */ - -static void -gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters) -{ - int i; - gcov_type *values; - int n = counters->num; - - gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS)); - values = counters->values; - - for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS) - { - gcov_type *value_array = &values[i + 1]; - gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1); - } -} - -/* Sort topn indirect_call profile counters in GI_PTR. */ - -static void -gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr) -{ - unsigned int i; - int f_ix; - const struct gcov_fn_info *gfi_ptr; - const struct gcov_ctr_info *ci_ptr; - - if (!gi_ptr->merge[GCOV_COUNTER_ICALL_TOPNV]) - return; - - for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++) - { - gfi_ptr = gi_ptr->functions[f_ix]; - ci_ptr = gfi_ptr->ctrs; - for (i = 0; i < GCOV_COUNTERS; i++) - { - if (!gi_ptr->merge[i]) - continue; - if (i == GCOV_COUNTER_ICALL_TOPNV) - { - gcov_sort_icall_topn_counter (ci_ptr); - break; - } - ci_ptr++; - } - } -} - /* Dump the coverage counts for one gcov_info object. We merge with existing counts when possible, to avoid growing the .da files ad infinitum. We use this program's checksum to make sure we only accumulate whole program @@ -756,20 +467,13 @@ gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr) static void dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf, - unsigned run_counted, - gcov_unsigned_t crc32, struct gcov_summary *all_prg, - struct gcov_summary *this_prg) + unsigned run_counted ATTRIBUTE_UNUSED, + gcov_type run_max ATTRIBUTE_UNUSED) { - struct gcov_summary prg; /* summary for this object over all program. */ + struct gcov_summary summary = {}; int error; gcov_unsigned_t tag; - gcov_position_t summary_pos = 0; - gcov_position_t eof_pos = 0; - fn_buffer = 0; - sum_buffer = 0; - - gcov_sort_topn_counter_arrays (gi_ptr); error = gcov_exit_open_gcda_file (gi_ptr, gf); if (error == -1) @@ -781,29 +485,28 @@ dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf, /* Merge data from file. */ if (tag != GCOV_DATA_MAGIC) { - gcov_error ("profiling:%s:Not a gcov data file\n", gf->filename); + gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n", + gf->filename); goto read_fatal; } - error = merge_one_data (gf->filename, gi_ptr, &prg, this_prg, - &summary_pos, &eof_pos, crc32); + error = merge_one_data (gf->filename, gi_ptr, &summary); if (error == -1) goto read_fatal; } gcov_rewrite (); - if (!summary_pos) +#if !IN_GCOV_TOOL + if (!run_counted) { - memset (&prg, 0, sizeof (prg)); - summary_pos = eof_pos; + summary.runs++; + summary.sum_max += run_max; } +#else + summary = gi_ptr->summary; +#endif - error = merge_summary (gf->filename, run_counted, gi_ptr, &prg, this_prg, - crc32, all_prg); - if (error == -1) - goto read_fatal; - - write_one_data (gi_ptr, &prg, eof_pos, summary_pos); + write_one_data (gi_ptr, &summary); /* fall through */ read_fatal:; @@ -812,8 +515,8 @@ read_fatal:; if ((error = gcov_close ())) gcov_error (error < 0 ? - "profiling:%s:Overflow writing\n" : - "profiling:%s:Error writing\n", + GCOV_PROF_PREFIX "Overflow writing\n" : + GCOV_PROF_PREFIX "Error writing\n", gf->filename); } @@ -830,24 +533,41 @@ gcov_do_dump (struct gcov_info *list, int run_counted) { struct gcov_info *gi_ptr; struct gcov_filename gf; - gcov_unsigned_t crc32; - struct gcov_summary all_prg; - struct gcov_summary this_prg; - crc32 = compute_summary (list, &this_prg, &gf.max_length); + /* Compute run_max of this program run. */ + gcov_type run_max = 0; + for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) + for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++) + { + const struct gcov_ctr_info *cinfo + = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS]; + + for (unsigned i = 0; i < cinfo->num; i++) + if (run_max < cinfo->values[i]) + run_max = cinfo->values[i]; + } allocate_filename_struct (&gf); -#if !GCOV_LOCKED - memset (&all_prg, 0, sizeof (all_prg)); -#endif /* Now merge each file. */ for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next) - dump_one_gcov (gi_ptr, &gf, run_counted, crc32, &all_prg, &this_prg); + { + dump_one_gcov (gi_ptr, &gf, run_counted, run_max); + free (gf.filename); + } - free (gf.filename); + free (gf.prefix); } +#if IN_GCOV_TOOL +const char * +__attribute__ ((unused)) +gcov_get_filename (struct gcov_info *list) +{ + return list->filename; +} +#endif + #if !IN_GCOV_TOOL void __gcov_dump_one (struct gcov_root *root) @@ -868,8 +588,14 @@ struct gcov_root __gcov_root; struct gcov_master __gcov_master = {GCOV_VERSION, 0}; -static void -gcov_exit (void) +/* Pool of pre-allocated gcov_kvp strutures. */ +struct gcov_kvp __gcov_kvp_pool[GCOV_PREALLOCATED_KVP]; + +/* Index to first free gcov_kvp in the pool. */ +unsigned __gcov_kvp_pool_index; + +void +__gcov_exit (void) { __gcov_dump_one (&__gcov_root); if (__gcov_root.next) @@ -878,6 +604,8 @@ gcov_exit (void) __gcov_root.prev->next = __gcov_root.next; else __gcov_master.root = __gcov_root.next; + + gcov_error_exit (); } /* Add a new object file onto the bb chain. Invoked automatically @@ -900,7 +628,6 @@ __gcov_init (struct gcov_info *info) __gcov_master.root->prev = &__gcov_root; __gcov_master.root = &__gcov_root; } - atexit (gcov_exit); } info->next = __gcov_root.list;