libgcov.c (gcov_crc32): Remove global var.

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

From-SVN: r182743
This commit is contained in:
Nathan Sidwell 2011-12-30 18:08:56 +00:00 committed by Nathan Sidwell
parent 84de2982de
commit 04dbc287a6
2 changed files with 146 additions and 94 deletions

View file

@ -1,3 +1,13 @@
2011-12-30 Nathan Sidwell <nathan@acm.org>
* 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.
2011-12-21 Tristan Gingold <gingold@adacore.com>
* config/ia64/fde-vms.c (UNW_IVMS_MODE): Define.

View file

@ -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 **
buffer_fn_data (struct gcov_info *gi_ptr, struct gcov_fn_buffer **end_ptr,
unsigned fn_ix)
static struct gcov_fn_buffer *
free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
unsigned limit)
{
unsigned n_ctrs = 0, ix;
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 (const char *filename, const struct gcov_info *gi_ptr,
struct gcov_fn_buffer **end_ptr, unsigned fn_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);