* gcov-io.h (gcov_write_bytes, gcov_read_bytes): Remove here.
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 14 May 2003 16:01:20 +0000 (16:01 +0000)
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 14 May 2003 16:01:20 +0000 (16:01 +0000)
(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

gcc/ChangeLog
gcc/coverage.c
gcc/gcov-dump.c
gcc/gcov-io.c
gcc/gcov-io.h
gcc/gcov.c
gcc/libgcov.c

index b449645..f8af6e7 100644 (file)
@@ -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.
index 5926a7e..1b537c6 100644 (file)
@@ -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 ();
 }
 
index d70e4dd..c7c31ad 100644 (file)
@@ -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,
index d61cff3..3aad30e 100644 (file)
@@ -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.  */
 
index f739653..e6cf94e 100644 (file)
@@ -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 */
 
index 2225f02..32590cb 100644 (file)
@@ -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;
 }
index 221eae4..ba54281 100644 (file)
@@ -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.  */