This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gcov] Simplify file interface


This patch simplifies the gcov file interface. The original interface
was designed around FILE, but Zdenek Dvorak found a problem with
the seeks performed that caused excessive disk activity. He implemented
a buffer based interface behind the FILE interface. That overly complicates
things, and has excessive copying.

This patch removes the FILE interface, and makes the gcov file access work
one file at a time (the runtime already did this, but the compiler
did not). IMO this makes the interface much simpler.

In profile.c I now read in and merge the appropriate counts in one go,
rather than index the gcov file and then gather the statistics as necessary.

I also corrected some errors with Zdenek's patch, it incorrectly accumulated
PROGRAM_SUMMARY data, and would open binary files not in text mode.

The patch is obvious, once one has bought into removing the FILE interface.
It shaves about 2 minutes of a --enable-coverage bootstrap and 1/3 off a
subsequent check-gcc & check-g++.

I'd like to further simplify things and improve the runtime performance,
and this patch is a step in the right direction.

booted and tested on i686-pc-linux gnu, ok?

nathan
--
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
         The voices in my head said this was stupid too
nathan at codesourcery dot com : http://www.cs.bris.ac.uk/~nathan/ : nathan at acm dot org

2003-04-02  Nathan Sidwell  <nathan at codesourcery dot 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.

Index: gcov-dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcov-dump.c,v
retrieving revision 1.4
diff -c -3 -p -r1.4 gcov-dump.c
*** gcov-dump.c	26 Feb 2003 16:55:09 -0000	1.4
--- gcov-dump.c	2 Apr 2003 15:13:20 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 23,48 ****
  #include "tm.h"
  #include "version.h"
  #include <getopt.h>
! typedef HOST_WIDEST_INT gcov_type;
  #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));
  extern int main PARAMS ((int, char **));
  
  typedef struct tag_format
  {
    unsigned tag;
    char const *name;
!   int (*proc) (const char *, FILE *, unsigned, unsigned);
  } tag_format_t;
  
  static int flag_dump_contents = 0;
--- 23,48 ----
  #include "tm.h"
  #include "version.h"
  #include <getopt.h>
! #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 *, 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 *, unsigned, unsigned);
  } tag_format_t;
  
  static int flag_dump_contents = 0;
*************** static void
*** 138,161 ****
  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)
      {
        fprintf (stderr, "%s:cannot open\n", filename);
        return;
      }
    
!   if (gcov_read_unsigned (file, &magic)
!       || gcov_read_unsigned (file, &version))
      {
      read_error:;
!       printf ("%s:read error at %ld\n", filename, ftell (file));
!       fclose (file);
        return;
      }
  
--- 138,159 ----
  dump_file (filename)
       const char *filename;
  {
    unsigned tags[4];
    unsigned depth = 0;
    unsigned magic, version;
    unsigned tag, length;
    
!   if (!gcov_open (filename, 1))
      {
        fprintf (stderr, "%s:cannot open\n", filename);
        return;
      }
    
!   if (gcov_read_unsigned (&magic) || gcov_read_unsigned (&version))
      {
      read_error:;
!       printf ("%s:read error at %lu\n", filename, gcov_save_position ());
!       gcov_close ();
        return;
      }
  
*************** dump_file (filename)
*** 174,180 ****
      else
        {
  	printf ("%s:not a gcov file\n", filename);
! 	fclose (file);
  	return;
        }
      for (ix = 4; ix--; expected >>= 8, version >>= 8, magic >>= 8)
--- 172,178 ----
      else
        {
  	printf ("%s:not a gcov file\n", filename);
! 	gcov_close ();
  	return;
        }
      for (ix = 4; ix--; expected >>= 8, version >>= 8, magic >>= 8)
*************** dump_file (filename)
*** 189,202 ****
        printf ("%s:warning:current version is `%.4s'\n", filename, e);
    }
  
!   while (!gcov_read_unsigned (file, &tag)
! 	 && !gcov_read_unsigned (file, &length))
      {
        tag_format_t const *format;
        unsigned tag_depth;
        long base, end;
        
!       base = gcov_save_position (file);
        
        if (!tag)
  	tag_depth = depth;
--- 187,199 ----
        printf ("%s:warning:current version is `%.4s'\n", filename, e);
    }
  
!   while (!gcov_read_unsigned (&tag) && !gcov_read_unsigned (&length))
      {
        tag_format_t const *format;
        unsigned tag_depth;
        long base, end;
        
!       base = gcov_save_position ();
        
        if (!tag)
  	tag_depth = depth;
*************** dump_file (filename)
*** 234,244 ****
        print_prefix (filename, tag_depth);
        printf ("%08x:%4u:%s", tag, length, format->name);
        if (format->proc)
! 	if ((*format->proc) (filename, file, tag, length))
  	  goto read_error;
        printf ("\n");
!       end = gcov_save_position (file);
!       gcov_resync (file, base, length);
        if (format->proc && end != base + (long)length)
  	{
  	  if (end > base + (long)length)
--- 231,241 ----
        print_prefix (filename, tag_depth);
        printf ("%08x:%4u:%s", tag, length, format->name);
        if (format->proc)
! 	if ((*format->proc) (filename, tag, length))
  	  goto read_error;
        printf ("\n");
!       end = gcov_save_position ();
!       gcov_resync (base, length);
        if (format->proc && end != base + (long)length)
  	{
  	  if (end > base + (long)length)
*************** dump_file (filename)
*** 249,283 ****
  		    filename, length - (end - base));
  	}
      }
!   if (!feof (file))
      goto read_error;
!   fclose (file);
  }
  
  static int
! tag_function (filename, file, tag, length)
       const char *filename ATTRIBUTE_UNUSED;
-      FILE *file ATTRIBUTE_UNUSED;
       unsigned tag ATTRIBUTE_UNUSED;
       unsigned length ATTRIBUTE_UNUSED;
  {
    char *name = NULL;
    unsigned checksum;
  
!   if (gcov_read_string (file, &name, NULL)
!       || gcov_read_unsigned (file, &checksum))
      return 1;
  
    printf (" `%s' checksum=0x%08x", name, checksum);
    free (name);
    
    return 0;
  }
  
  static int
! tag_blocks (filename, file, tag, length)
       const char *filename ATTRIBUTE_UNUSED;
-      FILE *file ATTRIBUTE_UNUSED;
       unsigned tag ATTRIBUTE_UNUSED;
       unsigned length ATTRIBUTE_UNUSED;
  {
--- 246,289 ----
  		    filename, length - (end - base));
  	}
      }
!   if (!gcov_eof ())
      goto read_error;
!   gcov_close ();
  }
  
  static int
! tag_function (filename, tag, length)
       const char *filename 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_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, tag, length)
       const char *filename ATTRIBUTE_UNUSED;
       unsigned tag ATTRIBUTE_UNUSED;
       unsigned length ATTRIBUTE_UNUSED;
  {
*************** tag_blocks (filename, file, tag, length)
*** 292,298 ****
        for (ix = 0; ix != n_blocks; ix++)
  	{
  	  unsigned flags;
! 	  if (gcov_read_unsigned (file, &flags))
  	    return 1;
  	  if (!(ix & 7))
  	    printf ("\n%s:\t\t%u", filename, ix);
--- 298,304 ----
        for (ix = 0; ix != n_blocks; ix++)
  	{
  	  unsigned flags;
! 	  if (gcov_read_unsigned (&flags))
  	    return 1;
  	  if (!(ix & 7))
  	    printf ("\n%s:\t\t%u", filename, ix);
*************** tag_blocks (filename, file, tag, length)
*** 301,315 ****
        
      }
    else
!     gcov_skip (file, n_blocks * 4);
    
    return 0;
  }
  
  static int
! tag_arcs (filename, file, tag, length)
       const char *filename ATTRIBUTE_UNUSED;
-      FILE *file ATTRIBUTE_UNUSED;
       unsigned tag ATTRIBUTE_UNUSED;
       unsigned length ATTRIBUTE_UNUSED;
  {
--- 307,320 ----
        
      }
    else
!     gcov_skip (n_blocks * 4);
    
    return 0;
  }
  
  static int
! tag_arcs (filename, tag, length)
       const char *filename ATTRIBUTE_UNUSED;
       unsigned tag ATTRIBUTE_UNUSED;
       unsigned length ATTRIBUTE_UNUSED;
  {
*************** tag_arcs (filename, file, tag, length)
*** 321,335 ****
        unsigned ix;
        unsigned blockno;
  
!       if (gcov_read_unsigned (file, &blockno))
  	return 1;
  
        for (ix = 0; ix != n_arcs; ix++)
  	{
  	  unsigned dst, flags;
  	  
! 	  if (gcov_read_unsigned (file, &dst)
! 	      || gcov_read_unsigned (file, &flags))
  	    return 1;
  	  if (!(ix & 3))
  	    printf ("\n%s:\t\t%u:", filename, blockno);
--- 326,339 ----
        unsigned ix;
        unsigned blockno;
  
!       if (gcov_read_unsigned (&blockno))
  	return 1;
  
        for (ix = 0; ix != n_arcs; ix++)
  	{
  	  unsigned dst, flags;
  	  
! 	  if (gcov_read_unsigned (&dst) || gcov_read_unsigned (&flags))
  	    return 1;
  	  if (!(ix & 3))
  	    printf ("\n%s:\t\t%u:", filename, blockno);
*************** tag_arcs (filename, file, tag, length)
*** 337,351 ****
  	}
      }
    else
!     gcov_skip (file, 4 + n_arcs * 8);
    
    return 0;
  }
  
  static int
! tag_lines (filename, file, tag, length)
       const char *filename ATTRIBUTE_UNUSED;
-      FILE *file ATTRIBUTE_UNUSED;
       unsigned tag ATTRIBUTE_UNUSED;
       unsigned length ATTRIBUTE_UNUSED;
  {
--- 341,354 ----
  	}
      }
    else
!     gcov_skip (4 + n_arcs * 8);
    
    return 0;
  }
  
  static int
! tag_lines (filename, tag, length)
       const char *filename ATTRIBUTE_UNUSED;
       unsigned tag ATTRIBUTE_UNUSED;
       unsigned length ATTRIBUTE_UNUSED;
  {
*************** tag_lines (filename, file, tag, length)
*** 355,375 ****
        unsigned blockno;
        char const *sep = NULL;
  
!       if (gcov_read_unsigned (file, &blockno))
  	return 1;
        
        while (1)
  	{
  	  unsigned lineno;
  	  
! 	  if (gcov_read_unsigned (file, &lineno))
  	    {
  	      free (source);
  	      return 1;
  	    }
  	  if (!lineno)
  	    {
! 	      if (gcov_read_string (file, &source, NULL))
  		return 1;
  	      if (!source)
  		break;
--- 358,378 ----
        unsigned blockno;
        char const *sep = NULL;
  
!       if (gcov_read_unsigned (&blockno))
  	return 1;
        
        while (1)
  	{
  	  unsigned lineno;
  	  
! 	  if (gcov_read_unsigned (&lineno))
  	    {
  	      free (source);
  	      return 1;
  	    }
  	  if (!lineno)
  	    {
! 	      if (gcov_read_string (&source))
  		return 1;
  	      if (!source)
  		break;
*************** tag_lines (filename, file, tag, length)
*** 394,408 ****
  	}
      }
    else
!     gcov_skip (file, length);
    
    return 0;
  }
  
  static int
! tag_arc_counts (filename, file, tag, length)
       const char *filename ATTRIBUTE_UNUSED;
-      FILE *file ATTRIBUTE_UNUSED;
       unsigned tag ATTRIBUTE_UNUSED;
       unsigned length ATTRIBUTE_UNUSED;
  {
--- 397,410 ----
  	}
      }
    else
!     gcov_skip (length);
    
    return 0;
  }
  
  static int
! tag_arc_counts (filename, tag, length)
       const char *filename ATTRIBUTE_UNUSED;
       unsigned tag ATTRIBUTE_UNUSED;
       unsigned length ATTRIBUTE_UNUSED;
  {
*************** tag_arc_counts (filename, file, tag, len
*** 417,423 ****
  	{
  	  gcov_type count;
  	  
! 	  if (gcov_read_counter (file, &count))
  	    return 1;
  	  if (!(ix & 7))
  	    printf ("\n%s:\t\t%u", filename, ix);
--- 419,425 ----
  	{
  	  gcov_type count;
  	  
! 	  if (gcov_read_counter (&count))
  	    return 1;
  	  if (!(ix & 7))
  	    printf ("\n%s:\t\t%u", filename, ix);
*************** tag_arc_counts (filename, file, tag, len
*** 426,446 ****
  	}
      }
    else
!     gcov_skip (file, n_counts * 8);
    
    return 0;
  }
  
  static int
! tag_summary (filename, file, 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))
      return 1;
    printf (" checksum=0x%08x", summary.checksum);
    
--- 428,447 ----
  	}
      }
    else
!     gcov_skip (n_counts * 8);
    
    return 0;
  }
  
  static int
! tag_summary (filename, tag, length)
       const char *filename ATTRIBUTE_UNUSED;
       unsigned tag ATTRIBUTE_UNUSED;
       unsigned length ATTRIBUTE_UNUSED;
  {
    struct gcov_summary summary;
  
!   if (gcov_read_summary (&summary))
      return 1;
    printf (" checksum=0x%08x", summary.checksum);
    
Index: gcov-io.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcov-io.h,v
retrieving revision 1.22
diff -c -3 -p -r1.22 gcov-io.h
*** gcov-io.h	31 Mar 2003 15:18:20 -0000	1.22
--- gcov-io.h	2 Apr 2003 15:13:21 -0000
*************** Software Foundation, 59 Temple Place - S
*** 135,158 ****
     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).  */
  
  #ifndef GCC_GCOV_IO_H
  #define GCC_GCOV_IO_H
  
! #if IN_LIBGCC2
  #if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
  typedef long gcov_type;
  #else
  typedef long long gcov_type;
  #endif
! #endif /* IN_LIBGCC2 */
  
  /* File suffixes.  */
  #define GCOV_DATA_SUFFIX ".da"
--- 135,164 ----
     merged.
  
     This file is included by both the compiler, gcov tools and the
!    runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to
!    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_LIBGCOV
  #if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
  typedef long gcov_type;
  #else
  typedef long long gcov_type;
  #endif
! #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"
*************** struct counter_section
*** 228,234 ****
    unsigned n_counters;	/* Number of counters in the section.  */
  };
  
! #if IN_LIBGCC2
  /* Information about section of counters for an object file.  */
  struct counter_section_data
  {
--- 234,240 ----
    unsigned n_counters;	/* Number of counters in the section.  */
  };
  
! #if IN_LIBGCOV
  /* Information about section of counters for an object file.  */
  struct counter_section_data
  {
*************** extern void __gcov_flush (void);
*** 272,410 ****
  
  /* 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 */
  
  /* 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;
! #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;
! #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));
! #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 *));
  
! /* Write VALUE to coverage file 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;
  {
!   char buffer[4];
    unsigned ix;
  
!   for (ix = sizeof (buffer); ix--; )
      {
        buffer[ix] = value;
        value >>= 8;
      }
!   return ((sizeof (value) > sizeof (buffer) && value)
! 	  || da_file_write (buffer, 1, sizeof (buffer), file) != sizeof (buffer));
  }
  
! /* Write VALUE to coverage file 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.  */
  
  static int
! gcov_write_counter (file, value)
!      FILE *file;
!      gcov_type value;
  {
!   char buffer[8];
    unsigned ix;
  
!   for (ix = sizeof (buffer); 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));
  }
  
