1 /* Gcov.c: prepend line execution counts and branch probabilities to a
3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
4 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
5 Free Software Foundation, Inc.
6 Contributed by James E. Wilson of Cygnus Support.
7 Mangled by Bob Manson of Cygnus Support.
8 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
10 Gcov is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3, or (at your option)
15 Gcov is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with Gcov; see the file COPYING3. If not see
22 <http://www.gnu.org/licenses/>. */
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 /* Need an option to show individual block counts, and show
33 probabilities of fall through arcs. */
37 #include "coretypes.h"
40 #include "diagnostic.h"
49 /* The gcno file is generated by -ftest-coverage option. The gcda file is
50 generated by a program compiled with -fprofile-arcs. Their formats
51 are documented in gcov-io.h. */
53 /* The functions in this file for creating and solution program flow graphs
54 are very similar to functions in the gcc source file profile.c. In
55 some places we make use of the knowledge of how profile.c works to
56 select particular algorithms here. */
58 /* The code validates that the profile information read in corresponds
59 to the code currently being compiled. Rather than checking for
60 identical files, the code below computes a checksum on the CFG
61 (based on the order of basic blocks and the arcs in the CFG). If
62 the CFG checksum in the gcda file match the CFG checksum for the
63 code currently being compiled, the profile data will be used. */
65 /* This is the size of the buffer used to read in source file lines. */
67 #define STRING_SIZE 200
73 /* Describes an arc between two basic blocks. */
75 typedef struct arc_info
77 /* source and destination blocks. */
78 struct block_info
*src
;
79 struct block_info
*dst
;
81 /* transition counts. */
83 /* used in cycle search, so that we do not clobber original 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/setjmp. */
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. */
172 unsigned lineno_checksum
;
173 unsigned cfg_checksum
;
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. */
239 /* Array of line information. */
245 /* Functions in this source file. These are in ascending line
247 function_t
*functions
;
249 /* Next source file. */
250 struct source_info
*next
;
253 /* Holds a list of function basic block graphs. */
255 static function_t
*functions
;
257 /* This points to the head of the sourcefile structure list. New elements
258 are always prepended. */
260 static source_t
*sources
;
262 /* Next index for a source file. */
264 static unsigned source_index
;
266 /* This holds data summary information. */
268 static struct gcov_summary object_summary
;
269 static unsigned program_count
;
271 /* Modification time of graph file. */
273 static time_t bbg_file_time
;
275 /* Name and file pointer of the input file for the basic block graph. */
277 static char *bbg_file_name
;
279 /* Stamp of the bbg file */
280 static unsigned bbg_stamp
;
282 /* Name and file pointer of the input file for the arc count data. */
284 static char *da_file_name
;
286 /* Data file is missing. */
288 static int no_data_file
;
290 /* If there is several input files, compute and display results after
291 reading all data files. This way if two or more gcda file refer to
292 the same source file (eg inline subprograms in a .h file), the
295 static int multiple_files
= 0;
297 /* Output branch probabilities. */
299 static int flag_branches
= 0;
301 /* Show unconditional branches too. */
302 static int flag_unconditional
= 0;
304 /* Output a gcov file if this is true. This is on by default, and can
305 be turned off by the -n option. */
307 static int flag_gcov_file
= 1;
309 /* Output progress indication if this is true. This is off by default
310 and can be turned on by the -d option. */
312 static int flag_display_progress
= 0;
314 /* For included files, make the gcov output file name include the name
315 of the input source file. For example, if x.h is included in a.c,
316 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
318 static int flag_long_names
= 0;
320 /* Output count information for every basic block, not merely those
321 that contain line number information. */
323 static int flag_all_blocks
= 0;
325 /* Output summary info for each function. */
327 static int flag_function_summary
= 0;
329 /* Object directory file prefix. This is the directory/file where the
330 graph and data files are looked for, if nonzero. */
332 static char *object_directory
= 0;
334 /* Preserve all pathname components. Needed when object files and
335 source files are in subdirectories. '/' is mangled as '#', '.' is
336 elided and '..' mangled to '^'. */
338 static int flag_preserve_paths
= 0;
340 /* Output the number of times a branch was taken as opposed to the percentage
341 of times it was taken. */
343 static int flag_counts
= 0;
345 /* Forward declarations. */
346 static int process_args (int, char **);
347 static void print_usage (int) ATTRIBUTE_NORETURN
;
348 static void print_version (void) ATTRIBUTE_NORETURN
;
349 static void process_file (const char *);
350 static void generate_results (const char *);
351 static void create_file_names (const char *);
352 static source_t
*find_source (const char *);
353 static int read_graph_file (void);
354 static int read_count_file (void);
355 static void solve_flow_graph (function_t
*);
356 static void add_branch_counts (coverage_t
*, const arc_t
*);
357 static void add_line_counts (coverage_t
*, function_t
*);
358 static void function_summary (const coverage_t
*, const char *);
359 static const char *format_gcov (gcov_type
, gcov_type
, int);
360 static void accumulate_line_counts (source_t
*);
361 static int output_branch_count (FILE *, int, const arc_t
*);
362 static void output_lines (FILE *, const source_t
*);
363 static char *make_gcov_file_name (const char *, const char *);
364 static void release_structures (void);
365 extern int main (int, char **);
368 main (int argc
, char **argv
)
374 p
= argv
[0] + strlen (argv
[0]);
375 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
379 xmalloc_set_program_name (progname
);
381 /* Unlock the stdio streams. */
382 unlock_std_streams ();
386 diagnostic_initialize (global_dc
, 0);
388 /* Handle response files. */
389 expandargv (&argc
, &argv
);
391 argno
= process_args (argc
, argv
);
395 if (argc
- argno
> 1)
400 for (; argno
!= argc
; argno
++)
402 if (flag_display_progress
)
403 printf("Processing file %d out of %d\n",
404 argno
- first_arg
+ 1, argc
- first_arg
);
405 process_file (argv
[argno
]);
408 generate_results (multiple_files
? NULL
: argv
[argc
- 1]);
410 release_structures ();
415 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
416 otherwise the output of --help. */
419 print_usage (int error_p
)
421 FILE *file
= error_p
? stderr
: stdout
;
422 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
424 fnotice (file
, "Usage: gcov [OPTION]... SOURCEFILE...\n\n");
425 fnotice (file
, "Print code coverage information.\n\n");
426 fnotice (file
, " -h, --help Print this help, then exit\n");
427 fnotice (file
, " -v, --version Print version number, then exit\n");
428 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
429 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
430 fnotice (file
, " -c, --branch-counts Given counts of branches taken\n\
431 rather than percentages\n");
432 fnotice (file
, " -n, --no-output Do not create an output file\n");
433 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
435 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
436 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
437 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
438 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
439 fnotice (file
, " -d, --display-progress Display progress information\n");
440 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
445 /* Print version information and exit. */
450 fnotice (stdout
, "gcov %s%s\n", pkgversion_string
, version_string
);
451 fprintf (stdout
, "Copyright %s 2011 Free Software Foundation, Inc.\n",
454 _("This is free software; see the source for copying conditions.\n"
455 "There is NO warranty; not even for MERCHANTABILITY or \n"
456 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
457 exit (SUCCESS_EXIT_CODE
);
460 static const struct option options
[] =
462 { "help", no_argument
, NULL
, 'h' },
463 { "version", no_argument
, NULL
, 'v' },
464 { "all-blocks", no_argument
, NULL
, 'a' },
465 { "branch-probabilities", no_argument
, NULL
, 'b' },
466 { "branch-counts", no_argument
, NULL
, 'c' },
467 { "no-output", no_argument
, NULL
, 'n' },
468 { "long-file-names", no_argument
, NULL
, 'l' },
469 { "function-summaries", no_argument
, NULL
, 'f' },
470 { "preserve-paths", no_argument
, NULL
, 'p' },
471 { "object-directory", required_argument
, NULL
, 'o' },
472 { "object-file", required_argument
, NULL
, 'o' },
473 { "unconditional-branches", no_argument
, NULL
, 'u' },
474 { "display-progress", no_argument
, NULL
, 'd' },
478 /* Process args, return index to first non-arg. */
481 process_args (int argc
, char **argv
)
485 while ((opt
= getopt_long (argc
, argv
, "abcdfhlno:puv", options
, NULL
)) != -1)
499 flag_function_summary
= 1;
503 /* print_usage will exit. */
511 object_directory
= optarg
;
514 flag_preserve_paths
= 1;
517 flag_unconditional
= 1;
520 flag_display_progress
= 1;
524 /* print_version will exit. */
527 /* print_usage will exit. */
534 /* Process a single source file. */
537 process_file (const char *file_name
)
541 function_t
*old_functions
;
543 /* Save and clear the list of current functions. They will be appended
545 old_functions
= functions
;
548 create_file_names (file_name
);
549 if (read_graph_file ())
554 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
558 if (read_count_file ())
561 for (fn_p
= NULL
, fn
= functions
; fn
; fn_p
= fn
, fn
= fn
->next
)
562 solve_flow_graph (fn
);
565 fn_p
->next
= old_functions
;
569 generate_results (const char *file_name
)
574 for (src
= sources
; src
; src
= src
->next
)
575 src
->lines
= XCNEWVEC (line_t
, src
->num_lines
);
576 for (fn
= functions
; fn
; fn
= fn
->next
)
580 memset (&coverage
, 0, sizeof (coverage
));
581 coverage
.name
= fn
->name
;
582 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
583 if (flag_function_summary
)
585 function_summary (&coverage
, "Function");
586 fnotice (stdout
, "\n");
590 for (src
= sources
; src
; src
= src
->next
)
592 accumulate_line_counts (src
);
593 function_summary (&src
->coverage
, "File");
596 char *gcov_file_name
= make_gcov_file_name (file_name
, src
->name
);
597 FILE *gcov_file
= fopen (gcov_file_name
, "w");
601 fnotice (stdout
, "%s:creating '%s'\n",
602 src
->name
, gcov_file_name
);
603 output_lines (gcov_file
, src
);
604 if (ferror (gcov_file
))
605 fnotice (stderr
, "%s:error writing output file '%s'\n",
606 src
->name
, gcov_file_name
);
610 fnotice (stderr
, "%s:could not open output file '%s'\n",
611 src
->name
, gcov_file_name
);
612 free (gcov_file_name
);
614 fnotice (stdout
, "\n");
618 /* Release all memory used. */
621 release_structures (void)
626 while ((src
= sources
))
634 while ((fn
= functions
))
639 functions
= fn
->next
;
640 for (ix
= fn
->num_blocks
, block
= fn
->blocks
; ix
--; block
++)
644 for (arc
= block
->succ
; arc
; arc
= arc_n
)
646 arc_n
= arc
->succ_next
;
655 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
656 is not specified, these are named from FILE_NAME sans extension. If
657 OBJECT_DIRECTORY is specified and is a directory, the files are in that
658 directory, but named from the basename of the FILE_NAME, sans extension.
659 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
660 and the data files are named from that. */
663 create_file_names (const char *file_name
)
667 int length
= strlen (file_name
);
670 /* Free previous file names. */
671 free (bbg_file_name
);
673 da_file_name
= bbg_file_name
= NULL
;
677 if (object_directory
&& object_directory
[0])
681 length
+= strlen (object_directory
) + 2;
682 name
= XNEWVEC (char, length
);
685 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
686 strcat (name
, object_directory
);
687 if (base
&& (! IS_DIR_SEPARATOR (name
[strlen (name
) - 1])))
692 name
= XNEWVEC (char, length
+ 1);
693 strcpy (name
, file_name
);
699 /* Append source file name. */
700 const char *cptr
= lbasename (file_name
);
701 strcat (name
, cptr
? cptr
: file_name
);
704 /* Remove the extension. */
705 cptr
= strrchr (name
, '.');
709 length
= strlen (name
);
711 bbg_file_name
= XNEWVEC (char, length
+ strlen (GCOV_NOTE_SUFFIX
) + 1);
712 strcpy (bbg_file_name
, name
);
713 strcpy (bbg_file_name
+ length
, GCOV_NOTE_SUFFIX
);
715 da_file_name
= XNEWVEC (char, length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
716 strcpy (da_file_name
, name
);
717 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
723 /* Find or create a source file structure for FILE_NAME. Copies
724 FILE_NAME on creation */
727 find_source (const char *file_name
)
733 file_name
= "<unknown>";
735 for (src
= sources
; src
; src
= src
->next
)
736 if (!filename_cmp (file_name
, src
->name
))
741 src
= XCNEW (source_t
);
742 src
->name
= xstrdup (file_name
);
743 src
->coverage
.name
= src
->name
;
744 src
->index
= source_index
++;
748 if (!stat (file_name
, &status
))
749 src
->file_time
= status
.st_mtime
;
752 if (src
->file_time
> bbg_file_time
)
754 static int info_emitted
;
756 fnotice (stderr
, "%s:source file is newer than graph file '%s'\n",
757 src
->name
, bbg_file_name
);
761 "(the message is only displayed one per source file)\n");
770 /* Read the graph file. Return nonzero on fatal error. */
773 read_graph_file (void)
776 unsigned current_tag
= 0;
777 struct function_info
*fn
= NULL
;
778 function_t
*old_functions_head
= functions
;
779 source_t
*src
= NULL
;
783 if (!gcov_open (bbg_file_name
, 1))
785 fnotice (stderr
, "%s:cannot open graph file\n", bbg_file_name
);
788 bbg_file_time
= gcov_time ();
789 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC
))
791 fnotice (stderr
, "%s:not a gcov graph file\n", bbg_file_name
);
796 version
= gcov_read_unsigned ();
797 if (version
!= GCOV_VERSION
)
801 GCOV_UNSIGNED2STRING (v
, version
);
802 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
804 fnotice (stderr
, "%s:version '%.4s', prefer '%.4s'\n",
805 bbg_file_name
, v
, e
);
807 bbg_stamp
= gcov_read_unsigned ();
809 while ((tag
= gcov_read_unsigned ()))
811 unsigned length
= gcov_read_unsigned ();
812 gcov_position_t base
= gcov_position ();
814 if (tag
== GCOV_TAG_FUNCTION
)
817 unsigned ident
, lineno
;
818 unsigned lineno_checksum
, cfg_checksum
;
820 function_t
*probe
, *prev
;
822 ident
= gcov_read_unsigned ();
823 lineno_checksum
= gcov_read_unsigned ();
824 cfg_checksum
= gcov_read_unsigned ();
825 function_name
= xstrdup (gcov_read_string ());
826 src
= find_source (gcov_read_string ());
827 lineno
= gcov_read_unsigned ();
829 fn
= XCNEW (function_t
);
830 fn
->name
= function_name
;
832 fn
->lineno_checksum
= lineno_checksum
;
833 fn
->cfg_checksum
= cfg_checksum
;
837 fn
->next
= functions
;
841 if (lineno
>= src
->num_lines
)
842 src
->num_lines
= lineno
+ 1;
843 /* Now insert it into the source file's list of
844 functions. Normally functions will be encountered in
845 ascending order, so a simple scan is quick. */
846 for (probe
= src
->functions
, prev
= NULL
;
847 probe
&& probe
->line
> lineno
;
848 prev
= probe
, probe
= probe
->line_next
)
850 fn
->line_next
= probe
;
852 prev
->line_next
= fn
;
856 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
859 fnotice (stderr
, "%s:already seen blocks for '%s'\n",
860 bbg_file_name
, fn
->name
);
863 unsigned ix
, num_blocks
= GCOV_TAG_BLOCKS_NUM (length
);
864 fn
->num_blocks
= num_blocks
;
866 fn
->blocks
= XCNEWVEC (block_t
, fn
->num_blocks
);
867 for (ix
= 0; ix
!= num_blocks
; ix
++)
868 fn
->blocks
[ix
].flags
= gcov_read_unsigned ();
871 else if (fn
&& tag
== GCOV_TAG_ARCS
)
873 unsigned src
= gcov_read_unsigned ();
874 unsigned num_dests
= GCOV_TAG_ARCS_NUM (length
);
876 if (src
>= fn
->num_blocks
|| fn
->blocks
[src
].succ
)
881 struct arc_info
*arc
;
882 unsigned dest
= gcov_read_unsigned ();
883 unsigned flags
= gcov_read_unsigned ();
885 if (dest
>= fn
->num_blocks
)
889 arc
->dst
= &fn
->blocks
[dest
];
890 arc
->src
= &fn
->blocks
[src
];
893 arc
->count_valid
= 0;
894 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
895 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
896 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
898 arc
->succ_next
= fn
->blocks
[src
].succ
;
899 fn
->blocks
[src
].succ
= arc
;
900 fn
->blocks
[src
].num_succ
++;
902 arc
->pred_next
= fn
->blocks
[dest
].pred
;
903 fn
->blocks
[dest
].pred
= arc
;
904 fn
->blocks
[dest
].num_pred
++;
910 /* Exceptional exit from this function, the
911 source block must be a call. */
912 fn
->blocks
[src
].is_call_site
= 1;
913 arc
->is_call_non_return
= 1;
917 /* Non-local return from a callee of this
918 function. The destination block is a catch or
920 arc
->is_nonlocal_return
= 1;
921 fn
->blocks
[dest
].is_nonlocal_return
= 1;
929 else if (fn
&& tag
== GCOV_TAG_LINES
)
931 unsigned blockno
= gcov_read_unsigned ();
932 unsigned *line_nos
= XCNEWVEC (unsigned, length
- 1);
934 if (blockno
>= fn
->num_blocks
|| fn
->blocks
[blockno
].u
.line
.encoding
)
939 unsigned lineno
= gcov_read_unsigned ();
946 line_nos
[ix
++] = src
->index
;
948 line_nos
[ix
++] = lineno
;
949 if (lineno
>= src
->num_lines
)
950 src
->num_lines
= lineno
+ 1;
954 const char *file_name
= gcov_read_string ();
958 src
= find_source (file_name
);
961 line_nos
[ix
++] = src
->index
;
965 fn
->blocks
[blockno
].u
.line
.encoding
= line_nos
;
966 fn
->blocks
[blockno
].u
.line
.num
= ix
;
968 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
973 gcov_sync (base
, length
);
974 if (gcov_is_error ())
977 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
984 /* We built everything backwards, so nreverse them all. */
986 /* Reverse sources. Not strictly necessary, but we'll then process
987 them in the 'expected' order. */
989 source_t
*src
, *src_p
, *src_n
;
991 for (src_p
= NULL
, src
= sources
; src
; src_p
= src
, src
= src_n
)
999 /* Reverse functions. */
1001 function_t
*fn
, *fn_p
, *fn_n
;
1003 for (fn_p
= old_functions_head
, fn
= functions
;
1004 fn
!= old_functions_head
;
1005 fn_p
= fn
, fn
= fn_n
)
1012 /* Reverse the arcs. */
1013 for (ix
= fn
->num_blocks
; ix
--;)
1015 arc_t
*arc
, *arc_p
, *arc_n
;
1017 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
1018 arc_p
= arc
, arc
= arc_n
)
1020 arc_n
= arc
->succ_next
;
1021 arc
->succ_next
= arc_p
;
1023 fn
->blocks
[ix
].succ
= arc_p
;
1025 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
1026 arc_p
= arc
, arc
= arc_n
)
1028 arc_n
= arc
->pred_next
;
1029 arc
->pred_next
= arc_p
;
1031 fn
->blocks
[ix
].pred
= arc_p
;
1039 /* Reads profiles from the count file and attach to each
1040 function. Return nonzero if fatal error. */
1043 read_count_file (void)
1048 function_t
*fn
= NULL
;
1051 if (!gcov_open (da_file_name
, 1))
1053 fnotice (stderr
, "%s:cannot open data file, assuming not executed\n",
1058 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
1060 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
1065 version
= gcov_read_unsigned ();
1066 if (version
!= GCOV_VERSION
)
1070 GCOV_UNSIGNED2STRING (v
, version
);
1071 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1073 fnotice (stderr
, "%s:version '%.4s', prefer version '%.4s'\n",
1074 da_file_name
, v
, e
);
1076 tag
= gcov_read_unsigned ();
1077 if (tag
!= bbg_stamp
)
1079 fnotice (stderr
, "%s:stamp mismatch with graph file\n", da_file_name
);
1083 while ((tag
= gcov_read_unsigned ()))
1085 unsigned length
= gcov_read_unsigned ();
1086 unsigned long base
= gcov_position ();
1088 if (tag
== GCOV_TAG_OBJECT_SUMMARY
)
1089 gcov_read_summary (&object_summary
);
1090 else if (tag
== GCOV_TAG_PROGRAM_SUMMARY
)
1092 else if (tag
== GCOV_TAG_FUNCTION
)
1095 unsigned ident
= gcov_read_unsigned ();
1096 struct function_info
*fn_n
= functions
;
1098 /* Try to find the function in the list.
1099 To speed up the search, first start from the last function
1101 for (fn
= fn
? fn
->next
: NULL
; ; fn
= fn
->next
)
1105 else if ((fn
= fn_n
))
1109 fnotice (stderr
, "%s:unknown function '%u'\n",
1110 da_file_name
, ident
);
1113 if (fn
->ident
== ident
)
1120 else if (gcov_read_unsigned () != fn
->lineno_checksum
1121 || gcov_read_unsigned () != fn
->cfg_checksum
)
1124 fnotice (stderr
, "%s:profile mismatch for '%s'\n",
1125 da_file_name
, fn
->name
);
1129 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
1131 if (length
!= GCOV_TAG_COUNTER_LENGTH (fn
->num_counts
))
1135 fn
->counts
= XCNEWVEC (gcov_type
, fn
->num_counts
);
1137 for (ix
= 0; ix
!= fn
->num_counts
; ix
++)
1138 fn
->counts
[ix
] += gcov_read_counter ();
1140 gcov_sync (base
, length
);
1141 if ((error
= gcov_is_error ()))
1143 fnotice (stderr
, error
< 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1153 /* Solve the flow graph. Propagate counts from the instrumented arcs
1154 to the blocks and the uninstrumented arcs. */
1157 solve_flow_graph (function_t
*fn
)
1161 gcov_type
*count_ptr
= fn
->counts
;
1163 block_t
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
1164 block_t
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
1166 if (fn
->num_blocks
< 2)
1167 fnotice (stderr
, "%s:'%s' lacks entry and/or exit blocks\n",
1168 bbg_file_name
, fn
->name
);
1171 if (fn
->blocks
[0].num_pred
)
1172 fnotice (stderr
, "%s:'%s' has arcs to entry block\n",
1173 bbg_file_name
, fn
->name
);
1175 /* We can't deduce the entry block counts from the lack of
1177 fn
->blocks
[0].num_pred
= ~(unsigned)0;
1179 if (fn
->blocks
[fn
->num_blocks
- 1].num_succ
)
1180 fnotice (stderr
, "%s:'%s' has arcs from exit block\n",
1181 bbg_file_name
, fn
->name
);
1183 /* Likewise, we can't deduce exit block counts from the lack
1184 of its successors. */
1185 fn
->blocks
[fn
->num_blocks
- 1].num_succ
= ~(unsigned)0;
1188 /* Propagate the measured counts, this must be done in the same
1189 order as the code in profile.c */
1190 for (ix
= 0, blk
= fn
->blocks
; ix
!= fn
->num_blocks
; ix
++, blk
++)
1192 block_t
const *prev_dst
= NULL
;
1193 int out_of_order
= 0;
1194 int non_fake_succ
= 0;
1196 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1204 arc
->count
= *count_ptr
++;
1205 arc
->count_valid
= 1;
1207 arc
->dst
->num_pred
--;
1209 if (prev_dst
&& prev_dst
> arc
->dst
)
1211 prev_dst
= arc
->dst
;
1213 if (non_fake_succ
== 1)
1215 /* If there is only one non-fake exit, it is an
1216 unconditional branch. */
1217 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1220 arc
->is_unconditional
= 1;
1221 /* If this block is instrumenting a call, it might be
1222 an artificial block. It is not artificial if it has
1223 a non-fallthrough exit, or the destination of this
1224 arc has more than one entry. Mark the destination
1225 block as a return site, if none of those conditions
1227 if (blk
->is_call_site
&& arc
->fall_through
1228 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
1229 arc
->dst
->is_call_return
= 1;
1233 /* Sort the successor arcs into ascending dst order. profile.c
1234 normally produces arcs in the right order, but sometimes with
1235 one or two out of order. We're not using a particularly
1239 arc_t
*start
= blk
->succ
;
1240 unsigned changes
= 1;
1244 arc_t
*arc
, *arc_p
, *arc_n
;
1247 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
1249 if (arc
->dst
> arc_n
->dst
)
1253 arc_p
->succ_next
= arc_n
;
1256 arc
->succ_next
= arc_n
->succ_next
;
1257 arc_n
->succ_next
= arc
;
1270 /* Place it on the invalid chain, it will be ignored if that's
1272 blk
->invalid_chain
= 1;
1273 blk
->chain
= invalid_blocks
;
1274 invalid_blocks
= blk
;
1277 while (invalid_blocks
|| valid_blocks
)
1279 while ((blk
= invalid_blocks
))
1281 gcov_type total
= 0;
1284 invalid_blocks
= blk
->chain
;
1285 blk
->invalid_chain
= 0;
1287 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1288 total
+= arc
->count
;
1289 else if (!blk
->num_pred
)
1290 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1291 total
+= arc
->count
;
1296 blk
->count_valid
= 1;
1297 blk
->chain
= valid_blocks
;
1298 blk
->valid_chain
= 1;
1301 while ((blk
= valid_blocks
))
1304 arc_t
*arc
, *inv_arc
;
1306 valid_blocks
= blk
->chain
;
1307 blk
->valid_chain
= 0;
1308 if (blk
->num_succ
== 1)
1314 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1316 total
-= arc
->count
;
1317 if (!arc
->count_valid
)
1321 inv_arc
->count_valid
= 1;
1322 inv_arc
->count
= total
;
1325 if (dst
->count_valid
)
1327 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
1329 dst
->chain
= valid_blocks
;
1330 dst
->valid_chain
= 1;
1336 if (!dst
->num_pred
&& !dst
->invalid_chain
)
1338 dst
->chain
= invalid_blocks
;
1339 dst
->invalid_chain
= 1;
1340 invalid_blocks
= dst
;
1344 if (blk
->num_pred
== 1)
1350 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1352 total
-= arc
->count
;
1353 if (!arc
->count_valid
)
1357 inv_arc
->count_valid
= 1;
1358 inv_arc
->count
= total
;
1361 if (src
->count_valid
)
1363 if (src
->num_succ
== 1 && !src
->valid_chain
)
1365 src
->chain
= valid_blocks
;
1366 src
->valid_chain
= 1;
1372 if (!src
->num_succ
&& !src
->invalid_chain
)
1374 src
->chain
= invalid_blocks
;
1375 src
->invalid_chain
= 1;
1376 invalid_blocks
= src
;
1383 /* If the graph has been correctly solved, every block will have a
1385 for (ix
= 0; ix
< fn
->num_blocks
; ix
++)
1386 if (!fn
->blocks
[ix
].count_valid
)
1388 fnotice (stderr
, "%s:graph is unsolvable for '%s'\n",
1389 bbg_file_name
, fn
->name
);
1396 /* Increment totals in COVERAGE according to arc ARC. */
1399 add_branch_counts (coverage_t
*coverage
, const arc_t
*arc
)
1401 if (arc
->is_call_non_return
)
1404 if (arc
->src
->count
)
1405 coverage
->calls_executed
++;
1407 else if (!arc
->is_unconditional
)
1409 coverage
->branches
++;
1410 if (arc
->src
->count
)
1411 coverage
->branches_executed
++;
1413 coverage
->branches_taken
++;
1417 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1418 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1419 If DP is zero, no decimal point is printed. Only print 100% when
1420 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1421 format TOP. Return pointer to a static string. */
1424 format_gcov (gcov_type top
, gcov_type bottom
, int dp
)
1426 static char buffer
[20];
1430 float ratio
= bottom
? (float)top
/ bottom
: 0;
1432 unsigned limit
= 100;
1435 for (ix
= dp
; ix
--; )
1438 percent
= (unsigned) (ratio
* limit
+ (float)0.5);
1439 if (percent
<= 0 && top
)
1441 else if (percent
>= limit
&& top
!= bottom
)
1442 percent
= limit
- 1;
1443 ix
= sprintf (buffer
, "%.*u%%", dp
+ 1, percent
);
1449 buffer
[ix
+1] = buffer
[ix
];
1453 buffer
[ix
+ 1] = '.';
1457 sprintf (buffer
, HOST_WIDEST_INT_PRINT_DEC
, (HOST_WIDEST_INT
)top
);
1463 /* Output summary info for a function. */
1466 function_summary (const coverage_t
*coverage
, const char *title
)
1468 fnotice (stdout
, "%s '%s'\n", title
, coverage
->name
);
1470 if (coverage
->lines
)
1471 fnotice (stdout
, "Lines executed:%s of %d\n",
1472 format_gcov (coverage
->lines_executed
, coverage
->lines
, 2),
1475 fnotice (stdout
, "No executable lines\n");
1479 if (coverage
->branches
)
1481 fnotice (stdout
, "Branches executed:%s of %d\n",
1482 format_gcov (coverage
->branches_executed
,
1483 coverage
->branches
, 2),
1484 coverage
->branches
);
1485 fnotice (stdout
, "Taken at least once:%s of %d\n",
1486 format_gcov (coverage
->branches_taken
,
1487 coverage
->branches
, 2),
1488 coverage
->branches
);
1491 fnotice (stdout
, "No branches\n");
1492 if (coverage
->calls
)
1493 fnotice (stdout
, "Calls executed:%s of %d\n",
1494 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
1497 fnotice (stdout
, "No calls\n");
1501 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1502 affect name generation. With preserve_paths we create a filename
1503 from all path components of the source file, replacing '/' with
1504 '#', without it we simply take the basename component. With
1505 long_output_names we prepend the processed name of the input file
1506 to each output name (except when the current source file is the
1507 input file, so you don't get a double concatenation). The two
1508 components are separated by '##'. Also '.' filename components are
1509 removed and '..' components are renamed to '^'. */
1512 make_gcov_file_name (const char *input_name
, const char *src_name
)
1517 if (flag_long_names
&& input_name
&& strcmp (src_name
, input_name
))
1519 name
= XNEWVEC (char, strlen (src_name
) + strlen (input_name
) + 10);
1521 /* Generate the input filename part. */
1522 cptr
= flag_preserve_paths
? NULL
: lbasename (input_name
);
1523 strcat (name
, cptr
? cptr
: input_name
);
1524 strcat (name
, "##");
1528 name
= XNEWVEC (char, strlen (src_name
) + 10);
1532 /* Generate the source filename part. */
1534 cptr
= flag_preserve_paths
? NULL
: lbasename (src_name
);
1535 strcat (name
, cptr
? cptr
: src_name
);
1537 if (flag_preserve_paths
)
1539 /* Convert '/' and '\' to '#', remove '/./', convert '/../' to '#^#',
1540 convert ':' to '~' on DOS based file system. */
1541 char *pnew
= name
, *pold
= name
;
1543 /* First check for leading drive separator. */
1545 while (*pold
!= '\0')
1547 #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
1556 && (strstr (pold
, "/./") == pold
1557 || strstr (pold
, "/.\\") == pold
))
1559 && (strstr (pold
, "\\.\\") == pold
1560 || strstr (pold
, "\\./") == pold
)))
1562 else if (*pold
== '/'
1563 && (strstr (pold
, "/../") == pold
1564 || strstr (pold
, "/..\\") == pold
))
1566 strcpy (pnew
, "#^#");
1570 else if (*pold
== '\\'
1571 && (strstr (pold
, "\\..\\") == pold
1572 || strstr (pold
, "\\../") == pold
))
1574 strcpy (pnew
, "#^#");
1578 else if (*pold
== '/' || *pold
== '\\')
1590 strcat (name
, ".gcov");
1594 /* Scan through the bb_data for each line in the block, increment
1595 the line number execution count indicated by the execution count of
1596 the appropriate basic block. */
1599 add_line_counts (coverage_t
*coverage
, function_t
*fn
)
1602 line_t
*line
= NULL
; /* This is propagated from one iteration to the
1605 /* Scan each basic block. */
1606 for (ix
= 0; ix
!= fn
->num_blocks
; ix
++)
1608 block_t
*block
= &fn
->blocks
[ix
];
1610 const source_t
*src
= NULL
;
1613 if (block
->count
&& ix
&& ix
+ 1 != fn
->num_blocks
)
1614 fn
->blocks_executed
++;
1615 for (jx
= 0, encoding
= block
->u
.line
.encoding
;
1616 jx
!= block
->u
.line
.num
; jx
++, encoding
++)
1619 unsigned src_n
= *++encoding
;
1621 for (src
= sources
; src
->index
!= src_n
; src
= src
->next
)
1627 line
= &src
->lines
[*encoding
];
1633 if (!line
->count
&& block
->count
)
1634 coverage
->lines_executed
++;
1637 line
->count
+= block
->count
;
1639 free (block
->u
.line
.encoding
);
1640 block
->u
.cycle
.arc
= NULL
;
1641 block
->u
.cycle
.ident
= ~0U;
1643 if (!ix
|| ix
+ 1 == fn
->num_blocks
)
1644 /* Entry or exit block */;
1645 else if (flag_all_blocks
)
1647 line_t
*block_line
= line
? line
: &fn
->src
->lines
[fn
->line
];
1649 block
->chain
= block_line
->u
.blocks
;
1650 block_line
->u
.blocks
= block
;
1652 else if (flag_branches
)
1656 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1658 arc
->line_next
= line
->u
.branches
;
1659 line
->u
.branches
= arc
;
1660 if (coverage
&& !arc
->is_unconditional
)
1661 add_branch_counts (coverage
, arc
);
1666 fnotice (stderr
, "%s:no lines for '%s'\n", bbg_file_name
, fn
->name
);
1669 /* Accumulate the line counts of a file. */
1672 accumulate_line_counts (source_t
*src
)
1675 function_t
*fn
, *fn_p
, *fn_n
;
1678 /* Reverse the function order. */
1679 for (fn
= src
->functions
, fn_p
= NULL
; fn
;
1680 fn_p
= fn
, fn
= fn_n
)
1682 fn_n
= fn
->line_next
;
1683 fn
->line_next
= fn_p
;
1685 src
->functions
= fn_p
;
1687 for (ix
= src
->num_lines
, line
= src
->lines
; ix
--; line
++)
1689 if (!flag_all_blocks
)
1691 arc_t
*arc
, *arc_p
, *arc_n
;
1693 /* Total and reverse the branch information. */
1694 for (arc
= line
->u
.branches
, arc_p
= NULL
; arc
;
1695 arc_p
= arc
, arc
= arc_n
)
1697 arc_n
= arc
->line_next
;
1698 arc
->line_next
= arc_p
;
1700 add_branch_counts (&src
->coverage
, arc
);
1702 line
->u
.branches
= arc_p
;
1704 else if (line
->u
.blocks
)
1706 /* The user expects the line count to be the number of times
1707 a line has been executed. Simply summing the block count
1708 will give an artificially high number. The Right Thing
1709 is to sum the entry counts to the graph of blocks on this
1710 line, then find the elementary cycles of the local graph
1711 and add the transition counts of those cycles. */
1712 block_t
*block
, *block_p
, *block_n
;
1713 gcov_type count
= 0;
1715 /* Reverse the block information. */
1716 for (block
= line
->u
.blocks
, block_p
= NULL
; block
;
1717 block_p
= block
, block
= block_n
)
1719 block_n
= block
->chain
;
1720 block
->chain
= block_p
;
1721 block
->u
.cycle
.ident
= ix
;
1723 line
->u
.blocks
= block_p
;
1725 /* Sum the entry arcs. */
1726 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
1730 for (arc
= block
->pred
; arc
; arc
= arc
->pred_next
)
1732 if (arc
->src
->u
.cycle
.ident
!= ix
)
1733 count
+= arc
->count
;
1735 add_branch_counts (&src
->coverage
, arc
);
1738 /* Initialize the cs_count. */
1739 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1740 arc
->cs_count
= arc
->count
;
1743 /* Find the loops. This uses the algorithm described in
1744 Tiernan 'An Efficient Search Algorithm to Find the
1745 Elementary Circuits of a Graph', CACM Dec 1970. We hold
1746 the P array by having each block point to the arc that
1747 connects to the previous block. The H array is implicitly
1748 held because of the arc ordering, and the block's
1749 previous arc pointer.
1751 Although the algorithm is O(N^3) for highly connected
1752 graphs, at worst we'll have O(N^2), as most blocks have
1753 only one or two exits. Most graphs will be small.
1755 For each loop we find, locate the arc with the smallest
1756 transition count, and add that to the cumulative
1757 count. Decrease flow over the cycle and remove the arc
1758 from consideration. */
1759 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
1761 block_t
*head
= block
;
1769 block_t
*dst
= arc
->dst
;
1770 if (/* Already used that arc. */
1772 /* Not to same graph, or before first vertex. */
1773 || dst
->u
.cycle
.ident
!= ix
1774 /* Already in path. */
1775 || dst
->u
.cycle
.arc
)
1777 arc
= arc
->succ_next
;
1783 /* Found a closing arc. */
1784 gcov_type cycle_count
= arc
->cs_count
;
1785 arc_t
*cycle_arc
= arc
;
1788 /* Locate the smallest arc count of the loop. */
1789 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
1790 dst
= probe_arc
->src
)
1791 if (cycle_count
> probe_arc
->cs_count
)
1793 cycle_count
= probe_arc
->cs_count
;
1794 cycle_arc
= probe_arc
;
1797 count
+= cycle_count
;
1798 cycle_arc
->cycle
= 1;
1800 /* Remove the flow from the cycle. */
1801 arc
->cs_count
-= cycle_count
;
1802 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
1803 dst
= probe_arc
->src
)
1804 probe_arc
->cs_count
-= cycle_count
;
1806 /* Unwind to the cyclic arc. */
1807 while (head
!= cycle_arc
->src
)
1809 arc
= head
->u
.cycle
.arc
;
1810 head
->u
.cycle
.arc
= NULL
;
1814 arc
= arc
->succ_next
;
1818 /* Add new block to chain. */
1819 dst
->u
.cycle
.arc
= arc
;
1823 /* We could not add another vertex to the path. Remove
1824 the last vertex from the list. */
1825 arc
= head
->u
.cycle
.arc
;
1828 /* It was not the first vertex. Move onto next arc. */
1829 head
->u
.cycle
.arc
= NULL
;
1831 arc
= arc
->succ_next
;
1832 goto current_vertex
;
1834 /* Mark this block as unusable. */
1835 block
->u
.cycle
.ident
= ~0U;
1838 line
->count
= count
;
1843 src
->coverage
.lines
++;
1845 src
->coverage
.lines_executed
++;
1850 /* Output information about ARC number IX. Returns nonzero if
1851 anything is output. */
1854 output_branch_count (FILE *gcov_file
, int ix
, const arc_t
*arc
)
1857 if (arc
->is_call_non_return
)
1859 if (arc
->src
->count
)
1861 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
1862 format_gcov (arc
->src
->count
- arc
->count
,
1863 arc
->src
->count
, -flag_counts
));
1866 fnotice (gcov_file
, "call %2d never executed\n", ix
);
1868 else if (!arc
->is_unconditional
)
1870 if (arc
->src
->count
)
1871 fnotice (gcov_file
, "branch %2d taken %s%s\n", ix
,
1872 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
1873 arc
->fall_through
? " (fallthrough)" : "");
1875 fnotice (gcov_file
, "branch %2d never executed\n", ix
);
1877 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
1879 if (arc
->src
->count
)
1880 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
1881 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
1883 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
1891 /* Read in the source file one line at a time, and output that line to
1892 the gcov file preceded by its execution count and other
1896 output_lines (FILE *gcov_file
, const source_t
*src
)
1899 unsigned line_num
; /* current line number. */
1900 const line_t
*line
; /* current line info ptr. */
1901 char string
[STRING_SIZE
]; /* line buffer. */
1902 char const *retval
= ""; /* status of source file reading. */
1903 function_t
*fn
= NULL
;
1905 fprintf (gcov_file
, "%9s:%5d:Source:%s\n", "-", 0, src
->name
);
1906 if (!multiple_files
)
1908 fprintf (gcov_file
, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name
);
1909 fprintf (gcov_file
, "%9s:%5d:Data:%s\n", "-", 0,
1910 no_data_file
? "-" : da_file_name
);
1911 fprintf (gcov_file
, "%9s:%5d:Runs:%u\n", "-", 0,
1912 object_summary
.ctrs
[GCOV_COUNTER_ARCS
].runs
);
1914 fprintf (gcov_file
, "%9s:%5d:Programs:%u\n", "-", 0, program_count
);
1916 source_file
= fopen (src
->name
, "r");
1919 fnotice (stderr
, "%s:cannot open source file\n", src
->name
);
1922 else if (src
->file_time
== 0)
1923 fprintf (gcov_file
, "%9s:%5d:Source is newer than graph\n", "-", 0);
1926 fn
= src
->functions
;
1928 for (line_num
= 1, line
= &src
->lines
[line_num
];
1929 line_num
< src
->num_lines
; line_num
++, line
++)
1931 for (; fn
&& fn
->line
== line_num
; fn
= fn
->line_next
)
1933 arc_t
*arc
= fn
->blocks
[fn
->num_blocks
- 1].pred
;
1934 gcov_type return_count
= fn
->blocks
[fn
->num_blocks
- 1].count
;
1936 for (; arc
; arc
= arc
->pred_next
)
1938 return_count
-= arc
->count
;
1940 fprintf (gcov_file
, "function %s", fn
->name
);
1941 fprintf (gcov_file
, " called %s",
1942 format_gcov (fn
->blocks
[0].count
, 0, -1));
1943 fprintf (gcov_file
, " returned %s",
1944 format_gcov (return_count
, fn
->blocks
[0].count
, 0));
1945 fprintf (gcov_file
, " blocks executed %s",
1946 format_gcov (fn
->blocks_executed
, fn
->num_blocks
- 2, 0));
1947 fprintf (gcov_file
, "\n");
1950 /* For lines which don't exist in the .bb file, print '-' before
1951 the source line. For lines which exist but were never
1952 executed, print '#####' before the source line. Otherwise,
1953 print the execution count before the source line. There are
1954 16 spaces of indentation added before the source line so that
1955 tabs won't be messed up. */
1956 fprintf (gcov_file
, "%9s:%5u:",
1957 !line
->exists
? "-" : !line
->count
? "#####"
1958 : format_gcov (line
->count
, 0, -1), line_num
);
1962 /* Copy source line. */
1965 retval
= fgets (string
, STRING_SIZE
, source_file
);
1968 fputs (retval
, gcov_file
);
1970 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n');
1973 fputs ("/*EOF*/\n", gcov_file
);
1975 if (flag_all_blocks
)
1981 for (ix
= jx
= 0, block
= line
->u
.blocks
; block
;
1982 block
= block
->chain
)
1984 if (!block
->is_call_return
)
1985 fprintf (gcov_file
, "%9s:%5u-block %2d\n",
1986 !line
->exists
? "-" : !block
->count
? "$$$$$"
1987 : format_gcov (block
->count
, 0, -1),
1990 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1991 jx
+= output_branch_count (gcov_file
, jx
, arc
);
1994 else if (flag_branches
)
1999 for (ix
= 0, arc
= line
->u
.branches
; arc
; arc
= arc
->line_next
)
2000 ix
+= output_branch_count (gcov_file
, ix
, arc
);
2004 /* Handle all remaining source lines. There may be lines after the
2005 last line of code. */
2008 for (; (retval
= fgets (string
, STRING_SIZE
, source_file
)); line_num
++)
2010 fprintf (gcov_file
, "%9s:%5u:%s", "-", line_num
, retval
);
2012 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n')
2014 retval
= fgets (string
, STRING_SIZE
, source_file
);
2017 fputs (retval
, gcov_file
);
2023 fclose (source_file
);