gcov-io.h: Update documentation.

* gcov-io.h: Update documentation.
	(GCOV_GRAPH_SUFFIX, GCOV_GRAPH_MAGIC): Rename to GCOV_NOTE_SUFFIX,
	GCOV_NOTE_MAGIC.
	(GCOV_DATA_SUFFIX, GCOV_NOTE_SUFFIX): Update.
	(GCOV_DATA_MAGIC, GCOV_NOTE_MAGIC): Make non-palindromic.
	(struct gcov_var): Change buffer's type. Add endian flag.
	(gcov_open): Remove mode in libgcov.
	(gcov_magic): Prototype.
	* gcov-io.c (from_file): New.
	(gcov_open): Clear endian flag.
	(gcov_magic): New.
	(gcov_write_bytes, gcov_read_bytes): Return gcov_unsigned_t
	pointers.
	(gcov_write_unsigned, gcov_write_counter, gcov_write_string,
	gcov_write_tag, gcov_write_length, gcov_write_tag_length): Update.
	(gcov_read_unsigned, gcov_read_counter, gcov_read_string): Update.
	* gcov-iov.c (main): Correct cast.
	* coverage.c (read_counts_file): Use gcov_magic. Remove endianness
	conversion.
	(gcov_begin_output): Use GCOV_NOTE_MAGIC.
	(coverage_init): Use GCOV_NOTE_SUFFIX.
	* libgcov.c (gcov_version_mismatch): Remove endianness conversion.
	Rename to gcov_version, and return flag.
	(gcov_exit): Use gcov_version.
	(__gcov_init): Use gcov_version.
	* Makefile.in (coverageexts): Update.
	* gcov.c (print_version): Remove endianness conversion.
	(create_file_names): Use GCOV_NOTE_SUFFIX.
	(read_graph_file): Use gcov_magic.
	(read_count_file): Likewise.
	* gcov-dump.c (dump_file): Remove endianness conversion, use
	gcov_magic.

From-SVN: r69137
This commit is contained in:
Nathan Sidwell 2003-07-09 12:12:29 +00:00 committed by Nathan Sidwell
parent 83599948cd
commit 160e2e4f23
9 changed files with 277 additions and 268 deletions

View File

@ -1,3 +1,38 @@
2003-07-09 Nathan Sidwell <nathan@codesourcery.com>
* gcov-io.h: Update documentation.
(GCOV_GRAPH_SUFFIX, GCOV_GRAPH_MAGIC): Rename to GCOV_NOTE_SUFFIX,
GCOV_NOTE_MAGIC.
(GCOV_DATA_SUFFIX, GCOV_NOTE_SUFFIX): Update.
(GCOV_DATA_MAGIC, GCOV_NOTE_MAGIC): Make non-palindromic.
(struct gcov_var): Change buffer's type. Add endian flag.
(gcov_open): Remove mode in libgcov.
(gcov_magic): Prototype.
* gcov-io.c (from_file): New.
(gcov_open): Clear endian flag.
(gcov_magic): New.
(gcov_write_bytes, gcov_read_bytes): Return gcov_unsigned_t
pointers.
(gcov_write_unsigned, gcov_write_counter, gcov_write_string,
gcov_write_tag, gcov_write_length, gcov_write_tag_length): Update.
(gcov_read_unsigned, gcov_read_counter, gcov_read_string): Update.
* gcov-iov.c (main): Correct cast.
* coverage.c (read_counts_file): Use gcov_magic. Remove endianness
conversion.
(gcov_begin_output): Use GCOV_NOTE_MAGIC.
(coverage_init): Use GCOV_NOTE_SUFFIX.
* libgcov.c (gcov_version_mismatch): Remove endianness conversion.
Rename to gcov_version, and return flag.
(gcov_exit): Use gcov_version.
(__gcov_init): Use gcov_version.
* Makefile.in (coverageexts): Update.
* gcov.c (print_version): Remove endianness conversion.
(create_file_names): Use GCOV_NOTE_SUFFIX.
(read_graph_file): Use gcov_magic.
(read_count_file): Likewise.
* gcov-dump.c (dump_file): Remove endianness conversion, use
gcov_magic.
2003-07-09 Nathan Sidwell <nathan@codesourcery.com>
* configure.in (BUILD_PREFIX, BUILD_PREFIX_1): Set if enable

View File

