mirror of git://gcc.gnu.org/git/gcc.git
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:
parent
84de2982de
commit
04dbc287a6
|
@ -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>
|
2011-12-21 Tristan Gingold <gingold@adacore.com>
|
||||||
|
|
||||||
* config/ia64/fde-vms.c (UNW_IVMS_MODE): Define.
|
* config/ia64/fde-vms.c (UNW_IVMS_MODE): Define.
|
||||||
|
|
182
libgcc/libgcov.c
182
libgcc/libgcov.c
|
@ -89,10 +89,6 @@ struct gcov_fn_buffer
|
||||||
/* Chain of per-object gcov structures. */
|
/* Chain of per-object gcov structures. */
|
||||||
static struct gcov_info *gcov_list;
|
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. */
|
/* Size of the longest file name. */
|
||||||
static size_t gcov_max_filename = 0;
|
static size_t gcov_max_filename = 0;
|
||||||
|
|
||||||
|
@ -143,22 +139,41 @@ create_file_directory (char *filename)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct gcov_fn_buffer **
|
static struct gcov_fn_buffer *
|
||||||
buffer_fn_data (struct gcov_info *gi_ptr, struct gcov_fn_buffer **end_ptr,
|
free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
|
||||||
unsigned fn_ix)
|
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;
|
struct gcov_fn_buffer *fn_buffer;
|
||||||
|
unsigned len;
|
||||||
|
|
||||||
for (ix = GCOV_COUNTERS; ix--;)
|
for (ix = GCOV_COUNTERS; ix--;)
|
||||||
if (gi_ptr->merge[ix])
|
if (gi_ptr->merge[ix])
|
||||||
n_ctrs++;
|
n_ctrs++;
|
||||||
|
|
||||||
fn_buffer = (struct gcov_fn_buffer *)malloc
|
len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
|
||||||
(sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs);
|
fn_buffer = (struct gcov_fn_buffer *)malloc (len);
|
||||||
|
|
||||||
if (!fn_buffer)
|
if (!fn_buffer)
|
||||||
return 0; /* We'll horribly fail. */
|
goto fail;
|
||||||
|
|
||||||
fn_buffer->next = 0;
|
fn_buffer->next = 0;
|
||||||
fn_buffer->fn_ix = fn_ix;
|
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;
|
continue;
|
||||||
|
|
||||||
if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
|
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--)
|
len = 0;
|
||||||
free (fn_buffer->info.ctrs[n_ctrs].values);
|
|
||||||
goto fail;
|
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].num = length;
|
||||||
fn_buffer->info.ctrs[n_ctrs].values = values;
|
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;
|
return &fn_buffer->next;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
free (fn_buffer);
|
fprintf (stderr, "profiling:%s:Function %u %s %u \n", filename, fn_ix,
|
||||||
return 0;
|
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.
|
/* Check if VERSION of the info block PTR matches libgcov one.
|
||||||
|
@ -241,22 +278,34 @@ gcov_exit (void)
|
||||||
struct gcov_summary all_prg; /* summary for all instances of program. */
|
struct gcov_summary all_prg; /* summary for all instances of program. */
|
||||||
struct gcov_ctr_summary *cs_ptr;
|
struct gcov_ctr_summary *cs_ptr;
|
||||||
const struct gcov_ctr_info *ci_ptr;
|
const struct gcov_ctr_info *ci_ptr;
|
||||||
unsigned t_ix, f_ix;
|
unsigned t_ix;
|
||||||
|
int f_ix;
|
||||||
gcov_unsigned_t c_num;
|
gcov_unsigned_t c_num;
|
||||||
const char *gcov_prefix;
|
const char *gcov_prefix;
|
||||||
int gcov_prefix_strip = 0;
|
int gcov_prefix_strip = 0;
|
||||||
size_t prefix_length;
|
size_t prefix_length;
|
||||||
char *gi_filename, *gi_filename_up;
|
char *gi_filename, *gi_filename_up;
|
||||||
|
gcov_unsigned_t crc32 = 0;
|
||||||
|
|
||||||
memset (&all_prg, 0, sizeof (all_prg));
|
memset (&all_prg, 0, sizeof (all_prg));
|
||||||
/* Find the totals for this execution. */
|
/* Find the totals for this execution. */
|
||||||
memset (&this_prg, 0, sizeof (this_prg));
|
memset (&this_prg, 0, sizeof (this_prg));
|
||||||
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
|
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
|
||||||
for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
|
{
|
||||||
|
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];
|
gfi_ptr = gi_ptr->functions[f_ix];
|
||||||
|
|
||||||
if (!gfi_ptr || gfi_ptr->key != gi_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;
|
continue;
|
||||||
|
|
||||||
ci_ptr = gfi_ptr->ctrs;
|
ci_ptr = gfi_ptr->ctrs;
|
||||||
|
@ -267,6 +316,8 @@ gcov_exit (void)
|
||||||
|
|
||||||
cs_ptr = &this_prg.ctrs[t_ix];
|
cs_ptr = &this_prg.ctrs[t_ix];
|
||||||
cs_ptr->num += ci_ptr->num;
|
cs_ptr->num += ci_ptr->num;
|
||||||
|
crc32 = crc32_unsigned (crc32, ci_ptr->num);
|
||||||
|
|
||||||
for (c_num = 0; c_num < ci_ptr->num; c_num++)
|
for (c_num = 0; c_num < ci_ptr->num; c_num++)
|
||||||
{
|
{
|
||||||
cs_ptr->sum_all += ci_ptr->values[c_num];
|
cs_ptr->sum_all += ci_ptr->values[c_num];
|
||||||
|
@ -276,6 +327,7 @@ gcov_exit (void)
|
||||||
ci_ptr++;
|
ci_ptr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Check if the level of dirs to strip off specified. */
|
/* Check if the level of dirs to strip off specified. */
|
||||||
|
@ -400,7 +452,7 @@ gcov_exit (void)
|
||||||
goto rewrite;
|
goto rewrite;
|
||||||
|
|
||||||
/* Look for program summary. */
|
/* Look for program summary. */
|
||||||
for (f_ix = ~0u;;)
|
for (f_ix = 0;;)
|
||||||
{
|
{
|
||||||
struct gcov_summary tmp;
|
struct gcov_summary tmp;
|
||||||
|
|
||||||
|
@ -409,29 +461,35 @@ gcov_exit (void)
|
||||||
if (tag != GCOV_TAG_PROGRAM_SUMMARY)
|
if (tag != GCOV_TAG_PROGRAM_SUMMARY)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
f_ix--;
|
||||||
length = gcov_read_unsigned ();
|
length = gcov_read_unsigned ();
|
||||||
if (length != GCOV_TAG_SUMMARY_LENGTH)
|
if (length != GCOV_TAG_SUMMARY_LENGTH)
|
||||||
goto read_mismatch;
|
goto read_mismatch;
|
||||||
gcov_read_summary (&tmp);
|
gcov_read_summary (&tmp);
|
||||||
if ((error = gcov_is_error ()))
|
if ((error = gcov_is_error ()))
|
||||||
goto read_error;
|
goto read_error;
|
||||||
if (!summary_pos && tmp.checksum == gcov_crc32)
|
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;
|
prg = tmp;
|
||||||
summary_pos = eof_pos;
|
summary_pos = eof_pos;
|
||||||
}
|
|
||||||
|
next_summary:;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Merge execution counts for each function. */
|
/* 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 ())
|
f_ix++, tag = gcov_read_unsigned ())
|
||||||
{
|
{
|
||||||
gfi_ptr = gi_ptr->functions[f_ix];
|
gfi_ptr = gi_ptr->functions[f_ix];
|
||||||
|
|
||||||
if (tag != GCOV_TAG_FUNCTION)
|
if (tag != GCOV_TAG_FUNCTION)
|
||||||
goto read_mismatch;
|
goto read_mismatch;
|
||||||
length = gcov_read_unsigned ();
|
|
||||||
|
|
||||||
|
length = gcov_read_unsigned ();
|
||||||
if (!length)
|
if (!length)
|
||||||
/* This function did not appear in the other program.
|
/* This function did not appear in the other program.
|
||||||
We have nothing to merge. */
|
We have nothing to merge. */
|
||||||
|
@ -447,15 +505,23 @@ gcov_exit (void)
|
||||||
it back out -- we'll be inserting data before
|
it back out -- we'll be inserting data before
|
||||||
this point, so cannot simply keep the data in the
|
this point, so cannot simply keep the data in the
|
||||||
file. */
|
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)
|
if (!fn_tail)
|
||||||
goto read_mismatch;
|
goto read_mismatch;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gcov_read_unsigned () != gfi_ptr->ident
|
length = gcov_read_unsigned ();
|
||||||
|| gcov_read_unsigned () != gfi_ptr->lineno_checksum
|
if (length != gfi_ptr->ident)
|
||||||
|| gcov_read_unsigned () != gfi_ptr->cfg_checksum)
|
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;
|
goto read_mismatch;
|
||||||
|
|
||||||
ci_ptr = gfi_ptr->ctrs;
|
ci_ptr = gfi_ptr->ctrs;
|
||||||
|
@ -481,8 +547,9 @@ gcov_exit (void)
|
||||||
if (tag)
|
if (tag)
|
||||||
{
|
{
|
||||||
read_mismatch:;
|
read_mismatch:;
|
||||||
fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
|
fprintf (stderr, "profiling:%s:Merge mismatch for %s %u\n",
|
||||||
gi_filename, f_ix + 1 ? "function" : "summaries");
|
gi_filename, f_ix >= 0 ? "function" : "summary",
|
||||||
|
f_ix < 0 ? -1 - f_ix : f_ix);
|
||||||
goto read_fatal;
|
goto read_fatal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -492,9 +559,7 @@ gcov_exit (void)
|
||||||
fprintf (stderr, "profiling:%s:%s merging\n", gi_filename,
|
fprintf (stderr, "profiling:%s:%s merging\n", gi_filename,
|
||||||
error < 0 ? "Overflow": "Error");
|
error < 0 ? "Overflow": "Error");
|
||||||
|
|
||||||
read_fatal:;
|
goto read_fatal;
|
||||||
gcov_close ();
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rewrite:;
|
rewrite:;
|
||||||
gcov_rewrite ();
|
gcov_rewrite ();
|
||||||
|
@ -515,8 +580,6 @@ gcov_exit (void)
|
||||||
{
|
{
|
||||||
if (!cs_prg->runs++)
|
if (!cs_prg->runs++)
|
||||||
cs_prg->num = cs_tprg->num;
|
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;
|
cs_prg->sum_all += cs_tprg->sum_all;
|
||||||
if (cs_prg->run_max < cs_tprg->run_max)
|
if (cs_prg->run_max < cs_tprg->run_max)
|
||||||
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. */
|
/* Write out the data. */
|
||||||
if (!eof_pos)
|
if (!eof_pos)
|
||||||
|
@ -557,11 +620,11 @@ gcov_exit (void)
|
||||||
gcov_seek (eof_pos);
|
gcov_seek (eof_pos);
|
||||||
|
|
||||||
/* Write execution counts for each function. */
|
/* 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;
|
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 data from another program. */
|
||||||
buffered = 1;
|
buffered = 1;
|
||||||
|
@ -597,19 +660,18 @@ gcov_exit (void)
|
||||||
gcov_type *c_ptr = ci_ptr->values;
|
gcov_type *c_ptr = ci_ptr->values;
|
||||||
while (n_counts--)
|
while (n_counts--)
|
||||||
gcov_write_counter (*c_ptr++);
|
gcov_write_counter (*c_ptr++);
|
||||||
if (buffered)
|
|
||||||
free (ci_ptr->values);
|
|
||||||
ci_ptr++;
|
ci_ptr++;
|
||||||
}
|
}
|
||||||
if (buffered)
|
if (buffered)
|
||||||
{
|
fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
|
||||||
struct gcov_fn_buffer *tmp = fn_buffer;
|
|
||||||
fn_buffer = fn_buffer->next;
|
|
||||||
free (tmp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gcov_write_unsigned (0);
|
gcov_write_unsigned (0);
|
||||||
|
|
||||||
|
read_fatal:;
|
||||||
|
while (fn_buffer)
|
||||||
|
fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
|
||||||
|
|
||||||
if ((error = gcov_close ()))
|
if ((error = gcov_close ()))
|
||||||
fprintf (stderr, error < 0 ?
|
fprintf (stderr, error < 0 ?
|
||||||
"profiling:%s:Overflow writing\n" :
|
"profiling:%s:Overflow writing\n" :
|
||||||
|
@ -628,32 +690,12 @@ __gcov_init (struct gcov_info *info)
|
||||||
return;
|
return;
|
||||||
if (gcov_version (info, info->version, 0))
|
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 */
|
/* Refresh the longest file name information */
|
||||||
if (filename_length > gcov_max_filename)
|
if (filename_length > gcov_max_filename)
|
||||||
gcov_max_filename = filename_length;
|
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)
|
if (!gcov_list)
|
||||||
atexit (gcov_exit);
|
atexit (gcov_exit);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue