/* File format for coverage information
- Copyright (C) 1996, 1997, 1998, 2000, 2002,
- 2003 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2007,
+ 2008 Free Software Foundation, Inc.
Contributed by Bob Manson <manson@cygnus.com>.
Completely remangled by Nathan Sidwell <nathan@codesourcery.com>.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* Routines declared in gcov-io.h. This file should be #included by
another source file, after having #included gcov-io.h. */
#if !IN_GCOV
static void gcov_write_block (unsigned);
-static unsigned char *gcov_write_bytes (unsigned);
+static gcov_unsigned_t *gcov_write_words (unsigned);
#endif
-static const unsigned char *gcov_read_bytes (unsigned);
+static const gcov_unsigned_t *gcov_read_words (unsigned);
#if !IN_LIBGCOV
static void gcov_allocate (unsigned);
#endif
+static inline gcov_unsigned_t from_file (gcov_unsigned_t value)
+{
+#if !IN_LIBGCOV
+ if (gcov_var.endian)
+ {
+ value = (value >> 16) | (value << 16);
+ value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff);
+ }
+#endif
+ return value;
+}
+
/* 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
opening an existing file and <0 on creating a new one. */
GCOV_LINKAGE int
+#if IN_LIBGCOV
+gcov_open (const char *name)
+#else
gcov_open (const char *name, int mode)
+#endif
{
- int result = 1;
+#if IN_LIBGCOV
+ const int mode = 0;
+#endif
#if GCOV_LOCKED
struct flock s_flock;
+ int fd;
s_flock.l_type = F_WRLCK;
s_flock.l_whence = SEEK_SET;
s_flock.l_pid = getpid ();
#endif
- if (gcov_var.file)
- abort ();
+ gcc_assert (!gcov_var.file);
gcov_var.start = 0;
gcov_var.offset = gcov_var.length = 0;
- gcov_var.overread = -4u;
+ gcov_var.overread = -1u;
gcov_var.error = 0;
+#if !IN_LIBGCOV
+ gcov_var.endian = 0;
+#endif
+#if GCOV_LOCKED
+ if (mode > 0)
+ fd = open (name, O_RDWR);
+ else
+ fd = open (name, O_RDWR | O_CREAT, 0666);
+ if (fd < 0)
+ return 0;
+
+ while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR)
+ continue;
+
+ gcov_var.file = fdopen (fd, "r+b");
+ if (!gcov_var.file)
+ {
+ close (fd);
+ return 0;
+ }
+
+ if (mode > 0)
+ gcov_var.mode = 1;
+ else if (mode == 0)
+ {
+ struct stat st;
+
+ if (fstat (fd, &st) < 0)
+ {
+ fclose (gcov_var.file);
+ gcov_var.file = 0;
+ return 0;
+ }
+ if (st.st_size != 0)
+ gcov_var.mode = 1;
+ else
+ gcov_var.mode = mode * 2 + 1;
+ }
+ else
+ gcov_var.mode = mode * 2 + 1;
+#else
if (mode >= 0)
gcov_var.file = fopen (name, "r+b");
if (gcov_var.file)
gcov_var.mode = 1;
else if (mode <= 0)
{
- result = -1;
gcov_var.file = fopen (name, "w+b");
if (gcov_var.file)
- gcov_var.mode = -1;
+ gcov_var.mode = mode * 2 + 1;
}
if (!gcov_var.file)
return 0;
+#endif
setbuf (gcov_var.file, (char *)0);
-#if GCOV_LOCKED
- while (fcntl (fileno (gcov_var.file), F_SETLKW, &s_flock)
- && errno == EINTR)
- continue;
-#endif
-
- return result;
+ return 1;
}
/* Close the current gcov file. Flushes data to disk. Returns nonzero
}
#if !IN_LIBGCOV
+/* Check if MAGIC is EXPECTED. Use it to determine endianness of the
+ file. Returns +1 for same endian, -1 for other endian and zero for
+ not EXPECTED. */
+
+GCOV_LINKAGE int
+gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected)
+{
+ if (magic == expected)
+ return 1;
+ magic = (magic >> 16) | (magic << 16);
+ magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff);
+ if (magic == expected)
+ {
+ gcov_var.endian = 1;
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+#if !IN_LIBGCOV
static void
gcov_allocate (unsigned length)
{
new_size *= 2;
gcov_var.alloc = new_size;
- gcov_var.buffer = xrealloc (gcov_var.buffer, new_size);
+ gcov_var.buffer = XRESIZEVAR (gcov_unsigned_t, gcov_var.buffer, new_size << 2);
}
#endif
static void
gcov_write_block (unsigned size)
{
- if (fwrite (gcov_var.buffer, size, 1, gcov_var.file) != 1)
+ if (fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1)
gcov_var.error = 1;
gcov_var.start += size;
gcov_var.offset -= size;
/* 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)
+static gcov_unsigned_t *
+gcov_write_words (unsigned words)
{
- char unsigned *result;
+ gcov_unsigned_t *result;
- GCOV_CHECK_WRITING ();
+ gcc_assert (gcov_var.mode < 0);
#if IN_LIBGCOV
if (gcov_var.offset >= GCOV_BLOCK_SIZE)
{
gcov_write_block (GCOV_BLOCK_SIZE);
if (gcov_var.offset)
{
- GCOV_CHECK (gcov_var.offset == 4);
+ gcc_assert (gcov_var.offset == 1);
memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4);
}
}
#else
- if (gcov_var.offset + bytes > gcov_var.alloc)
- gcov_allocate (gcov_var.offset + bytes);
+ if (gcov_var.offset + words > gcov_var.alloc)
+ gcov_allocate (gcov_var.offset + words);
#endif
result = &gcov_var.buffer[gcov_var.offset];
- gcov_var.offset += bytes;
+ gcov_var.offset += words;
return result;
}
GCOV_LINKAGE void
gcov_write_unsigned (gcov_unsigned_t value)
{
- unsigned char *buffer = gcov_write_bytes (4);
- unsigned ix;
+ gcov_unsigned_t *buffer = gcov_write_words (1);
- for (ix = 4; ix--; )
- {
- buffer[ix] = value;
- value >>= 8;
- }
- if (sizeof (value) > 4 && value)
- gcov_var.error = -1;
-
- return;
+ buffer[0] = value;
}
/* Write counter VALUE to coverage file. Sets error flag
GCOV_LINKAGE void
gcov_write_counter (gcov_type value)
{
- unsigned char *buffer = gcov_write_bytes (8);
- unsigned ix;
+ gcov_unsigned_t *buffer = gcov_write_words (2);
- for (ix = 8; ix--; )
- {
- buffer[ix] = value;
- value >>= 8;
- }
- if ((sizeof (value) > 8 && value) || value < 0)
- gcov_var.error = -1;
- return;
+ buffer[0] = (gcov_unsigned_t) value;
+ if (sizeof (value) > sizeof (gcov_unsigned_t))
+ buffer[1] = (gcov_unsigned_t) (value >> 32);
+ else
+ buffer[1] = 0;
}
#endif /* IN_LIBGCOV */
gcov_write_string (const char *string)
{
unsigned length = 0;
- unsigned pad = 0;
- unsigned rem = 0;
- unsigned char *buffer;
- unsigned ix;
- unsigned value;
+ unsigned alloc = 0;
+ gcov_unsigned_t *buffer;
if (string)
{
length = strlen (string);
- rem = 4 - (length & 3);
+ alloc = (length + 4) >> 2;
}
- buffer = gcov_write_bytes (4 + length + rem);
+ buffer = gcov_write_words (1 + alloc);
- value = length;
- for (ix = 4; ix--; )
- {
- buffer[ix] = value;
- value >>= 8;
- }
- memcpy (buffer + 4, string, length);
- memcpy (buffer + 4 + length, &pad, rem);
+ buffer[0] = alloc;
+ buffer[alloc] = 0;
+ memcpy (&buffer[1], string, length);
}
#endif
gcov_write_tag (gcov_unsigned_t tag)
{
gcov_position_t result = gcov_var.start + gcov_var.offset;
- unsigned char *buffer = gcov_write_bytes (8);
- unsigned ix;
+ gcov_unsigned_t *buffer = gcov_write_words (2);
- for (ix = 4; ix--; )
- {
- buffer[ix] = tag;
- tag >>= 8;
- }
- memset (buffer + 4, 0, 4);
+ buffer[0] = tag;
+ buffer[1] = 0;
+
return result;
}
{
unsigned offset;
gcov_unsigned_t length;
- unsigned char *buffer;
- unsigned ix;
+ gcov_unsigned_t *buffer;
- GCOV_CHECK_WRITING ();
- GCOV_CHECK (position + 8 <= gcov_var.start + gcov_var.offset);
- GCOV_CHECK (position >= gcov_var.start);
+ gcc_assert (gcov_var.mode < 0);
+ gcc_assert (position + 2 <= gcov_var.start + gcov_var.offset);
+ gcc_assert (position >= gcov_var.start);
offset = position - gcov_var.start;
- length = gcov_var.offset - offset - 8;
- buffer = &gcov_var.buffer[offset + 4];
- for (ix = 4; ix--; )
- {
- buffer[ix] = length;
- length >>= 8;
- }
+ length = gcov_var.offset - offset - 2;
+ buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset];
+ buffer[1] = length;
if (gcov_var.offset >= GCOV_BLOCK_SIZE)
gcov_write_block (gcov_var.offset);
}
GCOV_LINKAGE void
gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length)
{
- unsigned char *buffer = gcov_write_bytes (8);
- unsigned ix;
+ gcov_unsigned_t *buffer = gcov_write_words (2);
- for (ix = 4; ix--; )
- {
- buffer[ix] = tag;
- tag >>= 8;
- }
- for (ix = 4; ix--; )
- {
- buffer[ix + 4] = length;
- length >>= 8;
- }
- return;
+ buffer[0] = tag;
+ buffer[1] = length;
}
/* Write a summary structure to the gcov file. Return nonzero on
/* 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)
+static const gcov_unsigned_t *
+gcov_read_words (unsigned words)
{
- const unsigned char *result;
+ const gcov_unsigned_t *result;
unsigned excess = gcov_var.length - gcov_var.offset;
- GCOV_CHECK_READING ();
- if (excess < bytes)
+ gcc_assert (gcov_var.mode > 0);
+ if (excess < words)
{
gcov_var.start += gcov_var.offset;
#if IN_LIBGCOV
if (excess)
{
- GCOV_CHECK (excess == 4);
+ gcc_assert (excess == 1);
memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4);
}
#else
- memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess);
+ memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4);
#endif
gcov_var.offset = 0;
gcov_var.length = excess;
#if IN_LIBGCOV
- GCOV_CHECK (!gcov_var.length || gcov_var.length == 4);
+ gcc_assert (!gcov_var.length || gcov_var.length == 1);
excess = GCOV_BLOCK_SIZE;
#else
- if (gcov_var.length + bytes > gcov_var.alloc)
- gcov_allocate (gcov_var.length + bytes);
+ if (gcov_var.length + words > gcov_var.alloc)
+ gcov_allocate (gcov_var.length + words);
excess = gcov_var.alloc - gcov_var.length;
#endif
excess = fread (gcov_var.buffer + gcov_var.length,
- 1, excess, gcov_var.file);
+ 1, excess << 2, gcov_var.file) >> 2;
gcov_var.length += excess;
- if (gcov_var.length < bytes)
+ if (gcov_var.length < words)
{
- gcov_var.overread += bytes - gcov_var.length;
+ gcov_var.overread += words - gcov_var.length;
gcov_var.length = 0;
return 0;
}
}
result = &gcov_var.buffer[gcov_var.offset];
- gcov_var.offset += bytes;
+ gcov_var.offset += words;
return result;
}
GCOV_LINKAGE gcov_unsigned_t
gcov_read_unsigned (void)
{
- gcov_unsigned_t value = 0;
- unsigned ix;
- const unsigned char *buffer = gcov_read_bytes (4);
+ gcov_unsigned_t value;
+ const gcov_unsigned_t *buffer = gcov_read_words (1);
if (!buffer)
return 0;
- for (ix = sizeof (value); ix < 4; ix++)
- if (buffer[ix])
- gcov_var.error = -1;
- for (ix = 0; ix != 4; ix++)
- {
- value <<= 8;
- value |= buffer[ix];
- }
+ value = from_file (buffer[0]);
return value;
}
GCOV_LINKAGE gcov_type
gcov_read_counter (void)
{
- gcov_type value = 0;
- unsigned ix;
- const unsigned char *buffer = gcov_read_bytes (8);
+ gcov_type value;
+ const gcov_unsigned_t *buffer = gcov_read_words (2);
if (!buffer)
return 0;
- for (ix = sizeof (value); ix < 8; ix++)
- if (buffer[ix])
- gcov_var.error = -1;
- for (ix = 0; ix != 8; ix++)
- {
- value <<= 8;
- value |= buffer[ix];
- }
- if (value < 0)
+ value = from_file (buffer[0]);
+ if (sizeof (value) > sizeof (gcov_unsigned_t))
+ value |= ((gcov_type) from_file (buffer[1])) << 32;
+ else if (buffer[1])
gcov_var.error = -1;
+
return value;
}
if (!length)
return 0;
- length += 4 - (length & 3);
- return (const char *) gcov_read_bytes (length);
+ return (const char *) gcov_read_words (length);
}
#endif
GCOV_LINKAGE void
gcov_sync (gcov_position_t base, gcov_unsigned_t length)
{
- GCOV_CHECK_READING ();
+ gcc_assert (gcov_var.mode > 0);
base += length;
if (base - gcov_var.start <= gcov_var.length)
gcov_var.offset = base - gcov_var.start;
else
{
gcov_var.offset = gcov_var.length = 0;
- fseek (gcov_var.file, base, SEEK_SET);
- gcov_var.start = ftell (gcov_var.file);
+ fseek (gcov_var.file, base << 2, SEEK_SET);
+ gcov_var.start = ftell (gcov_var.file) >> 2;
}
}
#endif
#if IN_LIBGCOV
-/* Move to the a set position in a gcov file. BASE is zero to move to
- the end, and nonzero to move to that position. */
+/* Move to a given position in a gcov file. */
GCOV_LINKAGE void
gcov_seek (gcov_position_t base)
{
- GCOV_CHECK_WRITING ();
+ gcc_assert (gcov_var.mode < 0);
if (gcov_var.offset)
gcov_write_block (gcov_var.offset);
- fseek (gcov_var.file, base, base ? SEEK_SET : SEEK_END);
- gcov_var.start = ftell (gcov_var.file);
+ fseek (gcov_var.file, base << 2, SEEK_SET);
+ gcov_var.start = ftell (gcov_var.file) >> 2;
}
#endif