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, 2003, 2004, 2005 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"
57 /* The bbg file is generated by -ftest-coverage option. The da file is
58 generated by a program compiled with -fprofile-arcs. Their formats
59 are documented in gcov-io.h. */
61 /* The functions in this file for creating and solution program flow graphs
62 are very similar to functions in the gcc source file profile.c. In
63 some places we make use of the knowledge of how profile.c works to
64 select particular algorithms here. */
66 /* This is the size of the buffer used to read in source file lines. */
68 #define STRING_SIZE 200
74 /* Describes an arc between two basic blocks. */
76 typedef struct arc_info
78 /* source and destination blocks. */
79 struct block_info
*src
;
80 struct block_info
*dst
;
82 /* transition counts. */
84 /* used in cycle search, so that we do not clobber original counts. */
87 unsigned int count_valid
: 1;
88 unsigned int on_tree
: 1;
89 unsigned int fake
: 1;
90 unsigned int fall_through
: 1;
92 /* Arc is for a function that abnormally returns. */
93 unsigned int is_call_non_return
: 1;
95 /* Arc is for catch/setjump. */
96 unsigned int is_nonlocal_return
: 1;
98 /* Is an unconditional branch. */
99 unsigned int is_unconditional
: 1;
101 /* Loop making arc. */
102 unsigned int cycle
: 1;
104 /* Next branch on line. */
105 struct arc_info
*line_next
;
107 /* Links to next arc on src and dst lists. */
108 struct arc_info
*succ_next
;
109 struct arc_info
*pred_next
;
112 /* Describes a basic block. Contains lists of arcs to successor and
113 predecessor blocks. */
115 typedef struct block_info
117 /* Chain of exit and entry arcs. */
121 /* Number of unprocessed exit and entry arcs. */
125 /* Block execution count. */
128 unsigned count_valid
: 1;
129 unsigned valid_chain
: 1;
130 unsigned invalid_chain
: 1;
132 /* Block is a call instrumenting site. */
133 unsigned is_call_site
: 1; /* Does the call. */
134 unsigned is_call_return
: 1; /* Is the return. */
136 /* Block is a landing pad for longjmp or throw. */
137 unsigned is_nonlocal_return
: 1;
143 /* Array of line numbers and source files. source files are
144 introduced by a linenumber of zero, the next 'line number' is
145 the number of the source file. Always starts with a source
149 } line
; /* Valid until blocks are linked onto lines */
152 /* Single line graph cycle workspace. Used for all-blocks
156 } cycle
; /* Used in all-blocks mode, after blocks are linked onto
160 /* Temporary chain for solving graph, and for chaining blocks on one
162 struct block_info
*chain
;
166 /* Describes a single function. Contains an array of basic blocks. */
168 typedef struct function_info
170 /* Name of function. */
175 /* Array of basic blocks. */
178 unsigned blocks_executed
;
180 /* Raw arc coverage counts. */
184 /* First line number. */
186 struct source_info
*src
;
188 /* Next function in same source file. */
189 struct function_info
*line_next
;
192 struct function_info
*next
;
195 /* Describes coverage of a file or function. */
197 typedef struct coverage_info
203 int branches_executed
;
212 /* Describes a single line of source. Contains a chain of basic blocks
215 typedef struct line_info
217 gcov_type count
; /* execution count */
220 arc_t
*branches
; /* branches from blocks that end on this
221 line. Used for branch-counts when not
223 block_t
*blocks
; /* blocks which start on this line. Used
224 in all-blocks mode. */
229 /* Describes a file mentioned in the block graph. Contains an array
232 typedef struct source_info
234 /* Name of source file. */
238 /* Array of line information. */
244 /* Functions in this source file. These are in ascending line
246 function_t
*functions
;
248 /* Next source file. */
249 struct source_info
*next
;
252 /* Holds a list of function basic block graphs. */
254 static function_t
*functions
;
256 /* This points to the head of the sourcefile structure list. */
258 static source_t
*sources
;
260 /* This holds data summary information. */
262 static struct gcov_summary object_summary
;
263 static unsigned program_count
;
265 /* Modification time of graph file. */
267 static time_t bbg_file_time
;
269 /* Name and file pointer of the input file for the basic block graph. */
271 static char *bbg_file_name
;
273 /* Stamp of the bbg file */
274 static unsigned bbg_stamp
;
276 /* Name and file pointer of the input file for the arc count data. */
278 static char *da_file_name
;
280 /* Output branch probabilities. */
282 static int flag_branches
= 0;
284 /* Show unconditional branches too. */
285 static int flag_unconditional
= 0;
287 /* Output a gcov file if this is true. This is on by default, and can
288 be turned off by the -n option. */
290 static int flag_gcov_file
= 1;
292 /* For included files, make the gcov output file name include the name
293 of the input source file. For example, if x.h is included in a.c,
294 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
296 static int flag_long_names
= 0;
298 /* Output count information for every basic block, not merely those
299 that contain line number information. */
301 static int flag_all_blocks
= 0;
303 /* Output summary info for each function. */
305 static int flag_function_summary
= 0;
307 /* Object directory file prefix. This is the directory/file where the
308 graph and data files are looked for, if nonzero. */
310 static char *object_directory
= 0;
312 /* Preserve all pathname components. Needed when object files and
313 source files are in subdirectories. '/' is mangled as '#', '.' is
314 elided and '..' mangled to '^'. */
316 static int flag_preserve_paths
= 0;
318 /* Output the number of times a branch was taken as opposed to the percentage
319 of times it was taken. */
321 static int flag_counts
= 0;
323 /* Forward declarations. */
324 static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2
;
325 static int process_args (int, char **);
326 static void print_usage (int) ATTRIBUTE_NORETURN
;
327 static void print_version (void) ATTRIBUTE_NORETURN
;
328 static void process_file (const char *);
329 static void create_file_names (const char *);
330 static source_t
*find_source (const char *);
331 static int read_graph_file (void);
332 static int read_count_file (void);
333 static void solve_flow_graph (function_t
*);
334 static void add_branch_counts (coverage_t
*, const arc_t
*);
335 static void add_line_counts (coverage_t
*, function_t
*);
336 static void function_summary (const coverage_t
*, const char *);
337 static const char *format_gcov (gcov_type
, gcov_type
, int);
338 static void accumulate_line_counts (source_t
*);
339 static int output_branch_count (FILE *, int, const arc_t
*);
340 static void output_lines (FILE *, const source_t
*);
341 static char *make_gcov_file_name (const char *, const char *);
342 static void release_structures (void);
343 extern int main (int, char **);
346 main (int argc
, char **argv
)
350 /* Unlock the stdio streams. */
351 unlock_stream (stdin
);
352 unlock_stream (stdout
);
353 unlock_stream (stderr
);
357 argno
= process_args (argc
, argv
);
361 for (; argno
!= argc
; argno
++)
363 release_structures ();
365 process_file (argv
[argno
]);
372 fnotice (FILE *file
, const char *msgid
, ...)
376 va_start (ap
, msgid
);
377 vfprintf (file
, _(msgid
), ap
);
381 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
382 otherwise the output of --help. */
385 print_usage (int error_p
)
387 FILE *file
= error_p
? stderr
: stdout
;
388 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
390 fnotice (file
, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
391 fnotice (file
, "Print code coverage information.\n\n");
392 fnotice (file
, " -h, --help Print this help, then exit\n");
393 fnotice (file
, " -v, --version Print version number, then exit\n");
394 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
395 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
396 fnotice (file
, " -c, --branch-counts Given counts of branches taken\n\
397 rather than percentages\n");
398 fnotice (file
, " -n, --no-output Do not create an output file\n");
399 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
401 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
402 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
403 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
404 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
405 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
410 /* Print version information and exit. */
415 fnotice (stdout
, "gcov (GCC) %s\n", version_string
);
416 fprintf (stdout
, "Copyright %s 2004 Free Software Foundation, Inc.\n",
419 _("This is free software; see the source for copying conditions.\n"
420 "There is NO warranty; not even for MERCHANTABILITY or \n"
421 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
422 exit (SUCCESS_EXIT_CODE
);
425 static const struct option options
[] =
427 { "help", no_argument
, NULL
, 'h' },
428 { "version", no_argument
, NULL
, 'v' },
429 { "all-blocks", no_argument
, NULL
, 'a' },
430 { "branch-probabilities", no_argument
, NULL
, 'b' },
431 { "branch-counts", no_argument
, NULL
, 'c' },
432 { "no-output", no_argument
, NULL
, 'n' },
433 { "long-file-names", no_argument
, NULL
, 'l' },
434 { "function-summaries", no_argument
, NULL
, 'f' },
435 { "preserve-paths", no_argument
, NULL
, 'p' },
436 { "object-directory", required_argument
, NULL
, 'o' },
437 { "object-file", required_argument
, NULL
, 'o' },
438 { "unconditional-branches", no_argument
, NULL
, 'u' },
442 /* Process args, return index to first non-arg. */
445 process_args (int argc
, char **argv
)
449 while ((opt
= getopt_long (argc
, argv
, "abcfhlno:puv", options
, NULL
)) != -1)
463 flag_function_summary
= 1;
467 /* print_usage will exit. */
475 object_directory
= optarg
;
478 flag_preserve_paths
= 1;
481 flag_unconditional
= 1;
485 /* print_version will exit. */
488 /* print_usage will exit. */
495 /* Process a single source file. */
498 process_file (const char *file_name
)
503 create_file_names (file_name
);
504 if (read_graph_file ())
509 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
513 if (read_count_file ())
516 for (fn
= functions
; fn
; fn
= fn
->next
)
517 solve_flow_graph (fn
);
518 for (src
= sources
; src
; src
= src
->next
)
519 src
->lines
= xcalloc (src
->num_lines
, sizeof (line_t
));
520 for (fn
= functions
; fn
; fn
= fn
->next
)
524 memset (&coverage
, 0, sizeof (coverage
));
525 coverage
.name
= fn
->name
;
526 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
527 if (flag_function_summary
)
529 function_summary (&coverage
, "Function");
530 fnotice (stdout
, "\n");
534 for (src
= sources
; src
; src
= src
->next
)
536 accumulate_line_counts (src
);
537 function_summary (&src
->coverage
, "File");
540 char *gcov_file_name
= make_gcov_file_name (file_name
, src
->name
);
541 FILE *gcov_file
= fopen (gcov_file_name
, "w");
545 fnotice (stdout
, "%s:creating '%s'\n",
546 src
->name
, gcov_file_name
);
547 output_lines (gcov_file
, src
);
548 if (ferror (gcov_file
))
549 fnotice (stderr
, "%s:error writing output file '%s'\n",
550 src
->name
, gcov_file_name
);
554 fnotice (stderr
, "%s:could not open output file '%s'\n",
555 src
->name
, gcov_file_name
);
556 free (gcov_file_name
);
558 fnotice (stdout
, "\n");
562 /* Release all memory used. */
565 release_structures (void)
570 free (bbg_file_name
);
572 da_file_name
= bbg_file_name
= NULL
;
576 while ((src
= sources
))
584 while ((fn
= functions
))
589 functions
= fn
->next
;
590 for (ix
= fn
->num_blocks
, block
= fn
->blocks
; ix
--; block
++)
594 for (arc
= block
->succ
; arc
; arc
= arc_n
)
596 arc_n
= arc
->succ_next
;
605 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
606 is not specified, these are looked for in the current directory,
607 and named from the basename of the FILE_NAME sans extension. If
608 OBJECT_DIRECTORY is specified and is a directory, the files are in
609 that directory, but named from the basename of the FILE_NAME, sans
610 extension. Otherwise OBJECT_DIRECTORY is taken to be the name of
611 the object *file*, and the data files are named from that. */
614 create_file_names (const char *file_name
)
618 int length
= strlen (file_name
);
621 if (object_directory
&& object_directory
[0])
625 length
+= strlen (object_directory
) + 2;
626 name
= xmalloc (length
);
629 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
630 strcat (name
, object_directory
);
631 if (base
&& name
[strlen (name
) - 1] != '/')
636 name
= xmalloc (length
+ 1);
643 /* Append source file name. */
644 cptr
= strrchr (file_name
, '/');
645 strcat (name
, cptr
? cptr
+ 1 : file_name
);
648 /* Remove the extension. */
649 cptr
= strrchr (name
, '.');
653 length
= strlen (name
);
655 bbg_file_name
= xmalloc (length
+ strlen (GCOV_NOTE_SUFFIX
) + 1);
656 strcpy (bbg_file_name
, name
);
657 strcpy (bbg_file_name
+ length
, GCOV_NOTE_SUFFIX
);
659 da_file_name
= xmalloc (length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
660 strcpy (da_file_name
, name
);
661 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
666 /* Find or create a source file structure for FILE_NAME. Copies
667 FILE_NAME on creation */
670 find_source (const char *file_name
)
675 file_name
= "<unknown>";
677 for (src
= sources
; src
; src
= src
->next
)
678 if (!strcmp (file_name
, src
->name
))
681 src
= xcalloc (1, sizeof (source_t
));
682 src
->name
= xstrdup (file_name
);
683 src
->coverage
.name
= src
->name
;
684 src
->index
= sources
? sources
->index
+ 1 : 1;
691 /* Read the graph file. Return nonzero on fatal error. */
694 read_graph_file (void)
697 unsigned current_tag
= 0;
698 struct function_info
*fn
= NULL
;
699 source_t
*src
= NULL
;
703 if (!gcov_open (bbg_file_name
, 1))
705 fnotice (stderr
, "%s:cannot open graph file\n", bbg_file_name
);
708 bbg_file_time
= gcov_time ();
709 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC
))
711 fnotice (stderr
, "%s:not a gcov graph file\n", bbg_file_name
);
716 version
= gcov_read_unsigned ();
717 if (version
!= GCOV_VERSION
)
721 GCOV_UNSIGNED2STRING (v
, version
);
722 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
724 fnotice (stderr
, "%s:version '%.4s', prefer '%.4s'\n",
725 bbg_file_name
, v
, e
);
727 bbg_stamp
= gcov_read_unsigned ();
729 while ((tag
= gcov_read_unsigned ()))
731 unsigned length
= gcov_read_unsigned ();
732 gcov_position_t base
= gcov_position ();
734 if (tag
== GCOV_TAG_FUNCTION
)
737 unsigned ident
, checksum
, lineno
;
739 function_t
*probe
, *prev
;
741 ident
= gcov_read_unsigned ();
742 checksum
= gcov_read_unsigned ();
743 function_name
= xstrdup (gcov_read_string ());
744 src
= find_source (gcov_read_string ());
745 lineno
= gcov_read_unsigned ();
747 fn
= xcalloc (1, sizeof (function_t
));
748 fn
->name
= function_name
;
750 fn
->checksum
= checksum
;
754 fn
->next
= functions
;
758 if (lineno
>= src
->num_lines
)
759 src
->num_lines
= lineno
+ 1;
760 /* Now insert it into the source file's list of
761 functions. Normally functions will be encountered in
762 ascending order, so a simple scan is quick. */
763 for (probe
= src
->functions
, prev
= NULL
;
764 probe
&& probe
->line
> lineno
;
765 prev
= probe
, probe
= probe
->line_next
)
767 fn
->line_next
= probe
;
769 prev
->line_next
= fn
;
773 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
776 fnotice (stderr
, "%s:already seen blocks for '%s'\n",
777 bbg_file_name
, fn
->name
);
780 unsigned ix
, num_blocks
= GCOV_TAG_BLOCKS_NUM (length
);
781 fn
->num_blocks
= num_blocks
;
783 fn
->blocks
= xcalloc (fn
->num_blocks
, sizeof (block_t
));
784 for (ix
= 0; ix
!= num_blocks
; ix
++)
785 fn
->blocks
[ix
].flags
= gcov_read_unsigned ();
788 else if (fn
&& tag
== GCOV_TAG_ARCS
)
790 unsigned src
= gcov_read_unsigned ();
791 unsigned num_dests
= GCOV_TAG_ARCS_NUM (length
);
793 if (src
>= fn
->num_blocks
|| fn
->blocks
[src
].succ
)
798 struct arc_info
*arc
;
799 unsigned dest
= gcov_read_unsigned ();
800 unsigned flags
= gcov_read_unsigned ();
802 if (dest
>= fn
->num_blocks
)
804 arc
= xcalloc (1, sizeof (arc_t
));
806 arc
->dst
= &fn
->blocks
[dest
];
807 arc
->src
= &fn
->blocks
[src
];
810 arc
->count_valid
= 0;
811 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
812 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
813 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
815 arc
->succ_next
= fn
->blocks
[src
].succ
;
816 fn
->blocks
[src
].succ
= arc
;
817 fn
->blocks
[src
].num_succ
++;
819 arc
->pred_next
= fn
->blocks
[dest
].pred
;
820 fn
->blocks
[dest
].pred
= arc
;
821 fn
->blocks
[dest
].num_pred
++;
827 /* Exceptional exit from this function, the
828 source block must be a call. */
829 fn
->blocks
[src
].is_call_site
= 1;
830 arc
->is_call_non_return
= 1;
834 /* Non-local return from a callee of this
835 function. The destination block is a catch or
837 arc
->is_nonlocal_return
= 1;
838 fn
->blocks
[dest
].is_nonlocal_return
= 1;
846 else if (fn
&& tag
== GCOV_TAG_LINES
)
848 unsigned blockno
= gcov_read_unsigned ();
849 unsigned *line_nos
= xcalloc (length
- 1, sizeof (unsigned));
851 if (blockno
>= fn
->num_blocks
|| fn
->blocks
[blockno
].u
.line
.encoding
)
856 unsigned lineno
= gcov_read_unsigned ();
863 line_nos
[ix
++] = src
->index
;
865 line_nos
[ix
++] = lineno
;
866 if (lineno
>= src
->num_lines
)
867 src
->num_lines
= lineno
+ 1;
871 const char *file_name
= gcov_read_string ();
875 src
= find_source (file_name
);
878 line_nos
[ix
++] = src
->index
;
882 fn
->blocks
[blockno
].u
.line
.encoding
= line_nos
;
883 fn
->blocks
[blockno
].u
.line
.num
= ix
;
885 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
890 gcov_sync (base
, length
);
891 if (gcov_is_error ())
894 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
901 /* We built everything backwards, so nreverse them all. */
903 /* Reverse sources. Not strictly necessary, but we'll then process
904 them in the 'expected' order. */
906 source_t
*src
, *src_p
, *src_n
;
908 for (src_p
= NULL
, src
= sources
; src
; src_p
= src
, src
= src_n
)
916 /* Reverse functions. */
918 function_t
*fn
, *fn_p
, *fn_n
;
920 for (fn_p
= NULL
, fn
= functions
; fn
; fn_p
= fn
, fn
= fn_n
)
927 /* Reverse the arcs. */
928 for (ix
= fn
->num_blocks
; ix
--;)
930 arc_t
*arc
, *arc_p
, *arc_n
;
932 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
933 arc_p
= arc
, arc
= arc_n
)
935 arc_n
= arc
->succ_next
;
936 arc
->succ_next
= arc_p
;
938 fn
->blocks
[ix
].succ
= arc_p
;
940 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
941 arc_p
= arc
, arc
= arc_n
)
943 arc_n
= arc
->pred_next
;
944 arc
->pred_next
= arc_p
;
946 fn
->blocks
[ix
].pred
= arc_p
;
954 /* Reads profiles from the count file and attach to each
955 function. Return nonzero if fatal error. */
958 read_count_file (void)
963 function_t
*fn
= NULL
;
966 if (!gcov_open (da_file_name
, 1))
968 fnotice (stderr
, "%s:cannot open data file\n", da_file_name
);
971 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
973 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
978 version
= gcov_read_unsigned ();
979 if (version
!= GCOV_VERSION
)
983 GCOV_UNSIGNED2STRING (v
, version
);
984 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
986 fnotice (stderr
, "%s:version '%.4s', prefer version '%.4s'\n",
989 tag
= gcov_read_unsigned ();
990 if (tag
!= bbg_stamp
)
992 fnotice (stderr
, "%s:stamp mismatch with graph file\n", da_file_name
);
996 while ((tag
= gcov_read_unsigned ()))
998 unsigned length
= gcov_read_unsigned ();
999 unsigned long base
= gcov_position ();
1001 if (tag
== GCOV_TAG_OBJECT_SUMMARY
)
1002 gcov_read_summary (&object_summary
);
1003 else if (tag
== GCOV_TAG_PROGRAM_SUMMARY
)
1005 else if (tag
== GCOV_TAG_FUNCTION
)
1007 unsigned ident
= gcov_read_unsigned ();
1008 struct function_info
*fn_n
= functions
;
1010 for (fn
= fn
? fn
->next
: NULL
; ; fn
= fn
->next
)
1014 else if ((fn
= fn_n
))
1018 fnotice (stderr
, "%s:unknown function '%u'\n",
1019 da_file_name
, ident
);
1022 if (fn
->ident
== ident
)
1028 else if (gcov_read_unsigned () != fn
->checksum
)
1031 fnotice (stderr
, "%s:profile mismatch for '%s'\n",
1032 da_file_name
, fn
->name
);
1036 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
1038 if (length
!= GCOV_TAG_COUNTER_LENGTH (fn
->num_counts
))
1042 fn
->counts
= xcalloc (fn
->num_counts
, sizeof (gcov_type
));
1044 for (ix
= 0; ix
!= fn
->num_counts
; ix
++)
1045 fn
->counts
[ix
] += gcov_read_counter ();
1047 gcov_sync (base
, length
);
1048 if ((error
= gcov_is_error ()))
1050 fnotice (stderr
, error
< 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1060 /* Solve the flow graph. Propagate counts from the instrumented arcs
1061 to the blocks and the uninstrumented arcs. */
1064 solve_flow_graph (function_t
*fn
)
1068 gcov_type
*count_ptr
= fn
->counts
;
1070 block_t
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
1071 block_t
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
1073 if (fn
->num_blocks
< 2)
1074 fnotice (stderr
, "%s:'%s' lacks entry and/or exit blocks\n",
1075 bbg_file_name
, fn
->name
);
1078 if (fn
->blocks
[0].num_pred
)
1079 fnotice (stderr
, "%s:'%s' has arcs to entry block\n",
1080 bbg_file_name
, fn
->name
);
1082 /* We can't deduce the entry block counts from the lack of
1084 fn
->blocks
[0].num_pred
= ~(unsigned)0;
1086 if (fn
->blocks
[fn
->num_blocks
- 1].num_succ
)
1087 fnotice (stderr
, "%s:'%s' has arcs from exit block\n",
1088 bbg_file_name
, fn
->name
);
1090 /* Likewise, we can't deduce exit block counts from the lack
1091 of its successors. */
1092 fn
->blocks
[fn
->num_blocks
- 1].num_succ
= ~(unsigned)0;
1095 /* Propagate the measured counts, this must be done in the same
1096 order as the code in profile.c */
1097 for (ix
= 0, blk
= fn
->blocks
; ix
!= fn
->num_blocks
; ix
++, blk
++)
1099 block_t
const *prev_dst
= NULL
;
1100 int out_of_order
= 0;
1101 int non_fake_succ
= 0;
1103 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1111 arc
->count
= *count_ptr
++;
1112 arc
->count_valid
= 1;
1114 arc
->dst
->num_pred
--;
1116 if (prev_dst
&& prev_dst
> arc
->dst
)
1118 prev_dst
= arc
->dst
;
1120 if (non_fake_succ
== 1)
1122 /* If there is only one non-fake exit, it is an
1123 unconditional branch. */
1124 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1127 arc
->is_unconditional
= 1;
1128 /* If this block is instrumenting a call, it might be
1129 an artificial block. It is not artificial if it has
1130 a non-fallthrough exit, or the destination of this
1131 arc has more than one entry. Mark the destination
1132 block as a return site, if none of those conditions
1134 if (blk
->is_call_site
&& arc
->fall_through
1135 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
1136 arc
->dst
->is_call_return
= 1;
1140 /* Sort the successor arcs into ascending dst order. profile.c
1141 normally produces arcs in the right order, but sometimes with
1142 one or two out of order. We're not using a particularly
1146 arc_t
*start
= blk
->succ
;
1147 unsigned changes
= 1;
1151 arc_t
*arc
, *arc_p
, *arc_n
;
1154 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
1156 if (arc
->dst
> arc_n
->dst
)
1160 arc_p
->succ_next
= arc_n
;
1163 arc
->succ_next
= arc_n
->succ_next
;
1164 arc_n
->succ_next
= arc
;
1177 /* Place it on the invalid chain, it will be ignored if that's
1179 blk
->invalid_chain
= 1;
1180 blk
->chain
= invalid_blocks
;
1181 invalid_blocks
= blk
;
1184 while (invalid_blocks
|| valid_blocks
)
1186 while ((blk
= invalid_blocks
))
1188 gcov_type total
= 0;
1191 invalid_blocks
= blk
->chain
;
1192 blk
->invalid_chain
= 0;
1194 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1195 total
+= arc
->count
;
1196 else if (!blk
->num_pred
)
1197 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1198 total
+= arc
->count
;
1203 blk
->count_valid
= 1;
1204 blk
->chain
= valid_blocks
;
1205 blk
->valid_chain
= 1;
1208 while ((blk
= valid_blocks
))
1211 arc_t
*arc
, *inv_arc
;
1213 valid_blocks
= blk
->chain
;
1214 blk
->valid_chain
= 0;
1215 if (blk
->num_succ
== 1)
1221 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1223 total
-= arc
->count
;
1224 if (!arc
->count_valid
)
1228 inv_arc
->count_valid
= 1;
1229 inv_arc
->count
= total
;
1232 if (dst
->count_valid
)
1234 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
1236 dst
->chain
= valid_blocks
;
1237 dst
->valid_chain
= 1;
1243 if (!dst
->num_pred
&& !dst
->invalid_chain
)
1245 dst
->chain
= invalid_blocks
;
1246 dst
->invalid_chain
= 1;
1247 invalid_blocks
= dst
;
1251 if (blk
->num_pred
== 1)
1257 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1259 total
-= arc
->count
;
1260 if (!arc
->count_valid
)
1264 inv_arc
->count_valid
= 1;
1265 inv_arc
->count
= total
;
1268 if (src
->count_valid
)
1270 if (src
->num_succ
== 1 && !src
->valid_chain
)
1272 src
->chain
= valid_blocks
;
1273 src
->valid_chain
= 1;
1279 if (!src
->num_succ
&& !src
->invalid_chain
)
1281 src
->chain
= invalid_blocks
;
1282 src
->invalid_chain
= 1;
1283 invalid_blocks
= src
;
1290 /* If the graph has been correctly solved, every block will have a
1292 for (ix
= 0; ix
< fn
->num_blocks
; ix
++)
1293 if (!fn
->blocks
[ix
].count_valid
)
1295 fnotice (stderr
, "%s:graph is unsolvable for '%s'\n",
1296 bbg_file_name
, fn
->name
);
1303 /* Increment totals in COVERAGE according to arc ARC. */
1306 add_branch_counts (coverage_t
*coverage
, const arc_t
*arc
)
1308 if (arc
->is_call_non_return
)
1311 if (arc
->src
->count
)
1312 coverage
->calls_executed
++;
1314 else if (!arc
->is_unconditional
)
1316 coverage
->branches
++;
1317 if (arc
->src
->count
)
1318 coverage
->branches_executed
++;
1320 coverage
->branches_taken
++;
1324 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1325 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1326 If DP is zero, no decimal point is printed. Only print 100% when
1327 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1328 format TOP. Return pointer to a static string. */
1331 format_gcov (gcov_type top
, gcov_type bottom
, int dp
)
1333 static char buffer
[20];
1337 float ratio
= bottom
? (float)top
/ bottom
: 0;
1339 unsigned limit
= 100;
1342 for (ix
= dp
; ix
--; )
1345 percent
= (unsigned) (ratio
* limit
+ (float)0.5);
1346 if (percent
<= 0 && top
)
1348 else if (percent
>= limit
&& top
!= bottom
)
1349 percent
= limit
- 1;
1350 ix
= sprintf (buffer
, "%.*u%%", dp
+ 1, percent
);
1356 buffer
[ix
+1] = buffer
[ix
];
1360 buffer
[ix
+ 1] = '.';
1364 sprintf (buffer
, HOST_WIDEST_INT_PRINT_DEC
, (HOST_WIDEST_INT
)top
);
1370 /* Output summary info for a function. */
1373 function_summary (const coverage_t
*coverage
, const char *title
)
1375 fnotice (stdout
, "%s '%s'\n", title
, coverage
->name
);
1377 if (coverage
->lines
)
1378 fnotice (stdout
, "Lines executed:%s of %d\n",
1379 format_gcov (coverage
->lines_executed
, coverage
->lines
, 2),
1382 fnotice (stdout
, "No executable lines\n");
1386 if (coverage
->branches
)
1388 fnotice (stdout
, "Branches executed:%s of %d\n",
1389 format_gcov (coverage
->branches_executed
,
1390 coverage
->branches
, 2),
1391 coverage
->branches
);
1392 fnotice (stdout
, "Taken at least once:%s of %d\n",
1393 format_gcov (coverage
->branches_taken
,
1394 coverage
->branches
, 2),
1395 coverage
->branches
);
1398 fnotice (stdout
, "No branches\n");
1399 if (coverage
->calls
)
1400 fnotice (stdout
, "Calls executed:%s of %d\n",
1401 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
1404 fnotice (stdout
, "No calls\n");
1408 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1409 affect name generation. With preserve_paths we create a filename
1410 from all path components of the source file, replacing '/' with
1411 '#', without it we simply take the basename component. With
1412 long_output_names we prepend the processed name of the input file
1413 to each output name (except when the current source file is the
1414 input file, so you don't get a double concatenation). The two
1415 components are separated by '##'. Also '.' filename components are
1416 removed and '..' components are renamed to '^'. */
1419 make_gcov_file_name (const char *input_name
, const char *src_name
)
1422 char *name
= xmalloc (strlen (src_name
) + strlen (input_name
) + 10);
1425 if (flag_long_names
&& strcmp (src_name
, input_name
))
1427 /* Generate the input filename part. */
1428 cptr
= flag_preserve_paths
? NULL
: strrchr (input_name
, '/');
1429 strcat (name
, cptr
? cptr
+ 1 : input_name
);
1430 strcat (name
, "##");
1433 /* Generate the source filename part. */
1434 cptr
= flag_preserve_paths
? NULL
: strrchr (src_name
, '/');
1435 strcat (name
, cptr
? cptr
+ 1 : src_name
);
1437 if (flag_preserve_paths
)
1439 /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1442 for (cptr
= name
; (cptr
= strchr ((prev
= cptr
), '/'));)
1446 if (prev
+ 1 == cptr
&& prev
[0] == '.')
1451 else if (prev
+ 2 == cptr
&& prev
[0] == '.' && prev
[1] == '.')
1463 prev
[0] = prev
[shift
];
1469 strcat (name
, ".gcov");
1473 /* Scan through the bb_data for each line in the block, increment
1474 the line number execution count indicated by the execution count of
1475 the appropriate basic block. */
1478 add_line_counts (coverage_t
*coverage
, function_t
*fn
)
1481 line_t
*line
= NULL
; /* This is propagated from one iteration to the
1484 /* Scan each basic block. */
1485 for (ix
= 0; ix
!= fn
->num_blocks
; ix
++)
1487 block_t
*block
= &fn
->blocks
[ix
];
1489 const source_t
*src
= NULL
;
1492 if (block
->count
&& ix
&& ix
+ 1 != fn
->num_blocks
)
1493 fn
->blocks_executed
++;
1494 for (jx
= 0, encoding
= block
->u
.line
.encoding
;
1495 jx
!= block
->u
.line
.num
; jx
++, encoding
++)
1498 unsigned src_n
= *++encoding
;
1500 for (src
= sources
; src
->index
!= src_n
; src
= src
->next
)
1506 line
= &src
->lines
[*encoding
];
1512 if (!line
->count
&& block
->count
)
1513 coverage
->lines_executed
++;
1516 line
->count
+= block
->count
;
1518 free (block
->u
.line
.encoding
);
1519 block
->u
.cycle
.arc
= NULL
;
1520 block
->u
.cycle
.ident
= ~0U;
1522 if (!ix
|| ix
+ 1 == fn
->num_blocks
)
1523 /* Entry or exit block */;
1524 else if (flag_all_blocks
)
1526 line_t
*block_line
= line
? line
: &fn
->src
->lines
[fn
->line
];
1528 block
->chain
= block_line
->u
.blocks
;
1529 block_line
->u
.blocks
= block
;
1531 else if (flag_branches
)
1535 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1537 arc
->line_next
= line
->u
.branches
;
1538 line
->u
.branches
= arc
;
1539 if (coverage
&& !arc
->is_unconditional
)
1540 add_branch_counts (coverage
, arc
);
1545 fnotice (stderr
, "%s:no lines for '%s'\n", bbg_file_name
, fn
->name
);
1548 /* Accumulate the line counts of a file. */
1551 accumulate_line_counts (source_t
*src
)
1554 function_t
*fn
, *fn_p
, *fn_n
;
1557 /* Reverse the function order. */
1558 for (fn
= src
->functions
, fn_p
= NULL
; fn
;
1559 fn_p
= fn
, fn
= fn_n
)
1561 fn_n
= fn
->line_next
;
1562 fn
->line_next
= fn_p
;
1564 src
->functions
= fn_p
;
1566 for (ix
= src
->num_lines
, line
= src
->lines
; ix
--; line
++)
1568 if (!flag_all_blocks
)
1570 arc_t
*arc
, *arc_p
, *arc_n
;
1572 /* Total and reverse the branch information. */
1573 for (arc
= line
->u
.branches
, arc_p
= NULL
; arc
;
1574 arc_p
= arc
, arc
= arc_n
)
1576 arc_n
= arc
->line_next
;
1577 arc
->line_next
= arc_p
;
1579 add_branch_counts (&src
->coverage
, arc
);
1581 line
->u
.branches
= arc_p
;
1583 else if (line
->u
.blocks
)
1585 /* The user expects the line count to be the number of times
1586 a line has been executed. Simply summing the block count
1587 will give an artificially high number. The Right Thing
1588 is to sum the entry counts to the graph of blocks on this
1589 line, then find the elementary cycles of the local graph
1590 and add the transition counts of those cycles. */
1591 block_t
*block
, *block_p
, *block_n
;
1592 gcov_type count
= 0;
1594 /* Reverse the block information. */
1595 for (block
= line
->u
.blocks
, block_p
= NULL
; block
;
1596 block_p
= block
, block
= block_n
)
1598 block_n
= block
->chain
;
1599 block
->chain
= block_p
;
1600 block
->u
.cycle
.ident
= ix
;
1602 line
->u
.blocks
= block_p
;
1604 /* Sum the entry arcs. */
1605 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
1609 for (arc
= block
->pred
; arc
; arc
= arc
->pred_next
)
1611 if (arc
->src
->u
.cycle
.ident
!= ix
)
1612 count
+= arc
->count
;
1614 add_branch_counts (&src
->coverage
, arc
);
1617 /* Initialize the cs_count. */
1618 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1619 arc
->cs_count
= arc
->count
;
1622 /* Find the loops. This uses the algorithm described in
1623 Tiernan 'An Efficient Search Algorithm to Find the
1624 Elementary Circuits of a Graph', CACM Dec 1970. We hold
1625 the P array by having each block point to the arc that
1626 connects to the previous block. The H array is implicitly
1627 held because of the arc ordering, and the block's
1628 previous arc pointer.
1630 Although the algorithm is O(N^3) for highly connected
1631 graphs, at worst we'll have O(N^2), as most blocks have
1632 only one or two exits. Most graphs will be small.
1634 For each loop we find, locate the arc with the smallest
1635 transition count, and add that to the cumulative
1636 count. Decrease flow over the cycle and remove the arc
1637 from consideration. */
1638 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
1640 block_t
*head
= block
;
1648 block_t
*dst
= arc
->dst
;
1649 if (/* Already used that arc. */
1651 /* Not to same graph, or before first vertex. */
1652 || dst
->u
.cycle
.ident
!= ix
1653 /* Already in path. */
1654 || dst
->u
.cycle
.arc
)
1656 arc
= arc
->succ_next
;
1662 /* Found a closing arc. */
1663 gcov_type cycle_count
= arc
->cs_count
;
1664 arc_t
*cycle_arc
= arc
;
1667 /* Locate the smallest arc count of the loop. */
1668 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
1669 dst
= probe_arc
->src
)
1670 if (cycle_count
> probe_arc
->cs_count
)
1672 cycle_count
= probe_arc
->cs_count
;
1673 cycle_arc
= probe_arc
;
1676 count
+= cycle_count
;
1677 cycle_arc
->cycle
= 1;
1679 /* Remove the flow from the cycle. */
1680 arc
->cs_count
-= cycle_count
;
1681 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
1682 dst
= probe_arc
->src
)
1683 probe_arc
->cs_count
-= cycle_count
;
1685 /* Unwind to the cyclic arc. */
1686 while (head
!= cycle_arc
->src
)
1688 arc
= head
->u
.cycle
.arc
;
1689 head
->u
.cycle
.arc
= NULL
;
1693 arc
= arc
->succ_next
;
1697 /* Add new block to chain. */
1698 dst
->u
.cycle
.arc
= arc
;
1702 /* We could not add another vertex to the path. Remove
1703 the last vertex from the list. */
1704 arc
= head
->u
.cycle
.arc
;
1707 /* It was not the first vertex. Move onto next arc. */
1708 head
->u
.cycle
.arc
= NULL
;
1710 arc
= arc
->succ_next
;
1711 goto current_vertex
;
1713 /* Mark this block as unusable. */
1714 block
->u
.cycle
.ident
= ~0U;
1717 line
->count
= count
;
1722 src
->coverage
.lines
++;
1724 src
->coverage
.lines_executed
++;
1729 /* Output information about ARC number IX. Returns nonzero if
1730 anything is output. */
1733 output_branch_count (FILE *gcov_file
, int ix
, const arc_t
*arc
)
1736 if (arc
->is_call_non_return
)
1738 if (arc
->src
->count
)
1740 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
1741 format_gcov (arc
->src
->count
- arc
->count
,
1742 arc
->src
->count
, -flag_counts
));
1745 fnotice (gcov_file
, "call %2d never executed\n", ix
);
1747 else if (!arc
->is_unconditional
)
1749 if (arc
->src
->count
)
1750 fnotice (gcov_file
, "branch %2d taken %s%s\n", ix
,
1751 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
1752 arc
->fall_through
? " (fallthrough)" : "");
1754 fnotice (gcov_file
, "branch %2d never executed\n", ix
);
1756 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
1758 if (arc
->src
->count
)
1759 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
1760 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
1762 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
1770 /* Read in the source file one line at a time, and output that line to
1771 the gcov file preceded by its execution count and other
1775 output_lines (FILE *gcov_file
, const source_t
*src
)
1778 unsigned line_num
; /* current line number. */
1779 const line_t
*line
; /* current line info ptr. */
1780 char string
[STRING_SIZE
]; /* line buffer. */
1781 char const *retval
= ""; /* status of source file reading. */
1782 function_t
*fn
= NULL
;
1784 fprintf (gcov_file
, "%9s:%5d:Source:%s\n", "-", 0, src
->name
);
1785 fprintf (gcov_file
, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name
);
1786 fprintf (gcov_file
, "%9s:%5d:Data:%s\n", "-", 0, da_file_name
);
1787 fprintf (gcov_file
, "%9s:%5d:Runs:%u\n", "-", 0,
1788 object_summary
.ctrs
[GCOV_COUNTER_ARCS
].runs
);
1789 fprintf (gcov_file
, "%9s:%5d:Programs:%u\n", "-", 0, program_count
);
1791 source_file
= fopen (src
->name
, "r");
1794 fnotice (stderr
, "%s:cannot open source file\n", src
->name
);
1801 if (!fstat (fileno (source_file
), &status
)
1802 && status
.st_mtime
> bbg_file_time
)
1804 fnotice (stderr
, "%s:source file is newer than graph file '%s'\n",
1805 src
->name
, bbg_file_name
);
1806 fprintf (gcov_file
, "%9s:%5d:Source is newer than graph\n",
1812 fn
= src
->functions
;
1814 for (line_num
= 1, line
= &src
->lines
[line_num
];
1815 line_num
< src
->num_lines
; line_num
++, line
++)
1817 for (; fn
&& fn
->line
== line_num
; fn
= fn
->line_next
)
1819 arc_t
*arc
= fn
->blocks
[fn
->num_blocks
- 1].pred
;
1820 gcov_type return_count
= fn
->blocks
[fn
->num_blocks
- 1].count
;
1822 for (; arc
; arc
= arc
->pred_next
)
1824 return_count
-= arc
->count
;
1826 fprintf (gcov_file
, "function %s", fn
->name
);
1827 fprintf (gcov_file
, " called %s",
1828 format_gcov (fn
->blocks
[0].count
, 0, -1));
1829 fprintf (gcov_file
, " returned %s",
1830 format_gcov (return_count
, fn
->blocks
[0].count
, 0));
1831 fprintf (gcov_file
, " blocks executed %s",
1832 format_gcov (fn
->blocks_executed
, fn
->num_blocks
- 2, 0));
1833 fprintf (gcov_file
, "\n");
1836 /* For lines which don't exist in the .bb file, print '-' before
1837 the source line. For lines which exist but were never
1838 executed, print '#####' before the source line. Otherwise,
1839 print the execution count before the source line. There are
1840 16 spaces of indentation added before the source line so that
1841 tabs won't be messed up. */
1842 fprintf (gcov_file
, "%9s:%5u:",
1843 !line
->exists
? "-" : !line
->count
? "#####"
1844 : format_gcov (line
->count
, 0, -1), line_num
);
1848 /* Copy source line. */
1851 retval
= fgets (string
, STRING_SIZE
, source_file
);
1854 fputs (retval
, gcov_file
);
1856 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n');
1859 fputs ("/*EOF*/\n", gcov_file
);
1861 if (flag_all_blocks
)
1867 for (ix
= jx
= 0, block
= line
->u
.blocks
; block
;
1868 block
= block
->chain
)
1870 if (!block
->is_call_return
)
1871 fprintf (gcov_file
, "%9s:%5u-block %2d\n",
1872 !line
->exists
? "-" : !block
->count
? "$$$$$"
1873 : format_gcov (block
->count
, 0, -1),
1876 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1877 jx
+= output_branch_count (gcov_file
, jx
, arc
);
1880 else if (flag_branches
)
1885 for (ix
= 0, arc
= line
->u
.branches
; arc
; arc
= arc
->line_next
)
1886 ix
+= output_branch_count (gcov_file
, ix
, arc
);
1890 /* Handle all remaining source lines. There may be lines after the
1891 last line of code. */
1894 for (; (retval
= fgets (string
, STRING_SIZE
, source_file
)); line_num
++)
1896 fprintf (gcov_file
, "%9s:%5u:%s", "-", line_num
, retval
);
1898 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n')
1900 retval
= fgets (string
, STRING_SIZE
, source_file
);
1903 fputs (retval
, gcov_file
);
1909 fclose (source_file
);