@ -125,7 +125,7 @@ BOOT_CFLAGS = -g -O2
# contain the optimization flags, as you normally want code coverage
# without optimization.
COVERAGE_FLAGS = @coverage_flags@
coverageexts = .{da,bbg}
coverageexts = .{gcda,gcno}
# The warning flags are separate from BOOT_CFLAGS because people tend to
# override optimization flags and we'd like them to still have warnings

View File

@ -150,8 +150,7 @@ static void
read_counts_file (void)
{
gcov_unsigned_t fn_ident = 0;
gcov_unsigned_t version, checksum = -1;
unsigned ix;
gcov_unsigned_t checksum = -1;
counts_entry_t *summaried = NULL;
unsigned seen_summary = 0;
gcov_unsigned_t tag;
@ -160,24 +159,18 @@ read_counts_file (void)
if (!gcov_open (da_file_name, 1))
return;
if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
{
warning ("`%s' is not a gcov data file", da_file_name);
gcov_close ();
return;
}
else if ((version = gcov_read_unsigned ()) != GCOV_VERSION)
else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION)
{
char v[4], e[4];
gcov_unsigned_t required = GCOV_VERSION;
for (ix = 4; ix--; required >>= 8, version >>= 8)
{
v[ix] = version;
e[ix] = required;
}
warning ("`%s' is version `%.4s', expected version `%.4s'",
da_file_name, v, e);
da_file_name, (const char *)&tag, (const char *)&required);
gcov_close ();
return;
}
@ -446,7 +439,7 @@ coverage_begin_output (void)
error ("cannot open %s", bbg_file_name);
else
{
gcov_write_unsigned (GCOV_GRAPH_MAGIC);
gcov_write_unsigned (GCOV_NOTE_MAGIC);
gcov_write_unsigned (GCOV_VERSION);
gcov_write_unsigned (local_tick);
}
@ -897,9 +890,9 @@ coverage_init (const char *filename)
strcat (da_file_name, GCOV_DATA_SUFFIX);
/* Name of bbg file. */
bbg_file_name = (char *) xmalloc (len + strlen (GCOV_GRAPH_SUFFIX) + 1);
bbg_file_name = (char *) xmalloc (len + strlen (GCOV_NOTE_SUFFIX) + 1);
strcpy (bbg_file_name, filename);
strcat (bbg_file_name, GCOV_GRAPH_SUFFIX);
strcat (bbg_file_name, GCOV_NOTE_SUFFIX);
read_counts_file ();
}

View File

@ -155,33 +155,32 @@ dump_file (const char *filename)
/* magic */
{
unsigned magic = gcov_read_unsigned ();
unsigned version = gcov_read_unsigned ();
unsigned version;
const char *type = NULL;
char e[4], v[4], m[4];
unsigned expected = GCOV_VERSION;
unsigned ix;
int different = version != GCOV_VERSION;
if (magic == GCOV_DATA_MAGIC)
int endianness = 0;
if ((endianness = gcov_magic (magic, GCOV_DATA_MAGIC)))
type = "data";
else if (magic == GCOV_GRAPH_MAGIC)
type = "graph";
else if ((endianness = gcov_magic (magic, GCOV_NOTE_MAGIC)))
type = "note";
else
{
printf ("%s:not a gcov file\n", filename);
gcov_close ();
return;
}
for (ix = 4; ix--; expected >>= 8, version >>= 8, magic >>= 8)
version = gcov_read_unsigned ();
printf ("%s:%s:magic `%.4s':version `%.4s'%s\n", filename, type,
(const char *)&magic, (const char *)&version,
endianness < 0 ? " (swapped endianness)" : "");
if (version != GCOV_VERSION)
{
e[ix] = expected;
v[ix] = version;
m[ix] = magic;
unsigned expected = GCOV_VERSION;
printf ("%s:warning:current version is `%.4s'\n", filename,
(const char *)expected);
}
printf ("%s:%s:magic `%.4s':version `%.4s'\n", filename, type, m, v);
if (different)
printf ("%s:warning:current version is `%.4s'\n", filename, e);
}
/* stamp */

View File

