From 80abd9e48ad1b4de289b09cc79163ed49ac7b579 Mon Sep 17 00:00:00 2001 From: nathan Date: Wed, 14 May 2003 16:01:20 +0000 Subject: [PATCH] * gcov-io.h (gcov_write_bytes, gcov_read_bytes): Remove here. (GCOV_TAG_*) Force type to gcov_unsigned_t. (GCOV_CHECK, GCOV_CHECK_READING, GCOV_CHECK_WRITING): New. (struct gcov_var): Remove modified. Add start, length, offset, overread. Have buffer array for libgcov. (gcov_sync, gcov_seek): Definitions moved to gcov-io.c. (gcov_position, gcov_rewrite, gcov_is_eof): Adjust. * gcov-io.c (gcov_open): Set mode, do not read anything. (gcov_close): Write final block. (gcov_write_block, gcov_allocate): New. (gcov_write_bytes): Make static. Write or allocate buffer. (gcov_write_unsigned, gcov_write_counter): Buffer can never be null. (gcov_write_string): Adjust. (gcov_write_tag) (gcov_write_length): Adjust. Flush the block. (gcov_write_tag_length): Buffer can never be null. (gcov_read_bytes): Make static. Read in block. (gcov_sync): Moved here. Adjust. (gcov_seek): Moved here. Adjust. * coverage.c (read_counts_file): Adjust. * gcov-dump.c (print_prefix): Add position parameter. (flag_dump_positions): New flag. (options, main, print_usage): Add it. (dump_file, tag_blocks, tag_arcs, tag_lines, tag_counters, tag_summary): Adjust. * gcov.c (read_graph_file, read_count_file): Adjust. * libgcov.c (gcov_exit): Adjust. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@66805 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 29 ++++++ gcc/coverage.c | 24 ++--- gcc/gcov-dump.c | 89 ++++++++++++------ gcc/gcov-io.c | 274 +++++++++++++++++++++++++++++++++----------------------- gcc/gcov-io.h | 202 ++++++++++++++++++++++------------------- gcc/gcov.c | 41 +++++---- gcc/libgcov.c | 32 ++++--- 7 files changed, 413 insertions(+), 278 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b449645..f8af6e7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,34 @@ 2003-05-14 Nathan Sidwell + * gcov-io.h (gcov_write_bytes, gcov_read_bytes): Remove here. + (GCOV_TAG_*) Force type to gcov_unsigned_t. + (GCOV_CHECK, GCOV_CHECK_READING, GCOV_CHECK_WRITING): New. + (struct gcov_var): Remove modified. Add start, length, offset, + overread. Have buffer array for libgcov. + (gcov_sync, gcov_seek): Definitions moved to gcov-io.c. + (gcov_position, gcov_rewrite, gcov_is_eof): Adjust. + * gcov-io.c (gcov_open): Set mode, do not read anything. + (gcov_close): Write final block. + (gcov_write_block, gcov_allocate): New. + (gcov_write_bytes): Make static. Write or allocate buffer. + (gcov_write_unsigned, gcov_write_counter): Buffer can never be + null. + (gcov_write_string): Adjust. + (gcov_write_tag) + (gcov_write_length): Adjust. Flush the block. + (gcov_write_tag_length): Buffer can never be null. + (gcov_read_bytes): Make static. Read in block. + (gcov_sync): Moved here. Adjust. + (gcov_seek): Moved here. Adjust. + * coverage.c (read_counts_file): Adjust. + * gcov-dump.c (print_prefix): Add position parameter. + (flag_dump_positions): New flag. + (options, main, print_usage): Add it. + (dump_file, tag_blocks, tag_arcs, tag_lines, tag_counters, + tag_summary): Adjust. + * gcov.c (read_graph_file, read_count_file): Adjust. + * libgcov.c (gcov_exit): Adjust. + * Makefile.in (LIBGCC_DEPS): Use $(srcdir) on gcov files (libgcov.a): Depend on libgcc.a. (gcov.o, gcov-dump.o): Add gcov-io.c. diff --git a/gcc/coverage.c b/gcc/coverage.c index 5926a7e..1b537c6 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -158,7 +158,9 @@ read_counts_file () unsigned ix; counts_entry_t *summaried = NULL; unsigned seen_summary = 0; - + gcov_unsigned_t tag; + int error = 0; + if (!gcov_open (da_file_name, 1)) return; @@ -187,13 +189,11 @@ read_counts_file () counts_hash = htab_create (10, htab_counts_entry_hash, htab_counts_entry_eq, htab_counts_entry_del); - while (!gcov_is_eof ()) + while ((tag = gcov_read_unsigned ())) { - gcov_unsigned_t tag, length; + gcov_unsigned_t length; gcov_position_t offset; - int error; - tag = gcov_read_unsigned (); length = gcov_read_unsigned (); offset = gcov_position (); if (tag == GCOV_TAG_FUNCTION) @@ -284,14 +284,16 @@ read_counts_file () } gcov_sync (offset, length); if ((error = gcov_is_error ())) - { - warning (error < 0 ? "`%s' has overflowed" : "`%s' is corrupted", - da_file_name); - htab_delete (counts_hash); - break; - } + break; } + if (!gcov_is_eof ()) + { + warning (error < 0 ? "`%s' has overflowed" : "`%s' is corrupted", + da_file_name); + htab_delete (counts_hash); + } + gcov_close (); } diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c index d70e4dd..c7c31ad 100644 --- a/gcc/gcov-dump.c +++ b/gcc/gcov-dump.c @@ -28,7 +28,7 @@ Boston, MA 02111-1307, USA. */ #include "gcov-io.c" static void dump_file PARAMS ((const char *)); -static void print_prefix PARAMS ((const char *, unsigned)); +static void print_prefix PARAMS ((const char *, unsigned, gcov_position_t)); static void print_usage PARAMS ((void)); static void print_version PARAMS ((void)); static void tag_function PARAMS ((const char *, unsigned, unsigned)); @@ -47,12 +47,14 @@ typedef struct tag_format } tag_format_t; static int flag_dump_contents = 0; +static int flag_dump_positions = 0; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "long", no_argument, NULL, 'l' }, + { "positions", no_argument, NULL, 'o' }, }; static const tag_format_t tag_table[] = @@ -75,7 +77,7 @@ int main (argc, argv) { int opt; - while ((opt = getopt_long (argc, argv, "hlv", options, NULL)) != -1) + while ((opt = getopt_long (argc, argv, "hlpv", options, NULL)) != -1) { switch (opt) { @@ -88,6 +90,9 @@ int main (argc, argv) case 'l': flag_dump_contents = 1; break; + case 'p': + flag_dump_positions = 1; + break; default: fprintf (stderr, "unknown flag `%c'\n", opt); } @@ -106,6 +111,7 @@ print_usage () printf (" -h, --help Print this help\n"); printf (" -v, --version Print version number\n"); printf (" -l, --long Dump record contents too\n"); + printf (" -p, --positions Dump record positions\n"); } static void @@ -124,13 +130,17 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } static void -print_prefix (filename, depth) +print_prefix (filename, depth, position) const char *filename; unsigned depth; + gcov_position_t position; { static const char prefix[] = " "; - printf ("%s:%.*s", filename, (int) depth, prefix); + printf ("%s:", filename); + if (flag_dump_positions) + printf ("%lu:", (unsigned long) position); + printf ("%.*s", (int) depth, prefix); } static void @@ -178,30 +188,29 @@ dump_file (filename) printf ("%s:warning:current version is `%.4s'\n", filename, e); } - while (!gcov_is_eof ()) + while (1) { - unsigned tag = gcov_read_unsigned (); - unsigned length = gcov_read_unsigned (); - unsigned long base = gcov_position (); + gcov_position_t base, position = gcov_position (); + unsigned tag, length; tag_format_t const *format; unsigned tag_depth; int error; - + unsigned mask; + + tag = gcov_read_unsigned (); if (!tag) - tag_depth = depth; - else + break; + length = gcov_read_unsigned (); + base = gcov_position (); + mask = GCOV_TAG_MASK (tag) >> 1; + for (tag_depth = 4; mask; mask >>= 8) { - unsigned mask = GCOV_TAG_MASK (tag) >> 1; - - for (tag_depth = 4; mask; mask >>= 8) + if ((mask & 0xff) != 0xff) { - if ((mask & 0xff) != 0xff) - { - printf ("%s:tag `%08x' is invalid\n", filename, tag); - break; - } - tag_depth--; + printf ("%s:tag `%08x' is invalid\n", filename, tag); + break; } + tag_depth--; } for (format = tag_table; format->name; format++) if (format->tag == tag) @@ -220,7 +229,7 @@ dump_file (filename) tags[depth - 1] = tag; } - print_prefix (filename, tag_depth); + print_prefix (filename, tag_depth, position); printf ("%08x:%4u:%s", tag, length, format->name); if (format->proc) (*format->proc) (filename, tag, length); @@ -246,6 +255,8 @@ dump_file (filename) break; } } + if (!gcov_is_eof ()) + printf ("%s:early end of file\n", filename); gcov_close (); } @@ -289,7 +300,11 @@ tag_blocks (filename, tag, length) for (ix = 0; ix != n_blocks; ix++) { if (!(ix & 7)) - printf ("\n%s:\t\t%u", filename, ix); + { + printf ("\n"); + print_prefix (filename, 0, gcov_position ()); + printf ("\t\t%u", ix); + } printf (" %04x", gcov_read_unsigned ()); } } @@ -311,11 +326,16 @@ tag_arcs (filename, tag, length) for (ix = 0; ix != n_arcs; ix++) { - unsigned dst = gcov_read_unsigned (); - unsigned flags = gcov_read_unsigned (); + unsigned dst, flags; if (!(ix & 3)) - printf ("\n%s:\tblock %u:", filename, blockno); + { + printf ("\n"); + print_prefix (filename, 0, gcov_position ()); + printf ("\tblock %u:", blockno); + } + dst = gcov_read_unsigned (); + flags = gcov_read_unsigned (); printf (" %u:%04x", dst, flags); } } @@ -334,6 +354,7 @@ tag_lines (filename, tag, length) while (1) { + gcov_position_t position = gcov_position (); const char *source = NULL; unsigned lineno = gcov_read_unsigned (); @@ -347,7 +368,9 @@ tag_lines (filename, tag, length) if (!sep) { - printf ("\n%s:\tblock %u:", filename, blockno); + printf ("\n"); + print_prefix (filename, 0, position); + printf ("\tblock %u:", blockno); sep = ""; } if (lineno) @@ -381,10 +404,16 @@ tag_counters (filename, tag, length) for (ix = 0; ix != n_counts; ix++) { - gcov_type count = gcov_read_counter (); + gcov_type count; if (!(ix & 7)) - printf ("\n%s:\t\t%u", filename, ix); + { + printf ("\n"); + print_prefix (filename, 0, gcov_position ()); + printf ("\t\t%u", ix); + } + + count = gcov_read_counter (); printf (" "); printf (HOST_WIDEST_INT_PRINT_DEC, count); } @@ -405,7 +434,9 @@ tag_summary (filename, tag, length) for (ix = 0; ix != GCOV_COUNTERS; ix++) { - printf ("\n%sL\t\tcounts=%u, runs=%u", filename, + printf ("\n"); + print_prefix (filename, 0, 0); + printf ("\t\tcounts=%u, runs=%u", summary.ctrs[ix].num, summary.ctrs[ix].runs); printf (", sum_all=" HOST_WIDEST_INT_PRINT_DEC, diff --git a/gcc/gcov-io.c b/gcc/gcov-io.c index d61cff3..3aad30e 100644 --- a/gcc/gcov-io.c +++ b/gcc/gcov-io.c @@ -24,6 +24,15 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* 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); +#endif +static const unsigned char *gcov_read_bytes (unsigned); +#if !IN_LIBGCOV +static void gcov_allocate (unsigned); +#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 @@ -36,7 +45,6 @@ GCOV_LINKAGE int gcov_open (const char *name, int mode) { int result = 1; - size_t alloc = 1024; #if GCOV_LOCKED struct flock s_flock; @@ -49,63 +57,32 @@ gcov_open (const char *name, int mode) if (gcov_var.file) abort (); - gcov_var.position = gcov_var.length = 0; - gcov_var.error = gcov_var.modified = 0; + gcov_var.start = 0; + gcov_var.offset = gcov_var.length = 0; + gcov_var.overread = -4u; + gcov_var.error = 0; if (mode >= 0) gcov_var.file = fopen (name, "r+b"); - if (!gcov_var.file && mode <= 0) + 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; } if (!gcov_var.file) return 0; + setbuf (gcov_var.file, (char *)0); + #if GCOV_LOCKED while (fcntl (fileno (gcov_var.file), F_SETLKW, &s_flock) && errno == EINTR) continue; #endif - if (result >= 0) - { - if (fseek (gcov_var.file, 0, SEEK_END)) - { - fclose (gcov_var.file); - gcov_var.file = 0; - return 0; - } - gcov_var.length = ftell (gcov_var.file); - fseek (gcov_var.file, 0, SEEK_SET); - alloc += gcov_var.length; - } - if (alloc > gcov_var.alloc) - { - if (gcov_var.buffer) - free (gcov_var.buffer); - gcov_var.alloc = alloc; -#if IN_LIBGCOV - gcov_var.buffer = malloc (gcov_var.alloc); - if (!gcov_var.buffer) - { - fclose (gcov_var.file); - gcov_var.file = 0; - gcov_var.length = 0; - gcov_var.alloc = 0; - return 0; - } -#else - gcov_var.buffer = xmalloc (gcov_var.alloc); -#endif - } - if (result >= 0 - && fread (gcov_var.buffer, gcov_var.length, 1, gcov_var.file) != 1) - { - fclose (gcov_var.file); - gcov_var.file = 0; - gcov_var.length = 0; - return 0; - } return result; } @@ -115,15 +92,12 @@ gcov_open (const char *name, int mode) GCOV_LINKAGE int gcov_close () { - int result = 0; - if (gcov_var.file) { - if (gcov_var.modified - && (fseek (gcov_var.file, 0, SEEK_SET) - || fwrite (gcov_var.buffer, gcov_var.length, - 1, gcov_var.file) != 1)) - result = 1; +#if !IN_GCOV + if (gcov_var.offset && gcov_var.mode < 0) + gcov_write_block (gcov_var.offset); +#endif fclose (gcov_var.file); gcov_var.file = 0; gcov_var.length = 0; @@ -133,47 +107,64 @@ gcov_close () gcov_var.alloc = 0; gcov_var.buffer = 0; #endif - return result ? 1 : gcov_var.error; + gcov_var.mode = 0; + return gcov_var.error; +} + +#if !IN_LIBGCOV +static void +gcov_allocate (unsigned length) +{ + size_t new_size = gcov_var.alloc; + + if (!new_size) + new_size = GCOV_BLOCK_SIZE; + new_size += length; + new_size *= 2; + + gcov_var.alloc = new_size; + gcov_var.buffer = xrealloc (gcov_var.buffer, new_size); } +#endif #if !IN_GCOV +/* Write out the current block, if needs be. */ + +static void +gcov_write_block (unsigned size) +{ + if (fwrite (gcov_var.buffer, size, 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. */ -GCOV_LINKAGE unsigned char * +static unsigned char * gcov_write_bytes (unsigned bytes) { char unsigned *result; - if (gcov_var.position + bytes > gcov_var.alloc) - { - size_t new_size = (gcov_var.alloc + bytes) * 3 / 2; - - if (!gcov_var.buffer) - return 0; + GCOV_CHECK_WRITING (); #if IN_LIBGCOV - result = realloc (gcov_var.buffer, new_size); - if (!result) + if (gcov_var.offset >= GCOV_BLOCK_SIZE) + { + gcov_write_block (GCOV_BLOCK_SIZE); + if (gcov_var.offset) { - free (gcov_var.buffer); - gcov_var.buffer = 0; - gcov_var.alloc = 0; - gcov_var.position = gcov_var.length = 0; - gcov_var.error = 1; - return 0; + GCOV_CHECK (gcov_var.offset == 4); + memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4); } + } #else - result = xrealloc (gcov_var.buffer, new_size); + if (gcov_var.offset + bytes > gcov_var.alloc) + gcov_allocate (gcov_var.offset + bytes); #endif - gcov_var.alloc = new_size; - gcov_var.buffer = result; - } + result = &gcov_var.buffer[gcov_var.offset]; + gcov_var.offset += bytes; - result = &gcov_var.buffer[gcov_var.position]; - gcov_var.position += bytes; - gcov_var.modified = 1; - if (gcov_var.position > gcov_var.length) - gcov_var.length = gcov_var.position; return result; } @@ -186,8 +177,6 @@ gcov_write_unsigned (gcov_unsigned_t value) unsigned char *buffer = gcov_write_bytes (4); unsigned ix; - if (!buffer) - return; for (ix = 4; ix--; ) { buffer[ix] = value; @@ -209,8 +198,6 @@ gcov_write_counter (gcov_type value) unsigned char *buffer = gcov_write_bytes (8); unsigned ix; - if (!buffer) - return; for (ix = 8; ix--; ) { buffer[ix] = value; @@ -233,6 +220,8 @@ gcov_write_string (const char *string) unsigned pad = 0; unsigned rem = 0; unsigned char *buffer; + unsigned ix; + unsigned value; if (string) { @@ -241,19 +230,15 @@ gcov_write_string (const char *string) } buffer = gcov_write_bytes (4 + length + rem); - if (buffer) + + value = length; + for (ix = 4; ix--; ) { - unsigned ix; - unsigned value = length; - - for (ix = 4; ix--; ) - { - buffer[ix] = value; - value >>= 8; - } - memcpy (buffer + 4, string, length); - memcpy (buffer + 4 + length, &pad, rem); + buffer[ix] = value; + value >>= 8; } + memcpy (buffer + 4, string, length); + memcpy (buffer + 4 + length, &pad, rem); } #endif @@ -264,12 +249,10 @@ gcov_write_string (const char *string) GCOV_LINKAGE gcov_position_t gcov_write_tag (gcov_unsigned_t tag) { - gcov_position_t result = gcov_var.position; + gcov_position_t result = gcov_var.start + gcov_var.offset; unsigned char *buffer = gcov_write_bytes (8); unsigned ix; - if (!buffer) - return 0; for (ix = 4; ix--; ) { buffer[ix] = tag; @@ -287,18 +270,24 @@ gcov_write_tag (gcov_unsigned_t tag) GCOV_LINKAGE void gcov_write_length (gcov_position_t position) { - if (position) + unsigned offset; + gcov_unsigned_t length; + unsigned char *buffer; + unsigned ix; + + GCOV_CHECK_WRITING (); + GCOV_CHECK (position + 8 <= gcov_var.start + gcov_var.offset); + GCOV_CHECK (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--; ) { - gcov_unsigned_t length = gcov_var.position - position - 8; - unsigned char *buffer = &gcov_var.buffer[position + 4]; - unsigned ix; - - for (ix = 4; ix--; ) - { - buffer[ix] = length; - length >>= 8; - } + buffer[ix] = length; + length >>= 8; } + if (gcov_var.offset >= GCOV_BLOCK_SIZE) + gcov_write_block (gcov_var.offset); } #else /* IN_LIBGCOV */ @@ -311,8 +300,6 @@ gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length) unsigned char *buffer = gcov_write_bytes (8); unsigned ix; - if (!buffer) - return; for (ix = 4; ix--; ) { buffer[ix] = tag; @@ -353,19 +340,47 @@ gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary) /* Return a pointer to read BYTES bytes from the gcov file. Returns NULL on failure (read past EOF). */ -GCOV_LINKAGE const unsigned char * +static const unsigned char * gcov_read_bytes (unsigned bytes) { const unsigned char *result; + unsigned excess = gcov_var.length - gcov_var.offset; - if (gcov_var.position + bytes > gcov_var.length) + GCOV_CHECK_READING (); + if (excess < bytes) { - gcov_var.error = 1; - return 0; + gcov_var.start += gcov_var.offset; +#if IN_LIBGCOV + if (excess) + { + GCOV_CHECK (excess == 4); + memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4); + } +#else + memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess); +#endif + gcov_var.offset = 0; + gcov_var.length = excess; +#if IN_LIBGCOV + GCOV_CHECK (!gcov_var.length || gcov_var.length == 4); + excess = GCOV_BLOCK_SIZE; +#else + if (gcov_var.length + bytes > gcov_var.alloc) + gcov_allocate (gcov_var.length + bytes); + excess = gcov_var.alloc - gcov_var.length; +#endif + excess = fread (gcov_var.buffer + gcov_var.offset, + 1, excess, gcov_var.file); + gcov_var.length += excess; + if (gcov_var.length < bytes) + { + gcov_var.overread += bytes - gcov_var.length; + gcov_var.length = 0; + return 0; + } } - - result = &gcov_var.buffer[gcov_var.position]; - gcov_var.position += bytes; + result = &gcov_var.buffer[gcov_var.offset]; + gcov_var.offset += bytes; return result; } @@ -452,6 +467,41 @@ gcov_read_summary (struct gcov_summary *summary) } } +#if !IN_LIBGCOV +/* Reset to a known position. BASE should have been obtained from + gcov_position, LENGTH should be a record length. */ + +GCOV_LINKAGE void +gcov_sync (gcov_position_t base, gcov_unsigned_t length) +{ + GCOV_CHECK_READING (); + 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); + } +} +#endif + +#if IN_LIBGCOV +/* Move to the a set position in a gcov file. BASE is zero to move to + the end, and non-zero to move to that position. */ + +GCOV_LINKAGE void +gcov_seek (gcov_position_t base) +{ + GCOV_CHECK_WRITING (); + 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); +} +#endif + #if IN_GCOV > 0 /* Return the modification time of the current gcov file. */ diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h index f739653..e6cf94e 100644 --- a/gcc/gcov-io.h +++ b/gcc/gcov-io.h @@ -202,35 +202,31 @@ typedef HOST_WIDEST_INT gcov_type; #endif /* !IN_LIBGCOV */ -/* In gcov we want function linkage to be static, so we do not - polute the global namespace. In libgcov we need these functions - to be extern, so prefix them with __gcov so that we do not conflict. - In the compiler we want it extern, so that they can be accessed from +/* In gcov we want function linkage to be static. In libgcov we need + these functions to be extern, so prefix them with __gcov. In the + compiler we want it extern, so that they can be accessed from elsewhere. */ #if IN_LIBGCOV #define gcov_var __gcov_var #define gcov_open __gcov_open #define gcov_close __gcov_close -#define gcov_write_bytes __gcov_write_bytes +#define gcov_write_tag_length __gcov_write_tag_length +#define gcov_position __gcov_position +#define gcov_seek __gcov_seek +#define gcov_rewrite __gcov_rewrite +#define gcov_is_error __gcov_is_error +#define gcov_is_eof __gcov_is_eof #define gcov_write_unsigned __gcov_write_unsigned #define gcov_write_counter __gcov_write_counter -#pragma GCC poison gcov_write_string -#pragma GCC poison gcov_write_tag -#pragma GCC poison gcov_write_length -#define gcov_write_tag_length __gcov_write_tag_length #define gcov_write_summary __gcov_write_summary -#define gcov_read_bytes __gcov_read_bytes #define gcov_read_unsigned __gcov_read_unsigned #define gcov_read_counter __gcov_read_counter -#pragma GCC poison gcov_read_string #define gcov_read_summary __gcov_read_summary -#define gcov_position __gcov_position -#define gcov_sync __gcov_sync -#define gcov_seek __gcov_seek -#define gcov_rewrite __gcov_rewrite -#define gcov_is_eof __gcov_is_eof -#define gcov_is_error __gcov_is_error -#pragma GCC poison gcov_time + +/* Poison these, so they don't accidentally slip in. */ +#pragma GCC poison gcov_write_string gcov_write_tag gcov_write_length +#pragma GCC poison gcov_read_string gcov_sync gcov_time + #endif #ifndef GCOV_LINKAGE @@ -255,18 +251,19 @@ typedef HOST_WIDEST_INT gcov_type; file. Values [41..9f] for those in the bbg file and [a1..ff] for the data file. */ -#define GCOV_TAG_FUNCTION ((unsigned)0x01000000) +#define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000) #define GCOV_TAG_FUNCTION_LENGTH (2 * 4) -#define GCOV_TAG_BLOCKS ((unsigned)0x01410000) +#define GCOV_TAG_BLOCKS ((gcov_unsigned_t)0x01410000) #define GCOV_TAG_BLOCKS_LENGTH(NUM) ((NUM) * 4) -#define GCOV_TAG_ARCS ((unsigned)0x01430000) +#define GCOV_TAG_ARCS ((gcov_unsigned_t)0x01430000) #define GCOV_TAG_ARCS_LENGTH(NUM) (1 * 4 + (NUM) * (2 * 4)) -#define GCOV_TAG_LINES ((unsigned)0x01450000) -#define GCOV_TAG_COUNTER_BASE ((unsigned)0x01a10000) /* First counter */ +#define GCOV_TAG_LINES ((gcov_unsigned_t)0x01450000) +#define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t)0x01a10000) #define GCOV_TAG_COUNTER_LENGTH(NUM) ((NUM) * 8) -#define GCOV_TAG_OBJECT_SUMMARY ((unsigned)0xa1000000) -#define GCOV_TAG_PROGRAM_SUMMARY ((unsigned)0xa3000000) -#define GCOV_TAG_SUMMARY_LENGTH (1 * 4 + GCOV_COUNTERS_SUMMABLE * (2 * 4 + 3 * 8)) +#define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000) +#define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000) +#define GCOV_TAG_SUMMARY_LENGTH \ + (1 * 4 + GCOV_COUNTERS_SUMMABLE * (2 * 4 + 3 * 8)) /* Counters that are collected. */ #define GCOV_COUNTER_ARCS 0 /* Arc transitions. */ @@ -282,10 +279,10 @@ typedef HOST_WIDEST_INT gcov_type; /* Convert a counter index to a tag. */ #define GCOV_TAG_FOR_COUNTER(COUNT) \ - (GCOV_TAG_COUNTER_BASE + ((COUNT) << 17)) + (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t)(COUNT) << 17)) /* Convert a tag to a counter. */ #define GCOV_COUNTER_FOR_TAG(TAG) \ - (((TAG) - GCOV_TAG_COUNTER_BASE) >> 17) + ((unsigned)(((TAG) - GCOV_TAG_COUNTER_BASE) >> 17)) /* Check whether a tag is a counter tag. */ #define GCOV_TAG_IS_COUNTER(TAG) \ (!((TAG) & 0xFFFF) && GCOV_COUNTER_FOR_TAG (TAG) < GCOV_COUNTERS) @@ -387,114 +384,131 @@ extern void __gcov_merge_add (gcov_type *, unsigned); #if IN_LIBGCOV >= 0 -/* Because small reads and writes, interspersed with seeks cause lots - of disk activity, we buffer the entire count files. */ +/* Optimum size read from or written to disk. */ +#define GCOV_BLOCK_SIZE (1 << 12) GCOV_LINKAGE struct gcov_var { FILE *file; - gcov_position_t position; - gcov_position_t length; + gcov_position_t start; /* Position of first byte of block */ + unsigned offset; /* Read/write position within the block. */ + unsigned length; /* Read limit in the block. */ + unsigned overread; /* Number of bytes overread. */ + int error; /* < 0 overflow, > 0 disk error. */ + int mode; /* < 0 writing, > 0 reading */ +#if IN_LIBGCOV + /* Holds one block plus 4 bytes, thus all coverage reads & writes + fit within this buffer and we always can transfer GCOV_BLOCK_SIZE + to and from the disk. libgcov never backtracks and only writes 4 + or 8 byte objects. */ + unsigned char buffer[GCOV_BLOCK_SIZE + 4]; +#else + /* Holds a variable length block, as the compiler can write + strings and needs to backtrack. */ size_t alloc; - unsigned modified; - int error; unsigned char *buffer; +#endif } gcov_var; -/* Functions for reading and writing gcov files. */ +/* Functions for reading and writing gcov files. You can open a file + for (1) reading or (2) writing or (3) reading then rewriting. When + reading a file you may use the gcov_read_* functions, gcov_sync, + gcov_position, & gcov_error. When writing a file you + may use the gcov_write functions, gcov_seek & gcov_error. When a + file is to be rewritten you use the functions for reading, then + gcov_rewrite then the functions for writing. Your file may become + corrupted if you break these invariants. */ GCOV_LINKAGE int gcov_open (const char */*name*/, int /*truncate*/); GCOV_LINKAGE int gcov_close (void); -#if !IN_GCOV -GCOV_LINKAGE unsigned char *gcov_write_bytes (unsigned); -GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t); + +/* Available everywhere. */ +static gcov_position_t gcov_position (void); +static int gcov_is_error (void); +static int gcov_is_eof (void); + +GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void); +GCOV_LINKAGE gcov_type gcov_read_counter (void); +GCOV_LINKAGE void gcov_read_summary (struct gcov_summary *); + #if IN_LIBGCOV +/* Available only in libgcov */ GCOV_LINKAGE void gcov_write_counter (gcov_type); -#else -GCOV_LINKAGE void gcov_write_string (const char *); -#endif -#if !IN_LIBGCOV -GCOV_LINKAGE gcov_position_t gcov_write_tag (gcov_unsigned_t); -GCOV_LINKAGE void gcov_write_length (gcov_position_t /*position*/); -#else GCOV_LINKAGE void gcov_write_tag_length (gcov_unsigned_t, gcov_unsigned_t); GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/, const struct gcov_summary *); -#endif -#endif /* !IN_GCOV */ -GCOV_LINKAGE const unsigned char *gcov_read_bytes (unsigned); -GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void); -GCOV_LINKAGE gcov_type gcov_read_counter (void); -#if !IN_LIBGCOV +static void gcov_rewrite (void); +GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/); +#else +/* Available outside libgcov */ GCOV_LINKAGE const char *gcov_read_string (void); +GCOV_LINKAGE void gcov_sync (gcov_position_t /*base*/, + gcov_unsigned_t /*length */); #endif -GCOV_LINKAGE void gcov_read_summary (struct gcov_summary *); -static gcov_position_t gcov_position (void); -static void gcov_sync (gcov_position_t /*base*/, gcov_unsigned_t /*length */); -static void gcov_seek (gcov_position_t /*position*/); -static void gcov_rewrite (void); -static int gcov_is_eof (void); -static int gcov_is_error (void); + +#if !IN_GCOV +/* Available outside gcov */ +GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t); +#endif + +#if !IN_GCOV && !IN_LIBGCOV +/* Available only in compiler */ +GCOV_LINKAGE void gcov_write_string (const char *); +GCOV_LINKAGE gcov_position_t gcov_write_tag (gcov_unsigned_t); +GCOV_LINKAGE void gcov_write_length (gcov_position_t /*position*/); +#endif + #if IN_GCOV > 0 +/* Available in gcov */ GCOV_LINKAGE time_t gcov_time (void); #endif +/* Make sure the library is used correctly. */ +#if ENABLE_CHECKING +#define GCOV_CHECK(expr) ((expr) ? (void)0 : (void)abort ()) +#else +#define GCOV_CHECK(expr) +#endif +#define GCOV_CHECK_READING() GCOV_CHECK(gcov_var.mode > 0) +#define GCOV_CHECK_WRITING() GCOV_CHECK(gcov_var.mode < 0) + /* Save the current position in the gcov file. */ static inline gcov_position_t gcov_position (void) { - return gcov_var.position; + GCOV_CHECK_READING (); + return gcov_var.start + gcov_var.offset; } -/* Reset to a known position. BASE should have been obtained from - gcov_save_position, LENGTH should be a record length, or zero. */ +/* Return non-zero if we read to end of file. */ -static inline void -gcov_sync (gcov_position_t base, gcov_unsigned_t length) +static inline int +gcov_is_eof () { - if (gcov_var.buffer) - { - base += length; - if (gcov_var.length < base) - { - gcov_var.error = 1; - base = gcov_var.length; - } - gcov_var.position = base; - } + return !gcov_var.overread; } -/* Move to the end of the gcov file. */ +/* Return non-zero if the error flag is set. */ -static inline void -gcov_seek (gcov_position_t base) +static inline int +gcov_is_error () { - gcov_var.position = base < gcov_var.length ? base : gcov_var.length; + return gcov_var.file ? gcov_var.error : 1; } +#if IN_LIBGCOV /* Move to beginning of file and intialize for writing. */ static inline void gcov_rewrite (void) { - gcov_var.position = 0; -} - -/* Tests whether we have reached end of .da file. */ - -static inline int -gcov_is_eof () -{ - return gcov_var.position == gcov_var.length; -} - -/* Return non-zero if the error flag is set. */ - -static inline int -gcov_is_error () -{ - return gcov_var.file ? gcov_var.error : 1; + GCOV_CHECK_READING (); + gcov_var.mode = -1; + gcov_var.start = 0; + gcov_var.offset = 0; + fseek (gcov_var.file, 0L, SEEK_SET); } +#endif #endif /* IN_LIBGCOV >= 0 */ diff --git a/gcc/gcov.c b/gcc/gcov.c index 2225f02..32590cb 100644 --- a/gcc/gcov.c +++ b/gcc/gcov.c @@ -711,7 +711,8 @@ read_graph_file () struct function_info *fn = NULL; source_t *src = NULL; unsigned ix; - + unsigned tag; + if (!gcov_open (bbg_file_name, 1)) { fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name); @@ -740,11 +741,10 @@ read_graph_file () bbg_file_name, v, e); } - while (!gcov_is_eof ()) + while ((tag = gcov_read_unsigned ())) { - unsigned tag = gcov_read_unsigned (); unsigned length = gcov_read_unsigned (); - unsigned long base = gcov_position (); + gcov_position_t base = gcov_position (); if (tag == GCOV_TAG_FUNCTION) { @@ -906,12 +906,14 @@ read_graph_file () } gcov_sync (base, length); if (gcov_is_error ()) - { - corrupt:; - fnotice (stderr, "%s:corrupted\n", bbg_file_name); - gcov_close (); - return 1; - } + break; + } + if (!gcov_is_eof ()) + { + corrupt:; + fnotice (stderr, "%s:corrupted\n", bbg_file_name); + gcov_close (); + return 1; } gcov_close (); @@ -976,7 +978,9 @@ read_count_file () { unsigned ix; unsigned version; + unsigned tag; function_t *fn = NULL; + int error = 0; if (!gcov_open (da_file_name, 1)) { @@ -1005,12 +1009,10 @@ read_count_file () da_file_name, v, e); } - while (!gcov_is_eof ()) + while ((tag = gcov_read_unsigned ())) { - unsigned tag = gcov_read_unsigned (); unsigned length = gcov_read_unsigned (); unsigned long base = gcov_position (); - int error; if (tag == GCOV_TAG_OBJECT_SUMMARY) gcov_read_summary (&object_summary); @@ -1061,13 +1063,16 @@ read_count_file () } gcov_sync (base, length); if ((error = gcov_is_error ())) - { - fnotice (stderr, error < 0 - ? "%s:overflowed\n" : "%s:corrupted\n", da_file_name); - goto cleanup; - } + break; } + if (!gcov_is_eof ()) + { + fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n", + da_file_name); + goto cleanup; + } + gcov_close (); return 0; } diff --git a/gcc/libgcov.c b/gcc/libgcov.c index 221eae4..ba54281 100644 --- a/gcc/libgcov.c +++ b/gcc/libgcov.c @@ -152,10 +152,10 @@ gcov_exit (void) const struct gcov_ctr_info *ci_ptr; struct gcov_ctr_summary *cs_ptr; struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all; - int error; + int error = 0; int merging; gcov_unsigned_t tag, length; - gcov_position_t summary_pos = ~(gcov_position_t)0; + gcov_position_t summary_pos = 0; /* Totals for this object file. */ memset (&this_object, 0, sizeof (this_object)); @@ -256,12 +256,14 @@ gcov_exit (void) } /* Check program & object summary */ - while (!gcov_is_eof ()) + while (1) { gcov_position_t base = gcov_position (); int is_program; tag = gcov_read_unsigned (); + if (!tag) + break; length = gcov_read_unsigned (); is_program = tag == GCOV_TAG_PROGRAM_SUMMARY; if (length != GCOV_TAG_SUMMARY_LENGTH @@ -269,24 +271,26 @@ gcov_exit (void) goto read_mismatch; gcov_read_summary (is_program ? &program : &object); if ((error = gcov_is_error ())) + goto read_error; + if (is_program && program.checksum == gcov_crc32) { - read_error:; - fprintf (stderr, error < 0 ? - "profiling:%s:Overflow merging\n" : - "profiling:%s:Error merging\n", gi_ptr->filename); - goto read_fatal; + summary_pos = base; + goto rewrite; } - - if (!is_program || program.checksum != gcov_crc32) - continue; - summary_pos = base; - break; } + if (!gcov_is_eof ()) + { + read_error:; + fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n" + : "profiling:%s:Error merging\n", gi_ptr->filename); + goto read_fatal; + } + rewrite:; gcov_rewrite (); } else memset (&object, 0, sizeof (object)); - if (!(summary_pos + 1)) + if (!summary_pos) memset (&program, 0, sizeof (program)); /* Merge the summaries. */ -- 2.7.4