X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgcov.c;h=c988730e38a74763b454632a8206944e434268ca;hb=34d2ae7f01a3522bde5149aef4a883795eb60004;hp=4c92170ebbf282894e06f27de79fea93b10ff340;hpb=4eb7b61f2c1c20024050339e57a2aee041147ec4;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/gcov.c b/gcc/gcov.c index 4c92170ebbf..c988730e38a 100644 --- a/gcc/gcov.c +++ b/gcc/gcov.c @@ -1,7 +1,7 @@ /* Gcov.c: prepend line execution counts and branch probabilities to a source file. Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, - 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by James E. Wilson of Cygnus Support. Mangled by Bob Manson of Cygnus Support. Mangled further by Nathan Sidwell @@ -82,6 +82,8 @@ typedef struct arc_info /* transition counts. */ gcov_type count; + /* used in cycle search, so that we do not clobber original counts. */ + gcov_type cs_count; unsigned int count_valid : 1; unsigned int on_tree : 1; @@ -102,7 +104,7 @@ typedef struct arc_info /* Next branch on line. */ struct arc_info *line_next; - + /* Links to next arc on src and dst lists. */ struct arc_info *succ_next; struct arc_info *pred_next; @@ -149,17 +151,17 @@ typedef struct block_info struct { /* Single line graph cycle workspace. Used for all-blocks - mode. */ + mode. */ arc_t *arc; unsigned ident; } cycle; /* Used in all-blocks mode, after blocks are linked onto - lines. */ + lines. */ } u; /* Temporary chain for solving graph, and for chaining blocks on one line. */ struct block_info *chain; - + } block_t; /* Describes a single function. Contains an array of basic blocks. */ @@ -186,7 +188,7 @@ typedef struct function_info /* Next function in same source file. */ struct function_info *line_next; - + /* Next function. */ struct function_info *next; } function_t; @@ -197,14 +199,14 @@ typedef struct coverage_info { int lines; int lines_executed; - + int branches; int branches_executed; int branches_taken; - + int calls; int calls_executed; - + char *name; } coverage_t; @@ -216,11 +218,11 @@ typedef struct line_info gcov_type count; /* execution count */ union { - arc_t *branches; /* branches from blocks that end on this + arc_t *branches; /* branches from blocks that end on this line. Used for branch-counts when not - all-blocks mode. */ + all-blocks mode. */ block_t *blocks; /* blocks which start on this line. Used - in all-blocks mode. */ + in all-blocks mode. */ } u; unsigned exists : 1; } line_t; @@ -243,7 +245,7 @@ typedef struct source_info /* Functions in this source file. These are in ascending line number order. */ function_t *functions; - + /* Next source file. */ struct source_info *next; } source_t; @@ -269,6 +271,9 @@ static time_t bbg_file_time; static char *bbg_file_name; +/* Stamp of the bbg file */ +static unsigned bbg_stamp; + /* Name and file pointer of the input file for the arc count data. */ static char *da_file_name; @@ -277,7 +282,7 @@ static char *da_file_name; static int flag_branches = 0; -/* Show unconditional branches too. */ +/* Show unconditional branches too. */ static int flag_unconditional = 0; /* Output a gcov file if this is true. This is on by default, and can @@ -317,34 +322,32 @@ static int flag_preserve_paths = 0; static int flag_counts = 0; /* Forward declarations. */ -static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2; -static int process_args PARAMS ((int, char **)); -static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN; -static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN; -static void process_file PARAMS ((const char *)); -static void create_file_names PARAMS ((const char *)); -static source_t *find_source PARAMS ((const char *)); -static int read_graph_file PARAMS ((void)); -static int read_count_file PARAMS ((void)); -static void solve_flow_graph PARAMS ((function_t *)); -static void add_branch_counts PARAMS ((coverage_t *, const arc_t *)); -static void add_line_counts PARAMS ((coverage_t *, function_t *)); -static void function_summary PARAMS ((const coverage_t *, const char *)); -static const char *format_gcov PARAMS ((gcov_type, gcov_type, int)); -static void accumulate_line_counts PARAMS ((source_t *)); -static int output_branch_count PARAMS ((FILE *, int, const arc_t *)); -static void output_lines PARAMS ((FILE *, const source_t *)); -static char *make_gcov_file_name PARAMS ((const char *, const char *)); -static void release_structures PARAMS ((void)); -extern int main PARAMS ((int, char **)); +static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2; +static int process_args (int, char **); +static void print_usage (int) ATTRIBUTE_NORETURN; +static void print_version (void) ATTRIBUTE_NORETURN; +static void process_file (const char *); +static void create_file_names (const char *); +static source_t *find_source (const char *); +static int read_graph_file (void); +static int read_count_file (void); +static void solve_flow_graph (function_t *); +static void add_branch_counts (coverage_t *, const arc_t *); +static void add_line_counts (coverage_t *, function_t *); +static void function_summary (const coverage_t *, const char *); +static const char *format_gcov (gcov_type, gcov_type, int); +static void accumulate_line_counts (source_t *); +static int output_branch_count (FILE *, int, const arc_t *); +static void output_lines (FILE *, const source_t *); +static char *make_gcov_file_name (const char *, const char *); +static void release_structures (void); +extern int main (int, char **); int -main (argc, argv) - int argc; - char **argv; +main (int argc, char **argv) { int argno; - + gcc_init_libintl (); argno = process_args (argc, argv); @@ -354,10 +357,10 @@ main (argc, argv) for (; argno != argc; argno++) { release_structures (); - + process_file (argv[argno]); } - + return 0; } @@ -365,7 +368,7 @@ static void fnotice (FILE *file, const char *msgid, ...) { va_list ap; - + va_start (ap, msgid); vfprintf (file, _(msgid), ap); va_end (ap); @@ -373,10 +376,10 @@ fnotice (FILE *file, const char *msgid, ...) /* More 'friendly' abort that prints the line and file. config.h can #define abort fancy_abort if you like that sort of thing. */ -extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN; +extern void fancy_abort (void) ATTRIBUTE_NORETURN; void -fancy_abort () +fancy_abort (void) { fnotice (stderr, "Internal gcov abort.\n"); exit (FATAL_EXIT_CODE); @@ -386,12 +389,11 @@ fancy_abort () otherwise the output of --help. */ static void -print_usage (error_p) - int error_p; +print_usage (int error_p) { FILE *file = error_p ? stderr : stdout; int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; - + fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n"); fnotice (file, "Print code coverage information.\n\n"); fnotice (file, " -h, --help Print this help, then exit\n"); @@ -415,19 +417,15 @@ print_usage (error_p) /* Print version information and exit. */ static void -print_version () +print_version (void) { - char v[4]; - unsigned version = GCOV_VERSION; - unsigned ix; - - for (ix = 4; ix--; version >>= 8) - v[ix] = version; - fnotice (stdout, "gcov %.4s (GCC %s)\n", v, version_string); - fnotice (stdout, "Copyright (C) 2002 Free Software Foundation, Inc.\n"); + fnotice (stdout, "gcov (GCC) %s\n", version_string); + fprintf (stdout, "Copyright %s 2004 Free Software Foundation, Inc.\n", + _("(C)")); fnotice (stdout, - "This is free software; see the source for copying conditions. There is NO\n\ -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); + _("This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or \n" + "FITNESS FOR A PARTICULAR PURPOSE.\n\n")); exit (SUCCESS_EXIT_CODE); } @@ -451,9 +449,7 @@ static const struct option options[] = /* Process args, return index to first non-arg. */ static int -process_args (argc, argv) - int argc; - char **argv; +process_args (int argc, char **argv) { int opt; @@ -506,33 +502,32 @@ process_args (argc, argv) /* Process a single source file. */ static void -process_file (file_name) - const char *file_name; +process_file (const char *file_name) { source_t *src; function_t *fn; - + create_file_names (file_name); if (read_graph_file ()) return; - + if (!functions) { fnotice (stderr, "%s:no functions found\n", bbg_file_name); return; } - + if (read_count_file ()) return; - + for (fn = functions; fn; fn = fn->next) solve_flow_graph (fn); for (src = sources; src; src = src->next) - src->lines = (line_t *) xcalloc (src->num_lines, sizeof (line_t)); + src->lines = xcalloc (src->num_lines, sizeof (line_t)); for (fn = functions; fn; fn = fn->next) { coverage_t coverage; - + memset (&coverage, 0, sizeof (coverage)); coverage.name = fn->name; add_line_counts (flag_function_summary ? &coverage : NULL, fn); @@ -542,7 +537,7 @@ process_file (file_name) fnotice (stdout, "\n"); } } - + for (src = sources; src; src = src->next) { accumulate_line_counts (src); @@ -551,7 +546,7 @@ process_file (file_name) { char *gcov_file_name = make_gcov_file_name (file_name, src->name); FILE *gcov_file = fopen (gcov_file_name, "w"); - + if (gcov_file) { fnotice (stdout, "%s:creating `%s'\n", @@ -574,16 +569,17 @@ process_file (file_name) /* Release all memory used. */ static void -release_structures () +release_structures (void) { function_t *fn; source_t *src; - + free (bbg_file_name); free (da_file_name); da_file_name = bbg_file_name = NULL; bbg_file_time = 0; - + bbg_stamp = 0; + while ((src = sources)) { sources = src->next; @@ -591,12 +587,12 @@ release_structures () free (src->name); free (src->lines); } - + while ((fn = functions)) { unsigned ix; block_t *block; - + functions = fn->next; for (ix = fn->num_blocks, block = fn->blocks; ix--; block++) { @@ -622,14 +618,13 @@ release_structures () the object *file*, and the data files are named from that. */ static void -create_file_names (file_name) - const char *file_name; +create_file_names (const char *file_name) { char *cptr; char *name; int length = strlen (file_name); int base; - + if (object_directory && object_directory[0]) { struct stat status; @@ -637,7 +632,7 @@ create_file_names (file_name) length += strlen (object_directory) + 2; name = xmalloc (length); name[0] = 0; - + base = !stat (object_directory, &status) && S_ISDIR (status.st_mode); strcat (name, object_directory); if (base && name[strlen (name) - 1] != '/') @@ -649,29 +644,29 @@ create_file_names (file_name) name[0] = 0; base = 1; } - + if (base) { - /* Append source file name */ + /* Append source file name. */ cptr = strrchr (file_name, '/'); strcat (name, cptr ? cptr + 1 : file_name); } - + /* Remove the extension. */ cptr = strrchr (name, '.'); if (cptr) *cptr = 0; - + length = strlen (name); - bbg_file_name = xmalloc (length + strlen (GCOV_GRAPH_SUFFIX) + 1); + bbg_file_name = xmalloc (length + strlen (GCOV_NOTE_SUFFIX) + 1); strcpy (bbg_file_name, name); - strcpy (bbg_file_name + length, GCOV_GRAPH_SUFFIX); + strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX); da_file_name = xmalloc (length + strlen (GCOV_DATA_SUFFIX) + 1); strcpy (da_file_name, name); strcpy (da_file_name + length, GCOV_DATA_SUFFIX); - + return; } @@ -679,19 +674,18 @@ create_file_names (file_name) FILE_NAME on creation */ static source_t * -find_source (file_name) - const char *file_name; +find_source (const char *file_name) { source_t *src; if (!file_name) file_name = ""; - + for (src = sources; src; src = src->next) if (!strcmp (file_name, src->name)) return src; - - src = (source_t *)xcalloc (1, sizeof (source_t)); + + src = xcalloc (1, sizeof (source_t)); src->name = xstrdup (file_name); src->coverage.name = src->name; src->index = sources ? sources->index + 1 : 1; @@ -704,7 +698,7 @@ find_source (file_name) /* Read the graph file. Return nonzero on fatal error. */ static int -read_graph_file () +read_graph_file (void) { unsigned version; unsigned current_tag = 0; @@ -712,14 +706,14 @@ read_graph_file () 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); return 1; } bbg_file_time = gcov_time (); - if (gcov_read_unsigned () != GCOV_GRAPH_MAGIC) + if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC)) { fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name); gcov_close (); @@ -730,17 +724,15 @@ read_graph_file () if (version != GCOV_VERSION) { char v[4], e[4]; - unsigned required = GCOV_VERSION; - - for (ix = 4; ix--; required >>= 8, version >>= 8) - { - v[ix] = version; - e[ix] = required; - } + + GCOV_UNSIGNED2STRING (v, version); + GCOV_UNSIGNED2STRING (e, GCOV_VERSION); + fnotice (stderr, "%s:version `%.4s', prefer `%.4s'\n", bbg_file_name, v, e); } - + bbg_stamp = gcov_read_unsigned (); + while ((tag = gcov_read_unsigned ())) { unsigned length = gcov_read_unsigned (); @@ -758,8 +750,8 @@ read_graph_file () function_name = xstrdup (gcov_read_string ()); src = find_source (gcov_read_string ()); lineno = gcov_read_unsigned (); - - fn = (function_t *)xcalloc (1, sizeof (function_t)); + + fn = xcalloc (1, sizeof (function_t)); fn->name = function_name; fn->ident = ident; fn->checksum = checksum; @@ -769,7 +761,7 @@ read_graph_file () fn->next = functions; functions = fn; current_tag = tag; - + if (lineno >= src->num_lines) src->num_lines = lineno + 1; /* Now insert it into the source file's list of @@ -792,11 +784,10 @@ read_graph_file () bbg_file_name, fn->name); else { - unsigned ix, num_blocks = length / 4; + unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length); fn->num_blocks = num_blocks; - - fn->blocks - = (block_t *)xcalloc (fn->num_blocks, sizeof (block_t)); + + fn->blocks = xcalloc (fn->num_blocks, sizeof (block_t)); for (ix = 0; ix != num_blocks; ix++) fn->blocks[ix].flags = gcov_read_unsigned (); } @@ -804,34 +795,34 @@ read_graph_file () else if (fn && tag == GCOV_TAG_ARCS) { unsigned src = gcov_read_unsigned (); - unsigned num_dests = (length - 4) / 8; + unsigned num_dests = GCOV_TAG_ARCS_NUM (length); if (src >= fn->num_blocks || fn->blocks[src].succ) goto corrupt; - + while (num_dests--) { struct arc_info *arc; unsigned dest = gcov_read_unsigned (); unsigned flags = gcov_read_unsigned (); - + if (dest >= fn->num_blocks) goto corrupt; - arc = (arc_t *) xcalloc (1, sizeof (arc_t)); - + arc = xcalloc (1, sizeof (arc_t)); + arc->dst = &fn->blocks[dest]; arc->src = &fn->blocks[src]; - + arc->count = 0; arc->count_valid = 0; arc->on_tree = !!(flags & GCOV_ARC_ON_TREE); arc->fake = !!(flags & GCOV_ARC_FAKE); arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH); - + arc->succ_next = fn->blocks[src].succ; fn->blocks[src].succ = arc; fn->blocks[src].num_succ++; - + arc->pred_next = fn->blocks[dest].pred; fn->blocks[dest].pred = arc; fn->blocks[dest].num_pred++; @@ -848,13 +839,13 @@ read_graph_file () else { /* Non-local return from a callee of this - function. The destination block is a catch or - setjmp. */ + function. The destination block is a catch or + setjmp. */ arc->is_nonlocal_return = 1; fn->blocks[dest].is_nonlocal_return = 1; } } - + if (!arc->on_tree) fn->num_counts++; } @@ -862,16 +853,15 @@ read_graph_file () else if (fn && tag == GCOV_TAG_LINES) { unsigned blockno = gcov_read_unsigned (); - unsigned *line_nos - = (unsigned *)xcalloc ((length - 4) / 4, sizeof (unsigned)); + unsigned *line_nos = xcalloc (length - 1, sizeof (unsigned)); if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding) goto corrupt; - + for (ix = 0; ; ) { unsigned lineno = gcov_read_unsigned (); - + if (lineno) { if (!ix) @@ -886,16 +876,16 @@ read_graph_file () else { const char *file_name = gcov_read_string (); - + if (!file_name) break; src = find_source (file_name); - + line_nos[ix++] = 0; line_nos[ix++] = src->index; } } - + fn->blocks[blockno].u.line.encoding = line_nos; fn->blocks[blockno].u.line.num = ix; } @@ -906,19 +896,17 @@ read_graph_file () } gcov_sync (base, length); if (gcov_is_error ()) - break; - } - if (!gcov_is_eof ()) - { - corrupt:; - fnotice (stderr, "%s:corrupted\n", bbg_file_name); - gcov_close (); - return 1; + { + corrupt:; + fnotice (stderr, "%s:corrupted\n", bbg_file_name); + gcov_close (); + return 1; + } } gcov_close (); - - /* We built everything backwards, so nreverse them all */ - + + /* We built everything backwards, so nreverse them all. */ + /* Reverse sources. Not strictly necessary, but we'll then process them in the 'expected' order. */ { @@ -939,15 +927,15 @@ read_graph_file () for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn_n) { unsigned ix; - + fn_n = fn->next; fn->next = fn_p; - /* Reverse the arcs */ + /* Reverse the arcs. */ for (ix = fn->num_blocks; ix--;) { arc_t *arc, *arc_p, *arc_n; - + for (arc_p = NULL, arc = fn->blocks[ix].succ; arc; arc_p = arc, arc = arc_n) { @@ -974,7 +962,7 @@ read_graph_file () function. Return nonzero if fatal error. */ static int -read_count_file () +read_count_file (void) { unsigned ix; unsigned version; @@ -987,7 +975,7 @@ read_count_file () fnotice (stderr, "%s:cannot open data file\n", da_file_name); return 1; } - if (gcov_read_unsigned () != GCOV_DATA_MAGIC) + if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC)) { fnotice (stderr, "%s:not a gcov data file\n", da_file_name); cleanup:; @@ -998,17 +986,20 @@ read_count_file () if (version != GCOV_VERSION) { char v[4], e[4]; - unsigned desired = GCOV_VERSION; + + GCOV_UNSIGNED2STRING (v, version); + GCOV_UNSIGNED2STRING (e, GCOV_VERSION); - for (ix = 4; ix--; desired >>= 8, version >>= 8) - { - v[ix] = version; - e[ix] = desired; - } fnotice (stderr, "%s:version `%.4s', prefer version `%.4s'\n", da_file_name, v, e); } - + tag = gcov_read_unsigned (); + if (tag != bbg_stamp) + { + fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name); + goto cleanup; + } + while ((tag = gcov_read_unsigned ())) { unsigned length = gcov_read_unsigned (); @@ -1051,28 +1042,24 @@ read_count_file () } else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn) { - if (length != 8 * fn->num_counts) + if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts)) goto mismatch; - + if (!fn->counts) - fn->counts - = (gcov_type *)xcalloc (fn->num_counts, sizeof (gcov_type)); - + fn->counts = xcalloc (fn->num_counts, sizeof (gcov_type)); + for (ix = 0; ix != fn->num_counts; ix++) fn->counts[ix] += gcov_read_counter (); } gcov_sync (base, length); if ((error = gcov_is_error ())) - break; + { + fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n", + da_file_name); + goto cleanup; + } } - if (!gcov_is_eof ()) - { - fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n", - da_file_name); - goto cleanup; - } - gcov_close (); return 0; } @@ -1081,8 +1068,7 @@ read_count_file () to the blocks and the uninstrumented arcs. */ static void -solve_flow_graph (fn) - function_t *fn; +solve_flow_graph (function_t *fn) { unsigned ix; arc_t *arc; @@ -1090,7 +1076,7 @@ solve_flow_graph (fn) block_t *blk; block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */ block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */ - + if (fn->num_blocks < 2) fnotice (stderr, "%s:`%s' lacks entry and/or exit blocks\n", bbg_file_name, fn->name); @@ -1103,7 +1089,7 @@ solve_flow_graph (fn) /* We can't deduce the entry block counts from the lack of predecessors. */ fn->blocks[0].num_pred = ~(unsigned)0; - + if (fn->blocks[fn->num_blocks - 1].num_succ) fnotice (stderr, "%s:`%s' has arcs from exit block\n", bbg_file_name, fn->name); @@ -1120,12 +1106,12 @@ solve_flow_graph (fn) block_t const *prev_dst = NULL; int out_of_order = 0; int non_fake_succ = 0; - + for (arc = blk->succ; arc; arc = arc->succ_next) { if (!arc->fake) non_fake_succ++; - + if (!arc->on_tree) { if (count_ptr) @@ -1147,7 +1133,7 @@ solve_flow_graph (fn) { arc->is_unconditional = 1; /* If this block is instrumenting a call, it might be - an artifical block. It is not artificial if it has + an artificial block. It is not artificial if it has a non-fallthrough exit, or the destination of this arc has more than one entry. Mark the destination block as a return site, if none of those conditions @@ -1157,7 +1143,7 @@ solve_flow_graph (fn) arc->dst->is_call_return = 1; } } - + /* Sort the successor arcs into ascending dst order. profile.c normally produces arcs in the right order, but sometimes with one or two out of order. We're not using a particularly @@ -1166,11 +1152,11 @@ solve_flow_graph (fn) { arc_t *start = blk->succ; unsigned changes = 1; - + while (changes) { arc_t *arc, *arc_p, *arc_n; - + changes = 0; for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);) { @@ -1194,7 +1180,7 @@ solve_flow_graph (fn) } blk->succ = start; } - + /* Place it on the invalid chain, it will be ignored if that's wrong. */ blk->invalid_chain = 1; @@ -1208,7 +1194,7 @@ solve_flow_graph (fn) { gcov_type total = 0; const arc_t *arc; - + invalid_blocks = blk->chain; blk->invalid_chain = 0; if (!blk->num_succ) @@ -1219,7 +1205,7 @@ solve_flow_graph (fn) total += arc->count; else continue; - + blk->count = total; blk->count_valid = 1; blk->chain = valid_blocks; @@ -1236,7 +1222,7 @@ solve_flow_graph (fn) if (blk->num_succ == 1) { block_t *dst; - + total = blk->count; inv_arc = NULL; for (arc = blk->succ; arc; arc = arc->succ_next) @@ -1272,7 +1258,7 @@ solve_flow_graph (fn) if (blk->num_pred == 1) { block_t *src; - + total = blk->count; inv_arc = NULL; for (arc = blk->pred; arc; arc = arc->pred_next) @@ -1307,7 +1293,7 @@ solve_flow_graph (fn) } } } - + /* If the graph has been correctly solved, every block will have a valid count. */ for (ix = 0; ix < fn->num_blocks; ix++) @@ -1324,9 +1310,7 @@ solve_flow_graph (fn) /* Increment totals in COVERAGE according to arc ARC. */ static void -add_branch_counts (coverage, arc) - coverage_t *coverage; - const arc_t *arc; +add_branch_counts (coverage_t *coverage, const arc_t *arc) { if (arc->is_call_non_return) { @@ -1351,22 +1335,20 @@ add_branch_counts (coverage, arc) format TOP. Return pointer to a static string. */ static char const * -format_gcov (top, bottom, dp) - gcov_type top, bottom; - int dp; +format_gcov (gcov_type top, gcov_type bottom, int dp) { static char buffer[20]; - + if (dp >= 0) { float ratio = bottom ? (float)top / bottom : 0; int ix; unsigned limit = 100; unsigned percent; - + for (ix = dp; ix--; ) limit *= 10; - + percent = (unsigned) (ratio * limit + (float)0.5); if (percent <= 0 && top) percent = 1; @@ -1387,7 +1369,7 @@ format_gcov (top, bottom, dp) } else sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top); - + return buffer; } @@ -1395,9 +1377,7 @@ format_gcov (top, bottom, dp) /* Output summary info for a function. */ static void -function_summary (coverage, title) - const coverage_t *coverage; - const char *title; +function_summary (const coverage_t *coverage, const char *title) { fnotice (stdout, "%s `%s'\n", title, coverage->name); @@ -1406,7 +1386,7 @@ function_summary (coverage, title) format_gcov (coverage->lines_executed, coverage->lines, 2), coverage->lines); else - fnotice (stdout, "No executable lines"); + fnotice (stdout, "No executable lines\n"); if (flag_branches) { @@ -1443,13 +1423,11 @@ function_summary (coverage, title) removed and '..' components are renamed to '^'. */ static char * -make_gcov_file_name (input_name, src_name) - const char *input_name; - const char *src_name; +make_gcov_file_name (const char *input_name, const char *src_name) { char *cptr; char *name = xmalloc (strlen (src_name) + strlen (input_name) + 10); - + name[0] = 0; if (flag_long_names && strcmp (src_name, input_name)) { @@ -1458,43 +1436,43 @@ make_gcov_file_name (input_name, src_name) strcat (name, cptr ? cptr + 1 : input_name); strcat (name, "##"); } - + /* Generate the source filename part. */ cptr = flag_preserve_paths ? NULL : strrchr (src_name, '/'); strcat (name, cptr ? cptr + 1 : src_name); - + if (flag_preserve_paths) { /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */ char *prev; - + for (cptr = name; (cptr = strchr ((prev = cptr), '/'));) - { - unsigned shift = 0; - - if (prev + 1 == cptr && prev[0] == '.') - { - /* Remove '.' */ - shift = 2; - } - else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.') - { - /* Convert '..' */ - shift = 1; - prev[1] = '^'; - } - else - *cptr++ = '#'; - if (shift) - { - cptr = prev; - do - prev[0] = prev[shift]; + { + unsigned shift = 0; + + if (prev + 1 == cptr && prev[0] == '.') + { + /* Remove '.' */ + shift = 2; + } + else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.') + { + /* Convert '..' */ + shift = 1; + prev[1] = '^'; + } + else + *cptr++ = '#'; + if (shift) + { + cptr = prev; + do + prev[0] = prev[shift]; while (*prev++); - } - } + } + } } - + strcat (name, ".gcov"); return name; } @@ -1504,12 +1482,10 @@ make_gcov_file_name (input_name, src_name) the appropriate basic block. */ static void -add_line_counts (coverage, fn) - coverage_t *coverage; - function_t *fn; +add_line_counts (coverage_t *coverage, function_t *fn) { unsigned ix; - line_t *line = NULL; /* this is propagated from one iteration to the + line_t *line = NULL; /* This is propagated from one iteration to the next. */ /* Scan each basic block. */ @@ -1549,13 +1525,13 @@ add_line_counts (coverage, fn) free (block->u.line.encoding); block->u.cycle.arc = NULL; block->u.cycle.ident = ~0U; - + if (!ix || ix + 1 == fn->num_blocks) /* Entry or exit block */; else if (flag_all_blocks) { line_t *block_line = line ? line : &fn->src->lines[fn->line]; - + block->chain = block_line->u.blocks; block_line->u.blocks = block; } @@ -1579,8 +1555,7 @@ add_line_counts (coverage, fn) /* Accumulate the line counts of a file. */ static void -accumulate_line_counts (src) - source_t *src; +accumulate_line_counts (source_t *src) { line_t *line; function_t *fn, *fn_p, *fn_n; @@ -1594,20 +1569,20 @@ accumulate_line_counts (src) fn->line_next = fn_p; } src->functions = fn_p; - + for (ix = src->num_lines, line = src->lines; ix--; line++) { if (!flag_all_blocks) { arc_t *arc, *arc_p, *arc_n; - + /* Total and reverse the branch information. */ for (arc = line->u.branches, arc_p = NULL; arc; arc_p = arc, arc = arc_n) { arc_n = arc->line_next; arc->line_next = arc_p; - + add_branch_counts (&src->coverage, arc); } line->u.branches = arc_p; @@ -1622,8 +1597,8 @@ accumulate_line_counts (src) and add the transition counts of those cycles. */ block_t *block, *block_p, *block_n; gcov_type count = 0; - - /* Reverse the block information */ + + /* Reverse the block information. */ for (block = line->u.blocks, block_p = NULL; block; block_p = block, block = block_n) { @@ -1632,7 +1607,7 @@ accumulate_line_counts (src) block->u.cycle.ident = ix; } line->u.blocks = block_p; - + /* Sum the entry arcs. */ for (block = line->u.blocks; block; block = block->chain) { @@ -1645,6 +1620,10 @@ accumulate_line_counts (src) if (flag_branches) add_branch_counts (&src->coverage, arc); } + + /* Initialize the cs_count. */ + for (arc = block->succ; arc; arc = arc->succ_next) + arc->cs_count = arc->count; } /* Find the loops. This uses the algorithm described in @@ -1661,12 +1640,13 @@ accumulate_line_counts (src) For each loop we find, locate the arc with the smallest transition count, and add that to the cumulative - count. Remove the arc from consideration. */ + count. Decrease flow over the cycle and remove the arc + from consideration. */ for (block = line->u.blocks; block; block = block->chain) { block_t *head = block; arc_t *arc; - + next_vertex:; arc = head->succ; current_vertex:; @@ -1683,36 +1663,44 @@ accumulate_line_counts (src) arc = arc->succ_next; continue; } - + if (dst == block) { /* Found a closing arc. */ - gcov_type cycle_count = arc->count; + gcov_type cycle_count = arc->cs_count; arc_t *cycle_arc = arc; arc_t *probe_arc; - - /* Locate the smallest arc count of the loop. */ + + /* Locate the smallest arc count of the loop. */ for (dst = head; (probe_arc = dst->u.cycle.arc); dst = probe_arc->src) - if (cycle_count > probe_arc->count) + if (cycle_count > probe_arc->cs_count) { - cycle_count = probe_arc->count; + cycle_count = probe_arc->cs_count; cycle_arc = probe_arc; } - + count += cycle_count; cycle_arc->cycle = 1; + + /* Remove the flow from the cycle. */ + arc->cs_count -= cycle_count; + for (dst = head; (probe_arc = dst->u.cycle.arc); + dst = probe_arc->src) + probe_arc->cs_count -= cycle_count; + /* Unwind to the cyclic arc. */ while (head != cycle_arc->src) { arc = head->u.cycle.arc; + head->u.cycle.arc = NULL; head = arc->src; } /* Move on. */ arc = arc->succ_next; continue; } - + /* Add new block to chain. */ dst->u.cycle.arc = arc; head = dst; @@ -1723,7 +1711,7 @@ accumulate_line_counts (src) arc = head->u.cycle.arc; if (arc) { - /* It was not the first vertex. Move onto next arc. */ + /* It was not the first vertex. Move onto next arc. */ head->u.cycle.arc = NULL; head = arc->src; arc = arc->succ_next; @@ -1735,7 +1723,7 @@ accumulate_line_counts (src) line->count = count; } - + if (line->exists) { src->coverage.lines++; @@ -1745,16 +1733,13 @@ accumulate_line_counts (src) } } -/* Ouput information about ARC number IX. Returns non-zero if +/* Output information about ARC number IX. Returns nonzero if anything is output. */ static int -output_branch_count (gcov_file, ix, arc) - FILE *gcov_file; - int ix; - const arc_t *arc; +output_branch_count (FILE *gcov_file, int ix, const arc_t *arc) { - + if (arc->is_call_non_return) { if (arc->src->count) @@ -1786,7 +1771,7 @@ output_branch_count (gcov_file, ix, arc) else return 0; return 1; - + } /* Read in the source file one line at a time, and output that line to @@ -1794,12 +1779,10 @@ output_branch_count (gcov_file, ix, arc) information. */ static void -output_lines (gcov_file, src) - FILE *gcov_file; - const source_t *src; +output_lines (FILE *gcov_file, const source_t *src) { FILE *source_file; - unsigned line_num; /* current line number. */ + unsigned line_num; /* current line number. */ const line_t *line; /* current line info ptr. */ char string[STRING_SIZE]; /* line buffer. */ char const *retval = ""; /* status of source file reading. */ @@ -1811,7 +1794,7 @@ output_lines (gcov_file, src) fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, object_summary.ctrs[GCOV_COUNTER_ARCS].runs); fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count); - + source_file = fopen (src->name, "r"); if (!source_file) { @@ -1821,7 +1804,7 @@ output_lines (gcov_file, src) else { struct stat status; - + if (!fstat (fileno (source_file), &status) && status.st_mtime > bbg_file_time) { @@ -1843,7 +1826,7 @@ output_lines (gcov_file, src) for (; arc; arc = arc->pred_next) if (arc->fake) return_count -= arc->count; - + fprintf (gcov_file, "function %s", fn->name); fprintf (gcov_file, " called %s", format_gcov (fn->blocks[0].count, 0, -1)); @@ -1853,17 +1836,17 @@ output_lines (gcov_file, src) format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0)); fprintf (gcov_file, "\n"); } - + /* For lines which don't exist in the .bb file, print '-' before - the source line. For lines which exist but were never - executed, print '#####' before the source line. Otherwise, - print the execution count before the source line. There are - 16 spaces of indentation added before the source line so that - tabs won't be messed up. */ + the source line. For lines which exist but were never + executed, print '#####' before the source line. Otherwise, + print the execution count before the source line. There are + 16 spaces of indentation added before the source line so that + tabs won't be messed up. */ fprintf (gcov_file, "%9s:%5u:", !line->exists ? "-" : !line->count ? "#####" : format_gcov (line->count, 0, -1), line_num); - + if (retval) { /* Copy source line. */ @@ -1884,7 +1867,7 @@ output_lines (gcov_file, src) block_t *block; arc_t *arc; int ix, jx; - + for (ix = jx = 0, block = line->u.blocks; block; block = block->chain) { @@ -1902,12 +1885,12 @@ output_lines (gcov_file, src) { int ix; arc_t *arc; - + for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next) ix += output_branch_count (gcov_file, ix, arc); } } - + /* Handle all remaining source lines. There may be lines after the last line of code. */ if (retval) @@ -1915,7 +1898,7 @@ output_lines (gcov_file, src) for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++) { fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval); - + while (!retval[0] || retval[strlen (retval) - 1] != '\n') { retval = fgets (string, STRING_SIZE, source_file); @@ -1925,7 +1908,7 @@ output_lines (gcov_file, src) } } } - + if (source_file) fclose (source_file); }