@ -26,13 +26,25 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#if !IN_GCOV
static void gcov_write_block (unsigned);
static unsigned char *gcov_write_bytes (unsigned);
static gcov_unsigned_t *gcov_write_bytes (unsigned);
#endif
static const unsigned char *gcov_read_bytes (unsigned);
static const gcov_unsigned_t *gcov_read_bytes (unsigned);
#if !IN_LIBGCOV
static void gcov_allocate (unsigned);
#endif
static inline gcov_unsigned_t from_file (gcov_unsigned_t value)
{
#if !IN_LIBGCOV
if (gcov_var.endian)
{
value = (value >> 16) | (value << 16);
value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff);
}
#endif
return value;
}
/* 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
@ -42,9 +54,15 @@ static void gcov_allocate (unsigned);
opening an existing file and <0 on creating a new one. */
GCOV_LINKAGE int
#if IN_LIBGCOV
gcov_open (const char *name)
#else
gcov_open (const char *name, int mode)
#endif
{
int result = 1;
#if IN_LIBGCOV
const int mode = 0;
#endif
#if GCOV_LOCKED
struct flock s_flock;
@ -61,20 +79,22 @@ gcov_open (const char *name, int mode)
gcov_var.offset = gcov_var.length = 0;
gcov_var.overread = -4u;
gcov_var.error = 0;
#if !IN_LIBGCOV
gcov_var.endian = 0;
#endif
if (mode >= 0)
gcov_var.file = fopen (name, "r+b");
if (gcov_var.file)
gcov_var.mode = 1;
else if (mode <= 0)
{
result = -1;
gcov_var.file = fopen (name, "w+b");
if (gcov_var.file)
gcov_var.mode = -1;
gcov_var.mode = mode * 2 + 1;
}
if (!gcov_var.file)
return 0;
setbuf (gcov_var.file, (char *)0);
#if GCOV_LOCKED
@ -83,7 +103,7 @@ gcov_open (const char *name, int mode)
continue;
#endif
return result;
return 1;
}
/* Close the current gcov file. Flushes data to disk. Returns nonzero
@ -111,6 +131,27 @@ gcov_close (void)
return gcov_var.error;
}
#if !IN_LIBGCOV
/* Check if MAGIC is EXPECTED. Use it to determine endianness of the
file. Returns +1 for same endian, -1 for other endian and zero for
not EXPECTED. */
GCOV_LINKAGE int
gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
{
if (magic == expected)
return 1;
magic = (magic >> 16) | (magic << 16);
magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff);
if (magic == expected)
{
gcov_var.endian = 1;
return -1;
}
return 0;
}
#endif
#if !IN_LIBGCOV
static void
gcov_allocate (unsigned length)
@ -142,12 +183,13 @@ gcov_write_block (unsigned size)
/* Allocate space to write BYTES bytes to the gcov file. Return a
pointer to those bytes, or NULL on failure. */
static unsigned char *
static gcov_unsigned_t *
gcov_write_bytes (unsigned bytes)
{
char unsigned *result;
gcov_unsigned_t *result;
GCOV_CHECK_WRITING ();
GCOV_CHECK (!(bytes & 3));
#if IN_LIBGCOV
if (gcov_var.offset >= GCOV_BLOCK_SIZE)
{
@ -162,7 +204,7 @@ gcov_write_bytes (unsigned bytes)
if (gcov_var.offset + bytes > gcov_var.alloc)
gcov_allocate (gcov_var.offset + bytes);
#endif
result = &gcov_var.buffer[gcov_var.offset];
result = (gcov_unsigned_t *)&gcov_var.buffer[gcov_var.offset];
gcov_var.offset += bytes;
return result;
@ -174,18 +216,9 @@ gcov_write_bytes (unsigned bytes)
GCOV_LINKAGE void
gcov_write_unsigned (gcov_unsigned_t value)
{
unsigned char *buffer = gcov_write_bytes (4);
unsigned ix;
gcov_unsigned_t *buffer = gcov_write_bytes (4);
for (ix = 4; ix--; )
{
buffer[ix] = value;
value >>= 8;
}
if (sizeof (value) > 4 && value)
gcov_var.error = -1;
return;
buffer[0] = value;
}
/* Write counter VALUE to coverage file. Sets error flag
@ -195,17 +228,16 @@ gcov_write_unsigned (gcov_unsigned_t value)
GCOV_LINKAGE void
gcov_write_counter (gcov_type value)
{
unsigned char *buffer = gcov_write_bytes (8);
unsigned ix;
gcov_unsigned_t *buffer = gcov_write_bytes (8);
for (ix = 8; ix--; )
{
buffer[ix] = value;
value >>= 8;
}
if ((sizeof (value) > 8 && value) || value < 0)
buffer[0] = (gcov_unsigned_t) value;
if (sizeof (value) > sizeof (gcov_unsigned_t))
buffer[1] = (gcov_unsigned_t) (value >> 32);
else
buffer[1] = 0;
if (value < 0)
gcov_var.error = -1;
return;
}
#endif /* IN_LIBGCOV */
@ -217,28 +249,20 @@ GCOV_LINKAGE void
gcov_write_string (const char *string)
{
unsigned length = 0;
unsigned pad = 0;
unsigned rem = 0;
unsigned char *buffer;
unsigned ix;
unsigned value;
unsigned alloc = 0;
gcov_unsigned_t *buffer;
if (string)
{
length = strlen (string);
rem = 4 - (length & 3);
alloc = (length + 4) >> 2;
}
buffer = gcov_write_bytes (4 + length + rem);
buffer = gcov_write_bytes (4 + alloc * 4);
value = length;
for (ix = 4; ix--; )
{
buffer[ix] = value;
value >>= 8;
}
memcpy (buffer + 4, string, length);
memcpy (buffer + 4 + length, &pad, rem);
buffer[0] = alloc;
buffer[alloc] = 0;
memcpy (&buffer[1], string, length);
}
#endif
@ -250,15 +274,11 @@ GCOV_LINKAGE gcov_position_t
gcov_write_tag (gcov_unsigned_t tag)
{
gcov_position_t result = gcov_var.start + gcov_var.offset;
unsigned char *buffer = gcov_write_bytes (8);
unsigned ix;
gcov_unsigned_t *buffer = gcov_write_bytes (8);
for (ix = 4; ix--; )
{
buffer[ix] = tag;
tag >>= 8;
}
memset (buffer + 4, 0, 4);
buffer[0] = tag;
buffer[1] = 0;
return result;
}
@ -272,20 +292,15 @@ gcov_write_length (gcov_position_t position)
{
unsigned offset;
gcov_unsigned_t length;
unsigned char *buffer;
unsigned ix;
gcov_unsigned_t *buffer;
GCOV_CHECK_WRITING ();
GCOV_CHECK (position + 8 <= gcov_var.start + gcov_var.offset);
GCOV_CHECK (position >= gcov_var.start);
offset = position - gcov_var.start;
length = gcov_var.offset - offset - 8;
buffer = &gcov_var.buffer[offset + 4];
for (ix = 4; ix--; )
{
buffer[ix] = length;
length >>= 8;
}
buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset];
buffer[1] = length;
if (gcov_var.offset >= GCOV_BLOCK_SIZE)
gcov_write_block (gcov_var.offset);
}
@ -297,20 +312,10 @@ gcov_write_length (gcov_position_t position)
GCOV_LINKAGE void
gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
{
unsigned char *buffer = gcov_write_bytes (8);
unsigned ix;
gcov_unsigned_t *buffer = gcov_write_bytes (8);
for (ix = 4; ix--; )
{
buffer[ix] = tag;
tag >>= 8;
}
for (ix = 4; ix--; )
{
buffer[ix + 4] = length;
length >>= 8;
}
return;
buffer[0] = tag;
buffer[1] = length;
}
/* Write a summary structure to the gcov file. Return nonzero on
@ -340,13 +345,14 @@ gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary)
/* Return a pointer to read BYTES bytes from the gcov file. Returns
NULL on failure (read past EOF). */
static const unsigned char *
static const gcov_unsigned_t *
gcov_read_bytes (unsigned bytes)
{
const unsigned char *result;
const gcov_unsigned_t *result;
unsigned excess = gcov_var.length - gcov_var.offset;
GCOV_CHECK_READING ();
GCOV_CHECK (!(bytes & 3));
if (excess < bytes)
{
gcov_var.start += gcov_var.offset;
@ -379,7 +385,7 @@ gcov_read_bytes (unsigned bytes)
return 0;
}
}
result = &gcov_var.buffer[gcov_var.offset];
result = (gcov_unsigned_t *)&gcov_var.buffer[gcov_var.offset];
gcov_var.offset += bytes;
return result;
}
@ -390,20 +396,12 @@ gcov_read_bytes (unsigned bytes)
GCOV_LINKAGE gcov_unsigned_t
gcov_read_unsigned (void)
{
gcov_unsigned_t value = 0;
unsigned ix;
const unsigned char *buffer = gcov_read_bytes (4);
gcov_unsigned_t value;
const gcov_unsigned_t *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];
}
value = from_file (buffer[0]);
return value;
}
@ -413,20 +411,17 @@ gcov_read_unsigned (void)
GCOV_LINKAGE gcov_type
gcov_read_counter (void)
{
gcov_type value = 0;
unsigned ix;
const unsigned char *buffer = gcov_read_bytes (8);
gcov_type value;
const gcov_unsigned_t *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];
}
value = from_file (buffer[0]);
if (sizeof (value) > sizeof (gcov_unsigned_t))
value |= ((gcov_type) from_file (buffer[1])) << 32;
else if (buffer[1])
gcov_var.error = -1;
if (value < 0)
gcov_var.error = -1;
return value;
@ -445,7 +440,6 @@ gcov_read_string (void)
if (!length)
return 0;
length += 4 - (length & 3);
return (const char *) gcov_read_bytes (length);
}
#endif

