From 9219dd0a97690c85202ee9f576b49b58b9659bcf Mon Sep 17 00:00:00 2001
From: nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Mon, 7 Apr 2003 19:37:12 +0000
Subject: 	Change gcov file interface to single file at a time. 	*
 gcov-io.h: Replace IN_LIBGCC1 with IN_LIBGCOV. Use IN_GCOV. 	Convert to C89
 prototypes. 	(gcov_file, gcov_length, gcov_position, gcov_buffer,
 gcov_alloc, 	gcov_error, gcov_modified): New static variables. 
 (gcov_open, gcov_close, gcov_read_bytes, gcov_write_bytes): New 
 functions. 	(gcov_write_unsigned, gcov_write_counter, gcov_write_string, 
 gcov_read_unsigned, gcov_read_counter, gcov_read_string): Adjust. 
 (gcov_read_summary, gcov_write_summary): Adjust. 	(gcov_save_position,
 gcov_reserve_length, gcov_write_length): 	Adjust. 	(gcov_resync,
 gcov_skip, gcov_skip_string): Adjust. 	(da_file_open, da_file_close,
 da_file_eof, da_file_error): Remove. 	(da_file_position, da_file_seek,
 da_file_write, da_file_read): 	Remove. 	(gcov_error, gcov_eof,
 gcov_ok, gcov_time): New functions. 	* gcov.c (gcov_type): Don't typedef
 here. 	(IN_GCOV): #define 	(read_graph_file, read_count_file): Adjust. 
 * gcov-dump.c (gcov_type): Don't typedef here. 	(IN_GCOV): #define. 
 (tag_function, tag_blocks, tag_arcs, tag_lines, tag_arc_counts): 	Remove
 FILE parameter, adjust. 	(struct tag_format): Adjust proc member. 
 (dump_file): Adjust. 	* libgcov.c (IN_LIBGCOV): #define. 	(gcov_exit):
 Adjust. 	* loop-init.c: Don't #include gcov-io.h 	* profile.c
 (struct counts_entry): New structure to hold counter 	values. 
 (struct section_reference, struct da_index_entry): Remove. 	(bbg_file,
 da_file): Remove. 	(htab_counts_index_hash, htab_counts_index_eq, 
 htab_counts_index_del): Replace with ... 	(htab_counts_entry_hash,
 htab_counts_entry_eq, 	htab_counts_entry_del): ... these. 
 (cleanup_counts_index, index_counts_file): Remove. 	(read_counts_file):
 New function. 	(get_exec_counts): Adjust. 
 (compute_branch_probabilities): Don't free the exec counts here. 
 (branch_prob): Adjust. 	(init_branch_prob): Adjust. 
 (end_branch_prob): Adjust.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@65338 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog   |  47 ++++
 gcc/gcov-dump.c | 101 +++----
 gcc/gcov-io.h   | 830 ++++++++++++++++++++++++++++----------------------------
 gcc/gcov.c      |  86 +++---
 gcc/libgcov.c   | 124 ++++-----
 gcc/loop-init.c |   1 -
 gcc/profile.c   | 511 ++++++++++++++--------------------
 7 files changed, 810 insertions(+), 890 deletions(-)

(limited to 'gcc')

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f779ed3382e..af381309253 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,50 @@
+2003-04-07  Nathan Sidwell  <nathan@codesourcery.com>
+
+	Change gcov file interface to single file at a time.
+	* gcov-io.h: Replace IN_LIBGCC1 with IN_LIBGCOV. Use IN_GCOV.
+	Convert to C89 prototypes.
+	(gcov_file, gcov_length, gcov_position, gcov_buffer, gcov_alloc,
+	gcov_error, gcov_modified): New static variables.
+	(gcov_open, gcov_close, gcov_read_bytes, gcov_write_bytes): New
+	functions.
+	(gcov_write_unsigned, gcov_write_counter, gcov_write_string,
+	gcov_read_unsigned, gcov_read_counter, gcov_read_string): Adjust.
+	(gcov_read_summary, gcov_write_summary): Adjust.
+	(gcov_save_position, gcov_reserve_length, gcov_write_length):
+	Adjust.
+	(gcov_resync, gcov_skip, gcov_skip_string): Adjust.
+	(da_file_open, da_file_close, da_file_eof, da_file_error): Remove.
+	(da_file_position, da_file_seek, da_file_write, da_file_read):
+	Remove.
+	(gcov_error, gcov_eof, gcov_ok, gcov_time): New functions.
+	* gcov.c (gcov_type): Don't typedef here.
+	(IN_GCOV): #define
+	(read_graph_file, read_count_file): Adjust.
+	* gcov-dump.c (gcov_type): Don't typedef here.
+	(IN_GCOV): #define.
+	(tag_function, tag_blocks, tag_arcs, tag_lines, tag_arc_counts):
+	Remove FILE parameter, adjust.
+	(struct tag_format): Adjust proc member.
+	(dump_file): Adjust.
+	* libgcov.c (IN_LIBGCOV): #define.
+	(gcov_exit): Adjust.
+	* loop-init.c: Don't #include gcov-io.h
+	* profile.c (struct counts_entry): New structure to hold counter
+	values.
+	(struct section_reference, struct da_index_entry): Remove.
+	(bbg_file, da_file): Remove.
+	(htab_counts_index_hash, htab_counts_index_eq,
+	htab_counts_index_del): Replace with ...
+	(htab_counts_entry_hash, htab_counts_entry_eq,
+	htab_counts_entry_del): ... these.
+	(cleanup_counts_index, index_counts_file): Remove.
+	(read_counts_file): New function.
+	(get_exec_counts): Adjust.
+	(compute_branch_probabilities): Don't free the exec counts here.
+	(branch_prob): Adjust.
+	(init_branch_prob): Adjust.
+	(end_branch_prob): Adjust.
+
 2003-04-07  Aldy Hernandez  <aldyh@redhat.com>
 
         * doc/invoke.texi (RS/6000 and PowerPC Options): Document
diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c
index acea56d9d64..5ca64a4f6cf 100644
--- a/gcc/gcov-dump.c
+++ b/gcc/gcov-dump.c
@@ -23,26 +23,26 @@ Boston, MA 02111-1307, USA.  */
 #include "tm.h"
 #include "version.h"
 #include <getopt.h>
-typedef HOST_WIDEST_INT gcov_type;
+#define IN_GCOV (-1)
 #include "gcov-io.h"
 
 static void dump_file PARAMS ((const char *));
 static void print_prefix PARAMS ((const char *, unsigned));
 static void print_usage PARAMS ((void));
 static void print_version PARAMS ((void));
-static int tag_function PARAMS ((const char *, FILE *, unsigned, unsigned));
-static int tag_blocks PARAMS ((const char *, FILE *, unsigned, unsigned));
-static int tag_arcs PARAMS ((const char *, FILE *, unsigned, unsigned));
-static int tag_lines PARAMS ((const char *, FILE *, unsigned, unsigned));
-static int tag_arc_counts PARAMS ((const char *, FILE *, unsigned, unsigned));
-static int tag_summary PARAMS ((const char *, FILE *, unsigned, unsigned));
+static int tag_function PARAMS ((const char *, unsigned, unsigned));
+static int tag_blocks PARAMS ((const char *, unsigned, unsigned));
+static int tag_arcs PARAMS ((const char *, unsigned, unsigned));
+static int tag_lines PARAMS ((const char *, unsigned, unsigned));
+static int tag_arc_counts PARAMS ((const char *, unsigned, unsigned));
+static int tag_summary PARAMS ((const char *, unsigned, unsigned));
 extern int main PARAMS ((int, char **));
 
 typedef struct tag_format
 {
   unsigned tag;
   char const *name;
-  int (*proc) (const char *, FILE *, unsigned, unsigned);
+  int (*proc) (const char *, unsigned, unsigned);
 } tag_format_t;
 
 static int flag_dump_contents = 0;
@@ -138,24 +138,22 @@ static void
 dump_file (filename)
      const char *filename;
 {
-  FILE *file = fopen (filename, "rb");
   unsigned tags[4];
   unsigned depth = 0;
   unsigned magic, version;
   unsigned tag, length;
   
-  if (!file)
+  if (!gcov_open (filename, 1))
     {
       fprintf (stderr, "%s:cannot open\n", filename);
       return;
     }
   
-  if (gcov_read_unsigned (file, &magic)
-      || gcov_read_unsigned (file, &version))
+  if (gcov_read_unsigned (&magic) || gcov_read_unsigned (&version))
     {
     read_error:;
-      printf ("%s:read error at %ld\n", filename, ftell (file));
-      fclose (file);
+      printf ("%s:read error at %lu\n", filename, gcov_save_position ());
+      gcov_close ();
       return;
     }
 
@@ -174,7 +172,7 @@ dump_file (filename)
     else
       {
 	printf ("%s:not a gcov file\n", filename);
-	fclose (file);
+	gcov_close ();
 	return;
       }
     for (ix = 4; ix--; expected >>= 8, version >>= 8, magic >>= 8)
@@ -189,14 +187,13 @@ dump_file (filename)
       printf ("%s:warning:current version is `%.4s'\n", filename, e);
   }
 
-  while (!gcov_read_unsigned (file, &tag)
-	 && !gcov_read_unsigned (file, &length))
+  while (!gcov_read_unsigned (&tag) && !gcov_read_unsigned (&length))
     {
       tag_format_t const *format;
       unsigned tag_depth;
       long base, end;
       
-      base = gcov_save_position (file);
+      base = gcov_save_position ();
       
       if (!tag)
 	tag_depth = depth;
@@ -234,11 +231,11 @@ dump_file (filename)
       print_prefix (filename, tag_depth);
       printf ("%08x:%4u:%s", tag, length, format->name);
       if (format->proc)
-	if ((*format->proc) (filename, file, tag, length))
+	if ((*format->proc) (filename, tag, length))
 	  goto read_error;
       printf ("\n");
-      end = gcov_save_position (file);
-      gcov_resync (file, base, length);
+      end = gcov_save_position ();
+      gcov_resync (base, length);
       if (format->proc && end != base + (long)length)
 	{
 	  if (end > base + (long)length)
@@ -249,35 +246,44 @@ dump_file (filename)
 		    filename, length - (end - base));
 	}
     }
-  if (!feof (file))
+  if (!gcov_eof ())
     goto read_error;
-  fclose (file);
+  gcov_close ();
 }
 
 static int
-tag_function (filename, file, tag, length)
+tag_function (filename, tag, length)
      const char *filename ATTRIBUTE_UNUSED;
-     FILE *file ATTRIBUTE_UNUSED;
      unsigned tag ATTRIBUTE_UNUSED;
      unsigned length ATTRIBUTE_UNUSED;
 {
   char *name = NULL;
   unsigned checksum;
+  char *src = NULL;
+  unsigned lineno = 0;
+  unsigned long pos = gcov_save_position ();
+  
+  if (gcov_read_string (&name)
+      || gcov_read_unsigned (&checksum))
+    return 1;
 
-  if (gcov_read_string (file, &name, NULL)
-      || gcov_read_unsigned (file, &checksum))
+  if (gcov_save_position () - pos != length
+      && (gcov_read_string (&src)
+	  || gcov_read_unsigned (&lineno)))
     return 1;
 
   printf (" `%s' checksum=0x%08x", name, checksum);
+  if (src)
+    printf (" %s:%u", src, lineno);
   free (name);
+  free (src);
   
   return 0;
 }
 
 static int
-tag_blocks (filename, file, tag, length)
+tag_blocks (filename, tag, length)
      const char *filename ATTRIBUTE_UNUSED;
