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 /* Stamp of the bbg file */
273 static unsigned bbg_stamp
;
275 /* Name and file pointer of the input file for the arc count data. */
277 static char *da_file_name
;
279 /* Output branch probabilities. */
281 static int flag_branches
= 0;
283 /* Show unconditional branches too. */
284 static int flag_unconditional
= 0;
286 /* Output a gcov file if this is true. This is on by default, and can
287 be turned off by the -n option. */
289 static int flag_gcov_file
= 1;
291 /* For included files, make the gcov output file name include the name
292 of the input source file. For example, if x.h is included in a.c,
293 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
295 static int flag_long_names
= 0;
297 /* Output count information for every basic block, not merely those
298 that contain line number information. */
300 static int flag_all_blocks
= 0;
302 /* Output summary info for each function. */
304 static int flag_function_summary
= 0;
306 /* Object directory file prefix. This is the directory/file where the
307 graph and data files are looked for, if nonzero. */
309 static char *object_directory
= 0;
311 /* Preserve all pathname components. Needed when object files and
312 source files are in subdirectories. '/' is mangled as '#', '.' is
313 elided and '..' mangled to '^'. */
315 static int flag_preserve_paths
= 0;
317 /* Output the number of times a branch was taken as opposed to the percentage
318 of times it was taken. */
320 static int flag_counts
= 0;
322 /* Forward declarations. */
323 static void fnotice
PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2
;
324 static int process_args
PARAMS ((int, char **));
325 static void print_usage
PARAMS ((int)) ATTRIBUTE_NORETURN
;
326 static void print_version
PARAMS ((void)) ATTRIBUTE_NORETURN
;
327 static void process_file
PARAMS ((const char *));
328 static void create_file_names
PARAMS ((const char *));
329 static source_t
*find_source
PARAMS ((const char *));
330 static int read_graph_file
PARAMS ((void));
331 static int read_count_file
PARAMS ((void));
332 static void solve_flow_graph
PARAMS ((function_t
*));
333 static void add_branch_counts
PARAMS ((coverage_t
*, const arc_t
*));
334 static void add_line_counts
PARAMS ((coverage_t
*, function_t
*));
335 static void function_summary
PARAMS ((const coverage_t
*, const char *));
336 static const char *format_gcov
PARAMS ((gcov_type
, gcov_type
, int));
337 static void accumulate_line_counts
PARAMS ((source_t
*));
338 static int output_branch_count
PARAMS ((FILE *, int, const arc_t
*));
339 static void output_lines
PARAMS ((FILE *, const source_t
*));
340 static char *make_gcov_file_name
PARAMS ((const char *, const char *));
341 static void release_structures
PARAMS ((void));
342 extern int main
PARAMS ((int, char **));
353 argno
= process_args (argc
, argv
);
357 for (; argno
!= argc
; argno
++)
359 release_structures ();
361 process_file (argv
[argno
]);
368 fnotice (FILE *file
, const char *msgid
, ...)
372 va_start (ap
, msgid
);
373 vfprintf (file
, _(msgid
), ap
);
377 /* More 'friendly' abort that prints the line and file.
378 config.h can #define abort fancy_abort if you like that sort of thing. */
379 extern void fancy_abort
PARAMS ((void)) ATTRIBUTE_NORETURN
;
384 fnotice (stderr
, "Internal gcov abort.\n");
385 exit (FATAL_EXIT_CODE
);
388 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
389 otherwise the output of --help. */
392 print_usage (error_p
)
395 FILE *file
= error_p
? stderr
: stdout
;
396 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
398 fnotice (file
, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
399 fnotice (file
, "Print code coverage information.\n\n");
400 fnotice (file
, " -h, --help Print this help, then exit\n");
401 fnotice (file
, " -v, --version Print version number, then exit\n");
402 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
403 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
404 fnotice (file
, " -c, --branch-counts Given counts of branches taken\n\
405 rather than percentages\n");
406 fnotice (file
, " -n, --no-output Do not create an output file\n");
407 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
409 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
410 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
411 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
412 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
413 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
418 /* Print version information and exit. */
424 unsigned version
= GCOV_VERSION
;
427 for (ix
= 4; ix
--; version
>>= 8)
429 fnotice (stdout
, "gcov %.4s (GCC %s)\n", v
, version_string
);
430 fnotice (stdout
, "Copyright (C) 2002 Free Software Foundation, Inc.\n");
432 "This is free software; see the source for copying conditions. There is NO\n\
433 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
434 exit (SUCCESS_EXIT_CODE
);
437 static const struct option options
[] =
439 { "help", no_argument
, NULL
, 'h' },
440 { "version", no_argument
, NULL
, 'v' },
441 { "all-blocks", no_argument
, NULL
, 'a' },
442 { "branch-probabilities", no_argument
, NULL
, 'b' },
443 { "branch-counts", no_argument
, NULL
, 'c' },
444 { "no-output", no_argument
, NULL
, 'n' },
445 { "long-file-names", no_argument
, NULL
, 'l' },
446 { "function-summaries", no_argument
, NULL
, 'f' },
447 { "preserve-paths", no_argument
, NULL
, 'p' },
448 { "object-directory", required_argument
, NULL
, 'o' },
449 { "object-file", required_argument
, NULL
, 'o' },
450 { "unconditional-branches", no_argument
, NULL
, 'u' },
454 /* Process args, return index to first non-arg. */
457 process_args (argc
, argv
)
463 while ((opt
= getopt_long (argc
, argv
, "abcfhlno:puv", options
, NULL
)) != -1)
477 flag_function_summary
= 1;
481 /* print_usage will exit. */
489 object_directory
= optarg
;
492 flag_preserve_paths
= 1;
495 flag_unconditional
= 1;
499 /* print_version will exit. */
502 /* print_usage will exit. */
509 /* Process a single source file. */
512 process_file (file_name
)
513 const char *file_name
;
518 create_file_names (file_name
);
519 if (read_graph_file ())
524 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
528 if (read_count_file ())
531 for (fn
= functions
; fn
; fn
= fn
->next
)
532 solve_flow_graph (fn
);
533 for (src
= sources
; src
; src
= src
->next
)
534 src
->lines
= (line_t
*) xcalloc (src
->num_lines
, sizeof (line_t
));
535 for (fn
= functions
; fn
; fn
= fn
->next
)
539 memset (&coverage
, 0, sizeof (coverage
));
540 coverage
.name
= fn
->name
;
541 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
542 if (flag_function_summary
)
544 function_summary (&coverage
, "Function");
545 fnotice (stdout
, "\n");
549 for (src
= sources
; src
; src
= src
->next
)
551 accumulate_line_counts (src
);
552 function_summary (&src
->coverage
, "File");
555 char *gcov_file_name
= make_gcov_file_name (file_name
, src
->name
);
556 FILE *gcov_file
= fopen (gcov_file_name
, "w");
560 fnotice (stdout
, "%s:creating `%s'\n",
561 src
->name
, gcov_file_name
);
562 output_lines (gcov_file
, src
);
563 if (ferror (gcov_file
))
564 fnotice (stderr
, "%s:error writing output file `%s'\n",
565 src
->name
, gcov_file_name
);
569 fnotice (stderr
, "%s:could not open output file `%s'\n",
570 src
->name
, gcov_file_name
);
571 free (gcov_file_name
);
573 fnotice (stdout
, "\n");
577 /* Release all memory used. */
580 release_structures ()
585 free (bbg_file_name
);
587 da_file_name
= bbg_file_name
= NULL
;
591 while ((src
= sources
))
599 while ((fn
= functions
))
604 functions
= fn
->next
;
605 for (ix
= fn
->num_blocks
, block
= fn
->blocks
; ix
--; block
++)
609 for (arc
= block
->succ
; arc
; arc
= arc_n
)
611 arc_n
= arc
->succ_next
;
620 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
621 is not specified, these are looked for in the current directory,
622 and named from the basename of the FILE_NAME sans extension. If
623 OBJECT_DIRECTORY is specified and is a directory, the files are in
624 that directory, but named from the basename of the FILE_NAME, sans
625 extension. Otherwise OBJECT_DIRECTORY is taken to be the name of
626 the object *file*, and the data files are named from that. */
629 create_file_names (file_name
)
630 const char *file_name
;
634 int length
= strlen (file_name
);
637 if (object_directory
&& object_directory
[0])
641 length
+= strlen (object_directory
) + 2;
642 name
= xmalloc (length
);
645 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
646 strcat (name
, object_directory
);
647 if (base
&& name
[strlen (name
) - 1] != '/')
652 name
= xmalloc (length
+ 1);
659 /* Append source file name. */
660 cptr
= strrchr (file_name
, '/');
661 strcat (name
, cptr
? cptr
+ 1 : file_name
);
664 /* Remove the extension. */
665 cptr
= strrchr (name
, '.');
669 length
= strlen (name
);
671 bbg_file_name
= xmalloc (length
+ strlen (GCOV_GRAPH_SUFFIX
) + 1);
672 strcpy (bbg_file_name
, name
);
673 strcpy (bbg_file_name
+ length
, GCOV_GRAPH_SUFFIX
);
675 da_file_name
= xmalloc (length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
676 strcpy (da_file_name
, name
);
677 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
682 /* Find or create a source file structure for FILE_NAME. Copies
683 FILE_NAME on creation */
686 find_source (file_name
)
687 const char *file_name
;
692 file_name
= "<unknown>";
694 for (src
= sources
; src
; src
= src
->next
)
695 if (!strcmp (file_name
, src
->name
))
698 src
= (source_t
*)xcalloc (1, sizeof (source_t
));
699 src
->name
= xstrdup (file_name
);
700 src
->coverage
.name
= src
->name
;
701 src
->index
= sources
? sources
->index
+ 1 : 1;
708 /* Read the graph file. Return nonzero on fatal error. */
714 unsigned current_tag
= 0;
715 struct function_info
*fn
= NULL
;
716 source_t
*src
= NULL
;
720 if (!gcov_open (bbg_file_name
, 1))
722 fnotice (stderr
, "%s:cannot open graph file\n", bbg_file_name
);
725 bbg_file_time
= gcov_time ();
726 if (gcov_read_unsigned () != GCOV_GRAPH_MAGIC
)
728 fnotice (stderr
, "%s:not a gcov graph file\n", bbg_file_name
);
733 version
= gcov_read_unsigned ();
734 if (version
!= GCOV_VERSION
)
737 unsigned required
= GCOV_VERSION
;
739 for (ix
= 4; ix
--; required
>>= 8, version
>>= 8)
744 fnotice (stderr
, "%s:version `%.4s', prefer `%.4s'\n",
745 bbg_file_name
, v
, e
);
747 bbg_stamp
= gcov_read_unsigned ();
749 while ((tag
= gcov_read_unsigned ()))
751 unsigned length
= gcov_read_unsigned ();
752 gcov_position_t base
= gcov_position ();
754 if (tag
== GCOV_TAG_FUNCTION
)
757 unsigned ident
, checksum
, lineno
;
759 function_t
*probe
, *prev
;
761 ident
= gcov_read_unsigned ();
762 checksum
= gcov_read_unsigned ();
763 function_name
= xstrdup (gcov_read_string ());
764 src
= find_source (gcov_read_string ());
765 lineno
= gcov_read_unsigned ();
767 fn
= (function_t
*)xcalloc (1, sizeof (function_t
));
768 fn
->name
= function_name
;
770 fn
->checksum
= checksum
;
774 fn
->next
= functions
;
778 if (lineno
>= src
->num_lines
)
779 src
->num_lines
= lineno
+ 1;
780 /* Now insert it into the source file's list of
781 functions. Normally functions will be encountered in
782 ascending order, so a simple scan is quick. */
783 for (probe
= src
->functions
, prev
= NULL
;
784 probe
&& probe
->line
> lineno
;
785 prev
= probe
, probe
= probe
->line_next
)
787 fn
->line_next
= probe
;
789 prev
->line_next
= fn
;
793 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
796 fnotice (stderr
, "%s:already seen blocks for `%s'\n",
797 bbg_file_name
, fn
->name
);
800 unsigned ix
, num_blocks
= length
/ 4;
801 fn
->num_blocks
= num_blocks
;
804 = (block_t
*)xcalloc (fn
->num_blocks
, sizeof (block_t
));
805 for (ix
= 0; ix
!= num_blocks
; ix
++)
806 fn
->blocks
[ix
].flags
= gcov_read_unsigned ();
809 else if (fn
&& tag
== GCOV_TAG_ARCS
)
811 unsigned src
= gcov_read_unsigned ();
812 unsigned num_dests
= (length
- 4) / 8;
814 if (src
>= fn
->num_blocks
|| fn
->blocks
[src
].succ
)
819 struct arc_info
*arc
;
820 unsigned dest
= gcov_read_unsigned ();
821 unsigned flags
= gcov_read_unsigned ();
823 if (dest
>= fn
->num_blocks
)
825 arc
= (arc_t
*) xcalloc (1, sizeof (arc_t
));
827 arc
->dst
= &fn
->blocks
[dest
];
828 arc
->src
= &fn
->blocks
[src
];
831 arc
->count_valid
= 0;
832 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
833 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
834 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
836 arc
->succ_next
= fn
->blocks
[src
].succ
;
837 fn
->blocks
[src
].succ
= arc
;
838 fn
->blocks
[src
].num_succ
++;
840 arc
->pred_next
= fn
->blocks
[dest
].pred
;
841 fn
->blocks
[dest
].pred
= arc
;
842 fn
->blocks
[dest
].num_pred
++;
848 /* Exceptional exit from this function, the
849 source block must be a call. */
850 fn
->blocks
[src
].is_call_site
= 1;
851 arc
->is_call_non_return
= 1;
855 /* Non-local return from a callee of this
856 function. The destination block is a catch or
858 arc
->is_nonlocal_return
= 1;
859 fn
->blocks
[dest
].is_nonlocal_return
= 1;
867 else if (fn
&& tag
== GCOV_TAG_LINES
)
869 unsigned blockno
= gcov_read_unsigned ();
871 = (unsigned *)xcalloc ((length
- 4) / 4, sizeof (unsigned));
873 if (blockno
>= fn
->num_blocks
|| fn
->blocks
[blockno
].u
.line
.encoding
)
878 unsigned lineno
= gcov_read_unsigned ();
885 line_nos
[ix
++] = src
->index
;
887 line_nos
[ix
++] = lineno
;
888 if (lineno
>= src
->num_lines
)
889 src
->num_lines
= lineno
+ 1;
893 const char *file_name
= gcov_read_string ();
897 src
= find_source (file_name
);
900 line_nos
[ix
++] = src
->index
;
904 fn
->blocks
[blockno
].u
.line
.encoding
= line_nos
;
905 fn
->blocks
[blockno
].u
.line
.num
= ix
;
907 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
912 gcov_sync (base
, length
);
913 if (gcov_is_error ())
919 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
925 /* We built everything backwards, so nreverse them all */
927 /* Reverse sources. Not strictly necessary, but we'll then process
928 them in the 'expected' order. */
930 source_t
*src
, *src_p
, *src_n
;
932 for (src_p
= NULL
, src
= sources
; src
; src_p
= src
, src
= src_n
)
940 /* Reverse functions. */
942 function_t
*fn
, *fn_p
, *fn_n
;
944 for (fn_p
= NULL
, fn
= functions
; fn
; fn_p
= fn
, fn
= fn_n
)
951 /* Reverse the arcs. */
952 for (ix
= fn
->num_blocks
; ix
--;)
954 arc_t
*arc
, *arc_p
, *arc_n
;
956 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
957 arc_p
= arc
, arc
= arc_n
)
959 arc_n
= arc
->succ_next
;
960 arc
->succ_next
= arc_p
;
962 fn
->blocks
[ix
].succ
= arc_p
;
964 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
965 arc_p
= arc
, arc
= arc_n
)
967 arc_n
= arc
->pred_next
;
968 arc
->pred_next
= arc_p
;
970 fn
->blocks
[ix
].pred
= arc_p
;
978 /* Reads profiles from the count file and attach to each
979 function. Return nonzero if fatal error. */
987 function_t
*fn
= NULL
;
990 if (!gcov_open (da_file_name
, 1))
992 fnotice (stderr
, "%s:cannot open data file\n", da_file_name
);
995 if (gcov_read_unsigned () != GCOV_DATA_MAGIC
)
997 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
1002 version
= gcov_read_unsigned ();
1003 if (version
!= GCOV_VERSION
)
1006 unsigned desired
= GCOV_VERSION
;
1008 for (ix
= 4; ix
--; desired
>>= 8, version
>>= 8)
1013 fnotice (stderr
, "%s:version `%.4s', prefer version `%.4s'\n",
1014 da_file_name
, v
, e
);
1016 tag
= gcov_read_unsigned ();
1017 if (tag
!= bbg_stamp
)
1019 fnotice (stderr
, "%s:stamp mismatch with graph file\n", da_file_name
);
1023 while ((tag
= gcov_read_unsigned ()))
1025 unsigned length
= gcov_read_unsigned ();
1026 unsigned long base
= gcov_position ();
1028 if (tag
== GCOV_TAG_OBJECT_SUMMARY
)
1029 gcov_read_summary (&object_summary
);
1030 else if (tag
== GCOV_TAG_PROGRAM_SUMMARY
)
1032 else if (tag
== GCOV_TAG_FUNCTION
)
1034 unsigned ident
= gcov_read_unsigned ();
1035 struct function_info
*fn_n
= functions
;
1037 for (fn
= fn
? fn
->next
: NULL
; ; fn
= fn
->next
)
1041 else if ((fn
= fn_n
))
1045 fnotice (stderr
, "%s:unknown function `%u'\n",
1046 da_file_name
, ident
);
1049 if (fn
->ident
== ident
)
1055 else if (gcov_read_unsigned () != fn
->checksum
)
1058 fnotice (stderr
, "%s:profile mismatch for `%s'\n",
1059 da_file_name
, fn
->name
);
1063 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
1065 if (length
!= 8 * fn
->num_counts
)
1070 = (gcov_type
*)xcalloc (fn
->num_counts
, sizeof (gcov_type
));
1072 for (ix
= 0; ix
!= fn
->num_counts
; ix
++)
1073 fn
->counts
[ix
] += gcov_read_counter ();
1075 gcov_sync (base
, length
);
1076 if ((error
= gcov_is_error ()))
1080 if (!gcov_is_eof ())
1082 fnotice (stderr
, error
< 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1091 /* Solve the flow graph. Propagate counts from the instrumented arcs
1092 to the blocks and the uninstrumented arcs. */
1095 solve_flow_graph (fn
)
1100 gcov_type
*count_ptr
= fn
->counts
;
1102 block_t
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
1103 block_t
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
1105 if (fn
->num_blocks
< 2)
1106 fnotice (stderr
, "%s:`%s' lacks entry and/or exit blocks\n",
1107 bbg_file_name
, fn
->name
);
1110 if (fn
->blocks
[0].num_pred
)
1111 fnotice (stderr
, "%s:`%s' has arcs to entry block\n",
1112 bbg_file_name
, fn
->name
);
1114 /* We can't deduce the entry block counts from the lack of
1116 fn
->blocks
[0].num_pred
= ~(unsigned)0;
1118 if (fn
->blocks
[fn
->num_blocks
- 1].num_succ
)
1119 fnotice (stderr
, "%s:`%s' has arcs from exit block\n",
1120 bbg_file_name
, fn
->name
);
1122 /* Likewise, we can't deduce exit block counts from the lack
1123 of its successors. */
1124 fn
->blocks
[fn
->num_blocks
- 1].num_succ
= ~(unsigned)0;
1127 /* Propagate the measured counts, this must be done in the same
1128 order as the code in profile.c */
1129 for (ix
= 0, blk
= fn
->blocks
; ix
!= fn
->num_blocks
; ix
++, blk
++)
1131 block_t
const *prev_dst
= NULL
;
1132 int out_of_order
= 0;
1133 int non_fake_succ
= 0;
1135 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1143 arc
->count
= *count_ptr
++;
1144 arc
->count_valid
= 1;
1146 arc
->dst
->num_pred
--;
1148 if (prev_dst
&& prev_dst
> arc
->dst
)
1150 prev_dst
= arc
->dst
;
1152 if (non_fake_succ
== 1)
1154 /* If there is only one non-fake exit, it is an
1155 unconditional branch. */
1156 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1159 arc
->is_unconditional
= 1;
1160 /* If this block is instrumenting a call, it might be
1161 an artificial block. It is not artificial if it has
1162 a non-fallthrough exit, or the destination of this
1163 arc has more than one entry. Mark the destination
1164 block as a return site, if none of those conditions
1166 if (blk
->is_call_site
&& arc
->fall_through
1167 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
1168 arc
->dst
->is_call_return
= 1;
1172 /* Sort the successor arcs into ascending dst order. profile.c
1173 normally produces arcs in the right order, but sometimes with
1174 one or two out of order. We're not using a particularly
1178 arc_t
*start
= blk
->succ
;
1179 unsigned changes
= 1;
1183 arc_t
*arc
, *arc_p
, *arc_n
;
1186 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
1188 if (arc
->dst
> arc_n
->dst
)
1192 arc_p
->succ_next
= arc_n
;
1195 arc
->succ_next
= arc_n
->succ_next
;
1196 arc_n
->succ_next
= arc
;
1209 /* Place it on the invalid chain, it will be ignored if that's
1211 blk
->invalid_chain
= 1;
1212 blk
->chain
= invalid_blocks
;
1213 invalid_blocks
= blk
;
1216 while (invalid_blocks
|| valid_blocks
)
1218 while ((blk
= invalid_blocks
))
1220 gcov_type total
= 0;
1223 invalid_blocks
= blk
->chain
;
1224 blk
->invalid_chain
= 0;
1226 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1227 total
+= arc
->count
;
1228 else if (!blk
->num_pred
)
1229 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1230 total
+= arc
->count
;
1235 blk
->count_valid
= 1;
1236 blk
->chain
= valid_blocks
;
1237 blk
->valid_chain
= 1;
1240 while ((blk
= valid_blocks
))
1243 arc_t
*arc
, *inv_arc
;
1245 valid_blocks
= blk
->chain
;
1246 blk
->valid_chain
= 0;
1247 if (blk
->num_succ
== 1)
1253 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1255 total
-= arc
->count
;
1256 if (!arc
->count_valid
)
1260 inv_arc
->count_valid
= 1;
1261 inv_arc
->count
= total
;
1264 if (dst
->count_valid
)
1266 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
1268 dst
->chain
= valid_blocks
;
1269 dst
->valid_chain
= 1;
1275 if (!dst
->num_pred
&& !dst
->invalid_chain
)
1277 dst
->chain
= invalid_blocks
;
1278 dst
->invalid_chain
= 1;
1279 invalid_blocks
= dst
;
1283 if (blk
->num_pred
== 1)
1289 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1291 total
-= arc
->count
;
1292 if (!arc
->count_valid
)
1296 inv_arc
->count_valid
= 1;
1297 inv_arc
->count
= total
;
1300 if (src
->count_valid
)
1302 if (src
->num_succ
== 1 && !src
->valid_chain
)
1304 src
->chain
= valid_blocks
;
1305 src
->valid_chain
= 1;
1311 if (!src
->num_succ
&& !src
->invalid_chain
)
1313 src
->chain
= invalid_blocks
;
1314 src
->invalid_chain
= 1;
1315 invalid_blocks
= src
;
1322 /* If the graph has been correctly solved, every block will have a
1324 for (ix
= 0; ix
< fn
->num_blocks
; ix
++)
1325 if (!fn
->blocks
[ix
].count_valid
)
1327 fnotice (stderr
, "%s:graph is unsolvable for `%s'\n",
1328 bbg_file_name
, fn
->name
);
1335 /* Increment totals in COVERAGE according to arc ARC. */
1338 add_branch_counts (coverage
, arc
)
1339 coverage_t
*coverage
;
1342 if (arc
->is_call_non_return
)
1345 if (arc
->src
->count
)
1346 coverage
->calls_executed
++;
1348 else if (!arc
->is_unconditional
)
1350 coverage
->branches
++;
1351 if (arc
->src
->count
)
1352 coverage
->branches_executed
++;
1354 coverage
->branches_taken
++;
1358 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1359 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1360 If DP is zero, no decimal point is printed. Only print 100% when
1361 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1362 format TOP. Return pointer to a static string. */
1365 format_gcov (top
, bottom
, dp
)
1366 gcov_type top
, bottom
;
1369 static char buffer
[20];
1373 float ratio
= bottom
? (float)top
/ bottom
: 0;
1375 unsigned limit
= 100;
1378 for (ix
= dp
; ix
--; )
1381 percent
= (unsigned) (ratio
* limit
+ (float)0.5);
1382 if (percent
<= 0 && top
)
1384 else if (percent
>= limit
&& top
!= bottom
)
1385 percent
= limit
- 1;
1386 ix
= sprintf (buffer
, "%.*u%%", dp
+ 1, percent
);
1392 buffer
[ix
+1] = buffer
[ix
];
1396 buffer
[ix
+ 1] = '.';
1400 sprintf (buffer
, HOST_WIDEST_INT_PRINT_DEC
, (HOST_WIDEST_INT
)top
);
1406 /* Output summary info for a function. */
1409 function_summary (coverage
, title
)
1410 const coverage_t
*coverage
;
1413 fnotice (stdout
, "%s `%s'\n", title
, coverage
->name
);
1415 if (coverage
->lines
)
1416 fnotice (stdout
, "Lines executed:%s of %d\n",
1417 format_gcov (coverage
->lines_executed
, coverage
->lines
, 2),
1420 fnotice (stdout
, "No executable lines");
1424 if (coverage
->branches
)
1426 fnotice (stdout
, "Branches executed:%s of %d\n",
1427 format_gcov (coverage
->branches_executed
,
1428 coverage
->branches
, 2),
1429 coverage
->branches
);
1430 fnotice (stdout
, "Taken at least once:%s of %d\n",
1431 format_gcov (coverage
->branches_taken
,
1432 coverage
->branches
, 2),
1433 coverage
->branches
);
1436 fnotice (stdout
, "No branches\n");
1437 if (coverage
->calls
)
1438 fnotice (stdout
, "Calls executed:%s of %d\n",
1439 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
1442 fnotice (stdout
, "No calls\n");
1446 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1447 affect name generation. With preserve_paths we create a filename
1448 from all path components of the source file, replacing '/' with
1449 '#', without it we simply take the basename component. With
1450 long_output_names we prepend the processed name of the input file
1451 to each output name (except when the current source file is the
1452 input file, so you don't get a double concatenation). The two
1453 components are separated by '##'. Also '.' filename components are
1454 removed and '..' components are renamed to '^'. */
1457 make_gcov_file_name (input_name
, src_name
)
1458 const char *input_name
;
1459 const char *src_name
;
1462 char *name
= xmalloc (strlen (src_name
) + strlen (input_name
) + 10);
1465 if (flag_long_names
&& strcmp (src_name
, input_name
))
1467 /* Generate the input filename part. */
1468 cptr
= flag_preserve_paths
? NULL
: strrchr (input_name
, '/');
1469 strcat (name
, cptr
? cptr
+ 1 : input_name
);
1470 strcat (name
, "##");
1473 /* Generate the source filename part. */
1474 cptr
= flag_preserve_paths
? NULL
: strrchr (src_name
, '/');
1475 strcat (name
, cptr
? cptr
+ 1 : src_name
);
1477 if (flag_preserve_paths
)
1479 /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1482 for (cptr
= name
; (cptr
= strchr ((prev
= cptr
), '/'));)
1486 if (prev
+ 1 == cptr
&& prev
[0] == '.')
1491 else if (prev
+ 2 == cptr
&& prev
[0] == '.' && prev
[1] == '.')
1503 prev
[0] = prev
[shift
];
1509 strcat (name
, ".gcov");
1513 /* Scan through the bb_data for each line in the block, increment
1514 the line number execution count indicated by the execution count of
1515 the appropriate basic block. */
1518 add_line_counts (coverage
, fn
)
1519 coverage_t
*coverage
;
1523 line_t
*line
= NULL
; /* this is propagated from one iteration to the
1526 /* Scan each basic block. */
1527 for (ix
= 0; ix
!= fn
->num_blocks
; ix
++)
1529 block_t
*block
= &fn
->blocks
[ix
];
1531 const source_t
*src
= NULL
;
1534 if (block
->count
&& ix
&& ix
+ 1 != fn
->num_blocks
)
1535 fn
->blocks_executed
++;
1536 for (jx
= 0, encoding
= block
->u
.line
.encoding
;
1537 jx
!= block
->u
.line
.num
; jx
++, encoding
++)
1540 unsigned src_n
= *++encoding
;
1542 for (src
= sources
; src
->index
!= src_n
; src
= src
->next
)
1548 line
= &src
->lines
[*encoding
];
1554 if (!line
->count
&& block
->count
)
1555 coverage
->lines_executed
++;
1558 line
->count
+= block
->count
;
1560 free (block
->u
.line
.encoding
);
1561 block
->u
.cycle
.arc
= NULL
;
1562 block
->u
.cycle
.ident
= ~0U;
1564 if (!ix
|| ix
+ 1 == fn
->num_blocks
)
1565 /* Entry or exit block */;
1566 else if (flag_all_blocks
)
1568 line_t
*block_line
= line
? line
: &fn
->src
->lines
[fn
->line
];
1570 block
->chain
= block_line
->u
.blocks
;
1571 block_line
->u
.blocks
= block
;
1573 else if (flag_branches
)
1577 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1579 arc
->line_next
= line
->u
.branches
;
1580 line
->u
.branches
= arc
;
1581 if (coverage
&& !arc
->is_unconditional
)
1582 add_branch_counts (coverage
, arc
);
1587 fnotice (stderr
, "%s:no lines for `%s'\n", bbg_file_name
, fn
->name
);
1590 /* Accumulate the line counts of a file. */
1593 accumulate_line_counts (src
)
1597 function_t
*fn
, *fn_p
, *fn_n
;
1600 /* Reverse the function order. */
1601 for (fn
= src
->functions
, fn_p
= NULL
; fn
;
1602 fn_p
= fn
, fn
= fn_n
)
1604 fn_n
= fn
->line_next
;
1605 fn
->line_next
= fn_p
;
1607 src
->functions
= fn_p
;
1609 for (ix
= src
->num_lines
, line
= src
->lines
; ix
--; line
++)
1611 if (!flag_all_blocks
)
1613 arc_t
*arc
, *arc_p
, *arc_n
;
1615 /* Total and reverse the branch information. */
1616 for (arc
= line
->u
.branches
, arc_p
= NULL
; arc
;
1617 arc_p
= arc
, arc
= arc_n
)
1619 arc_n
= arc
->line_next
;
1620 arc
->line_next
= arc_p
;
1622 add_branch_counts (&src
->coverage
, arc
);
1624 line
->u
.branches
= arc_p
;
1626 else if (line
->u
.blocks
)
1628 /* The user expects the line count to be the number of times
1629 a line has been executed. Simply summing the block count
1630 will give an artificially high number. The Right Thing
1631 is to sum the entry counts to the graph of blocks on this
1632 line, then find the elementary cycles of the local graph
1633 and add the transition counts of those cycles. */
1634 block_t
*block
, *block_p
, *block_n
;
1635 gcov_type count
= 0;
1637 /* Reverse the block information. */
1638 for (block
= line
->u
.blocks
, block_p
= NULL
; block
;
1639 block_p
= block
, block
= block_n
)
1641 block_n
= block
->chain
;
1642 block
->chain
= block_p
;
1643 block
->u
.cycle
.ident
= ix
;
1645 line
->u
.blocks
= block_p
;
1647 /* Sum the entry arcs. */
1648 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
1652 for (arc
= block
->pred
; arc
; arc
= arc
->pred_next
)
1654 if (arc
->src
->u
.cycle
.ident
!= ix
)
1655 count
+= arc
->count
;
1657 add_branch_counts (&src
->coverage
, arc
);
1661 /* Find the loops. This uses the algorithm described in
1662 Tiernan 'An Efficient Search Algorithm to Find the
1663 Elementary Circuits of a Graph', CACM Dec 1970. We hold
1664 the P array by having each block point to the arc that
1665 connects to the previous block. The H array is implicitly
1666 held because of the arc ordering, and the block's
1667 previous arc pointer.
1669 Although the algorithm is O(N^3) for highly connected
1670 graphs, at worst we'll have O(N^2), as most blocks have
1671 only one or two exits. Most graphs will be small.
1673 For each loop we find, locate the arc with the smallest
1674 transition count, and add that to the cumulative
1675 count. Remove the arc from consideration. */
1676 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
1678 block_t
*head
= block
;
1686 block_t
*dst
= arc
->dst
;
1687 if (/* Already used that arc. */
1689 /* Not to same graph, or before first vertex. */
1690 || dst
->u
.cycle
.ident
!= ix
1691 /* Already in path. */
1692 || dst
->u
.cycle
.arc
)
1694 arc
= arc
->succ_next
;
1700 /* Found a closing arc. */
1701 gcov_type cycle_count
= arc
->count
;
1702 arc_t
*cycle_arc
= arc
;
1705 /* Locate the smallest arc count of the loop. */
1706 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
1707 dst
= probe_arc
->src
)
1708 if (cycle_count
> probe_arc
->count
)
1710 cycle_count
= probe_arc
->count
;
1711 cycle_arc
= probe_arc
;
1714 count
+= cycle_count
;
1715 cycle_arc
->cycle
= 1;
1716 /* Unwind to the cyclic arc. */
1717 while (head
!= cycle_arc
->src
)
1719 arc
= head
->u
.cycle
.arc
;
1723 arc
= arc
->succ_next
;
1727 /* Add new block to chain. */
1728 dst
->u
.cycle
.arc
= arc
;
1732 /* We could not add another vertex to the path. Remove
1733 the last vertex from the list. */
1734 arc
= head
->u
.cycle
.arc
;
1737 /* It was not the first vertex. Move onto next arc. */
1738 head
->u
.cycle
.arc
= NULL
;
1740 arc
= arc
->succ_next
;
1741 goto current_vertex
;
1743 /* Mark this block as unusable. */
1744 block
->u
.cycle
.ident
= ~0U;
1747 line
->count
= count
;
1752 src
->coverage
.lines
++;
1754 src
->coverage
.lines_executed
++;
1759 /* Ouput information about ARC number IX. Returns nonzero if
1760 anything is output. */
1763 output_branch_count (gcov_file
, ix
, arc
)
1769 if (arc
->is_call_non_return
)
1771 if (arc
->src
->count
)
1773 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
1774 format_gcov (arc
->src
->count
- arc
->count
,
1775 arc
->src
->count
, -flag_counts
));
1778 fnotice (gcov_file
, "call %2d never executed\n", ix
);
1780 else if (!arc
->is_unconditional
)
1782 if (arc
->src
->count
)
1783 fnotice (gcov_file
, "branch %2d taken %s%s\n", ix
,
1784 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
1785 arc
->fall_through
? " (fallthrough)" : "");
1787 fnotice (gcov_file
, "branch %2d never executed\n", ix
);
1789 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
1791 if (arc
->src
->count
)
1792 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
1793 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
1795 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
1803 /* Read in the source file one line at a time, and output that line to
1804 the gcov file preceded by its execution count and other
1808 output_lines (gcov_file
, src
)
1810 const source_t
*src
;
1813 unsigned line_num
; /* current line number. */
1814 const line_t
*line
; /* current line info ptr. */
1815 char string
[STRING_SIZE
]; /* line buffer. */
1816 char const *retval
= ""; /* status of source file reading. */
1817 function_t
*fn
= src
->functions
;
1819 fprintf (gcov_file
, "%9s:%5d:Source:%s\n", "-", 0, src
->name
);
1820 fprintf (gcov_file
, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name
);
1821 fprintf (gcov_file
, "%9s:%5d:Data:%s\n", "-", 0, da_file_name
);
1822 fprintf (gcov_file
, "%9s:%5d:Runs:%u\n", "-", 0,
1823 object_summary
.ctrs
[GCOV_COUNTER_ARCS
].runs
);
1824 fprintf (gcov_file
, "%9s:%5d:Programs:%u\n", "-", 0, program_count
);
1826 source_file
= fopen (src
->name
, "r");
1829 fnotice (stderr
, "%s:cannot open source file\n", src
->name
);
1836 if (!fstat (fileno (source_file
), &status
)
1837 && status
.st_mtime
> bbg_file_time
)
1839 fnotice (stderr
, "%s:source file is newer than graph file `%s'\n",
1840 src
->name
, bbg_file_name
);
1841 fprintf (gcov_file
, "%9s:%5d:Source is newer than graph\n",
1846 for (line_num
= 1, line
= &src
->lines
[line_num
];
1847 line_num
< src
->num_lines
; line_num
++, line
++)
1849 for (; fn
&& fn
->line
== line_num
; fn
= fn
->line_next
)
1851 arc_t
*arc
= fn
->blocks
[fn
->num_blocks
- 1].pred
;
1852 gcov_type return_count
= fn
->blocks
[fn
->num_blocks
- 1].count
;
1854 for (; arc
; arc
= arc
->pred_next
)
1856 return_count
-= arc
->count
;
1858 fprintf (gcov_file
, "function %s", fn
->name
);
1859 fprintf (gcov_file
, " called %s",
1860 format_gcov (fn
->blocks
[0].count
, 0, -1));
1861 fprintf (gcov_file
, " returned %s",
1862 format_gcov (return_count
, fn
->blocks
[0].count
, 0));
1863 fprintf (gcov_file
, " blocks executed %s",
1864 format_gcov (fn
->blocks_executed
, fn
->num_blocks
- 2, 0));
1865 fprintf (gcov_file
, "\n");
1868 /* For lines which don't exist in the .bb file, print '-' before
1869 the source line. For lines which exist but were never
1870 executed, print '#####' before the source line. Otherwise,
1871 print the execution count before the source line. There are
1872 16 spaces of indentation added before the source line so that
1873 tabs won't be messed up. */
1874 fprintf (gcov_file
, "%9s:%5u:",
1875 !line
->exists
? "-" : !line
->count
? "#####"
1876 : format_gcov (line
->count
, 0, -1), line_num
);
1880 /* Copy source line. */
1883 retval
= fgets (string
, STRING_SIZE
, source_file
);
1886 fputs (retval
, gcov_file
);
1888 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n');
1891 fputs ("/*EOF*/\n", gcov_file
);
1893 if (flag_all_blocks
)
1899 for (ix
= jx
= 0, block
= line
->u
.blocks
; block
;
1900 block
= block
->chain
)
1902 if (!block
->is_call_return
)
1903 fprintf (gcov_file
, "%9s:%5u-block %2d\n",
1904 !line
->exists
? "-" : !block
->count
? "$$$$$"
1905 : format_gcov (block
->count
, 0, -1),
1908 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1909 jx
+= output_branch_count (gcov_file
, jx
, arc
);
1912 else if (flag_branches
)
1917 for (ix
= 0, arc
= line
->u
.branches
; arc
; arc
= arc
->line_next
)
1918 ix
+= output_branch_count (gcov_file
, ix
, arc
);
1922 /* Handle all remaining source lines. There may be lines after the
1923 last line of code. */
1926 for (; (retval
= fgets (string
, STRING_SIZE
, source_file
)); line_num
++)
1928 fprintf (gcov_file
, "%9s:%5u:%s", "-", line_num
, retval
);
1930 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n')
1932 retval
= fgets (string
, STRING_SIZE
, source_file
);
1935 fputs (retval
, gcov_file
);
1941 fclose (source_file
);