aboutsummaryrefslogtreecommitdiff
path: root/gcc/gcov-io.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gcov-io.h')
-rw-r--r--gcc/gcov-io.h830
1 files changed, 413 insertions, 417 deletions
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index 14dc584..8e10e49 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -135,24 +135,30 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
merged.
This file is included by both the compiler, gcov tools and the
- library. The IN_LIBGCC2 define distinguishes these cases. When
- IN_LIBGCC2 is nonzero, we're building libgcc2 for the target and
- know the compiler is (the just built) gcc. Otherwise we're
- generating code for the host, and the compiler may or may not be
- gcc. In this latter case, you must ensure that 'gcov_type' is
- typedefed to something suitable (unsigned HOST_WIDEST_INT is
- usually what you want). */
+ runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to
+ distinguish which case is which. If IN_LIBGCOV is non-zero,
+ libgcov is being built. If IN_GCOV is non-zero, the gcov tools are
+ being built. Otherwise the compiler is being built. IN_GCOV may be
+ positive or negative. If positive, we are compiling a tool that
+ requires additional functions (see the code for knowledge of what
+ those functions are). */
#ifndef GCC_GCOV_IO_H
#define GCC_GCOV_IO_H
-#if IN_LIBGCC2
+#if IN_LIBGCOV
#if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
typedef long gcov_type;
#else
typedef long long gcov_type;
#endif
-#endif /* IN_LIBGCC2 */
+#endif /* IN_LIBGCOV */
+#if IN_GCOV
+typedef HOST_WIDEST_INT gcov_type;
+#if IN_GCOV > 0
+#include <sys/types.h>
+#endif
+#endif
/* File suffixes. */
#define GCOV_DATA_SUFFIX ".da"
@@ -228,7 +234,7 @@ struct counter_section
unsigned n_counters; /* Number of counters in the section. */
};
-#if IN_LIBGCC2
+#if IN_LIBGCOV
/* Information about section of counters for an object file. */
struct counter_section_data
{
@@ -272,139 +278,369 @@ extern void __gcov_flush (void);
/* Since this file is used in both host and target files, and we don't
include ansidecl.h in target files, provide some necessary macros. */
-#ifndef PARAMS
-# define PARAMS(X) X
-#endif
#ifndef ATTRIBUTE_UNUSED
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#endif
-#endif /* IN_LIBGCC2 */
+#endif /* IN_LIBGCOV */
+
+/* Because small reads and writes, interspersed with seeks cause lots
+ of disk activity, we buffer the entire count files. */
+
+static FILE *gcov_file;
+static size_t gcov_position;
+static size_t gcov_length;
+static unsigned char *gcov_buffer;
+static size_t gcov_alloc;
+static int gcov_modified;
+static int gcov_errored = 1;
/* Functions for reading and writing gcov files. */
-static int gcov_write_unsigned PARAMS((FILE *, unsigned))
- ATTRIBUTE_UNUSED;
-static int gcov_write_counter PARAMS((FILE *, gcov_type))
- ATTRIBUTE_UNUSED;
-static int gcov_write_string PARAMS((FILE *, const char *, unsigned))
- ATTRIBUTE_UNUSED;
-static int gcov_read_unsigned PARAMS((FILE *, unsigned *))
- ATTRIBUTE_UNUSED;
-static int gcov_read_counter PARAMS((FILE *, gcov_type *))
- ATTRIBUTE_UNUSED;
-#if !IN_LIBGCC2
-static int gcov_read_string PARAMS((FILE *, char **, unsigned *))
- ATTRIBUTE_UNUSED;
+static int gcov_open (const char */*name*/, int /*truncate*/);
+static int gcov_close (void);
+#if !IN_GCOV
+static unsigned char *gcov_write_bytes (unsigned);
+static int gcov_write_unsigned (unsigned);
+#if IN_LIBGCOV
+static int gcov_write_counter (gcov_type);
+#endif
+static int gcov_write_string (const char *);
+static unsigned long gcov_reserve_length (void);
+static int gcov_write_length (unsigned long /*position*/);
+#if IN_LIBGCOV
+static int gcov_write_summary (unsigned, const struct gcov_summary *);
+#endif
+#endif /* !IN_GCOV */
+static const unsigned char *gcov_read_bytes (unsigned);
+static int gcov_read_unsigned (unsigned *);
+static int gcov_read_counter (gcov_type *);
+#if !IN_LIBGCOV
+static int gcov_read_string (char **);
+#endif
+static int gcov_read_summary (struct gcov_summary *);
+static __inline__ unsigned long gcov_save_position (void);
+static int gcov_resync (unsigned long /*base*/, unsigned /*length */);
+static unsigned long gcov_seek_end (void);
+static int gcov_skip (unsigned /*length*/);
+static int gcov_skip_string (unsigned /*length*/);
+static int gcov_ok (void);
+static int gcov_error (void);
+static int gcov_eof (void);
+#if IN_GCOV > 0
+static time_t gcov_time (void);
+#endif
+
+/* Open a gcov file. NAME is the name of the file to open and MODE
+ indicates whether a new file should be created, or an existing file
+ opened for modification. If MODE is >= 0 an existing file will be
+ opened, if possible, and if MODE is <= 0, a new file will be
+ created. Use MODE=0 to attempt to reopen an existing file and then
+ fall back on creating a new one. Return zero on failure, >0 on
+ opening an existing file and <0 on creating a new one. */
+
+static int
+gcov_open (const char *name, int mode)
+{
+ int result = 1;
+ size_t alloc = 1024;
+#if defined (TARGET_HAS_F_SETLKW) && IN_LIBGCOV
+ struct flock s_flock;
+
+ s_flock.l_type = F_WRLCK;
+ s_flock.l_whence = SEEK_SET;
+ s_flock.l_start = 0;
+ s_flock.l_len = 0; /* Until EOF. */
+ s_flock.l_pid = getpid ();
+#endif
+
+ if (gcov_file)
+ abort ();
+ gcov_position = gcov_length = 0;
+ gcov_errored = gcov_modified = 0;
+ if (mode >= 0)
+ gcov_file = fopen (name, "r+b");
+ if (!gcov_file && mode <= 0)
+ {
+ result = -1;
+ gcov_file = fopen (name, "w+b");
+ }
+ if (!gcov_file)
+ return 0;
+
+#if defined (TARGET_HAS_F_SETLKW) && IN_LIBGCOV
+ while (fcntl (fileno (gcov_file), F_SETLKW, &s_flock)
+ && errno == EINTR)
+ continue;
#endif
-static int gcov_read_summary PARAMS ((FILE *, struct gcov_summary *))
- ATTRIBUTE_UNUSED;
-#if IN_LIBGCC2
-static int gcov_write_summary PARAMS ((FILE *, unsigned,
- const struct gcov_summary *))
- ATTRIBUTE_UNUSED;
+
+ if (result >= 0)
+ {
+ if (fseek (gcov_file, 0, SEEK_END))
+ {
+ fclose (gcov_file);
+ gcov_file = 0;
+ return 0;
+ }
+ gcov_length = ftell (gcov_file);
+ fseek (gcov_file, 0, SEEK_SET);
+ alloc += gcov_length;
+ }
+ if (alloc > gcov_alloc)
+ {
+ if (gcov_buffer)
+ free (gcov_buffer);
+ gcov_alloc = alloc;
+#if IN_LIBGCOV
+ gcov_buffer = malloc (gcov_alloc);
+ if (!gcov_buffer)
+ {
+ fclose (gcov_file);
+ gcov_file = 0;
+ gcov_length = 0;
+ gcov_alloc = 0;
+ return 0;
+ }
+#else
+ gcov_buffer = xmalloc (gcov_alloc);
#endif
-#define gcov_save_position(STREAM) \
- da_file_position (STREAM)
-#define gcov_reserve_length(STREAM) \
- (gcov_write_unsigned (STREAM, 0) ? 0 : da_file_position (STREAM) - 4)
-static int gcov_write_length PARAMS((FILE *, long))
- ATTRIBUTE_UNUSED;
-#define gcov_resync(STREAM, BASE, LENGTH) \
- da_file_seek (STREAM, BASE + (long)LENGTH, SEEK_SET)
-#define gcov_skip(STREAM, LENGTH) \
- da_file_seek (STREAM, LENGTH, SEEK_CUR)
-#define gcov_skip_string(STREAM, LENGTH) \
- da_file_seek (STREAM, (LENGTH) + 4 - ((LENGTH) & 3), SEEK_CUR)
-#if IN_LIBGCC2
-static FILE *da_file_open PARAMS ((const char *, int *));
-static int da_file_close PARAMS ((void));
-static int da_file_eof PARAMS ((void));
-static int da_file_error PARAMS ((void));
+ }
+ if (result >= 0 && fread (gcov_buffer, gcov_length, 1, gcov_file) != 1)
+ {
+ fclose (gcov_file);
+ gcov_file = 0;
+ gcov_length = 0;
+ return 0;
+ }
+ return result;
+}
+
+/* Close the current gcov file. Flushes data to disk. Returns nonzero
+ on failure or error flag set. */
+
+static int
+gcov_close ()
+{
+ int result = 0;
+
+ if (gcov_file)
+ {
+ if (gcov_modified
+ && (fseek (gcov_file, 0, SEEK_SET)
+ || fwrite (gcov_buffer, gcov_length, 1, gcov_file) != 1))
+ result = -1;
+ fclose (gcov_file);
+ gcov_file = 0;
+ gcov_length = 0;
+ }
+ return result || gcov_errored;
+}
+
+#if !IN_GCOV
+/* Allocate space to write BYTES bytes to the gcov file. Return a
+ pointer to those bytes, or NULL on failure. */
+
+static unsigned char *
+gcov_write_bytes (unsigned bytes)
+{
+ char unsigned *result;
+
+ if (gcov_position + bytes > gcov_alloc)
+ {
+ size_t new_size = (gcov_alloc + bytes) * 3 / 2;
+
+ if (!gcov_buffer)
+ return 0;
+#if IN_LIBGCOV
+ result = realloc (gcov_buffer, new_size);
+ if (!result)
+ {
+ free (gcov_buffer);
+ gcov_buffer = 0;
+ gcov_alloc = 0;
+ gcov_position = gcov_length = 0;
+ return 0;
+ }
+#else
+ result = xrealloc (gcov_buffer, new_size);
#endif
-static unsigned long da_file_position PARAMS ((FILE *));
-static int da_file_seek PARAMS ((FILE *, long, int));
-static size_t da_file_write PARAMS ((const void *, size_t, size_t, FILE *));
-static size_t da_file_read PARAMS ((void *, size_t, size_t, FILE *));
+ gcov_alloc = new_size;
+ gcov_buffer = result;
+ }
+
+ result = &gcov_buffer[gcov_position];
+ gcov_position += bytes;
+ gcov_modified = 1;
+ if (gcov_position > gcov_length)
+ gcov_length = gcov_position;
+ return result;
+}
-/* Write VALUE to coverage file FILE. Return nonzero if failed due to
+/* Write VALUE to coverage file. Return nonzero if failed due to
file i/o error, or value error. */
static int
-gcov_write_unsigned (file, value)
- FILE *file;
- unsigned value;
+gcov_write_unsigned (unsigned value)
{
- char buffer[4];
+ unsigned char *buffer = gcov_write_bytes (4);
unsigned ix;
- for (ix = sizeof (buffer); ix--; )
+ if (!buffer)
+ return 1;
+
+ for (ix = 4; ix--; )
{
buffer[ix] = value;
value >>= 8;
}
- return ((sizeof (value) > sizeof (buffer) && value)
- || da_file_write (buffer, 1, sizeof (buffer), file) != sizeof (buffer));
+ return sizeof (value) > 4 && value;
}
-/* Write VALUE to coverage file FILE. Return nonzero if failed due to
+/* Write VALUE to coverage file. Return nonzero if failed due to
file i/o error, or value error. Negative values are not checked
here -- they are checked in gcov_read_counter. */
+#if IN_LIBGCOV
static int
-gcov_write_counter (file, value)
- FILE *file;
- gcov_type value;
+gcov_write_counter (gcov_type value)
{
- char buffer[8];
+ unsigned char *buffer = gcov_write_bytes (8);
unsigned ix;
- for (ix = sizeof (buffer); ix--; )
+ if (!buffer)
+ return 1;
+
+ for (ix = 8; ix--; )
{
buffer[ix] = value;
value >>= 8;
}
- return ((sizeof (value) > sizeof (buffer) && value != 0 && value != -1)
- || da_file_write (buffer, 1, sizeof (buffer), file) != sizeof (buffer));
+ return sizeof (value) > 8 && value;
}
+#endif /* IN_LIBGCOV */
-/* Write VALUE to coverage file FILE. Return nonzero if failed due to
+/* Write VALUE to coverage file. Return nonzero if failed due to
file i/o error, or value error. */
static int
-gcov_write_string (file, string, length)
- FILE *file;
- unsigned length;
- const char *string;
+gcov_write_string (const char *string)
{
- unsigned pad = 0;
- unsigned rem = 4 - (length & 3);
-
if (string)
- return (gcov_write_unsigned (file, length)
- || da_file_write (string, 1, length, file) != length
- || da_file_write (&pad, 1, rem, file) != rem);
+ {
+ unsigned length = strlen (string);
+ unsigned pad = 0;
+ unsigned rem = 4 - (length & 3);
+ unsigned char *buffer;
+
+ if (gcov_write_unsigned (length))
+ return 1;
+ buffer = gcov_write_bytes (length + rem);
+ if (!buffer)
+ return 1;
+ memcpy (buffer, string, length);
+ memcpy (buffer + length, &pad, rem);
+ return 0;
+ }
else
- return gcov_write_unsigned (file, 0);
+ return gcov_write_unsigned (0);
+}
+
+/* Allocate space to write a record tag length. Return a value to be
+ used for gcov_write_length. */
+
+static unsigned long
+gcov_reserve_length (void)
+{
+ unsigned long result = gcov_position;
+ unsigned char *buffer = gcov_write_bytes (4);
+
+ if (!buffer)
+ return 0;
+ memset (buffer, 0, 4);
+ return result;
+}
+
+/* Write a record length at PLACE. The current file position is the
+ end of the record, and is restored before returning. Returns
+ nonzero on failure. */
+
+static int
+gcov_write_length (unsigned long position)
+{
+ unsigned length = gcov_position - position - 4;
+ unsigned char *buffer = &gcov_buffer[position];
+ unsigned ix;
+
+ if (!position)
+ return 1;
+ for (ix = 4; ix--; )
+ {
+ buffer[ix] = length;
+ length >>= 8;
+ }
+ return 0;
+}
+
+#if IN_LIBGCOV
+/* Write a summary structure to the gcov file. */
+
+static int
+gcov_write_summary (unsigned tag, const struct gcov_summary *summary)
+{
+ volatile unsigned long base; /* volatile is necessary to work around
+ a compiler bug. */
+
+ if (gcov_write_unsigned (tag))
+ return 1;
+ base = gcov_reserve_length ();
+ if (gcov_write_unsigned (summary->checksum))
+ return 1;
+ if (gcov_write_unsigned (summary->runs)
+ || gcov_write_unsigned (summary->arcs))
+ return 1;
+ if (gcov_write_counter (summary->arc_sum)
+ || gcov_write_counter (summary->arc_max_one)
+ || gcov_write_counter (summary->arc_max_sum)
+ || gcov_write_counter (summary->arc_sum_max))
+ return 1;
+ if (gcov_write_length (base))
+ return 1;
+ return 0;
+}
+#endif /* IN_LIBGCOV */
+
+#endif /*!IN_GCOV */
+
+/* Return a pointer to read BYTES bytes from the gcov file. Returns
+ NULL on failure (read past EOF). */
+
+static const unsigned char *
+gcov_read_bytes (unsigned bytes)
+{
+ const unsigned char *result;
+
+ if (gcov_position + bytes > gcov_length)
+ return 0;
+ result = &gcov_buffer[gcov_position];
+ gcov_position += bytes;
+ return result;
}
-/* Read *VALUE_P from coverage file FILE. Return nonzero if failed
+/* Read *VALUE_P from coverage file. Return nonzero if failed
due to file i/o error, or range error. */
static int
-gcov_read_unsigned (file, value_p)
- FILE *file;
- unsigned *value_p;
+gcov_read_unsigned (unsigned *value_p)
{
unsigned value = 0;
unsigned ix;
- unsigned char buffer[4];
+ const unsigned char *buffer = gcov_read_bytes (4);
- if (da_file_read (buffer, 1, sizeof (buffer), file) != sizeof (buffer))
+ if (!buffer)
return 1;
- for (ix = sizeof (value); ix < sizeof (buffer); ix++)
+ for (ix = sizeof (value); ix < 4; ix++)
if (buffer[ix])
return 1;
- for (ix = 0; ix != sizeof (buffer); ix++)
+ for (ix = 0; ix != 4; ix++)
{
value <<= 8;
value |= buffer[ix];
@@ -413,24 +649,22 @@ gcov_read_unsigned (file, value_p)
return 0;
}
-/* Read *VALUE_P from coverage file FILE. Return nonzero if failed
+/* Read *VALUE_P from coverage file. Return nonzero if failed
due to file i/o error, or range error. */
static int
-gcov_read_counter (file, value_p)
- FILE *file;
- gcov_type *value_p;
+gcov_read_counter (gcov_type *value_p)
{
gcov_type value = 0;
unsigned ix;
- unsigned char buffer[8];
+ const unsigned char *buffer = gcov_read_bytes (8);
- if (da_file_read (buffer, 1, sizeof (buffer), file) != sizeof (buffer))
+ if (!buffer)
return 1;
- for (ix = sizeof (value); ix < sizeof (buffer); ix++)
+ for (ix = sizeof (value); ix < 8; ix++)
if (buffer[ix])
return 1;
- for (ix = 0; ix != sizeof (buffer); ix++)
+ for (ix = 0; ix != 8; ix++)
{
value <<= 8;
value |= buffer[ix];
@@ -440,377 +674,139 @@ gcov_read_counter (file, value_p)
return value < 0;
}
-#if !IN_LIBGCC2
+#if !IN_LIBGCOV
-/* Read string from coverage file FILE. Length is stored in *LENGTH_P
- (if non-null), a buffer is allocated and returned in *STRING_P.
- Return nonzero if failed due to file i/o error, or range
- error. Uses xmalloc to allocate the string buffer. */
+/* Read string from coverage file. A buffer is allocated and returned
+ in *STRING_P. Return nonzero if failed due to file i/o error, or
+ range error. Uses xmalloc to allocate the string buffer. */
static int
-gcov_read_string (file, string_p, length_p)
- FILE *file;
- char **string_p;
- unsigned *length_p;
+gcov_read_string (char **string_p)
{
unsigned length;
+ const unsigned char *buffer;
- if (gcov_read_unsigned (file, &length))
+ if (gcov_read_unsigned (&length))
return 1;
- if (length_p)
- *length_p = length;
free (*string_p);
-
*string_p = NULL;
if (!length)
return 0;
length += 4 - (length & 3);
- *string_p = (char *) xmalloc (length);
-
- return da_file_read (*string_p, 1, length, file) != length;
+ buffer = gcov_read_bytes (length);
+ if (!buffer)
+ return 1;
+
+ *string_p = xmalloc (length);
+ if (!*string_p)
+ return 1;
+ memcpy (*string_p, buffer, length);
+ return 0;
}
-#endif /* !IN_LIBGCC2 */
-
-/* Write a record length at PLACE. The current file position is the
- end of the record, and is restored before returning. Returns
- nonzero on failure. */
-
-static int
-gcov_write_length (file, place)
- FILE *file;
- long place;
-{
- long here = da_file_position (file);
- int result = (!place || da_file_seek (file, place, SEEK_SET)
- || gcov_write_unsigned (file, here - place - 4));
- if (da_file_seek (file, here, SEEK_SET))
- result = 1;
- return result;
-}
+#endif /* !IN_LIBGCOV */
#define GCOV_SUMMARY_LENGTH 44
static int
-gcov_read_summary (da_file, summary)
- FILE *da_file;
- struct gcov_summary *summary;
+gcov_read_summary (struct gcov_summary *summary)
{
- return (gcov_read_unsigned (da_file, &summary->checksum)
- || gcov_read_unsigned (da_file, &summary->runs)
- || gcov_read_unsigned (da_file, &summary->arcs)
- || gcov_read_counter (da_file, &summary->arc_sum)
- || gcov_read_counter (da_file, &summary->arc_max_one)
- || gcov_read_counter (da_file, &summary->arc_max_sum)
- || gcov_read_counter (da_file, &summary->arc_sum_max));
+ return (gcov_read_unsigned (&summary->checksum)
+ || gcov_read_unsigned (&summary->runs)
+ || gcov_read_unsigned (&summary->arcs)
+ || gcov_read_counter (&summary->arc_sum)
+ || gcov_read_counter (&summary->arc_max_one)
+ || gcov_read_counter (&summary->arc_max_sum)
+ || gcov_read_counter (&summary->arc_sum_max));
}
-#if IN_LIBGCC2
-static int
-gcov_write_summary (da_file, tag, summary)
- FILE *da_file;
- unsigned tag;
- const struct gcov_summary *summary;
-{
- long base;
-
- return (gcov_write_unsigned (da_file, tag)
- || !(base = gcov_reserve_length (da_file))
- || gcov_write_unsigned (da_file, summary->checksum)
- || gcov_write_unsigned (da_file, summary->runs)
- || gcov_write_unsigned (da_file, summary->arcs)
- || gcov_write_counter (da_file, summary->arc_sum)
- || gcov_write_counter (da_file, summary->arc_max_one)
- || gcov_write_counter (da_file, summary->arc_max_sum)
- || gcov_write_counter (da_file, summary->arc_sum_max)
- || gcov_write_length (da_file, base));
-}
-#endif
+/* Save the current position in the gcov file. */
-#if IN_LIBGCC2
-/* The kernel had problems with managing a lot of small reads/writes we use;
- the functions below are used to buffer whole file in memory, thus reading and
- writing it only once. This should be feasible, as we have this amount
- of memory for counters allocated anyway. */
-
-static FILE *actual_da_file;
-static unsigned long actual_da_file_position;
-static unsigned long actual_da_file_length;
-static char *actual_da_file_buffer;
-static unsigned long actual_da_file_buffer_size;
-
-/* Open the file NAME and return it; in EXISTED return 1 if it existed
- already. */
-static FILE *
-da_file_open (name, existed)
- const char *name;
- int *existed;
+static inline unsigned long
+gcov_save_position (void)
{
-#if defined (TARGET_HAS_F_SETLKW)
- struct flock s_flock;
-
- s_flock.l_type = F_WRLCK;
- s_flock.l_whence = SEEK_SET;
- s_flock.l_start = 0;
- s_flock.l_len = 0; /* Until EOF. */
- s_flock.l_pid = getpid ();
-#endif
-
- if (actual_da_file)
- return 0;
- actual_da_file_position = 0;
- if (!actual_da_file_buffer)
- {
- actual_da_file_buffer = malloc (1);
- actual_da_file_buffer_size = 1;
- }
-
- actual_da_file = fopen (name, "r+t");
- if (actual_da_file)
- *existed = 1;
- else
- {
- actual_da_file = fopen (name, "w+t");
- if (actual_da_file)
- *existed = 0;
- else
- return 0;
- }
-
-#if defined (TARGET_HAS_F_SETLKW)
- /* After a fork, another process might try to read and/or write
- the same file simultaneously. So if we can, lock the file to
- avoid race conditions. */
- while (fcntl (fileno (actual_da_file), F_SETLKW, &s_flock)
- && errno == EINTR)
- continue;
-#endif
-
- if (*existed)
- {
- if (fseek (actual_da_file, 0, SEEK_END))
- {
- fclose (actual_da_file);
- actual_da_file = 0;
- return 0;
- }
- actual_da_file_length = ftell (actual_da_file);
- rewind (actual_da_file);
- }
- else
- actual_da_file_length = 0;
-
- if (actual_da_file_length > actual_da_file_buffer_size)
- {
- actual_da_file_buffer_size = actual_da_file_length;
- actual_da_file_buffer = realloc (actual_da_file_buffer,
- actual_da_file_buffer_size);
- if (!actual_da_file_buffer)
- {
- fclose (actual_da_file);
- actual_da_file = 0;
- return 0;
- }
- }
-
- if (*existed)
- {
- if (fread (actual_da_file_buffer, actual_da_file_length,
- 1, actual_da_file) != 1)
- {
- fclose (actual_da_file);
- actual_da_file = 0;
- return 0;
- }
- rewind (actual_da_file);
- }
-
- return actual_da_file;
+ return gcov_position;
}
-/* Write changes to the .da file and close it. */
-static int da_file_close ()
-{
- if (!actual_da_file)
- return -1;
-
- if (fwrite (actual_da_file_buffer, actual_da_file_length,
- 1, actual_da_file) != 1)
- return da_file_error ();
-
- if (fclose (actual_da_file))
- {
- actual_da_file = 0;
- return -1;
- }
+/* Reset to a known position. BASE should have been obtained from
+ gcov_save_position, LENGTH should be a record length, or zero. */
- actual_da_file = 0;
+static inline int
+gcov_resync (unsigned long base, unsigned length)
+{
+ if (gcov_buffer)
+ gcov_position = base + length;
return 0;
}
-/* Returns current position in .da file. */
-static unsigned long
-da_file_position (file)
- FILE *file;
-{
- if (file)
- return ftell (file);
- return actual_da_file_position;
-}
+/* Move to the end of the gcov file. */
-/* Tests whether we have reached end of .da file. */
-static int
-da_file_eof ()
+static inline unsigned long
+gcov_seek_end ()
{
- return actual_da_file_position == actual_da_file_length;
+ gcov_position = gcov_length;
+ return gcov_position;
}
-/* Change position in the .da file. */
-static int
-da_file_seek (file, pos, whence)
- FILE *file;
- long pos;
- int whence;
-{
- if (file)
- return fseek (file, pos, whence);
-
- if (!actual_da_file)
- return -1;
+/* Skip LENGTH bytes in the file. */
- switch (whence)
- {
- case SEEK_CUR:
- if (pos < 0 && (unsigned long) -pos > actual_da_file_position)
- return da_file_error ();
-
- actual_da_file_position += pos;
- break;
- case SEEK_SET:
- actual_da_file_position = pos;
- break;
- case SEEK_END:
- if ((unsigned long) -pos > actual_da_file_length)
- return da_file_error ();
- actual_da_file_position = actual_da_file_length + pos;
- }
- if (actual_da_file_position > actual_da_file_length)
- return da_file_error ();
+static inline int
+gcov_skip (unsigned length)
+{
+ if (gcov_length < gcov_position + length)
+ return 1;
+ gcov_position += length;
return 0;
}
-/* Write LEN chars of DATA to actual .da file; ELTS is expected to be 1,
- FILE 0. */
-static size_t
-da_file_write (data, elts, len, file)
- const void *data;
- size_t elts;
- size_t len;
- FILE *file;
-{
- size_t l = len;
- const char *dat = data;
-
- if (file)
- return fwrite (data, elts, len, file);
-
- if (elts != 1)
- abort ();
-
- if (!actual_da_file)
- return -1;
- if (actual_da_file_position + len > actual_da_file_buffer_size)
- {
- actual_da_file_buffer_size = 2 * (actual_da_file_position + len);
- actual_da_file_buffer = realloc (actual_da_file_buffer,
- actual_da_file_buffer_size);
- if (!actual_da_file_buffer)
- return da_file_error ();
- }
- while (len--)
- actual_da_file_buffer[actual_da_file_position++] = *dat++;
- if (actual_da_file_position > actual_da_file_length)
- actual_da_file_length = actual_da_file_position;
-
- return l;
-}
+/* Skip a string of LENGTH bytes. */
-/* Read LEN chars of DATA from actual .da file; ELTS is expected to be 1,
- FILE 0. */
-static size_t
-da_file_read (data, elts, len, file)
- void *data;
- size_t elts;
- size_t len;
- FILE *file;
+static inline int
+gcov_skip_string (unsigned length)
{
- size_t l;
- char *dat = data;
-
- if (file)
- return fread (data, elts, len, file);
-
- if (elts != 1)
- abort ();
-
- if (!actual_da_file)
- return -1;
- if (actual_da_file_position + len > actual_da_file_length)
- len = actual_da_file_length - actual_da_file_position;
- l = len;
-
- while (len--)
- *dat++ = actual_da_file_buffer[actual_da_file_position++];
- return l;
+ return gcov_skip (length + 4 - (length & 3));
}
-/* Close the current .da file and report error. */
-static int
-da_file_error ()
-{
- if (actual_da_file)
- fclose (actual_da_file);
- actual_da_file = 0;
- return -1;
-}
-#else /* !IN_LIBGCC2 */
-static size_t
-da_file_write (data, elts, len, file)
- const void *data;
- size_t elts;
- size_t len;
- FILE *file;
+/* Tests whether we have reached end of .da file. */
+
+static inline int
+gcov_eof ()
{
- return fwrite (data, elts, len, file);
+ return gcov_position == gcov_length;
}
-static size_t
-da_file_read (data, elts, len, file)
- void *data;
- size_t elts;
- size_t len;
- FILE *file;
+/* Return non-zero if the error flag is set. */
+
+static inline int
+gcov_ok ()
{
- return fread (data, elts, len, file);
+ return gcov_file != 0 && !gcov_errored;
}
-static unsigned long
-da_file_position (file)
- FILE *file;
+/* Set the error flag. */
+static inline int
+gcov_error ()
{
- return ftell (file);
+ int error = gcov_errored;
+
+ gcov_errored = 1;
+ return error;
}
-static int
-da_file_seek (file, pos, whence)
- FILE *file;
- long pos;
- int whence;
+#if IN_GCOV > 0
+/* Return the modification time of the current gcov file. */
+
+static time_t
+gcov_time ()
{
- return fseek (file, pos, whence);
+ struct stat status;
+
+ if (fstat (fileno (gcov_file), &status))
+ return 0;
+ else
+ return status.st_mtime;
}
-#endif
-
+#endif /* IN_GCOV */
#endif /* GCC_GCOV_IO_H */