cgraph.c (cgraph_make_decl_local): Handle DECL_ONE_ONLY similarly to DECL_COMDAT.
[official-gcc.git] / gcc / gcov.c
blob94a1c350c8059e682bf25bf6a620ccd42ed2f9c6
1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file.
3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
4 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
5 Free Software Foundation, Inc.
6 Contributed by James E. Wilson of Cygnus Support.
7 Mangled by Bob Manson of Cygnus Support.
8 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
10 Gcov is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3, or (at your option)
13 any later version.
15 Gcov is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with Gcov; see the file COPYING3. If not see
22 <http://www.gnu.org/licenses/>. */
24 /* ??? Print a list of the ten blocks with the highest execution counts,
25 and list the line numbers corresponding to those blocks. Also, perhaps
26 list the line numbers with the highest execution counts, only printing
27 the first if there are several which are all listed in the same block. */
29 /* ??? Should have an option to print the number of basic blocks, and the
30 percent of them that are covered. */
32 /* Need an option to show individual block counts, and show
33 probabilities of fall through arcs. */
35 #include "config.h"
36 #include "system.h"
37 #include "coretypes.h"
38 #include "tm.h"
39 #include "intl.h"
40 #include "diagnostic.h"
41 #include "version.h"
43 #include <getopt.h>
45 #define IN_GCOV 1
46 #include "gcov-io.h"
47 #include "gcov-io.c"
49 /* The gcno file is generated by -ftest-coverage option. The gcda file is
50 generated by a program compiled with -fprofile-arcs. Their formats
51 are documented in gcov-io.h. */
53 /* The functions in this file for creating and solution program flow graphs
54 are very similar to functions in the gcc source file profile.c. In
55 some places we make use of the knowledge of how profile.c works to
56 select particular algorithms here. */
58 /* The code validates that the profile information read in corresponds
59 to the code currently being compiled. Rather than checking for
60 identical files, the code below computes a checksum on the CFG
61 (based on the order of basic blocks and the arcs in the CFG). If
62 the CFG checksum in the gcda file match the CFG checksum for the
63 code currently being compiled, the profile data will be used. */
65 /* This is the size of the buffer used to read in source file lines. */
67 #define STRING_SIZE 200
69 struct function_info;
70 struct block_info;
71 struct source_info;
73 /* Describes an arc between two basic blocks. */
75 typedef struct arc_info
77 /* source and destination blocks. */
78 struct block_info *src;
79 struct block_info *dst;
81 /* transition counts. */
82 gcov_type count;
83 /* used in cycle search, so that we do not clobber original counts. */
84 gcov_type cs_count;
86 unsigned int count_valid : 1;
87 unsigned int on_tree : 1;
88 unsigned int fake : 1;
89 unsigned int fall_through : 1;
91 /* Arc is for a function that abnormally returns. */
92 unsigned int is_call_non_return : 1;
94 /* Arc is for catch/setjmp. */
95 unsigned int is_nonlocal_return : 1;
97 /* Is an unconditional branch. */
98 unsigned int is_unconditional : 1;
100 /* Loop making arc. */
101 unsigned int cycle : 1;
103 /* Next branch on line. */
104 struct arc_info *line_next;
106 /* Links to next arc on src and dst lists. */
107 struct arc_info *succ_next;
108 struct arc_info *pred_next;
109 } arc_t;
111 /* Describes a basic block. Contains lists of arcs to successor and
112 predecessor blocks. */
114 typedef struct block_info
116 /* Chain of exit and entry arcs. */
117 arc_t *succ;
118 arc_t *pred;
120 /* Number of unprocessed exit and entry arcs. */
121 gcov_type num_succ;
122 gcov_type num_pred;
124 /* Block execution count. */
125 gcov_type count;
126 unsigned flags : 13;
127 unsigned count_valid : 1;
128 unsigned valid_chain : 1;
129 unsigned invalid_chain : 1;
131 /* Block is a call instrumenting site. */
132 unsigned is_call_site : 1; /* Does the call. */
133 unsigned is_call_return : 1; /* Is the return. */
135 /* Block is a landing pad for longjmp or throw. */
136 unsigned is_nonlocal_return : 1;
138 union
140 struct
142 /* Array of line numbers and source files. source files are
143 introduced by a linenumber of zero, the next 'line number' is
144 the number of the source file. Always starts with a source
145 file. */
146 unsigned *encoding;
147 unsigned num;
148 } line; /* Valid until blocks are linked onto lines */
149 struct
151 /* Single line graph cycle workspace. Used for all-blocks
152 mode. */
153 arc_t *arc;
154 unsigned ident;
155 } cycle; /* Used in all-blocks mode, after blocks are linked onto
156 lines. */
157 } u;
159 /* Temporary chain for solving graph, and for chaining blocks on one
160 line. */
161 struct block_info *chain;
163 } block_t;
165 /* Describes a single function. Contains an array of basic blocks. */
167 typedef struct function_info
169 /* Name of function. */
170 char *name;
171 unsigned ident;
172 unsigned lineno_checksum;
173 unsigned cfg_checksum;
175 /* Array of basic blocks. */
176 block_t *blocks;
177 unsigned num_blocks;
178 unsigned blocks_executed;
180 /* Raw arc coverage counts. */
181 gcov_type *counts;
182 unsigned num_counts;
184 /* First line number. */
185 unsigned line;
186 struct source_info *src;
188 /* Next function in same source file. */
189 struct function_info *line_next;
191 /* Next function. */
192 struct function_info *next;
193 } function_t;
195 /* Describes coverage of a file or function. */
197 typedef struct coverage_info
199 int lines;
200 int lines_executed;
202 int branches;
203 int branches_executed;
204 int branches_taken;
206 int calls;
207 int calls_executed;
209 char *name;
210 } coverage_t;
212 /* Describes a single line of source. Contains a chain of basic blocks
213 with code on it. */
215 typedef struct line_info
217 gcov_type count; /* execution count */
218 union
220 arc_t *branches; /* branches from blocks that end on this
221 line. Used for branch-counts when not
222 all-blocks mode. */
223 block_t *blocks; /* blocks which start on this line. Used
224 in all-blocks mode. */
225 } u;
226 unsigned exists : 1;
227 } line_t;
229 /* Describes a file mentioned in the block graph. Contains an array
230 of line info. */
232 typedef struct source_info
234 /* Name of source file. */
235 char *name;
236 unsigned index;
237 time_t file_time;
239 /* Array of line information. */
240 line_t *lines;
241 unsigned num_lines;
243 coverage_t coverage;
245 /* Functions in this source file. These are in ascending line
246 number order. */
247 function_t *functions;
249 /* Next source file. */
250 struct source_info *next;
251 } source_t;
253 /* Holds a list of function basic block graphs. */
255 static function_t *functions;
257 /* This points to the head of the sourcefile structure list. New elements
258 are always prepended. */
260 static source_t *sources;
262 /* Next index for a source file. */
264 static unsigned source_index;
266 /* This holds data summary information. */
268 static struct gcov_summary object_summary;
269 static unsigned program_count;
271 /* Modification time of graph file. */
273 static time_t bbg_file_time;
275 /* Name and file pointer of the input file for the basic block graph. */
277 static char *bbg_file_name;
279 /* Stamp of the bbg file */
280 static unsigned bbg_stamp;
282 /* Name and file pointer of the input file for the arc count data. */
284 static char *da_file_name;
286 /* Data file is missing. */
288 static int no_data_file;
290 /* If there is several input files, compute and display results after
291 reading all data files. This way if two or more gcda file refer to
292 the same source file (eg inline subprograms in a .h file), the
293 counts are added. */
295 static int multiple_files = 0;
297 /* Output branch probabilities. */
299 static int flag_branches = 0;
301 /* Show unconditional branches too. */
302 static int flag_unconditional = 0;
304 /* Output a gcov file if this is true. This is on by default, and can
305 be turned off by the -n option. */
307 static int flag_gcov_file = 1;
309 /* Output progress indication if this is true. This is off by default
310 and can be turned on by the -d option. */
312 static int flag_display_progress = 0;
314 /* For included files, make the gcov output file name include the name
315 of the input source file. For example, if x.h is included in a.c,
316 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
318 static int flag_long_names = 0;
320 /* Output count information for every basic block, not merely those
321 that contain line number information. */
323 static int flag_all_blocks = 0;
325 /* Output summary info for each function. */
327 static int flag_function_summary = 0;
329 /* Object directory file prefix. This is the directory/file where the
330 graph and data files are looked for, if nonzero. */
332 static char *object_directory = 0;
334 /* Preserve all pathname components. Needed when object files and
335 source files are in subdirectories. '/' is mangled as '#', '.' is
336 elided and '..' mangled to '^'. */
338 static int flag_preserve_paths = 0;
340 /* Output the number of times a branch was taken as opposed to the percentage
341 of times it was taken. */
343 static int flag_counts = 0;
345 /* Forward declarations. */
346 static int process_args (int, char **);
347 static void print_usage (int) ATTRIBUTE_NORETURN;
348 static void print_version (void) ATTRIBUTE_NORETURN;
349 static void process_file (const char *);
350 static void generate_results (const char *);
351 static void create_file_names (const char *);
352 static source_t *find_source (const char *);
353 static int read_graph_file (void);
354 static int read_count_file (void);
355 static void solve_flow_graph (function_t *);
356 static void add_branch_counts (coverage_t *, const arc_t *);
357 static void add_line_counts (coverage_t *, function_t *);
358 static void function_summary (const coverage_t *, const char *);
359 static const char *format_gcov (gcov_type, gcov_type, int);
360 static void accumulate_line_counts (source_t *);
361 static int output_branch_count (FILE *, int, const arc_t *);
362 static void output_lines (FILE *, const source_t *);
363 static char *make_gcov_file_name (const char *, const char *);
364 static void release_structures (void);
365 extern int main (int, char **);
368 main (int argc, char **argv)
370 int argno;
371 int first_arg;
372 const char *p;
374 p = argv[0] + strlen (argv[0]);
375 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
376 --p;
377 progname = p;
379 xmalloc_set_program_name (progname);
381 /* Unlock the stdio streams. */
382 unlock_std_streams ();
384 gcc_init_libintl ();
386 diagnostic_initialize (global_dc, 0);
388 /* Handle response files. */
389 expandargv (&argc, &argv);
391 argno = process_args (argc, argv);
392 if (optind == argc)
393 print_usage (true);
395 if (argc - argno > 1)
396 multiple_files = 1;
398 first_arg = argno;
400 for (; argno != argc; argno++)
402 if (flag_display_progress)
403 printf("Processing file %d out of %d\n",
404 argno - first_arg + 1, argc - first_arg);
405 process_file (argv[argno]);
408 generate_results (multiple_files ? NULL : argv[argc - 1]);
410 release_structures ();
412 return 0;
415 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
416 otherwise the output of --help. */
418 static void
419 print_usage (int error_p)
421 FILE *file = error_p ? stderr : stdout;
422 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
424 fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE...\n\n");
425 fnotice (file, "Print code coverage information.\n\n");
426 fnotice (file, " -h, --help Print this help, then exit\n");
427 fnotice (file, " -v, --version Print version number, then exit\n");
428 fnotice (file, " -a, --all-blocks Show information for every basic block\n");
429 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
430 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
431 rather than percentages\n");
432 fnotice (file, " -n, --no-output Do not create an output file\n");
433 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
434 source files\n");
435 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
436 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
437 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
438 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
439 fnotice (file, " -d, --display-progress Display progress information\n");
440 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
441 bug_report_url);
442 exit (status);
445 /* Print version information and exit. */
447 static void
448 print_version (void)
450 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
451 fprintf (stdout, "Copyright %s 2011 Free Software Foundation, Inc.\n",
452 _("(C)"));
453 fnotice (stdout,
454 _("This is free software; see the source for copying conditions.\n"
455 "There is NO warranty; not even for MERCHANTABILITY or \n"
456 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
457 exit (SUCCESS_EXIT_CODE);
460 static const struct option options[] =
462 { "help", no_argument, NULL, 'h' },
463 { "version", no_argument, NULL, 'v' },
464 { "all-blocks", no_argument, NULL, 'a' },
465 { "branch-probabilities", no_argument, NULL, 'b' },
466 { "branch-counts", no_argument, NULL, 'c' },
467 { "no-output", no_argument, NULL, 'n' },
468 { "long-file-names", no_argument, NULL, 'l' },
469 { "function-summaries", no_argument, NULL, 'f' },
470 { "preserve-paths", no_argument, NULL, 'p' },
471 { "object-directory", required_argument, NULL, 'o' },
472 { "object-file", required_argument, NULL, 'o' },
473 { "unconditional-branches", no_argument, NULL, 'u' },
474 { "display-progress", no_argument, NULL, 'd' },
475 { 0, 0, 0, 0 }
478 /* Process args, return index to first non-arg. */
480 static int
481 process_args (int argc, char **argv)
483 int opt;
485 while ((opt = getopt_long (argc, argv, "abcdfhlno:puv", options, NULL)) != -1)
487 switch (opt)
489 case 'a':
490 flag_all_blocks = 1;
491 break;
492 case 'b':
493 flag_branches = 1;
494 break;
495 case 'c':
496 flag_counts = 1;
497 break;
498 case 'f':
499 flag_function_summary = 1;
500 break;
501 case 'h':
502 print_usage (false);
503 /* print_usage will exit. */
504 case 'l':
505 flag_long_names = 1;
506 break;
507 case 'n':
508 flag_gcov_file = 0;
509 break;
510 case 'o':
511 object_directory = optarg;
512 break;
513 case 'p':
514 flag_preserve_paths = 1;
515 break;
516 case 'u':
517 flag_unconditional = 1;
518 break;
519 case 'd':
520 flag_display_progress = 1;
521 break;
522 case 'v':
523 print_version ();
524 /* print_version will exit. */
525 default:
526 print_usage (true);
527 /* print_usage will exit. */
531 return optind;
534 /* Process a single source file. */
536 static void
537 process_file (const char *file_name)
539 function_t *fn;
540 function_t *fn_p;
541 function_t *old_functions;
543 /* Save and clear the list of current functions. They will be appended
544 later. */
545 old_functions = functions;
546 functions = NULL;
548 create_file_names (file_name);
549 if (read_graph_file ())
550 return;
552 if (!functions)
554 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
555 return;
558 if (read_count_file ())
559 return;
561 for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn->next)
562 solve_flow_graph (fn);
564 if (fn_p)
565 fn_p->next = old_functions;
568 static void
569 generate_results (const char *file_name)
571 source_t *src;
572 function_t *fn;
574 for (src = sources; src; src = src->next)
575 src->lines = XCNEWVEC (line_t, src->num_lines);
576 for (fn = functions; fn; fn = fn->next)
578 coverage_t coverage;
580 memset (&coverage, 0, sizeof (coverage));
581 coverage.name = fn->name;
582 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
583 if (flag_function_summary)
585 function_summary (&coverage, "Function");
586 fnotice (stdout, "\n");
590 for (src = sources; src; src = src->next)
592 accumulate_line_counts (src);
593 function_summary (&src->coverage, "File");
594 if (flag_gcov_file)
596 char *gcov_file_name = make_gcov_file_name (file_name, src->name);
597 FILE *gcov_file = fopen (gcov_file_name, "w");
599 if (gcov_file)
601 fnotice (stdout, "%s:creating '%s'\n",
602 src->name, gcov_file_name);
603 output_lines (gcov_file, src);
604 if (ferror (gcov_file))
605 fnotice (stderr, "%s:error writing output file '%s'\n",
606 src->name, gcov_file_name);
607 fclose (gcov_file);
609 else
610 fnotice (stderr, "%s:could not open output file '%s'\n",
611 src->name, gcov_file_name);
612 free (gcov_file_name);
614 fnotice (stdout, "\n");
618 /* Release all memory used. */
620 static void
621 release_structures (void)
623 function_t *fn;
624 source_t *src;
626 while ((src = sources))
628 sources = src->next;
630 free (src->name);
631 free (src->lines);
634 while ((fn = functions))
636 unsigned ix;
637 block_t *block;
639 functions = fn->next;
640 for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
642 arc_t *arc, *arc_n;
644 for (arc = block->succ; arc; arc = arc_n)
646 arc_n = arc->succ_next;
647 free (arc);
650 free (fn->blocks);
651 free (fn->counts);
655 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
656 is not specified, these are named from FILE_NAME sans extension. If
657 OBJECT_DIRECTORY is specified and is a directory, the files are in that
658 directory, but named from the basename of the FILE_NAME, sans extension.
659 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
660 and the data files are named from that. */
662 static void
663 create_file_names (const char *file_name)
665 char *cptr;
666 char *name;
667 int length = strlen (file_name);
668 int base;
670 /* Free previous file names. */
671 free (bbg_file_name);
672 free (da_file_name);
673 da_file_name = bbg_file_name = NULL;
674 bbg_file_time = 0;
675 bbg_stamp = 0;
677 if (object_directory && object_directory[0])
679 struct stat status;
681 length += strlen (object_directory) + 2;
682 name = XNEWVEC (char, length);
683 name[0] = 0;
685 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
686 strcat (name, object_directory);
687 if (base && (! IS_DIR_SEPARATOR (name[strlen (name) - 1])))
688 strcat (name, "/");
690 else
692 name = XNEWVEC (char, length + 1);
693 strcpy (name, file_name);
694 base = 0;
697 if (base)
699 /* Append source file name. */
700 const char *cptr = lbasename (file_name);
701 strcat (name, cptr ? cptr : file_name);
704 /* Remove the extension. */
705 cptr = strrchr (name, '.');
706 if (cptr)
707 *cptr = 0;
709 length = strlen (name);
711 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
712 strcpy (bbg_file_name, name);
713 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
715 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
716 strcpy (da_file_name, name);
717 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
719 free (name);
720 return;
723 /* Find or create a source file structure for FILE_NAME. Copies
724 FILE_NAME on creation */
726 static source_t *
727 find_source (const char *file_name)
729 source_t *src;
730 struct stat status;
732 if (!file_name)
733 file_name = "<unknown>";
735 for (src = sources; src; src = src->next)
736 if (!filename_cmp (file_name, src->name))
737 break;
739 if (!src)
741 src = XCNEW (source_t);
742 src->name = xstrdup (file_name);
743 src->coverage.name = src->name;
744 src->index = source_index++;
745 src->next = sources;
746 sources = src;
748 if (!stat (file_name, &status))
749 src->file_time = status.st_mtime;
752 if (src->file_time > bbg_file_time)
754 static int info_emitted;
756 fnotice (stderr, "%s:source file is newer than graph file '%s'\n",
757 src->name, bbg_file_name);
758 if (!info_emitted)
760 fnotice (stderr,
761 "(the message is only displayed one per source file)\n");
762 info_emitted = 1;
764 src->file_time = 0;
767 return src;
770 /* Read the graph file. Return nonzero on fatal error. */
772 static int
773 read_graph_file (void)
775 unsigned version;
776 unsigned current_tag = 0;
777 struct function_info *fn = NULL;
778 function_t *old_functions_head = functions;
779 source_t *src = NULL;
780 unsigned ix;
781 unsigned tag;
783 if (!gcov_open (bbg_file_name, 1))
785 fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
786 return 1;
788 bbg_file_time = gcov_time ();
789 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
791 fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
792 gcov_close ();
793 return 1;
796 version = gcov_read_unsigned ();
797 if (version != GCOV_VERSION)
799 char v[4], e[4];
801 GCOV_UNSIGNED2STRING (v, version);
802 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
804 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
805 bbg_file_name, v, e);
807 bbg_stamp = gcov_read_unsigned ();
809 while ((tag = gcov_read_unsigned ()))
811 unsigned length = gcov_read_unsigned ();
812 gcov_position_t base = gcov_position ();
814 if (tag == GCOV_TAG_FUNCTION)
816 char *function_name;
817 unsigned ident, lineno;
818 unsigned lineno_checksum, cfg_checksum;
819 source_t *src;
820 function_t *probe, *prev;
822 ident = gcov_read_unsigned ();
823 lineno_checksum = gcov_read_unsigned ();
824 cfg_checksum = gcov_read_unsigned ();
825 function_name = xstrdup (gcov_read_string ());
826 src = find_source (gcov_read_string ());
827 lineno = gcov_read_unsigned ();
829 fn = XCNEW (function_t);
830 fn->name = function_name;
831 fn->ident = ident;
832 fn->lineno_checksum = lineno_checksum;
833 fn->cfg_checksum = cfg_checksum;
834 fn->src = src;
835 fn->line = lineno;
837 fn->next = functions;
838 functions = fn;
839 current_tag = tag;
841 if (lineno >= src->num_lines)
842 src->num_lines = lineno + 1;
843 /* Now insert it into the source file's list of
844 functions. Normally functions will be encountered in
845 ascending order, so a simple scan is quick. */
846 for (probe = src->functions, prev = NULL;
847 probe && probe->line > lineno;
848 prev = probe, probe = probe->line_next)
849 continue;
850 fn->line_next = probe;
851 if (prev)
852 prev->line_next = fn;
853 else
854 src->functions = fn;
856 else if (fn && tag == GCOV_TAG_BLOCKS)
858 if (fn->blocks)
859 fnotice (stderr, "%s:already seen blocks for '%s'\n",
860 bbg_file_name, fn->name);
861 else
863 unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
864 fn->num_blocks = num_blocks;
866 fn->blocks = XCNEWVEC (block_t, fn->num_blocks);
867 for (ix = 0; ix != num_blocks; ix++)
868 fn->blocks[ix].flags = gcov_read_unsigned ();
871 else if (fn && tag == GCOV_TAG_ARCS)
873 unsigned src = gcov_read_unsigned ();
874 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
876 if (src >= fn->num_blocks || fn->blocks[src].succ)
877 goto corrupt;
879 while (num_dests--)
881 struct arc_info *arc;
882 unsigned dest = gcov_read_unsigned ();
883 unsigned flags = gcov_read_unsigned ();
885 if (dest >= fn->num_blocks)
886 goto corrupt;
887 arc = XCNEW (arc_t);
889 arc->dst = &fn->blocks[dest];
890 arc->src = &fn->blocks[src];
892 arc->count = 0;
893 arc->count_valid = 0;
894 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
895 arc->fake = !!(flags & GCOV_ARC_FAKE);
896 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
898 arc->succ_next = fn->blocks[src].succ;
899 fn->blocks[src].succ = arc;
900 fn->blocks[src].num_succ++;
902 arc->pred_next = fn->blocks[dest].pred;
903 fn->blocks[dest].pred = arc;
904 fn->blocks[dest].num_pred++;
906 if (arc->fake)
908 if (src)
910 /* Exceptional exit from this function, the
911 source block must be a call. */
912 fn->blocks[src].is_call_site = 1;
913 arc->is_call_non_return = 1;
915 else
917 /* Non-local return from a callee of this
918 function. The destination block is a catch or
919 setjmp. */
920 arc->is_nonlocal_return = 1;
921 fn->blocks[dest].is_nonlocal_return = 1;
925 if (!arc->on_tree)
926 fn->num_counts++;
929 else if (fn && tag == GCOV_TAG_LINES)
931 unsigned blockno = gcov_read_unsigned ();
932 unsigned *line_nos = XCNEWVEC (unsigned, length - 1);
934 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
935 goto corrupt;
937 for (ix = 0; ; )
939 unsigned lineno = gcov_read_unsigned ();
941 if (lineno)
943 if (!ix)
945 line_nos[ix++] = 0;
946 line_nos[ix++] = src->index;
948 line_nos[ix++] = lineno;
949 if (lineno >= src->num_lines)
950 src->num_lines = lineno + 1;
952 else
954 const char *file_name = gcov_read_string ();
956 if (!file_name)
957 break;
958 src = find_source (file_name);
960 line_nos[ix++] = 0;
961 line_nos[ix++] = src->index;
965 fn->blocks[blockno].u.line.encoding = line_nos;
966 fn->blocks[blockno].u.line.num = ix;
968 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
970 fn = NULL;
971 current_tag = 0;
973 gcov_sync (base, length);
974 if (gcov_is_error ())
976 corrupt:;
977 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
978 gcov_close ();
979 return 1;
982 gcov_close ();
984 /* We built everything backwards, so nreverse them all. */
986 /* Reverse sources. Not strictly necessary, but we'll then process
987 them in the 'expected' order. */
989 source_t *src, *src_p, *src_n;
991 for (src_p = NULL, src = sources; src; src_p = src, src = src_n)
993 src_n = src->next;
994 src->next = src_p;
996 sources = src_p;
999 /* Reverse functions. */
1001 function_t *fn, *fn_p, *fn_n;
1003 for (fn_p = old_functions_head, fn = functions;
1004 fn != old_functions_head;
1005 fn_p = fn, fn = fn_n)
1007 unsigned ix;
1009 fn_n = fn->next;
1010 fn->next = fn_p;
1012 /* Reverse the arcs. */
1013 for (ix = fn->num_blocks; ix--;)
1015 arc_t *arc, *arc_p, *arc_n;
1017 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
1018 arc_p = arc, arc = arc_n)
1020 arc_n = arc->succ_next;
1021 arc->succ_next = arc_p;
1023 fn->blocks[ix].succ = arc_p;
1025 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
1026 arc_p = arc, arc = arc_n)
1028 arc_n = arc->pred_next;
1029 arc->pred_next = arc_p;
1031 fn->blocks[ix].pred = arc_p;
1034 functions = fn_p;
1036 return 0;
1039 /* Reads profiles from the count file and attach to each
1040 function. Return nonzero if fatal error. */
1042 static int
1043 read_count_file (void)
1045 unsigned ix;
1046 unsigned version;
1047 unsigned tag;
1048 function_t *fn = NULL;
1049 int error = 0;
1051 if (!gcov_open (da_file_name, 1))
1053 fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
1054 da_file_name);
1055 no_data_file = 1;
1056 return 0;
1058 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
1060 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
1061 cleanup:;
1062 gcov_close ();
1063 return 1;
1065 version = gcov_read_unsigned ();
1066 if (version != GCOV_VERSION)
1068 char v[4], e[4];
1070 GCOV_UNSIGNED2STRING (v, version);
1071 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1073 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
1074 da_file_name, v, e);
1076 tag = gcov_read_unsigned ();
1077 if (tag != bbg_stamp)
1079 fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
1080 goto cleanup;
1083 while ((tag = gcov_read_unsigned ()))
1085 unsigned length = gcov_read_unsigned ();
1086 unsigned long base = gcov_position ();
1088 if (tag == GCOV_TAG_OBJECT_SUMMARY)
1089 gcov_read_summary (&object_summary);
1090 else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1091 program_count++;
1092 else if (tag == GCOV_TAG_FUNCTION)
1095 unsigned ident = gcov_read_unsigned ();
1096 struct function_info *fn_n = functions;
1098 /* Try to find the function in the list.
1099 To speed up the search, first start from the last function
1100 found. */
1101 for (fn = fn ? fn->next : NULL; ; fn = fn->next)
1103 if (fn)
1105 else if ((fn = fn_n))
1106 fn_n = NULL;
1107 else
1109 fnotice (stderr, "%s:unknown function '%u'\n",
1110 da_file_name, ident);
1111 break;
1113 if (fn->ident == ident)
1114 break;
1118 if (!fn)
1120 else if (gcov_read_unsigned () != fn->lineno_checksum
1121 || gcov_read_unsigned () != fn->cfg_checksum)
1123 mismatch:;
1124 fnotice (stderr, "%s:profile mismatch for '%s'\n",
1125 da_file_name, fn->name);
1126 goto cleanup;
1129 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1131 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
1132 goto mismatch;
1134 if (!fn->counts)
1135 fn->counts = XCNEWVEC (gcov_type, fn->num_counts);
1137 for (ix = 0; ix != fn->num_counts; ix++)
1138 fn->counts[ix] += gcov_read_counter ();
1140 gcov_sync (base, length);
1141 if ((error = gcov_is_error ()))
1143 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1144 da_file_name);
1145 goto cleanup;
1149 gcov_close ();
1150 return 0;
1153 /* Solve the flow graph. Propagate counts from the instrumented arcs
1154 to the blocks and the uninstrumented arcs. */
1156 static void
1157 solve_flow_graph (function_t *fn)
1159 unsigned ix;
1160 arc_t *arc;
1161 gcov_type *count_ptr = fn->counts;
1162 block_t *blk;
1163 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */
1164 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
1166 if (fn->num_blocks < 2)
1167 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
1168 bbg_file_name, fn->name);
1169 else
1171 if (fn->blocks[0].num_pred)
1172 fnotice (stderr, "%s:'%s' has arcs to entry block\n",
1173 bbg_file_name, fn->name);
1174 else
1175 /* We can't deduce the entry block counts from the lack of
1176 predecessors. */
1177 fn->blocks[0].num_pred = ~(unsigned)0;
1179 if (fn->blocks[fn->num_blocks - 1].num_succ)
1180 fnotice (stderr, "%s:'%s' has arcs from exit block\n",
1181 bbg_file_name, fn->name);
1182 else
1183 /* Likewise, we can't deduce exit block counts from the lack
1184 of its successors. */
1185 fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0;
1188 /* Propagate the measured counts, this must be done in the same
1189 order as the code in profile.c */
1190 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
1192 block_t const *prev_dst = NULL;
1193 int out_of_order = 0;
1194 int non_fake_succ = 0;
1196 for (arc = blk->succ; arc; arc = arc->succ_next)
1198 if (!arc->fake)
1199 non_fake_succ++;
1201 if (!arc->on_tree)
1203 if (count_ptr)
1204 arc->count = *count_ptr++;
1205 arc->count_valid = 1;
1206 blk->num_succ--;
1207 arc->dst->num_pred--;
1209 if (prev_dst && prev_dst > arc->dst)
1210 out_of_order = 1;
1211 prev_dst = arc->dst;
1213 if (non_fake_succ == 1)
1215 /* If there is only one non-fake exit, it is an
1216 unconditional branch. */
1217 for (arc = blk->succ; arc; arc = arc->succ_next)
1218 if (!arc->fake)
1220 arc->is_unconditional = 1;
1221 /* If this block is instrumenting a call, it might be
1222 an artificial block. It is not artificial if it has
1223 a non-fallthrough exit, or the destination of this
1224 arc has more than one entry. Mark the destination
1225 block as a return site, if none of those conditions
1226 hold. */
1227 if (blk->is_call_site && arc->fall_through
1228 && arc->dst->pred == arc && !arc->pred_next)
1229 arc->dst->is_call_return = 1;
1233 /* Sort the successor arcs into ascending dst order. profile.c
1234 normally produces arcs in the right order, but sometimes with
1235 one or two out of order. We're not using a particularly
1236 smart sort. */
1237 if (out_of_order)
1239 arc_t *start = blk->succ;
1240 unsigned changes = 1;
1242 while (changes)
1244 arc_t *arc, *arc_p, *arc_n;
1246 changes = 0;
1247 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1249 if (arc->dst > arc_n->dst)
1251 changes = 1;
1252 if (arc_p)
1253 arc_p->succ_next = arc_n;
1254 else
1255 start = arc_n;
1256 arc->succ_next = arc_n->succ_next;
1257 arc_n->succ_next = arc;
1258 arc_p = arc_n;
1260 else
1262 arc_p = arc;
1263 arc = arc_n;
1267 blk->succ = start;
1270 /* Place it on the invalid chain, it will be ignored if that's
1271 wrong. */
1272 blk->invalid_chain = 1;
1273 blk->chain = invalid_blocks;
1274 invalid_blocks = blk;
1277 while (invalid_blocks || valid_blocks)
1279 while ((blk = invalid_blocks))
1281 gcov_type total = 0;
1282 const arc_t *arc;
1284 invalid_blocks = blk->chain;
1285 blk->invalid_chain = 0;
1286 if (!blk->num_succ)
1287 for (arc = blk->succ; arc; arc = arc->succ_next)
1288 total += arc->count;
1289 else if (!blk->num_pred)
1290 for (arc = blk->pred; arc; arc = arc->pred_next)
1291 total += arc->count;
1292 else
1293 continue;
1295 blk->count = total;
1296 blk->count_valid = 1;
1297 blk->chain = valid_blocks;
1298 blk->valid_chain = 1;
1299 valid_blocks = blk;
1301 while ((blk = valid_blocks))
1303 gcov_type total;
1304 arc_t *arc, *inv_arc;
1306 valid_blocks = blk->chain;
1307 blk->valid_chain = 0;
1308 if (blk->num_succ == 1)
1310 block_t *dst;
1312 total = blk->count;
1313 inv_arc = NULL;
1314 for (arc = blk->succ; arc; arc = arc->succ_next)
1316 total -= arc->count;
1317 if (!arc->count_valid)
1318 inv_arc = arc;
1320 dst = inv_arc->dst;
1321 inv_arc->count_valid = 1;
1322 inv_arc->count = total;
1323 blk->num_succ--;
1324 dst->num_pred--;
1325 if (dst->count_valid)
1327 if (dst->num_pred == 1 && !dst->valid_chain)
1329 dst->chain = valid_blocks;
1330 dst->valid_chain = 1;
1331 valid_blocks = dst;
1334 else
1336 if (!dst->num_pred && !dst->invalid_chain)
1338 dst->chain = invalid_blocks;
1339 dst->invalid_chain = 1;
1340 invalid_blocks = dst;
1344 if (blk->num_pred == 1)
1346 block_t *src;
1348 total = blk->count;
1349 inv_arc = NULL;
1350 for (arc = blk->pred; arc; arc = arc->pred_next)
1352 total -= arc->count;
1353 if (!arc->count_valid)
1354 inv_arc = arc;
1356 src = inv_arc->src;
1357 inv_arc->count_valid = 1;
1358 inv_arc->count = total;
1359 blk->num_pred--;
1360 src->num_succ--;
1361 if (src->count_valid)
1363 if (src->num_succ == 1 && !src->valid_chain)
1365 src->chain = valid_blocks;
1366 src->valid_chain = 1;
1367 valid_blocks = src;
1370 else
1372 if (!src->num_succ && !src->invalid_chain)
1374 src->chain = invalid_blocks;
1375 src->invalid_chain = 1;
1376 invalid_blocks = src;
1383 /* If the graph has been correctly solved, every block will have a
1384 valid count. */
1385 for (ix = 0; ix < fn->num_blocks; ix++)
1386 if (!fn->blocks[ix].count_valid)
1388 fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
1389 bbg_file_name, fn->name);
1390 break;
1396 /* Increment totals in COVERAGE according to arc ARC. */
1398 static void
1399 add_branch_counts (coverage_t *coverage, const arc_t *arc)
1401 if (arc->is_call_non_return)
1403 coverage->calls++;
1404 if (arc->src->count)
1405 coverage->calls_executed++;
1407 else if (!arc->is_unconditional)
1409 coverage->branches++;
1410 if (arc->src->count)
1411 coverage->branches_executed++;
1412 if (arc->count)
1413 coverage->branches_taken++;
1417 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1418 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1419 If DP is zero, no decimal point is printed. Only print 100% when
1420 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1421 format TOP. Return pointer to a static string. */
1423 static char const *
1424 format_gcov (gcov_type top, gcov_type bottom, int dp)
1426 static char buffer[20];
1428 if (dp >= 0)
1430 float ratio = bottom ? (float)top / bottom : 0;
1431 int ix;
1432 unsigned limit = 100;
1433 unsigned percent;
1435 for (ix = dp; ix--; )
1436 limit *= 10;
1438 percent = (unsigned) (ratio * limit + (float)0.5);
1439 if (percent <= 0 && top)
1440 percent = 1;
1441 else if (percent >= limit && top != bottom)
1442 percent = limit - 1;
1443 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1444 if (dp)
1446 dp++;
1449 buffer[ix+1] = buffer[ix];
1450 ix--;
1452 while (dp--);
1453 buffer[ix + 1] = '.';
1456 else
1457 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
1459 return buffer;
1463 /* Output summary info for a function. */
1465 static void
1466 function_summary (const coverage_t *coverage, const char *title)
1468 fnotice (stdout, "%s '%s'\n", title, coverage->name);
1470 if (coverage->lines)
1471 fnotice (stdout, "Lines executed:%s of %d\n",
1472 format_gcov (coverage->lines_executed, coverage->lines, 2),
1473 coverage->lines);
1474 else
1475 fnotice (stdout, "No executable lines\n");
1477 if (flag_branches)
1479 if (coverage->branches)
1481 fnotice (stdout, "Branches executed:%s of %d\n",
1482 format_gcov (coverage->branches_executed,
1483 coverage->branches, 2),
1484 coverage->branches);
1485 fnotice (stdout, "Taken at least once:%s of %d\n",
1486 format_gcov (coverage->branches_taken,
1487 coverage->branches, 2),
1488 coverage->branches);
1490 else
1491 fnotice (stdout, "No branches\n");
1492 if (coverage->calls)
1493 fnotice (stdout, "Calls executed:%s of %d\n",
1494 format_gcov (coverage->calls_executed, coverage->calls, 2),
1495 coverage->calls);
1496 else
1497 fnotice (stdout, "No calls\n");
1501 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1502 affect name generation. With preserve_paths we create a filename
1503 from all path components of the source file, replacing '/' with
1504 '#', without it we simply take the basename component. With
1505 long_output_names we prepend the processed name of the input file
1506 to each output name (except when the current source file is the
1507 input file, so you don't get a double concatenation). The two
1508 components are separated by '##'. Also '.' filename components are
1509 removed and '..' components are renamed to '^'. */
1511 static char *
1512 make_gcov_file_name (const char *input_name, const char *src_name)
1514 const char *cptr;
1515 char *name;
1517 if (flag_long_names && input_name && strcmp (src_name, input_name))
1519 name = XNEWVEC (char, strlen (src_name) + strlen (input_name) + 10);
1520 name[0] = 0;
1521 /* Generate the input filename part. */
1522 cptr = flag_preserve_paths ? NULL : lbasename (input_name);
1523 strcat (name, cptr ? cptr : input_name);
1524 strcat (name, "##");
1526 else
1528 name = XNEWVEC (char, strlen (src_name) + 10);
1529 name[0] = 0;
1532 /* Generate the source filename part. */
1534 cptr = flag_preserve_paths ? NULL : lbasename (src_name);
1535 strcat (name, cptr ? cptr : src_name);
1537 if (flag_preserve_paths)
1539 /* Convert '/' and '\' to '#', remove '/./', convert '/../' to '#^#',
1540 convert ':' to '~' on DOS based file system. */
1541 char *pnew = name, *pold = name;
1543 /* First check for leading drive separator. */
1545 while (*pold != '\0')
1547 #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
1548 if (*pold == ':')
1550 *pnew++ = '~';
1551 pold++;
1553 else
1554 #endif
1555 if ((*pold == '/'
1556 && (strstr (pold, "/./") == pold
1557 || strstr (pold, "/.\\") == pold))
1558 || (*pold == '\\'
1559 && (strstr (pold, "\\.\\") == pold
1560 || strstr (pold, "\\./") == pold)))
1561 pold += 3;
1562 else if (*pold == '/'
1563 && (strstr (pold, "/../") == pold
1564 || strstr (pold, "/..\\") == pold))
1566 strcpy (pnew, "#^#");
1567 pnew += 3;
1568 pold += 4;
1570 else if (*pold == '\\'
1571 && (strstr (pold, "\\..\\") == pold
1572 || strstr (pold, "\\../") == pold))
1574 strcpy (pnew, "#^#");
1575 pnew += 3;
1576 pold += 4;
1578 else if (*pold == '/' || *pold == '\\')
1580 *pnew++ = '#';
1581 pold++;
1583 else
1584 *pnew++ = *pold++;
1587 *pnew = '\0';
1590 strcat (name, ".gcov");
1591 return name;
1594 /* Scan through the bb_data for each line in the block, increment
1595 the line number execution count indicated by the execution count of
1596 the appropriate basic block. */
1598 static void
1599 add_line_counts (coverage_t *coverage, function_t *fn)
1601 unsigned ix;
1602 line_t *line = NULL; /* This is propagated from one iteration to the
1603 next. */
1605 /* Scan each basic block. */
1606 for (ix = 0; ix != fn->num_blocks; ix++)
1608 block_t *block = &fn->blocks[ix];
1609 unsigned *encoding;
1610 const source_t *src = NULL;
1611 unsigned jx;
1613 if (block->count && ix && ix + 1 != fn->num_blocks)
1614 fn->blocks_executed++;
1615 for (jx = 0, encoding = block->u.line.encoding;
1616 jx != block->u.line.num; jx++, encoding++)
1617 if (!*encoding)
1619 unsigned src_n = *++encoding;
1621 for (src = sources; src->index != src_n; src = src->next)
1622 continue;
1623 jx++;
1625 else
1627 line = &src->lines[*encoding];
1629 if (coverage)
1631 if (!line->exists)
1632 coverage->lines++;
1633 if (!line->count && block->count)
1634 coverage->lines_executed++;
1636 line->exists = 1;
1637 line->count += block->count;
1639 free (block->u.line.encoding);
1640 block->u.cycle.arc = NULL;
1641 block->u.cycle.ident = ~0U;
1643 if (!ix || ix + 1 == fn->num_blocks)
1644 /* Entry or exit block */;
1645 else if (flag_all_blocks)
1647 line_t *block_line = line ? line : &fn->src->lines[fn->line];
1649 block->chain = block_line->u.blocks;
1650 block_line->u.blocks = block;
1652 else if (flag_branches)
1654 arc_t *arc;
1656 for (arc = block->succ; arc; arc = arc->succ_next)
1658 arc->line_next = line->u.branches;
1659 line->u.branches = arc;
1660 if (coverage && !arc->is_unconditional)
1661 add_branch_counts (coverage, arc);
1665 if (!line)
1666 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
1669 /* Accumulate the line counts of a file. */
1671 static void
1672 accumulate_line_counts (source_t *src)
1674 line_t *line;
1675 function_t *fn, *fn_p, *fn_n;
1676 unsigned ix;
1678 /* Reverse the function order. */
1679 for (fn = src->functions, fn_p = NULL; fn;
1680 fn_p = fn, fn = fn_n)
1682 fn_n = fn->line_next;
1683 fn->line_next = fn_p;
1685 src->functions = fn_p;
1687 for (ix = src->num_lines, line = src->lines; ix--; line++)
1689 if (!flag_all_blocks)
1691 arc_t *arc, *arc_p, *arc_n;
1693 /* Total and reverse the branch information. */
1694 for (arc = line->u.branches, arc_p = NULL; arc;
1695 arc_p = arc, arc = arc_n)
1697 arc_n = arc->line_next;
1698 arc->line_next = arc_p;
1700 add_branch_counts (&src->coverage, arc);
1702 line->u.branches = arc_p;
1704 else if (line->u.blocks)
1706 /* The user expects the line count to be the number of times
1707 a line has been executed. Simply summing the block count
1708 will give an artificially high number. The Right Thing
1709 is to sum the entry counts to the graph of blocks on this
1710 line, then find the elementary cycles of the local graph
1711 and add the transition counts of those cycles. */
1712 block_t *block, *block_p, *block_n;
1713 gcov_type count = 0;
1715 /* Reverse the block information. */
1716 for (block = line->u.blocks, block_p = NULL; block;
1717 block_p = block, block = block_n)
1719 block_n = block->chain;
1720 block->chain = block_p;
1721 block->u.cycle.ident = ix;
1723 line->u.blocks = block_p;
1725 /* Sum the entry arcs. */
1726 for (block = line->u.blocks; block; block = block->chain)
1728 arc_t *arc;
1730 for (arc = block->pred; arc; arc = arc->pred_next)
1732 if (arc->src->u.cycle.ident != ix)
1733 count += arc->count;
1734 if (flag_branches)
1735 add_branch_counts (&src->coverage, arc);
1738 /* Initialize the cs_count. */
1739 for (arc = block->succ; arc; arc = arc->succ_next)
1740 arc->cs_count = arc->count;
1743 /* Find the loops. This uses the algorithm described in
1744 Tiernan 'An Efficient Search Algorithm to Find the
1745 Elementary Circuits of a Graph', CACM Dec 1970. We hold
1746 the P array by having each block point to the arc that
1747 connects to the previous block. The H array is implicitly
1748 held because of the arc ordering, and the block's
1749 previous arc pointer.
1751 Although the algorithm is O(N^3) for highly connected
1752 graphs, at worst we'll have O(N^2), as most blocks have
1753 only one or two exits. Most graphs will be small.
1755 For each loop we find, locate the arc with the smallest
1756 transition count, and add that to the cumulative
1757 count. Decrease flow over the cycle and remove the arc
1758 from consideration. */
1759 for (block = line->u.blocks; block; block = block->chain)
1761 block_t *head = block;
1762 arc_t *arc;
1764 next_vertex:;
1765 arc = head->succ;
1766 current_vertex:;
1767 while (arc)
1769 block_t *dst = arc->dst;
1770 if (/* Already used that arc. */
1771 arc->cycle
1772 /* Not to same graph, or before first vertex. */
1773 || dst->u.cycle.ident != ix
1774 /* Already in path. */
1775 || dst->u.cycle.arc)
1777 arc = arc->succ_next;
1778 continue;
1781 if (dst == block)
1783 /* Found a closing arc. */
1784 gcov_type cycle_count = arc->cs_count;
1785 arc_t *cycle_arc = arc;
1786 arc_t *probe_arc;
1788 /* Locate the smallest arc count of the loop. */
1789 for (dst = head; (probe_arc = dst->u.cycle.arc);
1790 dst = probe_arc->src)
1791 if (cycle_count > probe_arc->cs_count)
1793 cycle_count = probe_arc->cs_count;
1794 cycle_arc = probe_arc;
1797 count += cycle_count;
1798 cycle_arc->cycle = 1;
1800 /* Remove the flow from the cycle. */
1801 arc->cs_count -= cycle_count;
1802 for (dst = head; (probe_arc = dst->u.cycle.arc);
1803 dst = probe_arc->src)
1804 probe_arc->cs_count -= cycle_count;
1806 /* Unwind to the cyclic arc. */
1807 while (head != cycle_arc->src)
1809 arc = head->u.cycle.arc;
1810 head->u.cycle.arc = NULL;
1811 head = arc->src;
1813 /* Move on. */
1814 arc = arc->succ_next;
1815 continue;
1818 /* Add new block to chain. */
1819 dst->u.cycle.arc = arc;
1820 head = dst;
1821 goto next_vertex;
1823 /* We could not add another vertex to the path. Remove
1824 the last vertex from the list. */
1825 arc = head->u.cycle.arc;
1826 if (arc)
1828 /* It was not the first vertex. Move onto next arc. */
1829 head->u.cycle.arc = NULL;
1830 head = arc->src;
1831 arc = arc->succ_next;
1832 goto current_vertex;
1834 /* Mark this block as unusable. */
1835 block->u.cycle.ident = ~0U;
1838 line->count = count;
1841 if (line->exists)
1843 src->coverage.lines++;
1844 if (line->count)
1845 src->coverage.lines_executed++;
1850 /* Output information about ARC number IX. Returns nonzero if
1851 anything is output. */
1853 static int
1854 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
1857 if (arc->is_call_non_return)
1859 if (arc->src->count)
1861 fnotice (gcov_file, "call %2d returned %s\n", ix,
1862 format_gcov (arc->src->count - arc->count,
1863 arc->src->count, -flag_counts));
1865 else
1866 fnotice (gcov_file, "call %2d never executed\n", ix);
1868 else if (!arc->is_unconditional)
1870 if (arc->src->count)
1871 fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
1872 format_gcov (arc->count, arc->src->count, -flag_counts),
1873 arc->fall_through ? " (fallthrough)" : "");
1874 else
1875 fnotice (gcov_file, "branch %2d never executed\n", ix);
1877 else if (flag_unconditional && !arc->dst->is_call_return)
1879 if (arc->src->count)
1880 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
1881 format_gcov (arc->count, arc->src->count, -flag_counts));
1882 else
1883 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
1885 else
1886 return 0;
1887 return 1;
1891 /* Read in the source file one line at a time, and output that line to
1892 the gcov file preceded by its execution count and other
1893 information. */
1895 static void
1896 output_lines (FILE *gcov_file, const source_t *src)
1898 FILE *source_file;
1899 unsigned line_num; /* current line number. */
1900 const line_t *line; /* current line info ptr. */
1901 char string[STRING_SIZE]; /* line buffer. */
1902 char const *retval = ""; /* status of source file reading. */
1903 function_t *fn = NULL;
1905 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
1906 if (!multiple_files)
1908 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
1909 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
1910 no_data_file ? "-" : da_file_name);
1911 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
1912 object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
1914 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
1916 source_file = fopen (src->name, "r");
1917 if (!source_file)
1919 fnotice (stderr, "%s:cannot open source file\n", src->name);
1920 retval = NULL;
1922 else if (src->file_time == 0)
1923 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0);
1925 if (flag_branches)
1926 fn = src->functions;
1928 for (line_num = 1, line = &src->lines[line_num];
1929 line_num < src->num_lines; line_num++, line++)
1931 for (; fn && fn->line == line_num; fn = fn->line_next)
1933 arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
1934 gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
1936 for (; arc; arc = arc->pred_next)
1937 if (arc->fake)
1938 return_count -= arc->count;
1940 fprintf (gcov_file, "function %s", fn->name);
1941 fprintf (gcov_file, " called %s",
1942 format_gcov (fn->blocks[0].count, 0, -1));
1943 fprintf (gcov_file, " returned %s",
1944 format_gcov (return_count, fn->blocks[0].count, 0));
1945 fprintf (gcov_file, " blocks executed %s",
1946 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
1947 fprintf (gcov_file, "\n");
1950 /* For lines which don't exist in the .bb file, print '-' before
1951 the source line. For lines which exist but were never
1952 executed, print '#####' before the source line. Otherwise,
1953 print the execution count before the source line. There are
1954 16 spaces of indentation added before the source line so that
1955 tabs won't be messed up. */
1956 fprintf (gcov_file, "%9s:%5u:",
1957 !line->exists ? "-" : !line->count ? "#####"
1958 : format_gcov (line->count, 0, -1), line_num);
1960 if (retval)
1962 /* Copy source line. */
1965 retval = fgets (string, STRING_SIZE, source_file);
1966 if (!retval)
1967 break;
1968 fputs (retval, gcov_file);
1970 while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1972 if (!retval)
1973 fputs ("/*EOF*/\n", gcov_file);
1975 if (flag_all_blocks)
1977 block_t *block;
1978 arc_t *arc;
1979 int ix, jx;
1981 for (ix = jx = 0, block = line->u.blocks; block;
1982 block = block->chain)
1984 if (!block->is_call_return)
1985 fprintf (gcov_file, "%9s:%5u-block %2d\n",
1986 !line->exists ? "-" : !block->count ? "$$$$$"
1987 : format_gcov (block->count, 0, -1),
1988 line_num, ix++);
1989 if (flag_branches)
1990 for (arc = block->succ; arc; arc = arc->succ_next)
1991 jx += output_branch_count (gcov_file, jx, arc);
1994 else if (flag_branches)
1996 int ix;
1997 arc_t *arc;
1999 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
2000 ix += output_branch_count (gcov_file, ix, arc);
2004 /* Handle all remaining source lines. There may be lines after the
2005 last line of code. */
2006 if (retval)
2008 for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
2010 fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval);
2012 while (!retval[0] || retval[strlen (retval) - 1] != '\n')
2014 retval = fgets (string, STRING_SIZE, source_file);
2015 if (!retval)
2016 break;
2017 fputs (retval, gcov_file);
2022 if (source_file)
2023 fclose (source_file);