c-decl.c: Fix comment formatting.
[gcc.git] / gcc / gcov.c
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>
8
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.
13
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.
18
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. */
23
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. */
28
29 /* ??? Should have an option to print the number of basic blocks, and the
30 percent of them that are covered. */
31
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. */
40
41 /* Need an option to show individual block counts, and show
42 probabilities of fall through arcs. */
43
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
51
52 #include <getopt.h>
53
54 #define IN_GCOV 1
55 #include "gcov-io.h"
56 #include "gcov-io.c"
57
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. */
61
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. */
66
67 /* This is the size of the buffer used to read in source file lines. */
68
69 #define STRING_SIZE 200
70
71 struct function_info;
72 struct block_info;
73 struct source_info;
74
75 /* Describes an arc between two basic blocks. */
76
77 typedef struct arc_info
78 {
79 /* source and destination blocks. */
80 struct block_info *src;
81 struct block_info *dst;
82
83 /* transition counts. */
84 gcov_type count;
85
86 unsigned int count_valid : 1;
87 unsigned int on_tree : 1;
88 unsigned int fake : 1;
89 unsigned int fall_through : 1;
90
91 /* Arc is for a function that abnormally returns. */
92 unsigned int is_call_non_return : 1;
93
94 /* Arc is for catch/setjump. */
95 unsigned int is_nonlocal_return : 1;
96
97 /* Is an unconditional branch. */
98 unsigned int is_unconditional : 1;
99
100 /* Loop making arc. */
101 unsigned int cycle : 1;
102
103 /* Next branch on line. */
104 struct arc_info *line_next;
105
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;
110
111 /* Describes a basic block. Contains lists of arcs to successor and
112 predecessor blocks. */
113
114 typedef struct block_info
115 {
116 /* Chain of exit and entry arcs. */
117 arc_t *succ;
118 arc_t *pred;
119
120 /* Number of unprocessed exit and entry arcs. */
121 gcov_type num_succ;
122 gcov_type num_pred;
123
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;
130
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. */
134
135 /* Block is a landing pad for longjmp or throw. */
136 unsigned is_nonlocal_return : 1;
137
138 union
139 {
140 struct
141 {
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
150 {
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;
158
159 /* Temporary chain for solving graph, and for chaining blocks on one
160 line. */
161 struct block_info *chain;
162
163 } block_t;
164
165 /* Describes a single function. Contains an array of basic blocks. */
166
167 typedef struct function_info
168 {
169 /* Name of function. */
170 char *name;
171 unsigned ident;
172 unsigned checksum;
173
174 /* Array of basic blocks. */
175 block_t *blocks;
176 unsigned num_blocks;
177 unsigned blocks_executed;
178
179 /* Raw arc coverage counts. */
180 gcov_type *counts;
181 unsigned num_counts;
182
183 /* First line number. */
184 unsigned line;
185 struct source_info *src;
186
187 /* Next function in same source file. */
188 struct function_info *line_next;
189
190 /* Next function. */
191 struct function_info *next;
192 } function_t;
193
194 /* Describes coverage of a file or function. */
195
196 typedef struct coverage_info
197 {
198 int lines;
199 int lines_executed;
200
201 int branches;
202 int branches_executed;
203 int branches_taken;
204
205 int calls;
206 int calls_executed;
207
208 char *name;
209 } coverage_t;
210
211 /* Describes a single line of source. Contains a chain of basic blocks
212 with code on it. */
213
214 typedef struct line_info
215 {
216 gcov_type count; /* execution count */
217 union
218 {
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;
227
228 /* Describes a file mentioned in the block graph. Contains an array
229 of line info. */
230
231 typedef struct source_info
232 {
233 /* Name of source file. */
234 char *name;
235 unsigned index;
236
237 /* Array of line information. */
238 line_t *lines;
239 unsigned num_lines;
240
241 coverage_t coverage;
242
243 /* Functions in this source file. These are in ascending line
244 number order. */
245 function_t *functions;
246
247 /* Next source file. */
248 struct source_info *next;
249 } source_t;
250
251 /* Holds a list of function basic block graphs. */
252
253 static function_t *functions;
254
255 /* This points to the head of the sourcefile structure list. */
256
257 static source_t *sources;
258
259 /* This holds data summary information. */
260
261 static struct gcov_summary object_summary;
262 static unsigned program_count;
263
264 /* Modification time of graph file. */
265
266 static time_t bbg_file_time;
267
268 /* Name and file pointer of the input file for the basic block graph. */
269
270 static char *bbg_file_name;
271
272 /* Stamp of the bbg file */
273 static unsigned bbg_stamp;
274
275 /* Name and file pointer of the input file for the arc count data. */
276
277 static char *da_file_name;
278
279 /* Output branch probabilities. */
280
281 static int flag_branches = 0;
282
283 /* Show unconditional branches too. */
284 static int flag_unconditional = 0;
285
286 /* Output a gcov file if this is true. This is on by default, and can
287 be turned off by the -n option. */
288
289 static int flag_gcov_file = 1;
290
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. */
294
295 static int flag_long_names = 0;
296
297 /* Output count information for every basic block, not merely those
298 that contain line number information. */
299
300 static int flag_all_blocks = 0;
301
302 /* Output summary info for each function. */
303
304 static int flag_function_summary = 0;
305
306 /* Object directory file prefix. This is the directory/file where the
307 graph and data files are looked for, if nonzero. */
308
309 static char *object_directory = 0;
310
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 '^'. */
314
315 static int flag_preserve_paths = 0;
316
317 /* Output the number of times a branch was taken as opposed to the percentage
318 of times it was taken. */
319
320 static int flag_counts = 0;
321
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 **);
343
344 int
345 main (int argc, char **argv)
346 {
347 int argno;
348
349 gcc_init_libintl ();
350
351 argno = process_args (argc, argv);
352 if (optind == argc)
353 print_usage (true);
354
355 for (; argno != argc; argno++)
356 {
357 release_structures ();
358
359 process_file (argv[argno]);
360 }
361
362 return 0;
363 }
364
365 static void
366 fnotice (FILE *file, const char *msgid, ...)
367 {
368 va_list ap;
369
370 va_start (ap, msgid);
371 vfprintf (file, _(msgid), ap);
372 va_end (ap);
373 }
374
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;
378
379 void
380 fancy_abort (void)
381 {
382 fnotice (stderr, "Internal gcov abort.\n");
383 exit (FATAL_EXIT_CODE);
384 }
385 \f
386 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
387 otherwise the output of --help. */
388
389 static void
390 print_usage (int error_p)
391 {
392 FILE *file = error_p ? stderr : stdout;
393 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
394
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);
413 }
414
415 /* Print version information and exit. */
416
417 static void
418 print_version (void)
419 {
420 fnotice (stdout, "gcov (GCC) %s\n", version_string);
421 fnotice (stdout, "Copyright (C) 2003 Free Software Foundation, Inc.\n");
422 fnotice (stdout,
423 "This is free software; see the source for copying conditions.\n"
424 "There is NO warranty; not even for MERCHANTABILITY or \n"
425 "FITNESS FOR A PARTICULAR PURPOSE.\n\n");
426 exit (SUCCESS_EXIT_CODE);
427 }
428
429 static const struct option options[] =
430 {
431 { "help", no_argument, NULL, 'h' },
432 { "version", no_argument, NULL, 'v' },
433 { "all-blocks", no_argument, NULL, 'a' },
434 { "branch-probabilities", no_argument, NULL, 'b' },
435 { "branch-counts", no_argument, NULL, 'c' },
436 { "no-output", no_argument, NULL, 'n' },
437 { "long-file-names", no_argument, NULL, 'l' },
438 { "function-summaries", no_argument, NULL, 'f' },
439 { "preserve-paths", no_argument, NULL, 'p' },
440 { "object-directory", required_argument, NULL, 'o' },
441 { "object-file", required_argument, NULL, 'o' },
442 { "unconditional-branches", no_argument, NULL, 'u' },
443 { 0, 0, 0, 0 }
444 };
445
446 /* Process args, return index to first non-arg. */
447
448 static int
449 process_args (int argc, char **argv)
450 {
451 int opt;
452
453 while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1)
454 {
455 switch (opt)
456 {
457 case 'a':
458 flag_all_blocks = 1;
459 break;
460 case 'b':
461 flag_branches = 1;
462 break;
463 case 'c':
464 flag_counts = 1;
465 break;
466 case 'f':
467 flag_function_summary = 1;
468 break;
469 case 'h':
470 print_usage (false);
471 /* print_usage will exit. */
472 case 'l':
473 flag_long_names = 1;
474 break;
475 case 'n':
476 flag_gcov_file = 0;
477 break;
478 case 'o':
479 object_directory = optarg;
480 break;
481 case 'p':
482 flag_preserve_paths = 1;
483 break;
484 case 'u':
485 flag_unconditional = 1;
486 break;
487 case 'v':
488 print_version ();
489 /* print_version will exit. */
490 default:
491 print_usage (true);
492 /* print_usage will exit. */
493 }
494 }
495
496 return optind;
497 }
498
499 /* Process a single source file. */
500
501 static void
502 process_file (const char *file_name)
503 {
504 source_t *src;
505 function_t *fn;
506
507 create_file_names (file_name);
508 if (read_graph_file ())
509 return;
510
511 if (!functions)
512 {
513 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
514 return;
515 }
516
517 if (read_count_file ())
518 return;
519
520 for (fn = functions; fn; fn = fn->next)
521 solve_flow_graph (fn);
522 for (src = sources; src; src = src->next)
523 src->lines = xcalloc (src->num_lines, sizeof (line_t));
524 for (fn = functions; fn; fn = fn->next)
525 {
526 coverage_t coverage;
527
528 memset (&coverage, 0, sizeof (coverage));
529 coverage.name = fn->name;
530 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
531 if (flag_function_summary)
532 {
533 function_summary (&coverage, "Function");
534 fnotice (stdout, "\n");
535 }
536 }
537
538 for (src = sources; src; src = src->next)
539 {
540 accumulate_line_counts (src);
541 function_summary (&src->coverage, "File");
542 if (flag_gcov_file)
543 {
544 char *gcov_file_name = make_gcov_file_name (file_name, src->name);
545 FILE *gcov_file = fopen (gcov_file_name, "w");
546
547 if (gcov_file)
548 {
549 fnotice (stdout, "%s:creating `%s'\n",
550 src->name, gcov_file_name);
551 output_lines (gcov_file, src);
552 if (ferror (gcov_file))
553 fnotice (stderr, "%s:error writing output file `%s'\n",
554 src->name, gcov_file_name);
555 fclose (gcov_file);
556 }
557 else
558 fnotice (stderr, "%s:could not open output file `%s'\n",
559 src->name, gcov_file_name);
560 free (gcov_file_name);
561 }
562 fnotice (stdout, "\n");
563 }
564 }
565
566 /* Release all memory used. */
567
568 static void
569 release_structures (void)
570 {
571 function_t *fn;
572 source_t *src;
573
574 free (bbg_file_name);
575 free (da_file_name);
576 da_file_name = bbg_file_name = NULL;
577 bbg_file_time = 0;
578 bbg_stamp = 0;
579
580 while ((src = sources))
581 {
582 sources = src->next;
583
584 free (src->name);
585 free (src->lines);
586 }
587
588 while ((fn = functions))
589 {
590 unsigned ix;
591 block_t *block;
592
593 functions = fn->next;
594 for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
595 {
596 arc_t *arc, *arc_n;
597
598 for (arc = block->succ; arc; arc = arc_n)
599 {
600 arc_n = arc->succ_next;
601 free (arc);
602 }
603 }
604 free (fn->blocks);
605 free (fn->counts);
606 }
607 }
608
609 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
610 is not specified, these are looked for in the current directory,
611 and named from the basename of the FILE_NAME sans extension. If
612 OBJECT_DIRECTORY is specified and is a directory, the files are in
613 that directory, but named from the basename of the FILE_NAME, sans
614 extension. Otherwise OBJECT_DIRECTORY is taken to be the name of
615 the object *file*, and the data files are named from that. */
616
617 static void
618 create_file_names (const char *file_name)
619 {
620 char *cptr;
621 char *name;
622 int length = strlen (file_name);
623 int base;
624
625 if (object_directory && object_directory[0])
626 {
627 struct stat status;
628
629 length += strlen (object_directory) + 2;
630 name = xmalloc (length);
631 name[0] = 0;
632
633 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
634 strcat (name, object_directory);
635 if (base && name[strlen (name) - 1] != '/')
636 strcat (name, "/");
637 }
638 else
639 {
640 name = xmalloc (length + 1);
641 name[0] = 0;
642 base = 1;
643 }
644
645 if (base)
646 {
647 /* Append source file name. */
648 cptr = strrchr (file_name, '/');
649 strcat (name, cptr ? cptr + 1 : file_name);
650 }
651
652 /* Remove the extension. */
653 cptr = strrchr (name, '.');
654 if (cptr)
655 *cptr = 0;
656
657 length = strlen (name);
658
659 bbg_file_name = xmalloc (length + strlen (GCOV_NOTE_SUFFIX) + 1);
660 strcpy (bbg_file_name, name);
661 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
662
663 da_file_name = xmalloc (length + strlen (GCOV_DATA_SUFFIX) + 1);
664 strcpy (da_file_name, name);
665 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
666
667 return;
668 }
669
670 /* Find or create a source file structure for FILE_NAME. Copies
671 FILE_NAME on creation */
672
673 static source_t *
674 find_source (const char *file_name)
675 {
676 source_t *src;
677
678 if (!file_name)
679 file_name = "<unknown>";
680
681 for (src = sources; src; src = src->next)
682 if (!strcmp (file_name, src->name))
683 return src;
684
685 src = xcalloc (1, sizeof (source_t));
686 src->name = xstrdup (file_name);
687 src->coverage.name = src->name;
688 src->index = sources ? sources->index + 1 : 1;
689 src->next = sources;
690 sources = src;
691
692 return src;
693 }
694
695 /* Read the graph file. Return nonzero on fatal error. */
696
697 static int
698 read_graph_file (void)
699 {
700 unsigned version;
701 unsigned current_tag = 0;
702 struct function_info *fn = NULL;
703 source_t *src = NULL;
704 unsigned ix;
705 unsigned tag;
706
707 if (!gcov_open (bbg_file_name, 1))
708 {
709 fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
710 return 1;
711 }
712 bbg_file_time = gcov_time ();
713 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
714 {
715 fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
716 gcov_close ();
717 return 1;
718 }
719
720 version = gcov_read_unsigned ();
721 if (version != GCOV_VERSION)
722 {
723 char v[4], e[4];
724
725 GCOV_UNSIGNED2STRING (v, version);
726 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
727
728 fnotice (stderr, "%s:version `%.4s', prefer `%.4s'\n",
729 bbg_file_name, v, e);
730 }
731 bbg_stamp = gcov_read_unsigned ();
732
733 while ((tag = gcov_read_unsigned ()))
734 {
735 unsigned length = gcov_read_unsigned ();
736 gcov_position_t base = gcov_position ();
737
738 if (tag == GCOV_TAG_FUNCTION)
739 {
740 char *function_name;
741 unsigned ident, checksum, lineno;
742 source_t *src;
743 function_t *probe, *prev;
744
745 ident = gcov_read_unsigned ();
746 checksum = gcov_read_unsigned ();
747 function_name = xstrdup (gcov_read_string ());
748 src = find_source (gcov_read_string ());
749 lineno = gcov_read_unsigned ();
750
751 fn = xcalloc (1, sizeof (function_t));
752 fn->name = function_name;
753 fn->ident = ident;
754 fn->checksum = checksum;
755 fn->src = src;
756 fn->line = lineno;
757
758 fn->next = functions;
759 functions = fn;
760 current_tag = tag;
761
762 if (lineno >= src->num_lines)
763 src->num_lines = lineno + 1;
764 /* Now insert it into the source file's list of
765 functions. Normally functions will be encountered in
766 ascending order, so a simple scan is quick. */
767 for (probe = src->functions, prev = NULL;
768 probe && probe->line > lineno;
769 prev = probe, probe = probe->line_next)
770 continue;
771 fn->line_next = probe;
772 if (prev)
773 prev->line_next = fn;
774 else
775 src->functions = fn;
776 }
777 else if (fn && tag == GCOV_TAG_BLOCKS)
778 {
779 if (fn->blocks)
780 fnotice (stderr, "%s:already seen blocks for `%s'\n",
781 bbg_file_name, fn->name);
782 else
783 {
784 unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
785 fn->num_blocks = num_blocks;
786
787 fn->blocks = xcalloc (fn->num_blocks, sizeof (block_t));
788 for (ix = 0; ix != num_blocks; ix++)
789 fn->blocks[ix].flags = gcov_read_unsigned ();
790 }
791 }
792 else if (fn && tag == GCOV_TAG_ARCS)
793 {
794 unsigned src = gcov_read_unsigned ();
795 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
796
797 if (src >= fn->num_blocks || fn->blocks[src].succ)
798 goto corrupt;
799
800 while (num_dests--)
801 {
802 struct arc_info *arc;
803 unsigned dest = gcov_read_unsigned ();
804 unsigned flags = gcov_read_unsigned ();
805
806 if (dest >= fn->num_blocks)
807 goto corrupt;
808 arc = xcalloc (1, sizeof (arc_t));
809
810 arc->dst = &fn->blocks[dest];
811 arc->src = &fn->blocks[src];
812
813 arc->count = 0;
814 arc->count_valid = 0;
815 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
816 arc->fake = !!(flags & GCOV_ARC_FAKE);
817 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
818
819 arc->succ_next = fn->blocks[src].succ;
820 fn->blocks[src].succ = arc;
821 fn->blocks[src].num_succ++;
822
823 arc->pred_next = fn->blocks[dest].pred;
824 fn->blocks[dest].pred = arc;
825 fn->blocks[dest].num_pred++;
826
827 if (arc->fake)
828 {
829 if (src)
830 {
831 /* Exceptional exit from this function, the
832 source block must be a call. */
833 fn->blocks[src].is_call_site = 1;
834 arc->is_call_non_return = 1;
835 }
836 else
837 {
838 /* Non-local return from a callee of this
839 function. The destination block is a catch or
840 setjmp. */
841 arc->is_nonlocal_return = 1;
842 fn->blocks[dest].is_nonlocal_return = 1;
843 }
844 }
845
846 if (!arc->on_tree)
847 fn->num_counts++;
848 }
849 }
850 else if (fn && tag == GCOV_TAG_LINES)
851 {
852 unsigned blockno = gcov_read_unsigned ();
853 unsigned *line_nos = xcalloc (length - 1, sizeof (unsigned));
854
855 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
856 goto corrupt;
857
858 for (ix = 0; ; )
859 {
860 unsigned lineno = gcov_read_unsigned ();
861
862 if (lineno)
863 {
864 if (!ix)
865 {
866 line_nos[ix++] = 0;
867 line_nos[ix++] = src->index;
868 }
869 line_nos[ix++] = lineno;
870 if (lineno >= src->num_lines)
871 src->num_lines = lineno + 1;
872 }
873 else
874 {
875 const char *file_name = gcov_read_string ();
876
877 if (!file_name)
878 break;
879 src = find_source (file_name);
880
881 line_nos[ix++] = 0;
882 line_nos[ix++] = src->index;
883 }
884 }
885
886 fn->blocks[blockno].u.line.encoding = line_nos;
887 fn->blocks[blockno].u.line.num = ix;
888 }
889 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
890 {
891 fn = NULL;
892 current_tag = 0;
893 }
894 gcov_sync (base, length);
895 if (gcov_is_error ())
896 break;
897 }
898 if (!gcov_is_eof ())
899 {
900 corrupt:;
901 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
902 gcov_close ();
903 return 1;
904 }
905 gcov_close ();
906
907 /* We built everything backwards, so nreverse them all */
908
909 /* Reverse sources. Not strictly necessary, but we'll then process
910 them in the 'expected' order. */
911 {
912 source_t *src, *src_p, *src_n;
913
914 for (src_p = NULL, src = sources; src; src_p = src, src = src_n)
915 {
916 src_n = src->next;
917 src->next = src_p;
918 }
919 sources = src_p;
920 }
921
922 /* Reverse functions. */
923 {
924 function_t *fn, *fn_p, *fn_n;
925
926 for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn_n)
927 {
928 unsigned ix;
929
930 fn_n = fn->next;
931 fn->next = fn_p;
932
933 /* Reverse the arcs. */
934 for (ix = fn->num_blocks; ix--;)
935 {
936 arc_t *arc, *arc_p, *arc_n;
937
938 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
939 arc_p = arc, arc = arc_n)
940 {
941 arc_n = arc->succ_next;
942 arc->succ_next = arc_p;
943 }
944 fn->blocks[ix].succ = arc_p;
945
946 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
947 arc_p = arc, arc = arc_n)
948 {
949 arc_n = arc->pred_next;
950 arc->pred_next = arc_p;
951 }
952 fn->blocks[ix].pred = arc_p;
953 }
954 }
955 functions = fn_p;
956 }
957 return 0;
958 }
959
960 /* Reads profiles from the count file and attach to each
961 function. Return nonzero if fatal error. */
962
963 static int
964 read_count_file (void)
965 {
966 unsigned ix;
967 unsigned version;
968 unsigned tag;
969 function_t *fn = NULL;
970 int error = 0;
971
972 if (!gcov_open (da_file_name, 1))
973 {
974 fnotice (stderr, "%s:cannot open data file\n", da_file_name);
975 return 1;
976 }
977 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
978 {
979 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
980 cleanup:;
981 gcov_close ();
982 return 1;
983 }
984 version = gcov_read_unsigned ();
985 if (version != GCOV_VERSION)
986 {
987 char v[4], e[4];
988
989 GCOV_UNSIGNED2STRING (v, version);
990 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
991
992 fnotice (stderr, "%s:version `%.4s', prefer version `%.4s'\n",
993 da_file_name, v, e);
994 }
995 tag = gcov_read_unsigned ();
996 if (tag != bbg_stamp)
997 {
998 fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
999 goto cleanup;
1000 }
1001
1002 while ((tag = gcov_read_unsigned ()))
1003 {
1004 unsigned length = gcov_read_unsigned ();
1005 unsigned long base = gcov_position ();
1006
1007 if (tag == GCOV_TAG_OBJECT_SUMMARY)
1008 gcov_read_summary (&object_summary);
1009 else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1010 program_count++;
1011 else if (tag == GCOV_TAG_FUNCTION)
1012 {
1013 unsigned ident = gcov_read_unsigned ();
1014 struct function_info *fn_n = functions;
1015
1016 for (fn = fn ? fn->next : NULL; ; fn = fn->next)
1017 {
1018 if (fn)
1019 ;
1020 else if ((fn = fn_n))
1021 fn_n = NULL;
1022 else
1023 {
1024 fnotice (stderr, "%s:unknown function `%u'\n",
1025 da_file_name, ident);
1026 break;
1027 }
1028 if (fn->ident == ident)
1029 break;
1030 }
1031
1032 if (!fn)
1033 ;
1034 else if (gcov_read_unsigned () != fn->checksum)
1035 {
1036 mismatch:;
1037 fnotice (stderr, "%s:profile mismatch for `%s'\n",
1038 da_file_name, fn->name);
1039 goto cleanup;
1040 }
1041 }
1042 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1043 {
1044 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
1045 goto mismatch;
1046
1047 if (!fn->counts)
1048 fn->counts = xcalloc (fn->num_counts, sizeof (gcov_type));
1049
1050 for (ix = 0; ix != fn->num_counts; ix++)
1051 fn->counts[ix] += gcov_read_counter ();
1052 }
1053 gcov_sync (base, length);
1054 if ((error = gcov_is_error ()))
1055 break;
1056 }
1057
1058 if (!gcov_is_eof ())
1059 {
1060 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1061 da_file_name);
1062 goto cleanup;
1063 }
1064
1065 gcov_close ();
1066 return 0;
1067 }
1068
1069 /* Solve the flow graph. Propagate counts from the instrumented arcs
1070 to the blocks and the uninstrumented arcs. */
1071
1072 static void
1073 solve_flow_graph (function_t *fn)
1074 {
1075 unsigned ix;
1076 arc_t *arc;
1077 gcov_type *count_ptr = fn->counts;
1078 block_t *blk;
1079 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */
1080 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
1081
1082 if (fn->num_blocks < 2)
1083 fnotice (stderr, "%s:`%s' lacks entry and/or exit blocks\n",
1084 bbg_file_name, fn->name);
1085 else
1086 {
1087 if (fn->blocks[0].num_pred)
1088 fnotice (stderr, "%s:`%s' has arcs to entry block\n",
1089 bbg_file_name, fn->name);
1090 else
1091 /* We can't deduce the entry block counts from the lack of
1092 predecessors. */
1093 fn->blocks[0].num_pred = ~(unsigned)0;
1094
1095 if (fn->blocks[fn->num_blocks - 1].num_succ)
1096 fnotice (stderr, "%s:`%s' has arcs from exit block\n",
1097 bbg_file_name, fn->name);
1098 else
1099 /* Likewise, we can't deduce exit block counts from the lack
1100 of its successors. */
1101 fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0;
1102 }
1103
1104 /* Propagate the measured counts, this must be done in the same
1105 order as the code in profile.c */
1106 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
1107 {
1108 block_t const *prev_dst = NULL;
1109 int out_of_order = 0;
1110 int non_fake_succ = 0;
1111
1112 for (arc = blk->succ; arc; arc = arc->succ_next)
1113 {
1114 if (!arc->fake)
1115 non_fake_succ++;
1116
1117 if (!arc->on_tree)
1118 {
1119 if (count_ptr)
1120 arc->count = *count_ptr++;
1121 arc->count_valid = 1;
1122 blk->num_succ--;
1123 arc->dst->num_pred--;
1124 }
1125 if (prev_dst && prev_dst > arc->dst)
1126 out_of_order = 1;
1127 prev_dst = arc->dst;
1128 }
1129 if (non_fake_succ == 1)
1130 {
1131 /* If there is only one non-fake exit, it is an
1132 unconditional branch. */
1133 for (arc = blk->succ; arc; arc = arc->succ_next)
1134 if (!arc->fake)
1135 {
1136 arc->is_unconditional = 1;
1137 /* If this block is instrumenting a call, it might be
1138 an artificial block. It is not artificial if it has
1139 a non-fallthrough exit, or the destination of this
1140 arc has more than one entry. Mark the destination
1141 block as a return site, if none of those conditions
1142 hold. */
1143 if (blk->is_call_site && arc->fall_through
1144 && arc->dst->pred == arc && !arc->pred_next)
1145 arc->dst->is_call_return = 1;
1146 }
1147 }
1148
1149 /* Sort the successor arcs into ascending dst order. profile.c
1150 normally produces arcs in the right order, but sometimes with
1151 one or two out of order. We're not using a particularly
1152 smart sort. */
1153 if (out_of_order)
1154 {
1155 arc_t *start = blk->succ;
1156 unsigned changes = 1;
1157
1158 while (changes)
1159 {
1160 arc_t *arc, *arc_p, *arc_n;
1161
1162 changes = 0;
1163 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1164 {
1165 if (arc->dst > arc_n->dst)
1166 {
1167 changes = 1;
1168 if (arc_p)
1169 arc_p->succ_next = arc_n;
1170 else
1171 start = arc_n;
1172 arc->succ_next = arc_n->succ_next;
1173 arc_n->succ_next = arc;
1174 arc_p = arc_n;
1175 }
1176 else
1177 {
1178 arc_p = arc;
1179 arc = arc_n;
1180 }
1181 }
1182 }
1183 blk->succ = start;
1184 }
1185
1186 /* Place it on the invalid chain, it will be ignored if that's
1187 wrong. */
1188 blk->invalid_chain = 1;
1189 blk->chain = invalid_blocks;
1190 invalid_blocks = blk;
1191 }
1192
1193 while (invalid_blocks || valid_blocks)
1194 {
1195 while ((blk = invalid_blocks))
1196 {
1197 gcov_type total = 0;
1198 const arc_t *arc;
1199
1200 invalid_blocks = blk->chain;
1201 blk->invalid_chain = 0;
1202 if (!blk->num_succ)
1203 for (arc = blk->succ; arc; arc = arc->succ_next)
1204 total += arc->count;
1205 else if (!blk->num_pred)
1206 for (arc = blk->pred; arc; arc = arc->pred_next)
1207 total += arc->count;
1208 else
1209 continue;
1210
1211 blk->count = total;
1212 blk->count_valid = 1;
1213 blk->chain = valid_blocks;
1214 blk->valid_chain = 1;
1215 valid_blocks = blk;
1216 }
1217 while ((blk = valid_blocks))
1218 {
1219 gcov_type total;
1220 arc_t *arc, *inv_arc;
1221
1222 valid_blocks = blk->chain;
1223 blk->valid_chain = 0;
1224 if (blk->num_succ == 1)
1225 {
1226 block_t *dst;
1227
1228 total = blk->count;
1229 inv_arc = NULL;
1230 for (arc = blk->succ; arc; arc = arc->succ_next)
1231 {
1232 total -= arc->count;
1233 if (!arc->count_valid)
1234 inv_arc = arc;
1235 }
1236 dst = inv_arc->dst;
1237 inv_arc->count_valid = 1;
1238 inv_arc->count = total;
1239 blk->num_succ--;
1240 dst->num_pred--;
1241 if (dst->count_valid)
1242 {
1243 if (dst->num_pred == 1 && !dst->valid_chain)
1244 {
1245 dst->chain = valid_blocks;
1246 dst->valid_chain = 1;
1247 valid_blocks = dst;
1248 }
1249 }
1250 else
1251 {
1252 if (!dst->num_pred && !dst->invalid_chain)
1253 {
1254 dst->chain = invalid_blocks;
1255 dst->invalid_chain = 1;
1256 invalid_blocks = dst;
1257 }
1258 }
1259 }
1260 if (blk->num_pred == 1)
1261 {
1262 block_t *src;
1263
1264 total = blk->count;
1265 inv_arc = NULL;
1266 for (arc = blk->pred; arc; arc = arc->pred_next)
1267 {
1268 total -= arc->count;
1269 if (!arc->count_valid)
1270 inv_arc = arc;
1271 }
1272 src = inv_arc->src;
1273 inv_arc->count_valid = 1;
1274 inv_arc->count = total;
1275 blk->num_pred--;
1276 src->num_succ--;
1277 if (src->count_valid)
1278 {
1279 if (src->num_succ == 1 && !src->valid_chain)
1280 {
1281 src->chain = valid_blocks;
1282 src->valid_chain = 1;
1283 valid_blocks = src;
1284 }
1285 }
1286 else
1287 {
1288 if (!src->num_succ && !src->invalid_chain)
1289 {
1290 src->chain = invalid_blocks;
1291 src->invalid_chain = 1;
1292 invalid_blocks = src;
1293 }
1294 }
1295 }
1296 }
1297 }
1298
1299 /* If the graph has been correctly solved, every block will have a
1300 valid count. */
1301 for (ix = 0; ix < fn->num_blocks; ix++)
1302 if (!fn->blocks[ix].count_valid)
1303 {
1304 fnotice (stderr, "%s:graph is unsolvable for `%s'\n",
1305 bbg_file_name, fn->name);
1306 break;
1307 }
1308 }
1309
1310 \f
1311
1312 /* Increment totals in COVERAGE according to arc ARC. */
1313
1314 static void
1315 add_branch_counts (coverage_t *coverage, const arc_t *arc)
1316 {
1317 if (arc->is_call_non_return)
1318 {
1319 coverage->calls++;
1320 if (arc->src->count)
1321 coverage->calls_executed++;
1322 }
1323 else if (!arc->is_unconditional)
1324 {
1325 coverage->branches++;
1326 if (arc->src->count)
1327 coverage->branches_executed++;
1328 if (arc->count)
1329 coverage->branches_taken++;
1330 }
1331 }
1332
1333 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1334 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1335 If DP is zero, no decimal point is printed. Only print 100% when
1336 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1337 format TOP. Return pointer to a static string. */
1338
1339 static char const *
1340 format_gcov (gcov_type top, gcov_type bottom, int dp)
1341 {
1342 static char buffer[20];
1343
1344 if (dp >= 0)
1345 {
1346 float ratio = bottom ? (float)top / bottom : 0;
1347 int ix;
1348 unsigned limit = 100;
1349 unsigned percent;
1350
1351 for (ix = dp; ix--; )
1352 limit *= 10;
1353
1354 percent = (unsigned) (ratio * limit + (float)0.5);
1355 if (percent <= 0 && top)
1356 percent = 1;
1357 else if (percent >= limit && top != bottom)
1358 percent = limit - 1;
1359 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1360 if (dp)
1361 {
1362 dp++;
1363 do
1364 {
1365 buffer[ix+1] = buffer[ix];
1366 ix--;
1367 }
1368 while (dp--);
1369 buffer[ix + 1] = '.';
1370 }
1371 }
1372 else
1373 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
1374
1375 return buffer;
1376 }
1377
1378
1379 /* Output summary info for a function. */
1380
1381 static void
1382 function_summary (const coverage_t *coverage, const char *title)
1383 {
1384 fnotice (stdout, "%s `%s'\n", title, coverage->name);
1385
1386 if (coverage->lines)
1387 fnotice (stdout, "Lines executed:%s of %d\n",
1388 format_gcov (coverage->lines_executed, coverage->lines, 2),
1389 coverage->lines);
1390 else
1391 fnotice (stdout, "No executable lines");
1392
1393 if (flag_branches)
1394 {
1395 if (coverage->branches)
1396 {
1397 fnotice (stdout, "Branches executed:%s of %d\n",
1398 format_gcov (coverage->branches_executed,
1399 coverage->branches, 2),
1400 coverage->branches);
1401 fnotice (stdout, "Taken at least once:%s of %d\n",
1402 format_gcov (coverage->branches_taken,
1403 coverage->branches, 2),
1404 coverage->branches);
1405 }
1406 else
1407 fnotice (stdout, "No branches\n");
1408 if (coverage->calls)
1409 fnotice (stdout, "Calls executed:%s of %d\n",
1410 format_gcov (coverage->calls_executed, coverage->calls, 2),
1411 coverage->calls);
1412 else
1413 fnotice (stdout, "No calls\n");
1414 }
1415 }
1416
1417 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1418 affect name generation. With preserve_paths we create a filename
1419 from all path components of the source file, replacing '/' with
1420 '#', without it we simply take the basename component. With
1421 long_output_names we prepend the processed name of the input file
1422 to each output name (except when the current source file is the
1423 input file, so you don't get a double concatenation). The two
1424 components are separated by '##'. Also '.' filename components are
1425 removed and '..' components are renamed to '^'. */
1426
1427 static char *
1428 make_gcov_file_name (const char *input_name, const char *src_name)
1429 {
1430 char *cptr;
1431 char *name = xmalloc (strlen (src_name) + strlen (input_name) + 10);
1432
1433 name[0] = 0;
1434 if (flag_long_names && strcmp (src_name, input_name))
1435 {
1436 /* Generate the input filename part. */
1437 cptr = flag_preserve_paths ? NULL : strrchr (input_name, '/');
1438 strcat (name, cptr ? cptr + 1 : input_name);
1439 strcat (name, "##");
1440 }
1441
1442 /* Generate the source filename part. */
1443 cptr = flag_preserve_paths ? NULL : strrchr (src_name, '/');
1444 strcat (name, cptr ? cptr + 1 : src_name);
1445
1446 if (flag_preserve_paths)
1447 {
1448 /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1449 char *prev;
1450
1451 for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
1452 {
1453 unsigned shift = 0;
1454
1455 if (prev + 1 == cptr && prev[0] == '.')
1456 {
1457 /* Remove '.' */
1458 shift = 2;
1459 }
1460 else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
1461 {
1462 /* Convert '..' */
1463 shift = 1;
1464 prev[1] = '^';
1465 }
1466 else
1467 *cptr++ = '#';
1468 if (shift)
1469 {
1470 cptr = prev;
1471 do
1472 prev[0] = prev[shift];
1473 while (*prev++);
1474 }
1475 }
1476 }
1477
1478 strcat (name, ".gcov");
1479 return name;
1480 }
1481
1482 /* Scan through the bb_data for each line in the block, increment
1483 the line number execution count indicated by the execution count of
1484 the appropriate basic block. */
1485
1486 static void
1487 add_line_counts (coverage_t *coverage, function_t *fn)
1488 {
1489 unsigned ix;
1490 line_t *line = NULL; /* This is propagated from one iteration to the
1491 next. */
1492
1493 /* Scan each basic block. */
1494 for (ix = 0; ix != fn->num_blocks; ix++)
1495 {
1496 block_t *block = &fn->blocks[ix];
1497 unsigned *encoding;
1498 const source_t *src = NULL;
1499 unsigned jx;
1500
1501 if (block->count && ix && ix + 1 != fn->num_blocks)
1502 fn->blocks_executed++;
1503 for (jx = 0, encoding = block->u.line.encoding;
1504 jx != block->u.line.num; jx++, encoding++)
1505 if (!*encoding)
1506 {
1507 unsigned src_n = *++encoding;
1508
1509 for (src = sources; src->index != src_n; src = src->next)
1510 continue;
1511 jx++;
1512 }
1513 else
1514 {
1515 line = &src->lines[*encoding];
1516
1517 if (coverage)
1518 {
1519 if (!line->exists)
1520 coverage->lines++;
1521 if (!line->count && block->count)
1522 coverage->lines_executed++;
1523 }
1524 line->exists = 1;
1525 line->count += block->count;
1526 }
1527 free (block->u.line.encoding);
1528 block->u.cycle.arc = NULL;
1529 block->u.cycle.ident = ~0U;
1530
1531 if (!ix || ix + 1 == fn->num_blocks)
1532 /* Entry or exit block */;
1533 else if (flag_all_blocks)
1534 {
1535 line_t *block_line = line ? line : &fn->src->lines[fn->line];
1536
1537 block->chain = block_line->u.blocks;
1538 block_line->u.blocks = block;
1539 }
1540 else if (flag_branches)
1541 {
1542 arc_t *arc;
1543
1544 for (arc = block->succ; arc; arc = arc->succ_next)
1545 {
1546 arc->line_next = line->u.branches;
1547 line->u.branches = arc;
1548 if (coverage && !arc->is_unconditional)
1549 add_branch_counts (coverage, arc);
1550 }
1551 }
1552 }
1553 if (!line)
1554 fnotice (stderr, "%s:no lines for `%s'\n", bbg_file_name, fn->name);
1555 }
1556
1557 /* Accumulate the line counts of a file. */
1558
1559 static void
1560 accumulate_line_counts (source_t *src)
1561 {
1562 line_t *line;
1563 function_t *fn, *fn_p, *fn_n;
1564 unsigned ix;
1565
1566 /* Reverse the function order. */
1567 for (fn = src->functions, fn_p = NULL; fn;
1568 fn_p = fn, fn = fn_n)
1569 {
1570 fn_n = fn->line_next;
1571 fn->line_next = fn_p;
1572 }
1573 src->functions = fn_p;
1574
1575 for (ix = src->num_lines, line = src->lines; ix--; line++)
1576 {
1577 if (!flag_all_blocks)
1578 {
1579 arc_t *arc, *arc_p, *arc_n;
1580
1581 /* Total and reverse the branch information. */
1582 for (arc = line->u.branches, arc_p = NULL; arc;
1583 arc_p = arc, arc = arc_n)
1584 {
1585 arc_n = arc->line_next;
1586 arc->line_next = arc_p;
1587
1588 add_branch_counts (&src->coverage, arc);
1589 }
1590 line->u.branches = arc_p;
1591 }
1592 else if (line->u.blocks)
1593 {
1594 /* The user expects the line count to be the number of times
1595 a line has been executed. Simply summing the block count
1596 will give an artificially high number. The Right Thing
1597 is to sum the entry counts to the graph of blocks on this
1598 line, then find the elementary cycles of the local graph
1599 and add the transition counts of those cycles. */
1600 block_t *block, *block_p, *block_n;
1601 gcov_type count = 0;
1602
1603 /* Reverse the block information. */
1604 for (block = line->u.blocks, block_p = NULL; block;
1605 block_p = block, block = block_n)
1606 {
1607 block_n = block->chain;
1608 block->chain = block_p;
1609 block->u.cycle.ident = ix;
1610 }
1611 line->u.blocks = block_p;
1612
1613 /* Sum the entry arcs. */
1614 for (block = line->u.blocks; block; block = block->chain)
1615 {
1616 arc_t *arc;
1617
1618 for (arc = block->pred; arc; arc = arc->pred_next)
1619 {
1620 if (arc->src->u.cycle.ident != ix)
1621 count += arc->count;
1622 if (flag_branches)
1623 add_branch_counts (&src->coverage, arc);
1624 }
1625 }
1626
1627 /* Find the loops. This uses the algorithm described in
1628 Tiernan 'An Efficient Search Algorithm to Find the
1629 Elementary Circuits of a Graph', CACM Dec 1970. We hold
1630 the P array by having each block point to the arc that
1631 connects to the previous block. The H array is implicitly
1632 held because of the arc ordering, and the block's
1633 previous arc pointer.
1634
1635 Although the algorithm is O(N^3) for highly connected
1636 graphs, at worst we'll have O(N^2), as most blocks have
1637 only one or two exits. Most graphs will be small.
1638
1639 For each loop we find, locate the arc with the smallest
1640 transition count, and add that to the cumulative
1641 count. Remove the arc from consideration. */
1642 for (block = line->u.blocks; block; block = block->chain)
1643 {
1644 block_t *head = block;
1645 arc_t *arc;
1646
1647 next_vertex:;
1648 arc = head->succ;
1649 current_vertex:;
1650 while (arc)
1651 {
1652 block_t *dst = arc->dst;
1653 if (/* Already used that arc. */
1654 arc->cycle
1655 /* Not to same graph, or before first vertex. */
1656 || dst->u.cycle.ident != ix
1657 /* Already in path. */
1658 || dst->u.cycle.arc)
1659 {
1660 arc = arc->succ_next;
1661 continue;
1662 }
1663
1664 if (dst == block)
1665 {
1666 /* Found a closing arc. */
1667 gcov_type cycle_count = arc->count;
1668 arc_t *cycle_arc = arc;
1669 arc_t *probe_arc;
1670
1671 /* Locate the smallest arc count of the loop. */
1672 for (dst = head; (probe_arc = dst->u.cycle.arc);
1673 dst = probe_arc->src)
1674 if (cycle_count > probe_arc->count)
1675 {
1676 cycle_count = probe_arc->count;
1677 cycle_arc = probe_arc;
1678 }
1679
1680 count += cycle_count;
1681 cycle_arc->cycle = 1;
1682 /* Unwind to the cyclic arc. */
1683 while (head != cycle_arc->src)
1684 {
1685 arc = head->u.cycle.arc;
1686 head = arc->src;
1687 }
1688 /* Move on. */
1689 arc = arc->succ_next;
1690 continue;
1691 }
1692
1693 /* Add new block to chain. */
1694 dst->u.cycle.arc = arc;
1695 head = dst;
1696 goto next_vertex;
1697 }
1698 /* We could not add another vertex to the path. Remove
1699 the last vertex from the list. */
1700 arc = head->u.cycle.arc;
1701 if (arc)
1702 {
1703 /* It was not the first vertex. Move onto next arc. */
1704 head->u.cycle.arc = NULL;
1705 head = arc->src;
1706 arc = arc->succ_next;
1707 goto current_vertex;
1708 }
1709 /* Mark this block as unusable. */
1710 block->u.cycle.ident = ~0U;
1711 }
1712
1713 line->count = count;
1714 }
1715
1716 if (line->exists)
1717 {
1718 src->coverage.lines++;
1719 if (line->count)
1720 src->coverage.lines_executed++;
1721 }
1722 }
1723 }
1724
1725 /* Ouput information about ARC number IX. Returns nonzero if
1726 anything is output. */
1727
1728 static int
1729 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
1730 {
1731
1732 if (arc->is_call_non_return)
1733 {
1734 if (arc->src->count)
1735 {
1736 fnotice (gcov_file, "call %2d returned %s\n", ix,
1737 format_gcov (arc->src->count - arc->count,
1738 arc->src->count, -flag_counts));
1739 }
1740 else
1741 fnotice (gcov_file, "call %2d never executed\n", ix);
1742 }
1743 else if (!arc->is_unconditional)
1744 {
1745 if (arc->src->count)
1746 fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
1747 format_gcov (arc->count, arc->src->count, -flag_counts),
1748 arc->fall_through ? " (fallthrough)" : "");
1749 else
1750 fnotice (gcov_file, "branch %2d never executed\n", ix);
1751 }
1752 else if (flag_unconditional && !arc->dst->is_call_return)
1753 {
1754 if (arc->src->count)
1755 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
1756 format_gcov (arc->count, arc->src->count, -flag_counts));
1757 else
1758 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
1759 }
1760 else
1761 return 0;
1762 return 1;
1763
1764 }
1765
1766 /* Read in the source file one line at a time, and output that line to
1767 the gcov file preceded by its execution count and other
1768 information. */
1769
1770 static void
1771 output_lines (FILE *gcov_file, const source_t *src)
1772 {
1773 FILE *source_file;
1774 unsigned line_num; /* current line number. */
1775 const line_t *line; /* current line info ptr. */
1776 char string[STRING_SIZE]; /* line buffer. */
1777 char const *retval = ""; /* status of source file reading. */
1778 function_t *fn = src->functions;
1779
1780 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
1781 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
1782 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, da_file_name);
1783 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
1784 object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
1785 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
1786
1787 source_file = fopen (src->name, "r");
1788 if (!source_file)
1789 {
1790 fnotice (stderr, "%s:cannot open source file\n", src->name);
1791 retval = NULL;
1792 }
1793 else
1794 {
1795 struct stat status;
1796
1797 if (!fstat (fileno (source_file), &status)
1798 && status.st_mtime > bbg_file_time)
1799 {
1800 fnotice (stderr, "%s:source file is newer than graph file `%s'\n",
1801 src->name, bbg_file_name);
1802 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n",
1803 "-", 0);
1804 }
1805 }
1806
1807 for (line_num = 1, line = &src->lines[line_num];
1808 line_num < src->num_lines; line_num++, line++)
1809 {
1810 for (; fn && fn->line == line_num; fn = fn->line_next)
1811 {
1812 arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
1813 gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
1814
1815 for (; arc; arc = arc->pred_next)
1816 if (arc->fake)
1817 return_count -= arc->count;
1818
1819 fprintf (gcov_file, "function %s", fn->name);
1820 fprintf (gcov_file, " called %s",
1821 format_gcov (fn->blocks[0].count, 0, -1));
1822 fprintf (gcov_file, " returned %s",
1823 format_gcov (return_count, fn->blocks[0].count, 0));
1824 fprintf (gcov_file, " blocks executed %s",
1825 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
1826 fprintf (gcov_file, "\n");
1827 }
1828
1829 /* For lines which don't exist in the .bb file, print '-' before
1830 the source line. For lines which exist but were never
1831 executed, print '#####' before the source line. Otherwise,
1832 print the execution count before the source line. There are
1833 16 spaces of indentation added before the source line so that
1834 tabs won't be messed up. */
1835 fprintf (gcov_file, "%9s:%5u:",
1836 !line->exists ? "-" : !line->count ? "#####"
1837 : format_gcov (line->count, 0, -1), line_num);
1838
1839 if (retval)
1840 {
1841 /* Copy source line. */
1842 do
1843 {
1844 retval = fgets (string, STRING_SIZE, source_file);
1845 if (!retval)
1846 break;
1847 fputs (retval, gcov_file);
1848 }
1849 while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1850 }
1851 if (!retval)
1852 fputs ("/*EOF*/\n", gcov_file);
1853
1854 if (flag_all_blocks)
1855 {
1856 block_t *block;
1857 arc_t *arc;
1858 int ix, jx;
1859
1860 for (ix = jx = 0, block = line->u.blocks; block;
1861 block = block->chain)
1862 {
1863 if (!block->is_call_return)
1864 fprintf (gcov_file, "%9s:%5u-block %2d\n",
1865 !line->exists ? "-" : !block->count ? "$$$$$"
1866 : format_gcov (block->count, 0, -1),
1867 line_num, ix++);
1868 if (flag_branches)
1869 for (arc = block->succ; arc; arc = arc->succ_next)
1870 jx += output_branch_count (gcov_file, jx, arc);
1871 }
1872 }
1873 else if (flag_branches)
1874 {
1875 int ix;
1876 arc_t *arc;
1877
1878 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
1879 ix += output_branch_count (gcov_file, ix, arc);
1880 }
1881 }
1882
1883 /* Handle all remaining source lines. There may be lines after the
1884 last line of code. */
1885 if (retval)
1886 {
1887 for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
1888 {
1889 fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval);
1890
1891 while (!retval[0] || retval[strlen (retval) - 1] != '\n')
1892 {
1893 retval = fgets (string, STRING_SIZE, source_file);
1894 if (!retval)
1895 break;
1896 fputs (retval, gcov_file);
1897 }
1898 }
1899 }
1900
1901 if (source_file)
1902 fclose (source_file);
1903 }