-     FILE *file ATTRIBUTE_UNUSED;
      unsigned tag ATTRIBUTE_UNUSED;
      unsigned length ATTRIBUTE_UNUSED;
 {
@@ -292,7 +298,7 @@ tag_blocks (filename, file, tag, length)
       for (ix = 0; ix != n_blocks; ix++)
 	{
 	  unsigned flags;
-	  if (gcov_read_unsigned (file, &flags))
+	  if (gcov_read_unsigned (&flags))
 	    return 1;
 	  if (!(ix & 7))
 	    printf ("\n%s:\t\t%u", filename, ix);
@@ -301,15 +307,14 @@ tag_blocks (filename, file, tag, length)
       
     }
   else
-    gcov_skip (file, n_blocks * 4);
+    gcov_skip (n_blocks * 4);
   
   return 0;
 }
 
 static int
-tag_arcs (filename, file, tag, length)
+tag_arcs (filename, tag, length)
      const char *filename ATTRIBUTE_UNUSED;
-     FILE *file ATTRIBUTE_UNUSED;
      unsigned tag ATTRIBUTE_UNUSED;
      unsigned length ATTRIBUTE_UNUSED;
 {
@@ -321,15 +326,14 @@ tag_arcs (filename, file, tag, length)
       unsigned ix;
       unsigned blockno;
 
-      if (gcov_read_unsigned (file, &blockno))
+      if (gcov_read_unsigned (&blockno))
 	return 1;
 
       for (ix = 0; ix != n_arcs; ix++)
 	{
 	  unsigned dst, flags;
 	  
-	  if (gcov_read_unsigned (file, &dst)
-	      || gcov_read_unsigned (file, &flags))
+	  if (gcov_read_unsigned (&dst) || gcov_read_unsigned (&flags))
 	    return 1;
 	  if (!(ix & 3))
 	    printf ("\n%s:\t\t%u:", filename, blockno);
@@ -337,15 +341,14 @@ tag_arcs (filename, file, tag, length)
 	}
     }
   else
-    gcov_skip (file, 4 + n_arcs * 8);
+    gcov_skip (4 + n_arcs * 8);
   
   return 0;
 }
 
 static int
-tag_lines (filename, file, tag, length)
+tag_lines (filename, tag, length)
      const char *filename ATTRIBUTE_UNUSED;
-     FILE *file ATTRIBUTE_UNUSED;
      unsigned tag ATTRIBUTE_UNUSED;
      unsigned length ATTRIBUTE_UNUSED;
 {
@@ -355,21 +358,21 @@ tag_lines (filename, file, tag, length)
       unsigned blockno;
       char const *sep = NULL;
 
-      if (gcov_read_unsigned (file, &blockno))
+      if (gcov_read_unsigned (&blockno))
 	return 1;
       
       while (1)
 	{
 	  unsigned lineno;
 	  
-	  if (gcov_read_unsigned (file, &lineno))
+	  if (gcov_read_unsigned (&lineno))
 	    {
 	      free (source);
 	      return 1;
 	    }
 	  if (!lineno)
 	    {
-	      if (gcov_read_string (file, &source, NULL))
+	      if (gcov_read_string (&source))
 		return 1;
 	      if (!source)
 		break;
@@ -394,15 +397,14 @@ tag_lines (filename, file, tag, length)
 	}
     }
   else
-    gcov_skip (file, length);
+    gcov_skip (length);
   
   return 0;
 }
 
 static int
-tag_arc_counts (filename, file, tag, length)
+tag_arc_counts (filename, tag, length)
      const char *filename ATTRIBUTE_UNUSED;
-     FILE *file ATTRIBUTE_UNUSED;
      unsigned tag ATTRIBUTE_UNUSED;
      unsigned length ATTRIBUTE_UNUSED;
 {
@@ -417,7 +419,7 @@ tag_arc_counts (filename, file, tag, length)
 	{
 	  gcov_type count;
 	  
-	  if (gcov_read_counter (file, &count))
+	  if (gcov_read_counter (&count))
 	    return 1;
 	  if (!(ix & 7))
 	    printf ("\n%s:\t\t%u", filename, ix);
@@ -426,21 +428,20 @@ tag_arc_counts (filename, file, tag, length)
 	}
     }
   else
-    gcov_skip (file, n_counts * 8);
+    gcov_skip (n_counts * 8);
   
   return 0;
 }
 
 static int
-tag_summary (filename, file, tag, length)
+tag_summary (filename, tag, length)
      const char *filename ATTRIBUTE_UNUSED;
-     FILE *file ATTRIBUTE_UNUSED;
      unsigned tag ATTRIBUTE_UNUSED;
      unsigned length ATTRIBUTE_UNUSED;
 {
   struct gcov_summary summary;
 
-  if (gcov_read_summary (file, &summary))
+  if (gcov_read_summary (&summary))
     return 1;
   printf (" checksum=0x%08x", summary.checksum);
   
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index 14dc5842ad1..8e10e49141a 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -135,24 +135,30 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    merged.
 
    This file is included by both the compiler, gcov tools and the
-   library.  The IN_LIBGCC2 define distinguishes these cases.  When
-   IN_LIBGCC2 is nonzero, we're building libgcc2 for the target and
-   know the compiler is (the just built) gcc.  Otherwise we're
-   generating code for the host, and the compiler may or may not be
-   gcc.  In this latter case, you must ensure that 'gcov_type' is
-   typedefed to something suitable (unsigned HOST_WIDEST_INT is
-   usually what you want).  */
+   runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to
+   distinguish which case is which.  If IN_LIBGCOV is non-zero,
+   libgcov is being built. If IN_GCOV is non-zero, the gcov tools are
+   being built. Otherwise the compiler is being built. IN_GCOV may be
+   positive or negative. If positive, we are compiling a tool that
+   requires additional functions (see the code for knowledge of what
+   those functions are).  */
 
 #ifndef GCC_GCOV_IO_H
 #define GCC_GCOV_IO_H
 
-#if IN_LIBGCC2
+#if IN_LIBGCOV
 #if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
 typedef long gcov_type;
 #else
 typedef long long gcov_type;
 #endif
-#endif /* IN_LIBGCC2 */
+#endif /* IN_LIBGCOV */
+#if IN_GCOV
+typedef HOST_WIDEST_INT gcov_type;
+#if IN_GCOV > 0
+#include <sys/types.h>
+#endif
+#endif
 
 /* File suffixes.  */
 #define GCOV_DATA_SUFFIX ".da"
@@ -228,7 +234,7 @@ struct counter_section
   unsigned n_counters;	/* Number of counters in the section.  */
 };
 
