1 /* Gcov.c: prepend line execution counts and branch probabilities to a
3 Copyright (C) 1990-2013 Free Software Foundation, Inc.
4 Contributed by James E. Wilson of Cygnus Support.
5 Mangled by Bob Manson of Cygnus Support.
6 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
8 Gcov is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 Gcov is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Gcov; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 /* ??? Print a list of the ten blocks with the highest execution counts,
23 and list the line numbers corresponding to those blocks. Also, perhaps
24 list the line numbers with the highest execution counts, only printing
25 the first if there are several which are all listed in the same block. */
27 /* ??? Should have an option to print the number of basic blocks, and the
28 percent of them that are covered. */
30 /* Need an option to show individual block counts, and show
31 probabilities of fall through arcs. */
35 #include "coretypes.h"
38 #include "diagnostic.h"
47 /* The gcno file is generated by -ftest-coverage option. The gcda file is
48 generated by a program compiled with -fprofile-arcs. Their formats
49 are documented in gcov-io.h. */
51 /* The functions in this file for creating and solution program flow graphs
52 are very similar to functions in the gcc source file profile.c. In
53 some places we make use of the knowledge of how profile.c works to
54 select particular algorithms here. */
56 /* The code validates that the profile information read in corresponds
57 to the code currently being compiled. Rather than checking for
58 identical files, the code below compares a checksum on the CFG
59 (based on the order of basic blocks and the arcs in the CFG). If
60 the CFG checksum in the gcda file match the CFG checksum in the
61 gcno file, the profile data will be used. */
63 /* This is the size of the buffer used to read in source file lines. */
69 /* Describes an arc between two basic blocks. */
71 typedef struct arc_info
73 /* source and destination blocks. */
74 struct block_info
*src
;
75 struct block_info
*dst
;
77 /* transition counts. */
79 /* used in cycle search, so that we do not clobber original counts. */
82 unsigned int count_valid
: 1;
83 unsigned int on_tree
: 1;
84 unsigned int fake
: 1;
85 unsigned int fall_through
: 1;
87 /* Arc to a catch handler. */
88 unsigned int is_throw
: 1;
90 /* Arc is for a function that abnormally returns. */
91 unsigned int is_call_non_return
: 1;
93 /* Arc is for catch/setjmp. */
94 unsigned int is_nonlocal_return
: 1;
96 /* Is an unconditional branch. */
97 unsigned int is_unconditional
: 1;
99 /* Loop making arc. */
100 unsigned int cycle
: 1;
102 /* Next branch on line. */
103 struct arc_info
*line_next
;
105 /* Links to next arc on src and dst lists. */
106 struct arc_info
*succ_next
;
107 struct arc_info
*pred_next
;
110 /* Describes a basic block. Contains lists of arcs to successor and
111 predecessor blocks. */
113 typedef struct block_info
115 /* Chain of exit and entry arcs. */
119 /* Number of unprocessed exit and entry arcs. */
123 /* Block execution count. */
126 unsigned count_valid
: 1;
127 unsigned valid_chain
: 1;
128 unsigned invalid_chain
: 1;
129 unsigned exceptional
: 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 /* The graph contains at least one fake incoming edge. */
176 unsigned has_catch
: 1;
178 /* Array of basic blocks. Like in GCC, the entry block is
179 at blocks[0] and the exit block is at blocks[1]. */
180 #define ENTRY_BLOCK (0)
181 #define EXIT_BLOCK (1)
184 unsigned blocks_executed
;
186 /* Raw arc coverage counts. */
190 /* First line number & file. */
194 /* Next function in same source file. */
195 struct function_info
*line_next
;
198 struct function_info
*next
;
201 /* Describes coverage of a file or function. */
203 typedef struct coverage_info
209 int branches_executed
;
218 /* Describes a single line of source. Contains a chain of basic blocks
221 typedef struct line_info
223 gcov_type count
; /* execution count */
226 arc_t
*branches
; /* branches from blocks that end on this
227 line. Used for branch-counts when not
229 block_t
*blocks
; /* blocks which start on this line. Used
230 in all-blocks mode. */
233 unsigned unexceptional
: 1;
236 /* Describes a file mentioned in the block graph. Contains an array
239 typedef struct source_info
241 /* Canonical name of source file. */
245 /* Array of line information. */
251 /* Functions in this source file. These are in ascending line
253 function_t
*functions
;
256 typedef struct name_map
258 char *name
; /* Source file name */
259 unsigned src
; /* Source file */
262 /* Holds a list of function basic block graphs. */
264 static function_t
*functions
;
265 static function_t
**fn_end
= &functions
;
267 static source_t
*sources
; /* Array of source files */
268 static unsigned n_sources
; /* Number of sources */
269 static unsigned a_sources
; /* Allocated sources */
271 static name_map_t
*names
; /* Mapping of file names to sources */
272 static unsigned n_names
; /* Number of names */
273 static unsigned a_names
; /* Allocated names */
275 /* This holds data summary information. */
277 static unsigned object_runs
;
278 static unsigned program_count
;
280 static unsigned total_lines
;
281 static unsigned total_executed
;
283 /* Modification time of graph file. */
285 static time_t bbg_file_time
;
287 /* Name of the notes (gcno) output file. The "bbg" prefix is for
288 historical reasons, when the notes file contained only the
289 basic block graph notes. */
291 static char *bbg_file_name
;
293 /* Stamp of the bbg file */
294 static unsigned bbg_stamp
;
296 /* Name and file pointer of the input file for the count data (gcda). */
298 static char *da_file_name
;
300 /* Data file is missing. */
302 static int no_data_file
;
304 /* If there is several input files, compute and display results after
305 reading all data files. This way if two or more gcda file refer to
306 the same source file (eg inline subprograms in a .h file), the
309 static int multiple_files
= 0;
311 /* Output branch probabilities. */
313 static int flag_branches
= 0;
315 /* Show unconditional branches too. */
316 static int flag_unconditional
= 0;
318 /* Output a gcov file if this is true. This is on by default, and can
319 be turned off by the -n option. */
321 static int flag_gcov_file
= 1;
323 /* Output progress indication if this is true. This is off by default
324 and can be turned on by the -d option. */
326 static int flag_display_progress
= 0;
328 /* For included files, make the gcov output file name include the name
329 of the input source file. For example, if x.h is included in a.c,
330 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
332 static int flag_long_names
= 0;
334 /* Output count information for every basic block, not merely those
335 that contain line number information. */
337 static int flag_all_blocks
= 0;
339 /* Output summary info for each function. */
341 static int flag_function_summary
= 0;
343 /* Object directory file prefix. This is the directory/file where the
344 graph and data files are looked for, if nonzero. */
346 static char *object_directory
= 0;
348 /* Source directory prefix. This is removed from source pathnames
349 that match, when generating the output file name. */
351 static char *source_prefix
= 0;
352 static size_t source_length
= 0;
354 /* Only show data for sources with relative pathnames. Absolute ones
355 usually indicate a system header file, which although it may
356 contain inline functions, is usually uninteresting. */
357 static int flag_relative_only
= 0;
359 /* Preserve all pathname components. Needed when object files and
360 source files are in subdirectories. '/' is mangled as '#', '.' is
361 elided and '..' mangled to '^'. */
363 static int flag_preserve_paths
= 0;
365 /* Output the number of times a branch was taken as opposed to the percentage
366 of times it was taken. */
368 static int flag_counts
= 0;
370 /* Forward declarations. */
371 static int process_args (int, char **);
372 static void print_usage (int) ATTRIBUTE_NORETURN
;
373 static void print_version (void) ATTRIBUTE_NORETURN
;
374 static void process_file (const char *);
375 static void generate_results (const char *);
376 static void create_file_names (const char *);
377 static int name_search (const void *, const void *);
378 static int name_sort (const void *, const void *);
379 static char *canonicalize_name (const char *);
380 static unsigned find_source (const char *);
381 static function_t
*read_graph_file (void);
382 static int read_count_file (function_t
*);
383 static void solve_flow_graph (function_t
*);
384 static void find_exception_blocks (function_t
*);
385 static void add_branch_counts (coverage_t
*, const arc_t
*);
386 static void add_line_counts (coverage_t
*, function_t
*);
387 static void executed_summary (unsigned, unsigned);
388 static void function_summary (const coverage_t
*, const char *);
389 static const char *format_gcov (gcov_type
, gcov_type
, int);
390 static void accumulate_line_counts (source_t
*);
391 static int output_branch_count (FILE *, int, const arc_t
*);
392 static void output_lines (FILE *, const source_t
*);
393 static char *make_gcov_file_name (const char *, const char *);
394 static char *mangle_name (const char *, char *);
395 static void release_structures (void);
396 static void release_function (function_t
*);
397 extern int main (int, char **);
400 main (int argc
, char **argv
)
406 p
= argv
[0] + strlen (argv
[0]);
407 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
411 xmalloc_set_program_name (progname
);
413 /* Unlock the stdio streams. */
414 unlock_std_streams ();
418 diagnostic_initialize (global_dc
, 0);
420 /* Handle response files. */
421 expandargv (&argc
, &argv
);
424 names
= XNEWVEC (name_map_t
, a_names
);
426 sources
= XNEWVEC (source_t
, a_sources
);
428 argno
= process_args (argc
, argv
);
432 if (argc
- argno
> 1)
437 for (; argno
!= argc
; argno
++)
439 if (flag_display_progress
)
440 printf("Processing file %d out of %d\n",
441 argno
- first_arg
+ 1, argc
- first_arg
);
442 process_file (argv
[argno
]);
445 generate_results (multiple_files
? NULL
: argv
[argc
- 1]);
447 release_structures ();
452 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
453 otherwise the output of --help. */
456 print_usage (int error_p
)
458 FILE *file
= error_p
? stderr
: stdout
;
459 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
461 fnotice (file
, "Usage: gcov [OPTION]... SOURCE|OBJ...\n\n");
462 fnotice (file
, "Print code coverage information.\n\n");
463 fnotice (file
, " -h, --help Print this help, then exit\n");
464 fnotice (file
, " -v, --version Print version number, then exit\n");
465 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
466 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
467 fnotice (file
, " -c, --branch-counts Given counts of branches taken\n\
468 rather than percentages\n");
469 fnotice (file
, " -n, --no-output Do not create an output file\n");
470 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
472 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
473 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
474 fnotice (file
, " -s, --source-prefix DIR Source prefix to elide\n");
475 fnotice (file
, " -r, --relative-only Only show data for relative sources\n");
476 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
477 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
478 fnotice (file
, " -d, --display-progress Display progress information\n");
479 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
484 /* Print version information and exit. */
489 fnotice (stdout
, "gcov %s%s\n", pkgversion_string
, version_string
);
490 fprintf (stdout
, "Copyright %s 2013 Free Software Foundation, Inc.\n",
493 _("This is free software; see the source for copying conditions.\n"
494 "There is NO warranty; not even for MERCHANTABILITY or \n"
495 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
496 exit (SUCCESS_EXIT_CODE
);
499 static const struct option options
[] =
501 { "help", no_argument
, NULL
, 'h' },
502 { "version", no_argument
, NULL
, 'v' },
503 { "all-blocks", no_argument
, NULL
, 'a' },
504 { "branch-probabilities", no_argument
, NULL
, 'b' },
505 { "branch-counts", no_argument
, NULL
, 'c' },
506 { "no-output", no_argument
, NULL
, 'n' },
507 { "long-file-names", no_argument
, NULL
, 'l' },
508 { "function-summaries", no_argument
, NULL
, 'f' },
509 { "preserve-paths", no_argument
, NULL
, 'p' },
510 { "relative-only", no_argument
, NULL
, 'r' },
511 { "object-directory", required_argument
, NULL
, 'o' },
512 { "object-file", required_argument
, NULL
, 'o' },
513 { "source-prefix", required_argument
, NULL
, 's' },
514 { "unconditional-branches", no_argument
, NULL
, 'u' },
515 { "display-progress", no_argument
, NULL
, 'd' },
519 /* Process args, return index to first non-arg. */
522 process_args (int argc
, char **argv
)
526 while ((opt
= getopt_long (argc
, argv
, "abcdfhlno:s:pruv", options
, NULL
)) != -1)
540 flag_function_summary
= 1;
544 /* print_usage will exit. */
552 object_directory
= optarg
;
555 source_prefix
= optarg
;
556 source_length
= strlen (source_prefix
);
559 flag_relative_only
= 1;
562 flag_preserve_paths
= 1;
565 flag_unconditional
= 1;
568 flag_display_progress
= 1;
572 /* print_version will exit. */
575 /* print_usage will exit. */
582 /* Process a single input file. */
585 process_file (const char *file_name
)
589 create_file_names (file_name
);
590 fns
= read_graph_file ();
594 read_count_file (fns
);
597 function_t
*fn
= fns
;
603 unsigned src
= fn
->src
;
604 unsigned line
= fn
->line
;
606 function_t
*probe
, **prev
;
608 /* Now insert it into the source file's list of
609 functions. Normally functions will be encountered in
610 ascending order, so a simple scan is quick. Note we're
611 building this list in reverse order. */
612 for (prev
= &sources
[src
].functions
;
613 (probe
= *prev
); prev
= &probe
->line_next
)
614 if (probe
->line
<= line
)
616 fn
->line_next
= probe
;
619 /* Mark last line in files touched by function. */
620 for (block_no
= 0; block_no
!= fn
->num_blocks
; block_no
++)
622 unsigned *enc
= fn
->blocks
[block_no
].u
.line
.encoding
;
623 unsigned num
= fn
->blocks
[block_no
].u
.line
.num
;
630 if (line
>= sources
[src
].num_lines
)
631 sources
[src
].num_lines
= line
+ 1;
638 else if (*enc
> line
)
641 if (line
>= sources
[src
].num_lines
)
642 sources
[src
].num_lines
= line
+ 1;
644 solve_flow_graph (fn
);
646 find_exception_blocks (fn
);
651 /* The function was not in the executable -- some other
652 instance must have been selected. */
653 release_function (fn
);
658 generate_results (const char *file_name
)
664 for (ix
= n_sources
, src
= sources
; ix
--; src
++)
666 src
->lines
= XCNEWVEC (line_t
, src
->num_lines
);
668 for (fn
= functions
; fn
; fn
= fn
->next
)
672 memset (&coverage
, 0, sizeof (coverage
));
673 coverage
.name
= fn
->name
;
674 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
675 if (flag_function_summary
)
677 function_summary (&coverage
, "Function");
678 fnotice (stdout
, "\n");
684 name_map_t
*name_map
= (name_map_t
*)bsearch
685 (file_name
, names
, n_names
, sizeof (*names
), name_search
);
687 file_name
= sources
[name_map
->src
].coverage
.name
;
689 file_name
= canonicalize_name (file_name
);
692 for (ix
= n_sources
, src
= sources
; ix
--; src
++)
694 if (flag_relative_only
)
696 /* Ignore this source, if it is an absolute path (after
697 source prefix removal). */
698 char first
= src
->coverage
.name
[0];
700 #if HAVE_DOS_BASED_FILE_SYSTEM
701 if (first
&& src
->coverage
.name
[1] == ':')
702 first
= src
->coverage
.name
[2];
704 if (IS_DIR_SEPARATOR (first
))
708 accumulate_line_counts (src
);
709 function_summary (&src
->coverage
, "File");
710 total_lines
+= src
->coverage
.lines
;
711 total_executed
+= src
->coverage
.lines_executed
;
715 = make_gcov_file_name (file_name
, src
->coverage
.name
);
717 if (src
->coverage
.lines
)
719 FILE *gcov_file
= fopen (gcov_file_name
, "w");
723 fnotice (stdout
, "Creating '%s'\n", gcov_file_name
);
724 output_lines (gcov_file
, src
);
725 if (ferror (gcov_file
))
726 fnotice (stderr
, "Error writing output file '%s'\n",
731 fnotice (stderr
, "Could not open output file '%s'\n",
736 unlink (gcov_file_name
);
737 fnotice (stdout
, "Removing '%s'\n", gcov_file_name
);
739 free (gcov_file_name
);
741 fnotice (stdout
, "\n");
745 executed_summary (total_lines
, total_executed
);
748 /* Release a function structure */
751 release_function (function_t
*fn
)
756 for (ix
= fn
->num_blocks
, block
= fn
->blocks
; ix
--; block
++)
760 for (arc
= block
->succ
; arc
; arc
= arc_n
)
762 arc_n
= arc
->succ_next
;
770 /* Release all memory used. */
773 release_structures (void)
778 for (ix
= n_sources
; ix
--;)
779 free (sources
[ix
].lines
);
782 for (ix
= n_names
; ix
--;)
783 free (names
[ix
].name
);
786 while ((fn
= functions
))
788 functions
= fn
->next
;
789 release_function (fn
);
793 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
794 is not specified, these are named from FILE_NAME sans extension. If
795 OBJECT_DIRECTORY is specified and is a directory, the files are in that
796 directory, but named from the basename of the FILE_NAME, sans extension.
797 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
798 and the data files are named from that. */
801 create_file_names (const char *file_name
)
805 int length
= strlen (file_name
);
808 /* Free previous file names. */
809 free (bbg_file_name
);
811 da_file_name
= bbg_file_name
= NULL
;
815 if (object_directory
&& object_directory
[0])
819 length
+= strlen (object_directory
) + 2;
820 name
= XNEWVEC (char, length
);
823 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
824 strcat (name
, object_directory
);
825 if (base
&& (! IS_DIR_SEPARATOR (name
[strlen (name
) - 1])))
830 name
= XNEWVEC (char, length
+ 1);
831 strcpy (name
, file_name
);
837 /* Append source file name. */
838 const char *cptr
= lbasename (file_name
);
839 strcat (name
, cptr
? cptr
: file_name
);
842 /* Remove the extension. */
843 cptr
= strrchr (CONST_CAST (char *, lbasename (name
)), '.');
847 length
= strlen (name
);
849 bbg_file_name
= XNEWVEC (char, length
+ strlen (GCOV_NOTE_SUFFIX
) + 1);
850 strcpy (bbg_file_name
, name
);
851 strcpy (bbg_file_name
+ length
, GCOV_NOTE_SUFFIX
);
853 da_file_name
= XNEWVEC (char, length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
854 strcpy (da_file_name
, name
);
855 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
861 /* A is a string and B is a pointer to name_map_t. Compare for file
862 name orderability. */
865 name_search (const void *a_
, const void *b_
)
867 const char *a
= (const char *)a_
;
868 const name_map_t
*b
= (const name_map_t
*)b_
;
870 #if HAVE_DOS_BASED_FILE_SYSTEM
871 return strcasecmp (a
, b
->name
);
873 return strcmp (a
, b
->name
);
877 /* A and B are a pointer to name_map_t. Compare for file name
881 name_sort (const void *a_
, const void *b_
)
883 const name_map_t
*a
= (const name_map_t
*)a_
;
884 return name_search (a
->name
, b_
);
887 /* Find or create a source file structure for FILE_NAME. Copies
888 FILE_NAME on creation */
891 find_source (const char *file_name
)
893 name_map_t
*name_map
;
899 file_name
= "<unknown>";
900 name_map
= (name_map_t
*)bsearch
901 (file_name
, names
, n_names
, sizeof (*names
), name_search
);
908 if (n_names
+ 2 > a_names
)
910 /* Extend the name map array -- we'll be inserting one or two
913 name_map
= XNEWVEC (name_map_t
, a_names
);
914 memcpy (name_map
, names
, n_names
* sizeof (*names
));
919 /* Not found, try the canonical name. */
920 canon
= canonicalize_name (file_name
);
921 name_map
= (name_map_t
*)bsearch
922 (canon
, names
, n_names
, sizeof (*names
), name_search
);
925 /* Not found with canonical name, create a new source. */
928 if (n_sources
== a_sources
)
931 src
= XNEWVEC (source_t
, a_sources
);
932 memcpy (src
, sources
, n_sources
* sizeof (*sources
));
939 name_map
= &names
[n_names
++];
940 name_map
->name
= canon
;
943 src
= &sources
[n_sources
++];
944 memset (src
, 0, sizeof (*src
));
946 src
->coverage
.name
= src
->name
;
948 #if HAVE_DOS_BASED_FILE_SYSTEM
949 /* You lose if separators don't match exactly in the
951 && !strncasecmp (source_prefix
, src
->coverage
.name
, source_length
)
953 && !strncmp (source_prefix
, src
->coverage
.name
, source_length
)
955 && IS_DIR_SEPARATOR (src
->coverage
.name
[source_length
]))
956 src
->coverage
.name
+= source_length
+ 1;
957 if (!stat (src
->name
, &status
))
958 src
->file_time
= status
.st_mtime
;
963 if (name_search (file_name
, name_map
))
965 /* Append the non-canonical name. */
966 name_map
= &names
[n_names
++];
967 name_map
->name
= xstrdup (file_name
);
971 /* Resort the name map. */
972 qsort (names
, n_names
, sizeof (*names
), name_sort
);
975 if (sources
[idx
].file_time
> bbg_file_time
)
977 static int info_emitted
;
979 fnotice (stderr
, "%s:source file is newer than notes file '%s'\n",
980 file_name
, bbg_file_name
);
984 "(the message is only displayed one per source file)\n");
987 sources
[idx
].file_time
= 0;
993 /* Read the notes file. Return list of functions read -- in reverse order. */
996 read_graph_file (void)
999 unsigned current_tag
= 0;
1000 function_t
*fn
= NULL
;
1001 function_t
*fns
= NULL
;
1002 function_t
**fns_end
= &fns
;
1003 unsigned src_idx
= 0;
1007 if (!gcov_open (bbg_file_name
, 1))
1009 fnotice (stderr
, "%s:cannot open notes file\n", bbg_file_name
);
1012 bbg_file_time
= gcov_time ();
1013 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC
))
1015 fnotice (stderr
, "%s:not a gcov notes file\n", bbg_file_name
);
1020 version
= gcov_read_unsigned ();
1021 if (version
!= GCOV_VERSION
)
1025 GCOV_UNSIGNED2STRING (v
, version
);
1026 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1028 fnotice (stderr
, "%s:version '%.4s', prefer '%.4s'\n",
1029 bbg_file_name
, v
, e
);
1031 bbg_stamp
= gcov_read_unsigned ();
1033 while ((tag
= gcov_read_unsigned ()))
1035 unsigned length
= gcov_read_unsigned ();
1036 gcov_position_t base
= gcov_position ();
1038 if (tag
== GCOV_TAG_FUNCTION
)
1040 char *function_name
;
1041 unsigned ident
, lineno
;
1042 unsigned lineno_checksum
, cfg_checksum
;
1044 ident
= gcov_read_unsigned ();
1045 lineno_checksum
= gcov_read_unsigned ();
1046 cfg_checksum
= gcov_read_unsigned ();
1047 function_name
= xstrdup (gcov_read_string ());
1048 src_idx
= find_source (gcov_read_string ());
1049 lineno
= gcov_read_unsigned ();
1051 fn
= XCNEW (function_t
);
1052 fn
->name
= function_name
;
1054 fn
->lineno_checksum
= lineno_checksum
;
1055 fn
->cfg_checksum
= cfg_checksum
;
1059 fn
->line_next
= NULL
;
1062 fns_end
= &fn
->next
;
1065 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
1068 fnotice (stderr
, "%s:already seen blocks for '%s'\n",
1069 bbg_file_name
, fn
->name
);
1072 unsigned ix
, num_blocks
= GCOV_TAG_BLOCKS_NUM (length
);
1073 fn
->num_blocks
= num_blocks
;
1075 fn
->blocks
= XCNEWVEC (block_t
, fn
->num_blocks
);
1076 for (ix
= 0; ix
!= num_blocks
; ix
++)
1077 fn
->blocks
[ix
].flags
= gcov_read_unsigned ();
1080 else if (fn
&& tag
== GCOV_TAG_ARCS
)
1082 unsigned src
= gcov_read_unsigned ();
1083 unsigned num_dests
= GCOV_TAG_ARCS_NUM (length
);
1084 block_t
*src_blk
= &fn
->blocks
[src
];
1085 unsigned mark_catches
= 0;
1086 struct arc_info
*arc
;
1088 if (src
>= fn
->num_blocks
|| fn
->blocks
[src
].succ
)
1093 unsigned dest
= gcov_read_unsigned ();
1094 unsigned flags
= gcov_read_unsigned ();
1096 if (dest
>= fn
->num_blocks
)
1098 arc
= XCNEW (arc_t
);
1100 arc
->dst
= &fn
->blocks
[dest
];
1104 arc
->count_valid
= 0;
1105 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
1106 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
1107 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
1109 arc
->succ_next
= src_blk
->succ
;
1110 src_blk
->succ
= arc
;
1111 src_blk
->num_succ
++;
1113 arc
->pred_next
= fn
->blocks
[dest
].pred
;
1114 fn
->blocks
[dest
].pred
= arc
;
1115 fn
->blocks
[dest
].num_pred
++;
1121 /* Exceptional exit from this function, the
1122 source block must be a call. */
1123 fn
->blocks
[src
].is_call_site
= 1;
1124 arc
->is_call_non_return
= 1;
1129 /* Non-local return from a callee of this
1130 function. The destination block is a setjmp. */
1131 arc
->is_nonlocal_return
= 1;
1132 fn
->blocks
[dest
].is_nonlocal_return
= 1;
1142 /* We have a fake exit from this block. The other
1143 non-fall through exits must be to catch handlers.
1144 Mark them as catch arcs. */
1146 for (arc
= src_blk
->succ
; arc
; arc
= arc
->succ_next
)
1147 if (!arc
->fake
&& !arc
->fall_through
)
1154 else if (fn
&& tag
== GCOV_TAG_LINES
)
1156 unsigned blockno
= gcov_read_unsigned ();
1157 unsigned *line_nos
= XCNEWVEC (unsigned, length
- 1);
1159 if (blockno
>= fn
->num_blocks
|| fn
->blocks
[blockno
].u
.line
.encoding
)
1164 unsigned lineno
= gcov_read_unsigned ();
1171 line_nos
[ix
++] = src_idx
;
1173 line_nos
[ix
++] = lineno
;
1177 const char *file_name
= gcov_read_string ();
1181 src_idx
= find_source (file_name
);
1183 line_nos
[ix
++] = src_idx
;
1187 fn
->blocks
[blockno
].u
.line
.encoding
= line_nos
;
1188 fn
->blocks
[blockno
].u
.line
.num
= ix
;
1190 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
1195 gcov_sync (base
, length
);
1196 if (gcov_is_error ())
1199 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
1206 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
1211 /* Reads profiles from the count file and attach to each
1212 function. Return nonzero if fatal error. */
1215 read_count_file (function_t
*fns
)
1220 function_t
*fn
= NULL
;
1223 if (!gcov_open (da_file_name
, 1))
1225 fnotice (stderr
, "%s:cannot open data file, assuming not executed\n",
1230 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
1232 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
1237 version
= gcov_read_unsigned ();
1238 if (version
!= GCOV_VERSION
)
1242 GCOV_UNSIGNED2STRING (v
, version
);
1243 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1245 fnotice (stderr
, "%s:version '%.4s', prefer version '%.4s'\n",
1246 da_file_name
, v
, e
);
1248 tag
= gcov_read_unsigned ();
1249 if (tag
!= bbg_stamp
)
1251 fnotice (stderr
, "%s:stamp mismatch with notes file\n", da_file_name
);
1255 while ((tag
= gcov_read_unsigned ()))
1257 unsigned length
= gcov_read_unsigned ();
1258 unsigned long base
= gcov_position ();
1260 if (tag
== GCOV_TAG_PROGRAM_SUMMARY
)
1262 struct gcov_summary summary
;
1263 gcov_read_summary (&summary
);
1264 object_runs
+= summary
.ctrs
[GCOV_COUNTER_ARCS
].runs
;
1267 else if (tag
== GCOV_TAG_FUNCTION
&& !length
)
1269 else if (tag
== GCOV_TAG_FUNCTION
&& length
== GCOV_TAG_FUNCTION_LENGTH
)
1272 struct function_info
*fn_n
;
1274 /* Try to find the function in the list. To speed up the
1275 search, first start from the last function found. */
1276 ident
= gcov_read_unsigned ();
1278 for (fn
= fn
? fn
->next
: NULL
; ; fn
= fn
->next
)
1282 else if ((fn
= fn_n
))
1286 fnotice (stderr
, "%s:unknown function '%u'\n",
1287 da_file_name
, ident
);
1290 if (fn
->ident
== ident
)
1296 else if (gcov_read_unsigned () != fn
->lineno_checksum
1297 || gcov_read_unsigned () != fn
->cfg_checksum
)
1300 fnotice (stderr
, "%s:profile mismatch for '%s'\n",
1301 da_file_name
, fn
->name
);
1305 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
1307 if (length
!= GCOV_TAG_COUNTER_LENGTH (fn
->num_counts
))
1311 fn
->counts
= XCNEWVEC (gcov_type
, fn
->num_counts
);
1313 for (ix
= 0; ix
!= fn
->num_counts
; ix
++)
1314 fn
->counts
[ix
] += gcov_read_counter ();
1316 gcov_sync (base
, length
);
1317 if ((error
= gcov_is_error ()))
1319 fnotice (stderr
, error
< 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1329 /* Solve the flow graph. Propagate counts from the instrumented arcs
1330 to the blocks and the uninstrumented arcs. */
1333 solve_flow_graph (function_t
*fn
)
1337 gcov_type
*count_ptr
= fn
->counts
;
1339 block_t
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
1340 block_t
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
1342 /* The arcs were built in reverse order. Fix that now. */
1343 for (ix
= fn
->num_blocks
; ix
--;)
1345 arc_t
*arc_p
, *arc_n
;
1347 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
1348 arc_p
= arc
, arc
= arc_n
)
1350 arc_n
= arc
->succ_next
;
1351 arc
->succ_next
= arc_p
;
1353 fn
->blocks
[ix
].succ
= arc_p
;
1355 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
1356 arc_p
= arc
, arc
= arc_n
)
1358 arc_n
= arc
->pred_next
;
1359 arc
->pred_next
= arc_p
;
1361 fn
->blocks
[ix
].pred
= arc_p
;
1364 if (fn
->num_blocks
< 2)
1365 fnotice (stderr
, "%s:'%s' lacks entry and/or exit blocks\n",
1366 bbg_file_name
, fn
->name
);
1369 if (fn
->blocks
[ENTRY_BLOCK
].num_pred
)
1370 fnotice (stderr
, "%s:'%s' has arcs to entry block\n",
1371 bbg_file_name
, fn
->name
);
1373 /* We can't deduce the entry block counts from the lack of
1375 fn
->blocks
[ENTRY_BLOCK
].num_pred
= ~(unsigned)0;
1377 if (fn
->blocks
[EXIT_BLOCK
].num_succ
)
1378 fnotice (stderr
, "%s:'%s' has arcs from exit block\n",
1379 bbg_file_name
, fn
->name
);
1381 /* Likewise, we can't deduce exit block counts from the lack
1382 of its successors. */
1383 fn
->blocks
[EXIT_BLOCK
].num_succ
= ~(unsigned)0;
1386 /* Propagate the measured counts, this must be done in the same
1387 order as the code in profile.c */
1388 for (ix
= 0, blk
= fn
->blocks
; ix
!= fn
->num_blocks
; ix
++, blk
++)
1390 block_t
const *prev_dst
= NULL
;
1391 int out_of_order
= 0;
1392 int non_fake_succ
= 0;
1394 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1402 arc
->count
= *count_ptr
++;
1403 arc
->count_valid
= 1;
1405 arc
->dst
->num_pred
--;
1407 if (prev_dst
&& prev_dst
> arc
->dst
)
1409 prev_dst
= arc
->dst
;
1411 if (non_fake_succ
== 1)
1413 /* If there is only one non-fake exit, it is an
1414 unconditional branch. */
1415 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1418 arc
->is_unconditional
= 1;
1419 /* If this block is instrumenting a call, it might be
1420 an artificial block. It is not artificial if it has
1421 a non-fallthrough exit, or the destination of this
1422 arc has more than one entry. Mark the destination
1423 block as a return site, if none of those conditions
1425 if (blk
->is_call_site
&& arc
->fall_through
1426 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
1427 arc
->dst
->is_call_return
= 1;
1431 /* Sort the successor arcs into ascending dst order. profile.c
1432 normally produces arcs in the right order, but sometimes with
1433 one or two out of order. We're not using a particularly
1437 arc_t
*start
= blk
->succ
;
1438 unsigned changes
= 1;
1442 arc_t
*arc
, *arc_p
, *arc_n
;
1445 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
1447 if (arc
->dst
> arc_n
->dst
)
1451 arc_p
->succ_next
= arc_n
;
1454 arc
->succ_next
= arc_n
->succ_next
;
1455 arc_n
->succ_next
= arc
;
1468 /* Place it on the invalid chain, it will be ignored if that's
1470 blk
->invalid_chain
= 1;
1471 blk
->chain
= invalid_blocks
;
1472 invalid_blocks
= blk
;
1475 while (invalid_blocks
|| valid_blocks
)
1477 while ((blk
= invalid_blocks
))
1479 gcov_type total
= 0;
1482 invalid_blocks
= blk
->chain
;
1483 blk
->invalid_chain
= 0;
1485 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1486 total
+= arc
->count
;
1487 else if (!blk
->num_pred
)
1488 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1489 total
+= arc
->count
;
1494 blk
->count_valid
= 1;
1495 blk
->chain
= valid_blocks
;
1496 blk
->valid_chain
= 1;
1499 while ((blk
= valid_blocks
))
1502 arc_t
*arc
, *inv_arc
;
1504 valid_blocks
= blk
->chain
;
1505 blk
->valid_chain
= 0;
1506 if (blk
->num_succ
== 1)
1512 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1514 total
-= arc
->count
;
1515 if (!arc
->count_valid
)
1519 inv_arc
->count_valid
= 1;
1520 inv_arc
->count
= total
;
1523 if (dst
->count_valid
)
1525 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
1527 dst
->chain
= valid_blocks
;
1528 dst
->valid_chain
= 1;
1534 if (!dst
->num_pred
&& !dst
->invalid_chain
)
1536 dst
->chain
= invalid_blocks
;
1537 dst
->invalid_chain
= 1;
1538 invalid_blocks
= dst
;
1542 if (blk
->num_pred
== 1)
1548 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1550 total
-= arc
->count
;
1551 if (!arc
->count_valid
)
1555 inv_arc
->count_valid
= 1;
1556 inv_arc
->count
= total
;
1559 if (src
->count_valid
)
1561 if (src
->num_succ
== 1 && !src
->valid_chain
)
1563 src
->chain
= valid_blocks
;
1564 src
->valid_chain
= 1;
1570 if (!src
->num_succ
&& !src
->invalid_chain
)
1572 src
->chain
= invalid_blocks
;
1573 src
->invalid_chain
= 1;
1574 invalid_blocks
= src
;
1581 /* If the graph has been correctly solved, every block will have a
1583 for (ix
= 0; ix
< fn
->num_blocks
; ix
++)
1584 if (!fn
->blocks
[ix
].count_valid
)
1586 fnotice (stderr
, "%s:graph is unsolvable for '%s'\n",
1587 bbg_file_name
, fn
->name
);
1592 /* Mark all the blocks only reachable via an incoming catch. */
1595 find_exception_blocks (function_t
*fn
)
1598 block_t
**queue
= XALLOCAVEC (block_t
*, fn
->num_blocks
);
1600 /* First mark all blocks as exceptional. */
1601 for (ix
= fn
->num_blocks
; ix
--;)
1602 fn
->blocks
[ix
].exceptional
= 1;
1604 /* Now mark all the blocks reachable via non-fake edges */
1605 queue
[0] = fn
->blocks
;
1606 queue
[0]->exceptional
= 0;
1609 block_t
*block
= queue
[--ix
];
1612 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1613 if (!arc
->fake
&& !arc
->is_throw
&& arc
->dst
->exceptional
)
1615 arc
->dst
->exceptional
= 0;
1616 queue
[ix
++] = arc
->dst
;
1622 /* Increment totals in COVERAGE according to arc ARC. */
1625 add_branch_counts (coverage_t
*coverage
, const arc_t
*arc
)
1627 if (arc
->is_call_non_return
)
1630 if (arc
->src
->count
)
1631 coverage
->calls_executed
++;
1633 else if (!arc
->is_unconditional
)
1635 coverage
->branches
++;
1636 if (arc
->src
->count
)
1637 coverage
->branches_executed
++;
1639 coverage
->branches_taken
++;
1643 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
1644 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1645 If DP is zero, no decimal point is printed. Only print 100% when
1646 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1647 format TOP. Return pointer to a static string. */
1650 format_gcov (gcov_type top
, gcov_type bottom
, int dp
)
1652 static char buffer
[20];
1656 float ratio
= bottom
? (float)top
/ bottom
: 0;
1658 unsigned limit
= 100;
1661 for (ix
= dp
; ix
--; )
1664 percent
= (unsigned) (ratio
* limit
+ (float)0.5);
1665 if (percent
<= 0 && top
)
1667 else if (percent
>= limit
&& top
!= bottom
)
1668 percent
= limit
- 1;
1669 ix
= sprintf (buffer
, "%.*u%%", dp
+ 1, percent
);
1675 buffer
[ix
+1] = buffer
[ix
];
1679 buffer
[ix
+ 1] = '.';
1683 sprintf (buffer
, HOST_WIDEST_INT_PRINT_DEC
, (HOST_WIDEST_INT
)top
);
1688 /* Summary of execution */
1691 executed_summary (unsigned lines
, unsigned executed
)
1694 fnotice (stdout
, "Lines executed:%s of %d\n",
1695 format_gcov (executed
, lines
, 2), lines
);
1697 fnotice (stdout
, "No executable lines\n");
1700 /* Output summary info for a function or file. */
1703 function_summary (const coverage_t
*coverage
, const char *title
)
1705 fnotice (stdout
, "%s '%s'\n", title
, coverage
->name
);
1706 executed_summary (coverage
->lines
, coverage
->lines_executed
);
1710 if (coverage
->branches
)
1712 fnotice (stdout
, "Branches executed:%s of %d\n",
1713 format_gcov (coverage
->branches_executed
,
1714 coverage
->branches
, 2),
1715 coverage
->branches
);
1716 fnotice (stdout
, "Taken at least once:%s of %d\n",
1717 format_gcov (coverage
->branches_taken
,
1718 coverage
->branches
, 2),
1719 coverage
->branches
);
1722 fnotice (stdout
, "No branches\n");
1723 if (coverage
->calls
)
1724 fnotice (stdout
, "Calls executed:%s of %d\n",
1725 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
1728 fnotice (stdout
, "No calls\n");
1732 /* Canonicalize the filename NAME by canonicalizing directory
1733 separators, eliding . components and resolving .. components
1734 appropriately. Always returns a unique string. */
1737 canonicalize_name (const char *name
)
1739 /* The canonical name cannot be longer than the incoming name. */
1740 char *result
= XNEWVEC (char, strlen (name
) + 1);
1741 const char *base
= name
, *probe
;
1746 #if HAVE_DOS_BASED_FILE_SYSTEM
1747 if (base
[0] && base
[1] == ':')
1749 result
[0] = base
[0];
1755 for (dd_base
= ptr
; *base
; base
= probe
)
1759 for (probe
= base
; *probe
; probe
++)
1760 if (IS_DIR_SEPARATOR (*probe
))
1764 if (len
== 1 && base
[0] == '.')
1765 /* Elide a '.' directory */
1767 else if (len
== 2 && base
[0] == '.' && base
[1] == '.')
1769 /* '..', we can only elide it and the previous directory, if
1770 we're not a symlink. */
1771 struct stat ATTRIBUTE_UNUSED buf
;
1775 #if defined (S_ISLNK)
1776 /* S_ISLNK is not POSIX.1-1996. */
1777 || stat (result
, &buf
) || S_ISLNK (buf
.st_mode
)
1781 /* Cannot elide, or unreadable or a symlink. */
1782 dd_base
= ptr
+ 2 + slash
;
1785 while (ptr
!= dd_base
&& *ptr
!= '/')
1787 slash
= ptr
!= result
;
1792 /* Regular pathname component. */
1795 memcpy (ptr
, base
, len
);
1800 for (; IS_DIR_SEPARATOR (*probe
); probe
++)
1808 /* Generate an output file name. INPUT_NAME is the canonicalized main
1809 input file and SRC_NAME is the canonicalized file name.
1810 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
1811 long_output_names we prepend the processed name of the input file
1812 to each output name (except when the current source file is the
1813 input file, so you don't get a double concatenation). The two
1814 components are separated by '##'. With preserve_paths we create a
1815 filename from all path components of the source file, replacing '/'
1816 with '#', and .. with '^', without it we simply take the basename
1817 component. (Remember, the canonicalized name will already have
1818 elided '.' components and converted \\ separators.) */
1821 make_gcov_file_name (const char *input_name
, const char *src_name
)
1826 if (flag_long_names
&& input_name
&& strcmp (src_name
, input_name
))
1828 /* Generate the input filename part. */
1829 result
= XNEWVEC (char, strlen (input_name
) + strlen (src_name
) + 10);
1832 ptr
= mangle_name (input_name
, ptr
);
1833 ptr
[0] = ptr
[1] = '#';
1838 result
= XNEWVEC (char, strlen (src_name
) + 10);
1842 ptr
= mangle_name (src_name
, ptr
);
1843 strcpy (ptr
, ".gcov");
1849 mangle_name (char const *base
, char *ptr
)
1853 /* Generate the source filename part. */
1854 if (!flag_preserve_paths
)
1856 base
= lbasename (base
);
1857 len
= strlen (base
);
1858 memcpy (ptr
, base
, len
);
1863 /* Convert '/' to '#', convert '..' to '^',
1864 convert ':' to '~' on DOS based file system. */
1867 #if HAVE_DOS_BASED_FILE_SYSTEM
1868 if (base
[0] && base
[1] == ':')
1876 for (; *base
; base
= probe
)
1880 for (probe
= base
; *probe
; probe
++)
1884 if (len
== 2 && base
[0] == '.' && base
[1] == '.')
1888 memcpy (ptr
, base
, len
);
1902 /* Scan through the bb_data for each line in the block, increment
1903 the line number execution count indicated by the execution count of
1904 the appropriate basic block. */
1907 add_line_counts (coverage_t
*coverage
, function_t
*fn
)
1910 line_t
*line
= NULL
; /* This is propagated from one iteration to the
1913 /* Scan each basic block. */
1914 for (ix
= 0; ix
!= fn
->num_blocks
; ix
++)
1916 block_t
*block
= &fn
->blocks
[ix
];
1918 const source_t
*src
= NULL
;
1921 if (block
->count
&& ix
&& ix
+ 1 != fn
->num_blocks
)
1922 fn
->blocks_executed
++;
1923 for (jx
= 0, encoding
= block
->u
.line
.encoding
;
1924 jx
!= block
->u
.line
.num
; jx
++, encoding
++)
1927 src
= &sources
[*++encoding
];
1932 line
= &src
->lines
[*encoding
];
1938 if (!line
->count
&& block
->count
)
1939 coverage
->lines_executed
++;
1942 if (!block
->exceptional
)
1943 line
->unexceptional
= 1;
1944 line
->count
+= block
->count
;
1946 free (block
->u
.line
.encoding
);
1947 block
->u
.cycle
.arc
= NULL
;
1948 block
->u
.cycle
.ident
= ~0U;
1950 if (!ix
|| ix
+ 1 == fn
->num_blocks
)
1951 /* Entry or exit block */;
1952 else if (flag_all_blocks
)
1954 line_t
*block_line
= line
;
1957 block_line
= &sources
[fn
->src
].lines
[fn
->line
];
1959 block
->chain
= block_line
->u
.blocks
;
1960 block_line
->u
.blocks
= block
;
1962 else if (flag_branches
)
1966 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1968 arc
->line_next
= line
->u
.branches
;
1969 line
->u
.branches
= arc
;
1970 if (coverage
&& !arc
->is_unconditional
)
1971 add_branch_counts (coverage
, arc
);
1976 fnotice (stderr
, "%s:no lines for '%s'\n", bbg_file_name
, fn
->name
);
1979 /* Accumulate the line counts of a file. */
1982 accumulate_line_counts (source_t
*src
)
1985 function_t
*fn
, *fn_p
, *fn_n
;
1988 /* Reverse the function order. */
1989 for (fn
= src
->functions
, fn_p
= NULL
; fn
;
1990 fn_p
= fn
, fn
= fn_n
)
1992 fn_n
= fn
->line_next
;
1993 fn
->line_next
= fn_p
;
1995 src
->functions
= fn_p
;
1997 for (ix
= src
->num_lines
, line
= src
->lines
; ix
--; line
++)
1999 if (!flag_all_blocks
)
2001 arc_t
*arc
, *arc_p
, *arc_n
;
2003 /* Total and reverse the branch information. */
2004 for (arc
= line
->u
.branches
, arc_p
= NULL
; arc
;
2005 arc_p
= arc
, arc
= arc_n
)
2007 arc_n
= arc
->line_next
;
2008 arc
->line_next
= arc_p
;
2010 add_branch_counts (&src
->coverage
, arc
);
2012 line
->u
.branches
= arc_p
;
2014 else if (line
->u
.blocks
)
2016 /* The user expects the line count to be the number of times
2017 a line has been executed. Simply summing the block count
2018 will give an artificially high number. The Right Thing
2019 is to sum the entry counts to the graph of blocks on this
2020 line, then find the elementary cycles of the local graph
2021 and add the transition counts of those cycles. */
2022 block_t
*block
, *block_p
, *block_n
;
2023 gcov_type count
= 0;
2025 /* Reverse the block information. */
2026 for (block
= line
->u
.blocks
, block_p
= NULL
; block
;
2027 block_p
= block
, block
= block_n
)
2029 block_n
= block
->chain
;
2030 block
->chain
= block_p
;
2031 block
->u
.cycle
.ident
= ix
;
2033 line
->u
.blocks
= block_p
;
2035 /* Sum the entry arcs. */
2036 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
2040 for (arc
= block
->pred
; arc
; arc
= arc
->pred_next
)
2042 if (arc
->src
->u
.cycle
.ident
!= ix
)
2043 count
+= arc
->count
;
2045 add_branch_counts (&src
->coverage
, arc
);
2048 /* Initialize the cs_count. */
2049 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2050 arc
->cs_count
= arc
->count
;
2053 /* Find the loops. This uses the algorithm described in
2054 Tiernan 'An Efficient Search Algorithm to Find the
2055 Elementary Circuits of a Graph', CACM Dec 1970. We hold
2056 the P array by having each block point to the arc that
2057 connects to the previous block. The H array is implicitly
2058 held because of the arc ordering, and the block's
2059 previous arc pointer.
2061 Although the algorithm is O(N^3) for highly connected
2062 graphs, at worst we'll have O(N^2), as most blocks have
2063 only one or two exits. Most graphs will be small.
2065 For each loop we find, locate the arc with the smallest
2066 transition count, and add that to the cumulative
2067 count. Decrease flow over the cycle and remove the arc
2068 from consideration. */
2069 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
2071 block_t
*head
= block
;
2079 block_t
*dst
= arc
->dst
;
2080 if (/* Already used that arc. */
2082 /* Not to same graph, or before first vertex. */
2083 || dst
->u
.cycle
.ident
!= ix
2084 /* Already in path. */
2085 || dst
->u
.cycle
.arc
)
2087 arc
= arc
->succ_next
;
2093 /* Found a closing arc. */
2094 gcov_type cycle_count
= arc
->cs_count
;
2095 arc_t
*cycle_arc
= arc
;
2098 /* Locate the smallest arc count of the loop. */
2099 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
2100 dst
= probe_arc
->src
)
2101 if (cycle_count
> probe_arc
->cs_count
)
2103 cycle_count
= probe_arc
->cs_count
;
2104 cycle_arc
= probe_arc
;
2107 count
+= cycle_count
;
2108 cycle_arc
->cycle
= 1;
2110 /* Remove the flow from the cycle. */
2111 arc
->cs_count
-= cycle_count
;
2112 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
2113 dst
= probe_arc
->src
)
2114 probe_arc
->cs_count
-= cycle_count
;
2116 /* Unwind to the cyclic arc. */
2117 while (head
!= cycle_arc
->src
)
2119 arc
= head
->u
.cycle
.arc
;
2120 head
->u
.cycle
.arc
= NULL
;
2124 arc
= arc
->succ_next
;
2128 /* Add new block to chain. */
2129 dst
->u
.cycle
.arc
= arc
;
2133 /* We could not add another vertex to the path. Remove
2134 the last vertex from the list. */
2135 arc
= head
->u
.cycle
.arc
;
2138 /* It was not the first vertex. Move onto next arc. */
2139 head
->u
.cycle
.arc
= NULL
;
2141 arc
= arc
->succ_next
;
2142 goto current_vertex
;
2144 /* Mark this block as unusable. */
2145 block
->u
.cycle
.ident
= ~0U;
2148 line
->count
= count
;
2153 src
->coverage
.lines
++;
2155 src
->coverage
.lines_executed
++;
2160 /* Output information about ARC number IX. Returns nonzero if
2161 anything is output. */
2164 output_branch_count (FILE *gcov_file
, int ix
, const arc_t
*arc
)
2166 if (arc
->is_call_non_return
)
2168 if (arc
->src
->count
)
2170 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
2171 format_gcov (arc
->src
->count
- arc
->count
,
2172 arc
->src
->count
, -flag_counts
));
2175 fnotice (gcov_file
, "call %2d never executed\n", ix
);
2177 else if (!arc
->is_unconditional
)
2179 if (arc
->src
->count
)
2180 fnotice (gcov_file
, "branch %2d taken %s%s\n", ix
,
2181 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
2182 arc
->fall_through
? " (fallthrough)"
2183 : arc
->is_throw
? " (throw)" : "");
2185 fnotice (gcov_file
, "branch %2d never executed\n", ix
);
2187 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
2189 if (arc
->src
->count
)
2190 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
2191 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
2193 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
2202 read_line (FILE *file
)
2204 static char *string
;
2205 static size_t string_len
;
2212 string
= XNEWVEC (char, string_len
);
2215 while ((ptr
= fgets (string
+ pos
, string_len
- pos
, file
)))
2217 size_t len
= strlen (string
+ pos
);
2219 if (string
[pos
+ len
- 1] == '\n')
2221 string
[pos
+ len
- 1] = 0;
2225 string
= XRESIZEVEC (char, string
, string_len
* 2);
2229 return pos
? string
: NULL
;
2232 /* Read in the source file one line at a time, and output that line to
2233 the gcov file preceded by its execution count and other
2237 output_lines (FILE *gcov_file
, const source_t
*src
)
2240 unsigned line_num
; /* current line number. */
2241 const line_t
*line
; /* current line info ptr. */
2242 const char *retval
= ""; /* status of source file reading. */
2243 function_t
*fn
= NULL
;
2245 fprintf (gcov_file
, "%9s:%5d:Source:%s\n", "-", 0, src
->coverage
.name
);
2246 if (!multiple_files
)
2248 fprintf (gcov_file
, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name
);
2249 fprintf (gcov_file
, "%9s:%5d:Data:%s\n", "-", 0,
2250 no_data_file
? "-" : da_file_name
);
2251 fprintf (gcov_file
, "%9s:%5d:Runs:%u\n", "-", 0, object_runs
);
2253 fprintf (gcov_file
, "%9s:%5d:Programs:%u\n", "-", 0, program_count
);
2255 source_file
= fopen (src
->name
, "r");
2258 fnotice (stderr
, "Cannot open source file %s\n", src
->name
);
2261 else if (src
->file_time
== 0)
2262 fprintf (gcov_file
, "%9s:%5d:Source is newer than graph\n", "-", 0);
2265 fn
= src
->functions
;
2267 for (line_num
= 1, line
= &src
->lines
[line_num
];
2268 line_num
< src
->num_lines
; line_num
++, line
++)
2270 for (; fn
&& fn
->line
== line_num
; fn
= fn
->line_next
)
2272 arc_t
*arc
= fn
->blocks
[EXIT_BLOCK
].pred
;
2273 gcov_type return_count
= fn
->blocks
[EXIT_BLOCK
].count
;
2274 gcov_type called_count
= fn
->blocks
[ENTRY_BLOCK
].count
;
2276 for (; arc
; arc
= arc
->pred_next
)
2278 return_count
-= arc
->count
;
2280 fprintf (gcov_file
, "function %s", fn
->name
);
2281 fprintf (gcov_file
, " called %s",
2282 format_gcov (called_count
, 0, -1));
2283 fprintf (gcov_file
, " returned %s",
2284 format_gcov (return_count
, called_count
, 0));
2285 fprintf (gcov_file
, " blocks executed %s",
2286 format_gcov (fn
->blocks_executed
, fn
->num_blocks
- 2, 0));
2287 fprintf (gcov_file
, "\n");
2291 retval
= read_line (source_file
);
2293 /* For lines which don't exist in the .bb file, print '-' before
2294 the source line. For lines which exist but were never
2295 executed, print '#####' or '=====' before the source line.
2296 Otherwise, print the execution count before the source line.
2297 There are 16 spaces of indentation added before the source
2298 line so that tabs won't be messed up. */
2299 fprintf (gcov_file
, "%9s:%5u:%s\n",
2300 !line
->exists
? "-" : line
->count
2301 ? format_gcov (line
->count
, 0, -1)
2302 : line
->unexceptional
? "#####" : "=====", line_num
,
2303 retval
? retval
: "/*EOF*/");
2305 if (flag_all_blocks
)
2311 for (ix
= jx
= 0, block
= line
->u
.blocks
; block
;
2312 block
= block
->chain
)
2314 if (!block
->is_call_return
)
2315 fprintf (gcov_file
, "%9s:%5u-block %2d\n",
2316 !line
->exists
? "-" : block
->count
2317 ? format_gcov (block
->count
, 0, -1)
2318 : block
->exceptional
? "%%%%%" : "$$$$$",
2321 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2322 jx
+= output_branch_count (gcov_file
, jx
, arc
);
2325 else if (flag_branches
)
2330 for (ix
= 0, arc
= line
->u
.branches
; arc
; arc
= arc
->line_next
)
2331 ix
+= output_branch_count (gcov_file
, ix
, arc
);
2335 /* Handle all remaining source lines. There may be lines after the
2336 last line of code. */
2339 for (; (retval
= read_line (source_file
)); line_num
++)
2340 fprintf (gcov_file
, "%9s:%5u:%s\n", "-", line_num
, retval
);
2344 fclose (source_file
);