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