-#if IN_LIBGCC2
+#if IN_LIBGCOV
 /* Information about section of counters for an object file.  */
 struct counter_section_data
 {
@@ -272,139 +278,369 @@ extern void __gcov_flush (void);
 
 /* Since this file is used in both host and target files, and we don't
    include ansidecl.h in target files, provide some necessary macros.  */
-#ifndef PARAMS
-# define PARAMS(X) X
-#endif
 #ifndef ATTRIBUTE_UNUSED
 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
 #endif
 
-#endif /* IN_LIBGCC2 */
+#endif /* IN_LIBGCOV */
+
+/* Because small reads and writes, interspersed with seeks cause lots
+   of disk activity, we buffer the entire count files.  */
+
+static FILE *gcov_file;
+static size_t gcov_position;
+static size_t gcov_length;
+static unsigned char *gcov_buffer;
+static size_t gcov_alloc;
+static int gcov_modified;
+static int gcov_errored = 1;
 
 /* Functions for reading and writing gcov files.  */
-static int gcov_write_unsigned PARAMS((FILE *, unsigned))
-     ATTRIBUTE_UNUSED;
-static int gcov_write_counter PARAMS((FILE *, gcov_type))
-     ATTRIBUTE_UNUSED;
-static int gcov_write_string PARAMS((FILE *, const char *, unsigned))
-     ATTRIBUTE_UNUSED;
-static int gcov_read_unsigned PARAMS((FILE *, unsigned *))
-     ATTRIBUTE_UNUSED;
-static int gcov_read_counter PARAMS((FILE *, gcov_type *))
-     ATTRIBUTE_UNUSED;
-#if !IN_LIBGCC2
-static int gcov_read_string PARAMS((FILE *, char **, unsigned *))
-     ATTRIBUTE_UNUSED;
+static int gcov_open (const char */*name*/, int /*truncate*/);
+static int gcov_close (void);
+#if !IN_GCOV
+static unsigned char *gcov_write_bytes (unsigned);
+static int gcov_write_unsigned (unsigned);
+#if IN_LIBGCOV
+static int gcov_write_counter (gcov_type);
+#endif
+static int gcov_write_string (const char *);
+static unsigned long gcov_reserve_length (void);
+static int gcov_write_length (unsigned long /*position*/);
+#if IN_LIBGCOV
+static int gcov_write_summary (unsigned, const struct gcov_summary *);
+#endif
+#endif /* !IN_GCOV */
+static const unsigned char *gcov_read_bytes (unsigned);
+static int gcov_read_unsigned (unsigned *);
+static int gcov_read_counter (gcov_type *);
+#if !IN_LIBGCOV
+static int gcov_read_string (char **);
+#endif
+static int gcov_read_summary (struct gcov_summary *);
+static __inline__ unsigned long gcov_save_position (void);
+static int gcov_resync (unsigned long /*base*/, unsigned /*length */);
+static unsigned long gcov_seek_end (void);
+static int gcov_skip (unsigned /*length*/);
+static int gcov_skip_string (unsigned /*length*/);
+static int gcov_ok (void);
+static int gcov_error (void);
+static int gcov_eof (void);
+#if IN_GCOV > 0
+static time_t gcov_time (void);
+#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
+   opened, if possible, and if MODE is <= 0, a new file will be
+   created. Use MODE=0 to attempt to reopen an existing file and then
+   fall back on creating a new one.  Return zero on failure, >0 on
+   opening an existing file and <0 on creating a new one.  */
+
+static int
+gcov_open (const char *name, int mode)
+{
+  int result = 1;
+  size_t alloc = 1024;
+#if defined (TARGET_HAS_F_SETLKW) && IN_LIBGCOV
+  struct flock s_flock;
+
+  s_flock.l_type = F_WRLCK;
+  s_flock.l_whence = SEEK_SET;
+  s_flock.l_start = 0;
+  s_flock.l_len = 0; /* Until EOF.  */
+  s_flock.l_pid = getpid ();
+#endif
+  
+  if (gcov_file)
+    abort ();
+  gcov_position = gcov_length = 0;
+  gcov_errored = gcov_modified = 0;
+  if (mode >= 0)
+    gcov_file = fopen (name, "r+b");
+  if (!gcov_file && mode <= 0)
+    {
+      result = -1;
+      gcov_file = fopen (name, "w+b");
+    }
+  if (!gcov_file)
+    return 0;
+
+#if defined (TARGET_HAS_F_SETLKW) && IN_LIBGCOV
+  while (fcntl (fileno (gcov_file), F_SETLKW, &s_flock)
+	 && errno == EINTR)
+    continue;
 #endif
-static int gcov_read_summary PARAMS ((FILE *, struct gcov_summary *))
-     ATTRIBUTE_UNUSED;
-#if IN_LIBGCC2
-static int gcov_write_summary PARAMS ((FILE *, unsigned,
-				       const struct gcov_summary *))
-     ATTRIBUTE_UNUSED;
+
+  if (result >= 0)
+    {
+      if (fseek (gcov_file, 0, SEEK_END))
+	{
+	  fclose (gcov_file);
+	  gcov_file = 0;
+	  return 0;
+	}
+      gcov_length = ftell (gcov_file);
+      fseek (gcov_file, 0, SEEK_SET);
+      alloc += gcov_length;
+    }
+  if (alloc > gcov_alloc)
+    {
+      if (gcov_buffer)
+	free (gcov_buffer);
+      gcov_alloc = alloc;
+#if IN_LIBGCOV
+      gcov_buffer = malloc (gcov_alloc);
+      if (!gcov_buffer)
+	{
+	  fclose (gcov_file);
+	  gcov_file = 0;
+	  gcov_length = 0;
+	  gcov_alloc = 0;
+	  return 0;
+	}
+#else
+      gcov_buffer = xmalloc (gcov_alloc);
 #endif
-#define gcov_save_position(STREAM) \
- 	da_file_position (STREAM)
-#define gcov_reserve_length(STREAM) \
-	(gcov_write_unsigned (STREAM, 0) ? 0 : da_file_position (STREAM) - 4)
-static int gcov_write_length PARAMS((FILE *, long))
-     ATTRIBUTE_UNUSED;
-#define gcov_resync(STREAM, BASE, LENGTH) \
-	da_file_seek (STREAM, BASE + (long)LENGTH, SEEK_SET)
-#define gcov_skip(STREAM, LENGTH) \
-	da_file_seek (STREAM, LENGTH, SEEK_CUR)
-#define gcov_skip_string(STREAM, LENGTH) \
-	da_file_seek (STREAM, (LENGTH) + 4 - ((LENGTH) & 3), SEEK_CUR)
-#if IN_LIBGCC2
-static FILE *da_file_open PARAMS ((const char *, int *));
-static int da_file_close PARAMS ((void));
-static int da_file_eof PARAMS ((void));
-static int da_file_error PARAMS ((void));
+    }
+  if (result >= 0 && fread (gcov_buffer, gcov_length, 1, gcov_file) != 1)
+    {
+      fclose (gcov_file);
+      gcov_file = 0;
+      gcov_length = 0;
+      return 0;
+    }
+  return result;
+}
+
+/* Close the current gcov file. Flushes data to disk. Returns nonzero
+   on failure or error flag set.  */
+
+static int
+gcov_close ()
+{
+  int result = 0;
+  
+  if (gcov_file)
+    {
+      if (gcov_modified
+	  && (fseek (gcov_file, 0, SEEK_SET)
+	      || fwrite (gcov_buffer, gcov_length, 1, gcov_file) != 1))
+	result = -1;
+      fclose (gcov_file);
+      gcov_file = 0;
+      gcov_length = 0;
+    }
+  return result || gcov_errored;
+}
+
+#if !IN_GCOV
+/* Allocate space to write BYTES bytes to the gcov file. Return a
+   pointer to those bytes, or NULL on failure.  */
+
+static unsigned char *
+gcov_write_bytes (unsigned bytes)
+{
+  char unsigned *result;
+
+  if (gcov_position + bytes > gcov_alloc)
+    {
+      size_t new_size = (gcov_alloc + bytes) * 3 / 2;
+
+      if (!gcov_buffer)
+	return 0;
+#if IN_LIBGCOV
+      result = realloc (gcov_buffer, new_size);
+      if (!result)
+	{
+	  free (gcov_buffer);
+	  gcov_buffer = 0;
+	  gcov_alloc = 0;
+	  gcov_position = gcov_length = 0;
+	  return 0;
+	}
+#else
+      result = xrealloc (gcov_buffer, new_size);
 #endif
-static unsigned long da_file_position PARAMS ((FILE *));
-static int da_file_seek PARAMS ((FILE *, long, int));
-static size_t da_file_write PARAMS ((const void *, size_t, size_t, FILE *));
-static size_t da_file_read PARAMS ((void *, size_t, size_t, FILE *));
+      gcov_alloc = new_size;
+      gcov_buffer = result;
+    }
+  
+  result = &gcov_buffer[gcov_position];
+  gcov_position += bytes;
+  gcov_modified = 1;
+  if (gcov_position > gcov_length)
+    gcov_length = gcov_position;
+  return result;
+}
 
-/* Write VALUE to coverage file FILE.  Return nonzero if failed due to
+/* Write VALUE to coverage file.  Return nonzero if failed due to
    file i/o error, or value error.  */
 
 static int
-gcov_write_unsigned (file, value)
-     FILE *file;
-     unsigned value;
+gcov_write_unsigned (unsigned value)
 {
-  char buffer[4];
+  unsigned char *buffer = gcov_write_bytes (4);
   unsigned ix;
 
-  for (ix = sizeof (buffer); ix--; )
+  if (!buffer)
+    return 1;
+  
+  for (ix = 4; ix--; )
     {
       buffer[ix] = value;
       value >>= 8;
     }
-  return ((sizeof (value) > sizeof (buffer) && value)
-	  || da_file_write (buffer, 1, sizeof (buffer), file) != sizeof (buffer));
+  return sizeof (value) > 4 && value;
 }
 
-/* Write VALUE to coverage file FILE.  Return nonzero if failed due to
+/* Write VALUE to coverage file.  Return nonzero if failed due to
    file i/o error, or value error.  Negative values are not checked
    here -- they are checked in gcov_read_counter.  */
 
+#if IN_LIBGCOV
 static int
-gcov_write_counter (file, value)
-     FILE *file;
-     gcov_type value;
+gcov_write_counter (gcov_type value)
 {
-  char buffer[8];
+  unsigned char *buffer = gcov_write_bytes (8);
   unsigned ix;
 
-  for (ix = sizeof (buffer); ix--; )
+  if (!buffer)
+    return 1;
+  
+  for (ix = 8; ix--; )
     {
       buffer[ix] = value;
       value >>= 8;
     }
-  return ((sizeof (value) > sizeof (buffer) && value != 0 && value != -1)
-	  || da_file_write (buffer, 1, sizeof (buffer), file) != sizeof (buffer));
+  return sizeof (value) > 8 && value;
 }
+#endif /* IN_LIBGCOV */
 
-/* Write VALUE to coverage file FILE.  Return nonzero if failed due to
+/* Write VALUE to coverage file.  Return nonzero if failed due to
    file i/o error, or value error.  */
 
 static int
-gcov_write_string (file, string, length)
-     FILE *file;
-     unsigned length;
-     const char *string;
+gcov_write_string (const char *string)
 {
-  unsigned pad = 0;
-  unsigned rem = 4 - (length & 3);
-
   if (string)
-    return (gcov_write_unsigned (file, length)
-	    || da_file_write (string, 1, length, file) != length
-	    || da_file_write (&pad, 1, rem, file) != rem);
+    {
+      unsigned length = strlen (string);
+      unsigned pad = 0;
+      unsigned rem = 4 - (length & 3);
+      unsigned char *buffer;
+
+      if (gcov_write_unsigned (length))
+	return 1;
+      buffer = gcov_write_bytes (length + rem);
+      if (!buffer)
+	return 1;
+      memcpy (buffer, string, length);
+      memcpy (buffer + length, &pad, rem);
+      return 0;
+    }
   else
-    return gcov_write_unsigned (file, 0);
+    return gcov_write_unsigned (0);
+}
+
+/* Allocate space to write a record tag length.  Return a value to be
+   used for gcov_write_length.  */
+
+static unsigned long
+gcov_reserve_length (void)
+{
+  unsigned long result = gcov_position;
+  unsigned char *buffer = gcov_write_bytes (4);
+
+  if (!buffer)
+    return 0;
+  memset (buffer, 0, 4);
+  return result;
+}
+
+/* Write a record length at PLACE.  The current file position is the
+   end of the record, and is restored before returning.  Returns
+   nonzero on failure.  */
+
+static int
+gcov_write_length (unsigned long position)
+{
+  unsigned length = gcov_position - position - 4;
+  unsigned char *buffer = &gcov_buffer[position];
+  unsigned ix;
+
+  if (!position)
+    return 1;
+  for (ix = 4; ix--; )
+    {
+      buffer[ix] = length;
+      length >>= 8;
+    }
+  return 0;
+}
+
+#if IN_LIBGCOV
+/* Write a summary structure to the gcov file.  */
+
+static int
+gcov_write_summary (unsigned tag, const struct gcov_summary *summary)
+{
+  volatile unsigned long base; /* volatile is necessary to work around
+				  a compiler bug. */
+
+  if (gcov_write_unsigned (tag))
+    return 1;
+  base = gcov_reserve_length ();
+  if (gcov_write_unsigned (summary->checksum))
+    return 1;
+  if (gcov_write_unsigned (summary->runs)
+      || gcov_write_unsigned (summary->arcs))
+    return 1;
+  if (gcov_write_counter (summary->arc_sum)
+      || gcov_write_counter (summary->arc_max_one)
+      || gcov_write_counter (summary->arc_max_sum)
+      || gcov_write_counter (summary->arc_sum_max))
+    return 1;
+  if (gcov_write_length (base))
+    return 1;
+  return 0;
+}
+#endif /* IN_LIBGCOV */
+
+#endif /*!IN_GCOV */
+
+/* Return a pointer to read BYTES bytes from the gcov file. Returns
+   NULL on failure (read past EOF). */
+
+static const unsigned char *
+gcov_read_bytes (unsigned bytes)
+{
+  const unsigned char *result;
+  
+  if (gcov_position + bytes > gcov_length)
+    return 0;
+  result = &gcov_buffer[gcov_position];
+  gcov_position += bytes;
+  return result;
 }
 
-/* Read *VALUE_P from coverage file FILE.  Return nonzero if failed
+/* Read *VALUE_P from coverage file.  Return nonzero if failed
    due to file i/o error, or range error.  */
 
 static int
-gcov_read_unsigned (file, value_p)
-     FILE *file;
-     unsigned *value_p;
+gcov_read_unsigned (unsigned *value_p)
 {
   unsigned value = 0;
   unsigned ix;
-  unsigned char buffer[4];
+  const unsigned char *buffer = gcov_read_bytes (4);
 
-  if (da_file_read (buffer, 1, sizeof (buffer), file) != sizeof (buffer))
+  if (!buffer)
     return 1;
-  for (ix = sizeof (value); ix < sizeof (buffer); ix++)
+  for (ix = sizeof (value); ix < 4; ix++)
     if (buffer[ix])
       return 1;
-  for (ix = 0; ix != sizeof (buffer); ix++)
+  for (ix = 0; ix != 4; ix++)
     {
       value <<= 8;
       value |= buffer[ix];
@@ -413,24 +649,22 @@ gcov_read_unsigned (file, value_p)
   return 0;
 }
 
-/* Read *VALUE_P from coverage file FILE.  Return nonzero if failed
+/* Read *VALUE_P from coverage file.  Return nonzero if failed
    due to file i/o error, or range error.  */
 
 static int
-gcov_read_counter (file, value_p)
-     FILE *file;
-     gcov_type *value_p;
+gcov_read_counter (gcov_type *value_p)
 {
   gcov_type value = 0;
   unsigned ix;
-  unsigned char buffer[8];
+  const unsigned char *buffer = gcov_read_bytes (8);
 
-  if (da_file_read (buffer, 1, sizeof (buffer), file) != sizeof (buffer))
+  if (!buffer)
     return 1;
-  for (ix = sizeof (value); ix < sizeof (buffer); ix++)
+  for (ix = sizeof (value); ix < 8; ix++)
     if (buffer[ix])
       return 1;
-  for (ix = 0; ix != sizeof (buffer); ix++)
+  for (ix = 0; ix != 8; ix++)
     {
       value <<= 8;
       value |= buffer[ix];
@@ -440,377 +674,139 @@ gcov_read_counter (file, value_p)
   return value < 0;
 }
 
-#if !IN_LIBGCC2
+#if !IN_LIBGCOV
 
-/* Read string from coverage file FILE.  Length is stored in *LENGTH_P
-   (if non-null), a buffer is allocated and returned in *STRING_P.
-   Return nonzero if failed due to file i/o error, or range
-   error.  Uses xmalloc to allocate the string buffer.  */
+/* Read string from coverage file.  A buffer is allocated and returned
+   in *STRING_P.  Return nonzero if failed due to file i/o error, or
+   range error.  Uses xmalloc to allocate the string buffer.  */
 
 static int
-gcov_read_string (file, string_p, length_p)
-     FILE *file;
-     char **string_p;
-     unsigned *length_p;
+gcov_read_string (char **string_p)
 {
   unsigned length;
+  const unsigned char *buffer;
 
-  if (gcov_read_unsigned (file, &length))
+  if (gcov_read_unsigned (&length))
     return 1;
 
-  if (length_p)
-    *length_p = length;
   free (*string_p);
-
   *string_p = NULL;
   if (!length)
     return 0;
 
   length += 4 - (length & 3);
-  *string_p = (char *) xmalloc (length);
-
-  return da_file_read (*string_p, 1, length, file) != length;
+  buffer = gcov_read_bytes (length);
+  if (!buffer)
+    return 1;
+  
+  *string_p = xmalloc (length);
+  if (!*string_p)
+    return 1;
 
+  memcpy (*string_p, buffer, length);
+  return 0;
 }
 
-#endif /* !IN_LIBGCC2 */
-
-/* Write a record length at PLACE.  The current file position is the
-   end of the record, and is restored before returning.  Returns
-   nonzero on failure.  */
-
-static int
-gcov_write_length (file, place)
-     FILE *file;
-     long place;
-{
-  long here = da_file_position (file);
-  int result = (!place || da_file_seek (file, place, SEEK_SET)
-		|| gcov_write_unsigned (file, here - place - 4));
-  if (da_file_seek (file, here, SEEK_SET))
-    result = 1;
-  return result;
-}
+#endif /* !IN_LIBGCOV */
 
 #define GCOV_SUMMARY_LENGTH 44
 static int
-gcov_read_summary (da_file, summary)
-     FILE *da_file;
-     struct gcov_summary *summary;
+gcov_read_summary (struct gcov_summary *summary)
 {
-  return (gcov_read_unsigned (da_file, &summary->checksum)
-	  || gcov_read_unsigned (da_file, &summary->runs)
-	  || gcov_read_unsigned (da_file, &summary->arcs)
-	  || gcov_read_counter (da_file, &summary->arc_sum)
-	  || gcov_read_counter (da_file, &summary->arc_max_one)
-	  || gcov_read_counter (da_file, &summary->arc_max_sum)
-	  || gcov_read_counter (da_file, &summary->arc_sum_max));
+  return (gcov_read_unsigned (&summary->checksum)
+	  || gcov_read_unsigned (&summary->runs)
+	  || gcov_read_unsigned (&summary->arcs)
+	  || gcov_read_counter (&summary->arc_sum)
+	  || gcov_read_counter (&summary->arc_max_one)
+	  || gcov_read_counter (&summary->arc_max_sum)
+	  || gcov_read_counter (&summary->arc_sum_max));
 }
 
-#if IN_LIBGCC2
-static int
-gcov_write_summary (da_file, tag, summary)
-     FILE *da_file;
-     unsigned tag;
-     const struct gcov_summary *summary;
-{
-  long base;
-
-  return (gcov_write_unsigned (da_file, tag)
-	  || !(base = gcov_reserve_length (da_file))
-	  || gcov_write_unsigned (da_file, summary->checksum)
-	  || gcov_write_unsigned (da_file, summary->runs)
-	  || gcov_write_unsigned (da_file, summary->arcs)
-	  || gcov_write_counter (da_file, summary->arc_sum)
-	  || gcov_write_counter (da_file, summary->arc_max_one)
-	  || gcov_write_counter (da_file, summary->arc_max_sum)
-	  || gcov_write_counter (da_file, summary->arc_sum_max)
-	  || gcov_write_length (da_file, base));
-}
-#endif
+/* Save the current position in the gcov file.  */
 
-#if IN_LIBGCC2
-/* The kernel had problems with managing a lot of small reads/writes we use;
-   the functions below are used to buffer whole file in memory, thus reading and
-   writing it only once.  This should be feasible, as we have this amount
-   of memory for counters allocated anyway.  */
-
-static FILE *actual_da_file;
-static unsigned long actual_da_file_position;
-static unsigned long actual_da_file_length;
-static char *actual_da_file_buffer;
-static unsigned long actual_da_file_buffer_size;
-
-/* Open the file NAME and return it; in EXISTED return 1 if it existed
-   already.  */
-static FILE *
-da_file_open (name, existed)
-     const char *name;
-     int *existed;
+static inline unsigned long
+gcov_save_position (void)
 {
-#if defined (TARGET_HAS_F_SETLKW)
-  struct flock s_flock;
-
-  s_flock.l_type = F_WRLCK;
-  s_flock.l_whence = SEEK_SET;
-  s_flock.l_start = 0;
-  s_flock.l_len = 0; /* Until EOF.  */
-  s_flock.l_pid = getpid ();
-#endif
-
-  if (actual_da_file)
-    return 0;
-  actual_da_file_position = 0;
-  if (!actual_da_file_buffer)
-    {
-      actual_da_file_buffer = malloc (1);
-      actual_da_file_buffer_size = 1;
-    }
-
-  actual_da_file = fopen (name, "r+t");
-  if (actual_da_file)
-    *existed = 1;
-  else
-    {
-      actual_da_file = fopen (name, "w+t");
-      if (actual_da_file)
-	*existed = 0;
-      else
-	return 0;
-    }
-
-#if defined (TARGET_HAS_F_SETLKW)
-  /* After a fork, another process might try to read and/or write
-     the same file simultaneously.  So if we can, lock the file to
-     avoid race conditions.  */
-  while (fcntl (fileno (actual_da_file), F_SETLKW, &s_flock)
-	 && errno == EINTR)
-    continue;
-#endif
-
-  if (*existed)
-    {
-      if (fseek (actual_da_file, 0, SEEK_END))
-	{
-	  fclose (actual_da_file);
-	  actual_da_file = 0;
-	  return 0;
-	}
-      actual_da_file_length = ftell (actual_da_file);
-      rewind (actual_da_file);
-    }
-  else
-    actual_da_file_length = 0;
-
-  if (actual_da_file_length > actual_da_file_buffer_size)
-    {
-      actual_da_file_buffer_size = actual_da_file_length;
-      actual_da_file_buffer = realloc (actual_da_file_buffer,
-				       actual_da_file_buffer_size);
-      if (!actual_da_file_buffer)
-	{
-	  fclose (actual_da_file);
-	  actual_da_file = 0;
-	  return 0;
-	}
-    }
-
-  if (*existed)
-    {
-      if (fread (actual_da_file_buffer, actual_da_file_length,
-		 1, actual_da_file) != 1)
-	{
-	  fclose (actual_da_file);
-	  actual_da_file = 0;
-	  return 0;
-	}
-      rewind (actual_da_file);
-    }
-
-  return actual_da_file;
+  return gcov_position;
 }
 
-/* Write changes to the .da file and close it.  */
-static int da_file_close ()
-{
-  if (!actual_da_file)
-    return -1;
-  
-  if (fwrite (actual_da_file_buffer, actual_da_file_length,
-     	      1, actual_da_file) != 1)
-    return da_file_error ();
-
-  if (fclose (actual_da_file))
-    {
-      actual_da_file = 0;
-      return -1;
-    }
+/* Reset to a known position.  BASE should have been obtained from
+   gcov_save_position, LENGTH should be a record length, or zero.  */
 
-  actual_da_file = 0;
+static inline int
+gcov_resync (unsigned long base, unsigned length)
+{
+  if (gcov_buffer)
+    gcov_position = base + length;
   return 0;
 }
 
-/* Returns current position in .da file.  */
-static unsigned long
-da_file_position (file)
-     FILE *file;
-{
-  if (file)
-    return ftell (file);
-  return actual_da_file_position;
-}
+/* Move to the end of the gcov file.  */
 
-/* Tests whether we have reached end of .da file.  */
-static int
-da_file_eof ()
+static inline unsigned long
+gcov_seek_end ()
 {
-  return actual_da_file_position == actual_da_file_length;
+  gcov_position = gcov_length;
+  return gcov_position;
 }
 
-/* Change position in the .da file.  */
-static int
-da_file_seek (file, pos, whence)
-     FILE *file;
-     long pos;
-     int whence;
-{
-  if (file)
-    return fseek (file, pos, whence);
-
-  if (!actual_da_file)
-    return -1;
+/* Skip LENGTH bytes in the file.  */
 
-  switch (whence)
-    {
-    case SEEK_CUR:
-      if (pos < 0 && (unsigned long) -pos > actual_da_file_position)
-	return da_file_error ();
-
-      actual_da_file_position += pos;
-      break;
-    case SEEK_SET:
-      actual_da_file_position = pos;
-      break;
-    case SEEK_END:
-      if ((unsigned long) -pos > actual_da_file_length)
-	return da_file_error ();
-      actual_da_file_position = actual_da_file_length + pos;
-    }
-  if (actual_da_file_position > actual_da_file_length)
-    return da_file_error ();
+static inline int
+gcov_skip (unsigned length)
+{
+  if (gcov_length < gcov_position + length)
+    return 1;
+  gcov_position += length;
   return 0;
 }
 
-/* Write LEN chars of DATA to actual .da file; ELTS is expected to be 1,
-   FILE 0.  */
-static size_t
-da_file_write (data, elts, len, file)
-     const void *data;
-     size_t elts;
-     size_t len;
-     FILE *file;
-{
-  size_t l = len;
-  const char *dat = data;
-
-  if (file)
-    return fwrite (data, elts, len, file);
-
-  if (elts != 1)
-    abort ();
-
-  if (!actual_da_file)
-    return -1;
-  if (actual_da_file_position + len > actual_da_file_buffer_size)
-    {
-      actual_da_file_buffer_size = 2 * (actual_da_file_position + len);
-      actual_da_file_buffer = realloc (actual_da_file_buffer,
-				       actual_da_file_buffer_size);
-      if (!actual_da_file_buffer)
-	return da_file_error ();
-    }
-  while (len--)
-    actual_da_file_buffer[actual_da_file_position++] = *dat++;
-  if (actual_da_file_position > actual_da_file_length)
-    actual_da_file_length = actual_da_file_position;
-
-  return l;
-}
+/* Skip a string of LENGTH bytes.  */
 
-/* Read LEN chars of DATA from actual .da file; ELTS is expected to be 1,
-   FILE 0.  */
-static size_t
-da_file_read (data, elts, len, file)
-     void *data;
-     size_t elts;
-     size_t len;
-     FILE *file;
+static inline int
+gcov_skip_string (unsigned length)
 {
-  size_t l;
-  char *dat = data;
-
-  if (file)
-    return fread (data, elts, len, file);
-
-  if (elts != 1)
-    abort ();
-
-  if (!actual_da_file)
-    return -1;
-  if (actual_da_file_position + len > actual_da_file_length)
-    len = actual_da_file_length - actual_da_file_position;
-  l = len;
-  
-  while (len--)
-    *dat++ = actual_da_file_buffer[actual_da_file_position++];
-  return l;
+  return gcov_skip (length + 4 - (length & 3));
 }
 
-/* Close the current .da file and report error.  */
-static int
-da_file_error ()
-{
-  if (actual_da_file)
-    fclose (actual_da_file);
-  actual_da_file = 0;
-  return -1;
-}
-#else /* !IN_LIBGCC2 */
-static size_t
-da_file_write (data, elts, len, file)
-     const void *data;
-     size_t elts;
-     size_t len;
-     FILE *file;
+/* Tests whether we have reached end of .da file.  */
+
+static inline int
+gcov_eof ()
 {
-  return fwrite (data, elts, len, file);
+  return gcov_position == gcov_length;
 }
 
-static size_t
-da_file_read (data, elts, len, file)
-     void *data;
-     size_t elts;
-     size_t len;
-     FILE *file;
+/* Return non-zero if the error flag is set.  */
+
+static inline int
+gcov_ok ()
 {
-  return fread (data, elts, len, file);
+  return gcov_file != 0 && !gcov_errored;
 }
 
-static unsigned long
-da_file_position (file)
-     FILE *file;
+/* Set the error flag. */
+static inline int
+gcov_error ()
 {
-  return ftell (file);
+  int error = gcov_errored;
+  
+  gcov_errored = 1;
+  return error;
 }
 
-static int
-da_file_seek (file, pos, whence)
-     FILE *file;
-     long pos;
-     int whence;
+#if IN_GCOV > 0
+/* Return the modification time of the current gcov file.  */
+
+static time_t
+gcov_time ()
 {
-  return fseek (file, pos, whence);
+  struct stat status;
+  
+  if (fstat (fileno (gcov_file), &status))
+    return 0;
+  else
+    return status.st_mtime;
 }
-#endif
-
+#endif /* IN_GCOV */
 #endif /* GCC_GCOV_IO_H */
diff --git a/gcc/gcov.c b/gcc/gcov.c
index 95968b585a6..5a2f4291f4a 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -51,7 +51,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include <getopt.h>
 
-typedef HOST_WIDEST_INT gcov_type;
+#define IN_GCOV 1
 #include "gcov-io.h"
 
 /* The bbg file is generated by -ftest-coverage option. The da file is
@@ -706,8 +706,6 @@ find_source (file_name)
 static int
 read_graph_file ()
 {
-  FILE *file;
-  struct stat status;
   unsigned magic, version;
   unsigned current_tag = 0;
   unsigned tag;
@@ -715,22 +713,20 @@ read_graph_file ()
   source_t *src = NULL;
   unsigned ix;
 
-  file = fopen (bbg_file_name, "rb");
-  if (!file)
+  if (!gcov_open (bbg_file_name, 1))
     {
       fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
       return 1;
     }
-  if (!fstat (fileno (file), &status))
-    bbg_file_time = status.st_mtime;
-  if (gcov_read_unsigned (file, &magic) || magic != GCOV_GRAPH_MAGIC)
+  bbg_file_time = gcov_time ();
+  if (gcov_read_unsigned (&magic) || magic != GCOV_GRAPH_MAGIC)
     {
       fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
-      fclose (file);
+      gcov_close ();
       return 1;
     }
 
-  if (gcov_read_unsigned (file, &version) || version != GCOV_VERSION)
+  if (gcov_read_unsigned (&version) || version != GCOV_VERSION)
     {
       char v[4], e[4];
 
@@ -745,15 +741,15 @@ read_graph_file ()
 	       bbg_file_name, v, e);
     }
   
-  while (!gcov_read_unsigned (file, &tag))
+  while (!gcov_read_unsigned (&tag))
     {
       unsigned length;
       long base;
 
-      if (gcov_read_unsigned (file, &length))
+      if (gcov_read_unsigned (&length))
 	goto corrupt;
 
-      base = gcov_save_position (file);
+      base = gcov_save_position ();
 
       if (tag == GCOV_TAG_FUNCTION)
 	{
@@ -763,10 +759,10 @@ read_graph_file ()
 	  source_t *src;
 	  function_t *probe, *prev;
 
-	  if (gcov_read_string (file, &function_name, NULL)
-	      || gcov_read_unsigned (file, &checksum)
-	      || gcov_read_string (file, &function_file, NULL)
-	      || gcov_read_unsigned (file, &lineno))
+	  if (gcov_read_string (&function_name)
+	      || gcov_read_unsigned (&checksum)
+	      || gcov_read_string (&function_file)
+	      || gcov_read_unsigned (&lineno))
 	    goto corrupt;
 	  src = find_source (function_file);
 	  fn = (function_t *)xcalloc (1, sizeof (function_t));
@@ -810,7 +806,7 @@ read_graph_file ()
 		{
 		  unsigned flags;
 		  
-		  if (gcov_read_unsigned (file, &flags))
+		  if (gcov_read_unsigned (&flags))
 		    goto corrupt;
 		  fn->blocks[ix].flags = flags;
 		}
@@ -822,7 +818,7 @@ read_graph_file ()
 	  unsigned num_dests = (length - 4) / 8;
 	  unsigned dest, flags;
 
-	  if (gcov_read_unsigned (file, &src)
+	  if (gcov_read_unsigned (&src)
 	      || src >= fn->num_blocks
 	      || fn->blocks[src].succ)
 	    goto corrupt;
@@ -831,8 +827,8 @@ read_graph_file ()
 	    {
 	      struct arc_info *arc;
 	      
-	      if (gcov_read_unsigned (file, &dest)
-		  || gcov_read_unsigned (file, &flags)
+	      if (gcov_read_unsigned (&dest)
+		  || gcov_read_unsigned (&flags)
 		  || dest >= fn->num_blocks)
 		goto corrupt;
 	      arc = (arc_t *) xcalloc (1, sizeof (arc_t));
@@ -883,7 +879,7 @@ read_graph_file ()
 	  unsigned *line_nos
 	    = (unsigned *)xcalloc ((length - 4) / 4, sizeof (unsigned));
 
-	  if (gcov_read_unsigned (file, &blockno)
+	  if (gcov_read_unsigned (&blockno)
 	      || blockno >= fn->num_blocks
 	      || fn->blocks[blockno].u.line.encoding)
 	    goto corrupt;
@@ -892,7 +888,7 @@ read_graph_file ()
 	    {
 	      unsigned lineno;
 	      
-	      if (gcov_read_unsigned (file, &lineno))
+	      if (gcov_read_unsigned (&lineno))
 		goto corrupt;
 	      if (lineno)
 		{
@@ -909,7 +905,7 @@ read_graph_file ()
 		{
 		  char *file_name = NULL;
 		  
-		  if (gcov_read_string (file, &file_name, NULL))
+		  if (gcov_read_string (&file_name))
 		    goto corrupt;
 		  if (!file_name)
 		    break;
@@ -928,15 +924,15 @@ read_graph_file ()
 	  fn = NULL;
 	  current_tag = 0;
 	}
-      if (gcov_resync (file, base, length))
+      if (gcov_resync (base, length))
 	{
 	corrupt:;
 	  fnotice (stderr, "%s:corrupted\n", bbg_file_name);
-	  fclose (file);
+	  gcov_close ();
 	  return 1;
 	}
     }
-  fclose (file);
+  gcov_close ();
   
   /* We built everything backwards, so nreverse them all */
   
@@ -997,27 +993,25 @@ read_graph_file ()
 static int
 read_count_file ()
 {
-  FILE *file;
   unsigned ix;
   char *function_name_buffer = NULL;
   unsigned magic, version;
   function_t *fn = NULL;
 
-  file = fopen (da_file_name, "rb");
-  if (!file)
+  if (!gcov_open (da_file_name, 1))
     {
       fnotice (stderr, "%s:cannot open data file\n", da_file_name);
       return 1;
     }
-  if (gcov_read_unsigned (file, &magic) || magic != GCOV_DATA_MAGIC)
+  if (gcov_read_unsigned (&magic) || magic != GCOV_DATA_MAGIC)
     {
       fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
     cleanup:;
       free (function_name_buffer);
-      fclose (file);
+      gcov_close ();
       return 1;
     }
-  if (gcov_read_unsigned (file, &version) || version != GCOV_VERSION)
+  if (gcov_read_unsigned (&version) || version != GCOV_VERSION)
     {
       char v[4], e[4];
       
@@ -1036,32 +1030,35 @@ read_count_file ()
       unsigned tag, length;
       long base;
       
-      if (gcov_read_unsigned (file, &tag)
-	  || gcov_read_unsigned (file, &length))
+      if (gcov_read_unsigned (&tag)
+	  || gcov_read_unsigned (&length))
 	{
-	  if (feof (file))
+	  if (gcov_eof ())
 	    break;
 	  
 	corrupt:;
 	  fnotice (stderr, "%s:corrupted\n", da_file_name);
 	  goto cleanup;
 	}
-      base = gcov_save_position (file);
+      base = gcov_save_position ();
       if (tag == GCOV_TAG_OBJECT_SUMMARY)
 	{
-	  if (gcov_read_summary (file, &object_summary))
+	  if (gcov_read_summary (&object_summary))
 	    goto corrupt;
 	}
       else if (tag == GCOV_TAG_PROGRAM_SUMMARY
 	       || tag == GCOV_TAG_INCORRECT_SUMMARY)
-	program_count++;
+	{
+	  program_count++;
+	  gcov_resync (base, length);
+	}
       else if (tag == GCOV_TAG_FUNCTION)
 	{
 	  unsigned checksum;
 	  struct function_info *fn_n = functions;
 	  
-	  if (gcov_read_string (file, &function_name_buffer, NULL)
-	      || gcov_read_unsigned (file, &checksum))
+	  if (gcov_read_string (&function_name_buffer)
+	      || gcov_read_unsigned (&checksum))
 	    goto corrupt;
 
 	  for (fn = fn ? fn->next : NULL; ; fn = fn->next)
@@ -1103,15 +1100,16 @@ read_count_file ()
 	    {
 	      gcov_type count;
 	      
-	      if (gcov_read_counter (file, &count))
+	      if (gcov_read_counter (&count))
 		goto corrupt;
 	      fn->counts[ix] += count;
 	    }
 	}
-      gcov_resync (file, base, length);
+      else
+	gcov_resync (base, length);
     }
 
-  fclose (file);
+  gcov_close ();
   free (function_name_buffer);
   return 0;
 }
diff --git a/gcc/libgcov.c b/gcc/libgcov.c
index 73b2379847d..37d3e800c1a 100644
--- a/gcc/libgcov.c
+++ b/gcc/libgcov.c
@@ -57,6 +57,7 @@ void __gcov_flush (void) { }
 #include <fcntl.h>
 #include <errno.h>
 #endif
+#define IN_LIBGCOV 1
 #include "gcov-io.h"
 
 /* Chain of per-object gcov structures.  */
@@ -102,16 +103,6 @@ gcov_exit (void)
   gcov_type program_sum = 0;
   unsigned program_arcs = 0;
   
-#if defined (TARGET_HAS_F_SETLKW)
-  struct flock s_flock;
-
-  s_flock.l_type = F_WRLCK;
-  s_flock.l_whence = SEEK_SET;
-  s_flock.l_start = 0;
-  s_flock.l_len = 0; /* Until EOF.  */
-  s_flock.l_pid = getpid ();
-#endif
-
   memset (&program, 0, sizeof (program));
   program.checksum = gcov_crc32;
   
@@ -119,7 +110,7 @@ gcov_exit (void)
     {
       struct gcov_summary object;
       struct gcov_summary local_prg;
-      int merging = 0;
+      int merging;
       long base;
       const struct function_info *fn_info;
       gcov_type **counters;
@@ -164,27 +155,28 @@ gcov_exit (void)
       memset (&object, 0, sizeof (object));
       
       /* Open for modification */
-      if (!da_file_open (ptr->filename, &merging))
+      merging = gcov_open (ptr->filename, 0);
+      
+      if (!merging)
 	{
 	  fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
 	  ptr->filename = 0;
 	  continue;
 	}
-
-      if (merging)
+      
+      if (merging > 0)
 	{
 	  /* Merge data from file.  */
-	      
-	  if (gcov_read_unsigned (0, &tag) || tag != GCOV_DATA_MAGIC)
+	  if (gcov_read_unsigned (&tag) || tag != GCOV_DATA_MAGIC)
 	    {
 	      fprintf (stderr, "profiling:%s:Not a gcov data file\n",
 		       ptr->filename);
 	    read_fatal:;
-	      da_file_close ();
+	      gcov_close ();
 	      ptr->filename = 0;
 	      continue;
 	    }
-	  if (gcov_read_unsigned (0, &length) || length != GCOV_VERSION)
+	  if (gcov_read_unsigned (&length) || length != GCOV_VERSION)
 	    {
 	      gcov_version_mismatch (ptr, length);
 	      goto read_fatal;
@@ -194,8 +186,7 @@ gcov_exit (void)
 	  for (ix = ptr->n_functions, fn_info = ptr->functions;
 	       ix--; fn_info++)
 	    {
-	      if (gcov_read_unsigned (0, &tag)
-		  || gcov_read_unsigned (0, &length))
+	      if (gcov_read_unsigned (&tag) || gcov_read_unsigned (&length))
 		{
 		read_error:;
 		  fprintf (stderr, "profiling:%s:Error merging\n",
@@ -212,9 +203,9 @@ gcov_exit (void)
 		  goto read_fatal;
 		}
 
-	      if (gcov_read_unsigned (0, &flength)
-		  || gcov_skip_string (0, flength)
-		  || gcov_read_unsigned (0, &checksum))
+	      if (gcov_read_unsigned (&flength)
+		  || gcov_skip_string (flength)
+		  || gcov_read_unsigned (&checksum))
 		goto read_error;
 	      if (flength != strlen (fn_info->name)
 		  || checksum != fn_info->checksum)
@@ -227,8 +218,8 @@ gcov_exit (void)
 		{
 		  unsigned n_counters;
 
-		  if (gcov_read_unsigned (0, &tag)
-		      || gcov_read_unsigned (0, &length))
+		  if (gcov_read_unsigned (&tag)
+		      || gcov_read_unsigned (&length))
 		    goto read_error;
 		  for (sect_index = 0;
 		       sect_index < ptr->n_counter_sections;
@@ -244,7 +235,7 @@ gcov_exit (void)
 		    goto read_mismatch;
 		 
 		  for (jx = 0; jx < n_counters; jx++)
-	    	    if (gcov_read_counter (0, &count))
+	    	    if (gcov_read_counter (&count))
     		      goto read_error;
 		    else
 		      counters[sect_index][jx] += count;
@@ -253,23 +244,22 @@ gcov_exit (void)
 	    }
 
 	  /* Check object summary */
-	  if (gcov_read_unsigned (0, &tag)
-	      || gcov_read_unsigned (0, &length))
+	  if (gcov_read_unsigned (&tag) || gcov_read_unsigned (&length))
 	    goto read_error;
 	  if (tag != GCOV_TAG_OBJECT_SUMMARY)
 	    goto read_mismatch;
-	  if (gcov_read_summary (0, &object))
+	  if (gcov_read_summary (&object))
 	    goto read_error;
 
 	  /* Check program summary */
 	  while (1)
 	    {
-	      long base = da_file_position (0);
+	      long base = gcov_save_position ();
 	      
-	      if (gcov_read_unsigned (0, &tag)
-		  || gcov_read_unsigned (0, &length))
+	      if (gcov_read_unsigned (&tag)
+		  || gcov_read_unsigned (&length))
 		{
-		  if (da_file_eof ())
+		  if (gcov_eof ())
 		    break;
 		  goto read_error;
 		}
@@ -277,7 +267,7 @@ gcov_exit (void)
 		  && tag != GCOV_TAG_PLACEHOLDER_SUMMARY
 		  && tag != GCOV_TAG_INCORRECT_SUMMARY)
 		goto read_mismatch;
-	      if (gcov_read_summary (0, &local_prg))
+	      if (gcov_read_summary (&local_prg))
 		goto read_error;
 	      if (local_prg.checksum != program.checksum)
 		continue;
@@ -288,7 +278,7 @@ gcov_exit (void)
 			   ptr->filename);
 		  goto read_fatal;
 		}
-	      merging = -1;
+	      merging = 0;
 	      if (tag != GCOV_TAG_PROGRAM_SUMMARY)
 		break;
 	      
@@ -304,7 +294,7 @@ gcov_exit (void)
 	      ptr->wkspc = base;
 	      break;
 	    }
-	  da_file_seek (0, 0, SEEK_SET);
+	  gcov_resync (0, 0);
 	}
 
       object.runs++;
@@ -316,12 +306,12 @@ gcov_exit (void)
       
       /* Write out the data.  */
       if (/* magic */
-	  gcov_write_unsigned (0, GCOV_DATA_MAGIC)
+	  gcov_write_unsigned (GCOV_DATA_MAGIC)
 	  /* version number */
-	  || gcov_write_unsigned (0, GCOV_VERSION))
+	  || gcov_write_unsigned (GCOV_VERSION))
 	{
 	write_error:;
-	  da_file_close ();
+	  gcov_close ();
 	  fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
 	  ptr->filename = 0;
 	  continue;
@@ -333,14 +323,13 @@ gcov_exit (void)
       for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
 	{
 	  /* Announce function.  */
-	  if (gcov_write_unsigned (0, GCOV_TAG_FUNCTION)
-	      || !(base = gcov_reserve_length (0))
+	  if (gcov_write_unsigned (GCOV_TAG_FUNCTION)
+	      || !(base = gcov_reserve_length ())
 	      /* function name */
-	      || gcov_write_string (0, fn_info->name,
-				    strlen (fn_info->name))
+	      || gcov_write_string (fn_info->name)
 	      /* function checksum */
-	      || gcov_write_unsigned (0, fn_info->checksum)
-	      || gcov_write_length (0, base))
+	      || gcov_write_unsigned (fn_info->checksum)
+	      || gcov_write_length (base))
 	    goto write_error;
 
 	  /* counters.  */
@@ -357,8 +346,8 @@ gcov_exit (void)
 	      if (sect_index == ptr->n_counter_sections)
 		abort ();
 
-	      if (gcov_write_unsigned (0, tag)
-		  || !(base = gcov_reserve_length (0)))
+	      if (gcov_write_unsigned (tag)
+		  || !(base = gcov_reserve_length ()))
 		goto write_error;
 	  
     	      for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
@@ -371,41 +360,39 @@ gcov_exit (void)
 		      if (object.arc_max_sum < count)
 			object.arc_max_sum = count;
 		    }
-		  if (gcov_write_counter (0, count))
+		  if (gcov_write_counter (count))
 		    goto write_error; /* RIP Edsger Dijkstra */
 		}
-	      if (gcov_write_length (0, base))
+	      if (gcov_write_length (base))
 		goto write_error;
 	    }
 	}
 
       /* Object file summary.  */
-      if (gcov_write_summary (0, GCOV_TAG_OBJECT_SUMMARY, &object))
+      if (gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object))
 	goto write_error;
 
-      if (merging >= 0)
+      if (merging)
 	{
-	  if (da_file_seek (0, 0, SEEK_END))
-	    goto write_error;
-	  ptr->wkspc = da_file_position (0);
-	  if (gcov_write_summary (0, GCOV_TAG_PLACEHOLDER_SUMMARY,
+	  ptr->wkspc = gcov_seek_end ();
+	  if (gcov_write_summary (GCOV_TAG_PLACEHOLDER_SUMMARY,
 				  &program))
 	    goto write_error;
 	}
       else if (ptr->wkspc)
 	{
 	  /* Zap trailing program summary */
-	  if (da_file_seek (0, ptr->wkspc, SEEK_SET))
+	  if (gcov_resync (ptr->wkspc, 0))
 	    goto write_error;
 	  if (!local_prg.runs)
 	    ptr->wkspc = 0;
-	  if (gcov_write_unsigned (0, local_prg.runs
-					? GCOV_TAG_PLACEHOLDER_SUMMARY
-					: GCOV_TAG_INCORRECT_SUMMARY))
+	  if (gcov_write_unsigned (local_prg.runs
+				   ? GCOV_TAG_PLACEHOLDER_SUMMARY
+				   : GCOV_TAG_INCORRECT_SUMMARY))
 	    goto write_error;
 	}
 
-      if (da_file_close ())
+      if (gcov_close ())
 	{
 	  fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
 	  ptr->filename = 0;
@@ -434,25 +421,16 @@ gcov_exit (void)
   for (ptr = gcov_list; ptr; ptr = ptr->next)
     if (ptr->filename && ptr->wkspc)
       {
-	FILE *da_file;
-	
-	da_file = fopen (ptr->filename, "r+b");
-	if (!da_file)
+	if (!gcov_open (ptr->filename, 1))
 	  {
 	    fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
 	    continue;
 	  }
 	
-#if defined (TARGET_HAS_F_SETLKW)
-	while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
-	       && errno == EINTR)
-	  continue;
-#endif
-	if (fseek (da_file, ptr->wkspc, SEEK_SET)
- 	    || gcov_write_summary (da_file, GCOV_TAG_PROGRAM_SUMMARY, &program)
- 	    || fflush (da_file))
+	if (gcov_resync (ptr->wkspc, 0)
+ 	    || gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program))
  	  fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
-	if (fclose (da_file))
+	if (gcov_close ())
 	  fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
       }
 }
diff --git a/gcc/loop-init.c b/gcc/loop-init.c
index 44b9d61d5b8..d64d407ad94 100644
--- a/gcc/loop-init.c
+++ b/gcc/loop-init.c
@@ -27,7 +27,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "basic-block.h"
 #include "cfgloop.h"
 #include "cfglayout.h"
-#include "gcov-io.h"
 #include "profile.h"
 
 /* Initialize loop optimizer.  */
diff --git a/gcc/profile.c b/gcc/profile.c
index 68435dfd987..ec53065d567 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -101,6 +101,27 @@ struct function_list
   				/* the sections */
 };
 
+
+/* Counts information for a function.  */
+typedef struct counts_entry
+{
+  /* We hash by  */
+  char *function_name;
+  unsigned section;
+  
+  /* Store  */
+  unsigned checksum;
+  unsigned n_counts;
+  gcov_type *counts;
+  unsigned merged;
+  gcov_type max_counter;
+  gcov_type max_counter_sum;
+
+  /* Workspace */
+  struct counts_entry *chain;
+  
+} counts_entry_t;
+
 static struct function_list *functions_head = 0;
 static struct function_list **functions_tail = &functions_head;
 
@@ -119,12 +140,10 @@ struct profile_info profile_info;
 
 /* Name and file pointer of the output file for the basic block graph.  */
 
-static FILE *bbg_file;
 static char *bbg_file_name;
 
 /* Name and file pointer of the input file for the arc count data.  */
 
-static FILE *da_file;
 static char *da_file_name;
 
 /* The name of the count table. Used by the edge profiling code.  */
@@ -149,11 +168,10 @@ static void find_spanning_tree PARAMS ((struct edge_list *));
 static rtx gen_edge_profiler PARAMS ((int));
 static void instrument_edges PARAMS ((struct edge_list *));
 static void compute_branch_probabilities PARAMS ((void));
-static hashval_t htab_counts_index_hash PARAMS ((const void *));
-static int htab_counts_index_eq PARAMS ((const void *, const void *));
-static void htab_counts_index_del PARAMS ((void *));
-static void cleanup_counts_index PARAMS ((int));
-static int index_counts_file PARAMS ((void));
+static hashval_t htab_counts_entry_hash PARAMS ((const void *));
+static int htab_counts_entry_eq PARAMS ((const void *, const void *));
+static void htab_counts_entry_del PARAMS ((void *));
+static void read_counts_file PARAMS ((const char *));
 static gcov_type * get_exec_counts PARAMS ((void));
 static unsigned compute_checksum PARAMS ((void));
 static basic_block find_group PARAMS ((basic_block));
@@ -218,106 +236,61 @@ instrument_edges (el)
     fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
 }
 
-struct section_reference
-{
-  long offset;
-  int owns_summary;
-  long *summary;
-};
-
-struct da_index_entry
-{
-  /* We hash by  */
-  char *function_name;
-  unsigned section;
-  /* and store  */
-  unsigned checksum;
-  unsigned n_offsets;
-  struct section_reference *offsets;
-};
-
 static hashval_t
-htab_counts_index_hash (of)
+htab_counts_entry_hash (of)
      const void *of;
 {
-  const struct da_index_entry *entry = of;
+  const counts_entry_t *entry = of;
 
   return htab_hash_string (entry->function_name) ^ entry->section;
 }
 
 static int
-htab_counts_index_eq (of1, of2)
+htab_counts_entry_eq (of1, of2)
      const void *of1;
      const void *of2;
 {
-  const struct da_index_entry *entry1 = of1;
-  const struct da_index_entry *entry2 = of2;
+  const counts_entry_t *entry1 = of1;
+  const counts_entry_t *entry2 = of2;
 
   return !strcmp (entry1->function_name, entry2->function_name)
-	  && entry1->section == entry2->section;
+    && entry1->section == entry2->section;
 }
 
 static void
-htab_counts_index_del (what)
-     void *what;
+htab_counts_entry_del (of)
+     void *of;
 {
-  struct da_index_entry *entry = what;
-  unsigned i;
+  counts_entry_t *entry = of;
 
-  for (i = 0; i < entry->n_offsets; i++)
-    {
-      struct section_reference *act = entry->offsets + i;
-      if (act->owns_summary)
-	free (act->summary);
-    }
   free (entry->function_name);
-  free (entry->offsets);
+  free (entry->counts);
   free (entry);
 }
 
-static char *counts_file_name;
-static htab_t counts_file_index = NULL;
+static htab_t counts_hash = NULL;
 
 static void
-cleanup_counts_index (close_file)
-     int close_file;
-{
-  if (da_file && close_file)
-    {
-      fclose (da_file);
-      da_file = NULL;
-    }
-  if (counts_file_name)
-    free (counts_file_name);
-  counts_file_name = NULL;
-  if (counts_file_index)
-    htab_delete (counts_file_index);
-  counts_file_index = NULL;
-}
-
-static int
-index_counts_file ()
+read_counts_file (const char *name)
 {
   char *function_name_buffer = NULL;
   unsigned magic, version, ix, checksum;
-  long *summary;
-
-  /* No .da file, no data.  */
-  if (!da_file)
-    return 0;
-  counts_file_index = htab_create (10, htab_counts_index_hash, htab_counts_index_eq, htab_counts_index_del);
-
-  /* Now index all profile sections.  */
-  rewind (da_file);
-
-  summary = NULL;
-
-  if (gcov_read_unsigned (da_file, &magic) || magic != GCOV_DATA_MAGIC)
+  counts_entry_t *summaried = NULL;
+  unsigned seen_summary = 0;
+  
+  if (!gcov_open (name, 1))
     {
-      warning ("`%s' is not a gcov data file", da_file_name);
-      goto cleanup;
+      warning ("file %s not found, execution counts assumed to be zero", name);
+      return;
     }
-  if (gcov_read_unsigned (da_file, &version) || version != GCOV_VERSION)
+  
+  if (gcov_read_unsigned (&magic) || magic != GCOV_DATA_MAGIC)
+    {
+      warning ("`%s' is not a gcov data file", name);
+      gcov_close ();
+      return;
+    }
+  else if (gcov_read_unsigned (&version) || version != GCOV_VERSION)
     {
       char v[4], e[4];
       magic = GCOV_VERSION;
@@ -327,97 +300,121 @@ index_counts_file ()
 	  v[ix] = version;
 	  e[ix] = magic;
 	}
-      warning ("`%s' is version `%.4s', expected version `%.4s'",
-	       da_file_name, v, e);
-      goto cleanup;
+      warning ("`%s' is version `%.4s', expected version `%.4s'", name, v, e);
+      gcov_close ();
+      return;
     }
   
+  counts_hash = htab_create (10,
+			     htab_counts_entry_hash, htab_counts_entry_eq,
+			     htab_counts_entry_del);
   while (1)
     {
       unsigned tag, length;
       long offset;
       
-      offset = gcov_save_position (da_file);
-      if (gcov_read_unsigned (da_file, &tag)
-	  || gcov_read_unsigned (da_file, &length))
+      offset = gcov_save_position ();
+      if (gcov_read_unsigned (&tag) || gcov_read_unsigned (&length))
 	{
-	  if (feof (da_file))
+	  if (gcov_eof ())
 	    break;
 	corrupt:;
-	  warning ("`%s' is corrupted", da_file_name);
-	  goto cleanup;
+	  warning ("`%s' is corrupted", name);
+	cleanup:
+	  htab_delete (counts_hash);
+	  break;
 	}
       if (tag == GCOV_TAG_FUNCTION)
 	{
-	  if (gcov_read_string (da_file, &function_name_buffer, NULL)
-	      || gcov_read_unsigned (da_file, &checksum))
+	  if (gcov_read_string (&function_name_buffer)
+	      || gcov_read_unsigned (&checksum))
 	    goto corrupt;
-	  continue;
+	  if (seen_summary)
+	    {
+	      /* We have already seen a summary, this means that this
+		 new function begins a new set of program runs. We
+		 must unlink the summaried chain.  */
+	      counts_entry_t *entry, *chain;
+	      
+	      for (entry = summaried; entry; entry = chain)
+		{
+		  chain = entry->chain;
+		  
+		  entry->max_counter_sum += entry->max_counter;
+		  entry->chain = NULL;
+		}
+	      summaried = NULL;
+	      seen_summary = 0;
+	    }
 	}
-      if (tag == GCOV_TAG_PROGRAM_SUMMARY)
+      else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
 	{
-	  if (length != GCOV_SUMMARY_LENGTH)
+	  counts_entry_t *entry;
+	  struct gcov_summary summary;
+	  
+	  if (length != GCOV_SUMMARY_LENGTH
+	      || gcov_read_summary (&summary))
 	    goto corrupt;
 
-	  if (summary)
-	    *summary = offset;
-	  summary = NULL;
+	  seen_summary = 1;
+	  for (entry = summaried; entry; entry = entry->chain)
+	    {
+	      entry->merged += summary.runs;
+	      if (entry->max_counter < summary.arc_sum_max)
+		entry->max_counter = summary.arc_sum_max;
+	    }
 	}
-      else
+      else if (GCOV_TAG_IS_SUBTAG (GCOV_TAG_FUNCTION, tag)
+	       && function_name_buffer)
 	{
-	  if (function_name_buffer)
-	    {
-	      struct da_index_entry **slot, elt;
-	      elt.function_name = function_name_buffer;
-	      elt.section = tag;
+	  counts_entry_t **slot, *entry, elt;
+	  unsigned n_counts = length / 8;
+	  unsigned ix;
+	  gcov_type count;
 
-	      slot = (struct da_index_entry **)
-		htab_find_slot (counts_file_index, &elt, INSERT);
-	      if (*slot)
-		{
-		  if ((*slot)->checksum != checksum)
-		    {
-		      warning ("profile mismatch for `%s'", function_name_buffer);
-		      goto cleanup;
-		    }
-		  (*slot)->n_offsets++;
-		  (*slot)->offsets = xrealloc ((*slot)->offsets,
-					       sizeof (struct section_reference) * (*slot)->n_offsets);
-		}
-	      else
-		{
-		  *slot = xmalloc (sizeof (struct da_index_entry));
-		  (*slot)->function_name = xstrdup (function_name_buffer);
-		  (*slot)->section = tag;
-		  (*slot)->checksum = checksum;
-		  (*slot)->n_offsets = 1;
-		  (*slot)->offsets = xmalloc (sizeof (struct section_reference));
-		}
-	      (*slot)->offsets[(*slot)->n_offsets - 1].offset = offset;
-	      if (summary)
-		(*slot)->offsets[(*slot)->n_offsets - 1].owns_summary = 0;
-	      else
-		{
-		  summary = xmalloc (sizeof (long));
-		  *summary = -1;
-		  (*slot)->offsets[(*slot)->n_offsets - 1].owns_summary = 1;
-		}
-	      (*slot)->offsets[(*slot)->n_offsets - 1].summary = summary;
+	  elt.function_name = function_name_buffer;
+	  elt.section = tag;
+
+	  slot = (counts_entry_t **) htab_find_slot
+	    (counts_hash, &elt, INSERT);
+	  entry = *slot;
+	  if (!entry)
+	    {
+	      *slot = entry = xmalloc (sizeof (counts_entry_t));
+	      entry->function_name = xstrdup (function_name_buffer);
+	      entry->section = tag;
+	      entry->checksum = checksum;
+	      entry->n_counts = n_counts;
+	      entry->counts = xcalloc (n_counts, sizeof (gcov_type));
+	    }
+	  else if (entry->checksum != checksum || entry->n_counts != n_counts)
+	    {
+	      warning ("profile mismatch for `%s'", function_name_buffer);
+	      goto cleanup;
+	    }
+	  
+	  /* This should always be true for a just allocated entry,
+	     and always false for an existing one. Check this way, in
+	     case the gcov file is corrupt.  */
+	  if (!entry->chain || summaried != entry)
+	    {
+	      entry->chain = summaried;
+	      summaried = entry;
+	    }
+	  for (ix = 0; ix != n_counts; ix++)
+	    {
+	      if (gcov_read_counter (&count))
+		goto corrupt;
+	      entry->counts[ix] += count;
 	    }
 	}
-      if (gcov_skip (da_file, length))
-	goto corrupt;
+      else
+	if (gcov_skip (length))
+	  goto corrupt;
     }
 
   free (function_name_buffer);
-
-  return 1;
-
-cleanup:
-  cleanup_counts_index (1);
-  if (function_name_buffer)
-    free (function_name_buffer);
-  return 0;
+  gcov_close ();
 }
 
 /* Computes hybrid profile for all matching entries in da_file.
@@ -428,26 +425,17 @@ get_exec_counts ()
 {
   unsigned num_edges = 0;
   basic_block bb;
-  gcov_type *profile;
-  gcov_type max_count;
-  unsigned ix, i, tag, length, num;
   const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
-  struct da_index_entry *entry, what;
-  struct section_reference *act;
-  gcov_type count;
-  struct gcov_summary summ;
+  counts_entry_t *entry, elt;
 
   profile_info.max_counter_in_program = 0;
   profile_info.count_profiles_merged = 0;
 
-  /* No .da file, no execution counts.  */
-  if (!da_file)
+  /* No hash table, no counts. */
+  if (!counts_hash)
     return NULL;
-  if (!counts_file_index)
-    abort ();
 
   /* Count the edges to be (possibly) instrumented.  */
-
   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
     {
       edge e;
@@ -456,81 +444,24 @@ get_exec_counts ()
 	  num_edges++;
     }
 
-  /* now read and combine all matching profiles.  */
-
-  profile = xmalloc (sizeof (gcov_type) * num_edges);
-
-  for (ix = 0; ix < num_edges; ix++)
-    profile[ix] = 0;
-
-  what.function_name = (char *) name;
-  what.section = GCOV_TAG_ARC_COUNTS;
-  entry = htab_find (counts_file_index, &what);
+  elt.function_name = (char *) name;
+  elt.section = GCOV_TAG_ARC_COUNTS;
+  entry = htab_find (counts_hash, &elt);
   if (!entry)
     {
       warning ("No profile for function '%s' found.", name);
-      goto cleanup;
+      return NULL;
     }
   
-  if (entry->checksum != profile_info.current_function_cfg_checksum)
+  if (entry->checksum != profile_info.current_function_cfg_checksum
+      || num_edges != entry->n_counts)
     {
       warning ("profile mismatch for `%s'", current_function_name);
-      goto cleanup;
+      return NULL;
     }
 
-  for (i = 0; i < entry->n_offsets; i++)
-    {
-      act = entry->offsets + i;
-
-      /* Read arc counters.  */
-      max_count = 0;
-      gcov_resync (da_file, act->offset, 0);
-
-      if (gcov_read_unsigned (da_file, &tag)
-	  || gcov_read_unsigned (da_file, &length)
-	  || tag != GCOV_TAG_ARC_COUNTS)
-	{
-	  /* We have already passed through file, so any error means
-	     something is rotten.  */
-	  abort ();
-	}
-      num = length / 8;
-
-      if (num != num_edges)
-	{
-	  warning ("profile mismatch for `%s'", current_function_name);
-	  goto cleanup;
-	}
-	  
-      for (ix = 0; ix != num; ix++)
-	{
-	  if (gcov_read_counter (da_file, &count))
-	    abort ();
-	  if (count > max_count)
-	    max_count = count;
-	  profile[ix] += count;
-	}
-
-      /* Read program summary.  */
-      if (*act->summary != -1)
-	{
-	  gcov_resync (da_file, *act->summary, 0);
-	  if (gcov_read_unsigned (da_file, &tag)
-	      || gcov_read_unsigned (da_file, &length)
-	      || tag != GCOV_TAG_PROGRAM_SUMMARY
-	      || gcov_read_summary (da_file, &summ))
-	    abort ();
-	  profile_info.count_profiles_merged += summ.runs;
-	  profile_info.max_counter_in_program += summ.arc_sum_max;
-	}
-      else
-	summ.runs = 0;
-      if (!summ.runs)
-	{
-	  profile_info.count_profiles_merged++;
-	  profile_info.max_counter_in_program += max_count;
-	}
-    }
+  profile_info.count_profiles_merged = entry->merged;
+  profile_info.max_counter_in_program = entry->max_counter_sum;
 
   if (rtl_dump_file)
     {
@@ -539,12 +470,7 @@ get_exec_counts ()
 	      (int)profile_info.max_counter_in_program);
     }
 
