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