1 /* Gcov.c: prepend line execution counts and branch probabilities to a
3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
4 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
5 Free Software Foundation, Inc.
6 Contributed by James E. Wilson of Cygnus Support.
7 Mangled by Bob Manson of Cygnus Support.
8 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
10 Gcov is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3, or (at your option)
15 Gcov is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with Gcov; see the file COPYING3. If not see
22 <http://www.gnu.org/licenses/>. */
24 /* ??? Print a list of the ten blocks with the highest execution counts,
25 and list the line numbers corresponding to those blocks. Also, perhaps
26 list the line numbers with the highest execution counts, only printing
27 the first if there are several which are all listed in the same block. */
29 /* ??? Should have an option to print the number of basic blocks, and the
30 percent of them that are covered. */
32 /* Need an option to show individual block counts, and show
33 probabilities of fall through arcs. */
37 #include "coretypes.h"
40 #include "diagnostic.h"
49 /* The gcno file is generated by -ftest-coverage option. The gcda file is
50 generated by a program compiled with -fprofile-arcs. Their formats
51 are documented in gcov-io.h. */
53 /* The functions in this file for creating and solution program flow graphs
54 are very similar to functions in the gcc source file profile.c. In
55 some places we make use of the knowledge of how profile.c works to
56 select particular algorithms here. */
58 /* The code validates that the profile information read in corresponds
59 to the code currently being compiled. Rather than checking for
60 identical files, the code below computes a checksum on the CFG
61 (based on the order of basic blocks and the arcs in the CFG). If
62 the CFG checksum in the gcda file match the CFG checksum for the
63 code currently being compiled, the profile data will be used. */
65 /* This is the size of the buffer used to read in source file lines. */
67 #define STRING_SIZE 200
73 /* Describes an arc between two basic blocks. */
75 typedef struct arc_info
77 /* source and destination blocks. */
78 struct block_info
*src
;
79 struct block_info
*dst
;
81 /* transition counts. */
83 /* used in cycle search, so that we do not clobber original counts. */
86 unsigned int count_valid
: 1;
87 unsigned int on_tree
: 1;
88 unsigned int fake
: 1;
89 unsigned int fall_through
: 1;
91 /* Arc to a catch handler. */
92 unsigned int is_throw
: 1;
94 /* Arc is for a function that abnormally returns. */
95 unsigned int is_call_non_return
: 1;
97 /* Arc is for catch/setjmp. */
98 unsigned int is_nonlocal_return
: 1;
100 /* Is an unconditional branch. */
101 unsigned int is_unconditional
: 1;
103 /* Loop making arc. */
104 unsigned int cycle
: 1;
106 /* Next branch on line. */
107 struct arc_info
*line_next
;
109 /* Links to next arc on src and dst lists. */
110 struct arc_info
*succ_next
;
111 struct arc_info
*pred_next
;
114 /* Describes a basic block. Contains lists of arcs to successor and
115 predecessor blocks. */
117 typedef struct block_info
119 /* Chain of exit and entry arcs. */
123 /* Number of unprocessed exit and entry arcs. */
127 /* Block execution count. */
130 unsigned count_valid
: 1;
131 unsigned valid_chain
: 1;
132 unsigned invalid_chain
: 1;
133 unsigned exceptional
: 1;
135 /* Block is a call instrumenting site. */
136 unsigned is_call_site
: 1; /* Does the call. */
137 unsigned is_call_return
: 1; /* Is the return. */
139 /* Block is a landing pad for longjmp or throw. */
140 unsigned is_nonlocal_return
: 1;
146 /* Array of line numbers and source files. source files are
147 introduced by a linenumber of zero, the next 'line number' is
148 the number of the source file. Always starts with a source
152 } line
; /* Valid until blocks are linked onto lines */
155 /* Single line graph cycle workspace. Used for all-blocks
159 } cycle
; /* Used in all-blocks mode, after blocks are linked onto
163 /* Temporary chain for solving graph, and for chaining blocks on one
165 struct block_info
*chain
;
169 /* Describes a single function. Contains an array of basic blocks. */
171 typedef struct function_info
173 /* Name of function. */
176 unsigned lineno_checksum
;
177 unsigned cfg_checksum
;
179 /* The graph contains at least one fake incoming edge. */
180 unsigned has_catch
: 1;
182 /* Array of basic blocks. */
185 unsigned blocks_executed
;
187 /* Raw arc coverage counts. */
191 /* First line number & file. */
195 /* Next function in same source file. */
196 struct function_info
*line_next
;
199 struct function_info
*next
;
202 /* Describes coverage of a file or function. */
204 typedef struct coverage_info
210 int branches_executed
;
219 /* Describes a single line of source. Contains a chain of basic blocks
222 typedef struct line_info
224 gcov_type count
; /* execution count */
227 arc_t
*branches
; /* branches from blocks that end on this
228 line. Used for branch-counts when not
230 block_t
*blocks
; /* blocks which start on this line. Used
231 in all-blocks mode. */
234 unsigned unexceptional
: 1;
237 /* Describes a file mentioned in the block graph. Contains an array
240 typedef struct source_info
242 /* Canonical name of source file. */
246 /* Array of line information. */
252 /* Functions in this source file. These are in ascending line
254 function_t
*functions
;
257 typedef struct name_map
259 char *name
; /* Source file name */
260 unsigned src
; /* Source file */
263 /* Holds a list of function basic block graphs. */
265 static function_t
*functions
;
266 static function_t
**fn_end
= &functions
;
268 static source_t
*sources
; /* Array of source files */
269 static unsigned n_sources
; /* Number of sources */
270 static unsigned a_sources
; /* Allocated sources */
272 static name_map_t
*names
; /* Mapping of file names to sources */
273 static unsigned n_names
; /* Number of names */
274 static unsigned a_names
; /* Allocated names */
276 /* This holds data summary information. */
278 static unsigned object_runs
;
279 static unsigned program_count
;
281 static unsigned total_lines
;
282 static unsigned total_executed
;
284 /* Modification time of graph file. */
286 static time_t bbg_file_time
;
288 /* Name and file pointer of the input file for the basic block graph. */
290 static char *bbg_file_name
;
292 /* Stamp of the bbg file */
293 static unsigned bbg_stamp
;
295 /* Name and file pointer of the input file for the arc count data. */
297 static char *da_file_name
;
299 /* Data file is missing. */
301 static int no_data_file
;
303 /* If there is several input files, compute and display results after
304 reading all data files. This way if two or more gcda file refer to
305 the same source file (eg inline subprograms in a .h file), the
308 static int multiple_files
= 0;
310 /* Output branch probabilities. */
312 static int flag_branches
= 0;
314 /* Show unconditional branches too. */
315 static int flag_unconditional
= 0;
317 /* Output a gcov file if this is true. This is on by default, and can
318 be turned off by the -n option. */
320 static int flag_gcov_file
= 1;
322 /* Output progress indication if this is true. This is off by default
323 and can be turned on by the -d option. */
325 static int flag_display_progress
= 0;
327 /* For included files, make the gcov output file name include the name
328 of the input source file. For example, if x.h is included in a.c,
329 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
331 static int flag_long_names
= 0;
333 /* Output count information for every basic block, not merely those
334 that contain line number information. */
336 static int flag_all_blocks
= 0;
338 /* Output summary info for each function. */
340 static int flag_function_summary
= 0;
342 /* Object directory file prefix. This is the directory/file where the
343 graph and data files are looked for, if nonzero. */
345 static char *object_directory
= 0;
347 /* Source directory prefix. This is removed from source pathnames
348 that match, when generating the output file name. */
350 static char *source_prefix
= 0;
351 static size_t source_length
= 0;
353 /* Only show data for sources with relative pathnames. Absolute ones
354 usually indicate a system header file, which although it may
355 contain inline functions, is usually uninteresting. */
356 static int flag_relative_only
= 0;
358 /* Preserve all pathname components. Needed when object files and
359 source files are in subdirectories. '/' is mangled as '#', '.' is
360 elided and '..' mangled to '^'. */
362 static int flag_preserve_paths
= 0;
364 /* Output the number of times a branch was taken as opposed to the percentage
365 of times it was taken. */
367 static int flag_counts
= 0;
369 /* Forward declarations. */
370 static int process_args (int, char **);
371 static void print_usage (int) ATTRIBUTE_NORETURN
;
372 static void print_version (void) ATTRIBUTE_NORETURN
;
373 static void process_file (const char *);
374 static void generate_results (const char *);
375 static void create_file_names (const char *);
376 static int name_search (const void *, const void *);
377 static int name_sort (const void *, const void *);
378 static char *canonicalize_name (const char *);
379 static unsigned find_source (const char *);
380 static function_t
*read_graph_file (void);
381 static int read_count_file (function_t
*);
382 static void solve_flow_graph (function_t
*);
383 static void find_exception_blocks (function_t
*);
384 static void add_branch_counts (coverage_t
*, const arc_t
*);
385 static void add_line_counts (coverage_t
*, function_t
*);
386 static void executed_summary (unsigned, unsigned);
387 static void function_summary (const coverage_t
*, const char *);
388 static const char *format_gcov (gcov_type
, gcov_type
, int);
389 static void accumulate_line_counts (source_t
*);
390 static int output_branch_count (FILE *, int, const arc_t
*);
391 static void output_lines (FILE *, const source_t
*);
392 static char *make_gcov_file_name (const char *, const char *);
393 static char *mangle_name (const char *, char *);
394 static void release_structures (void);
395 static void release_function (function_t
*);
396 extern int main (int, char **);
399 main (int argc
, char **argv
)
405 p
= argv
[0] + strlen (argv
[0]);
406 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
410 xmalloc_set_program_name (progname
);
412 /* Unlock the stdio streams. */
413 unlock_std_streams ();
417 diagnostic_initialize (global_dc
, 0);
419 /* Handle response files. */
420 expandargv (&argc
, &argv
);
423 names
= XNEWVEC (name_map_t
, a_names
);
425 sources
= XNEWVEC (source_t
, a_sources
);
427 argno
= process_args (argc
, argv
);
431 if (argc
- argno
> 1)
436 for (; argno
!= argc
; argno
++)
438 if (flag_display_progress
)
439 printf("Processing file %d out of %d\n",
440 argno
- first_arg
+ 1, argc
- first_arg
);
441 process_file (argv
[argno
]);
444 generate_results (multiple_files
? NULL
: argv
[argc
- 1]);
446 release_structures ();
451 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
452 otherwise the output of --help. */
455 print_usage (int error_p
)
457 FILE *file
= error_p
? stderr
: stdout
;
458 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
460 fnotice (file
, "Usage: gcov [OPTION]... SOURCE|OBJ...\n\n");
461 fnotice (file
, "Print code coverage information.\n\n");
462 fnotice (file
, " -h, --help Print this help, then exit\n");
463 fnotice (file
, " -v, --version Print version number, then exit\n");
464 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
465 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
466 fnotice (file
, " -c, --branch-counts Given counts of branches taken\n\
467 rather than percentages\n");
468 fnotice (file
, " -n, --no-output Do not create an output file\n");
469 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
471 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
472 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
473 fnotice (file
, " -s, --source-prefix DIR Source prefix to elide\n");
474 fnotice (file
, " -r, --relative-only Only show data for relative sources\n");
475 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
476 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
477 fnotice (file
, " -d, --display-progress Display progress information\n");
478 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
483 /* Print version information and exit. */
488 fnotice (stdout
, "gcov %s%s\n", pkgversion_string
, version_string
);
489 fprintf (stdout
, "Copyright %s 2011 Free Software Foundation, Inc.\n",
492 _("This is free software; see the source for copying conditions.\n"
493 "There is NO warranty; not even for MERCHANTABILITY or \n"
494 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
495 exit (SUCCESS_EXIT_CODE
);
498 static const struct option options
[] =
500 { "help", no_argument
, NULL
, 'h' },
501 { "version", no_argument
, NULL
, 'v' },
502 { "all-blocks", no_argument
, NULL
, 'a' },
503 { "branch-probabilities", no_argument
, NULL
, 'b' },
504 { "branch-counts", no_argument
, NULL
, 'c' },
505 { "no-output", no_argument
, NULL
, 'n' },
506 { "long-file-names", no_argument
, NULL
, 'l' },
507 { "function-summaries", no_argument
, NULL
, 'f' },
508 { "preserve-paths", no_argument
, NULL
, 'p' },
509 { "relative-only", no_argument
, NULL
, 'r' },
510 { "object-directory", required_argument
, NULL
, 'o' },
511 { "object-file", required_argument
, NULL
, 'o' },
512 { "source-prefix", required_argument
, NULL
, 's' },
513 { "unconditional-branches", no_argument
, NULL
, 'u' },
514 { "display-progress", no_argument
, NULL
, 'd' },
518 /* Process args, return index to first non-arg. */
521 process_args (int argc
, char **argv
)
525 while ((opt
= getopt_long (argc
, argv
, "abcdfhlno:s:pruv", options
, NULL
)) != -1)
539 flag_function_summary
= 1;
543 /* print_usage will exit. */
551 object_directory
= optarg
;
554 source_prefix
= optarg
;
555 source_length
= strlen (source_prefix
);
558 flag_relative_only
= 1;
561 flag_preserve_paths
= 1;
564 flag_unconditional
= 1;
567 flag_display_progress
= 1;
571 /* print_version will exit. */
574 /* print_usage will exit. */
581 /* Process a single input file. */
584 process_file (const char *file_name
)
588 create_file_names (file_name
);
589 fns
= read_graph_file ();
593 read_count_file (fns
);
596 function_t
*fn
= fns
;
602 unsigned src
= fn
->src
;
603 unsigned line
= fn
->line
;
605 function_t
*probe
, **prev
;
607 /* Now insert it into the source file's list of
608 functions. Normally functions will be encountered in
609 ascending order, so a simple scan is quick. Note we're
610 building this list in reverse order. */
611 for (prev
= &sources
[src
].functions
;
612 (probe
= *prev
); prev
= &probe
->line_next
)
613 if (probe
->line
<= line
)
615 fn
->line_next
= probe
;
618 /* Mark last line in files touched by function. */
619 for (block_no
= 0; block_no
!= fn
->num_blocks
; block_no
++)
621 unsigned *enc
= fn
->blocks
[block_no
].u
.line
.encoding
;
622 unsigned num
= fn
->blocks
[block_no
].u
.line
.num
;
629 if (line
>= sources
[src
].num_lines
)
630 sources
[src
].num_lines
= line
+ 1;
637 else if (*enc
> line
)
640 if (line
>= sources
[src
].num_lines
)
641 sources
[src
].num_lines
= line
+ 1;
643 solve_flow_graph (fn
);
645 find_exception_blocks (fn
);
650 /* The function was not in the executable -- some other
651 instance must have been selected. */
652 release_function (fn
);
657 generate_results (const char *file_name
)
663 for (ix
= n_sources
, src
= sources
; ix
--; src
++)
665 src
->lines
= XCNEWVEC (line_t
, src
->num_lines
);
667 for (fn
= functions
; fn
; fn
= fn
->next
)
671 memset (&coverage
, 0, sizeof (coverage
));
672 coverage
.name
= fn
->name
;
673 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
674 if (flag_function_summary
)
676 function_summary (&coverage
, "Function");
677 fnotice (stdout
, "\n");
683 name_map_t
*name_map
= (name_map_t
*)bsearch
684 (file_name
, names
, n_names
, sizeof (*names
), name_search
);
686 file_name
= sources
[name_map
->src
].coverage
.name
;
688 file_name
= canonicalize_name (file_name
);
691 for (ix
= n_sources
, src
= sources
; ix
--; src
++)
693 if (flag_relative_only
)
695 /* Ignore this source, if it is an absolute path (after
696 source prefix removal). */
697 char first
= src
->coverage
.name
[0];
699 #if HAVE_DOS_BASED_FILE_SYSTEM
700 if (first
&& src
->coverage
.name
[1] == ':')
701 first
= src
->coverage
.name
[2];
703 if (IS_DIR_SEPARATOR (first
))
707 accumulate_line_counts (src
);
708 function_summary (&src
->coverage
, "File");
709 total_lines
+= src
->coverage
.lines
;
710 total_executed
+= src
->coverage
.lines_executed
;
711 if (flag_gcov_file
&& src
->coverage
.lines
)
714 = make_gcov_file_name (file_name
, src
->coverage
.name
);
715 FILE *gcov_file
= fopen (gcov_file_name
, "w");
719 fnotice (stdout
, "Creating '%s'\n", gcov_file_name
);
720 output_lines (gcov_file
, src
);
721 if (ferror (gcov_file
))
722 fnotice (stderr
, "Error writing output file '%s'\n",
727 fnotice (stderr
, "Could not open output file '%s'\n",
729 free (gcov_file_name
);
731 fnotice (stdout
, "\n");
735 executed_summary (total_lines
, total_executed
);
738 /* Release a function structure */
741 release_function (function_t
*fn
)
746 for (ix
= fn
->num_blocks
, block
= fn
->blocks
; ix
--; block
++)
750 for (arc
= block
->succ
; arc
; arc
= arc_n
)
752 arc_n
= arc
->succ_next
;
760 /* Release all memory used. */
763 release_structures (void)
768 for (ix
= n_sources
; ix
--;)
769 free (sources
[ix
].lines
);
772 for (ix
= n_names
; ix
--;)
773 free (names
[ix
].name
);
776 while ((fn
= functions
))
778 functions
= fn
->next
;
779 release_function (fn
);
783 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
784 is not specified, these are named from FILE_NAME sans extension. If
785 OBJECT_DIRECTORY is specified and is a directory, the files are in that
786 directory, but named from the basename of the FILE_NAME, sans extension.
787 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
788 and the data files are named from that. */
791 create_file_names (const char *file_name
)
795 int length
= strlen (file_name
);
798 /* Free previous file names. */
799 free (bbg_file_name
);
801 da_file_name
= bbg_file_name
= NULL
;
805 if (object_directory
&& object_directory
[0])
809 length
+= strlen (object_directory
) + 2;
810 name
= XNEWVEC (char, length
);
813 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
814 strcat (name
, object_directory
);
815 if (base
&& (! IS_DIR_SEPARATOR (name
[strlen (name
) - 1])))
820 name
= XNEWVEC (char, length
+ 1);
821 strcpy (name
, file_name
);
827 /* Append source file name. */
828 const char *cptr
= lbasename (file_name
);
829 strcat (name
, cptr
? cptr
: file_name
);
832 /* Remove the extension. */
833 cptr
= strrchr (name
, '.');
837 length
= strlen (name
);
839 bbg_file_name
= XNEWVEC (char, length
+ strlen (GCOV_NOTE_SUFFIX
) + 1);
840 strcpy (bbg_file_name
, name
);
841 strcpy (bbg_file_name
+ length
, GCOV_NOTE_SUFFIX
);
843 da_file_name
= XNEWVEC (char, length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
844 strcpy (da_file_name
, name
);
845 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
851 /* A is a string and B is a pointer to name_map_t. Compare for file
852 name orderability. */
855 name_search (const void *a_
, const void *b_
)
857 const char *a
= (const char *)a_
;
858 const name_map_t
*b
= (const name_map_t
*)b_
;
860 #if HAVE_DOS_BASED_FILE_SYSTEM
861 return strcasecmp (a
, b
->name
);
863 return strcmp (a
, b
->name
);
867 /* A and B are a pointer to name_map_t. Compare for file name
871 name_sort (const void *a_
, const void *b_
)
873 const name_map_t
*a
= (const name_map_t
*)a_
;
874 return name_search (a
->name
, b_
);
877 /* Find or create a source file structure for FILE_NAME. Copies
878 FILE_NAME on creation */
881 find_source (const char *file_name
)
883 name_map_t
*name_map
;
889 file_name
= "<unknown>";
890 name_map
= (name_map_t
*)bsearch
891 (file_name
, names
, n_names
, sizeof (*names
), name_search
);
898 if (n_names
+ 2 > a_names
)
900 /* Extend the name map array -- we'll be inserting one or two
903 name_map
= XNEWVEC (name_map_t
, a_names
);
904 memcpy (name_map
, names
, n_names
* sizeof (*names
));
909 /* Not found, try the canonical name. */
910 canon
= canonicalize_name (file_name
);
911 name_map
= (name_map_t
*)bsearch
912 (canon
, names
, n_names
, sizeof (*names
), name_search
);
915 /* Not found with canonical name, create a new source. */
918 if (n_sources
== a_sources
)
921 src
= XNEWVEC (source_t
, a_sources
);
922 memcpy (src
, sources
, n_sources
* sizeof (*sources
));
929 name_map
= &names
[n_names
++];
930 name_map
->name
= canon
;
933 src
= &sources
[n_sources
++];
934 memset (src
, 0, sizeof (*src
));
936 src
->coverage
.name
= src
->name
;
938 #if HAVE_DOS_BASED_FILE_SYSTEM
939 /* You lose if separators don't match exactly in the
941 && !strncasecmp (source_prefix
, src
->coverage
.name
, source_length
)
943 && !strncmp (source_prefix
, src
->coverage
.name
, source_length
)
945 && IS_DIR_SEPARATOR (src
->coverage
.name
[source_length
]))
946 src
->coverage
.name
+= source_length
+ 1;
947 if (!stat (src
->name
, &status
))
948 src
->file_time
= status
.st_mtime
;
953 if (name_search (file_name
, name_map
))
955 /* Append the non-canonical name. */
956 name_map
= &names
[n_names
++];
957 name_map
->name
= xstrdup (file_name
);
961 /* Resort the name map. */
962 qsort (names
, n_names
, sizeof (*names
), name_sort
);
965 if (sources
[idx
].file_time
> bbg_file_time
)
967 static int info_emitted
;
969 fnotice (stderr
, "%s:source file is newer than graph file '%s'\n",
970 file_name
, bbg_file_name
);
974 "(the message is only displayed one per source file)\n");
977 sources
[idx
].file_time
= 0;
983 /* Read the graph file. Return list of functions read -- in reverse order. */
986 read_graph_file (void)
989 unsigned current_tag
= 0;
990 function_t
*fn
= NULL
;
991 function_t
*fns
= NULL
;
992 function_t
**fns_end
= &fns
;
993 unsigned src_idx
= 0;
997 if (!gcov_open (bbg_file_name
, 1))
999 fnotice (stderr
, "%s:cannot open graph file\n", bbg_file_name
);
1002 bbg_file_time
= gcov_time ();
1003 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC
))
1005 fnotice (stderr
, "%s:not a gcov graph file\n", bbg_file_name
);
1010 version
= gcov_read_unsigned ();
1011 if (version
!= GCOV_VERSION
)
1015 GCOV_UNSIGNED2STRING (v
, version
);
1016 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1018 fnotice (stderr
, "%s:version '%.4s', prefer '%.4s'\n",
1019 bbg_file_name
, v
, e
);
1021 bbg_stamp
= gcov_read_unsigned ();
1023 while ((tag
= gcov_read_unsigned ()))
1025 unsigned length
= gcov_read_unsigned ();
1026 gcov_position_t base
= gcov_position ();
1028 if (tag
== GCOV_TAG_FUNCTION
)
1030 char *function_name
;
1031 unsigned ident
, lineno
;
1032 unsigned lineno_checksum
, cfg_checksum
;
1034 ident
= gcov_read_unsigned ();
1035 lineno_checksum
= gcov_read_unsigned ();
1036 cfg_checksum
= gcov_read_unsigned ();
1037 function_name
= xstrdup (gcov_read_string ());
1038 src_idx
= find_source (gcov_read_string ());
1039 lineno
= gcov_read_unsigned ();
1041 fn
= XCNEW (function_t
);
1042 fn
->name
= function_name
;
1044 fn
->lineno_checksum
= lineno_checksum
;
1045 fn
->cfg_checksum
= cfg_checksum
;
1049 fn
->line_next
= NULL
;
1052 fns_end
= &fn
->next
;
1055 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
1058 fnotice (stderr
, "%s:already seen blocks for '%s'\n",
1059 bbg_file_name
, fn
->name
);
1062 unsigned ix
, num_blocks
= GCOV_TAG_BLOCKS_NUM (length
);
1063 fn
->num_blocks
= num_blocks
;
1065 fn
->blocks
= XCNEWVEC (block_t
, fn
->num_blocks
);
1066 for (ix
= 0; ix
!= num_blocks
; ix
++)
1067 fn
->blocks
[ix
].flags
= gcov_read_unsigned ();
1070 else if (fn
&& tag
== GCOV_TAG_ARCS
)
1072 unsigned src
= gcov_read_unsigned ();
1073 unsigned num_dests
= GCOV_TAG_ARCS_NUM (length
);
1074 block_t
*src_blk
= &fn
->blocks
[src
];
1075 unsigned mark_catches
= 0;
1076 struct arc_info
*arc
;
1078 if (src
>= fn
->num_blocks
|| fn
->blocks
[src
].succ
)
1083 unsigned dest
= gcov_read_unsigned ();
1084 unsigned flags
= gcov_read_unsigned ();
1086 if (dest
>= fn
->num_blocks
)
1088 arc
= XCNEW (arc_t
);
1090 arc
->dst
= &fn
->blocks
[dest
];
1094 arc
->count_valid
= 0;
1095 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
1096 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
1097 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
1099 arc
->succ_next
= src_blk
->succ
;
1100 src_blk
->succ
= arc
;
1101 src_blk
->num_succ
++;
1103 arc
->pred_next
= fn
->blocks
[dest
].pred
;
1104 fn
->blocks
[dest
].pred
= arc
;
1105 fn
->blocks
[dest
].num_pred
++;
1111 /* Exceptional exit from this function, the
1112 source block must be a call. */
1113 fn
->blocks
[src
].is_call_site
= 1;
1114 arc
->is_call_non_return
= 1;
1119 /* Non-local return from a callee of this
1120 function. The destination block is a setjmp. */
1121 arc
->is_nonlocal_return
= 1;
1122 fn
->blocks
[dest
].is_nonlocal_return
= 1;
1132 /* We have a fake exit from this block. The other
1133 non-fall through exits must be to catch handlers.
1134 Mark them as catch arcs. */
1136 for (arc
= src_blk
->succ
; arc
; arc
= arc
->succ_next
)
1137 if (!arc
->fake
&& !arc
->fall_through
)
1144 else if (fn
&& tag
== GCOV_TAG_LINES
)
1146 unsigned blockno
= gcov_read_unsigned ();
1147 unsigned *line_nos
= XCNEWVEC (unsigned, length
- 1);
1149 if (blockno
>= fn
->num_blocks
|| fn
->blocks
[blockno
].u
.line
.encoding
)
1154 unsigned lineno
= gcov_read_unsigned ();
1161 line_nos
[ix
++] = src_idx
;
1163 line_nos
[ix
++] = lineno
;
1167 const char *file_name
= gcov_read_string ();
1171 src_idx
= find_source (file_name
);
1173 line_nos
[ix
++] = src_idx
;
1177 fn
->blocks
[blockno
].u
.line
.encoding
= line_nos
;
1178 fn
->blocks
[blockno
].u
.line
.num
= ix
;
1180 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
1185 gcov_sync (base
, length
);
1186 if (gcov_is_error ())
1189 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
1196 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
1201 /* Reads profiles from the count file and attach to each
1202 function. Return nonzero if fatal error. */
1205 read_count_file (function_t
*fns
)
1210 function_t
*fn
= NULL
;
1213 if (!gcov_open (da_file_name
, 1))
1215 fnotice (stderr
, "%s:cannot open data file, assuming not executed\n",
1220 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
1222 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
1227 version
= gcov_read_unsigned ();
1228 if (version
!= GCOV_VERSION
)
1232 GCOV_UNSIGNED2STRING (v
, version
);
1233 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1235 fnotice (stderr
, "%s:version '%.4s', prefer version '%.4s'\n",
1236 da_file_name
, v
, e
);
1238 tag
= gcov_read_unsigned ();
1239 if (tag
!= bbg_stamp
)
1241 fnotice (stderr
, "%s:stamp mismatch with graph file\n", da_file_name
);
1245 while ((tag
= gcov_read_unsigned ()))
1247 unsigned length
= gcov_read_unsigned ();
1248 unsigned long base
= gcov_position ();
1250 if (tag
== GCOV_TAG_PROGRAM_SUMMARY
)
1252 struct gcov_summary summary
;
1253 gcov_read_summary (&summary
);
1254 object_runs
+= summary
.ctrs
[GCOV_COUNTER_ARCS
].runs
;
1257 else if (tag
== GCOV_TAG_FUNCTION
&& !length
)
1259 else if (tag
== GCOV_TAG_FUNCTION
&& length
== GCOV_TAG_FUNCTION_LENGTH
)
1262 struct function_info
*fn_n
;
1264 /* Try to find the function in the list. To speed up the
1265 search, first start from the last function found. */
1266 ident
= gcov_read_unsigned ();
1268 for (fn
= fn
? fn
->next
: NULL
; ; fn
= fn
->next
)
1272 else if ((fn
= fn_n
))
1276 fnotice (stderr
, "%s:unknown function '%u'\n",
1277 da_file_name
, ident
);
1280 if (fn
->ident
== ident
)
1286 else if (gcov_read_unsigned () != fn
->lineno_checksum
1287 || gcov_read_unsigned () != fn
->cfg_checksum
)
1290 fnotice (stderr
, "%s:profile mismatch for '%s'\n",
1291 da_file_name
, fn
->name
);
1295 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
1297 if (length
!= GCOV_TAG_COUNTER_LENGTH (fn
->num_counts
))
1301 fn
->counts
= XCNEWVEC (gcov_type
, fn
->num_counts
);
1303 for (ix
= 0; ix
!= fn
->num_counts
; ix
++)
1304 fn
->counts
[ix
] += gcov_read_counter ();
1306 gcov_sync (base
, length
);
1307 if ((error
= gcov_is_error ()))
1309 fnotice (stderr
, error
< 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1319 /* Solve the flow graph. Propagate counts from the instrumented arcs
1320 to the blocks and the uninstrumented arcs. */
1323 solve_flow_graph (function_t
*fn
)
1327 gcov_type
*count_ptr
= fn
->counts
;
1329 block_t
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
1330 block_t
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
1332 /* The arcs were built in reverse order. Fix that now. */
1333 for (ix
= fn
->num_blocks
; ix
--;)
1335 arc_t
*arc_p
, *arc_n
;
1337 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
1338 arc_p
= arc
, arc
= arc_n
)
1340 arc_n
= arc
->succ_next
;
1341 arc
->succ_next
= arc_p
;
1343 fn
->blocks
[ix
].succ
= arc_p
;
1345 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
1346 arc_p
= arc
, arc
= arc_n
)
1348 arc_n
= arc
->pred_next
;
1349 arc
->pred_next
= arc_p
;
1351 fn
->blocks
[ix
].pred
= arc_p
;
1354 if (fn
->num_blocks
< 2)
1355 fnotice (stderr
, "%s:'%s' lacks entry and/or exit blocks\n",
1356 bbg_file_name
, fn
->name
);
1359 if (fn
->blocks
[0].num_pred
)
1360 fnotice (stderr
, "%s:'%s' has arcs to entry block\n",
1361 bbg_file_name
, fn
->name
);
1363 /* We can't deduce the entry block counts from the lack of
1365 fn
->blocks
[0].num_pred
= ~(unsigned)0;
1367 if (fn
->blocks
[fn
->num_blocks
- 1].num_succ
)
1368 fnotice (stderr
, "%s:'%s' has arcs from exit block\n",
1369 bbg_file_name
, fn
->name
);
1371 /* Likewise, we can't deduce exit block counts from the lack
1372 of its successors. */
1373 fn
->blocks
[fn
->num_blocks
- 1].num_succ
= ~(unsigned)0;
1376 /* Propagate the measured counts, this must be done in the same
1377 order as the code in profile.c */
1378 for (ix
= 0, blk
= fn
->blocks
; ix
!= fn
->num_blocks
; ix
++, blk
++)
1380 block_t
const *prev_dst
= NULL
;
1381 int out_of_order
= 0;
1382 int non_fake_succ
= 0;
1384 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1392 arc
->count
= *count_ptr
++;
1393 arc
->count_valid
= 1;
1395 arc
->dst
->num_pred
--;
1397 if (prev_dst
&& prev_dst
> arc
->dst
)
1399 prev_dst
= arc
->dst
;
1401 if (non_fake_succ
== 1)
1403 /* If there is only one non-fake exit, it is an
1404 unconditional branch. */
1405 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1408 arc
->is_unconditional
= 1;
1409 /* If this block is instrumenting a call, it might be
1410 an artificial block. It is not artificial if it has
1411 a non-fallthrough exit, or the destination of this
1412 arc has more than one entry. Mark the destination
1413 block as a return site, if none of those conditions
1415 if (blk
->is_call_site
&& arc
->fall_through
1416 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
1417 arc
->dst
->is_call_return
= 1;
1421 /* Sort the successor arcs into ascending dst order. profile.c
1422 normally produces arcs in the right order, but sometimes with
1423 one or two out of order. We're not using a particularly
1427 arc_t
*start
= blk
->succ
;
1428 unsigned changes
= 1;
1432 arc_t
*arc
, *arc_p
, *arc_n
;
1435 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
1437 if (arc
->dst
> arc_n
->dst
)
1441 arc_p
->succ_next
= arc_n
;
1444 arc
->succ_next
= arc_n
->succ_next
;
1445 arc_n
->succ_next
= arc
;
1458 /* Place it on the invalid chain, it will be ignored if that's
1460 blk
->invalid_chain
= 1;
1461 blk
->chain
= invalid_blocks
;
1462 invalid_blocks
= blk
;
1465 while (invalid_blocks
|| valid_blocks
)
1467 while ((blk
= invalid_blocks
))
1469 gcov_type total
= 0;
1472 invalid_blocks
= blk
->chain
;
1473 blk
->invalid_chain
= 0;
1475 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1476 total
+= arc
->count
;
1477 else if (!blk
->num_pred
)
1478 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1479 total
+= arc
->count
;
1484 blk
->count_valid
= 1;
1485 blk
->chain
= valid_blocks
;
1486 blk
->valid_chain
= 1;
1489 while ((blk
= valid_blocks
))
1492 arc_t
*arc
, *inv_arc
;
1494 valid_blocks
= blk
->chain
;
1495 blk
->valid_chain
= 0;
1496 if (blk
->num_succ
== 1)
1502 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1504 total
-= arc
->count
;
1505 if (!arc
->count_valid
)
1509 inv_arc
->count_valid
= 1;
1510 inv_arc
->count
= total
;
1513 if (dst
->count_valid
)
1515 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
1517 dst
->chain
= valid_blocks
;
1518 dst
->valid_chain
= 1;
1524 if (!dst
->num_pred
&& !dst
->invalid_chain
)
1526 dst
->chain
= invalid_blocks
;
1527 dst
->invalid_chain
= 1;
1528 invalid_blocks
= dst
;
1532 if (blk
->num_pred
== 1)
1538 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1540 total
-= arc
->count
;
1541 if (!arc
->count_valid
)
1545 inv_arc
->count_valid
= 1;
1546 inv_arc
->count
= total
;
1549 if (src
->count_valid
)
1551 if (src
->num_succ
== 1 && !src
->valid_chain
)
1553 src
->chain
= valid_blocks
;
1554 src
->valid_chain
= 1;
1560 if (!src
->num_succ
&& !src
->invalid_chain
)
1562 src
->chain
= invalid_blocks
;
1563 src
->invalid_chain
= 1;
1564 invalid_blocks
= src
;
1571 /* If the graph has been correctly solved, every block will have a
1573 for (ix
= 0; ix
< fn
->num_blocks
; ix
++)
1574 if (!fn
->blocks
[ix
].count_valid
)
1576 fnotice (stderr
, "%s:graph is unsolvable for '%s'\n",
1577 bbg_file_name
, fn
->name
);
1582 /* Mark all the blocks only reachable via an incoming catch. */
1585 find_exception_blocks (function_t
*fn
)
1588 block_t
**queue
= XALLOCAVEC (block_t
*, fn
->num_blocks
);
1590 /* First mark all blocks as exceptional. */
1591 for (ix
= fn
->num_blocks
; ix
--;)
1592 fn
->blocks
[ix
].exceptional
= 1;
1594 /* Now mark all the blocks reachable via non-fake edges */
1595 queue
[0] = fn
->blocks
;
1596 queue
[0]->exceptional
= 0;
1599 block_t
*block
= queue
[--ix
];
1602 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1603 if (!arc
->fake
&& !arc
->is_throw
&& arc
->dst
->exceptional
)
1605 arc
->dst
->exceptional
= 0;
1606 queue
[ix
++] = arc
->dst
;
1612 /* Increment totals in COVERAGE according to arc ARC. */
1615 add_branch_counts (coverage_t
*coverage
, const arc_t
*arc
)
1617 if (arc
->is_call_non_return
)
1620 if (arc
->src
->count
)
1621 coverage
->calls_executed
++;
1623 else if (!arc
->is_unconditional
)
1625 coverage
->branches
++;
1626 if (arc
->src
->count
)
1627 coverage
->branches_executed
++;
1629 coverage
->branches_taken
++;
1633 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1634 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1635 If DP is zero, no decimal point is printed. Only print 100% when
1636 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1637 format TOP. Return pointer to a static string. */
1640 format_gcov (gcov_type top
, gcov_type bottom
, int dp
)
1642 static char buffer
[20];
1646 float ratio
= bottom
? (float)top
/ bottom
: 0;
1648 unsigned limit
= 100;
1651 for (ix
= dp
; ix
--; )
1654 percent
= (unsigned) (ratio
* limit
+ (float)0.5);
1655 if (percent
<= 0 && top
)
1657 else if (percent
>= limit
&& top
!= bottom
)
1658 percent
= limit
- 1;
1659 ix
= sprintf (buffer
, "%.*u%%", dp
+ 1, percent
);
1665 buffer
[ix
+1] = buffer
[ix
];
1669 buffer
[ix
+ 1] = '.';
1673 sprintf (buffer
, HOST_WIDEST_INT_PRINT_DEC
, (HOST_WIDEST_INT
)top
);
1678 /* Summary of execution */
1681 executed_summary (unsigned lines
, unsigned executed
)
1684 fnotice (stdout
, "Lines executed:%s of %d\n",
1685 format_gcov (executed
, lines
, 2), lines
);
1687 fnotice (stdout
, "No executable lines\n");
1690 /* Output summary info for a function or file. */
1693 function_summary (const coverage_t
*coverage
, const char *title
)
1695 fnotice (stdout
, "%s '%s'\n", title
, coverage
->name
);
1696 executed_summary (coverage
->lines
, coverage
->lines_executed
);
1700 if (coverage
->branches
)
1702 fnotice (stdout
, "Branches executed:%s of %d\n",
1703 format_gcov (coverage
->branches_executed
,
1704 coverage
->branches
, 2),
1705 coverage
->branches
);
1706 fnotice (stdout
, "Taken at least once:%s of %d\n",
1707 format_gcov (coverage
->branches_taken
,
1708 coverage
->branches
, 2),
1709 coverage
->branches
);
1712 fnotice (stdout
, "No branches\n");
1713 if (coverage
->calls
)
1714 fnotice (stdout
, "Calls executed:%s of %d\n",
1715 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
1718 fnotice (stdout
, "No calls\n");
1722 /* Canonicalize the filename NAME by canonicalizing directory
1723 separators, eliding . components and resolving .. components
1724 appropriately. Always returns a unique string. */
1727 canonicalize_name (const char *name
)
1729 /* The canonical name cannot be longer than the incoming name. */
1730 char *result
= XNEWVEC (char, strlen (name
) + 1);
1731 const char *base
= name
, *probe
;
1736 #if HAVE_DOS_BASED_FILE_SYSTEM
1737 if (base
[0] && base
[1] == ':')
1739 result
[0] = base
[0];
1745 for (dd_base
= ptr
; *base
; base
= probe
)
1749 for (probe
= base
; *probe
; probe
++)
1750 if (IS_DIR_SEPARATOR (*probe
))
1754 if (len
== 1 && base
[0] == '.')
1755 /* Elide a '.' directory */
1757 else if (len
== 2 && base
[0] == '.' && base
[1] == '.')
1759 /* '..', we can only elide it and the previous directory, if
1760 we're not a symlink. */
1761 struct stat ATTRIBUTE_UNUSED buf
;
1765 #if defined (S_ISLNK)
1766 /* S_ISLNK is not POSIX.1-1996. */
1767 || stat (result
, &buf
) || S_ISLNK (buf
.st_mode
)
1771 /* Cannot elide, or unreadable or a symlink. */
1772 dd_base
= ptr
+ 2 + slash
;
1775 while (ptr
!= dd_base
&& *ptr
!= '/')
1777 slash
= ptr
!= result
;
1782 /* Regular pathname component. */
1785 memcpy (ptr
, base
, len
);
1790 for (; IS_DIR_SEPARATOR (*probe
); probe
++)
1798 /* Generate an output file name. INPUT_NAME is the canonicalized main
1799 input file and SRC_NAME is the canonicalized file name.
1800 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
1801 long_output_names we prepend the processed name of the input file
1802 to each output name (except when the current source file is the
1803 input file, so you don't get a double concatenation). The two
1804 components are separated by '##'. With preserve_paths we create a
1805 filename from all path components of the source file, replacing '/'
1806 with '#', and .. with '^', without it we simply take the basename
1807 component. (Remember, the canonicalized name will already have
1808 elided '.' components and converted \\ separators.) */
1811 make_gcov_file_name (const char *input_name
, const char *src_name
)
1816 if (flag_long_names
&& input_name
&& strcmp (src_name
, input_name
))
1818 /* Generate the input filename part. */
1819 result
= XNEWVEC (char, strlen (input_name
) + strlen (src_name
) + 10);
1822 ptr
= mangle_name (input_name
, ptr
);
1823 ptr
[0] = ptr
[1] = '#';
1828 result
= XNEWVEC (char, strlen (src_name
) + 10);
1832 ptr
= mangle_name (src_name
, ptr
);
1833 strcpy (ptr
, ".gcov");
1839 mangle_name (char const *base
, char *ptr
)
1843 /* Generate the source filename part. */
1844 if (!flag_preserve_paths
)
1846 base
= lbasename (base
);
1847 len
= strlen (base
);
1848 memcpy (ptr
, base
, len
);
1853 /* Convert '/' to '#', convert '..' to '^',
1854 convert ':' to '~' on DOS based file system. */
1857 #if HAVE_DOS_BASED_FILE_SYSTEM
1858 if (base
[0] && base
[1] == ':')
1866 for (; *base
; base
= probe
)
1870 for (probe
= base
; *probe
; probe
++)
1874 if (len
== 2 && base
[0] == '.' && base
[1] == '.')
1878 memcpy (ptr
, base
, len
);
1892 /* Scan through the bb_data for each line in the block, increment
1893 the line number execution count indicated by the execution count of
1894 the appropriate basic block. */
1897 add_line_counts (coverage_t
*coverage
, function_t
*fn
)
1900 line_t
*line
= NULL
; /* This is propagated from one iteration to the
1903 /* Scan each basic block. */
1904 for (ix
= 0; ix
!= fn
->num_blocks
; ix
++)
1906 block_t
*block
= &fn
->blocks
[ix
];
1908 const source_t
*src
= NULL
;
1911 if (block
->count
&& ix
&& ix
+ 1 != fn
->num_blocks
)
1912 fn
->blocks_executed
++;
1913 for (jx
= 0, encoding
= block
->u
.line
.encoding
;
1914 jx
!= block
->u
.line
.num
; jx
++, encoding
++)
1917 src
= &sources
[*++encoding
];
1922 line
= &src
->lines
[*encoding
];
1928 if (!line
->count
&& block
->count
)
1929 coverage
->lines_executed
++;
1932 if (!block
->exceptional
)
1933 line
->unexceptional
= 1;
1934 line
->count
+= block
->count
;
1936 free (block
->u
.line
.encoding
);
1937 block
->u
.cycle
.arc
= NULL
;
1938 block
->u
.cycle
.ident
= ~0U;
1940 if (!ix
|| ix
+ 1 == fn
->num_blocks
)
1941 /* Entry or exit block */;
1942 else if (flag_all_blocks
)
1944 line_t
*block_line
= line
;
1947 block_line
= &sources
[fn
->src
].lines
[fn
->line
];
1949 block
->chain
= block_line
->u
.blocks
;
1950 block_line
->u
.blocks
= block
;
1952 else if (flag_branches
)
1956 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1958 arc
->line_next
= line
->u
.branches
;
1959 line
->u
.branches
= arc
;
1960 if (coverage
&& !arc
->is_unconditional
)
1961 add_branch_counts (coverage
, arc
);
1966 fnotice (stderr
, "%s:no lines for '%s'\n", bbg_file_name
, fn
->name
);
1969 /* Accumulate the line counts of a file. */
1972 accumulate_line_counts (source_t
*src
)
1975 function_t
*fn
, *fn_p
, *fn_n
;
1978 /* Reverse the function order. */
1979 for (fn
= src
->functions
, fn_p
= NULL
; fn
;
1980 fn_p
= fn
, fn
= fn_n
)
1982 fn_n
= fn
->line_next
;
1983 fn
->line_next
= fn_p
;
1985 src
->functions
= fn_p
;
1987 for (ix
= src
->num_lines
, line
= src
->lines
; ix
--; line
++)
1989 if (!flag_all_blocks
)
1991 arc_t
*arc
, *arc_p
, *arc_n
;
1993 /* Total and reverse the branch information. */
1994 for (arc
= line
->u
.branches
, arc_p
= NULL
; arc
;
1995 arc_p
= arc
, arc
= arc_n
)
1997 arc_n
= arc
->line_next
;
1998 arc
->line_next
= arc_p
;
2000 add_branch_counts (&src
->coverage
, arc
);
2002 line
->u
.branches
= arc_p
;
2004 else if (line
->u
.blocks
)
2006 /* The user expects the line count to be the number of times
2007 a line has been executed. Simply summing the block count
2008 will give an artificially high number. The Right Thing
2009 is to sum the entry counts to the graph of blocks on this
2010 line, then find the elementary cycles of the local graph
2011 and add the transition counts of those cycles. */
2012 block_t
*block
, *block_p
, *block_n
;
2013 gcov_type count
= 0;
2015 /* Reverse the block information. */
2016 for (block
= line
->u
.blocks
, block_p
= NULL
; block
;
2017 block_p
= block
, block
= block_n
)
2019 block_n
= block
->chain
;
2020 block
->chain
= block_p
;
2021 block
->u
.cycle
.ident
= ix
;
2023 line
->u
.blocks
= block_p
;
2025 /* Sum the entry arcs. */
2026 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
2030 for (arc
= block
->pred
; arc
; arc
= arc
->pred_next
)
2032 if (arc
->src
->u
.cycle
.ident
!= ix
)
2033 count
+= arc
->count
;
2035 add_branch_counts (&src
->coverage
, arc
);
2038 /* Initialize the cs_count. */
2039 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2040 arc
->cs_count
= arc
->count
;
2043 /* Find the loops. This uses the algorithm described in
2044 Tiernan 'An Efficient Search Algorithm to Find the
2045 Elementary Circuits of a Graph', CACM Dec 1970. We hold
2046 the P array by having each block point to the arc that
2047 connects to the previous block. The H array is implicitly
2048 held because of the arc ordering, and the block's
2049 previous arc pointer.
2051 Although the algorithm is O(N^3) for highly connected
2052 graphs, at worst we'll have O(N^2), as most blocks have
2053 only one or two exits. Most graphs will be small.
2055 For each loop we find, locate the arc with the smallest
2056 transition count, and add that to the cumulative
2057 count. Decrease flow over the cycle and remove the arc
2058 from consideration. */
2059 for (block
= line
->u
.blocks
; block
; block
= block
->chain
)
2061 block_t
*head
= block
;
2069 block_t
*dst
= arc
->dst
;
2070 if (/* Already used that arc. */
2072 /* Not to same graph, or before first vertex. */
2073 || dst
->u
.cycle
.ident
!= ix
2074 /* Already in path. */
2075 || dst
->u
.cycle
.arc
)
2077 arc
= arc
->succ_next
;
2083 /* Found a closing arc. */
2084 gcov_type cycle_count
= arc
->cs_count
;
2085 arc_t
*cycle_arc
= arc
;
2088 /* Locate the smallest arc count of the loop. */
2089 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
2090 dst
= probe_arc
->src
)
2091 if (cycle_count
> probe_arc
->cs_count
)
2093 cycle_count
= probe_arc
->cs_count
;
2094 cycle_arc
= probe_arc
;
2097 count
+= cycle_count
;
2098 cycle_arc
->cycle
= 1;
2100 /* Remove the flow from the cycle. */
2101 arc
->cs_count
-= cycle_count
;
2102 for (dst
= head
; (probe_arc
= dst
->u
.cycle
.arc
);
2103 dst
= probe_arc
->src
)
2104 probe_arc
->cs_count
-= cycle_count
;
2106 /* Unwind to the cyclic arc. */
2107 while (head
!= cycle_arc
->src
)
2109 arc
= head
->u
.cycle
.arc
;
2110 head
->u
.cycle
.arc
= NULL
;
2114 arc
= arc
->succ_next
;
2118 /* Add new block to chain. */
2119 dst
->u
.cycle
.arc
= arc
;
2123 /* We could not add another vertex to the path. Remove
2124 the last vertex from the list. */
2125 arc
= head
->u
.cycle
.arc
;
2128 /* It was not the first vertex. Move onto next arc. */
2129 head
->u
.cycle
.arc
= NULL
;
2131 arc
= arc
->succ_next
;
2132 goto current_vertex
;
2134 /* Mark this block as unusable. */
2135 block
->u
.cycle
.ident
= ~0U;
2138 line
->count
= count
;
2143 src
->coverage
.lines
++;
2145 src
->coverage
.lines_executed
++;
2150 /* Output information about ARC number IX. Returns nonzero if
2151 anything is output. */
2154 output_branch_count (FILE *gcov_file
, int ix
, const arc_t
*arc
)
2156 if (arc
->is_call_non_return
)
2158 if (arc
->src
->count
)
2160 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
2161 format_gcov (arc
->src
->count
- arc
->count
,
2162 arc
->src
->count
, -flag_counts
));
2165 fnotice (gcov_file
, "call %2d never executed\n", ix
);
2167 else if (!arc
->is_unconditional
)
2169 if (arc
->src
->count
)
2170 fnotice (gcov_file
, "branch %2d taken %s%s\n", ix
,
2171 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
2172 arc
->fall_through
? " (fallthrough)"
2173 : arc
->is_throw
? " (throw)" : "");
2175 fnotice (gcov_file
, "branch %2d never executed\n", ix
);
2177 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
2179 if (arc
->src
->count
)
2180 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
2181 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
2183 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
2191 /* Read in the source file one line at a time, and output that line to
2192 the gcov file preceded by its execution count and other
2196 output_lines (FILE *gcov_file
, const source_t
*src
)
2199 unsigned line_num
; /* current line number. */
2200 const line_t
*line
; /* current line info ptr. */
2201 char string
[STRING_SIZE
]; /* line buffer. */
2202 char const *retval
= ""; /* status of source file reading. */
2203 function_t
*fn
= NULL
;
2205 fprintf (gcov_file
, "%9s:%5d:Source:%s\n", "-", 0, src
->coverage
.name
);
2206 if (!multiple_files
)
2208 fprintf (gcov_file
, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name
);
2209 fprintf (gcov_file
, "%9s:%5d:Data:%s\n", "-", 0,
2210 no_data_file
? "-" : da_file_name
);
2211 fprintf (gcov_file
, "%9s:%5d:Runs:%u\n", "-", 0, object_runs
);
2213 fprintf (gcov_file
, "%9s:%5d:Programs:%u\n", "-", 0, program_count
);
2215 source_file
= fopen (src
->name
, "r");
2218 fnotice (stderr
, "Cannot open source file %s\n", src
->name
);
2221 else if (src
->file_time
== 0)
2222 fprintf (gcov_file
, "%9s:%5d:Source is newer than graph\n", "-", 0);
2225 fn
= src
->functions
;
2227 for (line_num
= 1, line
= &src
->lines
[line_num
];
2228 line_num
< src
->num_lines
; line_num
++, line
++)
2230 for (; fn
&& fn
->line
== line_num
; fn
= fn
->line_next
)
2232 arc_t
*arc
= fn
->blocks
[fn
->num_blocks
- 1].pred
;
2233 gcov_type return_count
= fn
->blocks
[fn
->num_blocks
- 1].count
;
2235 for (; arc
; arc
= arc
->pred_next
)
2237 return_count
-= arc
->count
;
2239 fprintf (gcov_file
, "function %s", fn
->name
);
2240 fprintf (gcov_file
, " called %s",
2241 format_gcov (fn
->blocks
[0].count
, 0, -1));
2242 fprintf (gcov_file
, " returned %s",
2243 format_gcov (return_count
, fn
->blocks
[0].count
, 0));
2244 fprintf (gcov_file
, " blocks executed %s",
2245 format_gcov (fn
->blocks_executed
, fn
->num_blocks
- 2, 0));
2246 fprintf (gcov_file
, "\n");
2249 /* For lines which don't exist in the .bb file, print '-' before
2250 the source line. For lines which exist but were never
2251 executed, print '#####' before the source line. Otherwise,
2252 print the execution count before the source line. There are
2253 16 spaces of indentation added before the source line so that
2254 tabs won't be messed up. */
2255 fprintf (gcov_file
, "%9s:%5u:",
2256 !line
->exists
? "-" : line
->count
2257 ? format_gcov (line
->count
, 0, -1)
2258 : line
->unexceptional
? "#####" : "=====", line_num
);
2262 /* Copy source line. */
2265 retval
= fgets (string
, STRING_SIZE
, source_file
);
2268 fputs (retval
, gcov_file
);
2270 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n');
2273 fputs ("/*EOF*/\n", gcov_file
);
2275 if (flag_all_blocks
)
2281 for (ix
= jx
= 0, block
= line
->u
.blocks
; block
;
2282 block
= block
->chain
)
2284 if (!block
->is_call_return
)
2285 fprintf (gcov_file
, "%9s:%5u-block %2d\n",
2286 !line
->exists
? "-" : block
->count
2287 ? format_gcov (block
->count
, 0, -1)
2288 : block
->exceptional
? "%%%%%" : "$$$$$",
2291 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2292 jx
+= output_branch_count (gcov_file
, jx
, arc
);
2295 else if (flag_branches
)
2300 for (ix
= 0, arc
= line
->u
.branches
; arc
; arc
= arc
->line_next
)
2301 ix
+= output_branch_count (gcov_file
, ix
, arc
);
2305 /* Handle all remaining source lines. There may be lines after the
2306 last line of code. */
2309 for (; (retval
= fgets (string
, STRING_SIZE
, source_file
)); line_num
++)
2311 fprintf (gcov_file
, "%9s:%5u:%s", "-", line_num
, retval
);
2313 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n')
2315 retval
= fgets (string
, STRING_SIZE
, source_file
);
2318 fputs (retval
, gcov_file
);
2324 fclose (source_file
);