-  return profile;
-
-cleanup:;
-  free (profile);
-  cleanup_counts_index (1);
-  return NULL;
+  return entry->counts;
 }
 
 
@@ -858,8 +784,6 @@ compute_branch_probabilities ()
     }
 
   free_aux_for_blocks ();
-  if (exec_counts)
-    free (exec_counts);
   find_counters_section (GCOV_TAG_ARC_COUNTS)->present = 1;
 }
 
@@ -1083,32 +1007,30 @@ branch_prob ()
      edge output the source and target basic block numbers.
      NOTE: The format of this file must be compatible with gcov.  */
 
-  if (flag_test_coverage && bbg_file)
+  if (gcov_ok ())
     {
       long offset;
       const char *file = DECL_SOURCE_FILE (current_function_decl);
       unsigned line = DECL_SOURCE_LINE (current_function_decl);
       
       /* Announce function */
-      if (gcov_write_unsigned (bbg_file, GCOV_TAG_FUNCTION)
-	  || !(offset = gcov_reserve_length (bbg_file))
-	  || gcov_write_string (bbg_file, name,
-			     strlen (name))
-	  || gcov_write_unsigned (bbg_file,
-			    profile_info.current_function_cfg_checksum)
-	  || gcov_write_string (bbg_file, file, strlen (file))
-	  || gcov_write_unsigned (bbg_file, line)
-	  || gcov_write_length (bbg_file, offset))
+      if (gcov_write_unsigned (GCOV_TAG_FUNCTION)
+	  || !(offset = gcov_reserve_length ())
+	  || gcov_write_string (name)
+	  || gcov_write_unsigned (profile_info.current_function_cfg_checksum)
+	  || gcov_write_string (file)
+	  || gcov_write_unsigned (line)
+	  || gcov_write_length (offset))
 	goto bbg_error;
 
       /* Basic block flags */
-      if (gcov_write_unsigned (bbg_file, GCOV_TAG_BLOCKS)
-	  || !(offset = gcov_reserve_length (bbg_file)))
+      if (gcov_write_unsigned (GCOV_TAG_BLOCKS)
+	  || !(offset = gcov_reserve_length ()))
 	goto bbg_error;
       for (i = 0; i != (unsigned) (n_basic_blocks + 2); i++)
-	if (gcov_write_unsigned (bbg_file, 0))
+	if (gcov_write_unsigned (0))
 	  goto bbg_error;
-      if (gcov_write_length (bbg_file, offset))
+      if (gcov_write_length (offset))
 	goto bbg_error;
       
       /* Arcs */
@@ -1116,9 +1038,9 @@ branch_prob ()
 	{
 	  edge e;
 
-	  if (gcov_write_unsigned (bbg_file, GCOV_TAG_ARCS)
-	      || !(offset = gcov_reserve_length (bbg_file))
-	      || gcov_write_unsigned (bbg_file, BB_TO_GCOV_INDEX (bb)))
+	  if (gcov_write_unsigned (GCOV_TAG_ARCS)
+	      || !(offset = gcov_reserve_length ())
+	      || gcov_write_unsigned (BB_TO_GCOV_INDEX (bb)))
 	    goto bbg_error;
 
 	  for (e = bb->succ; e; e = e->succ_next)
@@ -1135,14 +1057,13 @@ branch_prob ()
 		  if (e->flags & EDGE_FALLTHRU)
 		    flag_bits |= GCOV_ARC_FALLTHROUGH;
 
-		  if (gcov_write_unsigned (bbg_file,
-					   BB_TO_GCOV_INDEX (e->dest))
-		      || gcov_write_unsigned (bbg_file, flag_bits))
+		  if (gcov_write_unsigned (BB_TO_GCOV_INDEX (e->dest))
+		      || gcov_write_unsigned (flag_bits))
 		    goto bbg_error;
 	        }
 	    }
 
