summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog35
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/coverage.c21
-rw-r--r--gcc/gcov-dump.c33
-rw-r--r--gcc/gcov-io.c194
-rw-r--r--gcc/gcov-io.h174
-rw-r--r--gcc/gcov-iov.c2
-rw-r--r--gcc/gcov.c27
-rw-r--r--gcc/libgcov.c61
9 files changed, 279 insertions, 270 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d19961db885..00ab6ca8307 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,40 @@
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
coverage is on.
* configure: Regenerated.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index a0003cbeccd..8d9ceb8fd9b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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
diff --git a/gcc/coverage.c b/gcc/coverage.c
index 4a0033247ad..0bc7a26cecb 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -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 ();
}
diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c
index 67a34dcfff7..f6902a119e8 100644
--- a/gcc/gcov-dump.c
+++ b/gcc/gcov-dump.c
@@ -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 */
diff --git a/gcc/gcov-io.c b/gcc/gcov-io.c
index d0ca1266447..bce2d04e44a 100644
--- a/gcc/gcov-io.c
+++ b/gcc/gcov-io.c
@@ -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
@@ -112,6 +132,27 @@ gcov_close (void)
}
#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
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index 999d07eea08..35c31b955fe 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -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.
-
- 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).
-
- int32: byte3 byte2 byte1 byte0
- int64: byte7 byte6 byte5 byte4 byte3 byte2 byte1 byte0
+/* 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 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 | 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. */
diff --git a/gcc/gcov-iov.c b/gcc/gcov-iov.c
index a4ceeccbd3e..d6b39de3da1 100644
--- a/gcc/gcov-iov.c
+++ b/gcc/gcov-iov.c
@@ -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;
diff --git a/gcc/gcov.c b/gcc/gcov.c
index 276918f051b..d42cff15b2c 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -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)
diff --git a/gcc/libgcov.c b/gcc/libgcov.c
index 72126466f66..826617f14b4 100644
--- a/gcc/libgcov.c
+++ b/gcc/libgcov.c
@@ -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;