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:
parent
5da702b196
commit
546d2adb91
|
@ -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
|
||||
|
|
101
gcc/gcov-dump.c
101
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);
|
||||
|
||||
|
|
844
gcc/gcov-io.h
844
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_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 */
|
||||
|
|
86
gcc/gcov.c
86
gcc/gcov.c
|
@ -51,7 +51,7 @@ Boston, MA 02111-1307, USA. */
|
|||
|
||||
#include <getopt.h>
|
||||
|
||||
typedef HOST_WIDEST_INT gcov_type;
|
||||
#define IN_GCOV 1
|
||||
#include "gcov-io.h"
|
||||
|
||||
/* The bbg file is generated by -ftest-coverage option. The da file is
|
||||
|
@ -706,8 +706,6 @@ find_source (file_name)
|
|||
static int
|
||||
read_graph_file ()
|
||||
{
|
||||
FILE *file;
|
||||
struct stat status;
|
||||
unsigned magic, version;
|
||||
unsigned current_tag = 0;
|
||||
unsigned tag;
|
||||
|
@ -715,22 +713,20 @@ read_graph_file ()
|
|||
source_t *src = NULL;
|
||||
unsigned ix;
|
||||
|
||||
file = fopen (bbg_file_name, "rb");
|
||||
if (!file)
|
||||
if (!gcov_open (bbg_file_name, 1))
|
||||
{
|
||||
fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
|
||||
return 1;
|
||||
}
|
||||
if (!fstat (fileno (file), &status))
|
||||
bbg_file_time = status.st_mtime;
|
||||
if (gcov_read_unsigned (file, &magic) || magic != GCOV_GRAPH_MAGIC)
|
||||
bbg_file_time = gcov_time ();
|
||||
if (gcov_read_unsigned (&magic) || magic != GCOV_GRAPH_MAGIC)
|
||||
{
|
||||
fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
|
||||
fclose (file);
|
||||
gcov_close ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (gcov_read_unsigned (file, &version) || version != GCOV_VERSION)
|
||||
if (gcov_read_unsigned (&version) || version != GCOV_VERSION)
|
||||
{
|
||||
char v[4], e[4];
|
||||
|
||||
|
@ -745,15 +741,15 @@ read_graph_file ()
|
|||
bbg_file_name, v, e);
|
||||
}
|
||||
|
||||
while (!gcov_read_unsigned (file, &tag))
|
||||
while (!gcov_read_unsigned (&tag))
|
||||
{
|
||||
unsigned length;
|
||||
long base;
|
||||
|
||||
if (gcov_read_unsigned (file, &length))
|
||||
if (gcov_read_unsigned (&length))
|
||||
goto corrupt;
|
||||
|
||||
base = gcov_save_position (file);
|
||||
base = gcov_save_position ();
|
||||
|
||||
if (tag == GCOV_TAG_FUNCTION)
|
||||
{
|
||||
|
@ -763,10 +759,10 @@ read_graph_file ()
|
|||
source_t *src;
|
||||
function_t *probe, *prev;
|
||||
|
||||
if (gcov_read_string (file, &function_name, NULL)
|
||||
|| gcov_read_unsigned (file, &checksum)
|
||||
|| gcov_read_string (file, &function_file, NULL)
|
||||
|| gcov_read_unsigned (file, &lineno))
|
||||
if (gcov_read_string (&function_name)
|
||||
|| gcov_read_unsigned (&checksum)
|
||||
|| gcov_read_string (&function_file)
|
||||
|| gcov_read_unsigned (&lineno))
|
||||
goto corrupt;
|
||||
src = find_source (function_file);
|
||||
fn = (function_t *)xcalloc (1, sizeof (function_t));
|
||||
|
@ -810,7 +806,7 @@ read_graph_file ()
|
|||
{
|
||||
unsigned flags;
|
||||
|
||||
if (gcov_read_unsigned (file, &flags))
|
||||
if (gcov_read_unsigned (&flags))
|
||||
goto corrupt;
|
||||
fn->blocks[ix].flags = flags;
|
||||
}
|
||||
|
@ -822,7 +818,7 @@ read_graph_file ()
|
|||
unsigned num_dests = (length - 4) / 8;
|
||||
unsigned dest, flags;
|
||||
|
||||
if (gcov_read_unsigned (file, &src)
|
||||
if (gcov_read_unsigned (&src)
|
||||
|| src >= fn->num_blocks
|
||||
|| fn->blocks[src].succ)
|
||||
goto corrupt;
|
||||
|
@ -831,8 +827,8 @@ read_graph_file ()
|
|||
{
|
||||
struct arc_info *arc;
|
||||
|
||||
if (gcov_read_unsigned (file, &dest)
|
||||
|| gcov_read_unsigned (file, &flags)
|
||||
if (gcov_read_unsigned (&dest)
|
||||
|| gcov_read_unsigned (&flags)
|
||||
|| dest >= fn->num_blocks)
|
||||
goto corrupt;
|
||||
arc = (arc_t *) xcalloc (1, sizeof (arc_t));
|
||||
|
@ -883,7 +879,7 @@ read_graph_file ()
|
|||
unsigned *line_nos
|
||||
= (unsigned *)xcalloc ((length - 4) / 4, sizeof (unsigned));
|
||||
|
||||
if (gcov_read_unsigned (file, &blockno)
|
||||
if (gcov_read_unsigned (&blockno)
|
||||
|| blockno >= fn->num_blocks
|
||||
|| fn->blocks[blockno].u.line.encoding)
|
||||
goto corrupt;
|
||||
|
@ -892,7 +888,7 @@ read_graph_file ()
|
|||
{
|
||||
unsigned lineno;
|
||||
|
||||
if (gcov_read_unsigned (file, &lineno))
|
||||
if (gcov_read_unsigned (&lineno))
|
||||
goto corrupt;
|
||||
if (lineno)
|
||||
{
|
||||
|
@ -909,7 +905,7 @@ read_graph_file ()
|
|||
{
|
||||
char *file_name = NULL;
|
||||
|
||||
if (gcov_read_string (file, &file_name, NULL))
|
||||
if (gcov_read_string (&file_name))
|
||||
goto corrupt;
|
||||
if (!file_name)
|
||||
break;
|
||||
|
@ -928,15 +924,15 @@ read_graph_file ()
|
|||
fn = NULL;
|
||||
current_tag = 0;
|
||||
}
|
||||
if (gcov_resync (file, base, length))
|
||||
if (gcov_resync (base, length))
|
||||
{
|
||||
corrupt:;
|
||||
fnotice (stderr, "%s:corrupted\n", bbg_file_name);
|
||||
fclose (file);
|
||||
gcov_close ();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
fclose (file);
|
||||
gcov_close ();
|
||||
|
||||
/* We built everything backwards, so nreverse them all */
|
||||
|
||||
|
@ -997,27 +993,25 @@ read_graph_file ()
|
|||
static int
|
||||
read_count_file ()
|
||||
{
|
||||
FILE *file;
|
||||
unsigned ix;
|
||||
char *function_name_buffer = NULL;
|
||||
unsigned magic, version;
|
||||
function_t *fn = NULL;
|
||||
|
||||
file = fopen (da_file_name, "rb");
|
||||
if (!file)
|
||||
if (!gcov_open (da_file_name, 1))
|
||||
{
|
||||
fnotice (stderr, "%s:cannot open data file\n", da_file_name);
|
||||
return 1;
|
||||
}
|
||||
if (gcov_read_unsigned (file, &magic) || magic != GCOV_DATA_MAGIC)
|
||||
if (gcov_read_unsigned (&magic) || magic != GCOV_DATA_MAGIC)
|
||||
{
|
||||
fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
|
||||
cleanup:;
|
||||
free (function_name_buffer);
|
||||
fclose (file);
|
||||
gcov_close ();
|
||||
return 1;
|
||||
}
|
||||
if (gcov_read_unsigned (file, &version) || version != GCOV_VERSION)
|
||||
if (gcov_read_unsigned (&version) || version != GCOV_VERSION)
|
||||
{
|
||||
char v[4], e[4];
|
||||
|
||||
|
@ -1036,32 +1030,35 @@ read_count_file ()
|
|||
unsigned tag, length;
|
||||
long base;
|
||||
|
||||
if (gcov_read_unsigned (file, &tag)
|
||||
|| gcov_read_unsigned (file, &length))
|
||||
if (gcov_read_unsigned (&tag)
|
||||
|| gcov_read_unsigned (&length))
|
||||
{
|
||||
if (feof (file))
|
||||
if (gcov_eof ())
|
||||
break;
|
||||
|
||||
corrupt:;
|
||||
fnotice (stderr, "%s:corrupted\n", da_file_name);
|
||||
goto cleanup;
|
||||
}
|
||||
base = gcov_save_position (file);
|
||||
base = gcov_save_position ();
|
||||
if (tag == GCOV_TAG_OBJECT_SUMMARY)
|
||||
{
|
||||
if (gcov_read_summary (file, &object_summary))
|
||||
if (gcov_read_summary (&object_summary))
|
||||
goto corrupt;
|
||||
}
|
||||
else if (tag == GCOV_TAG_PROGRAM_SUMMARY
|
||||
|| tag == GCOV_TAG_INCORRECT_SUMMARY)
|
||||
program_count++;
|
||||
{
|
||||
program_count++;
|
||||
gcov_resync (base, length);
|
||||
}
|
||||
else if (tag == GCOV_TAG_FUNCTION)
|
||||
{
|
||||
unsigned checksum;
|
||||
struct function_info *fn_n = functions;
|
||||
|
||||
if (gcov_read_string (file, &function_name_buffer, NULL)
|
||||
|| gcov_read_unsigned (file, &checksum))
|
||||
if (gcov_read_string (&function_name_buffer)
|
||||
|| gcov_read_unsigned (&checksum))
|
||||
goto corrupt;
|
||||
|
||||
for (fn = fn ? fn->next : NULL; ; fn = fn->next)
|
||||
|
@ -1103,15 +1100,16 @@ read_count_file ()
|
|||
{
|
||||
gcov_type count;
|
||||
|
||||
if (gcov_read_counter (file, &count))
|
||||
if (gcov_read_counter (&count))
|
||||
goto corrupt;
|
||||
fn->counts[ix] += count;
|
||||
}
|
||||
}
|
||||
gcov_resync (file, base, length);
|
||||
else
|
||||
gcov_resync (base, length);
|
||||
}
|
||||
|
||||
fclose (file);
|
||||
gcov_close ();
|
||||
free (function_name_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
|
124
gcc/libgcov.c
124
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
519
gcc/profile.c
519
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 (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");
|
||||
|
|
Loading…
Reference in New Issue