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> 2003-07-09 Nathan Sidwell <nathan@codesourcery.com>
* configure.in (BUILD_PREFIX, BUILD_PREFIX_1): Set if enable * 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 # contain the optimization flags, as you normally want code coverage
# without optimization. # without optimization.
COVERAGE_FLAGS = @coverage_flags@ COVERAGE_FLAGS = @coverage_flags@
coverageexts = .{da,bbg} coverageexts = .{gcda,gcno}
# The warning flags are separate from BOOT_CFLAGS because people tend to # The warning flags are separate from BOOT_CFLAGS because people tend to
# override optimization flags and we'd like them to still have warnings # override optimization flags and we'd like them to still have warnings

View File

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

View File

@ -155,33 +155,32 @@ dump_file (const char *filename)
/* magic */ /* magic */
{ {
unsigned magic = gcov_read_unsigned (); unsigned magic = gcov_read_unsigned ();
unsigned version = gcov_read_unsigned (); unsigned version;
const char *type = NULL; const char *type = NULL;
char e[4], v[4], m[4]; int endianness = 0;
unsigned expected = GCOV_VERSION;
unsigned ix; if ((endianness = gcov_magic (magic, GCOV_DATA_MAGIC)))
int different = version != GCOV_VERSION;
if (magic == GCOV_DATA_MAGIC)
type = "data"; type = "data";
else if (magic == GCOV_GRAPH_MAGIC) else if ((endianness = gcov_magic (magic, GCOV_NOTE_MAGIC)))
type = "graph"; type = "note";
else else
{ {
printf ("%s:not a gcov file\n", filename); printf ("%s:not a gcov file\n", filename);
gcov_close (); gcov_close ();
return; 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; unsigned expected = GCOV_VERSION;
v[ix] = version;
m[ix] = magic; 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 */ /* stamp */

View File

@ -26,13 +26,25 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#if !IN_GCOV #if !IN_GCOV
static void gcov_write_block (unsigned); static void gcov_write_block (unsigned);
static unsigned char *gcov_write_bytes (unsigned); static gcov_unsigned_t *gcov_write_bytes (unsigned);
#endif #endif
static const unsigned char *gcov_read_bytes (unsigned); static const gcov_unsigned_t *gcov_read_bytes (unsigned);
#if !IN_LIBGCOV #if !IN_LIBGCOV
static void gcov_allocate (unsigned); static void gcov_allocate (unsigned);
#endif #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 /* 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 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 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. */ opening an existing file and <0 on creating a new one. */
GCOV_LINKAGE int GCOV_LINKAGE int
#if IN_LIBGCOV
gcov_open (const char *name)
#else
gcov_open (const char *name, int mode) gcov_open (const char *name, int mode)
#endif
{ {
int result = 1; #if IN_LIBGCOV
const int mode = 0;
#endif
#if GCOV_LOCKED #if GCOV_LOCKED
struct flock s_flock; struct flock s_flock;
@ -61,20 +79,22 @@ gcov_open (const char *name, int mode)
gcov_var.offset = gcov_var.length = 0; gcov_var.offset = gcov_var.length = 0;
gcov_var.overread = -4u; gcov_var.overread = -4u;
gcov_var.error = 0; gcov_var.error = 0;
#if !IN_LIBGCOV
gcov_var.endian = 0;
#endif
if (mode >= 0) if (mode >= 0)
gcov_var.file = fopen (name, "r+b"); gcov_var.file = fopen (name, "r+b");
if (gcov_var.file) if (gcov_var.file)
gcov_var.mode = 1; gcov_var.mode = 1;
else if (mode <= 0) else if (mode <= 0)
{ {
result = -1;
gcov_var.file = fopen (name, "w+b"); gcov_var.file = fopen (name, "w+b");
if (gcov_var.file) if (gcov_var.file)
gcov_var.mode = -1; gcov_var.mode = mode * 2 + 1;
} }
if (!gcov_var.file) if (!gcov_var.file)
return 0; return 0;
setbuf (gcov_var.file, (char *)0); setbuf (gcov_var.file, (char *)0);
#if GCOV_LOCKED #if GCOV_LOCKED
@ -83,7 +103,7 @@ gcov_open (const char *name, int mode)
continue; continue;
#endif #endif
return result; return 1;
} }
/* Close the current gcov file. Flushes data to disk. Returns nonzero /* Close the current gcov file. Flushes data to disk. Returns nonzero
@ -111,6 +131,27 @@ gcov_close (void)
return gcov_var.error; 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 #if !IN_LIBGCOV
static void static void
gcov_allocate (unsigned length) 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 /* Allocate space to write BYTES bytes to the gcov file. Return a
pointer to those bytes, or NULL on failure. */ pointer to those bytes, or NULL on failure. */
static unsigned char * static gcov_unsigned_t *
gcov_write_bytes (unsigned bytes) gcov_write_bytes (unsigned bytes)
{ {
char unsigned *result; gcov_unsigned_t *result;
GCOV_CHECK_WRITING (); GCOV_CHECK_WRITING ();
GCOV_CHECK (!(bytes & 3));
#if IN_LIBGCOV #if IN_LIBGCOV
if (gcov_var.offset >= GCOV_BLOCK_SIZE) if (gcov_var.offset >= GCOV_BLOCK_SIZE)
{ {
@ -162,7 +204,7 @@ gcov_write_bytes (unsigned bytes)
if (gcov_var.offset + bytes > gcov_var.alloc) if (gcov_var.offset + bytes > gcov_var.alloc)
gcov_allocate (gcov_var.offset + bytes); gcov_allocate (gcov_var.offset + bytes);
#endif #endif
result = &gcov_var.buffer[gcov_var.offset]; result = (gcov_unsigned_t *)&gcov_var.buffer[gcov_var.offset];
gcov_var.offset += bytes; gcov_var.offset += bytes;
return result; return result;
@ -174,18 +216,9 @@ gcov_write_bytes (unsigned bytes)
GCOV_LINKAGE void GCOV_LINKAGE void
gcov_write_unsigned (gcov_unsigned_t value) gcov_write_unsigned (gcov_unsigned_t value)
{ {
unsigned char *buffer = gcov_write_bytes (4); gcov_unsigned_t *buffer = gcov_write_bytes (4);
unsigned ix;
for (ix = 4; ix--; ) buffer[0] = value;
{
buffer[ix] = value;
value >>= 8;
}
if (sizeof (value) > 4 && value)
gcov_var.error = -1;
return;
} }
/* Write counter VALUE to coverage file. Sets error flag /* Write counter VALUE to coverage file. Sets error flag
@ -195,17 +228,16 @@ gcov_write_unsigned (gcov_unsigned_t value)
GCOV_LINKAGE void GCOV_LINKAGE void
gcov_write_counter (gcov_type value) gcov_write_counter (gcov_type value)
{ {
unsigned char *buffer = gcov_write_bytes (8); gcov_unsigned_t *buffer = gcov_write_bytes (8);
unsigned ix;
for (ix = 8; ix--; ) buffer[0] = (gcov_unsigned_t) value;
{ if (sizeof (value) > sizeof (gcov_unsigned_t))
buffer[ix] = value; buffer[1] = (gcov_unsigned_t) (value >> 32);
value >>= 8; else
} buffer[1] = 0;
if ((sizeof (value) > 8 && value) || value < 0)
if (value < 0)
gcov_var.error = -1; gcov_var.error = -1;
return;
} }
#endif /* IN_LIBGCOV */ #endif /* IN_LIBGCOV */
@ -217,28 +249,20 @@ GCOV_LINKAGE void
gcov_write_string (const char *string) gcov_write_string (const char *string)
{ {
unsigned length = 0; unsigned length = 0;
unsigned pad = 0; unsigned alloc = 0;
unsigned rem = 0; gcov_unsigned_t *buffer;
unsigned char *buffer;
unsigned ix;
unsigned value;
if (string) if (string)
{ {
length = strlen (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; buffer[0] = alloc;
for (ix = 4; ix--; ) buffer[alloc] = 0;
{ memcpy (&buffer[1], string, length);
buffer[ix] = value;
value >>= 8;
}
memcpy (buffer + 4, string, length);
memcpy (buffer + 4 + length, &pad, rem);
} }
#endif #endif
@ -250,15 +274,11 @@ GCOV_LINKAGE gcov_position_t
gcov_write_tag (gcov_unsigned_t tag) gcov_write_tag (gcov_unsigned_t tag)
{ {
gcov_position_t result = gcov_var.start + gcov_var.offset; gcov_position_t result = gcov_var.start + gcov_var.offset;
unsigned char *buffer = gcov_write_bytes (8); gcov_unsigned_t *buffer = gcov_write_bytes (8);
unsigned ix;
for (ix = 4; ix--; ) buffer[0] = tag;
{ buffer[1] = 0;
buffer[ix] = tag;
tag >>= 8;
}
memset (buffer + 4, 0, 4);
return result; return result;
} }
@ -272,20 +292,15 @@ gcov_write_length (gcov_position_t position)
{ {
unsigned offset; unsigned offset;
gcov_unsigned_t length; gcov_unsigned_t length;
unsigned char *buffer; gcov_unsigned_t *buffer;
unsigned ix;
GCOV_CHECK_WRITING (); GCOV_CHECK_WRITING ();
GCOV_CHECK (position + 8 <= gcov_var.start + gcov_var.offset); GCOV_CHECK (position + 8 <= gcov_var.start + gcov_var.offset);
GCOV_CHECK (position >= gcov_var.start); GCOV_CHECK (position >= gcov_var.start);
offset = position - gcov_var.start; offset = position - gcov_var.start;
length = gcov_var.offset - offset - 8; length = gcov_var.offset - offset - 8;
buffer = &gcov_var.buffer[offset + 4]; buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset];
for (ix = 4; ix--; ) buffer[1] = length;
{
buffer[ix] = length;
length >>= 8;
}
if (gcov_var.offset >= GCOV_BLOCK_SIZE) if (gcov_var.offset >= GCOV_BLOCK_SIZE)
gcov_write_block (gcov_var.offset); gcov_write_block (gcov_var.offset);
} }
@ -297,20 +312,10 @@ gcov_write_length (gcov_position_t position)
GCOV_LINKAGE void GCOV_LINKAGE void
gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length) gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
{ {
unsigned char *buffer = gcov_write_bytes (8); gcov_unsigned_t *buffer = gcov_write_bytes (8);
unsigned ix;
for (ix = 4; ix--; ) buffer[0] = tag;
{ buffer[1] = length;
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 nonzero on /* 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 /* Return a pointer to read BYTES bytes from the gcov file. Returns
NULL on failure (read past EOF). */ NULL on failure (read past EOF). */
static const unsigned char * static const gcov_unsigned_t *
gcov_read_bytes (unsigned bytes) gcov_read_bytes (unsigned bytes)
{ {
const unsigned char *result; const gcov_unsigned_t *result;
unsigned excess = gcov_var.length - gcov_var.offset; unsigned excess = gcov_var.length - gcov_var.offset;
GCOV_CHECK_READING (); GCOV_CHECK_READING ();
GCOV_CHECK (!(bytes & 3));
if (excess < bytes) if (excess < bytes)
{ {
gcov_var.start += gcov_var.offset; gcov_var.start += gcov_var.offset;
@ -379,7 +385,7 @@ gcov_read_bytes (unsigned bytes)
return 0; return 0;
} }
} }
result = &gcov_var.buffer[gcov_var.offset]; result = (gcov_unsigned_t *)&gcov_var.buffer[gcov_var.offset];
gcov_var.offset += bytes; gcov_var.offset += bytes;
return result; return result;
} }
@ -390,20 +396,12 @@ gcov_read_bytes (unsigned bytes)
GCOV_LINKAGE gcov_unsigned_t GCOV_LINKAGE gcov_unsigned_t
gcov_read_unsigned (void) gcov_read_unsigned (void)
{ {
gcov_unsigned_t value = 0; gcov_unsigned_t value;
unsigned ix; const gcov_unsigned_t *buffer = gcov_read_bytes (4);
const unsigned char *buffer = gcov_read_bytes (4);
if (!buffer) if (!buffer)
return 0; return 0;
for (ix = sizeof (value); ix < 4; ix++) value = from_file (buffer[0]);
if (buffer[ix])
gcov_var.error = -1;
for (ix = 0; ix != 4; ix++)
{
value <<= 8;
value |= buffer[ix];
}
return value; return value;
} }
@ -413,20 +411,17 @@ gcov_read_unsigned (void)
GCOV_LINKAGE gcov_type GCOV_LINKAGE gcov_type
gcov_read_counter (void) gcov_read_counter (void)
{ {
gcov_type value = 0; gcov_type value;
unsigned ix; const gcov_unsigned_t *buffer = gcov_read_bytes (8);
const unsigned char *buffer = gcov_read_bytes (8);
if (!buffer) if (!buffer)
return 0; return 0;
for (ix = sizeof (value); ix < 8; ix++) value = from_file (buffer[0]);
if (buffer[ix]) if (sizeof (value) > sizeof (gcov_unsigned_t))
gcov_var.error = -1; value |= ((gcov_type) from_file (buffer[1])) << 32;
for (ix = 0; ix != 8; ix++) else if (buffer[1])
{ gcov_var.error = -1;
value <<= 8;
value |= buffer[ix];
}
if (value < 0) if (value < 0)
gcov_var.error = -1; gcov_var.error = -1;
return value; return value;
@ -445,7 +440,6 @@ gcov_read_string (void)
if (!length) if (!length)
return 0; return 0;
length += 4 - (length & 3);
return (const char *) gcov_read_bytes (length); return (const char *) gcov_read_bytes (length);
} }
#endif #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 This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */ the executable file might be covered by the GNU General Public License. */
/* Coverage information is held in two files. A basic block graph /* Coverage information is held in two files. A notes file, which is
file, which is generated by the compiler, and a counter file, which generated by the compiler, and a data file, which is generated
is generated by the program under test. Both files use a similar by the program under test. Both files use a similar structure. We
structure. We do not attempt to make these files backwards do not attempt to make these files backwards compatible with
compatible with previous versions, as you only need coverage previous versions, as you only need coverage information when
information when developing a program. We do hold version developing a program. We do hold version information, so that
information, so that mismatches can be detected, and we use a mismatches can be detected, and we use a format that allows tools
format that allows tools to skip information they do not understand to skip information they do not understand or are not interested
or are not interested in. in.
Numbers are recorded in big endian unsigned binary form. Either in Numbers are recorded in the 32 bit unsigned binary form of the
32 or 64 bits. Strings are stored with a length count and NUL endianness of the machine generating the file. 64 bit numbers are
terminator, and 0 to 3 bytes of zero padding up to the next 4 byte stored as two 32 bit numbers, the low part first. Strings are
boundary. Zero length and NULL strings are simply stored as a stored as length rounded up to 4 followed by the string and then 1
length of zero (they have no trailing NUL or padding). 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 int32: byte3 byte2 byte1 byte0 | byte0 byte1 byte2 byte3
int64: byte7 byte6 byte5 byte4 byte3 byte2 byte1 byte0 int64: int32:low int32:high
string: int32:0 | int32:length char* char:0 padding string: int32:0 | int32:length char* char:0 padding
padding: | char:0 | char:0 char:0 | char:0 char:0 char:0 padding: | char:0 | char:0 char:0 | char:0 char:0 char:0
item: int32 | int64 | string 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* file : int32:magic int32:version int32:stamp record*
The magic ident is different for the bbg and the counter files. The magic ident is different for the notes and the data files. The
The version is the same for both files and is derived from gcc's magic ident is used to determine the endianness of the file, when
version number. The stamp value is used to synchronize bbg and reading. The version is the same for both files and is derived
counter files and to synchronize merging within a counter file. It from gcc's version number. The stamp value is used to synchronize
need not be an absolute time stamp, merely a ticker that increments note and data files and to synchronize merging within a data
fast enough and cycles slow enough to distinguish different file. It need not be an absolute time stamp, merely a ticker that
compile/run/compile cycles. increments fast enough and cycles slow enough to distinguish
different compile/run/compile cycles.
Although the ident and version are formally 32 bit Although the ident and version are formally 32 bit numbers, they
numbers, they are derived from 4 character ASCII strings. The are derived from 4 character ASCII strings. The version number
version number consists of the single character major version consists of the single character major version number, a two
number, a two character minor version number (leading zero for character minor version number (leading zero for versions less than
versions less than 10), and a single character indicating the 10), and a single character indicating the status of the release.
status of the release. That will be 'e' experimental, 'p' That will be 'e' experimental, 'p' prerelease and 'r' for release.
prerelease and 'r' for release. Because, by good fortune, these are Because, by good fortune, these are in alphabetical order, string
in alphabetical order, string collating can be used to compare collating can be used to compare version strings. Be aware that
version strings, and because numbers are stored big endian, numeric the 'e' designation will (naturally) be unstable and might be
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
incompatible with itself. For gcc 3.4 experimental, it would be incompatible with itself. For gcc 3.4 experimental, it would be
'304e' (0x33303465). When the major version reaches 10, the letters '304e' (0x33303465). When the major version reaches 10, the
A-Z will be used. Assuming minor increments releases every 6 letters A-Z will be used. Assuming minor increments releases every
months, we have to make a major increment every 50 years. Assuming 6 months, we have to make a major increment every 50 years.
major increments releases every 5 years, we're ok for the next 155 Assuming major increments releases every 5 years, we're ok for the
years -- good enough for me. next 155 years -- good enough for me.
A record has a tag, length and variable amount of data. 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* data: item*
Records are not nested, but there is a record hierarchy. Tag Records are not nested, but there is a record hierarchy. Tag
numbers reflect this hierarchy. Tags are unique across bbg and da numbers reflect this hierarchy. Tags are unique across note and
files. Some record types have a varying amount of data. The LENGTH data files. Some record types have a varying amount of data. The
is usually used to determine how much data. The tag value is split LENGTH is usually used to determine how much data. The tag value
into 4 8-bit fields, one for each of four possible levels. The is split into 4 8-bit fields, one for each of four possible levels.
most significant is allocated first. Unused levels are zero. The most significant is allocated first. Unused levels are zero.
Active levels are odd-valued, so that the LSB of the level is one. Active levels are odd-valued, so that the LSB of the level is one.
A sub-level incorporates the values of its superlevels. This A sub-level incorporates the values of its superlevels. This
formatting allows you to determine the tag hierarchy, without formatting allows you to determine the tag hierarchy, without
understanding the tags themselves, and is similar to the standard understanding the tags themselves, and is similar to the standard
section numbering used in technical documents. Level values section numbering used in technical documents. Level values
[1..3f] are used for common tags, values [41..9f] for the graph [1..3f] are used for common tags, values [41..9f] for the notes
file and [a1..ff] for the counter file. file and [a1..ff] for the data file.
The basic block graph file contains the following records The basic block graph file contains the following records
bbg: unit function-graph* note: unit function-graph*
unit: header int32:checksum string:source unit: header int32:checksum string:source
function-graph: announce_function basic_blocks {arcs | lines}* function-graph: announce_function basic_blocks {arcs | lines}*
announce_function: header int32:ident int32:checksum announce_function: header int32:ident int32:checksum
@ -130,7 +130,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
blocks they are for. blocks they are for.
The data file contains the following records. 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 unit: header int32:checksum
function-data: announce_function arc_counts function-data: announce_function arc_counts
announce_function: header int32:ident int32:checksum 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 count-summary: int32:num int32:runs int64:sum
int64:max int64:sum_max int64:max int64:sum_max
The ANNOUNCE_FUNCTION record is the same as that in the BBG file, The ANNOUNCE_FUNCTION record is the same as that in the note file,
but without the source location. but without the source location. The ARC_COUNTS gives the counter
The ARC_COUNTS gives the counter values for those arcs that are values for those arcs that are instrumented. The SUMMARY records
instrumented. The SUMMARY records give information about the whole give information about the whole object file and about the whole
object file and about the whole program. The checksum is used for program. The checksum is used for whole program summaries, and
whole program summaries, and disambiguates different programs which disambiguates different programs which include the same
include the same instrumented object file. There may be several instrumented object file. There may be several program summaries,
program summaries, each with a unique checksum. The object each with a unique checksum. The object summary's checkum is zero.
summary's checkum is zero. Note that the da file might contain Note that the data file might contain information from several runs
information from several runs concatenated, or the data might be concatenated, or the data might be merged.
merged.
This file is included by both the compiler, gcov tools and the This file is included by both the compiler, gcov tools and the
runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to 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. */ /* 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_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 #endif
@ -240,21 +239,21 @@ typedef HOST_WIDEST_INT gcov_type;
#endif #endif
/* File suffixes. */ /* File suffixes. */
#define GCOV_DATA_SUFFIX ".da" #define GCOV_DATA_SUFFIX ".gcda"
#define GCOV_GRAPH_SUFFIX ".bbg" #define GCOV_NOTE_SUFFIX ".gcno"
/* File magic. */ /* File magic. Must not be palindromes. */
#define GCOV_DATA_MAGIC 0x67636f76 /* "gcov" */ #define GCOV_DATA_MAGIC ((gcov_unsigned_t)0x67636461) /* "gcda" */
#define GCOV_GRAPH_MAGIC 0x67626267 /* "gbbg" */ #define GCOV_NOTE_MAGIC ((gcov_unsigned_t)0x67636e6f) /* "gcno" */
/* gcov-iov.h is automatically generated by the makefile from /* gcov-iov.h is automatically generated by the makefile from
version.c, it looks like version.c, it looks like
#define GCOV_VERSION ((unsigned)0x89abcdef) #define GCOV_VERSION ((gcov_unsigned_t)0x89abcdef)
*/ */
#include "gcov-iov.h" #include "gcov-iov.h"
/* The record tags. Values [1..3f] are for tags which may be in either /* 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. */ the data file. */
#define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000) #define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000)
@ -374,7 +373,7 @@ struct gcov_ctr_info
struct gcov_info struct gcov_info
{ {
gcov_unsigned_t version; /* expected version number */ 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 */ gcov_unsigned_t stamp; /* uniquifying time stamp */
const char *filename; /* output file name */ const char *filename; /* output file name */
@ -398,11 +397,11 @@ extern void __gcov_flush (void);
/* The merge function that just sums the counters. */ /* The merge function that just sums the counters. */
extern void __gcov_merge_add (gcov_type *, unsigned); 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); extern void __gcov_merge_single (gcov_type *, unsigned);
/* The merge function to choose the most often difference between consecutive /* The merge function to choose the most common difference between
values. */ consecutive values. */
extern void __gcov_merge_delta (gcov_type *, unsigned); extern void __gcov_merge_delta (gcov_type *, unsigned);
#endif /* IN_LIBGCOV */ #endif /* IN_LIBGCOV */
@ -425,24 +424,31 @@ GCOV_LINKAGE struct gcov_var
fit within this buffer and we always can transfer GCOV_BLOCK_SIZE fit within this buffer and we always can transfer GCOV_BLOCK_SIZE
to and from the disk. libgcov never backtracks and only writes 4 to and from the disk. libgcov never backtracks and only writes 4
or 8 byte objects. */ or 8 byte objects. */
unsigned char buffer[GCOV_BLOCK_SIZE + 4]; char buffer[GCOV_BLOCK_SIZE + 4] __attribute__ ((aligned (4)));
#else #else
int endian; /* Swap endianness. */
/* Holds a variable length block, as the compiler can write /* Holds a variable length block, as the compiler can write
strings and needs to backtrack. */ strings and needs to backtrack. */
size_t alloc; size_t alloc;
unsigned char *buffer; char *buffer;
#endif #endif
} gcov_var; } gcov_var;
/* Functions for reading and writing gcov files. You can open a file /* Functions for reading and writing gcov files. In libgcov you can
for (1) reading or (2) writing or (3) reading then rewriting. When open the file for reading then writing. Elsewhere you can open the
reading a file you may use the gcov_read_* functions, gcov_sync, file either for reading or for writing. When reading a file you may
gcov_position, & gcov_error. When writing a file you use the gcov_read_* functions, gcov_sync, gcov_position, &
may use the gcov_write functions, gcov_seek & gcov_error. When a gcov_error. When writing a file you may use the gcov_write
file is to be rewritten you use the functions for reading, then functions, gcov_seek & gcov_error. When a file is to be rewritten
gcov_rewrite then the functions for writing. Your file may become you use the functions for reading, then gcov_rewrite then the
corrupted if you break these invariants. */ functions for writing. Your file may become corrupted if you break
GCOV_LINKAGE int gcov_open (const char */*name*/, int /*truncate*/); 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); GCOV_LINKAGE int gcov_close (void);
/* Available everywhere. */ /* 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 ("/* Generated automatically by the program `%s'\n", argv[0]);
printf (" from `%s'. */\n", version_string); printf (" from `%s'. */\n", version_string);
printf ("\n"); printf ("\n");
printf ("#define GCOV_VERSION ((unsigned)%#08x) /* %.4s */\n", printf ("#define GCOV_VERSION ((gcov_unsigned_t)%#08x) /* %.4s */\n",
version, v); version, v);
return 0; return 0;

View File

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

View File

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