Fixed rare threading problem
[official-gcc.git] / gcc / gcov.c
blobd42cff15b2ca5e08a48837c7c24982d515139687
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,
4 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
5 Contributed by James E. Wilson of Cygnus Support.
6 Mangled by Bob Manson of Cygnus Support.
7 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
9 Gcov is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 Gcov is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Gcov; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
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 /* ??? Does not correctly handle the case where two .bb files refer to
33 the same included source file. For example, if one has a short
34 file containing only inline functions, which is then included in
35 two other files, then there will be two .bb files which refer to
36 the include file, but there is no way to get the total execution
37 counts for the included file, can only get execution counts for one
38 or the other of the including files. this can be fixed by --ratios
39 --long-file-names --preserve-paths and perl. */
41 /* Need an option to show individual block counts, and show
42 probabilities of fall through arcs. */
44 #include "config.h"
45 #include "system.h"
46 #include "coretypes.h"
47 #include "tm.h"
48 #include "intl.h"
49 #include "version.h"
50 #undef abort
52 #include <getopt.h>
54 #define IN_GCOV 1
55 #include "gcov-io.h"
56 #include "gcov-io.c"
58 /* The bbg file is generated by -ftest-coverage option. The da file is
59 generated by a program compiled with -fprofile-arcs. Their formats
60 are documented in gcov-io.h. */
62 /* The functions in this file for creating and solution program flow graphs
63 are very similar to functions in the gcc source file profile.c. In
64 some places we make use of the knowledge of how profile.c works to
65 select particular algorithms here. */
67 /* This is the size of the buffer used to read in source file lines. */
69 #define STRING_SIZE 200
71 struct function_info;
72 struct block_info;
73 struct source_info;
75 /* Describes an arc between two basic blocks. */
77 typedef struct arc_info
79 /* source and destination blocks. */
80 struct block_info *src;
81 struct block_info *dst;
83 /* transition counts. */
84 gcov_type 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/setjump. */
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 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;
237 /* Array of line information. */
238 line_t *lines;
239 unsigned num_lines;
241 coverage_t coverage;
243 /* Functions in this source file. These are in ascending line
244 number order. */
245 function_t *functions;
247 /* Next source file. */
248 struct source_info *next;
249 } source_t;
251 /* Holds a list of function basic block graphs. */
253 static function_t *functions;
255 /* This points to the head of the sourcefile structure list. */
257 static source_t *sources;
259 /* This holds data summary information. */
261 static struct gcov_summary object_summary;
262 static unsigned program_count;
264 /* Modification time of graph file. */
266 static time_t bbg_file_time;
268 /* Name and file pointer of the input file for the basic block graph. */
270 static char *bbg_file_name;
272 /* Stamp of the bbg file */
273 static unsigned bbg_stamp;
275 /* Name and file pointer of the input file for the arc count data. */
277 static char *da_file_name;
279 /* Output branch probabilities. */
281 static int flag_branches = 0;
283 /* Show unconditional branches too. */
284 static int flag_unconditional = 0;
286 /* Output a gcov file if this is true. This is on by default, and can
287 be turned off by the -n option. */
289 static int flag_gcov_file = 1;
291 /* For included files, make the gcov output file name include the name
292 of the input source file. For example, if x.h is included in a.c,
293 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
295 static int flag_long_names = 0;
297 /* Output count information for every basic block, not merely those
298 that contain line number information. */
300 static int flag_all_blocks = 0;
302 /* Output summary info for each function. */
304 static int flag_function_summary = 0;
306 /* Object directory file prefix. This is the directory/file where the
307 graph and data files are looked for, if nonzero. */
309 static char *object_directory = 0;
311 /* Preserve all pathname components. Needed when object files and
312 source files are in subdirectories. '/' is mangled as '#', '.' is
313 elided and '..' mangled to '^'. */
315 static int flag_preserve_paths = 0;
317 /* Output the number of times a branch was taken as opposed to the percentage
318 of times it was taken. */
320 static int flag_counts = 0;
322 /* Forward declarations. */
323 static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2;
324 static int process_args (int, char **);
325 static void print_usage (int) ATTRIBUTE_NORETURN;
326 static void print_version (void) ATTRIBUTE_NORETURN;
327 static void process_file (const char *);
328 static void create_file_names (const char *);
329 static source_t *find_source (const char *);
330 static int read_graph_file (void);
331 static int read_count_file (void);
332 static void solve_flow_graph (function_t *);
333 static void add_branch_counts (coverage_t *, const arc_t *);
334 static void add_line_counts (coverage_t *, function_t *);
335 static void function_summary (const coverage_t *, const char *);
336 static const char *format_gcov (gcov_type, gcov_type, int);
337 static void accumulate_line_counts (source_t *);
338 static int output_branch_count (FILE *, int, const arc_t *);
339 static void output_lines (FILE *, const source_t *);
340 static char *make_gcov_file_name (const char *, const char *);
341 static void release_structures (void);
342 extern int main (int, char **);
345 main (int argc, char **argv)
347 int argno;
349 gcc_init_libintl ();
351 argno = process_args (argc, argv);
352 if (optind == argc)
353 print_usage (true);
355 for (; argno != argc; argno++)
357 release_structures ();
359 process_file (argv[argno]);
362 return 0;
365 static void
366 fnotice (FILE *file, const char *msgid, ...)
368 va_list ap;
370 va_start (ap, msgid);
371 vfprintf (file, _(msgid), ap);
372 va_end (ap);
375 /* More 'friendly' abort that prints the line and file.
376 config.h can #define abort fancy_abort if you like that sort of thing. */
377 extern void fancy_abort (void) ATTRIBUTE_NORETURN;
379 void
380 fancy_abort (void)
382 fnotice (stderr, "Internal gcov abort.\n");
383 exit (FATAL_EXIT_CODE);
386 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
387 otherwise the output of --help. */
389 static void
390 print_usage (int error_p)
392 FILE *file = error_p ? stderr : stdout;
393 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
395 fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
396 fnotice (file, "Print code coverage information.\n\n");
397 fnotice (file, " -h, --help Print this help, then exit\n");
398 fnotice (file, " -v, --version Print version number, then exit\n");
399 fnotice (file, " -a, --all-blocks Show information for every basic block\n");
400 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
401 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
402 rather than percentages\n");
403 fnotice (file, " -n, --no-output Do not create an output file\n");
404 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
405 source files\n");
406 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
407 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
408 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
409 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
410 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
411 bug_report_url);
412 exit (status);
415 /* Print version information and exit. */
417 static void
418 print_version (void)
420 unsigned version = GCOV_VERSION;
422 fnotice (stdout, "gcov %.4s (GCC %s)\n",
423 (const char *)&version, version_string);
424 fnotice (stdout, "Copyright (C) 2002 Free Software Foundation, Inc.\n");
425 fnotice (stdout,
426 "This is free software; see the source for copying conditions. There is NO\n\
427 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
428 exit (SUCCESS_EXIT_CODE);
431 static const struct option options[] =
433 { "help", no_argument, NULL, 'h' },
434 { "version", no_argument, NULL, 'v' },
435 { "all-blocks", no_argument, NULL, 'a' },
436 { "branch-probabilities", no_argument, NULL, 'b' },
437 { "branch-counts", no_argument, NULL, 'c' },
438 { "no-output", no_argument, NULL, 'n' },
439 { "long-file-names", no_argument, NULL, 'l' },
440 { "function-summaries", no_argument, NULL, 'f' },
441 { "preserve-paths", no_argument, NULL, 'p' },
442 { "object-directory", required_argument, NULL, 'o' },
443 { "object-file", required_argument, NULL, 'o' },
444 { "unconditional-branches", no_argument, NULL, 'u' },
445 { 0, 0, 0, 0 }
448 /* Process args, return index to first non-arg. */
450 static int
451 process_args (int argc, char **argv)
453 int opt;
455 while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1)
457 switch (opt)
459 case 'a':
460 flag_all_blocks = 1;
461 break;
462 case 'b':
463 flag_branches = 1;
464 break;
465 case 'c':
466 flag_counts = 1;
467 break;
468 case 'f':
469 flag_function_summary = 1;
470 break;
471 case 'h':
472 print_usage (false);
473 /* print_usage will exit. */
474 case 'l':
475 flag_long_names = 1;
476 break;
477 case 'n':
478 flag_gcov_file = 0;
479 break;
480 case 'o':
481 object_directory = optarg;
482 break;
483 case 'p':
484 flag_preserve_paths = 1;
485 break;
486 case 'u':
487 flag_unconditional = 1;
488 break;
489 case 'v':
490 print_version ();
491 /* print_version will exit. */
492 default:
493 print_usage (true);
494 /* print_usage will exit. */
498 return optind;
501 /* Process a single source file. */
503 static void
504 process_file (const char *file_name)
506 source_t *src;
507 function_t *fn;
509 create_file_names (file_name);
510 if (read_graph_file ())
511 return;
513 if (!functions)
515 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
516 return;
519 if (read_count_file ())
520 return;
522 for (fn = functions; fn; fn = fn->next)
523 solve_flow_graph (fn);
524 for (src = sources; src; src = src->next)
525 src->lines = (line_t *) xcalloc (src->num_lines, sizeof (line_t));
526 for (fn = functions; fn; fn = fn->next)
528 coverage_t coverage;
530 memset (&coverage, 0, sizeof (coverage));
531 coverage.name = fn->name;
532 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
533 if (flag_function_summary)
535 function_summary (&coverage, "Function");
536 fnotice (stdout, "\n");
540 for (src = sources; src; src = src->next)
542 accumulate_line_counts (src);
543 function_summary (&src->coverage, "File");
544 if (flag_gcov_file)
546 char *gcov_file_name = make_gcov_file_name (file_name, src->name);
547 FILE *gcov_file = fopen (gcov_file_name, "w");
549 if (gcov_file)
551 fnotice (stdout, "%s:creating `%s'\n",
552 src->name, gcov_file_name);
553 output_lines (gcov_file, src);
554 if (ferror (gcov_file))
555 fnotice (stderr, "%s:error writing output file `%s'\n",
556 src->name, gcov_file_name);
557 fclose (gcov_file);
559 else
560 fnotice (stderr, "%s:could not open output file `%s'\n",
561 src->name, gcov_file_name);
562 free (gcov_file_name);
564 fnotice (stdout, "\n");
568 /* Release all memory used. */
570 static void
571 release_structures (void)
573 function_t *fn;
574 source_t *src;
576 free (bbg_file_name);
577 free (da_file_name);
578 da_file_name = bbg_file_name = NULL;
579 bbg_file_time = 0;
580 bbg_stamp = 0;
582 while ((src = sources))
584 sources = src->next;
586 free (src->name);
587 free (src->lines);
590 while ((fn = functions))
592 unsigned ix;
593 block_t *block;
595 functions = fn->next;
596 for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
598 arc_t *arc, *arc_n;
600 for (arc = block->succ; arc; arc = arc_n)
602 arc_n = arc->succ_next;
603 free (arc);
606 free (fn->blocks);
607 free (fn->counts);
611 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
612 is not specified, these are looked for in the current directory,
613 and named from the basename of the FILE_NAME sans extension. If
614 OBJECT_DIRECTORY is specified and is a directory, the files are in
615 that directory, but named from the basename of the FILE_NAME, sans
616 extension. Otherwise OBJECT_DIRECTORY is taken to be the name of
617 the object *file*, and the data files are named from that. */
619 static void
620 create_file_names (const char *file_name)
622 char *cptr;
623 char *name;
624 int length = strlen (file_name);
625 int base;
627 if (object_directory && object_directory[0])
629 struct stat status;
631 length += strlen (object_directory) + 2;
632 name = xmalloc (length);
633 name[0] = 0;
635 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
636 strcat (name, object_directory);
637 if (base && name[strlen (name) - 1] != '/')
638 strcat (name, "/");
640 else
642 name = xmalloc (length + 1);
643 name[0] = 0;
644 base = 1;
647 if (base)
649 /* Append source file name. */
650 cptr = strrchr (file_name, '/');
651 strcat (name, cptr ? cptr + 1 : file_name);
654 /* Remove the extension. */
655 cptr = strrchr (name, '.');
656 if (cptr)
657 *cptr = 0;
659 length = strlen (name);
661 bbg_file_name = xmalloc (length + strlen (GCOV_NOTE_SUFFIX) + 1);
662 strcpy (bbg_file_name, name);
663 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
665 da_file_name = xmalloc (length + strlen (GCOV_DATA_SUFFIX) + 1);
666 strcpy (da_file_name, name);
667 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
669 return;
672 /* Find or create a source file structure for FILE_NAME. Copies
673 FILE_NAME on creation */
675 static source_t *
676 find_source (const char *file_name)
678 source_t *src;
680 if (!file_name)
681 file_name = "<unknown>";
683 for (src = sources; src; src = src->next)
684 if (!strcmp (file_name, src->name))
685 return src;
687 src = (source_t *)xcalloc (1, sizeof (source_t));
688 src->name = xstrdup (file_name);
689 src->coverage.name = src->name;
690 src->index = sources ? sources->index + 1 : 1;
691 src->next = sources;
692 sources = src;
694 return src;
697 /* Read the graph file. Return nonzero on fatal error. */
699 static int
700 read_graph_file (void)
702 unsigned version;
703 unsigned current_tag = 0;
704 struct function_info *fn = NULL;
705 source_t *src = NULL;
706 unsigned ix;
707 unsigned tag;
709 if (!gcov_open (bbg_file_name, 1))
711 fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
712 return 1;
714 bbg_file_time = gcov_time ();
715 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
717 fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
718 gcov_close ();
719 return 1;
722 version = gcov_read_unsigned ();
723 if (version != GCOV_VERSION)
725 char v[4], e[4];
726 unsigned required = GCOV_VERSION;
728 for (ix = 4; ix--; required >>= 8, version >>= 8)
730 v[ix] = version;
731 e[ix] = required;
733 fnotice (stderr, "%s:version `%.4s', prefer `%.4s'\n",
734 bbg_file_name, v, e);
736 bbg_stamp = gcov_read_unsigned ();
738 while ((tag = gcov_read_unsigned ()))
740 unsigned length = gcov_read_unsigned ();
741 gcov_position_t base = gcov_position ();
743 if (tag == GCOV_TAG_FUNCTION)
745 char *function_name;
746 unsigned ident, checksum, lineno;
747 source_t *src;
748 function_t *probe, *prev;
750 ident = gcov_read_unsigned ();
751 checksum = gcov_read_unsigned ();
752 function_name = xstrdup (gcov_read_string ());
753 src = find_source (gcov_read_string ());
754 lineno = gcov_read_unsigned ();
756 fn = (function_t *)xcalloc (1, sizeof (function_t));
757 fn->name = function_name;
758 fn->ident = ident;
759 fn->checksum = checksum;
760 fn->src = src;
761 fn->line = lineno;
763 fn->next = functions;
764 functions = fn;
765 current_tag = tag;
767 if (lineno >= src->num_lines)
768 src->num_lines = lineno + 1;
769 /* Now insert it into the source file's list of
770 functions. Normally functions will be encountered in
771 ascending order, so a simple scan is quick. */
772 for (probe = src->functions, prev = NULL;
773 probe && probe->line > lineno;
774 prev = probe, probe = probe->line_next)
775 continue;
776 fn->line_next = probe;
777 if (prev)
778 prev->line_next = fn;
779 else
780 src->functions = fn;
782 else if (fn && tag == GCOV_TAG_BLOCKS)
784 if (fn->blocks)
785 fnotice (stderr, "%s:already seen blocks for `%s'\n",
786 bbg_file_name, fn->name);
787 else
789 unsigned ix, num_blocks = length / 4;
790 fn->num_blocks = num_blocks;
792 fn->blocks
793 = (block_t *)xcalloc (fn->num_blocks, sizeof (block_t));
794 for (ix = 0; ix != num_blocks; ix++)
795 fn->blocks[ix].flags = gcov_read_unsigned ();
798 else if (fn && tag == GCOV_TAG_ARCS)
800 unsigned src = gcov_read_unsigned ();
801 unsigned num_dests = (length - 4) / 8;
803 if (src >= fn->num_blocks || fn->blocks[src].succ)
804 goto corrupt;
806 while (num_dests--)
808 struct arc_info *arc;
809 unsigned dest = gcov_read_unsigned ();
810 unsigned flags = gcov_read_unsigned ();
812 if (dest >= fn->num_blocks)
813 goto corrupt;
814 arc = (arc_t *) xcalloc (1, sizeof (arc_t));
816 arc->dst = &fn->blocks[dest];
817 arc->src = &fn->blocks[src];
819 arc->count = 0;
820 arc->count_valid = 0;
821 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
822 arc->fake = !!(flags & GCOV_ARC_FAKE);
823 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
825 arc->succ_next = fn->blocks[src].succ;
826 fn->blocks[src].succ = arc;
827 fn->blocks[src].num_succ++;
829 arc->pred_next = fn->blocks[dest].pred;
830 fn->blocks[dest].pred = arc;
831 fn->blocks[dest].num_pred++;
833 if (arc->fake)
835 if (src)
837 /* Exceptional exit from this function, the
838 source block must be a call. */
839 fn->blocks[src].is_call_site = 1;
840 arc->is_call_non_return = 1;
842 else
844 /* Non-local return from a callee of this
845 function. The destination block is a catch or
846 setjmp. */
847 arc->is_nonlocal_return = 1;
848 fn->blocks[dest].is_nonlocal_return = 1;
852 if (!arc->on_tree)
853 fn->num_counts++;
856 else if (fn && tag == GCOV_TAG_LINES)
858 unsigned blockno = gcov_read_unsigned ();
859 unsigned *line_nos
860 = (unsigned *)xcalloc ((length - 4) / 4, sizeof (unsigned));
862 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
863 goto corrupt;
865 for (ix = 0; ; )
867 unsigned lineno = gcov_read_unsigned ();
869 if (lineno)
871 if (!ix)
873 line_nos[ix++] = 0;
874 line_nos[ix++] = src->index;
876 line_nos[ix++] = lineno;
877 if (lineno >= src->num_lines)
878 src->num_lines = lineno + 1;
880 else
882 const char *file_name = gcov_read_string ();
884 if (!file_name)
885 break;
886 src = find_source (file_name);
888 line_nos[ix++] = 0;
889 line_nos[ix++] = src->index;
893 fn->blocks[blockno].u.line.encoding = line_nos;
894 fn->blocks[blockno].u.line.num = ix;
896 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
898 fn = NULL;
899 current_tag = 0;
901 gcov_sync (base, length);
902 if (gcov_is_error ())
903 break;
905 if (!gcov_is_eof ())
907 corrupt:;
908 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
909 gcov_close ();
910 return 1;
912 gcov_close ();
914 /* We built everything backwards, so nreverse them all */
916 /* Reverse sources. Not strictly necessary, but we'll then process
917 them in the 'expected' order. */
919 source_t *src, *src_p, *src_n;
921 for (src_p = NULL, src = sources; src; src_p = src, src = src_n)
923 src_n = src->next;
924 src->next = src_p;
926 sources = src_p;
929 /* Reverse functions. */
931 function_t *fn, *fn_p, *fn_n;
933 for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn_n)
935 unsigned ix;
937 fn_n = fn->next;
938 fn->next = fn_p;
940 /* Reverse the arcs. */
941 for (ix = fn->num_blocks; ix--;)
943 arc_t *arc, *arc_p, *arc_n;
945 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
946 arc_p = arc, arc = arc_n)
948 arc_n = arc->succ_next;
949 arc->succ_next = arc_p;
951 fn->blocks[ix].succ = arc_p;
953 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
954 arc_p = arc, arc = arc_n)
956 arc_n = arc->pred_next;
957 arc->pred_next = arc_p;
959 fn->blocks[ix].pred = arc_p;
962 functions = fn_p;
964 return 0;
967 /* Reads profiles from the count file and attach to each
968 function. Return nonzero if fatal error. */
970 static int
971 read_count_file (void)
973 unsigned ix;
974 unsigned version;
975 unsigned tag;
976 function_t *fn = NULL;
977 int error = 0;
979 if (!gcov_open (da_file_name, 1))
981 fnotice (stderr, "%s:cannot open data file\n", da_file_name);
982 return 1;
984 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
986 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
987 cleanup:;
988 gcov_close ();
989 return 1;
991 version = gcov_read_unsigned ();
992 if (version != GCOV_VERSION)
994 unsigned desired = GCOV_VERSION;
996 fnotice (stderr, "%s:version `%.4s', prefer version `%.4s'\n",
997 da_file_name, (const char *)&version, (const char *)&desired);
999 tag = gcov_read_unsigned ();
1000 if (tag != bbg_stamp)
1002 fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
1003 goto cleanup;
1006 while ((tag = gcov_read_unsigned ()))
1008 unsigned length = gcov_read_unsigned ();
1009 unsigned long base = gcov_position ();
1011 if (tag == GCOV_TAG_OBJECT_SUMMARY)
1012 gcov_read_summary (&object_summary);
1013 else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1014 program_count++;
1015 else if (tag == GCOV_TAG_FUNCTION)
1017 unsigned ident = gcov_read_unsigned ();
1018 struct function_info *fn_n = functions;
1020 for (fn = fn ? fn->next : NULL; ; fn = fn->next)
1022 if (fn)
1024 else if ((fn = fn_n))
1025 fn_n = NULL;
1026 else
1028 fnotice (stderr, "%s:unknown function `%u'\n",
1029 da_file_name, ident);
1030 break;
1032 if (fn->ident == ident)
1033 break;
1036 if (!fn)
1038 else if (gcov_read_unsigned () != fn->checksum)
1040 mismatch:;
1041 fnotice (stderr, "%s:profile mismatch for `%s'\n",
1042 da_file_name, fn->name);
1043 goto cleanup;
1046 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1048 if (length != 8 * fn->num_counts)
1049 goto mismatch;
1051 if (!fn->counts)
1052 fn->counts
1053 = (gcov_type *)xcalloc (fn->num_counts, sizeof (gcov_type));
1055 for (ix = 0; ix != fn->num_counts; ix++)
1056 fn->counts[ix] += gcov_read_counter ();
1058 gcov_sync (base, length);
1059 if ((error = gcov_is_error ()))
1060 break;
1063 if (!gcov_is_eof ())
1065 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1066 da_file_name);
1067 goto cleanup;
1070 gcov_close ();
1071 return 0;
1074 /* Solve the flow graph. Propagate counts from the instrumented arcs
1075 to the blocks and the uninstrumented arcs. */
1077 static void
1078 solve_flow_graph (function_t *fn)
1080 unsigned ix;
1081 arc_t *arc;
1082 gcov_type *count_ptr = fn->counts;
1083 block_t *blk;
1084 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */
1085 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
1087 if (fn->num_blocks < 2)
1088 fnotice (stderr, "%s:`%s' lacks entry and/or exit blocks\n",
1089 bbg_file_name, fn->name);
1090 else
1092 if (fn->blocks[0].num_pred)
1093 fnotice (stderr, "%s:`%s' has arcs to entry block\n",
1094 bbg_file_name, fn->name);
1095 else
1096 /* We can't deduce the entry block counts from the lack of
1097 predecessors. */
1098 fn->blocks[0].num_pred = ~(unsigned)0;
1100 if (fn->blocks[fn->num_blocks - 1].num_succ)
1101 fnotice (stderr, "%s:`%s' has arcs from exit block\n",
1102 bbg_file_name, fn->name);
1103 else
1104 /* Likewise, we can't deduce exit block counts from the lack
1105 of its successors. */
1106 fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0;
1109 /* Propagate the measured counts, this must be done in the same
1110 order as the code in profile.c */
1111 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
1113 block_t const *prev_dst = NULL;
1114 int out_of_order = 0;
1115 int non_fake_succ = 0;
1117 for (arc = blk->succ; arc; arc = arc->succ_next)
1119 if (!arc->fake)
1120 non_fake_succ++;
1122 if (!arc->on_tree)
1124 if (count_ptr)
1125 arc->count = *count_ptr++;
1126 arc->count_valid = 1;
1127 blk->num_succ--;
1128 arc->dst->num_pred--;
1130 if (prev_dst && prev_dst > arc->dst)
1131 out_of_order = 1;
1132 prev_dst = arc->dst;
1134 if (non_fake_succ == 1)
1136 /* If there is only one non-fake exit, it is an
1137 unconditional branch. */
1138 for (arc = blk->succ; arc; arc = arc->succ_next)
1139 if (!arc->fake)
1141 arc->is_unconditional = 1;
1142 /* If this block is instrumenting a call, it might be
1143 an artificial block. It is not artificial if it has
1144 a non-fallthrough exit, or the destination of this
1145 arc has more than one entry. Mark the destination
1146 block as a return site, if none of those conditions
1147 hold. */
1148 if (blk->is_call_site && arc->fall_through
1149 && arc->dst->pred == arc && !arc->pred_next)
1150 arc->dst->is_call_return = 1;
1154 /* Sort the successor arcs into ascending dst order. profile.c
1155 normally produces arcs in the right order, but sometimes with
1156 one or two out of order. We're not using a particularly
1157 smart sort. */
1158 if (out_of_order)
1160 arc_t *start = blk->succ;
1161 unsigned changes = 1;
1163 while (changes)
1165 arc_t *arc, *arc_p, *arc_n;
1167 changes = 0;
1168 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1170 if (arc->dst > arc_n->dst)
1172 changes = 1;
1173 if (arc_p)
1174 arc_p->succ_next = arc_n;
1175 else
1176 start = arc_n;
1177 arc->succ_next = arc_n->succ_next;
1178 arc_n->succ_next = arc;
1179 arc_p = arc_n;
1181 else
1183 arc_p = arc;
1184 arc = arc_n;
1188 blk->succ = start;
1191 /* Place it on the invalid chain, it will be ignored if that's
1192 wrong. */
1193 blk->invalid_chain = 1;
1194 blk->chain = invalid_blocks;
1195 invalid_blocks = blk;
1198 while (invalid_blocks || valid_blocks)
1200 while ((blk = invalid_blocks))
1202 gcov_type total = 0;
1203 const arc_t *arc;
1205 invalid_blocks = blk->chain;
1206 blk->invalid_chain = 0;
1207 if (!blk->num_succ)
1208 for (arc = blk->succ; arc; arc = arc->succ_next)
1209 total += arc->count;
1210 else if (!blk->num_pred)
1211 for (arc = blk->pred; arc; arc = arc->pred_next)
1212 total += arc->count;
1213 else
1214 continue;
1216 blk->count = total;
1217 blk->count_valid = 1;
1218 blk->chain = valid_blocks;
1219 blk->valid_chain = 1;
1220 valid_blocks = blk;
1222 while ((blk = valid_blocks))
1224 gcov_type total;
1225 arc_t *arc, *inv_arc;
1227 valid_blocks = blk->chain;
1228 blk->valid_chain = 0;
1229 if (blk->num_succ == 1)
1231 block_t *dst;
1233 total = blk->count;
1234 inv_arc = NULL;
1235 for (arc = blk->succ; arc; arc = arc->succ_next)
1237 total -= arc->count;
1238 if (!arc->count_valid)
1239 inv_arc = arc;
1241 dst = inv_arc->dst;
1242 inv_arc->count_valid = 1;
1243 inv_arc->count = total;
1244 blk->num_succ--;
1245 dst->num_pred--;
1246 if (dst->count_valid)
1248 if (dst->num_pred == 1 && !dst->valid_chain)
1250 dst->chain = valid_blocks;
1251 dst->valid_chain = 1;
1252 valid_blocks = dst;
1255 else
1257 if (!dst->num_pred && !dst->invalid_chain)
1259 dst->chain = invalid_blocks;
1260 dst->invalid_chain = 1;
1261 invalid_blocks = dst;
1265 if (blk->num_pred == 1)
1267 block_t *src;
1269 total = blk->count;
1270 inv_arc = NULL;
1271 for (arc = blk->pred; arc; arc = arc->pred_next)
1273 total -= arc->count;
1274 if (!arc->count_valid)
1275 inv_arc = arc;
1277 src = inv_arc->src;
1278 inv_arc->count_valid = 1;
1279 inv_arc->count = total;
1280 blk->num_pred--;
1281 src->num_succ--;
1282 if (src->count_valid)
1284 if (src->num_succ == 1 && !src->valid_chain)
1286 src->chain = valid_blocks;
1287 src->valid_chain = 1;
1288 valid_blocks = src;
1291 else
1293 if (!src->num_succ && !src->invalid_chain)
1295 src->chain = invalid_blocks;
1296 src->invalid_chain = 1;
1297 invalid_blocks = src;
1304 /* If the graph has been correctly solved, every block will have a
1305 valid count. */
1306 for (ix = 0; ix < fn->num_blocks; ix++)
1307 if (!fn->blocks[ix].count_valid)
1309 fnotice (stderr, "%s:graph is unsolvable for `%s'\n",
1310 bbg_file_name, fn->name);
1311 break;
1317 /* Increment totals in COVERAGE according to arc ARC. */
1319 static void
1320 add_branch_counts (coverage_t *coverage, const arc_t *arc)
1322 if (arc->is_call_non_return)
1324 coverage->calls++;
1325 if (arc->src->count)
1326 coverage->calls_executed++;
1328 else if (!arc->is_unconditional)
1330 coverage->branches++;
1331 if (arc->src->count)
1332 coverage->branches_executed++;
1333 if (arc->count)
1334 coverage->branches_taken++;
1338 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1339 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1340 If DP is zero, no decimal point is printed. Only print 100% when
1341 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1342 format TOP. Return pointer to a static string. */
1344 static char const *
1345 format_gcov (gcov_type top, gcov_type bottom, int dp)
1347 static char buffer[20];
1349 if (dp >= 0)
1351 float ratio = bottom ? (float)top / bottom : 0;
1352 int ix;
1353 unsigned limit = 100;
1354 unsigned percent;
1356 for (ix = dp; ix--; )
1357 limit *= 10;
1359 percent = (unsigned) (ratio * limit + (float)0.5);
1360 if (percent <= 0 && top)
1361 percent = 1;
1362 else if (percent >= limit && top != bottom)
1363 percent = limit - 1;
1364 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1365 if (dp)
1367 dp++;
1370 buffer[ix+1] = buffer[ix];
1371 ix--;
1373 while (dp--);
1374 buffer[ix + 1] = '.';
1377 else
1378 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
1380 return buffer;
1384 /* Output summary info for a function. */
1386 static void
1387 function_summary (const coverage_t *coverage, const char *title)
1389 fnotice (stdout, "%s `%s'\n", title, coverage->name);
1391 if (coverage->lines)
1392 fnotice (stdout, "Lines executed:%s of %d\n",
1393 format_gcov (coverage->lines_executed, coverage->lines, 2),
1394 coverage->lines);
1395 else
1396 fnotice (stdout, "No executable lines");
1398 if (flag_branches)
1400 if (coverage->branches)
1402 fnotice (stdout, "Branches executed:%s of %d\n",
1403 format_gcov (coverage->branches_executed,
1404 coverage->branches, 2),
1405 coverage->branches);
1406 fnotice (stdout, "Taken at least once:%s of %d\n",
1407 format_gcov (coverage->branches_taken,
1408 coverage->branches, 2),
1409 coverage->branches);
1411 else
1412 fnotice (stdout, "No branches\n");
1413 if (coverage->calls)
1414 fnotice (stdout, "Calls executed:%s of %d\n",
1415 format_gcov (coverage->calls_executed, coverage->calls, 2),
1416 coverage->calls);
1417 else
1418 fnotice (stdout, "No calls\n");
1422 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1423 affect name generation. With preserve_paths we create a filename
1424 from all path components of the source file, replacing '/' with
1425 '#', without it we simply take the basename component. With
1426 long_output_names we prepend the processed name of the input file
1427 to each output name (except when the current source file is the
1428 input file, so you don't get a double concatenation). The two
1429 components are separated by '##'. Also '.' filename components are
1430 removed and '..' components are renamed to '^'. */
1432 static char *
1433 make_gcov_file_name (const char *input_name, const char *src_name)
1435 char *cptr;
1436 char *name = xmalloc (strlen (src_name) + strlen (input_name) + 10);
1438 name[0] = 0;
1439 if (flag_long_names && strcmp (src_name, input_name))
1441 /* Generate the input filename part. */
1442 cptr = flag_preserve_paths ? NULL : strrchr (input_name, '/');
1443 strcat (name, cptr ? cptr + 1 : input_name);
1444 strcat (name, "##");
1447 /* Generate the source filename part. */
1448 cptr = flag_preserve_paths ? NULL : strrchr (src_name, '/');
1449 strcat (name, cptr ? cptr + 1 : src_name);
1451 if (flag_preserve_paths)
1453 /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1454 char *prev;
1456 for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
1458 unsigned shift = 0;
1460 if (prev + 1 == cptr && prev[0] == '.')
1462 /* Remove '.' */
1463 shift = 2;
1465 else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
1467 /* Convert '..' */
1468 shift = 1;
1469 prev[1] = '^';
1471 else
1472 *cptr++ = '#';
1473 if (shift)
1475 cptr = prev;
1477 prev[0] = prev[shift];
1478 while (*prev++);
1483 strcat (name, ".gcov");
1484 return name;
1487 /* Scan through the bb_data for each line in the block, increment
1488 the line number execution count indicated by the execution count of
1489 the appropriate basic block. */
1491 static void
1492 add_line_counts (coverage_t *coverage, function_t *fn)
1494 unsigned ix;
1495 line_t *line = NULL; /* this is propagated from one iteration to the
1496 next. */
1498 /* Scan each basic block. */
1499 for (ix = 0; ix != fn->num_blocks; ix++)
1501 block_t *block = &fn->blocks[ix];
1502 unsigned *encoding;
1503 const source_t *src = NULL;
1504 unsigned jx;
1506 if (block->count && ix && ix + 1 != fn->num_blocks)
1507 fn->blocks_executed++;
1508 for (jx = 0, encoding = block->u.line.encoding;
1509 jx != block->u.line.num; jx++, encoding++)
1510 if (!*encoding)
1512 unsigned src_n = *++encoding;
1514 for (src = sources; src->index != src_n; src = src->next)
1515 continue;
1516 jx++;
1518 else
1520 line = &src->lines[*encoding];
1522 if (coverage)
1524 if (!line->exists)
1525 coverage->lines++;
1526 if (!line->count && block->count)
1527 coverage->lines_executed++;
1529 line->exists = 1;
1530 line->count += block->count;
1532 free (block->u.line.encoding);
1533 block->u.cycle.arc = NULL;
1534 block->u.cycle.ident = ~0U;
1536 if (!ix || ix + 1 == fn->num_blocks)
1537 /* Entry or exit block */;
1538 else if (flag_all_blocks)
1540 line_t *block_line = line ? line : &fn->src->lines[fn->line];
1542 block->chain = block_line->u.blocks;
1543 block_line->u.blocks = block;
1545 else if (flag_branches)
1547 arc_t *arc;
1549 for (arc = block->succ; arc; arc = arc->succ_next)
1551 arc->line_next = line->u.branches;
1552 line->u.branches = arc;
1553 if (coverage && !arc->is_unconditional)
1554 add_branch_counts (coverage, arc);
1558 if (!line)
1559 fnotice (stderr, "%s:no lines for `%s'\n", bbg_file_name, fn->name);
1562 /* Accumulate the line counts of a file. */
1564 static void
1565 accumulate_line_counts (source_t *src)
1567 line_t *line;
1568 function_t *fn, *fn_p, *fn_n;
1569 unsigned ix;
1571 /* Reverse the function order. */
1572 for (fn = src->functions, fn_p = NULL; fn;
1573 fn_p = fn, fn = fn_n)
1575 fn_n = fn->line_next;
1576 fn->line_next = fn_p;
1578 src->functions = fn_p;
1580 for (ix = src->num_lines, line = src->lines; ix--; line++)
1582 if (!flag_all_blocks)
1584 arc_t *arc, *arc_p, *arc_n;
1586 /* Total and reverse the branch information. */
1587 for (arc = line->u.branches, arc_p = NULL; arc;
1588 arc_p = arc, arc = arc_n)
1590 arc_n = arc->line_next;
1591 arc->line_next = arc_p;
1593 add_branch_counts (&src->coverage, arc);
1595 line->u.branches = arc_p;
1597 else if (line->u.blocks)
1599 /* The user expects the line count to be the number of times
1600 a line has been executed. Simply summing the block count
1601 will give an artificially high number. The Right Thing
1602 is to sum the entry counts to the graph of blocks on this
1603 line, then find the elementary cycles of the local graph
1604 and add the transition counts of those cycles. */
1605 block_t *block, *block_p, *block_n;
1606 gcov_type count = 0;
1608 /* Reverse the block information. */
1609 for (block = line->u.blocks, block_p = NULL; block;
1610 block_p = block, block = block_n)
1612 block_n = block->chain;
1613 block->chain = block_p;
1614 block->u.cycle.ident = ix;
1616 line->u.blocks = block_p;
1618 /* Sum the entry arcs. */
1619 for (block = line->u.blocks; block; block = block->chain)
1621 arc_t *arc;
1623 for (arc = block->pred; arc; arc = arc->pred_next)
1625 if (arc->src->u.cycle.ident != ix)
1626 count += arc->count;
1627 if (flag_branches)
1628 add_branch_counts (&src->coverage, arc);
1632 /* Find the loops. This uses the algorithm described in
1633 Tiernan 'An Efficient Search Algorithm to Find the
1634 Elementary Circuits of a Graph', CACM Dec 1970. We hold
1635 the P array by having each block point to the arc that
1636 connects to the previous block. The H array is implicitly
1637 held because of the arc ordering, and the block's
1638 previous arc pointer.
1640 Although the algorithm is O(N^3) for highly connected
1641 graphs, at worst we'll have O(N^2), as most blocks have
1642 only one or two exits. Most graphs will be small.
1644 For each loop we find, locate the arc with the smallest
1645 transition count, and add that to the cumulative
1646 count. Remove the arc from consideration. */
1647 for (block = line->u.blocks; block; block = block->chain)
1649 block_t *head = block;
1650 arc_t *arc;
1652 next_vertex:;
1653 arc = head->succ;
1654 current_vertex:;
1655 while (arc)
1657 block_t *dst = arc->dst;
1658 if (/* Already used that arc. */
1659 arc->cycle
1660 /* Not to same graph, or before first vertex. */
1661 || dst->u.cycle.ident != ix
1662 /* Already in path. */
1663 || dst->u.cycle.arc)
1665 arc = arc->succ_next;
1666 continue;
1669 if (dst == block)
1671 /* Found a closing arc. */
1672 gcov_type cycle_count = arc->count;
1673 arc_t *cycle_arc = arc;
1674 arc_t *probe_arc;
1676 /* Locate the smallest arc count of the loop. */
1677 for (dst = head; (probe_arc = dst->u.cycle.arc);
1678 dst = probe_arc->src)
1679 if (cycle_count > probe_arc->count)
1681 cycle_count = probe_arc->count;
1682 cycle_arc = probe_arc;
1685 count += cycle_count;
1686 cycle_arc->cycle = 1;
1687 /* Unwind to the cyclic arc. */
1688 while (head != cycle_arc->src)
1690 arc = head->u.cycle.arc;
1691 head = arc->src;
1693 /* Move on. */
1694 arc = arc->succ_next;
1695 continue;
1698 /* Add new block to chain. */
1699 dst->u.cycle.arc = arc;
1700 head = dst;
1701 goto next_vertex;
1703 /* We could not add another vertex to the path. Remove
1704 the last vertex from the list. */
1705 arc = head->u.cycle.arc;
1706 if (arc)
1708 /* It was not the first vertex. Move onto next arc. */
1709 head->u.cycle.arc = NULL;
1710 head = arc->src;
1711 arc = arc->succ_next;
1712 goto current_vertex;
1714 /* Mark this block as unusable. */
1715 block->u.cycle.ident = ~0U;
1718 line->count = count;
1721 if (line->exists)
1723 src->coverage.lines++;
1724 if (line->count)
1725 src->coverage.lines_executed++;
1730 /* Ouput information about ARC number IX. Returns nonzero if
1731 anything is output. */
1733 static int
1734 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
1737 if (arc->is_call_non_return)
1739 if (arc->src->count)
1741 fnotice (gcov_file, "call %2d returned %s\n", ix,
1742 format_gcov (arc->src->count - arc->count,
1743 arc->src->count, -flag_counts));
1745 else
1746 fnotice (gcov_file, "call %2d never executed\n", ix);
1748 else if (!arc->is_unconditional)
1750 if (arc->src->count)
1751 fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
1752 format_gcov (arc->count, arc->src->count, -flag_counts),
1753 arc->fall_through ? " (fallthrough)" : "");
1754 else
1755 fnotice (gcov_file, "branch %2d never executed\n", ix);
1757 else if (flag_unconditional && !arc->dst->is_call_return)
1759 if (arc->src->count)
1760 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
1761 format_gcov (arc->count, arc->src->count, -flag_counts));
1762 else
1763 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
1765 else
1766 return 0;
1767 return 1;
1771 /* Read in the source file one line at a time, and output that line to
1772 the gcov file preceded by its execution count and other
1773 information. */
1775 static void
1776 output_lines (FILE *gcov_file, const source_t *src)
1778 FILE *source_file;
1779 unsigned line_num; /* current line number. */
1780 const line_t *line; /* current line info ptr. */
1781 char string[STRING_SIZE]; /* line buffer. */
1782 char const *retval = ""; /* status of source file reading. */
1783 function_t *fn = src->functions;
1785 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
1786 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
1787 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, da_file_name);
1788 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
1789 object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
1790 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
1792 source_file = fopen (src->name, "r");
1793 if (!source_file)
1795 fnotice (stderr, "%s:cannot open source file\n", src->name);
1796 retval = NULL;
1798 else
1800 struct stat status;
1802 if (!fstat (fileno (source_file), &status)
1803 && status.st_mtime > bbg_file_time)
1805 fnotice (stderr, "%s:source file is newer than graph file `%s'\n",
1806 src->name, bbg_file_name);
1807 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n",
1808 "-", 0);
1812 for (line_num = 1, line = &src->lines[line_num];
1813 line_num < src->num_lines; line_num++, line++)
1815 for (; fn && fn->line == line_num; fn = fn->line_next)
1817 arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
1818 gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
1820 for (; arc; arc = arc->pred_next)
1821 if (arc->fake)
1822 return_count -= arc->count;
1824 fprintf (gcov_file, "function %s", fn->name);
1825 fprintf (gcov_file, " called %s",
1826 format_gcov (fn->blocks[0].count, 0, -1));
1827 fprintf (gcov_file, " returned %s",
1828 format_gcov (return_count, fn->blocks[0].count, 0));
1829 fprintf (gcov_file, " blocks executed %s",
1830 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
1831 fprintf (gcov_file, "\n");
1834 /* For lines which don't exist in the .bb file, print '-' before
1835 the source line. For lines which exist but were never
1836 executed, print '#####' before the source line. Otherwise,
1837 print the execution count before the source line. There are
1838 16 spaces of indentation added before the source line so that
1839 tabs won't be messed up. */
1840 fprintf (gcov_file, "%9s:%5u:",
1841 !line->exists ? "-" : !line->count ? "#####"
1842 : format_gcov (line->count, 0, -1), line_num);
1844 if (retval)
1846 /* Copy source line. */
1849 retval = fgets (string, STRING_SIZE, source_file);
1850 if (!retval)
1851 break;
1852 fputs (retval, gcov_file);
1854 while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1856 if (!retval)
1857 fputs ("/*EOF*/\n", gcov_file);
1859 if (flag_all_blocks)
1861 block_t *block;
1862 arc_t *arc;
1863 int ix, jx;
1865 for (ix = jx = 0, block = line->u.blocks; block;
1866 block = block->chain)
1868 if (!block->is_call_return)
1869 fprintf (gcov_file, "%9s:%5u-block %2d\n",
1870 !line->exists ? "-" : !block->count ? "$$$$$"
1871 : format_gcov (block->count, 0, -1),
1872 line_num, ix++);
1873 if (flag_branches)
1874 for (arc = block->succ; arc; arc = arc->succ_next)
1875 jx += output_branch_count (gcov_file, jx, arc);
1878 else if (flag_branches)
1880 int ix;
1881 arc_t *arc;
1883 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
1884 ix += output_branch_count (gcov_file, ix, arc);
1888 /* Handle all remaining source lines. There may be lines after the
1889 last line of code. */
1890 if (retval)
1892 for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
1894 fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval);
1896 while (!retval[0] || retval[strlen (retval) - 1] != '\n')
1898 retval = fgets (string, STRING_SIZE, source_file);
1899 if (!retval)
1900 break;
1901 fputs (retval, gcov_file);
1906 if (source_file)
1907 fclose (source_file);