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