1 /* Gcov.c: prepend line execution counts and branch probabilities to a
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>
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)
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.
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. */
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. */
29 /* ??? Should have an option to print the number of basic blocks, and the
30 percent of them that are covered. */
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. */
41 /* Need an option to show individual block counts, and show
42 probabilities of fall through arcs. */
46 #include "coretypes.h"
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. */
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. */
67 /* This is the size of the buffer used to read in source file lines. */
69 #define STRING_SIZE 200
75 /* Describes an arc between two basic blocks. */
77 typedef struct arc_info
79 /* source and destination blocks. */
80 struct block_info
*src
;
81 struct block_info
*dst
;
83 /* transition counts. */
86 unsigned int count_valid
: 1;
87 unsigned int on_tree
: 1;
88 unsigned int fake
: 1;
89 unsigned int fall_through
: 1;
91 /* Arc is for a function that abnormally returns. */
92 unsigned int is_call_non_return
: 1;
94 /* Arc is for catch/setjump. */
95 unsigned int is_nonlocal_return
: 1;
97 /* Is an unconditional branch. */
98 unsigned int is_unconditional
: 1;
100 /* Loop making arc. */
101 unsigned int cycle
: 1;
103 /* Next branch on line. */
104 struct arc_info
*line_next
;
106 /* Links to next arc on src and dst lists. */
107 struct arc_info
*succ_next
;
108 struct arc_info
*pred_next
;
111 /* Describes a basic block. Contains lists of arcs to successor and
112 predecessor blocks. */
114 typedef struct block_info
116 /* Chain of exit and entry arcs. */
120 /* Number of unprocessed exit and entry arcs. */
124 /* Block execution count. */
127 unsigned count_valid
: 1;
128 unsigned valid_chain
: 1;
129 unsigned invalid_chain
: 1;
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. */
135 /* Block is a landing pad for longjmp or throw. */
136 unsigned is_nonlocal_return
: 1;
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
148 } line
; /* Valid until blocks are linked onto lines */
151 /* Single line graph cycle workspace. Used for all-blocks
155 } cycle
; /* Used in all-blocks mode, after blocks are linked onto
159 /* Temporary chain for solving graph, and for chaining blocks on one
161 struct block_info
*chain
;
165 /* Describes a single function. Contains an array of basic blocks. */
167 typedef struct function_info
169 /* Name of function. */
174 /* Array of basic blocks. */
177 unsigned blocks_executed
;
179 /* Raw arc coverage counts. */
183 /* First line number. */
185 struct source_info
*src
;
187 /* Next function in same source file. */
188 struct function_info
*line_next
;
191 struct function_info
*next
;
194 /* Describes coverage of a file or function. */
196 typedef struct coverage_info
202 int branches_executed
;
211 /* Describes a single line of source. Contains a chain of basic blocks
214 typedef struct line_info
216 gcov_type count
; /* execution count */
219 arc_t
*branches
; /* branches from blocks that end on this
220 line. Used for branch-counts when not
222 block_t
*blocks
; /* blocks which start on this line. Used
223 in all-blocks mode. */
228 /* Describes a file mentioned in the block graph. Contains an array
231 typedef struct source_info
233 /* Name of source file. */
237 /* Array of line information. */
243 /* Functions in this source file. These are in ascending line
245 function_t
*functions
;
247 /* Next source file. */
248 struct source_info
*next
;
251 /* Holds a list of function basic block graphs. */
253 static function_t
*functions
;
255 /* This points to the head of the sourcefile structure list. */
257 static source_t
*sources
;
259 /* This holds data summary information. */
261 static struct gcov_summary object_summary
;
262 static unsigned program_count
;
264 /* Modification time of graph file. */
266 static time_t bbg_file_time
;
268 /* Name and file pointer of the input file for the basic block graph. */
270 static char *bbg_file_name
;
272 /* Name and file pointer of the input file for the arc count data. */
274 static char *da_file_name
;
276 /* Output branch probabilities. */
278 static int flag_branches
= 0;
280 /* Show unconditional branches too. */
281 static int flag_unconditional
= 0;
283 /* Output a gcov file if this is true. This is on by default, and can
284 be turned off by the -n option. */
286 static int flag_gcov_file
= 1;
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. */
292 static int flag_long_names
= 0;
294 /* Output count information for every basic block, not merely those
295 that contain line number information. */
297 static int flag_all_blocks
= 0;
299 /* Output summary info for each function. */
301 static int flag_function_summary
= 0;
303 /* Object directory file prefix. This is the directory/file where the
304 graph and data files are looked for, if nonzero. */
306 static char *object_directory
= 0;
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 '^'. */
312 static int flag_preserve_paths
= 0;
314 /* Output the number of times a branch was taken as opposed to the percentage
315 of times it was taken. */
317 static int flag_counts
= 0;
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 **));
350 argno
= process_args (argc
, argv
);
354 for (; argno
!= argc
; argno
++)
356 release_structures ();
358 process_file (argv
[argno
]);
365 fnotice (FILE *file
, const char *msgid
, ...)
369 va_start (ap
, msgid
);
370 vfprintf (file
, _(msgid
), ap
);
374 /* More 'friendly' abort that prints the line and file.
375 config.h can #define abort fancy_abort if you like that sort of thing. */
376 extern void fancy_abort
PARAMS ((void)) ATTRIBUTE_NORETURN
;
381 fnotice (stderr
, "Internal gcov abort.\n");
382 exit (FATAL_EXIT_CODE
);
385 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
386 otherwise the output of --help. */
389 print_usage (error_p
)
392 FILE *file
= error_p
? stderr
: stdout
;
393 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
395 fnotice (file
, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
396 fnotice (file
, "Print code coverage information.\n\n");
397 fnotice (file
, " -h, --help Print this help, then exit\n");
398 fnotice (file
, " -v, --version Print version number, then exit\n");
399 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
400 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
401 fnotice (file
, " -c, --branch-counts Given counts of branches taken\n\
402 rather than percentages\n");
403 fnotice (file
, " -n, --no-output Do not create an output file\n");
404 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
406 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
407 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
408 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
409 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
410 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
415 /* Print version information and exit. */
421 unsigned version
= GCOV_VERSION
;
424 for (ix
= 4; ix
--; version
>>= 8)
426 fnotice (stdout
, "gcov %.4s (GCC %s)\n", v
, version_string
);
427 fnotice (stdout
, "Copyright (C) 2002 Free Software Foundation, Inc.\n");
429 "This is free software; see the source for copying conditions. There is NO\n\
430 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
431 exit (SUCCESS_EXIT_CODE
);
434 static const struct option options
[] =
436 { "help", no_argument
, NULL
, 'h' },
437 { "version", no_argument
, NULL
, 'v' },
438 { "all-blocks", no_argument
, NULL
, 'a' },
439 { "branch-probabilities", no_argument
, NULL
, 'b' },
440 { "branch-counts", no_argument
, NULL
, 'c' },
441 { "no-output", no_argument
, NULL
, 'n' },
442 { "long-file-names", no_argument
, NULL
, 'l' },
443 { "function-summaries", no_argument
, NULL
, 'f' },
444 { "preserve-paths", no_argument
, NULL
, 'p' },
445 { "object-directory", required_argument
, NULL
, 'o' },
446 { "object-file", required_argument
, NULL
, 'o' },
447 { "unconditional-branches", no_argument
, NULL
, 'u' },
451 /* Process args, return index to first non-arg. */
454 process_args (argc
, argv
)
460 while ((opt
= getopt_long (argc
, argv
, "abcfhlno:puv", options
, NULL
)) != -1)
474 flag_function_summary
= 1;
478 /* print_usage will exit. */
486 object_directory
= optarg
;
489 flag_preserve_paths
= 1;
492 flag_unconditional
= 1;
496 /* print_version will exit. */
499 /* print_usage will exit. */
506 /* Process a single source file. */
509 process_file (file_name
)
510 const char *file_name
;
515 create_file_names (file_name
);
516 if (read_graph_file ())
521 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
525 if (read_count_file ())
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
)
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
)
541 function_summary (&coverage
, "Function");
542 fnotice (stdout
, "\n");
546 for (src
= sources
; src
; src
= src
->next
)
548 accumulate_line_counts (src
);
549 function_summary (&src
->coverage
, "File");
552 char *gcov_file_name
= make_gcov_file_name (file_name
, src
->name
);
553 FILE *gcov_file
= fopen (gcov_file_name
, "w");
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
);
566 fnotice (stderr
, "%s:could not open output file `%s'\n",
567 src
->name
, gcov_file_name
);
568 free (gcov_file_name
);
570 fnotice (stdout
, "\n");
574 /* Release all memory used. */
577 release_structures ()
582 free (bbg_file_name
);
584 da_file_name
= bbg_file_name
= NULL
;
587 while ((src
= sources
))
595 while ((fn
= functions
))
600 functions
= fn
->next
;
601 for (ix
= fn
->num_blocks
, block
= fn
->blocks
; ix
--; block
++)
605 for (arc
= block
->succ
; arc
; arc
= arc_n
)
607 arc_n
= arc
->succ_next
;
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. */
625 create_file_names (file_name
)
626 const char *file_name
;
630 int length
= strlen (file_name
);
633 if (object_directory
&& object_directory
[0])
637 length
+= strlen (object_directory
) + 2;
638 name
= xmalloc (length
);
641 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
642 strcat (name
, object_directory
);
643 if (base
&& name
[strlen (name
) - 1] != '/')
648 name
= xmalloc (length
+ 1);
655 /* Append source file name */
656 cptr
= strrchr (file_name
, '/');
657 strcat (name
, cptr
? cptr
+ 1 : file_name
);
660 /* Remove the extension. */
661 cptr
= strrchr (name
, '.');
665 length
= strlen (name
);
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
);
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
);
678 /* Find or create a source file structure for FILE_NAME. Copies
679 FILE_NAME on creation */
682 find_source (file_name
)
683 const char *file_name
;
688 file_name
= "<unknown>";
690 for (src
= sources
; src
; src
= src
->next
)
691 if (!strcmp (file_name
, src
->name
))
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;
704 /* Read the graph file. Return nonzero on fatal error. */
710 unsigned current_tag
= 0;
711 struct function_info
*fn
= NULL
;
712 source_t
*src
= NULL
;
716 if (!gcov_open (bbg_file_name
, 1))
718 fnotice (stderr
, "%s:cannot open graph file\n", bbg_file_name
);
721 bbg_file_time
= gcov_time ();
722 if (gcov_read_unsigned () != GCOV_GRAPH_MAGIC
)
724 fnotice (stderr
, "%s:not a gcov graph file\n", bbg_file_name
);
729 version
= gcov_read_unsigned ();
730 if (version
!= GCOV_VERSION
)
733 unsigned required
= GCOV_VERSION
;
735 for (ix
= 4; ix
--; required
>>= 8, version
>>= 8)
740 fnotice (stderr
, "%s:version `%.4s', prefer `%.4s'\n",
741 bbg_file_name
, v
, e
);
744 while ((tag
= gcov_read_unsigned ()))
746 unsigned length
= gcov_read_unsigned ();
747 gcov_position_t base
= gcov_position ();
749 if (tag
== GCOV_TAG_FUNCTION
)
752 unsigned ident
, checksum
, lineno
;
754 function_t
*probe
, *prev
;
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 ();
762 fn
= (function_t
*)xcalloc (1, sizeof (function_t
));
763 fn
->name
= function_name
;
765 fn
->checksum
= checksum
;
769 fn
->next
= functions
;
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
)
782 fn
->line_next
= probe
;
784 prev
->line_next
= fn
;
788 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
791 fnotice (stderr
, "%s:already seen blocks for `%s'\n",
792 bbg_file_name
, fn
->name
);
795 unsigned ix
, num_blocks
= length
/ 4;
796 fn
->num_blocks
= num_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 ();
804 else if (fn
&& tag
== GCOV_TAG_ARCS
)
806 unsigned src
= gcov_read_unsigned ();
807 unsigned num_dests
= (length
- 4) / 8;
809 if (src
>= fn
->num_blocks
|| fn
->blocks
[src
].succ
)
814 struct arc_info
*arc
;
815 unsigned dest
= gcov_read_unsigned ();
816 unsigned flags
= gcov_read_unsigned ();
818 if (dest
>= fn
->num_blocks
)
820 arc
= (arc_t
*) xcalloc (1, sizeof (arc_t
));
822 arc
->dst
= &fn
->blocks
[dest
];
823 arc
->src
= &fn
->blocks
[src
];
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
);
831 arc
->succ_next
= fn
->blocks
[src
].succ
;
832 fn
->blocks
[src
].succ
= arc
;
833 fn
->blocks
[src
].num_succ
++;
835 arc
->pred_next
= fn
->blocks
[dest
].pred
;
836 fn
->blocks
[dest
].pred
= arc
;
837 fn
->blocks
[dest
].num_pred
++;
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;
850 /* Non-local return from a callee of this
851 function. The destination block is a catch or
853 arc
->is_nonlocal_return
= 1;
854 fn
->blocks
[dest
].is_nonlocal_return
= 1;
862 else if (fn
&& tag
== GCOV_TAG_LINES
)
864 unsigned blockno
= gcov_read_unsigned ();
866 = (unsigned *)xcalloc ((length
- 4) / 4, sizeof (unsigned));
868 if (blockno
>= fn
->num_blocks
|| fn
->blocks
[blockno
].u
.line
.encoding
)
873 unsigned lineno
= gcov_read_unsigned ();
880 line_nos
[ix
++] = src
->index
;
882 line_nos
[ix
++] = lineno
;
883 if (lineno
>= src
->num_lines
)
884 src
->num_lines
= lineno
+ 1;
888 const char *file_name
= gcov_read_string ();
892 src
= find_source (file_name
);
895 line_nos
[ix
++] = src
->index
;
899 fn
->blocks
[blockno
].u
.line
.encoding
= line_nos
;
900 fn
->blocks
[blockno
].u
.line
.num
= ix
;
902 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
907 gcov_sync (base
, length
);
908 if (gcov_is_error ())
914 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
920 /* We built everything backwards, so nreverse them all */
922 /* Reverse sources. Not strictly necessary, but we'll then process
923 them in the 'expected' order. */
925 source_t
*src
, *src_p
, *src_n
;
927 for (src_p
= NULL
, src
= sources
; src
; src_p
= src
, src
= src_n
)
935 /* Reverse functions. */
937 function_t
*fn
, *fn_p
, *fn_n
;
939 for (fn_p
= NULL
, fn
= functions
; fn
; fn_p
= fn
, fn
= fn_n
)
946 /* Reverse the arcs */
947 for (ix
= fn
->num_blocks
; ix
--;)
949 arc_t
*arc
, *arc_p
, *arc_n
;
951 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
952 arc_p
= arc
, arc
= arc_n
)
954 arc_n
= arc
->succ_next
;
955 arc
->succ_next
= arc_p
;
957 fn
->blocks
[ix
].succ
= arc_p
;
959 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
960 arc_p
= arc
, arc
= arc_n
)
962 arc_n
= arc
->pred_next
;
963 arc
->pred_next
= arc_p
;
965 fn
->blocks
[ix
].pred
= arc_p
;
973 /* Reads profiles from the count file and attach to each
974 function. Return nonzero if fatal error. */
982 function_t
*fn
= NULL
;
985 if (!gcov_open (da_file_name
, 1))
987 fnotice (stderr
, "%s:cannot open data file\n", da_file_name
);
990 if (gcov_read_unsigned () != GCOV_DATA_MAGIC
)
992 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
997 version
= gcov_read_unsigned ();
998 if (version
!= GCOV_VERSION
)
1001 unsigned desired
= GCOV_VERSION
;
1003 for (ix
= 4; ix
--; desired
>>= 8, version
>>= 8)
1008 fnotice (stderr
, "%s:version `%.4s', prefer version `%.4s'\n",
1009 da_file_name
, v
, e
);
1012 while ((tag
= gcov_read_unsigned ()))
1014 unsigned length
= gcov_read_unsigned ();
1015 unsigned long base
= gcov_position ();
1017 if (tag
== GCOV_TAG_OBJECT_SUMMARY
)
1018 gcov_read_summary (&object_summary
);
1019 else if (tag
== GCOV_TAG_PROGRAM_SUMMARY
)
1021 else if (tag
== GCOV_TAG_FUNCTION
)
1023 unsigned ident
= gcov_read_unsigned ();
1024 struct function_info
*fn_n
= functions
;
1026 for (fn
= fn
? fn
->next
: NULL
; ; fn
= fn
->next
)
1030 else if ((fn
= fn_n
))
1034 fnotice (stderr
, "%s:unknown function `%u'\n",
1035 da_file_name
, ident
);
1038 if (fn
->ident
== ident
)
1044 else if (gcov_read_unsigned () != fn
->checksum
)
1047 fnotice (stderr
, "%s:profile mismatch for `%s'\n",
1048 da_file_name
, fn
->name
);
1052 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
1054 if (length
!= 8 * fn
->num_counts
)
1059 = (gcov_type
*)xcalloc (fn
->num_counts
, sizeof (gcov_type
));
1061 for (ix
= 0; ix
!= fn
->num_counts
; ix
++)
1062 fn
->counts
[ix
] += gcov_read_counter ();
1064 gcov_sync (base
, length
);
1065 if ((error
= gcov_is_error ()))
1069 if (!gcov_is_eof ())
1071 fnotice (stderr
, error
< 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1080 /* Solve the flow graph. Propagate counts from the instrumented arcs
1081 to the blocks and the uninstrumented arcs. */
1084 solve_flow_graph (fn
)
1089 gcov_type
*count_ptr
= fn
->counts
;
1091 block_t
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
1092 block_t
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
1094 if (fn
->num_blocks
< 2)
1095 fnotice (stderr
, "%s:`%s' lacks entry and/or exit blocks\n",
1096 bbg_file_name
, fn
->name
);
1099 if (fn
->blocks
[0].num_pred
)
1100 fnotice (stderr
, "%s:`%s' has arcs to entry block\n",
1101 bbg_file_name
, fn
->name
);
1103 /* We can't deduce the entry block counts from the lack of
1105 fn
->blocks
[0].num_pred
= ~(unsigned)0;
1107 if (fn
->blocks
[fn
->num_blocks
- 1].num_succ
)
1108 fnotice (stderr
, "%s:`%s' has arcs from exit block\n",
1109 bbg_file_name
, fn
->name
);
1111 /* Likewise, we can't deduce exit block counts from the lack
1112 of its successors. */
1113 fn
->blocks
[fn
->num_blocks
- 1].num_succ
= ~(unsigned)0;
1116 /* Propagate the measured counts, this must be done in the same
1117 order as the code in profile.c */
1118 for (ix
= 0, blk
= fn
->blocks
; ix
!= fn
->num_blocks
; ix
++, blk
++)
1120 block_t
const *prev_dst
= NULL
;
1121 int out_of_order
= 0;
1122 int non_fake_succ
= 0;
1124 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1132 arc
->count
= *count_ptr
++;
1133 arc
->count_valid
= 1;
1135 arc
->dst
->num_pred
--;
1137 if (prev_dst
&& prev_dst
> arc
->dst
)
1139 prev_dst
= arc
->dst
;
1141 if (non_fake_succ
== 1)
1143 /* If there is only one non-fake exit, it is an
1144 unconditional branch. */
1145 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1148 arc
->is_unconditional
= 1;
1149 /* If this block is instrumenting a call, it might be
1150 an artifical block. It is not artificial if it has
1151 a non-fallthrough exit, or the destination of this
1152 arc has more than one entry. Mark the destination
1153 block as a return site, if none of those conditions
1155 if (blk
->is_call_site
&& arc
->fall_through
1156 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
1157 arc
->dst
->is_call_return
= 1;
1161 /* Sort the successor arcs into ascending dst order. profile.c
1162 normally produces arcs in the right order, but sometimes with
1163 one or two out of order. We're not using a particularly
1167 arc_t
*start
= blk
->succ
;
1168 unsigned changes
= 1;
1172 arc_t
*arc
, *arc_p
, *arc_n
;
1175 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
1177 if (arc
->dst
> arc_n
->dst
)
1181 arc_p
->succ_next
= arc_n
;
1184 arc
->succ_next
= arc_n
->succ_next
;
1185 arc_n
->succ_next
= arc
;
1198 /* Place it on the invalid chain, it will be ignored if that's
1200 blk
->invalid_chain
= 1;
1201 blk
->chain
= invalid_blocks
;
1202 invalid_blocks
= blk
;
1205 while (invalid_blocks
|| valid_blocks
)
1207 while ((blk
= invalid_blocks
))
1209 gcov_type total
= 0;
1212 invalid_blocks
= blk
->chain
;
1213 blk
->invalid_chain
= 0;
1215 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1216 total
+= arc
->count
;
1217 else if (!blk
->num_pred
)
1218 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1219 total
+= arc
->count
;
1224 blk
->count_valid
= 1;
1225 blk
->chain
= valid_blocks
;
1226 blk
->valid_chain
= 1;
1229 while ((blk
= valid_blocks
))
1232 arc_t
*arc
, *inv_arc
;
1234 valid_blocks
= blk
->chain
;
1235 blk
->valid_chain
= 0;
1236 if (blk
->num_succ
== 1)
1242 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1244 total
-= arc
->count
;
1245 if (!arc
->count_valid
)
1249 inv_arc
->count_valid
= 1;
1250 inv_arc
->count
= total
;
1253 if (dst
->count_valid
)
1255 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
1257 dst
->chain
= valid_blocks
;
1258 dst
->valid_chain
= 1;
1264 if (!dst
->num_pred
&& !dst
->invalid_chain
)
1266 dst
->chain
= invalid_blocks
;
1267 dst
->invalid_chain
= 1;
1268 invalid_blocks
= dst
;
1272 if (blk
->num_pred
== 1)
1278 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1280 total
-= arc
->count
;
1281 if (!arc
->count_valid
)
1285 inv_arc
->count_valid
= 1;
1286 inv_arc
->count
= total
;
1289 if (src
->count_valid
)
1291 if (src
->num_succ
== 1 && !src
->valid_chain
)
1293 src
->chain
= valid_blocks
;
1294 src
->valid_chain
= 1;
1300 if (!src
->num_succ
&& !src
->invalid_chain
)
1302 src
->chain
= invalid_blocks
;
1303 src
->invalid_chain
= 1;
1304 invalid_blocks
= src
;
1311 /* If the graph has been correctly solved, every block will have a
1313 for (ix
= 0; ix
< fn
->num_blocks
; ix
++)
1314 if (!fn
->blocks
[ix
].count_valid
)
1316 fnotice (stderr
, "%s:graph is unsolvable for `%s'\n",
1317 bbg_file_name
, fn
->name
);
1324 /* Increment totals in COVERAGE according to arc ARC. */
1327 add_branch_counts (coverage
, arc
)
1328 coverage_t
*coverage
;
1331 if (arc
->is_call_non_return
)
1334 if (arc
->src
->count
)
1335 coverage
->calls_executed
++;
1337 else if (!arc
->is_unconditional
)
1339 coverage
->branches
++;
1340 if (arc
->src
->count
)
1341 coverage
->branches_executed
++;
1343 coverage
->branches_taken
++;
1347 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1348 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1349 If DP is zero, no decimal point is printed. Only print 100% when
1350 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1351 format TOP. Return pointer to a static string. */
1354 format_gcov (top
, bottom
, dp
)
1355 gcov_type top
, bottom
;
1358 static char buffer
[20];
1362 float ratio
= bottom
? (float)top
/ bottom
: 0;
1364 unsigned limit
= 100;
1367 for (ix
= dp
; ix
--; )
1370 percent
= (unsigned) (ratio
* limit
+ (float)0.5);
1371 if (percent
<= 0 && top
)
1373 else if (percent
>= limit
&& top
!= bottom
)
1374 percent
= limit
- 1;
1375 ix
= sprintf (buffer
, "%.*u%%", dp
+ 1, percent
);
1381 buffer
[ix
+1] = buffer
[ix
];
1385 buffer
[ix
+ 1] = '.';
1389 sprintf (buffer
, HOST_WIDEST_INT_PRINT_DEC
, (HOST_WIDEST_INT
)top
);
1395 /* Output summary info for a function. */
1398 function_summary (coverage
, title
)
1399 const coverage_t
*coverage
;
1402 fnotice (stdout
, "%s `%s'\n", title
, coverage
->name
);
1404 if (coverage
->lines
)
1405 fnotice (stdout
, "Lines executed:%s of %d\n",
1406 format_gcov (coverage
->lines_executed
, coverage
->lines
, 2),
1409 fnotice (stdout
, "No executable lines");
1413 if (coverage
->branches
)
1415 fnotice (stdout
, "Branches executed:%s of %d\n",
1416 format_gcov (coverage
->branches_executed
,
1417 coverage
->branches
, 2),
1418 coverage
->branches
);
1419 fnotice (stdout
, "Taken at least once:%s of %d\n",
1420 format_gcov (coverage
->branches_taken
,
1421 coverage
->branches
, 2),
1422 coverage
->branches
);
1425 fnotice (stdout
, "No branches\n");
1426 if (coverage
->calls
)
1427 fnotice (stdout
, "Calls executed:%s of %d\n",
1428 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
1431 fnotice (stdout
, "No calls\n");
1435 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1436 affect name generation. With preserve_paths we create a filename
1437 from all path components of the source file, replacing '/' with
1438 '#', without it we simply take the basename component. With
1439 long_output_names we prepend the processed name of the input file
1440 to each output name (except when the current source file is the
1441 input file, so you don't get a double concatenation). The two
1442 components are separated by '##'. Also '.' filename components are
1443 removed and '..' components are renamed to '^'. */
1446 make_gcov_file_name (input_name
, src_name
)
1447 const char *input_name
;
1448 const char *src_name
;
1451 char *name
= xmalloc (strlen (src_name
) + strlen (input_name
) + 10);
1454 if (flag_long_names
&& strcmp (src_name
, input_name
))
1456 /* Generate the input filename part. */
1457 cptr
= flag_preserve_paths
? NULL
: strrchr (input_name
, '/');
1458 strcat (name
, cptr
? cptr
+ 1 : input_name
);
1459 strcat (name
, "##");
1462 /* Generate the source filename part. */
1463 cptr
= flag_preserve_paths
? NULL
: strrchr (src_name
, '/');
1464 strcat (name
, cptr
? cptr
+ 1 : src_name
);
1466 if (flag_preserve_paths
)
1468 /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1471 for (cptr
= name
; (cptr
= strchr ((prev
= cptr
), '/'));)
1475 if (prev
+ 1 == cptr
&& prev
[0] == '.')
1480 else if (prev
+ 2 == cptr
&& prev
[0] == '.' && prev
[1] == '.')
1492 prev
[0] = prev
[shift
];
1498 strcat (name
, ".gcov");
1502 /* Scan through the bb_data for each line in the block, increment
1503 the line number execution count indicated by the execution count of
1504 the appropriate basic block. */
1507 add_line_counts (coverage
, fn
)
1508 coverage_t
*coverage
;
1512 line_t
*line
= NULL
; /* this is propagated from one iteration to the
1515 /* Scan each basic block. */
1516 for (ix
= 0; ix
!= fn
->num_blocks
; ix
++)
1518 block_t
*block
= &fn
->blocks
[ix
];
1520 const source_t
*src
= NULL
;
1523 if (block
->count
&& ix
&& ix
+ 1 != fn
->num_blocks
)
1524 fn
->blocks_executed
++;
1525 for (jx
= 0, encoding
= block
->u
.line
.encoding
;
1526 jx
!= block
->u
.line
.num
; jx
++, encoding
++)
1529 unsigned src_n
= *++encoding
;
1531 for (src
= sources
; src
->index
!= src_n
; src
= src
->next
)
1537 line
= &src
->lines
[*encoding
];
1543 if (!line
->count
&& block
->count
)
1544 coverage
->lines_executed
++;
1547 line
->count
+= block
->count
;
1549 free (block
->u
.line
.encoding
);
1550 block
->u
.cycle
.arc
= NULL
;
1551 block
->u
.cycle
.ident
= ~0U;
1553 if (!ix
|| ix
+ 1 == fn
->num_blocks
)
1554 /* Entry or exit block */;
1555 else if (flag_all_blocks
)
1557 line_t
*block_line
= line
? line
: &fn
->src
->lines
[fn
->line
];
1559 block
->chain
= block_line
->u
.blocks
;
1560 block_line
->u
.blocks
= block
;
1562 else if (flag_branches
)
1566 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1568 arc
->line_next
= line
->u
.branches
;
1569 line
->u
.branches
= arc
;
1570 if (coverage
&& !arc
->is_unconditional
)
1571 add_branch_counts (coverage
, arc
);
1576 fnotice (stderr
, "%s:no lines for `%s'\n", bbg_file_name
, fn
->name
);
1579 /* Accumulate the line counts of a file. */
1582 accumulate_line_counts (src
)
1586 function_t
*fn
, *fn_p
, *fn_n
;
1589 /* Reverse the function order. */
1590 for (fn
= src
->functions
, fn_p
= NULL
; fn
;
1591 fn_p
= fn
, fn
= fn_n
)
1593 fn_n
= fn
->line_next
;
1594 fn
->line_next
= fn_p
;
1596 src
->functions
= fn_p
;
1598 for (ix
= src
->num_lines
, line
= src
->lines
; ix
--; line
++)
1600 if (!flag_all_blocks
)
1602 arc_t
*arc
, *arc_p
, *arc_n
;
1604 /* Total and reverse the branch information. */
1605 for (arc
= line
->u
.branches
, arc_p
= NULL
; arc
;
1606 arc_p
= arc
, arc
= arc_n
)
1608 arc_n
= arc
->line_next
;
1609 arc
->line_next
= arc_p
;
1611 add_branch_counts (&src
->coverage
, arc
);
1613 line
->u
.branches
= arc_p
;
1615 else if (line
->u
.blocks
)
1617 /* The user expects the line count to be the number of times
1618 a line has been executed. Simply summing the block count
1619 will give an artificially high number. The Right Thing
1620 is to sum the entry counts to the graph of blocks on this
1621 line, then find the elementary cycles of the local graph
1622 and add the transition counts of those cycles. */
1623 block_t
*block
, *block_p
, *block_n
;
1624 gcov_type count
= 0;
1626 /* Reverse the block information */
1627 for (block
= line
->u
.blocks
, block_p
= NULL
; block
;
1628 block_p
= block
, block
= block_n
)
1630 block_n
= block
->chain
;
1631 block
->chain
= block_p
;
1632 block
->u
.cycle
.ident
= ix
;
1634 line
->u
.blocks
= block_p
;
1636 /* Sum the entry arcs. */
1637 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
1641 for (arc
= block
->pred
; arc
; arc
= arc
->pred_next
)
1643 if (arc
->src
->u
.cycle
.ident
!= ix
)
1644 count
+= arc
->count
;
1646 add_branch_counts (&src
->coverage
, arc
);
1650 /* Find the loops. This uses the algorithm described in
1651 Tiernan 'An Efficient Search Algorithm to Find the
1652 Elementary Circuits of a Graph', CACM Dec 1970. We hold
1653 the P array by having each block point to the arc that
1654 connects to the previous block. The H array is implicitly
1655 held because of the arc ordering, and the block's
1656 previous arc pointer.
1658 Although the algorithm is O(N^3) for highly connected
1659 graphs, at worst we'll have O(N^2), as most blocks have
1660 only one or two exits. Most graphs will be small.
1662 For each loop we find, locate the arc with the smallest
1663 transition count, and add that to the cumulative
1664 count. Remove the arc from consideration. */
1665 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
1667 block_t
*head
= block
;
1675 block_t
*dst
= arc
->dst
;
1676 if (/* Already used that arc. */
1678 /* Not to same graph, or before first vertex. */
1679 || dst
->u
.cycle
.ident
!= ix
1680 /* Already in path. */
1681 || dst
->u
.cycle
.arc
)
1683 arc
= arc
->succ_next
;
1689 /* Found a closing arc. */
1690 gcov_type cycle_count
= arc
->count
;
1691 arc_t
*cycle_arc
= arc
;
1694 /* Locate the smallest arc count of the loop. */
1695 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
1696 dst
= probe_arc
->src
)
1697 if (cycle_count
> probe_arc
->count
)
1699 cycle_count
= probe_arc
->count
;
1700 cycle_arc
= probe_arc
;
1703 count
+= cycle_count
;
1704 cycle_arc
->cycle
= 1;
1705 /* Unwind to the cyclic arc. */
1706 while (head
!= cycle_arc
->src
)
1708 arc
= head
->u
.cycle
.arc
;
1712 arc
= arc
->succ_next
;
1716 /* Add new block to chain. */
1717 dst
->u
.cycle
.arc
= arc
;
1721 /* We could not add another vertex to the path. Remove
1722 the last vertex from the list. */
1723 arc
= head
->u
.cycle
.arc
;
1726 /* It was not the first vertex. Move onto next arc. */
1727 head
->u
.cycle
.arc
= NULL
;
1729 arc
= arc
->succ_next
;
1730 goto current_vertex
;
1732 /* Mark this block as unusable. */
1733 block
->u
.cycle
.ident
= ~0U;
1736 line
->count
= count
;
1741 src
->coverage
.lines
++;
1743 src
->coverage
.lines_executed
++;
1748 /* Ouput information about ARC number IX. Returns non-zero if
1749 anything is output. */
1752 output_branch_count (gcov_file
, ix
, arc
)
1758 if (arc
->is_call_non_return
)
1760 if (arc
->src
->count
)
1762 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
1763 format_gcov (arc
->src
->count
- arc
->count
,
1764 arc
->src
->count
, -flag_counts
));
1767 fnotice (gcov_file
, "call %2d never executed\n", ix
);
1769 else if (!arc
->is_unconditional
)
1771 if (arc
->src
->count
)
1772 fnotice (gcov_file
, "branch %2d taken %s%s\n", ix
,
1773 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
1774 arc
->fall_through
? " (fallthrough)" : "");
1776 fnotice (gcov_file
, "branch %2d never executed\n", ix
);
1778 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
1780 if (arc
->src
->count
)
1781 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
1782 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
1784 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
1792 /* Read in the source file one line at a time, and output that line to
1793 the gcov file preceded by its execution count and other
1797 output_lines (gcov_file
, src
)
1799 const source_t
*src
;
1802 unsigned line_num
; /* current line number. */
1803 const line_t
*line
; /* current line info ptr. */
1804 char string
[STRING_SIZE
]; /* line buffer. */
1805 char const *retval
= ""; /* status of source file reading. */
1806 function_t
*fn
= src
->functions
;
1808 fprintf (gcov_file
, "%9s:%5d:Source:%s\n", "-", 0, src
->name
);
1809 fprintf (gcov_file
, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name
);
1810 fprintf (gcov_file
, "%9s:%5d:Data:%s\n", "-", 0, da_file_name
);
1811 fprintf (gcov_file
, "%9s:%5d:Runs:%u\n", "-", 0,
1812 object_summary
.ctrs
[GCOV_COUNTER_ARCS
].runs
);
1813 fprintf (gcov_file
, "%9s:%5d:Programs:%u\n", "-", 0, program_count
);
1815 source_file
= fopen (src
->name
, "r");
1818 fnotice (stderr
, "%s:cannot open source file\n", src
->name
);
1825 if (!fstat (fileno (source_file
), &status
)
1826 && status
.st_mtime
> bbg_file_time
)
1828 fnotice (stderr
, "%s:source file is newer than graph file `%s'\n",
1829 src
->name
, bbg_file_name
);
1830 fprintf (gcov_file
, "%9s:%5d:Source is newer than graph\n",
1835 for (line_num
= 1, line
= &src
->lines
[line_num
];
1836 line_num
< src
->num_lines
; line_num
++, line
++)
1838 for (; fn
&& fn
->line
== line_num
; fn
= fn
->line_next
)
1840 arc_t
*arc
= fn
->blocks
[fn
->num_blocks
- 1].pred
;
1841 gcov_type return_count
= fn
->blocks
[fn
->num_blocks
- 1].count
;
1843 for (; arc
; arc
= arc
->pred_next
)
1845 return_count
-= arc
->count
;
1847 fprintf (gcov_file
, "function %s", fn
->name
);
1848 fprintf (gcov_file
, " called %s",
1849 format_gcov (fn
->blocks
[0].count
, 0, -1));
1850 fprintf (gcov_file
, " returned %s",
1851 format_gcov (return_count
, fn
->blocks
[0].count
, 0));
1852 fprintf (gcov_file
, " blocks executed %s",
1853 format_gcov (fn
->blocks_executed
, fn
->num_blocks
- 2, 0));
1854 fprintf (gcov_file
, "\n");
1857 /* For lines which don't exist in the .bb file, print '-' before
1858 the source line. For lines which exist but were never
1859 executed, print '#####' before the source line. Otherwise,
1860 print the execution count before the source line. There are
1861 16 spaces of indentation added before the source line so that
1862 tabs won't be messed up. */
1863 fprintf (gcov_file
, "%9s:%5u:",
1864 !line
->exists
? "-" : !line
->count
? "#####"
1865 : format_gcov (line
->count
, 0, -1), line_num
);
1869 /* Copy source line. */
1872 retval
= fgets (string
, STRING_SIZE
, source_file
);
1875 fputs (retval
, gcov_file
);
1877 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n');
1880 fputs ("/*EOF*/\n", gcov_file
);
1882 if (flag_all_blocks
)
1888 for (ix
= jx
= 0, block
= line
->u
.blocks
; block
;
1889 block
= block
->chain
)
1891 if (!block
->is_call_return
)
1892 fprintf (gcov_file
, "%9s:%5u-block %2d\n",
1893 !line
->exists
? "-" : !block
->count
? "$$$$$"
1894 : format_gcov (block
->count
, 0, -1),
1897 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1898 jx
+= output_branch_count (gcov_file
, jx
, arc
);
1901 else if (flag_branches
)
1906 for (ix
= 0, arc
= line
->u
.branches
; arc
; arc
= arc
->line_next
)
1907 ix
+= output_branch_count (gcov_file
, ix
, arc
);
1911 /* Handle all remaining source lines. There may be lines after the
1912 last line of code. */
1915 for (; (retval
= fgets (string
, STRING_SIZE
, source_file
)); line_num
++)
1917 fprintf (gcov_file
, "%9s:%5u:%s", "-", line_num
, retval
);
1919 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n')
1921 retval
= fgets (string
, STRING_SIZE
, source_file
);
1924 fputs (retval
, gcov_file
);
1930 fclose (source_file
);