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.

From-SVN: r65338
This commit is contained in:
Nathan Sidwell 2003-04-07 19:37:12 +00:00 committed by Nathan Sidwell
parent 5da702b196
commit 546d2adb91
7 changed files with 821 additions and 901 deletions

View File

@ -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

View File

@ -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);

View File

@ -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_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;
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
#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 /* !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
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
/* 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 (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);
}
/* Read *VALUE_P from coverage file FILE. Return nonzero if failed
/* 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 (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;
/* Save the current position in the gcov file. */
static inline unsigned long
gcov_save_position (void)
{
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;
return gcov_position;
}
/* Write changes to the .da file and close it. */
static int da_file_close ()
/* 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 (!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;
if (gcov_buffer)
gcov_position = base + length;
return 0;
}
/* Returns current position in .da file. */
static unsigned long
da_file_position (file)
FILE *file;
/* Move to the end of the gcov file. */
static inline unsigned long
gcov_seek_end ()
{
if (file)
return ftell (file);
return actual_da_file_position;
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 int
da_file_eof ()
static inline int
gcov_eof ()
{
return actual_da_file_position == actual_da_file_length;
return gcov_position == gcov_length;
}
/* Change position in the .da file. */
static int
da_file_seek (file, pos, whence)
FILE *file;
long pos;
int whence;
/* Return non-zero if the error flag is set. */
static inline int
gcov_ok ()
{
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;
return gcov_file != 0 && !gcov_errored;
}
/* 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;
/* Set the error flag. */
static inline int
gcov_error ()
{
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;
int error = gcov_errored;
while (len--)
*dat++ = actual_da_file_buffer[actual_da_file_position++];
return l;
gcov_errored = 1;
return error;
}
/* 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);
}
#if IN_GCOV > 0
/* Return the modification time of the current gcov file. */
static size_t
da_file_read (data, elts, len, file)
void *data;
size_t elts;
size_t len;
FILE *file;
static time_t
gcov_time ()
{
return fread (data, elts, len, file);
struct stat status;
if (fstat (fileno (gcov_file), &status))
return 0;
else
return status.st_mtime;
}
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 /* IN_GCOV */
#endif /* GCC_GCOV_IO_H */

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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. */

View File

@ -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 (tag == GCOV_TAG_PROGRAM_SUMMARY)
{
if (length != GCOV_SUMMARY_LENGTH)
goto corrupt;
if (summary)
*summary = offset;
summary = NULL;
}
else
{
if (function_name_buffer)
if (seen_summary)
{
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)
/* 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)
{
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);
chain = entry->chain;
entry->max_counter_sum += entry->max_counter;
entry->chain = NULL;
}
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;
summaried = NULL;
seen_summary = 0;
}
}
if (gcov_skip (da_file, length))
goto corrupt;
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);
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");