new tests
[official-gcc.git] / gcc / gcov.c
blob27ae036740a67ed7f27993aa9611a32dbefc7303
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 "version.h"
42 #include <getopt.h>
44 #define IN_GCOV 1
45 #include "gcov-io.h"
46 #include "gcov-io.c"
48 /* The gcno file is generated by -ftest-coverage option. The gcda file is
49 generated by a program compiled with -fprofile-arcs. Their formats
50 are documented in gcov-io.h. */
52 /* The functions in this file for creating and solution program flow graphs
53 are very similar to functions in the gcc source file profile.c. In
54 some places we make use of the knowledge of how profile.c works to
55 select particular algorithms here. */
57 /* The code validates that the profile information read in corresponds
58 to the code currently being compiled. Rather than checking for
59 identical files, the code below computes a checksum on the CFG
60 (based on the order of basic blocks and the arcs in the CFG). If
61 the CFG checksum in the gcda file match the CFG checksum for the
62 code currently being compiled, the profile data will be used. */
64 /* This is the size of the buffer used to read in source file lines. */
66 #define STRING_SIZE 200
68 struct function_info;
69 struct block_info;
70 struct source_info;
72 /* Describes an arc between two basic blocks. */
74 typedef struct arc_info
76 /* source and destination blocks. */
77 struct block_info *src;
78 struct block_info *dst;
80 /* transition counts. */
81 gcov_type count;
82 /* used in cycle search, so that we do not clobber original counts. */
83 gcov_type cs_count;
85 unsigned int count_valid : 1;
86 unsigned int on_tree : 1;
87 unsigned int fake : 1;
88 unsigned int fall_through : 1;
90 /* Arc is for a function that abnormally returns. */
91 unsigned int is_call_non_return : 1;
93 /* Arc is for catch/setjmp. */
94 unsigned int is_nonlocal_return : 1;
96 /* Is an unconditional branch. */
97 unsigned int is_unconditional : 1;
99 /* Loop making arc. */
100 unsigned int cycle : 1;
102 /* Next branch on line. */
103 struct arc_info *line_next;
105 /* Links to next arc on src and dst lists. */
106 struct arc_info *succ_next;
107 struct arc_info *pred_next;
108 } arc_t;
110 /* Describes a basic block. Contains lists of arcs to successor and
111 predecessor blocks. */
113 typedef struct block_info
115 /* Chain of exit and entry arcs. */
116 arc_t *succ;
117 arc_t *pred;
119 /* Number of unprocessed exit and entry arcs. */
120 gcov_type num_succ;
121 gcov_type num_pred;
123 /* Block execution count. */
124 gcov_type count;
125 unsigned flags : 13;
126 unsigned count_valid : 1;
127 unsigned valid_chain : 1;
128 unsigned invalid_chain : 1;
130 /* Block is a call instrumenting site. */
131 unsigned is_call_site : 1; /* Does the call. */
132 unsigned is_call_return : 1; /* Is the return. */
134 /* Block is a landing pad for longjmp or throw. */
135 unsigned is_nonlocal_return : 1;
137 union
139 struct
141 /* Array of line numbers and source files. source files are
142 introduced by a linenumber of zero, the next 'line number' is
143 the number of the source file. Always starts with a source
144 file. */
145 unsigned *encoding;
146 unsigned num;
147 } line; /* Valid until blocks are linked onto lines */
148 struct
150 /* Single line graph cycle workspace. Used for all-blocks
151 mode. */
152 arc_t *arc;
153 unsigned ident;
154 } cycle; /* Used in all-blocks mode, after blocks are linked onto
155 lines. */
156 } u;
158 /* Temporary chain for solving graph, and for chaining blocks on one
159 line. */
160 struct block_info *chain;
162 } block_t;
164 /* Describes a single function. Contains an array of basic blocks. */
166 typedef struct function_info
168 /* Name of function. */
169 char *name;
170 unsigned ident;
171 unsigned lineno_checksum;
172 unsigned cfg_checksum;
174 /* Array of basic blocks. */
175 block_t *blocks;
176 unsigned num_blocks;
177 unsigned blocks_executed;
179 /* Raw arc coverage counts. */
180 gcov_type *counts;
181 unsigned num_counts;
183 /* First line number. */
184 unsigned line;
185 struct source_info *src;
187 /* Next function in same source file. */
188 struct function_info *line_next;
190 /* Next function. */
191 struct function_info *next;
192 } function_t;
194 /* Describes coverage of a file or function. */
196 typedef struct coverage_info
198 int lines;
199 int lines_executed;
201 int branches;
202 int branches_executed;
203 int branches_taken;
205 int calls;
206 int calls_executed;
208 char *name;
209 } coverage_t;
211 /* Describes a single line of source. Contains a chain of basic blocks
212 with code on it. */
214 typedef struct line_info
216 gcov_type count; /* execution count */
217 union
219 arc_t *branches; /* branches from blocks that end on this
220 line. Used for branch-counts when not
221 all-blocks mode. */
222 block_t *blocks; /* blocks which start on this line. Used
223 in all-blocks mode. */
224 } u;
225 unsigned exists : 1;
226 } line_t;
228 /* Describes a file mentioned in the block graph. Contains an array
229 of line info. */
231 typedef struct source_info
233 /* Name of source file. */
234 char *name;
235 unsigned index;
236 time_t file_time;
238 /* Array of line information. */
239 line_t *lines;
240 unsigned num_lines;
242 coverage_t coverage;
244 /* Functions in this source file. These are in ascending line
245 number order. */
246 function_t *functions;
248 /* Next source file. */
249 struct source_info *next;
250 } source_t;
252 /* Holds a list of function basic block graphs. */
254 static function_t *functions;
256 /* This points to the head of the sourcefile structure list. New elements
257 are always prepended. */
259 static source_t *sources;
261 /* Next index for a source file. */
263 static unsigned source_index;
265 /* This holds data summary information. */
267 static struct gcov_summary object_summary;
268 static unsigned program_count;
270 /* Modification time of graph file. */
272 static time_t bbg_file_time;
274 /* Name and file pointer of the input file for the basic block graph. */
276 static char *bbg_file_name;
278 /* Stamp of the bbg file */
279 static unsigned bbg_stamp;
281 /* Name and file pointer of the input file for the arc count data. */
283 static char *da_file_name;
285 /* Data file is missing. */
287 static int no_data_file;
289 /* If there is several input files, compute and display results after
290 reading all data files. This way if two or more gcda file refer to
291 the same source file (eg inline subprograms in a .h file), the
292 counts are added. */
294 static int multiple_files = 0;
296 /* Output branch probabilities. */
298 static int flag_branches = 0;
300 /* Show unconditional branches too. */
301 static int flag_unconditional = 0;
303 /* Output a gcov file if this is true. This is on by default, and can
304 be turned off by the -n option. */
306 static int flag_gcov_file = 1;
308 /* Output progress indication if this is true. This is off by default
309 and can be turned on by the -d option. */
311 static int flag_display_progress = 0;
313 /* For included files, make the gcov output file name include the name
314 of the input source file. For example, if x.h is included in a.c,
315 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
317 static int flag_long_names = 0;
319 /* Output count information for every basic block, not merely those
320 that contain line number information. */
322 static int flag_all_blocks = 0;
324 /* Output summary info for each function. */
326 static int flag_function_summary = 0;
328 /* Object directory file prefix. This is the directory/file where the
329 graph and data files are looked for, if nonzero. */
331 static char *object_directory = 0;
333 /* Preserve all pathname components. Needed when object files and
334 source files are in subdirectories. '/' is mangled as '#', '.' is
335 elided and '..' mangled to '^'. */
337 static int flag_preserve_paths = 0;
339 /* Output the number of times a branch was taken as opposed to the percentage
340 of times it was taken. */
342 static int flag_counts = 0;
344 /* Forward declarations. */
345 static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2;
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;
373 /* Unlock the stdio streams. */
374 unlock_std_streams ();
376 gcc_init_libintl ();
378 /* Handle response files. */
379 expandargv (&argc, &argv);
381 argno = process_args (argc, argv);
382 if (optind == argc)
383 print_usage (true);
385 if (argc - argno > 1)
386 multiple_files = 1;
388 first_arg = argno;
390 for (; argno != argc; argno++)
392 if (flag_display_progress)
393 printf("Processing file %d out of %d\n",
394 argno - first_arg + 1, argc - first_arg);
395 process_file (argv[argno]);
398 generate_results (multiple_files ? NULL : argv[argc - 1]);
400 release_structures ();
402 return 0;
405 static void
406 fnotice (FILE *file, const char *cmsgid, ...)
408 va_list ap;
410 va_start (ap, cmsgid);
411 vfprintf (file, _(cmsgid), ap);
412 va_end (ap);
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 looked for in the current directory,
657 and named from the basename of the FILE_NAME sans extension. If
658 OBJECT_DIRECTORY is specified and is a directory, the files are in
659 that directory, but named from the basename of the FILE_NAME, sans
660 extension. Otherwise OBJECT_DIRECTORY is taken to be the name of
661 the object *file*, and the data files are named from that. */
663 static void
664 create_file_names (const char *file_name)
666 char *cptr;
667 char *name;
668 int length = strlen (file_name);
669 int base;
671 /* Free previous file names. */
672 free (bbg_file_name);
673 free (da_file_name);
674 da_file_name = bbg_file_name = NULL;
675 bbg_file_time = 0;
676 bbg_stamp = 0;
678 if (object_directory && object_directory[0])
680 struct stat status;
682 length += strlen (object_directory) + 2;
683 name = XNEWVEC (char, length);
684 name[0] = 0;
686 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
687 strcat (name, object_directory);
688 if (base && (! IS_DIR_SEPARATOR (name[strlen (name) - 1])))
689 strcat (name, "/");
691 else
693 name = XNEWVEC (char, length + 1);
694 name[0] = 0;
695 base = 1;
698 if (base)
700 /* Append source file name. */
701 const char *cptr = lbasename (file_name);
702 strcat (name, cptr ? cptr : file_name);
705 /* Remove the extension. */
706 cptr = strrchr (name, '.');
707 if (cptr)
708 *cptr = 0;
710 length = strlen (name);
712 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
713 strcpy (bbg_file_name, name);
714 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
716 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
717 strcpy (da_file_name, name);
718 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
720 free (name);
721 return;
724 /* Find or create a source file structure for FILE_NAME. Copies
725 FILE_NAME on creation */
727 static source_t *
728 find_source (const char *file_name)
730 source_t *src;
731 struct stat status;
733 if (!file_name)
734 file_name = "<unknown>";
736 for (src = sources; src; src = src->next)
737 if (!filename_cmp (file_name, src->name))
738 break;
740 if (!src)
742 src = XCNEW (source_t);
743 src->name = xstrdup (file_name);
744 src->coverage.name = src->name;
745 src->index = source_index++;
746 src->next = sources;
747 sources = src;
749 if (!stat (file_name, &status))
750 src->file_time = status.st_mtime;
753 if (src->file_time > bbg_file_time)
755 static int info_emitted;
757 fnotice (stderr, "%s:source file is newer than graph file '%s'\n",
758 src->name, bbg_file_name);
759 if (!info_emitted)
761 fnotice (stderr,
762 "(the message is only displayed one per source file)\n");
763 info_emitted = 1;
765 src->file_time = 0;
768 return src;
771 /* Read the graph file. Return nonzero on fatal error. */
773 static int
774 read_graph_file (void)
776 unsigned version;
777 unsigned current_tag = 0;
778 struct function_info *fn = NULL;
779 function_t *old_functions_head = functions;
780 source_t *src = NULL;
781 unsigned ix;
782 unsigned tag;
784 if (!gcov_open (bbg_file_name, 1))
786 fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
787 return 1;
789 bbg_file_time = gcov_time ();
790 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
792 fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
793 gcov_close ();
794 return 1;
797 version = gcov_read_unsigned ();
798 if (version != GCOV_VERSION)
800 char v[4], e[4];
802 GCOV_UNSIGNED2STRING (v, version);
803 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
805 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
806 bbg_file_name, v, e);
808 bbg_stamp = gcov_read_unsigned ();
810 while ((tag = gcov_read_unsigned ()))
812 unsigned length = gcov_read_unsigned ();
813 gcov_position_t base = gcov_position ();
815 if (tag == GCOV_TAG_FUNCTION)
817 char *function_name;
818 unsigned ident, lineno;
819 unsigned lineno_checksum, cfg_checksum;
820 source_t *src;
821 function_t *probe, *prev;
823 ident = gcov_read_unsigned ();
824 lineno_checksum = gcov_read_unsigned ();
825 cfg_checksum = gcov_read_unsigned ();
826 function_name = xstrdup (gcov_read_string ());
827 src = find_source (gcov_read_string ());
828 lineno = gcov_read_unsigned ();
830 fn = XCNEW (function_t);
831 fn->name = function_name;
832 fn->ident = ident;
833 fn->lineno_checksum = lineno_checksum;
834 fn->cfg_checksum = cfg_checksum;
835 fn->src = src;
836 fn->line = lineno;
838 fn->next = functions;
839 functions = fn;
840 current_tag = tag;
842 if (lineno >= src->num_lines)
843 src->num_lines = lineno + 1;
844 /* Now insert it into the source file's list of
845 functions. Normally functions will be encountered in
846 ascending order, so a simple scan is quick. */
847 for (probe = src->functions, prev = NULL;
848 probe && probe->line > lineno;
849 prev = probe, probe = probe->line_next)
850 continue;
851 fn->line_next = probe;
852 if (prev)
853 prev->line_next = fn;
854 else
855 src->functions = fn;
857 else if (fn && tag == GCOV_TAG_BLOCKS)
859 if (fn->blocks)
860 fnotice (stderr, "%s:already seen blocks for '%s'\n",
861 bbg_file_name, fn->name);
862 else
864 unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
865 fn->num_blocks = num_blocks;
867 fn->blocks = XCNEWVEC (block_t, fn->num_blocks);
868 for (ix = 0; ix != num_blocks; ix++)
869 fn->blocks[ix].flags = gcov_read_unsigned ();
872 else if (fn && tag == GCOV_TAG_ARCS)
874 unsigned src = gcov_read_unsigned ();
875 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
877 if (src >= fn->num_blocks || fn->blocks[src].succ)
878 goto corrupt;
880 while (num_dests--)
882 struct arc_info *arc;
883 unsigned dest = gcov_read_unsigned ();
884 unsigned flags = gcov_read_unsigned ();
886 if (dest >= fn->num_blocks)
887 goto corrupt;
888 arc = XCNEW (arc_t);
890 arc->dst = &fn->blocks[dest];
891 arc->src = &fn->blocks[src];
893 arc->count = 0;
894 arc->count_valid = 0;
895 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
896 arc->fake = !!(flags & GCOV_ARC_FAKE);
897 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
899 arc->succ_next = fn->blocks[src].succ;
900 fn->blocks[src].succ = arc;
901 fn->blocks[src].num_succ++;
903 arc->pred_next = fn->blocks[dest].pred;
904 fn->blocks[dest].pred = arc;
905 fn->blocks[dest].num_pred++;
907 if (arc->fake)
909 if (src)
911 /* Exceptional exit from this function, the
912 source block must be a call. */
913 fn->blocks[src].is_call_site = 1;
914 arc->is_call_non_return = 1;
916 else
918 /* Non-local return from a callee of this
919 function. The destination block is a catch or
920 setjmp. */
921 arc->is_nonlocal_return = 1;
922 fn->blocks[dest].is_nonlocal_return = 1;
926 if (!arc->on_tree)
927 fn->num_counts++;
930 else if (fn && tag == GCOV_TAG_LINES)
932 unsigned blockno = gcov_read_unsigned ();
933 unsigned *line_nos = XCNEWVEC (unsigned, length - 1);
935 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
936 goto corrupt;
938 for (ix = 0; ; )
940 unsigned lineno = gcov_read_unsigned ();
942 if (lineno)
944 if (!ix)
946 line_nos[ix++] = 0;
947 line_nos[ix++] = src->index;
949 line_nos[ix++] = lineno;
950 if (lineno >= src->num_lines)
951 src->num_lines = lineno + 1;
953 else
955 const char *file_name = gcov_read_string ();
957 if (!file_name)
958 break;
959 src = find_source (file_name);
961 line_nos[ix++] = 0;
962 line_nos[ix++] = src->index;
966 fn->blocks[blockno].u.line.encoding = line_nos;
967 fn->blocks[blockno].u.line.num = ix;
969 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
971 fn = NULL;
972 current_tag = 0;
974 gcov_sync (base, length);
975 if (gcov_is_error ())
977 corrupt:;
978 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
979 gcov_close ();
980 return 1;
983 gcov_close ();
985 /* We built everything backwards, so nreverse them all. */
987 /* Reverse sources. Not strictly necessary, but we'll then process
988 them in the 'expected' order. */
990 source_t *src, *src_p, *src_n;
992 for (src_p = NULL, src = sources; src; src_p = src, src = src_n)
994 src_n = src->next;
995 src->next = src_p;
997 sources = src_p;
1000 /* Reverse functions. */
1002 function_t *fn, *fn_p, *fn_n;
1004 for (fn_p = old_functions_head, fn = functions;
1005 fn != old_functions_head;
1006 fn_p = fn, fn = fn_n)
1008 unsigned ix;
1010 fn_n = fn->next;
1011 fn->next = fn_p;
1013 /* Reverse the arcs. */
1014 for (ix = fn->num_blocks; ix--;)
1016 arc_t *arc, *arc_p, *arc_n;
1018 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
1019 arc_p = arc, arc = arc_n)
1021 arc_n = arc->succ_next;
1022 arc->succ_next = arc_p;
1024 fn->blocks[ix].succ = arc_p;
1026 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
1027 arc_p = arc, arc = arc_n)
1029 arc_n = arc->pred_next;
1030 arc->pred_next = arc_p;
1032 fn->blocks[ix].pred = arc_p;
1035 functions = fn_p;
1037 return 0;
1040 /* Reads profiles from the count file and attach to each
1041 function. Return nonzero if fatal error. */
1043 static int
1044 read_count_file (void)
1046 unsigned ix;
1047 unsigned version;
1048 unsigned tag;
1049 function_t *fn = NULL;
1050 int error = 0;
1052 if (!gcov_open (da_file_name, 1))
1054 fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
1055 da_file_name);
1056 no_data_file = 1;
1057 return 0;
1059 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
1061 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
1062 cleanup:;
1063 gcov_close ();
1064 return 1;
1066 version = gcov_read_unsigned ();
1067 if (version != GCOV_VERSION)
1069 char v[4], e[4];
1071 GCOV_UNSIGNED2STRING (v, version);
1072 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1074 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
1075 da_file_name, v, e);
1077 tag = gcov_read_unsigned ();
1078 if (tag != bbg_stamp)
1080 fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
1081 goto cleanup;
1084 while ((tag = gcov_read_unsigned ()))
1086 unsigned length = gcov_read_unsigned ();
1087 unsigned long base = gcov_position ();
1089 if (tag == GCOV_TAG_OBJECT_SUMMARY)
1090 gcov_read_summary (&object_summary);
1091 else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1092 program_count++;
1093 else if (tag == GCOV_TAG_FUNCTION)
1096 unsigned ident = gcov_read_unsigned ();
1097 struct function_info *fn_n = functions;
1099 /* Try to find the function in the list.
1100 To speed up the search, first start from the last function
1101 found. */
1102 for (fn = fn ? fn->next : NULL; ; fn = fn->next)
1104 if (fn)
1106 else if ((fn = fn_n))
1107 fn_n = NULL;
1108 else
1110 fnotice (stderr, "%s:unknown function '%u'\n",
1111 da_file_name, ident);
1112 break;
1114 if (fn->ident == ident)
1115 break;
1119 if (!fn)
1121 else if (gcov_read_unsigned () != fn->lineno_checksum
1122 || gcov_read_unsigned () != fn->cfg_checksum)
1124 mismatch:;
1125 fnotice (stderr, "%s:profile mismatch for '%s'\n",
1126 da_file_name, fn->name);
1127 goto cleanup;
1130 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1132 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
1133 goto mismatch;
1135 if (!fn->counts)
1136 fn->counts = XCNEWVEC (gcov_type, fn->num_counts);
1138 for (ix = 0; ix != fn->num_counts; ix++)
1139 fn->counts[ix] += gcov_read_counter ();
1141 gcov_sync (base, length);
1142 if ((error = gcov_is_error ()))
1144 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1145 da_file_name);
1146 goto cleanup;
1150 gcov_close ();
1151 return 0;
1154 /* Solve the flow graph. Propagate counts from the instrumented arcs
1155 to the blocks and the uninstrumented arcs. */
1157 static void
1158 solve_flow_graph (function_t *fn)
1160 unsigned ix;
1161 arc_t *arc;
1162 gcov_type *count_ptr = fn->counts;
1163 block_t *blk;
1164 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */
1165 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
1167 if (fn->num_blocks < 2)
1168 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
1169 bbg_file_name, fn->name);
1170 else
1172 if (fn->blocks[0].num_pred)
1173 fnotice (stderr, "%s:'%s' has arcs to entry block\n",
1174 bbg_file_name, fn->name);
1175 else
1176 /* We can't deduce the entry block counts from the lack of
1177 predecessors. */
1178 fn->blocks[0].num_pred = ~(unsigned)0;
1180 if (fn->blocks[fn->num_blocks - 1].num_succ)
1181 fnotice (stderr, "%s:'%s' has arcs from exit block\n",
1182 bbg_file_name, fn->name);
1183 else
1184 /* Likewise, we can't deduce exit block counts from the lack
1185 of its successors. */
1186 fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0;
1189 /* Propagate the measured counts, this must be done in the same
1190 order as the code in profile.c */
1191 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
1193 block_t const *prev_dst = NULL;
1194 int out_of_order = 0;
1195 int non_fake_succ = 0;
1197 for (arc = blk->succ; arc; arc = arc->succ_next)
1199 if (!arc->fake)
1200 non_fake_succ++;
1202 if (!arc->on_tree)
1204 if (count_ptr)
1205 arc->count = *count_ptr++;
1206 arc->count_valid = 1;
1207 blk->num_succ--;
1208 arc->dst->num_pred--;
1210 if (prev_dst && prev_dst > arc->dst)
1211 out_of_order = 1;
1212 prev_dst = arc->dst;
1214 if (non_fake_succ == 1)
1216 /* If there is only one non-fake exit, it is an
1217 unconditional branch. */
1218 for (arc = blk->succ; arc; arc = arc->succ_next)
1219 if (!arc->fake)
1221 arc->is_unconditional = 1;
1222 /* If this block is instrumenting a call, it might be
1223 an artificial block. It is not artificial if it has
1224 a non-fallthrough exit, or the destination of this
1225 arc has more than one entry. Mark the destination
1226 block as a return site, if none of those conditions
1227 hold. */
1228 if (blk->is_call_site && arc->fall_through
1229 && arc->dst->pred == arc && !arc->pred_next)
1230 arc->dst->is_call_return = 1;
1234 /* Sort the successor arcs into ascending dst order. profile.c
1235 normally produces arcs in the right order, but sometimes with
1236 one or two out of order. We're not using a particularly
1237 smart sort. */
1238 if (out_of_order)
1240 arc_t *start = blk->succ;
1241 unsigned changes = 1;
1243 while (changes)
1245 arc_t *arc, *arc_p, *arc_n;
1247 changes = 0;
1248 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1250 if (arc->dst > arc_n->dst)
1252 changes = 1;
1253 if (arc_p)
1254 arc_p->succ_next = arc_n;
1255 else
1256 start = arc_n;
1257 arc->succ_next = arc_n->succ_next;
1258 arc_n->succ_next = arc;
1259 arc_p = arc_n;
1261 else
1263 arc_p = arc;
1264 arc = arc_n;
1268 blk->succ = start;
1271 /* Place it on the invalid chain, it will be ignored if that's
1272 wrong. */
1273 blk->invalid_chain = 1;
1274 blk->chain = invalid_blocks;
1275 invalid_blocks = blk;
1278 while (invalid_blocks || valid_blocks)
1280 while ((blk = invalid_blocks))
1282 gcov_type total = 0;
1283 const arc_t *arc;
1285 invalid_blocks = blk->chain;
1286 blk->invalid_chain = 0;
1287 if (!blk->num_succ)
1288 for (arc = blk->succ; arc; arc = arc->succ_next)
1289 total += arc->count;
1290 else if (!blk->num_pred)
1291 for (arc = blk->pred; arc; arc = arc->pred_next)
1292 total += arc->count;
1293 else
1294 continue;
1296 blk->count = total;
1297 blk->count_valid = 1;
1298 blk->chain = valid_blocks;
1299 blk->valid_chain = 1;
1300 valid_blocks = blk;
1302 while ((blk = valid_blocks))
1304 gcov_type total;
1305 arc_t *arc, *inv_arc;
1307 valid_blocks = blk->chain;
1308 blk->valid_chain = 0;
1309 if (blk->num_succ == 1)
1311 block_t *dst;
1313 total = blk->count;
1314 inv_arc = NULL;
1315 for (arc = blk->succ; arc; arc = arc->succ_next)
1317 total -= arc->count;
1318 if (!arc->count_valid)
1319 inv_arc = arc;
1321 dst = inv_arc->dst;
1322 inv_arc->count_valid = 1;
1323 inv_arc->count = total;
1324 blk->num_succ--;
1325 dst->num_pred--;
1326 if (dst->count_valid)
1328 if (dst->num_pred == 1 && !dst->valid_chain)
1330 dst->chain = valid_blocks;
1331 dst->valid_chain = 1;
1332 valid_blocks = dst;
1335 else
1337 if (!dst->num_pred && !dst->invalid_chain)
1339 dst->chain = invalid_blocks;
1340 dst->invalid_chain = 1;
1341 invalid_blocks = dst;
1345 if (blk->num_pred == 1)
1347 block_t *src;
1349 total = blk->count;
1350 inv_arc = NULL;
1351 for (arc = blk->pred; arc; arc = arc->pred_next)
1353 total -= arc->count;
1354 if (!arc->count_valid)
1355 inv_arc = arc;
1357 src = inv_arc->src;
1358 inv_arc->count_valid = 1;
1359 inv_arc->count = total;
1360 blk->num_pred--;
1361 src->num_succ--;
1362 if (src->count_valid)
1364 if (src->num_succ == 1 && !src->valid_chain)
1366 src->chain = valid_blocks;
1367 src->valid_chain = 1;
1368 valid_blocks = src;
1371 else
1373 if (!src->num_succ && !src->invalid_chain)
1375 src->chain = invalid_blocks;
1376 src->invalid_chain = 1;
1377 invalid_blocks = src;
1384 /* If the graph has been correctly solved, every block will have a
1385 valid count. */
1386 for (ix = 0; ix < fn->num_blocks; ix++)
1387 if (!fn->blocks[ix].count_valid)
1389 fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
1390 bbg_file_name, fn->name);
1391 break;
1397 /* Increment totals in COVERAGE according to arc ARC. */
1399 static void
1400 add_branch_counts (coverage_t *coverage, const arc_t *arc)
1402 if (arc->is_call_non_return)
1404 coverage->calls++;
1405 if (arc->src->count)
1406 coverage->calls_executed++;
1408 else if (!arc->is_unconditional)
1410 coverage->branches++;
1411 if (arc->src->count)
1412 coverage->branches_executed++;
1413 if (arc->count)
1414 coverage->branches_taken++;
1418 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1419 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1420 If DP is zero, no decimal point is printed. Only print 100% when
1421 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1422 format TOP. Return pointer to a static string. */
1424 static char const *
1425 format_gcov (gcov_type top, gcov_type bottom, int dp)
1427 static char buffer[20];
1429 if (dp >= 0)
1431 float ratio = bottom ? (float)top / bottom : 0;
1432 int ix;
1433 unsigned limit = 100;
1434 unsigned percent;
1436 for (ix = dp; ix--; )
1437 limit *= 10;
1439 percent = (unsigned) (ratio * limit + (float)0.5);
1440 if (percent <= 0 && top)
1441 percent = 1;
1442 else if (percent >= limit && top != bottom)
1443 percent = limit - 1;
1444 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1445 if (dp)
1447 dp++;
1450 buffer[ix+1] = buffer[ix];
1451 ix--;
1453 while (dp--);
1454 buffer[ix + 1] = '.';
1457 else
1458 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
1460 return buffer;
1464 /* Output summary info for a function. */
1466 static void
1467 function_summary (const coverage_t *coverage, const char *title)
1469 fnotice (stdout, "%s '%s'\n", title, coverage->name);
1471 if (coverage->lines)
1472 fnotice (stdout, "Lines executed:%s of %d\n",
1473 format_gcov (coverage->lines_executed, coverage->lines, 2),
1474 coverage->lines);
1475 else
1476 fnotice (stdout, "No executable lines\n");
1478 if (flag_branches)
1480 if (coverage->branches)
1482 fnotice (stdout, "Branches executed:%s of %d\n",
1483 format_gcov (coverage->branches_executed,
1484 coverage->branches, 2),
1485 coverage->branches);
1486 fnotice (stdout, "Taken at least once:%s of %d\n",
1487 format_gcov (coverage->branches_taken,
1488 coverage->branches, 2),
1489 coverage->branches);
1491 else
1492 fnotice (stdout, "No branches\n");
1493 if (coverage->calls)
1494 fnotice (stdout, "Calls executed:%s of %d\n",
1495 format_gcov (coverage->calls_executed, coverage->calls, 2),
1496 coverage->calls);
1497 else
1498 fnotice (stdout, "No calls\n");
1502 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1503 affect name generation. With preserve_paths we create a filename
1504 from all path components of the source file, replacing '/' with
1505 '#', without it we simply take the basename component. With
1506 long_output_names we prepend the processed name of the input file
1507 to each output name (except when the current source file is the
1508 input file, so you don't get a double concatenation). The two
1509 components are separated by '##'. Also '.' filename components are
1510 removed and '..' components are renamed to '^'. */
1512 static char *
1513 make_gcov_file_name (const char *input_name, const char *src_name)
1515 const char *cptr;
1516 char *name;
1518 if (flag_long_names && input_name && strcmp (src_name, input_name))
1520 name = XNEWVEC (char, strlen (src_name) + strlen (input_name) + 10);
1521 name[0] = 0;
1522 /* Generate the input filename part. */
1523 cptr = flag_preserve_paths ? NULL : lbasename (input_name);
1524 strcat (name, cptr ? cptr : input_name);
1525 strcat (name, "##");
1527 else
1529 name = XNEWVEC (char, strlen (src_name) + 10);
1530 name[0] = 0;
1533 /* Generate the source filename part. */
1535 cptr = flag_preserve_paths ? NULL : lbasename (src_name);
1536 strcat (name, cptr ? cptr : src_name);
1538 if (flag_preserve_paths)
1540 /* Convert '/' and '\' to '#', remove '/./', convert '/../' to '#^#',
1541 convert ':' to '~' on DOS based file system. */
1542 char *pnew = name, *pold = name;
1544 /* First check for leading drive separator. */
1546 while (*pold != '\0')
1548 #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
1549 if (*pold == ':')
1551 *pnew++ = '~';
1552 pold++;
1554 else
1555 #endif
1556 if ((*pold == '/'
1557 && (strstr (pold, "/./") == pold
1558 || strstr (pold, "/.\\") == pold))
1559 || (*pold == '\\'
1560 && (strstr (pold, "\\.\\") == pold
1561 || strstr (pold, "\\./") == pold)))
1562 pold += 3;
1563 else if (*pold == '/'
1564 && (strstr (pold, "/../") == pold
1565 || strstr (pold, "/..\\") == pold))
1567 strcpy (pnew, "#^#");
1568 pnew += 3;
1569 pold += 4;
1571 else if (*pold == '\\'
1572 && (strstr (pold, "\\..\\") == pold
1573 || strstr (pold, "\\../") == pold))
1575 strcpy (pnew, "#^#");
1576 pnew += 3;
1577 pold += 4;
1579 else if (*pold == '/' || *pold == '\\')
1581 *pnew++ = '#';
1582 pold++;
1584 else
1585 *pnew++ = *pold++;
1588 *pnew = '\0';
1591 strcat (name, ".gcov");
1592 return name;
1595 /* Scan through the bb_data for each line in the block, increment
1596 the line number execution count indicated by the execution count of
1597 the appropriate basic block. */
1599 static void
1600 add_line_counts (coverage_t *coverage, function_t *fn)
1602 unsigned ix;
1603 line_t *line = NULL; /* This is propagated from one iteration to the
1604 next. */
1606 /* Scan each basic block. */
1607 for (ix = 0; ix != fn->num_blocks; ix++)
1609 block_t *block = &fn->blocks[ix];
1610 unsigned *encoding;
1611 const source_t *src = NULL;
1612 unsigned jx;
1614 if (block->count && ix && ix + 1 != fn->num_blocks)
1615 fn->blocks_executed++;
1616 for (jx = 0, encoding = block->u.line.encoding;
1617 jx != block->u.line.num; jx++, encoding++)
1618 if (!*encoding)
1620 unsigned src_n = *++encoding;
1622 for (src = sources; src->index != src_n; src = src->next)
1623 continue;
1624 jx++;
1626 else
1628 line = &src->lines[*encoding];
1630 if (coverage)
1632 if (!line->exists)
1633 coverage->lines++;
1634 if (!line->count && block->count)
1635 coverage->lines_executed++;
1637 line->exists = 1;
1638 line->count += block->count;
1640 free (block->u.line.encoding);
1641 block->u.cycle.arc = NULL;
1642 block->u.cycle.ident = ~0U;
1644 if (!ix || ix + 1 == fn->num_blocks)
1645 /* Entry or exit block */;
1646 else if (flag_all_blocks)
1648 line_t *block_line = line ? line : &fn->src->lines[fn->line];
1650 block->chain = block_line->u.blocks;
1651 block_line->u.blocks = block;
1653 else if (flag_branches)
1655 arc_t *arc;
1657 for (arc = block->succ; arc; arc = arc->succ_next)
1659 arc->line_next = line->u.branches;
1660 line->u.branches = arc;
1661 if (coverage && !arc->is_unconditional)
1662 add_branch_counts (coverage, arc);
1666 if (!line)
1667 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
1670 /* Accumulate the line counts of a file. */
1672 static void
1673 accumulate_line_counts (source_t *src)
1675 line_t *line;
1676 function_t *fn, *fn_p, *fn_n;
1677 unsigned ix;
1679 /* Reverse the function order. */
1680 for (fn = src->functions, fn_p = NULL; fn;
1681 fn_p = fn, fn = fn_n)
1683 fn_n = fn->line_next;
1684 fn->line_next = fn_p;
1686 src->functions = fn_p;
1688 for (ix = src->num_lines, line = src->lines; ix--; line++)
1690 if (!flag_all_blocks)
1692 arc_t *arc, *arc_p, *arc_n;
1694 /* Total and reverse the branch information. */
1695 for (arc = line->u.branches, arc_p = NULL; arc;
1696 arc_p = arc, arc = arc_n)
1698 arc_n = arc->line_next;
1699 arc->line_next = arc_p;
1701 add_branch_counts (&src->coverage, arc);
1703 line->u.branches = arc_p;
1705 else if (line->u.blocks)
1707 /* The user expects the line count to be the number of times
1708 a line has been executed. Simply summing the block count
1709 will give an artificially high number. The Right Thing
1710 is to sum the entry counts to the graph of blocks on this
1711 line, then find the elementary cycles of the local graph
1712 and add the transition counts of those cycles. */
1713 block_t *block, *block_p, *block_n;
1714 gcov_type count = 0;
1716 /* Reverse the block information. */
1717 for (block = line->u.blocks, block_p = NULL; block;
1718 block_p = block, block = block_n)
1720 block_n = block->chain;
1721 block->chain = block_p;
1722 block->u.cycle.ident = ix;
1724 line->u.blocks = block_p;
1726 /* Sum the entry arcs. */
1727 for (block = line->u.blocks; block; block = block->chain)
1729 arc_t *arc;
1731 for (arc = block->pred; arc; arc = arc->pred_next)
1733 if (arc->src->u.cycle.ident != ix)
1734 count += arc->count;
1735 if (flag_branches)
1736 add_branch_counts (&src->coverage, arc);
1739 /* Initialize the cs_count. */
1740 for (arc = block->succ; arc; arc = arc->succ_next)
1741 arc->cs_count = arc->count;
1744 /* Find the loops. This uses the algorithm described in
1745 Tiernan 'An Efficient Search Algorithm to Find the
1746 Elementary Circuits of a Graph', CACM Dec 1970. We hold
1747 the P array by having each block point to the arc that
1748 connects to the previous block. The H array is implicitly
1749 held because of the arc ordering, and the block's
1750 previous arc pointer.
1752 Although the algorithm is O(N^3) for highly connected
1753 graphs, at worst we'll have O(N^2), as most blocks have
1754 only one or two exits. Most graphs will be small.
1756 For each loop we find, locate the arc with the smallest
1757 transition count, and add that to the cumulative
1758 count. Decrease flow over the cycle and remove the arc
1759 from consideration. */
1760 for (block = line->u.blocks; block; block = block->chain)
1762 block_t *head = block;
1763 arc_t *arc;
1765 next_vertex:;
1766 arc = head->succ;
1767 current_vertex:;
1768 while (arc)
1770 block_t *dst = arc->dst;
1771 if (/* Already used that arc. */
1772 arc->cycle
1773 /* Not to same graph, or before first vertex. */
1774 || dst->u.cycle.ident != ix
1775 /* Already in path. */
1776 || dst->u.cycle.arc)
1778 arc = arc->succ_next;
1779 continue;
1782 if (dst == block)
1784 /* Found a closing arc. */
1785 gcov_type cycle_count = arc->cs_count;
1786 arc_t *cycle_arc = arc;
1787 arc_t *probe_arc;
1789 /* Locate the smallest arc count of the loop. */
1790 for (dst = head; (probe_arc = dst->u.cycle.arc);
1791 dst = probe_arc->src)
1792 if (cycle_count > probe_arc->cs_count)
1794 cycle_count = probe_arc->cs_count;
1795 cycle_arc = probe_arc;
1798 count += cycle_count;
1799 cycle_arc->cycle = 1;
1801 /* Remove the flow from the cycle. */
1802 arc->cs_count -= cycle_count;
1803 for (dst = head; (probe_arc = dst->u.cycle.arc);
1804 dst = probe_arc->src)
1805 probe_arc->cs_count -= cycle_count;
1807 /* Unwind to the cyclic arc. */
1808 while (head != cycle_arc->src)
1810 arc = head->u.cycle.arc;
1811 head->u.cycle.arc = NULL;
1812 head = arc->src;
1814 /* Move on. */
1815 arc = arc->succ_next;
1816 continue;
1819 /* Add new block to chain. */
1820 dst->u.cycle.arc = arc;
1821 head = dst;
1822 goto next_vertex;
1824 /* We could not add another vertex to the path. Remove
1825 the last vertex from the list. */
1826 arc = head->u.cycle.arc;
1827 if (arc)
1829 /* It was not the first vertex. Move onto next arc. */
1830 head->u.cycle.arc = NULL;
1831 head = arc->src;
1832 arc = arc->succ_next;
1833 goto current_vertex;
1835 /* Mark this block as unusable. */
1836 block->u.cycle.ident = ~0U;
1839 line->count = count;
1842 if (line->exists)
1844 src->coverage.lines++;
1845 if (line->count)
1846 src->coverage.lines_executed++;
1851 /* Output information about ARC number IX. Returns nonzero if
1852 anything is output. */
1854 static int
1855 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
1858 if (arc->is_call_non_return)
1860 if (arc->src->count)
1862 fnotice (gcov_file, "call %2d returned %s\n", ix,
1863 format_gcov (arc->src->count - arc->count,
1864 arc->src->count, -flag_counts));
1866 else
1867 fnotice (gcov_file, "call %2d never executed\n", ix);
1869 else if (!arc->is_unconditional)
1871 if (arc->src->count)
1872 fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
1873 format_gcov (arc->count, arc->src->count, -flag_counts),
1874 arc->fall_through ? " (fallthrough)" : "");
1875 else
1876 fnotice (gcov_file, "branch %2d never executed\n", ix);
1878 else if (flag_unconditional && !arc->dst->is_call_return)
1880 if (arc->src->count)
1881 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
1882 format_gcov (arc->count, arc->src->count, -flag_counts));
1883 else
1884 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
1886 else
1887 return 0;
1888 return 1;
1892 /* Read in the source file one line at a time, and output that line to
1893 the gcov file preceded by its execution count and other
1894 information. */
1896 static void
1897 output_lines (FILE *gcov_file, const source_t *src)
1899 FILE *source_file;
1900 unsigned line_num; /* current line number. */
1901 const line_t *line; /* current line info ptr. */
1902 char string[STRING_SIZE]; /* line buffer. */
1903 char const *retval = ""; /* status of source file reading. */
1904 function_t *fn = NULL;
1906 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
1907 if (!multiple_files)
1909 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
1910 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
1911 no_data_file ? "-" : da_file_name);
1912 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
1913 object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
1915 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
1917 source_file = fopen (src->name, "r");
1918 if (!source_file)
1920 fnotice (stderr, "%s:cannot open source file\n", src->name);
1921 retval = NULL;
1923 else if (src->file_time == 0)
1924 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0);
1926 if (flag_branches)
1927 fn = src->functions;
1929 for (line_num = 1, line = &src->lines[line_num];
1930 line_num < src->num_lines; line_num++, line++)
1932 for (; fn && fn->line == line_num; fn = fn->line_next)
1934 arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
1935 gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
1937 for (; arc; arc = arc->pred_next)
1938 if (arc->fake)
1939 return_count -= arc->count;
1941 fprintf (gcov_file, "function %s", fn->name);
1942 fprintf (gcov_file, " called %s",
1943 format_gcov (fn->blocks[0].count, 0, -1));
1944 fprintf (gcov_file, " returned %s",
1945 format_gcov (return_count, fn->blocks[0].count, 0));
1946 fprintf (gcov_file, " blocks executed %s",
1947 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
1948 fprintf (gcov_file, "\n");
1951 /* For lines which don't exist in the .bb file, print '-' before
1952 the source line. For lines which exist but were never
1953 executed, print '#####' before the source line. Otherwise,
1954 print the execution count before the source line. There are
1955 16 spaces of indentation added before the source line so that
1956 tabs won't be messed up. */
1957 fprintf (gcov_file, "%9s:%5u:",
1958 !line->exists ? "-" : !line->count ? "#####"
1959 : format_gcov (line->count, 0, -1), line_num);
1961 if (retval)
1963 /* Copy source line. */
1966 retval = fgets (string, STRING_SIZE, source_file);
1967 if (!retval)
1968 break;
1969 fputs (retval, gcov_file);
1971 while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1973 if (!retval)
1974 fputs ("/*EOF*/\n", gcov_file);
1976 if (flag_all_blocks)
1978 block_t *block;
1979 arc_t *arc;
1980 int ix, jx;
1982 for (ix = jx = 0, block = line->u.blocks; block;
1983 block = block->chain)
1985 if (!block->is_call_return)
1986 fprintf (gcov_file, "%9s:%5u-block %2d\n",
1987 !line->exists ? "-" : !block->count ? "$$$$$"
1988 : format_gcov (block->count, 0, -1),
1989 line_num, ix++);
1990 if (flag_branches)
1991 for (arc = block->succ; arc; arc = arc->succ_next)
1992 jx += output_branch_count (gcov_file, jx, arc);
1995 else if (flag_branches)
1997 int ix;
1998 arc_t *arc;
2000 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
2001 ix += output_branch_count (gcov_file, ix, arc);
2005 /* Handle all remaining source lines. There may be lines after the
2006 last line of code. */
2007 if (retval)
2009 for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
2011 fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval);
2013 while (!retval[0] || retval[strlen (retval) - 1] != '\n')
2015 retval = fgets (string, STRING_SIZE, source_file);
2016 if (!retval)
2017 break;
2018 fputs (retval, gcov_file);
2023 if (source_file)
2024 fclose (source_file);