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, 2012
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 compares 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 in the
63 gcno file, the profile data will be used. */
65 /* This is the size of the buffer used to read in source file lines. */
71 /* Describes an arc between two basic blocks. */
73 typedef struct arc_info
75 /* source and destination blocks. */
76 struct block_info
*src
;
77 struct block_info
*dst
;
79 /* transition counts. */
81 /* used in cycle search, so that we do not clobber original counts. */
84 unsigned int count_valid
: 1;
85 unsigned int on_tree
: 1;
86 unsigned int fake
: 1;
87 unsigned int fall_through
: 1;
89 /* Arc to a catch handler. */
90 unsigned int is_throw
: 1;
92 /* Arc is for a function that abnormally returns. */
93 unsigned int is_call_non_return
: 1;
95 /* Arc is for catch/setjmp. */
96 unsigned int is_nonlocal_return
: 1;
98 /* Is an unconditional branch. */
99 unsigned int is_unconditional
: 1;
101 /* Loop making arc. */
102 unsigned int cycle
: 1;
104 /* Next branch on line. */
105 struct arc_info
*line_next
;
107 /* Links to next arc on src and dst lists. */
108 struct arc_info
*succ_next
;
109 struct arc_info
*pred_next
;
112 /* Describes a basic block. Contains lists of arcs to successor and
113 predecessor blocks. */
115 typedef struct block_info
117 /* Chain of exit and entry arcs. */
121 /* Number of unprocessed exit and entry arcs. */
125 /* Block execution count. */
128 unsigned count_valid
: 1;
129 unsigned valid_chain
: 1;
130 unsigned invalid_chain
: 1;
131 unsigned exceptional
: 1;
133 /* Block is a call instrumenting site. */
134 unsigned is_call_site
: 1; /* Does the call. */
135 unsigned is_call_return
: 1; /* Is the return. */
137 /* Block is a landing pad for longjmp or throw. */
138 unsigned is_nonlocal_return
: 1;
144 /* Array of line numbers and source files. source files are
145 introduced by a linenumber of zero, the next 'line number' is
146 the number of the source file. Always starts with a source
150 } line
; /* Valid until blocks are linked onto lines */
153 /* Single line graph cycle workspace. Used for all-blocks
157 } cycle
; /* Used in all-blocks mode, after blocks are linked onto
161 /* Temporary chain for solving graph, and for chaining blocks on one
163 struct block_info
*chain
;
167 /* Describes a single function. Contains an array of basic blocks. */
169 typedef struct function_info
171 /* Name of function. */
174 unsigned lineno_checksum
;
175 unsigned cfg_checksum
;
177 /* The graph contains at least one fake incoming edge. */
178 unsigned has_catch
: 1;
180 /* Array of basic blocks. Like in GCC, the entry block is
181 at blocks[0] and the exit block is at blocks[1]. */
182 #define ENTRY_BLOCK (0)
183 #define EXIT_BLOCK (1)
186 unsigned blocks_executed
;
188 /* Raw arc coverage counts. */
192 /* First line number & file. */
196 /* Next function in same source file. */
197 struct function_info
*line_next
;
200 struct function_info
*next
;
203 /* Describes coverage of a file or function. */
205 typedef struct coverage_info
211 int branches_executed
;
220 /* Describes a single line of source. Contains a chain of basic blocks
223 typedef struct line_info
225 gcov_type count
; /* execution count */
228 arc_t
*branches
; /* branches from blocks that end on this
229 line. Used for branch-counts when not
231 block_t
*blocks
; /* blocks which start on this line. Used
232 in all-blocks mode. */
235 unsigned unexceptional
: 1;
238 /* Describes a file mentioned in the block graph. Contains an array
241 typedef struct source_info
243 /* Canonical name of source file. */
247 /* Array of line information. */
253 /* Functions in this source file. These are in ascending line
255 function_t
*functions
;
258 typedef struct name_map
260 char *name
; /* Source file name */
261 unsigned src
; /* Source file */
264 /* Holds a list of function basic block graphs. */
266 static function_t
*functions
;
267 static function_t
**fn_end
= &functions
;
269 static source_t
*sources
; /* Array of source files */
270 static unsigned n_sources
; /* Number of sources */
271 static unsigned a_sources
; /* Allocated sources */
273 static name_map_t
*names
; /* Mapping of file names to sources */
274 static unsigned n_names
; /* Number of names */
275 static unsigned a_names
; /* Allocated names */
277 /* This holds data summary information. */
279 static unsigned object_runs
;
280 static unsigned program_count
;
282 static unsigned total_lines
;
283 static unsigned total_executed
;
285 /* Modification time of graph file. */
287 static time_t bbg_file_time
;
289 /* Name of the notes (gcno) output file. The "bbg" prefix is for
290 historical reasons, when the notes file contained only the
291 basic block graph notes. */
293 static char *bbg_file_name
;
295 /* Stamp of the bbg file */
296 static unsigned bbg_stamp
;
298 /* Name and file pointer of the input file for the count data (gcda). */
300 static char *da_file_name
;
302 /* Data file is missing. */
304 static int no_data_file
;
306 /* If there is several input files, compute and display results after
307 reading all data files. This way if two or more gcda file refer to
308 the same source file (eg inline subprograms in a .h file), the
311 static int multiple_files
= 0;
313 /* Output branch probabilities. */
315 static int flag_branches
= 0;
317 /* Show unconditional branches too. */
318 static int flag_unconditional
= 0;
320 /* Output a gcov file if this is true. This is on by default, and can
321 be turned off by the -n option. */
323 static int flag_gcov_file
= 1;
325 /* Output progress indication if this is true. This is off by default
326 and can be turned on by the -d option. */
328 static int flag_display_progress
= 0;
330 /* For included files, make the gcov output file name include the name
331 of the input source file. For example, if x.h is included in a.c,
332 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
334 static int flag_long_names
= 0;
336 /* Output count information for every basic block, not merely those
337 that contain line number information. */
339 static int flag_all_blocks
= 0;
341 /* Output summary info for each function. */
343 static int flag_function_summary
= 0;
345 /* Object directory file prefix. This is the directory/file where the
346 graph and data files are looked for, if nonzero. */
348 static char *object_directory
= 0;
350 /* Source directory prefix. This is removed from source pathnames
351 that match, when generating the output file name. */
353 static char *source_prefix
= 0;
354 static size_t source_length
= 0;
356 /* Only show data for sources with relative pathnames. Absolute ones
357 usually indicate a system header file, which although it may
358 contain inline functions, is usually uninteresting. */
359 static int flag_relative_only
= 0;
361 /* Preserve all pathname components. Needed when object files and
362 source files are in subdirectories. '/' is mangled as '#', '.' is
363 elided and '..' mangled to '^'. */
365 static int flag_preserve_paths
= 0;
367 /* Output the number of times a branch was taken as opposed to the percentage
368 of times it was taken. */
370 static int flag_counts
= 0;
372 /* Forward declarations. */
373 static int process_args (int, char **);
374 static void print_usage (int) ATTRIBUTE_NORETURN
;
375 static void print_version (void) ATTRIBUTE_NORETURN
;
376 static void process_file (const char *);
377 static void generate_results (const char *);
378 static void create_file_names (const char *);
379 static int name_search (const void *, const void *);
380 static int name_sort (const void *, const void *);
381 static char *canonicalize_name (const char *);
382 static unsigned find_source (const char *);
383 static function_t
*read_graph_file (void);
384 static int read_count_file (function_t
*);
385 static void solve_flow_graph (function_t
*);
386 static void find_exception_blocks (function_t
*);
387 static void add_branch_counts (coverage_t
*, const arc_t
*);
388 static void add_line_counts (coverage_t
*, function_t
*);
389 static void executed_summary (unsigned, unsigned);
390 static void function_summary (const coverage_t
*, const char *);
391 static const char *format_gcov (gcov_type
, gcov_type
, int);
392 static void accumulate_line_counts (source_t
*);
393 static int output_branch_count (FILE *, int, const arc_t
*);
394 static void output_lines (FILE *, const source_t
*);
395 static char *make_gcov_file_name (const char *, const char *);
396 static char *mangle_name (const char *, char *);
397 static void release_structures (void);
398 static void release_function (function_t
*);
399 extern int main (int, char **);
402 main (int argc
, char **argv
)
408 p
= argv
[0] + strlen (argv
[0]);
409 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
413 xmalloc_set_program_name (progname
);
415 /* Unlock the stdio streams. */
416 unlock_std_streams ();
420 diagnostic_initialize (global_dc
, 0);
422 /* Handle response files. */
423 expandargv (&argc
, &argv
);
426 names
= XNEWVEC (name_map_t
, a_names
);
428 sources
= XNEWVEC (source_t
, a_sources
);
430 argno
= process_args (argc
, argv
);
434 if (argc
- argno
> 1)
439 for (; argno
!= argc
; argno
++)
441 if (flag_display_progress
)
442 printf("Processing file %d out of %d\n",
443 argno
- first_arg
+ 1, argc
- first_arg
);
444 process_file (argv
[argno
]);
447 generate_results (multiple_files
? NULL
: argv
[argc
- 1]);
449 release_structures ();
454 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
455 otherwise the output of --help. */
458 print_usage (int error_p
)
460 FILE *file
= error_p
? stderr
: stdout
;
461 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
463 fnotice (file
, "Usage: gcov [OPTION]... SOURCE|OBJ...\n\n");
464 fnotice (file
, "Print code coverage information.\n\n");
465 fnotice (file
, " -h, --help Print this help, then exit\n");
466 fnotice (file
, " -v, --version Print version number, then exit\n");
467 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
468 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
469 fnotice (file
, " -c, --branch-counts Given counts of branches taken\n\
470 rather than percentages\n");
471 fnotice (file
, " -n, --no-output Do not create an output file\n");
472 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
474 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
475 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
476 fnotice (file
, " -s, --source-prefix DIR Source prefix to elide\n");
477 fnotice (file
, " -r, --relative-only Only show data for relative sources\n");
478 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
479 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
480 fnotice (file
, " -d, --display-progress Display progress information\n");
481 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
486 /* Print version information and exit. */
491 fnotice (stdout
, "gcov %s%s\n", pkgversion_string
, version_string
);
492 fprintf (stdout
, "Copyright %s 2012 Free Software Foundation, Inc.\n",
495 _("This is free software; see the source for copying conditions.\n"
496 "There is NO warranty; not even for MERCHANTABILITY or \n"
497 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
498 exit (SUCCESS_EXIT_CODE
);
501 static const struct option options
[] =
503 { "help", no_argument
, NULL
, 'h' },
504 { "version", no_argument
, NULL
, 'v' },
505 { "all-blocks", no_argument
, NULL
, 'a' },
506 { "branch-probabilities", no_argument
, NULL
, 'b' },
507 { "branch-counts", no_argument
, NULL
, 'c' },
508 { "no-output", no_argument
, NULL
, 'n' },
509 { "long-file-names", no_argument
, NULL
, 'l' },
510 { "function-summaries", no_argument
, NULL
, 'f' },
511 { "preserve-paths", no_argument
, NULL
, 'p' },
512 { "relative-only", no_argument
, NULL
, 'r' },
513 { "object-directory", required_argument
, NULL
, 'o' },
514 { "object-file", required_argument
, NULL
, 'o' },
515 { "source-prefix", required_argument
, NULL
, 's' },
516 { "unconditional-branches", no_argument
, NULL
, 'u' },
517 { "display-progress", no_argument
, NULL
, 'd' },
521 /* Process args, return index to first non-arg. */
524 process_args (int argc
, char **argv
)
528 while ((opt
= getopt_long (argc
, argv
, "abcdfhlno:s:pruv", options
, NULL
)) != -1)
542 flag_function_summary
= 1;
546 /* print_usage will exit. */
554 object_directory
= optarg
;
557 source_prefix
= optarg
;
558 source_length
= strlen (source_prefix
);
561 flag_relative_only
= 1;
564 flag_preserve_paths
= 1;
567 flag_unconditional
= 1;
570 flag_display_progress
= 1;
574 /* print_version will exit. */
577 /* print_usage will exit. */
584 /* Process a single input file. */
587 process_file (const char *file_name
)
591 create_file_names (file_name
);
592 fns
= read_graph_file ();
596 read_count_file (fns
);
599 function_t
*fn
= fns
;
605 unsigned src
= fn
->src
;
606 unsigned line
= fn
->line
;
608 function_t
*probe
, **prev
;
610 /* Now insert it into the source file's list of
611 functions. Normally functions will be encountered in
612 ascending order, so a simple scan is quick. Note we're
613 building this list in reverse order. */
614 for (prev
= &sources
[src
].functions
;
615 (probe
= *prev
); prev
= &probe
->line_next
)
616 if (probe
->line
<= line
)
618 fn
->line_next
= probe
;
621 /* Mark last line in files touched by function. */
622 for (block_no
= 0; block_no
!= fn
->num_blocks
; block_no
++)
624 unsigned *enc
= fn
->blocks
[block_no
].u
.line
.encoding
;
625 unsigned num
= fn
->blocks
[block_no
].u
.line
.num
;
632 if (line
>= sources
[src
].num_lines
)
633 sources
[src
].num_lines
= line
+ 1;
640 else if (*enc
> line
)
643 if (line
>= sources
[src
].num_lines
)
644 sources
[src
].num_lines
= line
+ 1;
646 solve_flow_graph (fn
);
648 find_exception_blocks (fn
);
653 /* The function was not in the executable -- some other
654 instance must have been selected. */
655 release_function (fn
);
660 generate_results (const char *file_name
)
666 for (ix
= n_sources
, src
= sources
; ix
--; src
++)
668 src
->lines
= XCNEWVEC (line_t
, src
->num_lines
);
670 for (fn
= functions
; fn
; fn
= fn
->next
)
674 memset (&coverage
, 0, sizeof (coverage
));
675 coverage
.name
= fn
->name
;
676 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
677 if (flag_function_summary
)
679 function_summary (&coverage
, "Function");
680 fnotice (stdout
, "\n");
686 name_map_t
*name_map
= (name_map_t
*)bsearch
687 (file_name
, names
, n_names
, sizeof (*names
), name_search
);
689 file_name
= sources
[name_map
->src
].coverage
.name
;
691 file_name
= canonicalize_name (file_name
);
694 for (ix
= n_sources
, src
= sources
; ix
--; src
++)
696 if (flag_relative_only
)
698 /* Ignore this source, if it is an absolute path (after
699 source prefix removal). */
700 char first
= src
->coverage
.name
[0];
702 #if HAVE_DOS_BASED_FILE_SYSTEM
703 if (first
&& src
->coverage
.name
[1] == ':')
704 first
= src
->coverage
.name
[2];
706 if (IS_DIR_SEPARATOR (first
))
710 accumulate_line_counts (src
);
711 function_summary (&src
->coverage
, "File");
712 total_lines
+= src
->coverage
.lines
;
713 total_executed
+= src
->coverage
.lines_executed
;
717 = make_gcov_file_name (file_name
, src
->coverage
.name
);
719 if (src
->coverage
.lines
)
721 FILE *gcov_file
= fopen (gcov_file_name
, "w");
725 fnotice (stdout
, "Creating '%s'\n", gcov_file_name
);
726 output_lines (gcov_file
, src
);
727 if (ferror (gcov_file
))
728 fnotice (stderr
, "Error writing output file '%s'\n",
733 fnotice (stderr
, "Could not open output file '%s'\n",
738 unlink (gcov_file_name
);
739 fnotice (stdout
, "Removing '%s'\n", gcov_file_name
);
741 free (gcov_file_name
);
743 fnotice (stdout
, "\n");
747 executed_summary (total_lines
, total_executed
);
750 /* Release a function structure */
753 release_function (function_t
*fn
)
758 for (ix
= fn
->num_blocks
, block
= fn
->blocks
; ix
--; block
++)
762 for (arc
= block
->succ
; arc
; arc
= arc_n
)
764 arc_n
= arc
->succ_next
;
772 /* Release all memory used. */
775 release_structures (void)
780 for (ix
= n_sources
; ix
--;)
781 free (sources
[ix
].lines
);
784 for (ix
= n_names
; ix
--;)
785 free (names
[ix
].name
);
788 while ((fn
= functions
))
790 functions
= fn
->next
;
791 release_function (fn
);
795 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
796 is not specified, these are named from FILE_NAME sans extension. If
797 OBJECT_DIRECTORY is specified and is a directory, the files are in that
798 directory, but named from the basename of the FILE_NAME, sans extension.
799 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
800 and the data files are named from that. */
803 create_file_names (const char *file_name
)
807 int length
= strlen (file_name
);
810 /* Free previous file names. */
811 free (bbg_file_name
);
813 da_file_name
= bbg_file_name
= NULL
;
817 if (object_directory
&& object_directory
[0])
821 length
+= strlen (object_directory
) + 2;
822 name
= XNEWVEC (char, length
);
825 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
826 strcat (name
, object_directory
);
827 if (base
&& (! IS_DIR_SEPARATOR (name
[strlen (name
) - 1])))
832 name
= XNEWVEC (char, length
+ 1);
833 strcpy (name
, file_name
);
839 /* Append source file name. */
840 const char *cptr
= lbasename (file_name
);
841 strcat (name
, cptr
? cptr
: file_name
);
844 /* Remove the extension. */
845 cptr
= strrchr (CONST_CAST (char *, lbasename (name
)), '.');
849 length
= strlen (name
);
851 bbg_file_name
= XNEWVEC (char, length
+ strlen (GCOV_NOTE_SUFFIX
) + 1);
852 strcpy (bbg_file_name
, name
);
853 strcpy (bbg_file_name
+ length
, GCOV_NOTE_SUFFIX
);
855 da_file_name
= XNEWVEC (char, length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
856 strcpy (da_file_name
, name
);
857 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
863 /* A is a string and B is a pointer to name_map_t. Compare for file
864 name orderability. */
867 name_search (const void *a_
, const void *b_
)
869 const char *a
= (const char *)a_
;
870 const name_map_t
*b
= (const name_map_t
*)b_
;
872 #if HAVE_DOS_BASED_FILE_SYSTEM
873 return strcasecmp (a
, b
->name
);
875 return strcmp (a
, b
->name
);
879 /* A and B are a pointer to name_map_t. Compare for file name
883 name_sort (const void *a_
, const void *b_
)
885 const name_map_t
*a
= (const name_map_t
*)a_
;
886 return name_search (a
->name
, b_
);
889 /* Find or create a source file structure for FILE_NAME. Copies
890 FILE_NAME on creation */
893 find_source (const char *file_name
)
895 name_map_t
*name_map
;
901 file_name
= "<unknown>";
902 name_map
= (name_map_t
*)bsearch
903 (file_name
, names
, n_names
, sizeof (*names
), name_search
);
910 if (n_names
+ 2 > a_names
)
912 /* Extend the name map array -- we'll be inserting one or two
915 name_map
= XNEWVEC (name_map_t
, a_names
);
916 memcpy (name_map
, names
, n_names
* sizeof (*names
));
921 /* Not found, try the canonical name. */
922 canon
= canonicalize_name (file_name
);
923 name_map
= (name_map_t
*)bsearch
924 (canon
, names
, n_names
, sizeof (*names
), name_search
);
927 /* Not found with canonical name, create a new source. */
930 if (n_sources
== a_sources
)
933 src
= XNEWVEC (source_t
, a_sources
);
934 memcpy (src
, sources
, n_sources
* sizeof (*sources
));
941 name_map
= &names
[n_names
++];
942 name_map
->name
= canon
;
945 src
= &sources
[n_sources
++];
946 memset (src
, 0, sizeof (*src
));
948 src
->coverage
.name
= src
->name
;
950 #if HAVE_DOS_BASED_FILE_SYSTEM
951 /* You lose if separators don't match exactly in the
953 && !strncasecmp (source_prefix
, src
->coverage
.name
, source_length
)
955 && !strncmp (source_prefix
, src
->coverage
.name
, source_length
)
957 && IS_DIR_SEPARATOR (src
->coverage
.name
[source_length
]))
958 src
->coverage
.name
+= source_length
+ 1;
959 if (!stat (src
->name
, &status
))
960 src
->file_time
= status
.st_mtime
;
965 if (name_search (file_name
, name_map
))
967 /* Append the non-canonical name. */
968 name_map
= &names
[n_names
++];
969 name_map
->name
= xstrdup (file_name
);
973 /* Resort the name map. */
974 qsort (names
, n_names
, sizeof (*names
), name_sort
);
977 if (sources
[idx
].file_time
> bbg_file_time
)
979 static int info_emitted
;
981 fnotice (stderr
, "%s:source file is newer than notes file '%s'\n",
982 file_name
, bbg_file_name
);
986 "(the message is only displayed one per source file)\n");
989 sources
[idx
].file_time
= 0;
995 /* Read the notes file. Return list of functions read -- in reverse order. */
998 read_graph_file (void)
1001 unsigned current_tag
= 0;
1002 function_t
*fn
= NULL
;
1003 function_t
*fns
= NULL
;
1004 function_t
**fns_end
= &fns
;
1005 unsigned src_idx
= 0;
1009 if (!gcov_open (bbg_file_name
, 1))
1011 fnotice (stderr
, "%s:cannot open notes file\n", bbg_file_name
);
1014 bbg_file_time
= gcov_time ();
1015 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC
))
1017 fnotice (stderr
, "%s:not a gcov notes file\n", bbg_file_name
);
1022 version
= gcov_read_unsigned ();
1023 if (version
!= GCOV_VERSION
)
1027 GCOV_UNSIGNED2STRING (v
, version
);
1028 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1030 fnotice (stderr
, "%s:version '%.4s', prefer '%.4s'\n",
1031 bbg_file_name
, v
, e
);
1033 bbg_stamp
= gcov_read_unsigned ();
1035 while ((tag
= gcov_read_unsigned ()))
1037 unsigned length
= gcov_read_unsigned ();
1038 gcov_position_t base
= gcov_position ();
1040 if (tag
== GCOV_TAG_FUNCTION
)
1042 char *function_name
;
1043 unsigned ident
, lineno
;
1044 unsigned lineno_checksum
, cfg_checksum
;
1046 ident
= gcov_read_unsigned ();
1047 lineno_checksum
= gcov_read_unsigned ();
1048 cfg_checksum
= gcov_read_unsigned ();
1049 function_name
= xstrdup (gcov_read_string ());
1050 src_idx
= find_source (gcov_read_string ());
1051 lineno
= gcov_read_unsigned ();
1053 fn
= XCNEW (function_t
);
1054 fn
->name
= function_name
;
1056 fn
->lineno_checksum
= lineno_checksum
;
1057 fn
->cfg_checksum
= cfg_checksum
;
1061 fn
->line_next
= NULL
;
1064 fns_end
= &fn
->next
;
1067 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
1070 fnotice (stderr
, "%s:already seen blocks for '%s'\n",
1071 bbg_file_name
, fn
->name
);
1074 unsigned ix
, num_blocks
= GCOV_TAG_BLOCKS_NUM (length
);
1075 fn
->num_blocks
= num_blocks
;
1077 fn
->blocks
= XCNEWVEC (block_t
, fn
->num_blocks
);
1078 for (ix
= 0; ix
!= num_blocks
; ix
++)
1079 fn
->blocks
[ix
].flags
= gcov_read_unsigned ();
1082 else if (fn
&& tag
== GCOV_TAG_ARCS
)
1084 unsigned src
= gcov_read_unsigned ();
1085 unsigned num_dests
= GCOV_TAG_ARCS_NUM (length
);
1086 block_t
*src_blk
= &fn
->blocks
[src
];
1087 unsigned mark_catches
= 0;
1088 struct arc_info
*arc
;
1090 if (src
>= fn
->num_blocks
|| fn
->blocks
[src
].succ
)
1095 unsigned dest
= gcov_read_unsigned ();
1096 unsigned flags
= gcov_read_unsigned ();
1098 if (dest
>= fn
->num_blocks
)
1100 arc
= XCNEW (arc_t
);
1102 arc
->dst
= &fn
->blocks
[dest
];
1106 arc
->count_valid
= 0;
1107 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
1108 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
1109 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
1111 arc
->succ_next
= src_blk
->succ
;
1112 src_blk
->succ
= arc
;
1113 src_blk
->num_succ
++;
1115 arc
->pred_next
= fn
->blocks
[dest
].pred
;
1116 fn
->blocks
[dest
].pred
= arc
;
1117 fn
->blocks
[dest
].num_pred
++;
1123 /* Exceptional exit from this function, the
1124 source block must be a call. */
1125 fn
->blocks
[src
].is_call_site
= 1;
1126 arc
->is_call_non_return
= 1;
1131 /* Non-local return from a callee of this
1132 function. The destination block is a setjmp. */
1133 arc
->is_nonlocal_return
= 1;
1134 fn
->blocks
[dest
].is_nonlocal_return
= 1;
1144 /* We have a fake exit from this block. The other
1145 non-fall through exits must be to catch handlers.
1146 Mark them as catch arcs. */
1148 for (arc
= src_blk
->succ
; arc
; arc
= arc
->succ_next
)
1149 if (!arc
->fake
&& !arc
->fall_through
)
1156 else if (fn
&& tag
== GCOV_TAG_LINES
)
1158 unsigned blockno
= gcov_read_unsigned ();
1159 unsigned *line_nos
= XCNEWVEC (unsigned, length
- 1);
1161 if (blockno
>= fn
->num_blocks
|| fn
->blocks
[blockno
].u
.line
.encoding
)
1166 unsigned lineno
= gcov_read_unsigned ();
1173 line_nos
[ix
++] = src_idx
;
1175 line_nos
[ix
++] = lineno
;
1179 const char *file_name
= gcov_read_string ();
1183 src_idx
= find_source (file_name
);
1185 line_nos
[ix
++] = src_idx
;
1189 fn
->blocks
[blockno
].u
.line
.encoding
= line_nos
;
1190 fn
->blocks
[blockno
].u
.line
.num
= ix
;
1192 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
1197 gcov_sync (base
, length
);
1198 if (gcov_is_error ())
1201 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
1208 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
1213 /* Reads profiles from the count file and attach to each
1214 function. Return nonzero if fatal error. */
1217 read_count_file (function_t
*fns
)
1222 function_t
*fn
= NULL
;
1225 if (!gcov_open (da_file_name
, 1))
1227 fnotice (stderr
, "%s:cannot open data file, assuming not executed\n",
1232 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
1234 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
1239 version
= gcov_read_unsigned ();
1240 if (version
!= GCOV_VERSION
)
1244 GCOV_UNSIGNED2STRING (v
, version
);
1245 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1247 fnotice (stderr
, "%s:version '%.4s', prefer version '%.4s'\n",
1248 da_file_name
, v
, e
);
1250 tag
= gcov_read_unsigned ();
1251 if (tag
!= bbg_stamp
)
1253 fnotice (stderr
, "%s:stamp mismatch with notes file\n", da_file_name
);
1257 while ((tag
= gcov_read_unsigned ()))
1259 unsigned length
= gcov_read_unsigned ();
1260 unsigned long base
= gcov_position ();
1262 if (tag
== GCOV_TAG_PROGRAM_SUMMARY
)
1264 struct gcov_summary summary
;
1265 gcov_read_summary (&summary
);
1266 object_runs
+= summary
.ctrs
[GCOV_COUNTER_ARCS
].runs
;
1269 else if (tag
== GCOV_TAG_FUNCTION
&& !length
)
1271 else if (tag
== GCOV_TAG_FUNCTION
&& length
== GCOV_TAG_FUNCTION_LENGTH
)
1274 struct function_info
*fn_n
;
1276 /* Try to find the function in the list. To speed up the
1277 search, first start from the last function found. */
1278 ident
= gcov_read_unsigned ();
1280 for (fn
= fn
? fn
->next
: NULL
; ; fn
= fn
->next
)
1284 else if ((fn
= fn_n
))
1288 fnotice (stderr
, "%s:unknown function '%u'\n",
1289 da_file_name
, ident
);
1292 if (fn
->ident
== ident
)
1298 else if (gcov_read_unsigned () != fn
->lineno_checksum
1299 || gcov_read_unsigned () != fn
->cfg_checksum
)
1302 fnotice (stderr
, "%s:profile mismatch for '%s'\n",
1303 da_file_name
, fn
->name
);
1307 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
1309 if (length
!= GCOV_TAG_COUNTER_LENGTH (fn
->num_counts
))
1313 fn
->counts
= XCNEWVEC (gcov_type
, fn
->num_counts
);
1315 for (ix
= 0; ix
!= fn
->num_counts
; ix
++)
1316 fn
->counts
[ix
] += gcov_read_counter ();
1318 gcov_sync (base
, length
);
1319 if ((error
= gcov_is_error ()))
1321 fnotice (stderr
, error
< 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1331 /* Solve the flow graph. Propagate counts from the instrumented arcs
1332 to the blocks and the uninstrumented arcs. */
1335 solve_flow_graph (function_t
*fn
)
1339 gcov_type
*count_ptr
= fn
->counts
;
1341 block_t
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
1342 block_t
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
1344 /* The arcs were built in reverse order. Fix that now. */
1345 for (ix
= fn
->num_blocks
; ix
--;)
1347 arc_t
*arc_p
, *arc_n
;
1349 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
1350 arc_p
= arc
, arc
= arc_n
)
1352 arc_n
= arc
->succ_next
;
1353 arc
->succ_next
= arc_p
;
1355 fn
->blocks
[ix
].succ
= arc_p
;
1357 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
1358 arc_p
= arc
, arc
= arc_n
)
1360 arc_n
= arc
->pred_next
;
1361 arc
->pred_next
= arc_p
;
1363 fn
->blocks
[ix
].pred
= arc_p
;
1366 if (fn
->num_blocks
< 2)
1367 fnotice (stderr
, "%s:'%s' lacks entry and/or exit blocks\n",
1368 bbg_file_name
, fn
->name
);
1371 if (fn
->blocks
[ENTRY_BLOCK
].num_pred
)
1372 fnotice (stderr
, "%s:'%s' has arcs to entry block\n",
1373 bbg_file_name
, fn
->name
);
1375 /* We can't deduce the entry block counts from the lack of
1377 fn
->blocks
[ENTRY_BLOCK
].num_pred
= ~(unsigned)0;
1379 if (fn
->blocks
[EXIT_BLOCK
].num_succ
)
1380 fnotice (stderr
, "%s:'%s' has arcs from exit block\n",
1381 bbg_file_name
, fn
->name
);
1383 /* Likewise, we can't deduce exit block counts from the lack
1384 of its successors. */
1385 fn
->blocks
[EXIT_BLOCK
].num_succ
= ~(unsigned)0;
1388 /* Propagate the measured counts, this must be done in the same
1389 order as the code in profile.c */
1390 for (ix
= 0, blk
= fn
->blocks
; ix
!= fn
->num_blocks
; ix
++, blk
++)
1392 block_t
const *prev_dst
= NULL
;
1393 int out_of_order
= 0;
1394 int non_fake_succ
= 0;
1396 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1404 arc
->count
= *count_ptr
++;
1405 arc
->count_valid
= 1;
1407 arc
->dst
->num_pred
--;
1409 if (prev_dst
&& prev_dst
> arc
->dst
)
1411 prev_dst
= arc
->dst
;
1413 if (non_fake_succ
== 1)
1415 /* If there is only one non-fake exit, it is an
1416 unconditional branch. */
1417 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1420 arc
->is_unconditional
= 1;
1421 /* If this block is instrumenting a call, it might be
1422 an artificial block. It is not artificial if it has
1423 a non-fallthrough exit, or the destination of this
1424 arc has more than one entry. Mark the destination
1425 block as a return site, if none of those conditions
1427 if (blk
->is_call_site
&& arc
->fall_through
1428 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
1429 arc
->dst
->is_call_return
= 1;
1433 /* Sort the successor arcs into ascending dst order. profile.c
1434 normally produces arcs in the right order, but sometimes with
1435 one or two out of order. We're not using a particularly
1439 arc_t
*start
= blk
->succ
;
1440 unsigned changes
= 1;
1444 arc_t
*arc
, *arc_p
, *arc_n
;
1447 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
1449 if (arc
->dst
> arc_n
->dst
)
1453 arc_p
->succ_next
= arc_n
;
1456 arc
->succ_next
= arc_n
->succ_next
;
1457 arc_n
->succ_next
= arc
;
1470 /* Place it on the invalid chain, it will be ignored if that's
1472 blk
->invalid_chain
= 1;
1473 blk
->chain
= invalid_blocks
;
1474 invalid_blocks
= blk
;
1477 while (invalid_blocks
|| valid_blocks
)
1479 while ((blk
= invalid_blocks
))
1481 gcov_type total
= 0;
1484 invalid_blocks
= blk
->chain
;
1485 blk
->invalid_chain
= 0;
1487 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1488 total
+= arc
->count
;
1489 else if (!blk
->num_pred
)
1490 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1491 total
+= arc
->count
;
1496 blk
->count_valid
= 1;
1497 blk
->chain
= valid_blocks
;
1498 blk
->valid_chain
= 1;
1501 while ((blk
= valid_blocks
))
1504 arc_t
*arc
, *inv_arc
;
1506 valid_blocks
= blk
->chain
;
1507 blk
->valid_chain
= 0;
1508 if (blk
->num_succ
== 1)
1514 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1516 total
-= arc
->count
;
1517 if (!arc
->count_valid
)
1521 inv_arc
->count_valid
= 1;
1522 inv_arc
->count
= total
;
1525 if (dst
->count_valid
)
1527 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
1529 dst
->chain
= valid_blocks
;
1530 dst
->valid_chain
= 1;
1536 if (!dst
->num_pred
&& !dst
->invalid_chain
)
1538 dst
->chain
= invalid_blocks
;
1539 dst
->invalid_chain
= 1;
1540 invalid_blocks
= dst
;
1544 if (blk
->num_pred
== 1)
1550 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1552 total
-= arc
->count
;
1553 if (!arc
->count_valid
)
1557 inv_arc
->count_valid
= 1;
1558 inv_arc
->count
= total
;
1561 if (src
->count_valid
)
1563 if (src
->num_succ
== 1 && !src
->valid_chain
)
1565 src
->chain
= valid_blocks
;
1566 src
->valid_chain
= 1;
1572 if (!src
->num_succ
&& !src
->invalid_chain
)
1574 src
->chain
= invalid_blocks
;
1575 src
->invalid_chain
= 1;
1576 invalid_blocks
= src
;
1583 /* If the graph has been correctly solved, every block will have a
1585 for (ix
= 0; ix
< fn
->num_blocks
; ix
++)
1586 if (!fn
->blocks
[ix
].count_valid
)
1588 fnotice (stderr
, "%s:graph is unsolvable for '%s'\n",
1589 bbg_file_name
, fn
->name
);
1594 /* Mark all the blocks only reachable via an incoming catch. */
1597 find_exception_blocks (function_t
*fn
)
1600 block_t
**queue
= XALLOCAVEC (block_t
*, fn
->num_blocks
);
1602 /* First mark all blocks as exceptional. */
1603 for (ix
= fn
->num_blocks
; ix
--;)
1604 fn
->blocks
[ix
].exceptional
= 1;
1606 /* Now mark all the blocks reachable via non-fake edges */
1607 queue
[0] = fn
->blocks
;
1608 queue
[0]->exceptional
= 0;
1611 block_t
*block
= queue
[--ix
];
1614 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1615 if (!arc
->fake
&& !arc
->is_throw
&& arc
->dst
->exceptional
)
1617 arc
->dst
->exceptional
= 0;
1618 queue
[ix
++] = arc
->dst
;
1624 /* Increment totals in COVERAGE according to arc ARC. */
1627 add_branch_counts (coverage_t
*coverage
, const arc_t
*arc
)
1629 if (arc
->is_call_non_return
)
1632 if (arc
->src
->count
)
1633 coverage
->calls_executed
++;
1635 else if (!arc
->is_unconditional
)
1637 coverage
->branches
++;
1638 if (arc
->src
->count
)
1639 coverage
->branches_executed
++;
1641 coverage
->branches_taken
++;
1645 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
1646 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1647 If DP is zero, no decimal point is printed. Only print 100% when
1648 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1649 format TOP. Return pointer to a static string. */
1652 format_gcov (gcov_type top
, gcov_type bottom
, int dp
)
1654 static char buffer
[20];
1658 float ratio
= bottom
? (float)top
/ bottom
: 0;
1660 unsigned limit
= 100;
1663 for (ix
= dp
; ix
--; )
1666 percent
= (unsigned) (ratio
* limit
+ (float)0.5);
1667 if (percent
<= 0 && top
)
1669 else if (percent
>= limit
&& top
!= bottom
)
1670 percent
= limit
- 1;
1671 ix
= sprintf (buffer
, "%.*u%%", dp
+ 1, percent
);
1677 buffer
[ix
+1] = buffer
[ix
];
1681 buffer
[ix
+ 1] = '.';
1685 sprintf (buffer
, HOST_WIDEST_INT_PRINT_DEC
, (HOST_WIDEST_INT
)top
);
1690 /* Summary of execution */
1693 executed_summary (unsigned lines
, unsigned executed
)
1696 fnotice (stdout
, "Lines executed:%s of %d\n",
1697 format_gcov (executed
, lines
, 2), lines
);
1699 fnotice (stdout
, "No executable lines\n");
1702 /* Output summary info for a function or file. */
1705 function_summary (const coverage_t
*coverage
, const char *title
)
1707 fnotice (stdout
, "%s '%s'\n", title
, coverage
->name
);
1708 executed_summary (coverage
->lines
, coverage
->lines_executed
);
1712 if (coverage
->branches
)
1714 fnotice (stdout
, "Branches executed:%s of %d\n",
1715 format_gcov (coverage
->branches_executed
,
1716 coverage
->branches
, 2),
1717 coverage
->branches
);
1718 fnotice (stdout
, "Taken at least once:%s of %d\n",
1719 format_gcov (coverage
->branches_taken
,
1720 coverage
->branches
, 2),
1721 coverage
->branches
);
1724 fnotice (stdout
, "No branches\n");
1725 if (coverage
->calls
)
1726 fnotice (stdout
, "Calls executed:%s of %d\n",
1727 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
1730 fnotice (stdout
, "No calls\n");
1734 /* Canonicalize the filename NAME by canonicalizing directory
1735 separators, eliding . components and resolving .. components
1736 appropriately. Always returns a unique string. */
1739 canonicalize_name (const char *name
)
1741 /* The canonical name cannot be longer than the incoming name. */
1742 char *result
= XNEWVEC (char, strlen (name
) + 1);
1743 const char *base
= name
, *probe
;
1748 #if HAVE_DOS_BASED_FILE_SYSTEM
1749 if (base
[0] && base
[1] == ':')
1751 result
[0] = base
[0];
1757 for (dd_base
= ptr
; *base
; base
= probe
)
1761 for (probe
= base
; *probe
; probe
++)
1762 if (IS_DIR_SEPARATOR (*probe
))
1766 if (len
== 1 && base
[0] == '.')
1767 /* Elide a '.' directory */
1769 else if (len
== 2 && base
[0] == '.' && base
[1] == '.')
1771 /* '..', we can only elide it and the previous directory, if
1772 we're not a symlink. */
1773 struct stat ATTRIBUTE_UNUSED buf
;
1777 #if defined (S_ISLNK)
1778 /* S_ISLNK is not POSIX.1-1996. */
1779 || stat (result
, &buf
) || S_ISLNK (buf
.st_mode
)
1783 /* Cannot elide, or unreadable or a symlink. */
1784 dd_base
= ptr
+ 2 + slash
;
1787 while (ptr
!= dd_base
&& *ptr
!= '/')
1789 slash
= ptr
!= result
;
1794 /* Regular pathname component. */
1797 memcpy (ptr
, base
, len
);
1802 for (; IS_DIR_SEPARATOR (*probe
); probe
++)
1810 /* Generate an output file name. INPUT_NAME is the canonicalized main
1811 input file and SRC_NAME is the canonicalized file name.
1812 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
1813 long_output_names we prepend the processed name of the input file
1814 to each output name (except when the current source file is the
1815 input file, so you don't get a double concatenation). The two
1816 components are separated by '##'. With preserve_paths we create a
1817 filename from all path components of the source file, replacing '/'
1818 with '#', and .. with '^', without it we simply take the basename
1819 component. (Remember, the canonicalized name will already have
1820 elided '.' components and converted \\ separators.) */
1823 make_gcov_file_name (const char *input_name
, const char *src_name
)
1828 if (flag_long_names
&& input_name
&& strcmp (src_name
, input_name
))
1830 /* Generate the input filename part. */
1831 result
= XNEWVEC (char, strlen (input_name
) + strlen (src_name
) + 10);
1834 ptr
= mangle_name (input_name
, ptr
);
1835 ptr
[0] = ptr
[1] = '#';
1840 result
= XNEWVEC (char, strlen (src_name
) + 10);
1844 ptr
= mangle_name (src_name
, ptr
);
1845 strcpy (ptr
, ".gcov");
1851 mangle_name (char const *base
, char *ptr
)
1855 /* Generate the source filename part. */
1856 if (!flag_preserve_paths
)
1858 base
= lbasename (base
);
1859 len
= strlen (base
);
1860 memcpy (ptr
, base
, len
);
1865 /* Convert '/' to '#', convert '..' to '^',
1866 convert ':' to '~' on DOS based file system. */
1869 #if HAVE_DOS_BASED_FILE_SYSTEM
1870 if (base
[0] && base
[1] == ':')
1878 for (; *base
; base
= probe
)
1882 for (probe
= base
; *probe
; probe
++)
1886 if (len
== 2 && base
[0] == '.' && base
[1] == '.')
1890 memcpy (ptr
, base
, len
);
1904 /* Scan through the bb_data for each line in the block, increment
1905 the line number execution count indicated by the execution count of
1906 the appropriate basic block. */
1909 add_line_counts (coverage_t
*coverage
, function_t
*fn
)
1912 line_t
*line
= NULL
; /* This is propagated from one iteration to the
1915 /* Scan each basic block. */
1916 for (ix
= 0; ix
!= fn
->num_blocks
; ix
++)
1918 block_t
*block
= &fn
->blocks
[ix
];
1920 const source_t
*src
= NULL
;
1923 if (block
->count
&& ix
&& ix
+ 1 != fn
->num_blocks
)
1924 fn
->blocks_executed
++;
1925 for (jx
= 0, encoding
= block
->u
.line
.encoding
;
1926 jx
!= block
->u
.line
.num
; jx
++, encoding
++)
1929 src
= &sources
[*++encoding
];
1934 line
= &src
->lines
[*encoding
];
1940 if (!line
->count
&& block
->count
)
1941 coverage
->lines_executed
++;
1944 if (!block
->exceptional
)
1945 line
->unexceptional
= 1;
1946 line
->count
+= block
->count
;
1948 free (block
->u
.line
.encoding
);
1949 block
->u
.cycle
.arc
= NULL
;
1950 block
->u
.cycle
.ident
= ~0U;
1952 if (!ix
|| ix
+ 1 == fn
->num_blocks
)
1953 /* Entry or exit block */;
1954 else if (flag_all_blocks
)
1956 line_t
*block_line
= line
;
1959 block_line
= &sources
[fn
->src
].lines
[fn
->line
];
1961 block
->chain
= block_line
->u
.blocks
;
1962 block_line
->u
.blocks
= block
;
1964 else if (flag_branches
)
1968 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1970 arc
->line_next
= line
->u
.branches
;
1971 line
->u
.branches
= arc
;
1972 if (coverage
&& !arc
->is_unconditional
)
1973 add_branch_counts (coverage
, arc
);
1978 fnotice (stderr
, "%s:no lines for '%s'\n", bbg_file_name
, fn
->name
);
1981 /* Accumulate the line counts of a file. */
1984 accumulate_line_counts (source_t
*src
)
1987 function_t
*fn
, *fn_p
, *fn_n
;
1990 /* Reverse the function order. */
1991 for (fn
= src
->functions
, fn_p
= NULL
; fn
;
1992 fn_p
= fn
, fn
= fn_n
)
1994 fn_n
= fn
->line_next
;
1995 fn
->line_next
= fn_p
;
1997 src
->functions
= fn_p
;
1999 for (ix
= src
->num_lines
, line
= src
->lines
; ix
--; line
++)
2001 if (!flag_all_blocks
)
2003 arc_t
*arc
, *arc_p
, *arc_n
;
2005 /* Total and reverse the branch information. */
2006 for (arc
= line
->u
.branches
, arc_p
= NULL
; arc
;
2007 arc_p
= arc
, arc
= arc_n
)
2009 arc_n
= arc
->line_next
;
2010 arc
->line_next
= arc_p
;
2012 add_branch_counts (&src
->coverage
, arc
);
2014 line
->u
.branches
= arc_p
;
2016 else if (line
->u
.blocks
)
2018 /* The user expects the line count to be the number of times
2019 a line has been executed. Simply summing the block count
2020 will give an artificially high number. The Right Thing
2021 is to sum the entry counts to the graph of blocks on this
2022 line, then find the elementary cycles of the local graph
2023 and add the transition counts of those cycles. */
2024 block_t
*block
, *block_p
, *block_n
;
2025 gcov_type count
= 0;
2027 /* Reverse the block information. */
2028 for (block
= line
->u
.blocks
, block_p
= NULL
; block
;
2029 block_p
= block
, block
= block_n
)
2031 block_n
= block
->chain
;
2032 block
->chain
= block_p
;
2033 block
->u
.cycle
.ident
= ix
;
2035 line
->u
.blocks
= block_p
;
2037 /* Sum the entry arcs. */
2038 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
2042 for (arc
= block
->pred
; arc
; arc
= arc
->pred_next
)
2044 if (arc
->src
->u
.cycle
.ident
!= ix
)
2045 count
+= arc
->count
;
2047 add_branch_counts (&src
->coverage
, arc
);
2050 /* Initialize the cs_count. */
2051 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2052 arc
->cs_count
= arc
->count
;
2055 /* Find the loops. This uses the algorithm described in
2056 Tiernan 'An Efficient Search Algorithm to Find the
2057 Elementary Circuits of a Graph', CACM Dec 1970. We hold
2058 the P array by having each block point to the arc that
2059 connects to the previous block. The H array is implicitly
2060 held because of the arc ordering, and the block's
2061 previous arc pointer.
2063 Although the algorithm is O(N^3) for highly connected
2064 graphs, at worst we'll have O(N^2), as most blocks have
2065 only one or two exits. Most graphs will be small.
2067 For each loop we find, locate the arc with the smallest
2068 transition count, and add that to the cumulative
2069 count. Decrease flow over the cycle and remove the arc
2070 from consideration. */
2071 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
2073 block_t
*head
= block
;
2081 block_t
*dst
= arc
->dst
;
2082 if (/* Already used that arc. */
2084 /* Not to same graph, or before first vertex. */
2085 || dst
->u
.cycle
.ident
!= ix
2086 /* Already in path. */
2087 || dst
->u
.cycle
.arc
)
2089 arc
= arc
->succ_next
;
2095 /* Found a closing arc. */
2096 gcov_type cycle_count
= arc
->cs_count
;
2097 arc_t
*cycle_arc
= arc
;
2100 /* Locate the smallest arc count of the loop. */
2101 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
2102 dst
= probe_arc
->src
)
2103 if (cycle_count
> probe_arc
->cs_count
)
2105 cycle_count
= probe_arc
->cs_count
;
2106 cycle_arc
= probe_arc
;
2109 count
+= cycle_count
;
2110 cycle_arc
->cycle
= 1;
2112 /* Remove the flow from the cycle. */
2113 arc
->cs_count
-= cycle_count
;
2114 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
2115 dst
= probe_arc
->src
)
2116 probe_arc
->cs_count
-= cycle_count
;
2118 /* Unwind to the cyclic arc. */
2119 while (head
!= cycle_arc
->src
)
2121 arc
= head
->u
.cycle
.arc
;
2122 head
->u
.cycle
.arc
= NULL
;
2126 arc
= arc
->succ_next
;
2130 /* Add new block to chain. */
2131 dst
->u
.cycle
.arc
= arc
;
2135 /* We could not add another vertex to the path. Remove
2136 the last vertex from the list. */
2137 arc
= head
->u
.cycle
.arc
;
2140 /* It was not the first vertex. Move onto next arc. */
2141 head
->u
.cycle
.arc
= NULL
;
2143 arc
= arc
->succ_next
;
2144 goto current_vertex
;
2146 /* Mark this block as unusable. */
2147 block
->u
.cycle
.ident
= ~0U;
2150 line
->count
= count
;
2155 src
->coverage
.lines
++;
2157 src
->coverage
.lines_executed
++;
2162 /* Output information about ARC number IX. Returns nonzero if
2163 anything is output. */
2166 output_branch_count (FILE *gcov_file
, int ix
, const arc_t
*arc
)
2168 if (arc
->is_call_non_return
)
2170 if (arc
->src
->count
)
2172 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
2173 format_gcov (arc
->src
->count
- arc
->count
,
2174 arc
->src
->count
, -flag_counts
));
2177 fnotice (gcov_file
, "call %2d never executed\n", ix
);
2179 else if (!arc
->is_unconditional
)
2181 if (arc
->src
->count
)
2182 fnotice (gcov_file
, "branch %2d taken %s%s\n", ix
,
2183 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
2184 arc
->fall_through
? " (fallthrough)"
2185 : arc
->is_throw
? " (throw)" : "");
2187 fnotice (gcov_file
, "branch %2d never executed\n", ix
);
2189 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
2191 if (arc
->src
->count
)
2192 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
2193 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
2195 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
2204 read_line (FILE *file
)
2206 static char *string
;
2207 static size_t string_len
;
2214 string
= XNEWVEC (char, string_len
);
2217 while ((ptr
= fgets (string
+ pos
, string_len
- pos
, file
)))
2219 size_t len
= strlen (string
+ pos
);
2221 if (string
[pos
+ len
- 1] == '\n')
2223 string
[pos
+ len
- 1] = 0;
2227 string
= XRESIZEVEC (char, string
, string_len
* 2);
2231 return pos
? string
: NULL
;
2234 /* Read in the source file one line at a time, and output that line to
2235 the gcov file preceded by its execution count and other
2239 output_lines (FILE *gcov_file
, const source_t
*src
)
2242 unsigned line_num
; /* current line number. */
2243 const line_t
*line
; /* current line info ptr. */
2244 const char *retval
= ""; /* status of source file reading. */
2245 function_t
*fn
= NULL
;
2247 fprintf (gcov_file
, "%9s:%5d:Source:%s\n", "-", 0, src
->coverage
.name
);
2248 if (!multiple_files
)
2250 fprintf (gcov_file
, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name
);
2251 fprintf (gcov_file
, "%9s:%5d:Data:%s\n", "-", 0,
2252 no_data_file
? "-" : da_file_name
);
2253 fprintf (gcov_file
, "%9s:%5d:Runs:%u\n", "-", 0, object_runs
);
2255 fprintf (gcov_file
, "%9s:%5d:Programs:%u\n", "-", 0, program_count
);
2257 source_file
= fopen (src
->name
, "r");
2260 fnotice (stderr
, "Cannot open source file %s\n", src
->name
);
2263 else if (src
->file_time
== 0)
2264 fprintf (gcov_file
, "%9s:%5d:Source is newer than graph\n", "-", 0);
2267 fn
= src
->functions
;
2269 for (line_num
= 1, line
= &src
->lines
[line_num
];
2270 line_num
< src
->num_lines
; line_num
++, line
++)
2272 for (; fn
&& fn
->line
== line_num
; fn
= fn
->line_next
)
2274 arc_t
*arc
= fn
->blocks
[EXIT_BLOCK
].pred
;
2275 gcov_type return_count
= fn
->blocks
[EXIT_BLOCK
].count
;
2276 gcov_type called_count
= fn
->blocks
[ENTRY_BLOCK
].count
;
2278 for (; arc
; arc
= arc
->pred_next
)
2280 return_count
-= arc
->count
;
2282 fprintf (gcov_file
, "function %s", fn
->name
);
2283 fprintf (gcov_file
, " called %s",
2284 format_gcov (called_count
, 0, -1));
2285 fprintf (gcov_file
, " returned %s",
2286 format_gcov (return_count
, called_count
, 0));
2287 fprintf (gcov_file
, " blocks executed %s",
2288 format_gcov (fn
->blocks_executed
, fn
->num_blocks
- 2, 0));
2289 fprintf (gcov_file
, "\n");
2293 retval
= read_line (source_file
);
2295 /* For lines which don't exist in the .bb file, print '-' before
2296 the source line. For lines which exist but were never
2297 executed, print '#####' or '=====' before the source line.
2298 Otherwise, print the execution count before the source line.
2299 There are 16 spaces of indentation added before the source
2300 line so that tabs won't be messed up. */
2301 fprintf (gcov_file
, "%9s:%5u:%s\n",
2302 !line
->exists
? "-" : line
->count
2303 ? format_gcov (line
->count
, 0, -1)
2304 : line
->unexceptional
? "#####" : "=====", line_num
,
2305 retval
? retval
: "/*EOF*/");
2307 if (flag_all_blocks
)
2313 for (ix
= jx
= 0, block
= line
->u
.blocks
; block
;
2314 block
= block
->chain
)
2316 if (!block
->is_call_return
)
2317 fprintf (gcov_file
, "%9s:%5u-block %2d\n",
2318 !line
->exists
? "-" : block
->count
2319 ? format_gcov (block
->count
, 0, -1)
2320 : block
->exceptional
? "%%%%%" : "$$$$$",
2323 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2324 jx
+= output_branch_count (gcov_file
, jx
, arc
);
2327 else if (flag_branches
)
2332 for (ix
= 0, arc
= line
->u
.branches
; arc
; arc
= arc
->line_next
)
2333 ix
+= output_branch_count (gcov_file
, ix
, arc
);
2337 /* Handle all remaining source lines. There may be lines after the
2338 last line of code. */
2341 for (; (retval
= read_line (source_file
)); line_num
++)
2342 fprintf (gcov_file
, "%9s:%5u:%s\n", "-", line_num
, retval
);
2346 fclose (source_file
);