View File

@ -28,24 +28,25 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
/* Coverage information is held in two files. A basic block graph
file, which is generated by the compiler, and a counter file, which
is generated by the program under test. Both files use a similar
structure. We do not attempt to make these files backwards
compatible with previous versions, as you only need coverage
information when developing a program. We do hold version
information, so that mismatches can be detected, and we use a
format that allows tools to skip information they do not understand
or are not interested in.
/* Coverage information is held in two files. A notes file, which is
generated by the compiler, and a data file, which is generated
by the program under test. Both files use a similar structure. We
do not attempt to make these files backwards compatible with
previous versions, as you only need coverage information when
developing a program. We do hold version information, so that
mismatches can be detected, and we use a format that allows tools
to skip information they do not understand or are not interested
in.
Numbers are recorded in big endian unsigned binary form. Either in
32 or 64 bits. Strings are stored with a length count and NUL
terminator, and 0 to 3 bytes of zero padding up to the next 4 byte
boundary. Zero length and NULL strings are simply stored as a
length of zero (they have no trailing NUL or padding).
Numbers are recorded in the 32 bit unsigned binary form of the
endianness of the machine generating the file. 64 bit numbers are
stored as two 32 bit numbers, the low part first. Strings are
stored as length rounded up to 4 followed by the string and then 1
to 4 NUL bytes. Zero length and NULL strings are simply stored as
a length of zero (they have no trailing NUL or padding).
int32: byte3 byte2 byte1 byte0
int64: byte7 byte6 byte5 byte4 byte3 byte2 byte1 byte0
int32: byte3 byte2 byte1 byte0 | byte0 byte1 byte2 byte3
int64: int32:low int32:high
string: int32:0 | int32:length char* char:0 padding
padding: | char:0 | char:0 char:0 | char:0 char:0 char:0
item: int32 | int64 | string
@ -54,31 +55,30 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
file : int32:magic int32:version int32:stamp record*
The magic ident is different for the bbg and the counter files.
The version is the same for both files and is derived from gcc's
version number. The stamp value is used to synchronize bbg and
counter files and to synchronize merging within a counter file. It
need not be an absolute time stamp, merely a ticker that increments
fast enough and cycles slow enough to distinguish different
compile/run/compile cycles.
The magic ident is different for the notes and the data files. The
magic ident is used to determine the endianness of the file, when
reading. The version is the same for both files and is derived
from gcc's version number. The stamp value is used to synchronize
note and data files and to synchronize merging within a data
file. It need not be an absolute time stamp, merely a ticker that
increments fast enough and cycles slow enough to distinguish
different compile/run/compile cycles.
Although the ident and version are formally 32 bit
numbers, they are derived from 4 character ASCII strings. The
version number consists of the single character major version
number, a two character minor version number (leading zero for
versions less than 10), and a single character indicating the
status of the release. That will be 'e' experimental, 'p'
prerelease and 'r' for release. Because, by good fortune, these are
in alphabetical order, string collating can be used to compare
version strings, and because numbers are stored big endian, numeric
comparison can be used when it is read as a 32 bit value. Be aware
that the 'e' designation will (naturally) be unstable and might be
Although the ident and version are formally 32 bit numbers, they
are derived from 4 character ASCII strings. The version number
consists of the single character major version number, a two
character minor version number (leading zero for versions less than
10), and a single character indicating the status of the release.
That will be 'e' experimental, 'p' prerelease and 'r' for release.
Because, by good fortune, these are in alphabetical order, string
collating can be used to compare version strings. Be aware that
the 'e' designation will (naturally) be unstable and might be
incompatible with itself. For gcc 3.4 experimental, it would be
'304e' (0x33303465). When the major version reaches 10, the letters
A-Z will be used. Assuming minor increments releases every 6
months, we have to make a major increment every 50 years. Assuming
major increments releases every 5 years, we're ok for the next 155
years -- good enough for me.
'304e' (0x33303465). When the major version reaches 10, the
letters A-Z will be used. Assuming minor increments releases every
6 months, we have to make a major increment every 50 years.
Assuming major increments releases every 5 years, we're ok for the
next 155 years -- good enough for me.
A record has a tag, length and variable amount of data.
@ -87,21 +87,21 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
data: item*
Records are not nested, but there is a record hierarchy. Tag
numbers reflect this hierarchy. Tags are unique across bbg and da
files. Some record types have a varying amount of data. The LENGTH
is usually used to determine how much data. The tag value is split
into 4 8-bit fields, one for each of four possible levels. The
most significant is allocated first. Unused levels are zero.
numbers reflect this hierarchy. Tags are unique across note and
data files. Some record types have a varying amount of data. The
LENGTH is usually used to determine how much data. The tag value
is split into 4 8-bit fields, one for each of four possible levels.
The most significant is allocated first. Unused levels are zero.
Active levels are odd-valued, so that the LSB of the level is one.
A sub-level incorporates the values of its superlevels. This
formatting allows you to determine the tag hierarchy, without
understanding the tags themselves, and is similar to the standard
section numbering used in technical documents. Level values
[1..3f] are used for common tags, values [41..9f] for the graph
file and [a1..ff] for the counter file.
[1..3f] are used for common tags, values [41..9f] for the notes
file and [a1..ff] for the data file.
The basic block graph file contains the following records
bbg: unit function-graph*
note: unit function-graph*
unit: header int32:checksum string:source
function-graph: announce_function basic_blocks {arcs | lines}*
announce_function: header int32:ident int32:checksum
@ -130,7 +130,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
blocks they are for.
The data file contains the following records.
da: {unit function-data* summary:object summary:program*}*
data: {unit function-data* summary:object summary:program*}*
unit: header int32:checksum
function-data: announce_function arc_counts
announce_function: header int32:ident int32:checksum
@ -139,17 +139,16 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
count-summary: int32:num int32:runs int64:sum
int64:max int64:sum_max
The ANNOUNCE_FUNCTION record is the same as that in the BBG file,
but without the source location.
The ARC_COUNTS gives the counter values for those arcs that are
instrumented. The SUMMARY records give information about the whole
object file and about the whole program. The checksum is used for
whole program summaries, and disambiguates different programs which
include the same instrumented object file. There may be several
program summaries, each with a unique checksum. The object
summary's checkum is zero. Note that the da file might contain
information from several runs concatenated, or the data might be
merged.
The ANNOUNCE_FUNCTION record is the same as that in the note file,
but without the source location. The ARC_COUNTS gives the counter
values for those arcs that are instrumented. The SUMMARY records
give information about the whole object file and about the whole
program. The checksum is used for whole program summaries, and
disambiguates different programs which include the same
instrumented object file. There may be several program summaries,
each with a unique checksum. The object summary's checkum is zero.
Note that the data file might contain information from several runs
concatenated, or the data might be merged.
This file is included by both the compiler, gcov tools and the
runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to
@ -231,7 +230,7 @@ typedef HOST_WIDEST_INT gcov_type;
/* Poison these, so they don't accidentally slip in. */
#pragma GCC poison gcov_write_string gcov_write_tag gcov_write_length
#pragma GCC poison gcov_read_string gcov_sync gcov_time
#pragma GCC poison gcov_read_string gcov_sync gcov_time gcov_magic
#endif
@ -240,21 +239,21 @@ typedef HOST_WIDEST_INT gcov_type;
#endif
/* File suffixes. */
#define GCOV_DATA_SUFFIX ".da"
#define GCOV_GRAPH_SUFFIX ".bbg"
#define GCOV_DATA_SUFFIX ".gcda"
#define GCOV_NOTE_SUFFIX ".gcno"
/* File magic. */
#define GCOV_DATA_MAGIC 0x67636f76 /* "gcov" */
#define GCOV_GRAPH_MAGIC 0x67626267 /* "gbbg" */
/* File magic. Must not be palindromes. */
#define GCOV_DATA_MAGIC ((gcov_unsigned_t)0x67636461) /* "gcda" */
#define GCOV_NOTE_MAGIC ((gcov_unsigned_t)0x67636e6f) /* "gcno" */
/* gcov-iov.h is automatically generated by the makefile from
version.c, it looks like
#define GCOV_VERSION ((unsigned)0x89abcdef)
#define GCOV_VERSION ((gcov_unsigned_t)0x89abcdef)
*/
#include "gcov-iov.h"
/* The record tags. Values [1..3f] are for tags which may be in either
file. Values [41..9f] for those in the bbg file and [a1..ff] for
file. Values [41..9f] for those in the note file and [a1..ff] for
the data file. */
#define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000)
@ -374,7 +373,7 @@ struct gcov_ctr_info
struct gcov_info
{
gcov_unsigned_t version; /* expected version number */
struct gcov_info *next; /* link to next, used by libgcc */
struct gcov_info *next; /* link to next, used by libgcov */
gcov_unsigned_t stamp; /* uniquifying time stamp */
const char *filename; /* output file name */
@ -398,11 +397,11 @@ extern void __gcov_flush (void);
/* The merge function that just sums the counters. */
extern void __gcov_merge_add (gcov_type *, unsigned);
/* The merge function to choose the most often value. */
/* The merge function to choose the most common value. */
extern void __gcov_merge_single (gcov_type *, unsigned);
/* The merge function to choose the most often difference between consecutive
values. */
/* The merge function to choose the most common difference between
consecutive values. */
extern void __gcov_merge_delta (gcov_type *, unsigned);
#endif /* IN_LIBGCOV */
@ -425,24 +424,31 @@ GCOV_LINKAGE struct gcov_var
fit within this buffer and we always can transfer GCOV_BLOCK_SIZE
to and from the disk. libgcov never backtracks and only writes 4
or 8 byte objects. */
unsigned char buffer[GCOV_BLOCK_SIZE + 4];
char buffer[GCOV_BLOCK_SIZE + 4] __attribute__ ((aligned (4)));
#else
int endian; /* Swap endianness. */
/* Holds a variable length block, as the compiler can write
strings and needs to backtrack. */
size_t alloc;
unsigned char *buffer;
char *buffer;
#endif
} gcov_var;
/* Functions for reading and writing gcov files. You can open a file
for (1) reading or (2) writing or (3) reading then rewriting. When
reading a file you may use the gcov_read_* functions, gcov_sync,
gcov_position, & gcov_error. When writing a file you
may use the gcov_write functions, gcov_seek & gcov_error. When a
file is to be rewritten you use the functions for reading, then
gcov_rewrite then the functions for writing. Your file may become
corrupted if you break these invariants. */
GCOV_LINKAGE int gcov_open (const char */*name*/, int /*truncate*/);
/* Functions for reading and writing gcov files. In libgcov you can
open the file for reading then writing. Elsewhere you can open the
file either for reading or for writing. When reading a file you may
use the gcov_read_* functions, gcov_sync, gcov_position, &
gcov_error. When writing a file you may use the gcov_write
functions, gcov_seek & gcov_error. When a file is to be rewritten
you use the functions for reading, then gcov_rewrite then the
functions for writing. Your file may become corrupted if you break
these invariants. */
#if IN_LIBGCOV
GCOV_LINKAGE int gcov_open (const char */*name*/);
#else
GCOV_LINKAGE int gcov_open (const char */*name*/, int /*direction*/);
GCOV_LINKAGE int gcov_magic (gcov_unsigned_t, gcov_unsigned_t);
#endif
GCOV_LINKAGE int gcov_close (void);
/* Available everywhere. */

