8sa1-gcc/gcc/gcov-io.c
Nathan Sidwell 9b514d2586 defaults.h (GCOV_TYPE_SIZE): Remove.
* defaults.h (GCOV_TYPE_SIZE): Remove.
	* gcov-io.h (gcov_type): Set to specific mode int on target.
	(gcov_unsigned_t, gcov_position_t): New.
	(GCOV_TYPE_NODE): New.
	(GCOV_TAG_SUMMARY_LENGTH): Adjust.
	(GCOV_COUNTERS_SUMMABLE): New.
	(gcov_ctr_summary, gcov_sumary, gcov_fn_info, gcov_merge_fn,
	gcov_ctr_info, gcov_info): Adjust types.
	(gcov_var): Adjust types.
	(gcov_write_unsigned, gcov_write_tag,
	gcov_write_length, gcov_write_tag_length, gcov_write_summary,
	gcov_read_unsigned, gcov_read_summary): Adjust gcov types.
	(gcov_position, gcov_sync, gcov_seek): Adjust gcov types.
	* gcov-io.c (gcov_write_unsigned, gcov_write_tag,
	gcov_write_length, gcov_write_tag_length, gcov_write_summary,
	gcov_read_unsigned, gcov_read_summary): Adjust gcov types.
	* libgcov.c (gcov_crc32, gcov_version_mismatch, gcov_exit,
	__gcov_init, __gcov_merge_add): Adjust gcov types.
	* coverage.c (ctr_merge_functions): Constify.
	(ctr_names): New.
	(read_counts_file): Adjust gcov types. Only summarize & merge
	summable counters.
	(coverage_counter_ref): Use GCOV_TYPE_NODE.
	(build_fn_info_type, build_fn_info_value, build_ctr_info_type,
	build_ctr_info_value, build_gcov_info): Adjust types.
	* profile.c (branch_prob): Adjust gcov types.
	* gcov_dump (dump_file): Adjust gcov types.

From-SVN: r66668
2003-05-10 19:02:21 +00:00

469 lines
11 KiB
C