-	  if (gcov_write_length (bbg_file, offset))
+	  if (gcov_write_length (offset))
 	    goto bbg_error;
 	}
 
@@ -1185,10 +1106,10 @@ branch_prob ()
 		      {
 			if (offset)
 			  /*NOP*/;
-			else if (gcov_write_unsigned (bbg_file, GCOV_TAG_LINES)
-				 || !(offset = gcov_reserve_length (bbg_file))
-				 || gcov_write_unsigned (bbg_file,
-						   BB_TO_GCOV_INDEX (bb)))
+			else if (gcov_write_unsigned (GCOV_TAG_LINES)
+				 || !(offset = gcov_reserve_length ())
+				 || (gcov_write_unsigned
+				     (BB_TO_GCOV_INDEX (bb))))
 			  goto bbg_error;
 			/* If this is a new source file, then output
 			   the file's name to the .bb file.  */
@@ -1197,12 +1118,11 @@ branch_prob ()
 				       prev_file_name))
 			  {
 			    prev_file_name = NOTE_SOURCE_FILE (insn);
-			    if (gcov_write_unsigned (bbg_file, 0)
-				|| gcov_write_string (bbg_file, prev_file_name,
-						      strlen (prev_file_name)))
+			    if (gcov_write_unsigned (0)
+				|| gcov_write_string (prev_file_name))
 			      goto bbg_error;
 			  }
