diff options
author | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-12-30 18:08:56 +0000 |
---|---|---|
committer | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-12-30 18:08:56 +0000 |
commit | 6071b85b2e8962bbb12dc6cad177c19a440e84d8 (patch) | |
tree | c7ea31b85836773aaf801df12303fd2c6f04d6f3 /libgcc/libgcov.c | |
parent | 858d15ff4db1e4e00f7dc9bb78a748c7abdd007e (diff) | |
download | gcc-6071b85b2e8962bbb12dc6cad177c19a440e84d8.tar.gz |
* libgcov.c (gcov_crc32): Remove global var.
(free_fn_data): New function.
(buffer_fn_data): Pass in filename, more robust error recovery.
(crc32_unsigned): New function.
(gcov_exit): More robust detection of new program. More robust
error recovery.
(__gcov_init): Do not update program's crc here.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@182743 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgcc/libgcov.c')
-rw-r--r-- | libgcc/libgcov.c | 228 |
1 files changed, 135 insertions, 93 deletions
diff --git a/libgcc/libgcov.c b/libgcc/libgcov.c index f7691df967c..810175aafcf 100644 --- a/libgcc/libgcov.c +++ b/libgcc/libgcov.c @@ -89,10 +89,6 @@ struct gcov_fn_buffer /* Chain of per-object gcov structures. */ static struct gcov_info *gcov_list; -/* A program checksum allows us to distinguish program data for an - object file included in multiple programs. */ -static gcov_unsigned_t gcov_crc32; - /* Size of the longest file name. */ static size_t gcov_max_filename = 0; @@ -143,22 +139,41 @@ create_file_directory (char *filename) #endif } +static struct gcov_fn_buffer * +free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer, + unsigned limit) +{ + struct gcov_fn_buffer *next; + unsigned ix, n_ctr = 0; + + if (!buffer) + return 0; + next = buffer->next; + + for (ix = 0; ix != limit; ix++) + if (gi_ptr->merge[ix]) + free (buffer->info.ctrs[n_ctr++].values); + free (buffer); + return next; +} + static struct gcov_fn_buffer ** -buffer_fn_data (struct gcov_info *gi_ptr, struct gcov_fn_buffer **end_ptr, - unsigned fn_ix) +buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr, + struct gcov_fn_buffer **end_ptr, unsigned fn_ix) { - unsigned n_ctrs = 0, ix; + unsigned n_ctrs = 0, ix = 0; struct gcov_fn_buffer *fn_buffer; + unsigned len; for (ix = GCOV_COUNTERS; ix--;) if (gi_ptr->merge[ix]) n_ctrs++; - fn_buffer = (struct gcov_fn_buffer *)malloc - (sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs); + len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs; + fn_buffer = (struct gcov_fn_buffer *)malloc (len); if (!fn_buffer) - return 0; /* We'll horribly fail. */ + goto fail; fn_buffer->next = 0; fn_buffer->fn_ix = fn_ix; @@ -175,16 +190,17 @@ buffer_fn_data (struct gcov_info *gi_ptr, struct gcov_fn_buffer **end_ptr, continue; if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix)) - goto fail; - - length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ()); - values = (gcov_type *)malloc (length * sizeof (gcov_type)); - if (!values) { - while (n_ctrs--) - free (fn_buffer->info.ctrs[n_ctrs].values); + len = 0; goto fail; } + + length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ()); + len = length * sizeof (gcov_type); + values = (gcov_type *)malloc (len); + if (!values) + goto fail; + fn_buffer->info.ctrs[n_ctrs].num = length; fn_buffer->info.ctrs[n_ctrs].values = values; @@ -197,8 +213,29 @@ buffer_fn_data (struct gcov_info *gi_ptr, struct gcov_fn_buffer **end_ptr, return &fn_buffer->next; fail: - free (fn_buffer); - return 0; + fprintf (stderr, "profiling:%s: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 */ + +static gcov_unsigned_t +crc32_unsigned (gcov_unsigned_t crc32, gcov_unsigned_t value) +{ + unsigned ix; + + for (ix = 32; ix--; value <<= 1) + { + unsigned feedback; + + feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0; + crc32 <<= 1; + crc32 ^= feedback; + } + + return crc32; } /* Check if VERSION of the info block PTR matches libgcov one. @@ -241,41 +278,56 @@ gcov_exit (void) struct gcov_summary all_prg; /* summary for all instances of program. */ struct gcov_ctr_summary *cs_ptr; const struct gcov_ctr_info *ci_ptr; - unsigned t_ix, f_ix; + unsigned t_ix; + int f_ix; gcov_unsigned_t c_num; const char *gcov_prefix; int gcov_prefix_strip = 0; size_t prefix_length; char *gi_filename, *gi_filename_up; + gcov_unsigned_t crc32 = 0; memset (&all_prg, 0, sizeof (all_prg)); /* Find the totals for this execution. */ memset (&this_prg, 0, sizeof (this_prg)); for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) - 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; - for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++) - { - if (!gi_ptr->merge[t_ix]) - continue; + { + 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]; - cs_ptr = &this_prg.ctrs[t_ix]; - cs_ptr->num += 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++; - } - } + 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++; + } + } + } { /* Check if the level of dirs to strip off specified. */ @@ -400,7 +452,7 @@ gcov_exit (void) goto rewrite; /* Look for program summary. */ - for (f_ix = ~0u;;) + for (f_ix = 0;;) { struct gcov_summary tmp; @@ -409,29 +461,35 @@ gcov_exit (void) if (tag != GCOV_TAG_PROGRAM_SUMMARY) break; + f_ix--; length = gcov_read_unsigned (); if (length != GCOV_TAG_SUMMARY_LENGTH) goto read_mismatch; gcov_read_summary (&tmp); if ((error = gcov_is_error ())) goto read_error; - if (!summary_pos && tmp.checksum == gcov_crc32) - { - prg = tmp; - summary_pos = eof_pos; - } + if (summary_pos || 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 = tmp; + summary_pos = eof_pos; + + next_summary:; } /* Merge execution counts for each function. */ - for (f_ix = 0; f_ix != gi_ptr->n_functions; + for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++, tag = gcov_read_unsigned ()) { gfi_ptr = gi_ptr->functions[f_ix]; if (tag != GCOV_TAG_FUNCTION) goto read_mismatch; - length = gcov_read_unsigned (); + length = gcov_read_unsigned (); if (!length) /* This function did not appear in the other program. We have nothing to merge. */ @@ -447,15 +505,23 @@ gcov_exit (void) it back out -- we'll be inserting data before this point, so cannot simply keep the data in the file. */ - fn_tail = buffer_fn_data (gi_ptr, fn_tail, f_ix); + fn_tail = buffer_fn_data (gi_filename, + gi_ptr, fn_tail, f_ix); if (!fn_tail) goto read_mismatch; continue; } - if (gcov_read_unsigned () != gfi_ptr->ident - || gcov_read_unsigned () != gfi_ptr->lineno_checksum - || gcov_read_unsigned () != gfi_ptr->cfg_checksum) + length = gcov_read_unsigned (); + if (length != gfi_ptr->ident) + goto read_mismatch; + + length = gcov_read_unsigned (); + if (length != gfi_ptr->lineno_checksum) + goto read_mismatch; + + length = gcov_read_unsigned (); + if (length != gfi_ptr->cfg_checksum) goto read_mismatch; ci_ptr = gfi_ptr->ctrs; @@ -481,8 +547,9 @@ gcov_exit (void) if (tag) { read_mismatch:; - fprintf (stderr, "profiling:%s:Merge mismatch for %s\n", - gi_filename, f_ix + 1 ? "function" : "summaries"); + fprintf (stderr, "profiling:%s:Merge mismatch for %s %u\n", + gi_filename, f_ix >= 0 ? "function" : "summary", + f_ix < 0 ? -1 - f_ix : f_ix); goto read_fatal; } } @@ -492,9 +559,7 @@ gcov_exit (void) fprintf (stderr, "profiling:%s:%s merging\n", gi_filename, error < 0 ? "Overflow": "Error"); - read_fatal:; - gcov_close (); - continue; + goto read_fatal; rewrite:; gcov_rewrite (); @@ -515,8 +580,6 @@ gcov_exit (void) { if (!cs_prg->runs++) cs_prg->num = cs_tprg->num; - else if (cs_prg->num != cs_tprg->num) - goto read_mismatch; 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; @@ -538,7 +601,7 @@ gcov_exit (void) } } - prg.checksum = gcov_crc32; + prg.checksum = crc32; /* Write out the data. */ if (!eof_pos) @@ -557,11 +620,11 @@ gcov_exit (void) gcov_seek (eof_pos); /* Write execution counts for each function. */ - for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) + for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++) { unsigned buffered = 0; - if (fn_buffer && fn_buffer->fn_ix == f_ix) + if (fn_buffer && fn_buffer->fn_ix == (unsigned)f_ix) { /* Buffered data from another program. */ buffered = 1; @@ -597,19 +660,18 @@ gcov_exit (void) gcov_type *c_ptr = ci_ptr->values; while (n_counts--) gcov_write_counter (*c_ptr++); - if (buffered) - free (ci_ptr->values); ci_ptr++; } if (buffered) - { - struct gcov_fn_buffer *tmp = fn_buffer; - fn_buffer = fn_buffer->next; - free (tmp); - } + fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); } gcov_write_unsigned (0); + + read_fatal:; + while (fn_buffer) + fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); + if ((error = gcov_close ())) fprintf (stderr, error < 0 ? "profiling:%s:Overflow writing\n" : @@ -628,32 +690,12 @@ __gcov_init (struct gcov_info *info) return; if (gcov_version (info, info->version, 0)) { - const char *ptr = info->filename; - gcov_unsigned_t crc32 = gcov_crc32; - size_t filename_length = strlen(info->filename); + size_t filename_length = strlen(info->filename); /* Refresh the longest file name information */ if (filename_length > gcov_max_filename) gcov_max_filename = filename_length; - do - { - unsigned ix; - gcov_unsigned_t value = *ptr << 24; - - for (ix = 8; ix--; value <<= 1) - { - gcov_unsigned_t feedback; - - feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0; - crc32 <<= 1; - crc32 ^= feedback; - } - } - while (*ptr++); - - gcov_crc32 = crc32; - if (!gcov_list) atexit (gcov_exit); |