! /* Write VALUE to coverage file 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;
  {
-   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);
    else
!     return gcov_write_unsigned (file, 0);
  }
  
! /* Read *VALUE_P from coverage file 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;
  {
    unsigned value = 0;
    unsigned ix;
!   unsigned char buffer[4];
  
!   if (da_file_read (buffer, 1, sizeof (buffer), file) != sizeof (buffer))
      return 1;
!   for (ix = sizeof (value); ix < sizeof (buffer); ix++)
      if (buffer[ix])
        return 1;
!   for (ix = 0; ix != sizeof (buffer); ix++)
      {
        value <<= 8;
        value |= buffer[ix];
--- 278,646 ----
  
  /* 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 ATTRIBUTE_UNUSED
  # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
  #endif
  
! #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_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
! 
!   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
!     }
!   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
!       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.  Return nonzero if failed due to
     file i/o error, or value error.  */
  
  static int
! gcov_write_unsigned (unsigned value)
  {
!   unsigned char *buffer = gcov_write_bytes (4);
    unsigned ix;
  
!   if (!buffer)
!     return 1;
!   
!   for (ix = 4; ix--; )
      {
        buffer[ix] = value;
        value >>= 8;
      }
!   return sizeof (value) > 4 && value;
  }
  
! /* 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 (gcov_type value)
  {
!   unsigned char *buffer = gcov_write_bytes (8);
    unsigned ix;
  
!   if (!buffer)
!     return 1;
!   
!   for (ix = 8; ix--; )
      {
        buffer[ix] = value;
        value >>= 8;
      }
!   return sizeof (value) > 8 && value;
  }
+ #endif /* IN_LIBGCOV */
  
! /* Write VALUE to coverage file.  Return nonzero if failed due to
     file i/o error, or value error.  */
  
  static int
! gcov_write_string (const char *string)
  {
    if (string)
!     {
!       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 (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.  Return nonzero if failed
     due to file i/o error, or range error.  */
  
  static int
! gcov_read_unsigned (unsigned *value_p)
  {
    unsigned value = 0;
    unsigned ix;
!   const unsigned char *buffer = gcov_read_bytes (4);
  
!   if (!buffer)
      return 1;
!   for (ix = sizeof (value); ix < 4; ix++)
      if (buffer[ix])
        return 1;
!   for (ix = 0; ix != 4; ix++)
      {
        value <<= 8;
        value |= buffer[ix];
*************** gcov_read_unsigned (file, value_p)
*** 413,436 ****
    return 0;
  }
  
! /* Read *VALUE_P from coverage file 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_type value = 0;
    unsigned ix;
!   unsigned char buffer[8];
  
!   if (da_file_read (buffer, 1, sizeof (buffer), file) != sizeof (buffer))
      return 1;
!   for (ix = sizeof (value); ix < sizeof (buffer); ix++)
      if (buffer[ix])
        return 1;
!   for (ix = 0; ix != sizeof (buffer); ix++)
      {
        value <<= 8;
        value |= buffer[ix];
--- 649,670 ----
    return 0;
  }
  
! /* Read *VALUE_P from coverage file.  Return nonzero if failed
     due to file i/o error, or range error.  */
  
  static int
! gcov_read_counter (gcov_type *value_p)
  {
    gcov_type value = 0;
    unsigned ix;
!   const unsigned char *buffer = gcov_read_bytes (8);
  
!   if (!buffer)
      return 1;
!   for (ix = sizeof (value); ix < 8; ix++)
      if (buffer[ix])
        return 1;
!   for (ix = 0; ix != 8; ix++)
      {
        value <<= 8;
        value |= buffer[ix];
*************** gcov_read_counter (file, value_p)
*** 440,816 ****
    return value < 0;
  }
  
! #if !IN_LIBGCC2
  
! /* 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.  */
  
  static int
! gcov_read_string (file, string_p, length_p)
!      FILE *file;
!      char **string_p;
!      unsigned *length_p;
  {
    unsigned length;
  
!   if (gcov_read_unsigned (file, &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;
  
  }
  
! #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;
! }
  
  #define GCOV_SUMMARY_LENGTH 44
  static int
! gcov_read_summary (da_file, summary)
!      FILE *da_file;
!      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));
! }
! 
! #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
! 
! #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;
  {
! #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;
  }
  
! /* 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;
!     }
! 
!   actual_da_file = 0;
    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;
! }
  
! /* Tests whether we have reached end of .da file.  */
! static int
! da_file_eof ()
  {
!   return actual_da_file_position == actual_da_file_length;
  }
  
! /* 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;
! 
!   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 ();
    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;
! }
! 
! /* 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;
  {
!   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;
  }
  
! /* 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;
  {
!   return fwrite (data, elts, len, file);
  }
  
! static size_t
! da_file_read (data, elts, len, file)
!      void *data;
!      size_t elts;
!      size_t len;
!      FILE *file;
  {
!   return fread (data, elts, len, file);
  }
  
! static unsigned long
! da_file_position (file)
!      FILE *file;
  {
!   return ftell (file);
  }
  
! static int
! da_file_seek (file, pos, whence)
!      FILE *file;
!      long pos;
!      int whence;
  {
!   return fseek (file, pos, whence);
  }
! #endif
! 
  #endif /* GCC_GCOV_IO_H */
--- 674,812 ----
    return value < 0;
  }
  
! #if !IN_LIBGCOV
  
! /* 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 (char **string_p)
  {
    unsigned length;
+   const unsigned char *buffer;
  
!   if (gcov_read_unsigned (&length))
      return 1;
  
    free (*string_p);
    *string_p = NULL;
    if (!length)
      return 0;
  
    length += 4 - (length & 3);
!   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_LIBGCOV */
  
  #define GCOV_SUMMARY_LENGTH 44
  static int
! gcov_read_summary (struct gcov_summary *summary)
  {
!   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));
! }
  
! /* Save the current position in the gcov file.  */
  
! static inline unsigned long
! gcov_save_position (void)
! {
!   return gcov_position;
  }
  
! /* Reset to a known position.  BASE should have been obtained from
!    gcov_save_position, LENGTH should be a record length, or zero.  */
  
! static inline int
! gcov_resync (unsigned long base, unsigned length)
! {
!   if (gcov_buffer)
!     gcov_position = base + length;
    return 0;
  }
  
! /* Move to the end of the gcov file.  */
  
! static inline unsigned long
! gcov_seek_end ()
  {
!   gcov_position = gcov_length;
!   return gcov_position;
  }
  
! /* Skip LENGTH bytes in the file.  */
  
! static inline int
! gcov_skip (unsigned length)
! {
!   if (gcov_length < gcov_position + length)
!     return 1;
!   gcov_position += length;
    return 0;
  }
  
! /* Skip a string of LENGTH bytes.  */
  
! static inline int
! gcov_skip_string (unsigned length)
  {
!   return gcov_skip (length + 4 - (length & 3));
  }
  
! /* Tests whether we have reached end of .da file.  */
! 
! static inline int
! gcov_eof ()
  {
!   return gcov_position == gcov_length;
  }
  
! /* Return non-zero if the error flag is set.  */
! 
! static inline int
! gcov_ok ()
  {
!   return gcov_file != 0 && !gcov_errored;
  }
  