/* File format for coverage information
Copyright (C) 1996, 1997, 1998, 2000, 2002,
2003 Free Software Foundation, Inc.
Contributed by Bob Manson <manson@cygnus.com>.
Completely remangled by Nathan Sidwell <nathan@codesourcery.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* Routines declared in gcov-io.h. This file should be #included by
another source file, after having #included gcov-io.h. */
/* Open a gcov file. NAME is the name of the file to open and MODE
indicates whether a new file should be created, or an existing file
opened for modification. If MODE is >= 0 an existing file will be
opened, if possible, and if MODE is <= 0, a new file will be
created. Use MODE=0 to attempt to reopen an existing file and then
fall back on creating a new one. Return zero on failure, >0 on
opening an existing file and <0 on creating a new one. */
GCOV_LINKAGE int
gcov_open (const char *name, int mode)
{
int result = 1;
size_t alloc = 1024;
#if GCOV_LOCKED
struct flock s_flock;
s_flock.l_type = F_WRLCK;
s_flock.l_whence = SEEK_SET;
s_flock.l_start = 0;
s_flock.l_len = 0; /* Until EOF. */
s_flock.l_pid = getpid ();
#endif
if (gcov_var.file)
abort ();
gcov_var.position = gcov_var.length = 0;
gcov_var.error = gcov_var.modified = 0;
if (mode >= 0)
gcov_var.file = fopen (name, "r+b");
if (!gcov_var.file && mode <= 0)
{
result = -1;
gcov_var.file = fopen (name, "w+b");
}
if (!gcov_var.file)
return 0;
#if GCOV_LOCKED
while (fcntl (fileno (gcov_var.file), F_SETLKW, &s_flock)
&& errno == EINTR)
continue;
#endif
if (result >= 0)
{
if (fseek (gcov_var.file, 0, SEEK_END))
{
fclose (gcov_var.file);
gcov_var.file = 0;
return 0;
}
gcov_var.length = ftell (gcov_var.file);
fseek (gcov_var.file, 0, SEEK_SET);
alloc += gcov_var.length;
}
if (alloc > gcov_var.alloc)
{
if (gcov_var.buffer)
free (gcov_var.buffer);
gcov_var.alloc = alloc;
#if IN_LIBGCOV
gcov_var.buffer = malloc (gcov_var.alloc);
if (!gcov_var.buffer)
{
fclose (gcov_var.file);
gcov_var.file = 0;
gcov_var.length = 0;
gcov_var.alloc = 0;
return 0;
}
#else
gcov_var.buffer = xmalloc (gcov_var.alloc);
#endif
}
if (result >= 0
&& fread (gcov_var.buffer, gcov_var.length, 1, gcov_var.file) != 1)
{
fclose (gcov_var.file);
gcov_var.file = 0;
gcov_var.length = 0;
return 0;
}
return result;
}
/* Close the current gcov file. Flushes data to disk. Returns nonzero
on failure or error flag set. */
GCOV_LINKAGE int
gcov_close ()
{
int result = 0;
if (gcov_var.file)
{
if (gcov_var.modified
&& (fseek (gcov_var.file, 0, SEEK_SET)
|| fwrite (gcov_var.buffer, gcov_var.length,
1, gcov_var.file) != 1))
result = 1;
fclose (gcov_var.file);
gcov_var.file = 0;
gcov_var.length = 0;
}
#if !IN_LIBGCOV
free (gcov_var.buffer);
gcov_var.alloc = 0;
gcov_var.buffer = 0;
#endif
return result ? 1 : gcov_var.error;
}
#if !IN_GCOV
/* Allocate space to write BYTES bytes to the gcov file. Return a
pointer to those bytes, or NULL on failure. */
GCOV_LINKAGE unsigned char *
gcov_write_bytes (unsigned bytes)
{
char unsigned *result;
if (gcov_var.position + bytes > gcov_var.alloc)
{
size_t new_size = (gcov_var.alloc + bytes) * 3 / 2;
if (!gcov_var.buffer)
return 0;
#if IN_LIBGCOV
result = realloc (gcov_var.buffer, new_size);
if (!result)
{
free (gcov_var.buffer);
gcov_var.buffer = 0;
gcov_var.alloc = 0;
gcov_var.position = gcov_var.length = 0;
gcov_var.error = 1;
return 0;
}
#else
result = xrealloc (gcov_var.buffer, new_size);
#endif
gcov_var.alloc = new_size;
gcov_var.buffer = result;
}
result = &gcov_var.buffer[gcov_var.position];
gcov_var.position += bytes;
gcov_var.modified = 1;
if (gcov_var.position > gcov_var.length)
gcov_var.length = gcov_var.position;
return result;
}
/* Write unsigned VALUE to coverage file. Sets error flag
appropriately. */
GCOV_LINKAGE void
gcov_write_unsigned (gcov_unsigned_t value)
{
unsigned char *buffer = gcov_write_bytes (4);
unsigned ix;
if (!buffer)
return;
for (ix = 4; ix--; )
{
buffer[ix] = value;
value >>= 8;
}
if (sizeof (value) > 4 && value)
gcov_var.error = -1;
return;
}
/* Write counter VALUE to coverage file. Sets error flag
appropriately. */
#if IN_LIBGCOV
GCOV_LINKAGE void
gcov_write_counter (gcov_type value)
{
unsigned char *buffer = gcov_write_bytes (8);
unsigned ix;
if (!buffer)
return;
for (ix = 8; ix--; )
{
buffer[ix] = value;
value >>= 8;
}
if ((sizeof (value) > 8 && value) || value < 0)
gcov_var.error = -1;
return;
}
#endif /* IN_LIBGCOV */
#if !IN_LIBGCOV
/* Write STRING to coverage file. Sets error flag on file
error, overflow flag on overflow */
GCOV_LINKAGE void
gcov_write_string (const char *string)
{
unsigned length = 0;
unsigned pad = 0;
unsigned rem = 0;
unsigned char *buffer;
if (string)
{
length = strlen (string);
rem = 4 - (length & 3);
}
buffer = gcov_write_bytes (4 + length + rem);
if (buffer)
{
unsigned ix;
unsigned value = length;
for (ix = 4; ix--; )
{
buffer[ix] = value;
value >>= 8;
}
memcpy (buffer + 4, string, length);
memcpy (buffer + 4 + length, &pad, rem);
}
}
#endif
#if !IN_LIBGCOV
/* Write a tag TAG and reserve space for the record length. Return a
value to be used for gcov_write_length. */
GCOV_LINKAGE gcov_position_t
gcov_write_tag (gcov_unsigned_t tag)
{
gcov_position_t result = gcov_var.position;
unsigned char *buffer = gcov_write_bytes (8);
unsigned ix;
if (!buffer)
return 0;
for (ix = 4; ix--; )
{
buffer[ix] = tag;
tag >>= 8;
}
memset (buffer + 4, 0, 4);
return result;
}
/* Write a record length using POSITION, which was returned by
gcov_write_tag. The current file position is the end of the
record, and is restored before returning. Returns nonzero on
overflow. */
GCOV_LINKAGE void
gcov_write_length (gcov_position_t position)
{
if (position)
{
gcov_unsigned_t length = gcov_var.position - position - 8;
unsigned char *buffer = &gcov_var.buffer[position + 4];
unsigned ix;
for (ix = 4; ix--; )
{
buffer[ix] = length;
length >>= 8;
}
}
}
#else /* IN_LIBGCOV */
/* Write a tag TAG and length LENGTH. */
GCOV_LINKAGE void
gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
{
unsigned char *buffer = gcov_write_bytes (8);
unsigned ix;
if (!buffer)
return;
for (ix = 4; ix--; )
{
buffer[ix] = tag;
tag >>= 8;
}
for (ix = 4; ix--; )
{
buffer[ix + 4] = length;
length >>= 8;
}
return;
}
/* Write a summary structure to the gcov file. Return non-zero on
overflow. */
GCOV_LINKAGE void
gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
{
unsigned ix;
const struct gcov_ctr_summary *csum;
gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH);
gcov_write_unsigned (summary->checksum);
for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
{
gcov_write_unsigned (csum->num);
gcov_write_unsigned (csum->runs);
gcov_write_counter (csum->sum_all);
gcov_write_counter (csum->run_max);
gcov_write_counter (csum->sum_max);
}
}
#endif /* IN_LIBGCOV */
#endif /*!IN_GCOV */
/* Return a pointer to read BYTES bytes from the gcov file. Returns
NULL on failure (read past EOF). */
GCOV_LINKAGE const unsigned char *
gcov_read_bytes (unsigned bytes)
{
const unsigned char *result;
if (gcov_var.position + bytes > gcov_var.length)
{
gcov_var.error = 1;
return 0;
}
result = &gcov_var.buffer[gcov_var.position];
gcov_var.position += bytes;
return result;
}
/* Read unsigned value from a coverage file. Sets error flag on file
error, overflow flag on overflow */
GCOV_LINKAGE gcov_unsigned_t
gcov_read_unsigned ()
{
gcov_unsigned_t value = 0;
unsigned ix;
const unsigned char *buffer = gcov_read_bytes (4);
if (!buffer)
return 0;
for (ix = sizeof (value); ix < 4; ix++)
if (buffer[ix])
gcov_var.error = -1;
for (ix = 0; ix != 4; ix++)
{
value <<= 8;
value |= buffer[ix];
}
return value;
}
/* Read counter value from a coverage file. Sets error flag on file
error, overflow flag on overflow */
GCOV_LINKAGE gcov_type
gcov_read_counter ()
{
gcov_type value = 0;
unsigned ix;
const unsigned char *buffer = gcov_read_bytes (8);
if (!buffer)
return 0;
for (ix = sizeof (value); ix < 8; ix++)
if (buffer[ix])
gcov_var.error = -1;
for (ix = 0; ix != 8; ix++)
{
value <<= 8;
value |= buffer[ix];
}
if (value < 0)
gcov_var.error = -1;
return value;
}
/* Read string from coverage file. Returns a pointer to a static
buffer, or NULL on empty string. You must copy the string before
calling another gcov function. */
#if !IN_LIBGCOV
GCOV_LINKAGE const char *
gcov_read_string ()
{
unsigned length = gcov_read_unsigned ();
if (!length)
return 0;
length += 4 - (length & 3);
return (const char *) gcov_read_bytes (length);
}
#endif
GCOV_LINKAGE void
gcov_read_summary (struct gcov_summary *summary)
{
unsigned ix;
struct gcov_ctr_summary *csum;
summary->checksum = gcov_read_unsigned ();
for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++)
{
csum->num = gcov_read_unsigned ();
csum->runs = gcov_read_unsigned ();
csum->sum_all = gcov_read_counter ();
csum->run_max = gcov_read_counter ();
csum->sum_max = gcov_read_counter ();
}
}
#if IN_GCOV > 0
/* Return the modification time of the current gcov file. */
GCOV_LINKAGE time_t
gcov_time ()
{
struct stat status;
if (fstat (fileno (gcov_var.file), &status))
return 0;
else
return status.st_mtime;
}
#endif /* IN_GCOV */