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