summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>2003-05-14 16:01:20 +0000
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>2003-05-14 16:01:20 +0000
commit80abd9e48ad1b4de289b09cc79163ed49ac7b579 (patch)
tree1253c5f7880fe8708b5e0666b848785f27dcd9cc /gcc
parent9033d3d32c1b5068630d3b58b86214c2e2b1b6b3 (diff)
downloadgcc-80abd9e48ad1b4de289b09cc79163ed49ac7b579.tar.gz
* gcov-io.h (gcov_write_bytes, gcov_read_bytes): Remove here.
(GCOV_TAG_*) Force type to gcov_unsigned_t. (GCOV_CHECK, GCOV_CHECK_READING, GCOV_CHECK_WRITING): New. (struct gcov_var): Remove modified. Add start, length, offset, overread. Have buffer array for libgcov. (gcov_sync, gcov_seek): Definitions moved to gcov-io.c. (gcov_position, gcov_rewrite, gcov_is_eof): Adjust. * gcov-io.c (gcov_open): Set mode, do not read anything. (gcov_close): Write final block. (gcov_write_block, gcov_allocate): New. (gcov_write_bytes): Make static. Write or allocate buffer. (gcov_write_unsigned, gcov_write_counter): Buffer can never be null. (gcov_write_string): Adjust. (gcov_write_tag) (gcov_write_length): Adjust. Flush the block. (gcov_write_tag_length): Buffer can never be null. (gcov_read_bytes): Make static. Read in block. (gcov_sync): Moved here. Adjust. (gcov_seek): Moved here. Adjust. * coverage.c (read_counts_file): Adjust. * gcov-dump.c (print_prefix): Add position parameter. (flag_dump_positions): New flag. (options, main, print_usage): Add it. (dump_file, tag_blocks, tag_arcs, tag_lines, tag_counters, tag_summary): Adjust. * gcov.c (read_graph_file, read_count_file): Adjust. * libgcov.c (gcov_exit): Adjust. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@66805 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog29
-rw-r--r--gcc/coverage.c24
-rw-r--r--gcc/gcov-dump.c89
-rw-r--r--gcc/gcov-io.c274
-rw-r--r--gcc/gcov-io.h202
-rw-r--r--gcc/gcov.c41
-rw-r--r--gcc/libgcov.c32
7 files changed, 413 insertions, 278 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b449645f8fc..f8af6e71d2c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,34 @@
2003-05-14 Nathan Sidwell <nathan@codesourcery.com>
+ * gcov-io.h (gcov_write_bytes, gcov_read_bytes): Remove here.
+ (GCOV_TAG_*) Force type to gcov_unsigned_t.
+ (GCOV_CHECK, GCOV_CHECK_READING, GCOV_CHECK_WRITING): New.
+ (struct gcov_var): Remove modified. Add start, length, offset,
+ overread. Have buffer array for libgcov.
+ (gcov_sync, gcov_seek): Definitions moved to gcov-io.c.
+ (gcov_position, gcov_rewrite, gcov_is_eof): Adjust.
+ * gcov-io.c (gcov_open): Set mode, do not read anything.
+ (gcov_close): Write final block.
+ (gcov_write_block, gcov_allocate): New.
+ (gcov_write_bytes): Make static. Write or allocate buffer.
+ (gcov_write_unsigned, gcov_write_counter): Buffer can never be
+ null.
+ (gcov_write_string): Adjust.
+ (gcov_write_tag)
+ (gcov_write_length): Adjust. Flush the block.
+ (gcov_write_tag_length): Buffer can never be null.
+ (gcov_read_bytes): Make static. Read in block.
+ (gcov_sync): Moved here. Adjust.
+ (gcov_seek): Moved here. Adjust.
+ * coverage.c (read_counts_file): Adjust.
+ * gcov-dump.c (print_prefix): Add position parameter.
+ (flag_dump_positions): New flag.
+ (options, main, print_usage): Add it.
+ (dump_file, tag_blocks, tag_arcs, tag_lines, tag_counters,
+ tag_summary): Adjust.
+ * gcov.c (read_graph_file, read_count_file): Adjust.
+ * libgcov.c (gcov_exit): Adjust.
+
* Makefile.in (LIBGCC_DEPS): Use $(srcdir) on gcov files
(libgcov.a): Depend on libgcc.a.
(gcov.o, gcov-dump.o): Add gcov-io.c.
diff --git a/gcc/coverage.c b/gcc/coverage.c
index 5926a7ea7a5..1b537c621eb 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -158,7 +158,9 @@ read_counts_file ()
unsigned ix;
counts_entry_t *summaried = NULL;
unsigned seen_summary = 0;
-
+ gcov_unsigned_t tag;
+ int error = 0;
+
if (!gcov_open (da_file_name, 1))
return;
@@ -187,13 +189,11 @@ read_counts_file ()
counts_hash = htab_create (10,
htab_counts_entry_hash, htab_counts_entry_eq,
htab_counts_entry_del);
- while (!gcov_is_eof ())
+ while ((tag = gcov_read_unsigned ()))
{
- gcov_unsigned_t tag, length;
+ gcov_unsigned_t length;
gcov_position_t offset;
- int error;
- tag = gcov_read_unsigned ();
length = gcov_read_unsigned ();
offset = gcov_position ();
if (tag == GCOV_TAG_FUNCTION)
@@ -284,14 +284,16 @@ read_counts_file ()
}
gcov_sync (offset, length);
if ((error = gcov_is_error ()))
- {
- warning (error < 0 ? "`%s' has overflowed" : "`%s' is corrupted",
- da_file_name);
- htab_delete (counts_hash);
- break;
- }
+ break;
}
+ if (!gcov_is_eof ())
+ {
+ warning (error < 0 ? "`%s' has overflowed" : "`%s' is corrupted",
+ da_file_name);
+ htab_delete (counts_hash);
+ }
+
gcov_close ();
}
diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c
index d70e4dddc8b..c7c31ad5454 100644
--- a/gcc/gcov-dump.c
+++ b/gcc/gcov-dump.c
@@ -28,7 +28,7 @@ Boston, MA 02111-1307, USA. */
#include "gcov-io.c"
static void dump_file PARAMS ((const char *));
-static void print_prefix PARAMS ((const char *, unsigned));
+static void print_prefix PARAMS ((const char *, unsigned, gcov_position_t));
static void print_usage PARAMS ((void));
static void print_version PARAMS ((void));
static void tag_function PARAMS ((const char *, unsigned, unsigned));
@@ -47,12 +47,14 @@ typedef struct tag_format
} tag_format_t;
static int flag_dump_contents = 0;
+static int flag_dump_positions = 0;
static const struct option options[] =
{
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "long", no_argument, NULL, 'l' },
+ { "positions", no_argument, NULL, 'o' },
};
static const tag_format_t tag_table[] =
@@ -75,7 +77,7 @@ int main (argc, argv)
{
int opt;
- while ((opt = getopt_long (argc, argv, "hlv", options, NULL)) != -1)
+ while ((opt = getopt_long (argc, argv, "hlpv", options, NULL)) != -1)
{
switch (opt)
{
@@ -88,6 +90,9 @@ int main (argc, argv)
case 'l':
flag_dump_contents = 1;
break;
+ case 'p':
+ flag_dump_positions = 1;
+ break;
default:
fprintf (stderr, "unknown flag `%c'\n", opt);
}
@@ -106,6 +111,7 @@ print_usage ()
printf (" -h, --help Print this help\n");
printf (" -v, --version Print version number\n");
printf (" -l, --long Dump record contents too\n");
+ printf (" -p, --positions Dump record positions\n");
}
static void
@@ -124,13 +130,17 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
}
static void
-print_prefix (filename, depth)
+print_prefix (filename, depth, position)
const char *filename;
unsigned depth;
+ gcov_position_t position;
{
static const char prefix[] = " ";
- printf ("%s:%.*s", filename, (int) depth, prefix);
+ printf ("%s:", filename);
+ if (flag_dump_positions)
+ printf ("%lu:", (unsigned long) position);
+ printf ("%.*s", (int) depth, prefix);
}
static void
@@ -178,30 +188,29 @@ dump_file (filename)
printf ("%s:warning:current version is `%.4s'\n", filename, e);
}
- while (!gcov_is_eof ())
+ while (1)
{
- unsigned tag = gcov_read_unsigned ();
- unsigned length = gcov_read_unsigned ();
- unsigned long base = gcov_position ();
+ gcov_position_t base, position = gcov_position ();
+ unsigned tag, length;
tag_format_t const *format;
unsigned tag_depth;
int error;
-
+ unsigned mask;
+
+ tag = gcov_read_unsigned ();
if (!tag)
- tag_depth = depth;
- else
+ break;
+ length = gcov_read_unsigned ();
+ base = gcov_position ();
+ mask = GCOV_TAG_MASK (tag) >> 1;
+ for (tag_depth = 4; mask; mask >>= 8)
{
- unsigned mask = GCOV_TAG_MASK (tag) >> 1;
-
- for (tag_depth = 4; mask; mask >>= 8)
+ if ((mask & 0xff) != 0xff)
{
- if ((mask & 0xff) != 0xff)
- {
- printf ("%s:tag `%08x' is invalid\n", filename, tag);
- break;
- }
- tag_depth--;
+ printf ("%s:tag `%08x' is invalid\n", filename, tag);
+ break;
}
+ tag_depth--;
}
for (format = tag_table; format->name; format++)
if (format->tag == tag)
@@ -220,7 +229,7 @@ dump_file (filename)
tags[depth - 1] = tag;
}
- print_prefix (filename, tag_depth);
+ print_prefix (filename, tag_depth, position);
printf ("%08x:%4u:%s", tag, length, format->name);
if (format->proc)
(*format->proc) (filename, tag, length);
@@ -246,6 +255,8 @@ dump_file (filename)
break;
}
}
+ if (!gcov_is_eof ())
+ printf ("%s:early end of file\n", filename);
gcov_close ();
}
@@ -289,7 +300,11 @@ tag_blocks (filename, tag, length)
for (ix = 0; ix != n_blocks; ix++)
{
if (!(ix & 7))
- printf ("\n%s:\t\t%u", filename, ix);
+ {
+ printf ("\n");
+ print_prefix (filename, 0, gcov_position ());
+ printf ("\t\t%u", ix);
+ }
printf (" %04x", gcov_read_unsigned ());
}
}
@@ -311,11 +326,16 @@ tag_arcs (filename, tag, length)
for (ix = 0; ix != n_arcs; ix++)
{
- unsigned dst = gcov_read_unsigned ();
- unsigned flags = gcov_read_unsigned ();
+ unsigned dst, flags;
if (!(ix & 3))
- printf ("\n%s:\tblock %u:", filename, blockno);
+ {
+ printf ("\n");
+ print_prefix (filename, 0, gcov_position ());
+ printf ("\tblock %u:", blockno);
+ }
+ dst = gcov_read_unsigned ();
+ flags = gcov_read_unsigned ();
printf (" %u:%04x", dst, flags);
}
}
@@ -334,6 +354,7 @@ tag_lines (filename, tag, length)
while (1)
{
+ gcov_position_t position = gcov_position ();
const char *source = NULL;
unsigned lineno = gcov_read_unsigned ();
@@ -347,7 +368,9 @@ tag_lines (filename, tag, length)
if (!sep)
{
- printf ("\n%s:\tblock %u:", filename, blockno);
+ printf ("\n");
+ print_prefix (filename, 0, position);
+ printf ("\tblock %u:", blockno);
sep = "";
}
if (lineno)
@@ -381,10 +404,16 @@ tag_counters (filename, tag, length)
for (ix = 0; ix != n_counts; ix++)
{
- gcov_type count = gcov_read_counter ();
+ gcov_type count;
if (!(ix & 7))
- printf ("\n%s:\t\t%u", filename, ix);
+ {
+ printf ("\n");
+ print_prefix (filename, 0, gcov_position ());
+ printf ("\t\t%u", ix);
+ }
+
+ count = gcov_read_counter ();
printf (" ");
printf (HOST_WIDEST_INT_PRINT_DEC, count);
}
@@ -405,7 +434,9 @@ tag_summary (filename, tag, length)
for (ix = 0; ix != GCOV_COUNTERS; ix++)
{
- printf ("\n%sL\t\tcounts=%u, runs=%u", filename,
+ printf ("\n");
+ print_prefix (filename, 0, 0);
+ printf ("\t\tcounts=%u, runs=%u",
summary.ctrs[ix].num, summary.ctrs[ix].runs);
printf (", sum_all=" HOST_WIDEST_INT_PRINT_DEC,
diff --git a/gcc/gcov-io.c b/gcc/gcov-io.c
index d61cff392cd..3aad30e445d 100644
--- a/gcc/gcov-io.c
+++ b/gcc/gcov-io.c
@@ -24,6 +24,15 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
/* Routines declared in gcov-io.h. This file should be #included by
another source file, after having #included gcov-io.h. */
+#if !IN_GCOV
+static void gcov_write_block (unsigned);
+static unsigned char *gcov_write_bytes (unsigned);
+#endif
+static const unsigned char *gcov_read_bytes (unsigned);
+#if !IN_LIBGCOV
+static void gcov_allocate (unsigned);
+#endif
+
/* 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
@@ -36,7 +45,6 @@ GCOV_LINKAGE int
gcov_open (const char *name, int mode)
{
int result = 1;
- size_t alloc = 1024;
#if GCOV_LOCKED
struct flock s_flock;
@@ -49,63 +57,32 @@ gcov_open (const char *name, int mode)
if (gcov_var.file)
abort ();
- gcov_var.position = gcov_var.length = 0;
- gcov_var.error = gcov_var.modified = 0;
+ gcov_var.start = 0;
+ gcov_var.offset = gcov_var.length = 0;
+ gcov_var.overread = -4u;
+ gcov_var.error = 0;
if (mode >= 0)
gcov_var.file = fopen (name, "r+b");
- if (!gcov_var.file && mode <= 0)
+ 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;
}
if (!gcov_var.file)
return 0;
+ setbuf (gcov_var.file, (char *)0);
+
#if GCOV_LOCKED
while (fcntl (fileno (gcov_var.file), F_SETLKW, &s_flock)
&& errno == EINTR)
continue;
#endif
- if (result >= 0)
- {
- if (fseek (gcov_var.file, 0, SEEK_END))
- {
- fclose (gcov_var.file);
- gcov_var.file = 0;
- return 0;
- }
- gcov_var.length = ftell (gcov_var.file);
- fseek (gcov_var.file, 0, SEEK_SET);
- alloc += gcov_var.length;
- }
- if (alloc > gcov_var.alloc)
- {
- if (gcov_var.buffer)
- free (gcov_var.buffer);
- gcov_var.alloc = alloc;
-#if IN_LIBGCOV
- gcov_var.buffer = malloc (gcov_var.alloc);
- if (!gcov_var.buffer)
- {
- fclose (gcov_var.file);
- gcov_var.file = 0;
- gcov_var.length = 0;
- gcov_var.alloc = 0;
- return 0;
- }
-#else
- gcov_var.buffer = xmalloc (gcov_var.alloc);
-#endif
- }
- if (result >= 0
- && fread (gcov_var.buffer, gcov_var.length, 1, gcov_var.file) != 1)
- {
- fclose (gcov_var.file);
- gcov_var.file = 0;
- gcov_var.length = 0;
- return 0;
- }
return result;
}
@@ -115,15 +92,12 @@ gcov_open (const char *name, int mode)
GCOV_LINKAGE int
gcov_close ()
{
- int result = 0;
-
if (gcov_var.file)
{
- if (gcov_var.modified
- && (fseek (gcov_var.file, 0, SEEK_SET)
- || fwrite (gcov_var.buffer, gcov_var.length,
- 1, gcov_var.file) != 1))
- result = 1;
+#if !IN_GCOV
+ if (gcov_var.offset && gcov_var.mode < 0)
+ gcov_write_block (gcov_var.offset);
+#endif
fclose (gcov_var.file);
gcov_var.file = 0;
gcov_var.length = 0;
@@ -133,47 +107,64 @@ gcov_close ()
gcov_var.alloc = 0;
gcov_var.buffer = 0;
#endif
- return result ? 1 : gcov_var.error;
+ gcov_var.mode = 0;
+ return gcov_var.error;
+}
+
+#if !IN_LIBGCOV
+static void
+gcov_allocate (unsigned length)
+{
+ size_t new_size = gcov_var.alloc;
+
+ if (!new_size)
+ new_size = GCOV_BLOCK_SIZE;
+ new_size += length;
+ new_size *= 2;
+
+ gcov_var.alloc = new_size;
+ gcov_var.buffer = xrealloc (gcov_var.buffer, new_size);
}
+#endif
#if !IN_GCOV
+/* Write out the current block, if needs be. */
+
+static void
+gcov_write_block (unsigned size)
+{
+ if (fwrite (gcov_var.buffer, size, 1, gcov_var.file) != 1)
+ gcov_var.error = 1;
+ gcov_var.start += size;
+ gcov_var.offset -= size;
+}
+
/* Allocate space to write BYTES bytes to the gcov file. Return a
pointer to those bytes, or NULL on failure. */
-GCOV_LINKAGE unsigned char *
+static unsigned char *
gcov_write_bytes (unsigned bytes)
{
char unsigned *result;
- if (gcov_var.position + bytes > gcov_var.alloc)
- {
- size_t new_size = (gcov_var.alloc + bytes) * 3 / 2;
-
- if (!gcov_var.buffer)
- return 0;
+ GCOV_CHECK_WRITING ();
#if IN_LIBGCOV
- result = realloc (gcov_var.buffer, new_size);
- if (!result)
+ if (gcov_var.offset >= GCOV_BLOCK_SIZE)
+ {
+ gcov_write_block (GCOV_BLOCK_SIZE);
+ if (gcov_var.offset)
{
- free (gcov_var.buffer);
- gcov_var.buffer = 0;
- gcov_var.alloc = 0;
- gcov_var.position = gcov_var.length = 0;
- gcov_var.error = 1;
- return 0;
+ GCOV_CHECK (gcov_var.offset == 4);
+ memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4);
}
+ }
#else
- result = xrealloc (gcov_var.buffer, new_size);
+ if (gcov_var.offset + bytes > gcov_var.alloc)
+ gcov_allocate (gcov_var.offset + bytes);
#endif
- gcov_var.alloc = new_size;
- gcov_var.buffer = result;
- }
+ result = &gcov_var.buffer[gcov_var.offset];
+ gcov_var.offset += bytes;
- result = &gcov_var.buffer[gcov_var.position];
- gcov_var.position += bytes;
- gcov_var.modified = 1;
- if (gcov_var.position > gcov_var.length)
- gcov_var.length = gcov_var.position;
return result;
}
@@ -186,8 +177,6 @@ gcov_write_unsigned (gcov_unsigned_t value)
unsigned char *buffer = gcov_write_bytes (4);
unsigned ix;
- if (!buffer)
- return;
for (ix = 4; ix--; )
{
buffer[ix] = value;
@@ -209,8 +198,6 @@ gcov_write_counter (gcov_type value)
unsigned char *buffer = gcov_write_bytes (8);
unsigned ix;
- if (!buffer)
- return;
for (ix = 8; ix--; )
{
buffer[ix] = value;
@@ -233,6 +220,8 @@ gcov_write_string (const char *string)
unsigned pad = 0;
unsigned rem = 0;
unsigned char *buffer;
+ unsigned ix;
+ unsigned value;
if (string)
{
@@ -241,19 +230,15 @@ gcov_write_string (const char *string)
}
buffer = gcov_write_bytes (4 + length + rem);
- if (buffer)
+
+ value = length;
+ for (ix = 4; ix--; )
{
- unsigned ix;
- unsigned value = length;
-
- for (ix = 4; ix--; )
- {
- buffer[ix] = value;
- value >>= 8;
- }
- memcpy (buffer + 4, string, length);
- memcpy (buffer + 4 + length, &pad, rem);
+ buffer[ix] = value;
+ value >>= 8;
}
+ memcpy (buffer + 4, string, length);
+ memcpy (buffer + 4 + length, &pad, rem);
}
#endif
@@ -264,12 +249,10 @@ gcov_write_string (const char *string)
GCOV_LINKAGE gcov_position_t
gcov_write_tag (gcov_unsigned_t tag)
{
- gcov_position_t result = gcov_var.position;
+ gcov_position_t result = gcov_var.start + gcov_var.offset;
unsigned char *buffer = gcov_write_bytes (8);
unsigned ix;
- if (!buffer)
- return 0;
for (ix = 4; ix--; )
{
buffer[ix] = tag;
@@ -287,18 +270,24 @@ gcov_write_tag (gcov_unsigned_t tag)
GCOV_LINKAGE void
gcov_write_length (gcov_position_t position)
{
- if (position)
+ unsigned offset;
+ gcov_unsigned_t length;
+ unsigned char *buffer;
+ unsigned ix;
+
+ 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--; )
{
- gcov_unsigned_t length = gcov_var.position - position - 8;
- unsigned char *buffer = &gcov_var.buffer[position + 4];
- unsigned ix;
-
- for (ix = 4; ix--; )
- {
- buffer[ix] = length;
- length >>= 8;
- }
+ buffer[ix] = length;
+ length >>= 8;
}
+ if (gcov_var.offset >= GCOV_BLOCK_SIZE)
+ gcov_write_block (gcov_var.offset);
}
#else /* IN_LIBGCOV */
@@ -311,8 +300,6 @@ gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
unsigned char *buffer = gcov_write_bytes (8);
unsigned ix;
- if (!buffer)
- return;
for (ix = 4; ix--; )
{
buffer[ix] = tag;
@@ -353,19 +340,47 @@ 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). */
-GCOV_LINKAGE const unsigned char *
+static const unsigned char *
gcov_read_bytes (unsigned bytes)
{
const unsigned char *result;
+ unsigned excess = gcov_var.length - gcov_var.offset;
- if (gcov_var.position + bytes > gcov_var.length)
+ GCOV_CHECK_READING ();
+ if (excess < bytes)
{
- gcov_var.error = 1;
- return 0;
+ gcov_var.start += gcov_var.offset;
+#if IN_LIBGCOV
+ if (excess)
+ {
+ GCOV_CHECK (excess == 4);
+ memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4);
+ }
+#else
+ memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess);
+#endif
+ gcov_var.offset = 0;
+ gcov_var.length = excess;
+#if IN_LIBGCOV
+ GCOV_CHECK (!gcov_var.length || gcov_var.length == 4);
+ excess = GCOV_BLOCK_SIZE;
+#else
+ if (gcov_var.length + bytes > gcov_var.alloc)
+ gcov_allocate (gcov_var.length + bytes);
+ excess = gcov_var.alloc - gcov_var.length;
+#endif
+ excess = fread (gcov_var.buffer + gcov_var.offset,
+ 1, excess, gcov_var.file);
+ gcov_var.length += excess;
+ if (gcov_var.length < bytes)
+ {
+ gcov_var.overread += bytes - gcov_var.length;
+ gcov_var.length = 0;
+ return 0;
+ }
}
-
- result = &gcov_var.buffer[gcov_var.position];
- gcov_var.position += bytes;
+ result = &gcov_var.buffer[gcov_var.offset];
+ gcov_var.offset += bytes;
return result;
}
@@ -452,6 +467,41 @@ gcov_read_summary (struct gcov_summary *summary)
}
}
+#if !IN_LIBGCOV
+/* Reset to a known position. BASE should have been obtained from
+ gcov_position, LENGTH should be a record length. */
+
+GCOV_LINKAGE void
+gcov_sync (gcov_position_t base, gcov_unsigned_t length)
+{
+ GCOV_CHECK_READING ();
+ base += length;
+ if (base - gcov_var.start <= gcov_var.length)
+ gcov_var.offset = base - gcov_var.start;
+ else
+ {
+ gcov_var.offset = gcov_var.length = 0;
+ fseek (gcov_var.file, base, SEEK_SET);
+ gcov_var.start = ftell (gcov_var.file);
+ }
+}
+#endif
+
+#if IN_LIBGCOV
+/* Move to the a set position in a gcov file. BASE is zero to move to
+ the end, and non-zero to move to that position. */
+
+GCOV_LINKAGE void
+gcov_seek (gcov_position_t base)
+{
+ GCOV_CHECK_WRITING ();
+ if (gcov_var.offset)
+ gcov_write_block (gcov_var.offset);
+ fseek (gcov_var.file, base, base ? SEEK_SET : SEEK_END);
+ gcov_var.start = ftell (gcov_var.file);
+}
+#endif
+
#if IN_GCOV > 0
/* Return the modification time of the current gcov file. */
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index f7396532fff..e6cf94e6ac2 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -202,35 +202,31 @@ typedef HOST_WIDEST_INT gcov_type;
#endif /* !IN_LIBGCOV */
-/* In gcov we want function linkage to be static, so we do not
- polute the global namespace. In libgcov we need these functions
- to be extern, so prefix them with __gcov so that we do not conflict.
- In the compiler we want it extern, so that they can be accessed from
+/* In gcov we want function linkage to be static. In libgcov we need
+ these functions to be extern, so prefix them with __gcov. In the
+ compiler we want it extern, so that they can be accessed from
elsewhere. */
#if IN_LIBGCOV
#define gcov_var __gcov_var
#define gcov_open __gcov_open
#define gcov_close __gcov_close
-#define gcov_write_bytes __gcov_write_bytes
+#define gcov_write_tag_length __gcov_write_tag_length
+#define gcov_position __gcov_position
+#define gcov_seek __gcov_seek
+#define gcov_rewrite __gcov_rewrite
+#define gcov_is_error __gcov_is_error
+#define gcov_is_eof __gcov_is_eof
#define gcov_write_unsigned __gcov_write_unsigned
#define gcov_write_counter __gcov_write_counter
-#pragma GCC poison gcov_write_string
-#pragma GCC poison gcov_write_tag
-#pragma GCC poison gcov_write_length
-#define gcov_write_tag_length __gcov_write_tag_length
#define gcov_write_summary __gcov_write_summary
-#define gcov_read_bytes __gcov_read_bytes
#define gcov_read_unsigned __gcov_read_unsigned
#define gcov_read_counter __gcov_read_counter
-#pragma GCC poison gcov_read_string
#define gcov_read_summary __gcov_read_summary
-#define gcov_position __gcov_position
-#define gcov_sync __gcov_sync
-#define gcov_seek __gcov_seek
-#define gcov_rewrite __gcov_rewrite
-#define gcov_is_eof __gcov_is_eof
-#define gcov_is_error __gcov_is_error
-#pragma GCC poison gcov_time
+
+/* 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
+
#endif
#ifndef GCOV_LINKAGE
@@ -255,18 +251,19 @@ typedef HOST_WIDEST_INT gcov_type;
file. Values [41..9f] for those in the bbg file and [a1..ff] for
the data file. */
-#define GCOV_TAG_FUNCTION ((unsigned)0x01000000)
+#define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000)
#define GCOV_TAG_FUNCTION_LENGTH (2 * 4)
-#define GCOV_TAG_BLOCKS ((unsigned)0x01410000)
+#define GCOV_TAG_BLOCKS ((gcov_unsigned_t)0x01410000)
#define GCOV_TAG_BLOCKS_LENGTH(NUM) ((NUM) * 4)
-#define GCOV_TAG_ARCS ((unsigned)0x01430000)
+#define GCOV_TAG_ARCS ((gcov_unsigned_t)0x01430000)
#define GCOV_TAG_ARCS_LENGTH(NUM) (1 * 4 + (NUM) * (2 * 4))
-#define GCOV_TAG_LINES ((unsigned)0x01450000)
-#define GCOV_TAG_COUNTER_BASE ((unsigned)0x01a10000) /* First counter */
+#define GCOV_TAG_LINES ((gcov_unsigned_t)0x01450000)
+#define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t)0x01a10000)
#define GCOV_TAG_COUNTER_LENGTH(NUM) ((NUM) * 8)
-#define GCOV_TAG_OBJECT_SUMMARY ((unsigned)0xa1000000)
-#define GCOV_TAG_PROGRAM_SUMMARY ((unsigned)0xa3000000)
-#define GCOV_TAG_SUMMARY_LENGTH (1 * 4 + GCOV_COUNTERS_SUMMABLE * (2 * 4 + 3 * 8))
+#define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000)
+#define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000)
+#define GCOV_TAG_SUMMARY_LENGTH \
+ (1 * 4 + GCOV_COUNTERS_SUMMABLE * (2 * 4 + 3 * 8))
/* Counters that are collected. */
#define GCOV_COUNTER_ARCS 0 /* Arc transitions. */
@@ -282,10 +279,10 @@ typedef HOST_WIDEST_INT gcov_type;
/* Convert a counter index to a tag. */
#define GCOV_TAG_FOR_COUNTER(COUNT) \
- (GCOV_TAG_COUNTER_BASE + ((COUNT) << 17))
+ (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t)(COUNT) << 17))
/* Convert a tag to a counter. */
#define GCOV_COUNTER_FOR_TAG(TAG) \
- (((TAG) - GCOV_TAG_COUNTER_BASE) >> 17)
+ ((unsigned)(((TAG) - GCOV_TAG_COUNTER_BASE) >> 17))
/* Check whether a tag is a counter tag. */
#define GCOV_TAG_IS_COUNTER(TAG) \
(!((TAG) & 0xFFFF) && GCOV_COUNTER_FOR_TAG (TAG) < GCOV_COUNTERS)
@@ -387,114 +384,131 @@ extern void __gcov_merge_add (gcov_type *, unsigned);
#if IN_LIBGCOV >= 0
-/* Because small reads and writes, interspersed with seeks cause lots
- of disk activity, we buffer the entire count files. */
+/* Optimum size read from or written to disk. */
+#define GCOV_BLOCK_SIZE (1 << 12)
GCOV_LINKAGE struct gcov_var
{
FILE *file;
- gcov_position_t position;
- gcov_position_t length;
+ gcov_position_t start; /* Position of first byte of block */
+ unsigned offset; /* Read/write position within the block. */
+ unsigned length; /* Read limit in the block. */
+ unsigned overread; /* Number of bytes overread. */
+ int error; /* < 0 overflow, > 0 disk error. */
+ int mode; /* < 0 writing, > 0 reading */
+#if IN_LIBGCOV
+ /* Holds one block plus 4 bytes, thus all coverage reads & writes
+ 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];
+#else
+ /* Holds a variable length block, as the compiler can write
+ strings and needs to backtrack. */
size_t alloc;
- unsigned modified;
- int error;
unsigned char *buffer;
+#endif
} gcov_var;
-/* Functions for reading and writing gcov files. */
+/* 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*/);
GCOV_LINKAGE int gcov_close (void);
-#if !IN_GCOV
-GCOV_LINKAGE unsigned char *gcov_write_bytes (unsigned);
-GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t);
+
+/* Available everywhere. */
+static gcov_position_t gcov_position (void);
+static int gcov_is_error (void);
+static int gcov_is_eof (void);
+
+GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void);
+GCOV_LINKAGE gcov_type gcov_read_counter (void);
+GCOV_LINKAGE void gcov_read_summary (struct gcov_summary *);
+
#if IN_LIBGCOV
+/* Available only in libgcov */
GCOV_LINKAGE void gcov_write_counter (gcov_type);
-#else
-GCOV_LINKAGE void gcov_write_string (const char *);
-#endif
-#if !IN_LIBGCOV
-GCOV_LINKAGE gcov_position_t gcov_write_tag (gcov_unsigned_t);
-GCOV_LINKAGE void gcov_write_length (gcov_position_t /*position*/);
-#else
GCOV_LINKAGE void gcov_write_tag_length (gcov_unsigned_t, gcov_unsigned_t);
GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/,
const struct gcov_summary *);
-#endif
-#endif /* !IN_GCOV */
-GCOV_LINKAGE const unsigned char *gcov_read_bytes (unsigned);
-GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void);
-GCOV_LINKAGE gcov_type gcov_read_counter (void);
-#if !IN_LIBGCOV
+static void gcov_rewrite (void);
+GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/);
+#else
+/* Available outside libgcov */
GCOV_LINKAGE const char *gcov_read_string (void);
+GCOV_LINKAGE void gcov_sync (gcov_position_t /*base*/,
+ gcov_unsigned_t /*length */);
#endif
-GCOV_LINKAGE void gcov_read_summary (struct gcov_summary *);
-static gcov_position_t gcov_position (void);
-static void gcov_sync (gcov_position_t /*base*/, gcov_unsigned_t /*length */);
-static void gcov_seek (gcov_position_t /*position*/);
-static void gcov_rewrite (void);
-static int gcov_is_eof (void);
-static int gcov_is_error (void);
+
+#if !IN_GCOV
+/* Available outside gcov */
+GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t);
+#endif
+
+#if !IN_GCOV && !IN_LIBGCOV
+/* Available only in compiler */
+GCOV_LINKAGE void gcov_write_string (const char *);
+GCOV_LINKAGE gcov_position_t gcov_write_tag (gcov_unsigned_t);
+GCOV_LINKAGE void gcov_write_length (gcov_position_t /*position*/);
+#endif
+
#if IN_GCOV > 0
+/* Available in gcov */
GCOV_LINKAGE time_t gcov_time (void);
#endif
+/* Make sure the library is used correctly. */
+#if ENABLE_CHECKING
+#define GCOV_CHECK(expr) ((expr) ? (void)0 : (void)abort ())
+#else
+#define GCOV_CHECK(expr)
+#endif
+#define GCOV_CHECK_READING() GCOV_CHECK(gcov_var.mode > 0)
+#define GCOV_CHECK_WRITING() GCOV_CHECK(gcov_var.mode < 0)
+
/* Save the current position in the gcov file. */
static inline gcov_position_t
gcov_position (void)
{
- return gcov_var.position;
+ GCOV_CHECK_READING ();
+ return gcov_var.start + gcov_var.offset;
}
-/* Reset to a known position. BASE should have been obtained from
- gcov_save_position, LENGTH should be a record length, or zero. */
+/* Return non-zero if we read to end of file. */
-static inline void
-gcov_sync (gcov_position_t base, gcov_unsigned_t length)
+static inline int
+gcov_is_eof ()
{
- if (gcov_var.buffer)
- {
- base += length;
- if (gcov_var.length < base)
- {
- gcov_var.error = 1;
- base = gcov_var.length;
- }
- gcov_var.position = base;
- }
+ return !gcov_var.overread;
}
-/* Move to the end of the gcov file. */
+/* Return non-zero if the error flag is set. */
-static inline void
-gcov_seek (gcov_position_t base)
+static inline int
+gcov_is_error ()
{
- gcov_var.position = base < gcov_var.length ? base : gcov_var.length;
+ return gcov_var.file ? gcov_var.error : 1;
}
+#if IN_LIBGCOV
/* Move to beginning of file and intialize for writing. */
static inline void
gcov_rewrite (void)
{
- gcov_var.position = 0;
-}
-
-/* Tests whether we have reached end of .da file. */
-
-static inline int
-gcov_is_eof ()
-{
- return gcov_var.position == gcov_var.length;
-}
-
-/* Return non-zero if the error flag is set. */
-
-static inline int
-gcov_is_error ()
-{
- return gcov_var.file ? gcov_var.error : 1;
+ GCOV_CHECK_READING ();
+ gcov_var.mode = -1;
+ gcov_var.start = 0;
+ gcov_var.offset = 0;
+ fseek (gcov_var.file, 0L, SEEK_SET);
}
+#endif
#endif /* IN_LIBGCOV >= 0 */
diff --git a/gcc/gcov.c b/gcc/gcov.c
index 2225f02f9ab..32590cba2fa 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -711,7 +711,8 @@ read_graph_file ()
struct function_info *fn = NULL;
source_t *src = NULL;
unsigned ix;
-
+ unsigned tag;
+
if (!gcov_open (bbg_file_name, 1))
{
fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
@@ -740,11 +741,10 @@ read_graph_file ()
bbg_file_name, v, e);
}
- while (!gcov_is_eof ())
+ while ((tag = gcov_read_unsigned ()))
{
- unsigned tag = gcov_read_unsigned ();
unsigned length = gcov_read_unsigned ();
- unsigned long base = gcov_position ();
+ gcov_position_t base = gcov_position ();
if (tag == GCOV_TAG_FUNCTION)
{
@@ -906,12 +906,14 @@ read_graph_file ()
}
gcov_sync (base, length);
if (gcov_is_error ())
- {
- corrupt:;
- fnotice (stderr, "%s:corrupted\n", bbg_file_name);
- gcov_close ();
- return 1;
- }
+ break;
+ }
+ if (!gcov_is_eof ())
+ {
+ corrupt:;
+ fnotice (stderr, "%s:corrupted\n", bbg_file_name);
+ gcov_close ();
+ return 1;
}
gcov_close ();
@@ -976,7 +978,9 @@ read_count_file ()
{
unsigned ix;
unsigned version;
+ unsigned tag;
function_t *fn = NULL;
+ int error = 0;
if (!gcov_open (da_file_name, 1))
{
@@ -1005,12 +1009,10 @@ read_count_file ()
da_file_name, v, e);
}
- while (!gcov_is_eof ())
+ while ((tag = gcov_read_unsigned ()))
{
- unsigned tag = gcov_read_unsigned ();
unsigned length = gcov_read_unsigned ();
unsigned long base = gcov_position ();
- int error;
if (tag == GCOV_TAG_OBJECT_SUMMARY)
gcov_read_summary (&object_summary);
@@ -1061,13 +1063,16 @@ read_count_file ()
}
gcov_sync (base, length);
if ((error = gcov_is_error ()))
- {
- fnotice (stderr, error < 0
- ? "%s:overflowed\n" : "%s:corrupted\n", da_file_name);
- goto cleanup;
- }
+ break;
}
+ if (!gcov_is_eof ())
+ {
+ fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
+ da_file_name);
+ goto cleanup;
+ }
+
gcov_close ();
return 0;
}
diff --git a/gcc/libgcov.c b/gcc/libgcov.c
index 221eae47498..ba54281e585 100644
--- a/gcc/libgcov.c
+++ b/gcc/libgcov.c
@@ -152,10 +152,10 @@ gcov_exit (void)
const struct gcov_ctr_info *ci_ptr;
struct gcov_ctr_summary *cs_ptr;
struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
- int error;
+ int error = 0;
int merging;
gcov_unsigned_t tag, length;
- gcov_position_t summary_pos = ~(gcov_position_t)0;
+ gcov_position_t summary_pos = 0;
/* Totals for this object file. */
memset (&this_object, 0, sizeof (this_object));
@@ -256,12 +256,14 @@ gcov_exit (void)
}
/* Check program & object summary */
- while (!gcov_is_eof ())
+ while (1)
{
gcov_position_t base = gcov_position ();
int is_program;
tag = gcov_read_unsigned ();
+ if (!tag)
+ break;
length = gcov_read_unsigned ();
is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
if (length != GCOV_TAG_SUMMARY_LENGTH
@@ -269,24 +271,26 @@ gcov_exit (void)
goto read_mismatch;
gcov_read_summary (is_program ? &program : &object);
if ((error = gcov_is_error ()))
+ goto read_error;
+ if (is_program && program.checksum == gcov_crc32)
{
- read_error:;
- fprintf (stderr, error < 0 ?
- "profiling:%s:Overflow merging\n" :
- "profiling:%s:Error merging\n", gi_ptr->filename);
- goto read_fatal;
+ summary_pos = base;
+ goto rewrite;
}
-
- if (!is_program || program.checksum != gcov_crc32)
- continue;
- summary_pos = base;
- break;
}
+ 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 ();
}
else
memset (&object, 0, sizeof (object));
- if (!(summary_pos + 1))
+ if (!summary_pos)
memset (&program, 0, sizeof (program));
/* Merge the summaries. */