! /* Set the error flag. */
! static inline int
! gcov_error ()
  {
!   int error = gcov_errored;
!   
!   gcov_errored = 1;
!   return error;
  }
  
! #if IN_GCOV > 0
! /* Return the modification time of the current gcov file.  */
! 
! static time_t
! gcov_time ()
  {
!   struct stat status;
!   
!   if (fstat (fileno (gcov_file), &status))
!     return 0;
!   else
!     return status.st_mtime;
  }
! #endif /* IN_GCOV */
  #endif /* GCC_GCOV_IO_H */
Index: gcov.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcov.c,v
retrieving revision 1.54
diff -c -3 -p -r1.54 gcov.c
*** gcov.c	31 Mar 2003 15:18:23 -0000	1.54
--- gcov.c	2 Apr 2003 15:13:25 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 51,57 ****
  
  #include <getopt.h>
  
! typedef HOST_WIDEST_INT gcov_type;
  #include "gcov-io.h"
  
  /* The bbg file is generated by -ftest-coverage option. The da file is
--- 51,57 ----
  
  #include <getopt.h>
  
! #define IN_GCOV 1
  #include "gcov-io.h"
  
  /* The bbg file is generated by -ftest-coverage option. The da file is
*************** find_source (file_name)
*** 704,711 ****
  static int
  read_graph_file ()
  {
-   FILE *file;
-   struct stat status;
    unsigned magic, version;
    unsigned current_tag = 0;
    unsigned tag;
--- 704,709 ----
*************** read_graph_file ()
*** 713,734 ****
    source_t *src = NULL;
    unsigned ix;
  
!   file = fopen (bbg_file_name, "rb");
!   if (!file)
      {
        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)
      {
        fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
!       fclose (file);
        return 1;
      }
  
!   if (gcov_read_unsigned (file, &version) || version != GCOV_VERSION)
      {
        char v[4], e[4];
  
--- 711,730 ----
    source_t *src = NULL;
    unsigned ix;
  
!   if (!gcov_open (bbg_file_name, 1))
      {
        fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
        return 1;
      }
!   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);
!       gcov_close ();
        return 1;
      }
  
!   if (gcov_read_unsigned (&version) || version != GCOV_VERSION)
      {
        char v[4], e[4];
  
*************** read_graph_file ()
*** 743,757 ****
  	       bbg_file_name, v, e);
      }
    
!   while (!gcov_read_unsigned (file, &tag))
      {
        unsigned length;
        long base;
  
!       if (gcov_read_unsigned (file, &length))
  	goto corrupt;
  
!       base = gcov_save_position (file);
  
        if (tag == GCOV_TAG_FUNCTION)
  	{
--- 739,753 ----
  	       bbg_file_name, v, e);
      }
    
!   while (!gcov_read_unsigned (&tag))
      {
        unsigned length;
        long base;
  
!       if (gcov_read_unsigned (&length))
  	goto corrupt;
  
!       base = gcov_save_position ();
  
        if (tag == GCOV_TAG_FUNCTION)
  	{
*************** read_graph_file ()
*** 761,770 ****
  	  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))
  	    goto corrupt;
  	  src = find_source (function_file);
  	  fn = (function_t *)xcalloc (1, sizeof (function_t));
--- 757,766 ----
  	  source_t *src;
  	  function_t *probe, *prev;
  
! 	  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));
*************** read_graph_file ()
*** 808,814 ****
  		{
  		  unsigned flags;
  		  
! 		  if (gcov_read_unsigned (file, &flags))
  		    goto corrupt;
  		  fn->blocks[ix].flags = flags;
  		}
--- 804,810 ----
  		{
  		  unsigned flags;
  		  
! 		  if (gcov_read_unsigned (&flags))
  		    goto corrupt;
  		  fn->blocks[ix].flags = flags;
  		}
*************** read_graph_file ()
*** 820,826 ****
  	  unsigned num_dests = (length - 4) / 8;
  	  unsigned dest, flags;
  
! 	  if (gcov_read_unsigned (file, &src)
  	      || src >= fn->num_blocks
  	      || fn->blocks[src].succ)
  	    goto corrupt;
--- 816,822 ----
  	  unsigned num_dests = (length - 4) / 8;
  	  unsigned dest, flags;
  
! 	  if (gcov_read_unsigned (&src)
  	      || src >= fn->num_blocks
  	      || fn->blocks[src].succ)
  	    goto corrupt;
*************** read_graph_file ()
*** 829,836 ****
  	    {
  	      struct arc_info *arc;
  	      
! 	      if (gcov_read_unsigned (file, &dest)
! 		  || gcov_read_unsigned (file, &flags)
  		  || dest >= fn->num_blocks)
  		goto corrupt;
  	      arc = (arc_t *) xcalloc (1, sizeof (arc_t));
--- 825,832 ----
  	    {
  	      struct arc_info *arc;
  	      
! 	      if (gcov_read_unsigned (&dest)
! 		  || gcov_read_unsigned (&flags)
  		  || dest >= fn->num_blocks)
  		goto corrupt;
  	      arc = (arc_t *) xcalloc (1, sizeof (arc_t));
*************** read_graph_file ()
*** 881,887 ****
  	  unsigned *line_nos
  	    = (unsigned *)xcalloc ((length - 4) / 4, sizeof (unsigned));
  
! 	  if (gcov_read_unsigned (file, &blockno)
  	      || blockno >= fn->num_blocks
  	      || fn->blocks[blockno].u.line.encoding)
  	    goto corrupt;
--- 877,883 ----
  	  unsigned *line_nos
  	    = (unsigned *)xcalloc ((length - 4) / 4, sizeof (unsigned));
  
! 	  if (gcov_read_unsigned (&blockno)
  	      || blockno >= fn->num_blocks
  	      || fn->blocks[blockno].u.line.encoding)
  	    goto corrupt;
*************** read_graph_file ()
*** 890,896 ****
  	    {
  	      unsigned lineno;
  	      
! 	      if (gcov_read_unsigned (file, &lineno))
  		goto corrupt;
  	      if (lineno)
  		{
--- 886,892 ----
  	    {
  	      unsigned lineno;
  	      
! 	      if (gcov_read_unsigned (&lineno))
  		goto corrupt;
  	      if (lineno)
  		{
*************** read_graph_file ()
*** 907,913 ****
  		{
  		  char *file_name = NULL;
  		  
! 		  if (gcov_read_string (file, &file_name, NULL))
  		    goto corrupt;
  		  if (!file_name)
  		    break;
--- 903,909 ----
  		{
  		  char *file_name = NULL;
  		  
! 		  if (gcov_read_string (&file_name))
  		    goto corrupt;
  		  if (!file_name)
  		    break;
*************** read_graph_file ()
*** 926,940 ****
  	  fn = NULL;
  	  current_tag = 0;
  	}
!       if (gcov_resync (file, base, length))
  	{
  	corrupt:;
  	  fnotice (stderr, "%s:corrupted\n", bbg_file_name);
! 	  fclose (file);
  	  return 1;
  	}
      }
!   fclose (file);
    
    /* We built everything backwards, so nreverse them all */
    
--- 922,936 ----
  	  fn = NULL;
  	  current_tag = 0;
  	}
!       if (gcov_resync (base, length))
  	{
  	corrupt:;
  	  fnotice (stderr, "%s:corrupted\n", bbg_file_name);
! 	  gcov_close ();
  	  return 1;
  	}
      }
!   gcov_close ();
    
    /* We built everything backwards, so nreverse them all */
    
*************** read_graph_file ()
*** 995,1021 ****
  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)
      {
        fnotice (stderr, "%s:cannot open data file\n", da_file_name);
        return 1;
      }
!   if (gcov_read_unsigned (file, &magic) || magic != GCOV_DATA_MAGIC)
      {
        fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
      cleanup:;
        free (function_name_buffer);
!       fclose (file);
        return 1;
      }
!   if (gcov_read_unsigned (file, &version) || version != GCOV_VERSION)
      {
        char v[4], e[4];
        
--- 991,1015 ----
  static int
  read_count_file ()
  {
    unsigned ix;
    char *function_name_buffer = NULL;
    unsigned magic, version;
    function_t *fn = NULL;
  
!   if (!gcov_open (da_file_name, 1))
      {
        fnotice (stderr, "%s:cannot open data file\n", da_file_name);
        return 1;
      }
!   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);
!       gcov_close ();
        return 1;
      }
!   if (gcov_read_unsigned (&version) || version != GCOV_VERSION)
      {
        char v[4], e[4];
        
*************** read_count_file ()
*** 1034,1065 ****
        unsigned tag, length;
        long base;
        
!       if (gcov_read_unsigned (file, &tag)
! 	  || gcov_read_unsigned (file, &length))
  	{
! 	  if (feof (file))
  	    break;
  	  
  	corrupt:;
  	  fnotice (stderr, "%s:corrupted\n", da_file_name);
  	  goto cleanup;
  	}
!       base = gcov_save_position (file);
        if (tag == GCOV_TAG_OBJECT_SUMMARY)
  	{
! 	  if (gcov_read_summary (file, &object_summary))
  	    goto corrupt;
  	}
        else if (tag == GCOV_TAG_PROGRAM_SUMMARY
  	       || tag == GCOV_TAG_INCORRECT_SUMMARY)
! 	program_count++;
        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))
  	    goto corrupt;
  
  	  for (fn = fn ? fn->next : NULL; ; fn = fn->next)
--- 1028,1062 ----
        unsigned tag, length;
        long base;
        
!       if (gcov_read_unsigned (&tag)
! 	  || gcov_read_unsigned (&length))
  	{
! 	  if (gcov_eof ())
  	    break;
  	  
  	corrupt:;
  	  fnotice (stderr, "%s:corrupted\n", da_file_name);
  	  goto cleanup;
  	}
!       base = gcov_save_position ();
        if (tag == GCOV_TAG_OBJECT_SUMMARY)
  	{
! 	  if (gcov_read_summary (&object_summary))
  	    goto corrupt;
  	}
        else if (tag == GCOV_TAG_PROGRAM_SUMMARY
  	       || tag == GCOV_TAG_INCORRECT_SUMMARY)
! 	{
! 	  program_count++;
! 	  gcov_resync (base, length);
! 	}
        else if (tag == GCOV_TAG_FUNCTION)
  	{
  	  unsigned checksum;
  	  struct function_info *fn_n = functions;
  	  
! 	  if (gcov_read_string (&function_name_buffer)
! 	      || gcov_read_unsigned (&checksum))
  	    goto corrupt;
  
  	  for (fn = fn ? fn->next : NULL; ; fn = fn->next)
*************** read_count_file ()
*** 1101,1115 ****
  	    {
  	      gcov_type count;
  	      
! 	      if (gcov_read_counter (file, &count))
  		goto corrupt;
  	      fn->counts[ix] += count;
  	    }
  	}
!       gcov_resync (file, base, length);
      }
  
!   fclose (file);
    free (function_name_buffer);
    return 0;
  }
--- 1098,1113 ----
  	    {
  	      gcov_type count;
  	      
! 	      if (gcov_read_counter (&count))
  		goto corrupt;
  	      fn->counts[ix] += count;
  	    }
  	}
!       else
! 	gcov_resync (base, length);
      }
  
!   gcov_close ();
    free (function_name_buffer);
    return 0;
  }
Index: libgcov.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/libgcov.c,v
retrieving revision 1.4
diff -c -3 -p -r1.4 libgcov.c
*** libgcov.c	27 Mar 2003 23:52:02 -0000	1.4
--- libgcov.c	2 Apr 2003 15:13:28 -0000
*************** void __gcov_flush (void) { }
*** 57,62 ****
--- 57,63 ----
  #include <fcntl.h>
  #include <errno.h>
  #endif
+ #define IN_LIBGCOV 1
  #include "gcov-io.h"
  
  /* Chain of per-object gcov structures.  */
*************** gcov_exit (void)
*** 102,117 ****
    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;
    
--- 103,108 ----
*************** gcov_exit (void)
*** 119,125 ****
      {
        struct gcov_summary object;
        struct gcov_summary local_prg;
!       int merging = 0;
        long base;
        const struct function_info *fn_info;
        gcov_type **counters;
--- 110,116 ----
      {
        struct gcov_summary object;
        struct gcov_summary local_prg;
!       int merging;
        long base;
        const struct function_info *fn_info;
        gcov_type **counters;
*************** gcov_exit (void)
*** 164,190 ****
        memset (&object, 0, sizeof (object));
        
        /* Open for modification */
!       if (!da_file_open (ptr->filename, &merging))
  	{
  	  fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
  	  ptr->filename = 0;
  	  continue;
  	}
! 
!       if (merging)
  	{
  	  /* Merge data from file.  */
! 	      
! 	  if (gcov_read_unsigned (0, &tag) || tag != GCOV_DATA_MAGIC)
  	    {
  	      fprintf (stderr, "profiling:%s:Not a gcov data file\n",
  		       ptr->filename);
  	    read_fatal:;
! 	      da_file_close ();
  	      ptr->filename = 0;
  	      continue;
  	    }
! 	  if (gcov_read_unsigned (0, &length) || length != GCOV_VERSION)
  	    {
  	      gcov_version_mismatch (ptr, length);
  	      goto read_fatal;
--- 155,182 ----
        memset (&object, 0, sizeof (object));
        
        /* Open for modification */
!       merging = gcov_open (ptr->filename, 0);
!       
!       if (!merging)
  	{
  	  fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
  	  ptr->filename = 0;
  	  continue;
  	}
!       
!       if (merging > 0)
  	{
  	  /* Merge data from file.  */
! 	  if (gcov_read_unsigned (&tag) || tag != GCOV_DATA_MAGIC)
  	    {
  	      fprintf (stderr, "profiling:%s:Not a gcov data file\n",
  		       ptr->filename);
  	    read_fatal:;
! 	      gcov_close ();
  	      ptr->filename = 0;
  	      continue;
  	    }
! 	  if (gcov_read_unsigned (&length) || length != GCOV_VERSION)
  	    {
  	      gcov_version_mismatch (ptr, length);
  	      goto read_fatal;
*************** gcov_exit (void)
*** 194,201 ****
  	  for (ix = ptr->n_functions, fn_info = ptr->functions;
  	       ix--; fn_info++)
  	    {
! 	      if (gcov_read_unsigned (0, &tag)
! 		  || gcov_read_unsigned (0, &length))
  		{
  		read_error:;
  		  fprintf (stderr, "profiling:%s:Error merging\n",
--- 186,192 ----
  	  for (ix = ptr->n_functions, fn_info = ptr->functions;
  	       ix--; fn_info++)
  	    {
! 	      if (gcov_read_unsigned (&tag) || gcov_read_unsigned (&length))
  		{
  		read_error:;
  		  fprintf (stderr, "profiling:%s:Error merging\n",
*************** gcov_exit (void)
*** 212,220 ****
  		  goto read_fatal;
  		}
  
! 	      if (gcov_read_unsigned (0, &flength)
! 		  || gcov_skip_string (0, flength)
! 		  || gcov_read_unsigned (0, &checksum))
  		goto read_error;
  	      if (flength != strlen (fn_info->name)
  		  || checksum != fn_info->checksum)
--- 203,211 ----
  		  goto read_fatal;
  		}
  
! 	      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)
*************** gcov_exit (void)
*** 227,234 ****
  		{
  		  unsigned n_counters;
  
! 		  if (gcov_read_unsigned (0, &tag)
! 		      || gcov_read_unsigned (0, &length))
  		    goto read_error;
  		  for (sect_index = 0;
  		       sect_index < ptr->n_counter_sections;
--- 218,225 ----
  		{
  		  unsigned n_counters;
  
! 		  if (gcov_read_unsigned (&tag)
! 		      || gcov_read_unsigned (&length))
  		    goto read_error;
  		  for (sect_index = 0;
  		       sect_index < ptr->n_counter_sections;
*************** gcov_exit (void)
*** 244,250 ****
  		    goto read_mismatch;
  		 
  		  for (jx = 0; jx < n_counters; jx++)
! 	    	    if (gcov_read_counter (0, &count))
      		      goto read_error;
  		    else
  		      counters[sect_index][jx] += count;
--- 235,241 ----
  		    goto read_mismatch;
  		 
  		  for (jx = 0; jx < n_counters; jx++)
! 	    	    if (gcov_read_counter (&count))
      		      goto read_error;
  		    else
  		      counters[sect_index][jx] += count;
*************** gcov_exit (void)
*** 253,275 ****
  	    }
  
  	  /* Check object summary */
! 	  if (gcov_read_unsigned (0, &tag)
! 	      || gcov_read_unsigned (0, &length))
  	    goto read_error;
  	  if (tag != GCOV_TAG_OBJECT_SUMMARY)
  	    goto read_mismatch;
! 	  if (gcov_read_summary (0, &object))
  	    goto read_error;
  
  	  /* Check program summary */
  	  while (1)
  	    {
! 	      long base = da_file_position (0);
  	      
! 	      if (gcov_read_unsigned (0, &tag)
! 		  || gcov_read_unsigned (0, &length))
  		{
! 		  if (da_file_eof ())
  		    break;
  		  goto read_error;
  		}
--- 244,265 ----
  	    }
  
  	  /* Check object summary */
! 	  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 (&object))
  	    goto read_error;
  
  	  /* Check program summary */
  	  while (1)
  	    {
! 	      long base = gcov_save_position ();
  	      
! 	      if (gcov_read_unsigned (&tag)
! 		  || gcov_read_unsigned (&length))
  		{
! 		  if (gcov_eof ())
  		    break;
  		  goto read_error;
  		}
*************** gcov_exit (void)
*** 277,283 ****
  		  && tag != GCOV_TAG_PLACEHOLDER_SUMMARY
  		  && tag != GCOV_TAG_INCORRECT_SUMMARY)
  		goto read_mismatch;
! 	      if (gcov_read_summary (0, &local_prg))
  		goto read_error;
  	      if (local_prg.checksum != program.checksum)
  		continue;
--- 267,273 ----
  		  && tag != GCOV_TAG_PLACEHOLDER_SUMMARY
  		  && tag != GCOV_TAG_INCORRECT_SUMMARY)
  		goto read_mismatch;
! 	      if (gcov_read_summary (&local_prg))
  		goto read_error;
  	      if (local_prg.checksum != program.checksum)
  		continue;
*************** gcov_exit (void)
*** 288,294 ****
  			   ptr->filename);
  		  goto read_fatal;
  		}
! 	      merging = -1;
  	      if (tag != GCOV_TAG_PROGRAM_SUMMARY)
  		break;
  	      
--- 278,284 ----
  			   ptr->filename);
  		  goto read_fatal;
  		}
! 	      merging = 0;
  	      if (tag != GCOV_TAG_PROGRAM_SUMMARY)
  		break;
  	      
*************** gcov_exit (void)
*** 304,310 ****
  	      ptr->wkspc = base;
  	      break;
  	    }
! 	  da_file_seek (0, 0, SEEK_SET);
  	}
  
        object.runs++;
--- 294,300 ----
  	      ptr->wkspc = base;
  	      break;
  	    }
! 	  gcov_resync (0, 0);
  	}
  
        object.runs++;
*************** gcov_exit (void)
*** 316,327 ****
        
        /* Write out the data.  */
        if (/* magic */
! 	  gcov_write_unsigned (0, GCOV_DATA_MAGIC)
  	  /* version number */
! 	  || gcov_write_unsigned (0, GCOV_VERSION))
  	{
  	write_error:;
! 	  da_file_close ();
  	  fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
  	  ptr->filename = 0;
  	  continue;
--- 306,317 ----
        
        /* Write out the data.  */
        if (/* magic */
! 	  gcov_write_unsigned (GCOV_DATA_MAGIC)
  	  /* version number */
! 	  || gcov_write_unsigned (GCOV_VERSION))
  	{
  	write_error:;
! 	  gcov_close ();
  	  fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
  	  ptr->filename = 0;
  	  continue;
*************** gcov_exit (void)
*** 333,346 ****
        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))
  	      /* function name */
! 	      || gcov_write_string (0, fn_info->name,
! 				    strlen (fn_info->name))
  	      /* function checksum */
! 	      || gcov_write_unsigned (0, fn_info->checksum)
! 	      || gcov_write_length (0, base))
  	    goto write_error;
  
  	  /* counters.  */
--- 323,335 ----
        for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
  	{
  	  /* Announce function.  */
! 	  if (gcov_write_unsigned (GCOV_TAG_FUNCTION)
! 	      || !(base = gcov_reserve_length ())
  	      /* function name */
! 	      || gcov_write_string (fn_info->name)
  	      /* function checksum */
! 	      || gcov_write_unsigned (fn_info->checksum)
! 	      || gcov_write_length (base))
  	    goto write_error;
  
  	  /* counters.  */
*************** gcov_exit (void)
*** 357,364 ****
  	      if (sect_index == ptr->n_counter_sections)
  		abort ();
  
! 	      if (gcov_write_unsigned (0, tag)
! 		  || !(base = gcov_reserve_length (0)))
  		goto write_error;
  	  
      	      for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
--- 346,353 ----
  	      if (sect_index == ptr->n_counter_sections)
  		abort ();
  
! 	      if (gcov_write_unsigned (tag)
! 		  || !(base = gcov_reserve_length ()))
  		goto write_error;
  	  
      	      for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
*************** gcov_exit (void)
*** 371,411 ****
  		      if (object.arc_max_sum < count)
  			object.arc_max_sum = count;
  		    }
! 		  if (gcov_write_counter (0, count))
  		    goto write_error; /* RIP Edsger Dijkstra */
  		}
! 	      if (gcov_write_length (0, base))
  		goto write_error;
  	    }
  	}
  
        /* Object file summary.  */
!       if (gcov_write_summary (0, GCOV_TAG_OBJECT_SUMMARY, &object))
  	goto write_error;
  
!       if (merging >= 0)
  	{
! 	  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,
  				  &program))
  	    goto write_error;
  	}
        else if (ptr->wkspc)
  	{
  	  /* Zap trailing program summary */
! 	  if (da_file_seek (0, ptr->wkspc, SEEK_SET))
  	    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))
  	    goto write_error;
  	}
  
!       if (da_file_close ())
  	{
  	  fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
  	  ptr->filename = 0;
--- 360,398 ----
  		      if (object.arc_max_sum < count)
  			object.arc_max_sum = count;
  		    }
! 		  if (gcov_write_counter (count))
  		    goto write_error; /* RIP Edsger Dijkstra */
  		}
! 	      if (gcov_write_length (base))
  		goto write_error;
  	    }
  	}
  
        /* Object file summary.  */
!       if (gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object))
  	goto write_error;
  
!       if (merging)
  	{
! 	  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 (gcov_resync (ptr->wkspc, 0))
  	    goto write_error;
  	  if (!local_prg.runs)
  	    ptr->wkspc = 0;
! 	  if (gcov_write_unsigned (local_prg.runs
! 				   ? GCOV_TAG_PLACEHOLDER_SUMMARY
! 				   : GCOV_TAG_INCORRECT_SUMMARY))
  	    goto write_error;
  	}
  
!       if (gcov_close ())
  	{
  	  fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
  	  ptr->filename = 0;
*************** gcov_exit (void)
*** 434,458 ****
    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)
  	  {
  	    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))
   	  fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
! 	if (fclose (da_file))
  	  fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
        }
  }
--- 421,436 ----
    for (ptr = gcov_list; ptr; ptr = ptr->next)
      if (ptr->filename && ptr->wkspc)
        {
! 	if (!gcov_open (ptr->filename, 1))
  	  {
  	    fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
  	    continue;
  	  }
  	
! 	if (gcov_resync (ptr->wkspc, 0)
!  	    || gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program))
   	  fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
! 	if (gcov_close ())
  	  fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
        }
  }
Index: loop-init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop-init.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 loop-init.c
*** loop-init.c	8 Feb 2003 14:29:00 -0000	1.2
--- loop-init.c	2 Apr 2003 15:13:28 -0000
*************** Software Foundation, 59 Temple Place - S
*** 27,33 ****
  #include "basic-block.h"
  #include "cfgloop.h"
  #include "cfglayout.h"
- #include "gcov-io.h"
  #include "profile.h"
  
  /* Initialize loop optimizer.  */
--- 27,32 ----
Index: profile.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/profile.c,v
retrieving revision 1.110
diff -c -3 -p -r1.110 profile.c
*** profile.c	31 Mar 2003 15:18:23 -0000	1.110
--- profile.c	2 Apr 2003 15:13:30 -0000
*************** struct function_list
*** 101,106 ****
--- 101,127 ----
    				/* 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;
  
*************** struct profile_info profile_info;
*** 119,130 ****
  
  /* 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.  */
--- 140,149 ----
*************** static void find_spanning_tree PARAMS ((
*** 149,159 ****
  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 gcov_type * get_exec_counts PARAMS ((void));
  static unsigned compute_checksum PARAMS ((void));
  static basic_block find_group PARAMS ((basic_block));
--- 168,177 ----
  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_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));
*************** instrument_edges (el)
*** 218,323 ****
      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)
       const void *of;
  {
!   const struct da_index_entry *entry = of;
  
    return htab_hash_string (entry->function_name) ^ entry->section;
  }
  
  static int
! htab_counts_index_eq (of1, of2)
       const void *of1;
       const void *of2;
  {
!   const struct da_index_entry *entry1 = of1;
!   const struct da_index_entry *entry2 = of2;
  
    return !strcmp (entry1->function_name, entry2->function_name)
! 	  && entry1->section == entry2->section;
  }
  
  static void
! htab_counts_index_del (what)
!      void *what;
  {
!   struct da_index_entry *entry = what;
!   unsigned i;
  
-   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);
  }
  
! static char *counts_file_name;
! static htab_t counts_file_index = 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 ()
  {
    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)
      {
!       warning ("`%s' is not a gcov data file", da_file_name);
!       goto cleanup;
      }
!   if (gcov_read_unsigned (da_file, &version) || version != GCOV_VERSION)
      {
        char v[4], e[4];
        magic = GCOV_VERSION;
--- 236,296 ----
      fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
  }
  
  static hashval_t
! htab_counts_entry_hash (of)
       const void *of;
  {
!   const counts_entry_t *entry = of;
  
    return htab_hash_string (entry->function_name) ^ entry->section;
  }
  
  static int
! htab_counts_entry_eq (of1, of2)
       const void *of1;
       const void *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;
  }
  
  static void
! htab_counts_entry_del (of)
!      void *of;
  {
!   counts_entry_t *entry = of;
  
    free (entry->function_name);
!   free (entry->counts);
    free (entry);
  }
  
! static htab_t counts_hash = NULL;
  
  static void
! read_counts_file (const char *name)
  {
    char *function_name_buffer = NULL;
    unsigned magic, version, ix, checksum;
!   counts_entry_t *summaried = NULL;
!   unsigned seen_summary = 0;
!   
!   if (!gcov_open (name, 1))
!     {
!       warning ("file %s not found, execution counts assumed to be zero", name);
!       return;
!     }
!   
!   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;
*************** index_counts_file ()
*** 327,423 ****
  	  v[ix] = version;
  	  e[ix] = magic;
  	}
!       warning ("`%s' is version `%.4s', expected version `%.4s'",
! 	       da_file_name, v, e);
!       goto cleanup;
      }
    
    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))
  	{
! 	  if (feof (da_file))
  	    break;
  	corrupt:;
! 	  warning ("`%s' is corrupted", da_file_name);
! 	  goto cleanup;
  	}
        if (tag == GCOV_TAG_FUNCTION)
  	{
! 	  if (gcov_read_string (da_file, &function_name_buffer, NULL)
! 	      || gcov_read_unsigned (da_file, &checksum))
  	    goto corrupt;
! 	  continue;
  	}
!       if (tag == GCOV_TAG_PROGRAM_SUMMARY)
  	{
! 	  if (length != GCOV_SUMMARY_LENGTH)
  	    goto corrupt;
  
! 	  if (summary)
! 	    *summary = offset;
! 	  summary = NULL;
  	}
!       else
  	{
! 	  if (function_name_buffer)
  	    {
! 	      struct da_index_entry **slot, elt;
! 	      elt.function_name = function_name_buffer;
! 	      elt.section = tag;
! 
! 	      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;
  	    }
  	}
!       if (gcov_skip (da_file, length))
! 	goto corrupt;
      }
  
    free (function_name_buffer);
! 
!   return 1;
! 
! cleanup:
!   cleanup_counts_index (1);
!   if (function_name_buffer)
!     free (function_name_buffer);
!   return 0;
  }
  
  /* Computes hybrid profile for all matching entries in da_file.
--- 300,420 ----
  	  v[ix] = version;
  	  e[ix] = magic;
  	}
!       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 ();
!       if (gcov_read_unsigned (&tag) || gcov_read_unsigned (&length))
  	{
! 	  if (gcov_eof ())
  	    break;
  	corrupt:;
! 	  warning ("`%s' is corrupted", name);
! 	cleanup:
! 	  htab_delete (counts_hash);
! 	  break;
  	}
        if (tag == GCOV_TAG_FUNCTION)
  	{
! 	  if (gcov_read_string (&function_name_buffer)
! 	      || gcov_read_unsigned (&checksum))
  	    goto corrupt;
! 	  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;
! 	    }
  	}
!       else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
  	{
! 	  counts_entry_t *entry;
! 	  struct gcov_summary summary;
! 	  
! 	  if (length != GCOV_SUMMARY_LENGTH
! 	      || gcov_read_summary (&summary))
  	    goto corrupt;
  
! 	  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 if (GCOV_TAG_IS_SUBTAG (GCOV_TAG_FUNCTION, tag)
! 	       && function_name_buffer)
  	{
! 	  counts_entry_t **slot, *entry, elt;
! 	  unsigned n_counts = length / 8;
! 	  unsigned ix;
! 	  gcov_type count;
! 
! 	  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;
  	    }
  	}
!       else
! 	if (gcov_skip (length))
! 	  goto corrupt;
      }
  
    free (function_name_buffer);
!   gcov_close ();
  }
  
  /* Computes hybrid profile for all matching entries in da_file.
*************** get_exec_counts ()
*** 428,453 ****
  {
    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;
  
    profile_info.max_counter_in_program = 0;
    profile_info.count_profiles_merged = 0;
  
!   /* No .da file, no execution counts.  */
!   if (!da_file)
      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;
--- 425,441 ----
  {
    unsigned num_edges = 0;
    basic_block bb;
    const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
!   counts_entry_t *entry, elt;
  
    profile_info.max_counter_in_program = 0;
    profile_info.count_profiles_merged = 0;
  
!   /* No hash table, no counts. */
!   if (!counts_hash)
      return NULL;
  
    /* Count the edges to be (possibly) instrumented.  */
    FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
      {
        edge e;
*************** get_exec_counts ()
*** 456,536 ****
  	  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);
    if (!entry)
      {
        warning ("No profile for function '%s' found.", name);
!       goto cleanup;
      }
    
!   if (entry->checksum != profile_info.current_function_cfg_checksum)
      {
        warning ("profile mismatch for `%s'", current_function_name);
!       goto cleanup;
      }
  
!   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;
! 	}
!     }
  
    if (rtl_dump_file)
      {
--- 444,467 ----
  	  num_edges++;
      }
  
!   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);
!       return NULL;
      }
    
!   if (entry->checksum != profile_info.current_function_cfg_checksum
!       || num_edges != entry->n_counts)
      {
        warning ("profile mismatch for `%s'", current_function_name);
!       return NULL;
      }
  
!   profile_info.count_profiles_merged = entry->merged;
!   profile_info.max_counter_in_program = entry->max_counter_sum;
  
    if (rtl_dump_file)
      {
*************** get_exec_counts ()
*** 539,550 ****
  	      (int)profile_info.max_counter_in_program);
      }
  
!   return profile;
! 
! cleanup:;
!   free (profile);
!   cleanup_counts_index (1);
!   return NULL;
  }
  
  
--- 470,476 ----
  	      (int)profile_info.max_counter_in_program);
      }
  
!   return entry->counts;
  }
  
  
*************** compute_branch_probabilities ()
*** 858,865 ****
      }
  
    free_aux_for_blocks ();
-   if (exec_counts)
-     free (exec_counts);
    find_counters_section (GCOV_TAG_ARC_COUNTS)->present = 1;
  }
  
--- 784,789 ----
*************** branch_prob ()
*** 1083,1114 ****
       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)
      {
        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))
  	goto bbg_error;
  
        /* Basic block flags */
!       if (gcov_write_unsigned (bbg_file, GCOV_TAG_BLOCKS)
! 	  || !(offset = gcov_reserve_length (bbg_file)))
  	goto bbg_error;
        for (i = 0; i != (unsigned) (n_basic_blocks + 2); i++)
! 	if (gcov_write_unsigned (bbg_file, 0))
  	  goto bbg_error;
!       if (gcov_write_length (bbg_file, offset))
  	goto bbg_error;
        
        /* Arcs */
--- 1007,1036 ----
       edge output the source and target basic block numbers.
       NOTE: The format of this file must be compatible with gcov.  */
  
!   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 (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 (GCOV_TAG_BLOCKS)
! 	  || !(offset = gcov_reserve_length ()))
  	goto bbg_error;
        for (i = 0; i != (unsigned) (n_basic_blocks + 2); i++)
! 	if (gcov_write_unsigned (0))
  	  goto bbg_error;
!       if (gcov_write_length (offset))
  	goto bbg_error;
        
        /* Arcs */
*************** branch_prob ()
*** 1116,1124 ****
  	{
  	  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)))
  	    goto bbg_error;
  
  	  for (e = bb->succ; e; e = e->succ_next)
--- 1038,1046 ----
  	{
  	  edge e;
  
! 	  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)
*************** branch_prob ()
*** 1135,1148 ****
  		  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))
  		    goto bbg_error;
  	        }
  	    }
  
! 	  if (gcov_write_length (bbg_file, offset))
  	    goto bbg_error;
  	}
  
--- 1057,1069 ----
  		  if (e->flags & EDGE_FALLTHRU)
  		    flag_bits |= GCOV_ARC_FALLTHROUGH;
  
! 		  if (gcov_write_unsigned (BB_TO_GCOV_INDEX (e->dest))
! 		      || gcov_write_unsigned (flag_bits))
  		    goto bbg_error;
  	        }
  	    }
  
! 	  if (gcov_write_length (offset))
  	    goto bbg_error;
  	}
  
*************** branch_prob ()
*** 1185,1194 ****
  		      {
  			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)))
  			  goto bbg_error;
  			/* If this is a new source file, then output
  			   the file's name to the .bb file.  */
--- 1106,1115 ----
  		      {
  			if (offset)
  			  /*NOP*/;
! 			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.  */
*************** branch_prob ()
*** 1197,1208 ****
  				       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)))
  			      goto bbg_error;
  			  }
! 			if (gcov_write_unsigned (bbg_file, NOTE_LINE_NUMBER (insn)))
  			  goto bbg_error;
  		      }
  		  }
--- 1118,1128 ----
  				       prev_file_name))
  			  {
  			    prev_file_name = NOTE_SOURCE_FILE (insn);
! 			    if (gcov_write_unsigned (0)
! 				|| gcov_write_string (prev_file_name))
  			      goto bbg_error;
  			  }
! 			if (gcov_write_unsigned (NOTE_LINE_NUMBER (insn)))
  			  goto bbg_error;
  		      }
  		  }
*************** branch_prob ()
*** 1211,1224 ****
  
  	    if (offset)
  	      {
! 		if (gcov_write_unsigned (bbg_file, 0)
! 		    || gcov_write_string (bbg_file, NULL, 0)
! 		    || gcov_write_length (bbg_file, offset))
  		  {
  		  bbg_error:;
  		    warning ("error writing `%s'", bbg_file_name);
! 		    fclose (bbg_file);
! 		    bbg_file = NULL;
  		  }
  	      }
  	  }
--- 1131,1143 ----
  
  	    if (offset)
  	      {
! 		if (gcov_write_unsigned (0)
! 		    || gcov_write_string (NULL)
! 		    || gcov_write_length (offset))
  		  {
  		  bbg_error:;
  		    warning ("error writing `%s'", bbg_file_name);
! 		    gcov_error ();
  		  }
  	      }
  	  }
*************** init_branch_prob (filename)
*** 1395,1432 ****
    int len = strlen (filename);
    int i;
  
    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))
  	{
! 	  fclose (bbg_file);
! 	  fatal_io_error ("cannot write `%s'", bbg_file_name);
  	}
!     }
! 
!   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);
      }
  
    if (profile_arc_flag)
--- 1314,1340 ----
    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);
!       if (!gcov_open (bbg_file_name, -1))
  	{
! 	  error ("cannot open %s", bbg_file_name);
! 	  gcov_error ();
  	}
!       else if (gcov_write_unsigned (GCOV_GRAPH_MAGIC)
! 	       || gcov_write_unsigned (GCOV_VERSION))
! 	gcov_error ();
      }
  
    if (profile_arc_flag)
*************** end_branch_prob ()
*** 1459,1484 ****
  {
    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);
  #endif
! 	  fclose (bbg_file);
! 	}
!       else
! 	{
! 	  unlink (bbg_file_name);
! 	  unlink (da_file_name);
! 	}
      }
- 
-   if (da_file)
-     fclose (da_file);
  
    if (rtl_dump_file)
      {
--- 1367,1385 ----
  {
    if (flag_test_coverage)
      {
!       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
! 	unlink (da_file_name);
      }
  
    if (rtl_dump_file)
      {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]