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