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
2 changed files with 146 additions and 94 deletions
|
@ -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.
|
||||
|
|
230
libgcc/libgcov.c
230
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 **
|
||||
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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue