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