View File

@ -61,7 +61,7 @@ main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
printf ("/* Generated automatically by the program `%s'\n", argv[0]);
printf (" from `%s'. */\n", version_string);
printf ("\n");
printf ("#define GCOV_VERSION ((unsigned)%#08x) /* %.4s */\n",
printf ("#define GCOV_VERSION ((gcov_unsigned_t)%#08x) /* %.4s */\n",
version, v);
return 0;

View File

@ -417,13 +417,10 @@ print_usage (int error_p)
static void
print_version (void)
{
char v[4];
unsigned version = GCOV_VERSION;
unsigned ix;
for (ix = 4; ix--; version >>= 8)
v[ix] = version;
fnotice (stdout, "gcov %.4s (GCC %s)\n", v, version_string);
fnotice (stdout, "gcov %.4s (GCC %s)\n",
(const char *)&version, version_string);
fnotice (stdout, "Copyright (C) 2002 Free Software Foundation, Inc.\n");
fnotice (stdout,
"This is free software; see the source for copying conditions. There is NO\n\
@ -660,10 +657,10 @@ create_file_names (const char *file_name)
*cptr = 0;
length = strlen (name);
bbg_file_name = xmalloc (length + strlen (GCOV_GRAPH_SUFFIX) + 1);
bbg_file_name = xmalloc (length + strlen (GCOV_NOTE_SUFFIX) + 1);
strcpy (bbg_file_name, name);
strcpy (bbg_file_name + length, GCOV_GRAPH_SUFFIX);
strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
da_file_name = xmalloc (length + strlen (GCOV_DATA_SUFFIX) + 1);
strcpy (da_file_name, name);
@ -715,7 +712,7 @@ read_graph_file (void)
return 1;
}
bbg_file_time = gcov_time ();
if (gcov_read_unsigned () != GCOV_GRAPH_MAGIC)
if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
{
fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
gcov_close ();
@ -984,7 +981,7 @@ read_count_file (void)
fnotice (stderr, "%s:cannot open data file\n", da_file_name);
return 1;
}
if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
{
fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
cleanup:;
@ -994,16 +991,10 @@ read_count_file (void)
version = gcov_read_unsigned ();
if (version != GCOV_VERSION)
{
char v[4], e[4];
unsigned desired = GCOV_VERSION;
for (ix = 4; ix--; desired >>= 8, version >>= 8)
{
v[ix] = version;
e[ix] = desired;
}
fnotice (stderr, "%s:version `%.4s', prefer version `%.4s'\n",
da_file_name, v, e);
da_file_name, (const char *)&version, (const char *)&desired);
}
tag = gcov_read_unsigned ();
if (tag != bbg_stamp)

View File

@ -91,22 +91,19 @@ static struct gcov_info *gcov_list;
object file included in multiple programs. */
static gcov_unsigned_t gcov_crc32;
static void
gcov_version_mismatch (struct gcov_info *ptr, gcov_unsigned_t version)
static int
gcov_version (struct gcov_info *ptr, gcov_unsigned_t version)
{
gcov_unsigned_t expected = GCOV_VERSION;
unsigned ix;
char e[4], v[4];
for (ix = 4; ix--; expected >>= 8, version >>= 8)
if (version != GCOV_VERSION)
{
e[ix] = expected;
v[ix] = version;
fprintf (stderr,
"profiling:%s:Version mismatch - expected %.4s got %.4s\n",
ptr->filename, (const char *)&expected, (const char *)&version);
return 0;
}
fprintf (stderr,
"profiling:%s:Version mismatch - expected %.4s got %.4s\n",
ptr->filename, e, v);
return 1;
}
/* Dump the coverage counts. We merge with existing counts when
@ -163,7 +160,6 @@ gcov_exit (void)
struct gcov_ctr_summary *cs_ptr;
struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
int error = 0;
int merging;
gcov_unsigned_t tag, length;
gcov_position_t summary_pos = 0;
@ -200,18 +196,17 @@ gcov_exit (void)
fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
}
/* Open for modification, if possible */
merging = gcov_open (gi_ptr->filename, 0);
if (!merging)
if (!gcov_open (gi_ptr->filename))
{
fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
continue;
}
if (merging > 0)
tag = gcov_read_unsigned ();
if (tag)
{
/* Merge data from file. */
if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
if (tag != GCOV_DATA_MAGIC)
{
fprintf (stderr, "profiling:%s:Not a gcov data file\n",
gi_ptr->filename);
@ -220,11 +215,8 @@ gcov_exit (void)
continue;
}
length = gcov_read_unsigned ();
if (length != GCOV_VERSION)
{
gcov_version_mismatch (gi_ptr, length);
goto read_fatal;
}
if (!gcov_version (gi_ptr, length))
goto read_fatal;
length = gcov_read_unsigned ();
if (length != gi_ptr->stamp)
@ -299,16 +291,17 @@ gcov_exit (void)
goto rewrite;
}
}
if (!gcov_is_eof ())
{
read_error:;
fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
: "profiling:%s:Error merging\n", gi_ptr->filename);
goto read_fatal;
}
rewrite:;
gcov_rewrite ();
}
if (!gcov_is_eof ())
{
read_error:;
fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
: "profiling:%s:Error merging\n", gi_ptr->filename);
goto read_fatal;
}
rewrite:;
gcov_rewrite ();
if (!summary_pos)
memset (&program, 0, sizeof (program));
@ -414,9 +407,7 @@ __gcov_init (struct gcov_info *info)
{
if (!info->version)
return;
if (info->version != GCOV_VERSION)
gcov_version_mismatch (info, info->version);
else
if (gcov_version (info, info->version))
{
const char *ptr = info->filename;
gcov_unsigned_t crc32 = gcov_crc32;