-			if (gcov_write_unsigned (bbg_file, NOTE_LINE_NUMBER (insn)))
+			if (gcov_write_unsigned (NOTE_LINE_NUMBER (insn)))
 			  goto bbg_error;
 		      }
 		  }
@@ -1211,14 +1131,13 @@ branch_prob ()
 
 	    if (offset)
 	      {
-		if (gcov_write_unsigned (bbg_file, 0)
-		    || gcov_write_string (bbg_file, NULL, 0)
-		    || gcov_write_length (bbg_file, offset))
+		if (gcov_write_unsigned (0)
+		    || gcov_write_string (NULL)
+		    || gcov_write_length (offset))
 		  {
 		  bbg_error:;
 		    warning ("error writing `%s'", bbg_file_name);
-		    fclose (bbg_file);
-		    bbg_file = NULL;
+		    gcov_error ();
 		  }
 	      }
 	  }
@@ -1395,38 +1314,27 @@ init_branch_prob (filename)
   int len = strlen (filename);
   int i;
 
+  da_file_name = (char *) xmalloc (len + strlen (GCOV_DATA_SUFFIX) + 1);
+  strcpy (da_file_name, filename);
+  strcat (da_file_name, GCOV_DATA_SUFFIX);
+  
+  if (flag_branch_probabilities)
+    read_counts_file (da_file_name);
+
   if (flag_test_coverage)
     {
       /* Open the bbg output file.  */
       bbg_file_name = (char *) xmalloc (len + strlen (GCOV_GRAPH_SUFFIX) + 1);
       strcpy (bbg_file_name, filename);
       strcat (bbg_file_name, GCOV_GRAPH_SUFFIX);
-      bbg_file = fopen (bbg_file_name, "wb");
-      if (!bbg_file)
-	fatal_io_error ("cannot open %s", bbg_file_name);
-
-      if (gcov_write_unsigned (bbg_file, GCOV_GRAPH_MAGIC)
-	  || gcov_write_unsigned (bbg_file, GCOV_VERSION))
+      if (!gcov_open (bbg_file_name, -1))
 	{
-	  fclose (bbg_file);
-	  fatal_io_error ("cannot write `%s'", bbg_file_name);
+	  error ("cannot open %s", bbg_file_name);
+	  gcov_error ();
 	}
-    }
-
-  da_file_name = (char *) xmalloc (len + strlen (GCOV_DATA_SUFFIX) + 1);
-  strcpy (da_file_name, filename);
-  strcat (da_file_name, GCOV_DATA_SUFFIX);
-  
-  if (flag_branch_probabilities)
-    {
-      da_file = fopen (da_file_name, "rb");
-      if (!da_file)
-	warning ("file %s not found, execution counts assumed to be zero",
-		 da_file_name);
-      if (counts_file_index && strcmp (da_file_name, counts_file_name))
-       	cleanup_counts_index (0);
-      if (index_counts_file ())
-	counts_file_name = xstrdup (da_file_name);
+      else if (gcov_write_unsigned (GCOV_GRAPH_MAGIC)
+	       || gcov_write_unsigned (GCOV_VERSION))
+	gcov_error ();
     }
 
   if (profile_arc_flag)
@@ -1459,27 +1367,20 @@ end_branch_prob ()
 {
   if (flag_test_coverage)
     {
-      if (bbg_file)
-	{
-#if !SELF_COVERAGE
-	  /* If the compiler is instrumented, we should not remove the
-             counts file, because we might be recompiling
-             ourselves. The .da files are all removed during copying
-             the stage1 files.  */
-	  unlink (da_file_name);
+      int error = gcov_close ();
+      
+      if (error)
+	unlink (bbg_file_name);
+#if SELF_COVERAGE
+      /* If the compiler is instrumented, we should not
+         unconditionally remove the counts file, because we might be
+         recompiling ourselves. The .da files are all removed during
+         copying the stage1 files.  */
+      if (error)
 #endif
-	  fclose (bbg_file);
-	}
-      else
-	{
-	  unlink (bbg_file_name);
-	  unlink (da_file_name);
-	}
+	unlink (da_file_name);
     }
 
-  if (da_file)
-    fclose (da_file);
-
   if (rtl_dump_file)
     {
       fprintf (rtl_dump_file, "\n");
-- 
cgit v1.2.1