1 /* Gcov.c: prepend line execution counts and branch probabilities to a
3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
4 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
5 Contributed by James E. Wilson of Cygnus Support.
6 Mangled by Bob Manson of Cygnus Support.
7 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
9 Gcov is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 Gcov is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Gcov; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* ??? Print a list of the ten blocks with the highest execution counts,
25 and list the line numbers corresponding to those blocks. Also, perhaps
26 list the line numbers with the highest execution counts, only printing
27 the first if there are several which are all listed in the same block. */
29 /* ??? Should have an option to print the number of basic blocks, and the
30 percent of them that are covered. */
32 /* ??? Does not correctly handle the case where two .bb files refer to
33 the same included source file. For example, if one has a short
34 file containing only inline functions, which is then included in
35 two other files, then there will be two .bb files which refer to
36 the include file, but there is no way to get the total execution
37 counts for the included file, can only get execution counts for one
38 or the other of the including files. this can be fixed by --ratios
39 --long-file-names --preserve-paths and perl. */
41 /* Need an option to show individual block counts, and show
42 probabilities of fall through arcs. */
46 #include "coretypes.h"
54 typedef HOST_WIDEST_INT gcov_type
;
57 /* The bbg file is generated by -ftest-coverage option. The da file is
58 generated by a program compiled with -fprofile-arcs. Their formats
59 are documented in gcov-io.h. */
61 /* The functions in this file for creating and solution program flow graphs
62 are very similar to functions in the gcc source file profile.c. In
63 some places we make use of the knowledge of how profile.c works to
64 select particular algorithms here. */
66 /* This is the size of the buffer used to read in source file lines. */
68 #define STRING_SIZE 200
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. */
84 unsigned int count_valid
: 1;
85 unsigned int on_tree
: 1;
86 unsigned int fake
: 1;
87 unsigned int fall_through
: 1;
90 unsigned int is_call
: 1;
92 /* Next branch on line. */
93 struct arc_info
*line_next
;
95 /* Links to next arc on src and dst lists. */
96 struct arc_info
*succ_next
;
97 struct arc_info
*pred_next
;
100 /* Describes a basic block. Contains lists of arcs to successor and
101 predecessor blocks. */
103 typedef struct block_info
105 /* Chain of exit and entry arcs. */
109 /* Number of unprocessed exit and entry arcs. */
113 /* Block execution count. */
115 unsigned count_valid
: 1;
116 unsigned valid_chain
: 1;
117 unsigned invalid_chain
: 1;
119 /* Array of line numbers and source files. source files are
120 introduced by a linenumber of zero, the next 'line number' is the
121 number of the source file. Always starts with a source file. */
123 unsigned num_encodings
;
125 /* Temporary chain for solving graph. */
126 struct block_info
*chain
;
130 /* Describes a single function. Contains an array of basic blocks. */
132 typedef struct function_info
134 /* Name of function. */
138 /* Array of basic blocks. */
142 /* Raw arc coverage counts. */
147 struct function_info
*next
;
150 /* Describes coverage of a file or function. */
152 typedef struct coverage_info
158 int branches_executed
;
167 /* Describes a single line of source. Contains a chain of basic blocks
170 typedef struct line_info
172 gcov_type count
; /* execution count */
173 arc_t
*branches
; /* branches from blocks that end on this
178 /* Describes a file mentioned in the block graph. Contains an array
181 typedef struct source_info
183 /* Name of source file. */
187 /* Array of line information. */
193 /* Next source file. */
194 struct source_info
*next
;
197 /* Holds a list of function basic block graphs. */
199 static function_t
*functions
;
201 /* This points to the head of the sourcefile structure list. */
203 static source_t
*sources
;
205 /* Modification time of graph file. */
207 static time_t bbg_file_time
;
209 /* Name and file pointer of the input file for the basic block graph. */
211 static char *bbg_file_name
;
213 /* Name and file pointer of the input file for the arc count data. */
215 static char *da_file_name
;
217 /* Output branch probabilities. */
219 static int flag_branches
= 0;
221 /* Output a gcov file if this is true. This is on by default, and can
222 be turned off by the -n option. */
224 static int flag_gcov_file
= 1;
226 /* For included files, make the gcov output file name include the name
227 of the input source file. For example, if x.h is included in a.c,
228 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
230 static int flag_long_names
= 0;
232 /* Output summary info for each function. */
234 static int flag_function_summary
= 0;
236 /* Object directory file prefix. This is the directory/file where the
237 graph and data files are looked for, if nonzero. */
239 static char *object_directory
= 0;
241 /* Preserve all pathname components. Needed when object files and
242 source files are in subdirectories. '/' is mangled as '#', '.' is
243 elided and '..' mangled to '^'. */
245 static int flag_preserve_paths
= 0;
247 /* Output the number of times a branch was taken as opposed to the percentage
248 of times it was taken. */
250 static int flag_counts
= 0;
252 /* Forward declarations. */
253 static void fnotice
PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2
;
254 static int process_args
PARAMS ((int, char **));
255 static void print_usage
PARAMS ((int)) ATTRIBUTE_NORETURN
;
256 static void print_version
PARAMS ((void)) ATTRIBUTE_NORETURN
;
257 static void process_file
PARAMS ((const char *));
258 static void create_file_names
PARAMS ((const char *));
259 static int read_graph_file
PARAMS ((void));
260 static int read_count_file
PARAMS ((void));
261 static void solve_flow_graph
PARAMS ((function_t
*));
262 static void add_branch_counts
PARAMS ((coverage_t
*, const arc_t
*));
263 static void add_line_counts
PARAMS ((coverage_t
*, const function_t
*));
264 static void function_summary
PARAMS ((const coverage_t
*, const char *));
265 static const char *format_gcov
PARAMS ((gcov_type
, gcov_type
, int));
266 static void accumulate_line_counts
PARAMS ((source_t
*));
267 static void output_lines
PARAMS ((FILE *, const source_t
*));
268 static char *make_gcov_file_name
PARAMS ((const char *, const char *));
269 static void release_structures
PARAMS ((void));
270 extern int main
PARAMS ((int, char **));
281 argno
= process_args (argc
, argv
);
285 for (; argno
!= argc
; argno
++)
287 release_structures ();
289 process_file (argv
[argno
]);
296 fnotice
VPARAMS ((FILE *file
, const char *msgid
, ...))
299 VA_FIXEDARG (ap
, FILE *, file
);
300 VA_FIXEDARG (ap
, const char *, msgid
);
302 vfprintf (file
, _(msgid
), ap
);
306 /* More 'friendly' abort that prints the line and file.
307 config.h can #define abort fancy_abort if you like that sort of thing. */
308 extern void fancy_abort
PARAMS ((void)) ATTRIBUTE_NORETURN
;
313 fnotice (stderr
, "Internal gcov abort.\n");
314 exit (FATAL_EXIT_CODE
);
317 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
318 otherwise the output of --help. */
321 print_usage (error_p
)
324 FILE *file
= error_p
? stderr
: stdout
;
325 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
327 fnotice (file
, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
328 fnotice (file
, "Print code coverage information.\n\n");
329 fnotice (file
, " -h, --help Print this help, then exit\n");
330 fnotice (file
, " -v, --version Print version number, then exit\n");
331 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
332 fnotice (file
, " -c, --branch-counts Given counts of branches taken\n\
333 rather than percentages\n");
334 fnotice (file
, " -n, --no-output Do not create an output file\n");
335 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
337 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
338 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
339 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
340 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
345 /* Print version information and exit. */
351 unsigned version
= GCOV_VERSION
;
354 for (ix
= 4; ix
--; version
>>= 8)
356 fnotice (stdout
, "gcov %.4s (GCC %s)\n", v
, version_string
);
357 fnotice (stdout
, "Copyright (C) 2002 Free Software Foundation, Inc.\n");
359 "This is free software; see the source for copying conditions. There is NO\n\
360 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
361 exit (SUCCESS_EXIT_CODE
);
364 static const struct option options
[] =
366 { "help", no_argument
, NULL
, 'h' },
367 { "version", no_argument
, NULL
, 'v' },
368 { "branch-probabilities", no_argument
, NULL
, 'b' },
369 { "branch-counts", no_argument
, NULL
, 'c' },
370 { "no-output", no_argument
, NULL
, 'n' },
371 { "long-file-names", no_argument
, NULL
, 'l' },
372 { "function-summaries", no_argument
, NULL
, 'f' },
373 { "preserve-paths", no_argument
, NULL
, 'p' },
374 { "object-directory", required_argument
, NULL
, 'o' },
375 { "object-file", required_argument
, NULL
, 'o' },
378 /* Process args, return index to first non-arg. */
381 process_args (argc
, argv
)
387 while ((opt
= getopt_long (argc
, argv
, "hvbclnfo:p", options
, NULL
)) != -1)
393 /* print_usage will exit. */
396 /* print_version will exit. */
410 flag_function_summary
= 1;
413 object_directory
= optarg
;
416 flag_preserve_paths
= 1;
420 /* print_usage will exit. */
427 /* Process a single source file. */
430 process_file (file_name
)
431 const char *file_name
;
436 create_file_names (file_name
);
437 if (read_graph_file ())
442 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
446 if (read_count_file ())
449 for (fn
= functions
; fn
; fn
= fn
->next
)
450 solve_flow_graph (fn
);
451 for (src
= sources
; src
; src
= src
->next
)
452 src
->lines
= (line_t
*) xcalloc (src
->num_lines
, sizeof (line_t
));
453 for (fn
= functions
; fn
; fn
= fn
->next
)
457 memset (&coverage
, 0, sizeof (coverage
));
458 coverage
.name
= fn
->name
;
459 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
460 if (flag_function_summary
)
462 function_summary (&coverage
, "Function");
463 fnotice (stdout
, "\n");
467 for (src
= sources
; src
; src
= src
->next
)
469 accumulate_line_counts (src
);
470 function_summary (&src
->coverage
, "File");
473 char *gcov_file_name
= make_gcov_file_name (file_name
, src
->name
);
474 FILE *gcov_file
= fopen (gcov_file_name
, "w");
478 fnotice (stdout
, "%s:creating `%s'\n",
479 src
->name
, gcov_file_name
);
480 output_lines (gcov_file
, src
);
481 if (ferror (gcov_file
))
482 fnotice (stderr
, "%s:error writing output file `%s'\n",
483 src
->name
, gcov_file_name
);
487 fnotice (stderr
, "%s:could not open output file `%s'\n",
488 src
->name
, gcov_file_name
);
489 free (gcov_file_name
);
491 fnotice (stdout
, "\n");
495 /* Release all memory used. */
498 release_structures ()
503 free (bbg_file_name
);
505 da_file_name
= bbg_file_name
= NULL
;
508 while ((src
= sources
))
516 while ((fn
= functions
))
521 functions
= fn
->next
;
522 for (ix
= fn
->num_blocks
, block
= fn
->blocks
; ix
--; block
++)
526 for (arc
= block
->succ
; arc
; arc
= arc_n
)
528 arc_n
= arc
->succ_next
;
531 free (block
->encoding
);
538 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
539 is not specified, these are looked for in the current directory,
540 and named from the basename of the FILE_NAME sans extension. If
541 OBJECT_DIRECTORY is specified and is a directory, the files are in
542 that directory, but named from the basename of the FILE_NAME, sans
543 extension. Otherwise OBJECT_DIRECTORY is taken to be the name of
544 the object *file*, and the data files are named from that. */
547 create_file_names (file_name
)
548 const char *file_name
;
552 int length
= strlen (file_name
);
555 if (object_directory
&& object_directory
[0])
559 length
+= strlen (object_directory
) + 2;
560 name
= xmalloc (length
);
563 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
564 strcat (name
, object_directory
);
565 if (base
&& name
[strlen (name
) - 1] != '/')
570 name
= xmalloc (length
+ 1);
577 /* Append source file name */
578 cptr
= strrchr (file_name
, '/');
579 strcat (name
, cptr
? cptr
+ 1 : file_name
);
582 /* Remove the extension. */
583 cptr
= strrchr (name
, '.');
587 length
= strlen (name
);
589 bbg_file_name
= xmalloc (length
+ strlen (GCOV_GRAPH_SUFFIX
) + 1);
590 strcpy (bbg_file_name
, name
);
591 strcpy (bbg_file_name
+ length
, GCOV_GRAPH_SUFFIX
);
593 da_file_name
= xmalloc (length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
594 strcpy (da_file_name
, name
);
595 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
600 /* Read the graph file. Return nonzero on fatal error. */
607 unsigned magic
, version
;
608 unsigned current_tag
= 0;
610 struct function_info
*fn
= NULL
;
611 source_t
*src
= NULL
;
614 file
= fopen (bbg_file_name
, "rb");
617 fnotice (stderr
, "%s:cannot open graph file\n", bbg_file_name
);
620 if (!fstat (fileno (file
), &status
))
621 bbg_file_time
= status
.st_mtime
;
622 if (gcov_read_unsigned (file
, &magic
) || magic
!= GCOV_GRAPH_MAGIC
)
624 fnotice (stderr
, "%s:not a gcov graph file\n", bbg_file_name
);
629 if (gcov_read_unsigned (file
, &version
) || version
!= GCOV_VERSION
)
633 magic
= GCOV_VERSION
;
635 for (ix
= 4; ix
--; magic
>>= 8, version
>>= 8)
640 fnotice (stderr
, "%s:version `%.4s', prefer `%.4s'\n",
641 bbg_file_name
, v
, e
);
644 while (!gcov_read_unsigned (file
, &tag
))
649 if (gcov_read_unsigned (file
, &length
))
652 base
= gcov_save_position (file
);
654 if (tag
== GCOV_TAG_FUNCTION
)
656 char *function_name
= NULL
;
659 if (gcov_read_string (file
, &function_name
, NULL
)
660 || gcov_read_unsigned (file
, &checksum
))
662 fn
= (function_t
*)xcalloc (1, sizeof (function_t
));
663 fn
->name
= function_name
;
664 fn
->checksum
= checksum
;
666 fn
->next
= functions
;
670 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
673 fnotice (stderr
, "%s:already seen blocks for `%s'\n",
674 bbg_file_name
, fn
->name
);
677 fn
->num_blocks
= length
/ 4;
679 = (block_t
*)xcalloc (fn
->num_blocks
, sizeof (block_t
));
682 else if (fn
&& tag
== GCOV_TAG_ARCS
)
685 unsigned num_dests
= (length
- 4) / 8;
686 unsigned dest
, flags
;
688 if (gcov_read_unsigned (file
, &src
)
689 || src
>= fn
->num_blocks
690 || fn
->blocks
[src
].succ
)
695 struct arc_info
*arc
;
697 if (gcov_read_unsigned (file
, &dest
)
698 || gcov_read_unsigned (file
, &flags
)
699 || dest
>= fn
->num_blocks
)
701 arc
= (arc_t
*) xcalloc (1, sizeof (arc_t
));
703 arc
->dst
= &fn
->blocks
[dest
];
704 arc
->src
= &fn
->blocks
[src
];
707 arc
->count_valid
= 0;
708 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
709 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
710 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
712 arc
->succ_next
= fn
->blocks
[src
].succ
;
713 fn
->blocks
[src
].succ
= arc
;
714 fn
->blocks
[src
].num_succ
++;
716 arc
->pred_next
= fn
->blocks
[dest
].pred
;
717 fn
->blocks
[dest
].pred
= arc
;
718 fn
->blocks
[dest
].num_pred
++;
720 arc
->is_call
= arc
->fake
;
726 else if (fn
&& tag
== GCOV_TAG_LINES
)
730 = (unsigned *)xcalloc ((length
- 4) / 4, sizeof (unsigned));
732 if (gcov_read_unsigned (file
, &blockno
)
733 || blockno
>= fn
->num_blocks
734 || fn
->blocks
[blockno
].encoding
)
741 if (gcov_read_unsigned (file
, &lineno
))
748 line_nos
[ix
++] = src
->index
;
750 line_nos
[ix
++] = lineno
;
751 if (lineno
>= src
->num_lines
)
752 src
->num_lines
= lineno
+ 1;
756 char *file_name
= NULL
;
758 if (gcov_read_string (file
, &file_name
, NULL
))
762 for (src
= sources
; src
; src
= src
->next
)
763 if (!strcmp (file_name
, src
->name
))
770 src
= (source_t
*)xcalloc (1, sizeof (source_t
));
771 src
->name
= file_name
;
772 src
->coverage
.name
= file_name
;
773 src
->index
= sources
? sources
->index
+ 1 : 1;
778 line_nos
[ix
++] = src
->index
;
782 fn
->blocks
[blockno
].encoding
= line_nos
;
783 fn
->blocks
[blockno
].num_encodings
= ix
;
785 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
790 if (gcov_resync (file
, base
, length
))
793 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
800 /* We built everything backwards, so nreverse them all */
802 /* Reverse sources. Not strictly necessary, but we'll then process
803 them in the 'expected' order. */
805 source_t
*src
, *src_p
, *src_n
;
807 for (src_p
= NULL
, src
= sources
; src
; src_p
= src
, src
= src_n
)
815 /* Reverse functions. */
817 function_t
*fn
, *fn_p
, *fn_n
;
819 for (fn_p
= NULL
, fn
= functions
; fn
; fn_p
= fn
, fn
= fn_n
)
826 /* Reverse the arcs */
827 for (ix
= fn
->num_blocks
; ix
--;)
829 arc_t
*arc
, *arc_p
, *arc_n
;
831 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
832 arc_p
= arc
, arc
= arc_n
)
834 arc_n
= arc
->succ_next
;
835 arc
->succ_next
= arc_p
;
837 fn
->blocks
[ix
].succ
= arc_p
;
839 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
840 arc_p
= arc
, arc
= arc_n
)
842 arc_n
= arc
->pred_next
;
843 arc
->pred_next
= arc_p
;
845 fn
->blocks
[ix
].pred
= arc_p
;
853 /* Reads profiles from the count file and attach to each
854 function. Return nonzero if fatal error. */
861 char *function_name_buffer
= NULL
;
862 unsigned magic
, version
;
863 function_t
*fn
= NULL
;
865 file
= fopen (da_file_name
, "rb");
868 fnotice (stderr
, "%s:cannot open data file\n", da_file_name
);
871 if (gcov_read_unsigned (file
, &magic
) || magic
!= GCOV_DATA_MAGIC
)
873 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
875 free (function_name_buffer
);
879 if (gcov_read_unsigned (file
, &version
) || version
!= GCOV_VERSION
)
883 magic
= GCOV_VERSION
;
884 for (ix
= 4; ix
--; magic
>>= 8, version
>>= 8)
889 fnotice (stderr
, "%s:version `%.4s', prefer version `%.4s'\n",
895 unsigned tag
, length
;
898 if (gcov_read_unsigned (file
, &tag
)
899 || gcov_read_unsigned (file
, &length
))
905 fnotice (stderr
, "%s:corrupted\n", da_file_name
);
908 base
= gcov_save_position (file
);
909 if (tag
== GCOV_TAG_FUNCTION
)
912 struct function_info
*fn_n
= functions
;
914 if (gcov_read_string (file
, &function_name_buffer
, NULL
)
915 || gcov_read_unsigned (file
, &checksum
))
918 for (fn
= fn
? fn
->next
: NULL
; ; fn
= fn
->next
)
922 else if ((fn
= fn_n
))
926 fnotice (stderr
, "%s:unknown function `%s'\n",
927 da_file_name
, function_name_buffer
);
930 if (!strcmp (fn
->name
, function_name_buffer
))
936 else if (checksum
!= fn
->checksum
)
939 fnotice (stderr
, "%s:profile mismatch for `%s'\n",
940 da_file_name
, function_name_buffer
);
944 else if (tag
== GCOV_TAG_ARC_COUNTS
&& fn
)
946 if (length
!= 8 * fn
->num_counts
)
951 = (gcov_type
*)xcalloc (fn
->num_counts
, sizeof (gcov_type
));
953 for (ix
= 0; ix
!= fn
->num_counts
; ix
++)
957 if (gcov_read_counter (file
, &count
))
959 fn
->counts
[ix
] += count
;
962 gcov_resync (file
, base
, length
);
966 free (function_name_buffer
);
970 /* Solve the flow graph. Propagate counts from the instrumented arcs
971 to the blocks and the uninstrumented arcs. */
974 solve_flow_graph (fn
)
979 gcov_type
*count_ptr
= fn
->counts
;
980 block_t
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
981 block_t
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
983 if (fn
->num_blocks
< 2)
984 fnotice (stderr
, "%s:`%s' lacks entry and/or exit blocks\n",
985 bbg_file_name
, fn
->name
);
988 if (fn
->blocks
[0].num_pred
)
989 fnotice (stderr
, "%s:`%s' has arcs to entry block\n",
990 bbg_file_name
, fn
->name
);
992 /* We can't deduce the entry block counts from the lack of
994 fn
->blocks
[0].num_pred
= ~(unsigned)0;
996 if (fn
->blocks
[fn
->num_blocks
- 1].num_succ
)
997 fnotice (stderr
, "%s:`%s' has arcs from exit block\n",
998 bbg_file_name
, fn
->name
);
1000 /* Likewise, we can't deduce exit block counts from the lack
1001 of its successors. */
1002 fn
->blocks
[fn
->num_blocks
- 1].num_succ
= ~(unsigned)0;
1005 /* Propagate the measured counts, this must be done in the same
1006 order as the code in profile.c */
1007 for (ix
= 0; ix
!= fn
->num_blocks
; ix
++)
1009 block_t
const *prev_dst
= NULL
;
1010 int out_of_order
= 0;
1012 for (arc
= fn
->blocks
[ix
].succ
; arc
; arc
= arc
->succ_next
)
1017 arc
->count
= *count_ptr
++;
1018 arc
->count_valid
= 1;
1019 fn
->blocks
[ix
].num_succ
--;
1020 arc
->dst
->num_pred
--;
1022 if (prev_dst
&& prev_dst
> arc
->dst
)
1024 prev_dst
= arc
->dst
;
1027 /* Sort the successor arcs into ascending dst order. profile.c
1028 normally produces arcs in the right order, but sometimes with
1029 one or two out of order. We're not using a particularly
1033 arc_t
*start
= fn
->blocks
[ix
].succ
;
1034 unsigned changes
= 1;
1038 arc_t
*arc
, *arc_p
, *arc_n
;
1041 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
1043 if (arc
->dst
> arc_n
->dst
)
1047 arc_p
->succ_next
= arc_n
;
1050 arc
->succ_next
= arc_n
->succ_next
;
1051 arc_n
->succ_next
= arc
;
1061 fn
->blocks
[ix
].succ
= start
;
1064 /* Place it on the invalid chain, it will be ignored if that's
1066 fn
->blocks
[ix
].invalid_chain
= 1;
1067 fn
->blocks
[ix
].chain
= invalid_blocks
;
1068 invalid_blocks
= &fn
->blocks
[ix
];
1071 while (invalid_blocks
|| valid_blocks
)
1075 while ((blk
= invalid_blocks
))
1077 gcov_type total
= 0;
1080 invalid_blocks
= blk
->chain
;
1081 blk
->invalid_chain
= 0;
1083 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1084 total
+= arc
->count
;
1085 else if (!blk
->num_pred
)
1086 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1087 total
+= arc
->count
;
1092 blk
->count_valid
= 1;
1093 blk
->chain
= valid_blocks
;
1094 blk
->valid_chain
= 1;
1097 while ((blk
= valid_blocks
))
1100 arc_t
*arc
, *inv_arc
;
1102 valid_blocks
= blk
->chain
;
1103 blk
->valid_chain
= 0;
1104 if (blk
->num_succ
== 1)
1110 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1112 total
-= arc
->count
;
1113 if (!arc
->count_valid
)
1117 inv_arc
->count_valid
= 1;
1118 inv_arc
->count
= total
;
1121 if (dst
->count_valid
)
1123 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
1125 dst
->chain
= valid_blocks
;
1126 dst
->valid_chain
= 1;
1132 if (!dst
->num_pred
&& !dst
->invalid_chain
)
1134 dst
->chain
= invalid_blocks
;
1135 dst
->invalid_chain
= 1;
1136 invalid_blocks
= dst
;
1140 if (blk
->num_pred
== 1)
1146 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1148 total
-= arc
->count
;
1149 if (!arc
->count_valid
)
1153 inv_arc
->count_valid
= 1;
1154 inv_arc
->count
= total
;
1157 if (src
->count_valid
)
1159 if (src
->num_succ
== 1 && !src
->valid_chain
)
1161 src
->chain
= valid_blocks
;
1162 src
->valid_chain
= 1;
1168 if (!src
->num_succ
&& !src
->invalid_chain
)
1170 src
->chain
= invalid_blocks
;
1171 src
->invalid_chain
= 1;
1172 invalid_blocks
= src
;
1179 /* If the graph has been correctly solved, every block will have a
1181 for (ix
= 0; ix
< fn
->num_blocks
; ix
++)
1182 if (!fn
->blocks
[ix
].count_valid
)
1184 fnotice (stderr
, "%s:graph is unsolvable for `%s'\n",
1185 bbg_file_name
, fn
->name
);
1192 /* Increment totals in COVERAGE according to arc ARC. */
1195 add_branch_counts (coverage
, arc
)
1196 coverage_t
*coverage
;
1202 if (arc
->src
->count
)
1203 coverage
->calls_executed
++;
1207 coverage
->branches
++;
1208 if (arc
->src
->count
)
1209 coverage
->branches_executed
++;
1211 coverage
->branches_taken
++;
1215 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1216 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1217 If DP is zero, no decimal point is printed. Only print 100% when
1218 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1219 format TOP. Return pointer to a static string. */
1222 format_gcov (top
, bottom
, dp
)
1223 gcov_type top
, bottom
;
1226 static char buffer
[20];
1230 float ratio
= bottom
? (float)top
/ bottom
: 0;
1232 unsigned limit
= 100;
1235 for (ix
= dp
; ix
--; )
1238 percent
= (unsigned) (ratio
* limit
+ (float)0.5);
1239 if (percent
<= 0 && top
)
1241 else if (percent
>= limit
&& top
!= bottom
)
1242 percent
= limit
- 1;
1243 ix
= sprintf (buffer
, "%.*u%%", dp
+ 1, percent
);
1249 buffer
[ix
+1] = buffer
[ix
];
1253 buffer
[ix
+ 1] = '.';
1257 sprintf (buffer
, HOST_WIDEST_INT_PRINT_DEC
, (HOST_WIDEST_INT
)top
);
1263 /* Output summary info for a function. */
1266 function_summary (coverage
, title
)
1267 const coverage_t
*coverage
;
1270 fnotice (stdout
, "%s `%s'\n", title
, coverage
->name
);
1272 if (coverage
->lines
)
1273 fnotice (stdout
, "Lines executed:%s of %d\n",
1274 format_gcov (coverage
->lines_executed
, coverage
->lines
, 2),
1277 fnotice (stdout
, "No executable lines");
1281 if (coverage
->branches
)
1283 fnotice (stdout
, "Branches executed:%s of %d\n",
1284 format_gcov (coverage
->branches_executed
,
1285 coverage
->branches
, 2),
1286 coverage
->branches
);
1287 fnotice (stdout
, "Taken at least once:%s of %d\n",
1288 format_gcov (coverage
->branches_taken
,
1289 coverage
->branches
, 2),
1290 coverage
->branches
);
1293 fnotice (stdout
, "No branches\n");
1294 if (coverage
->calls
)
1295 fnotice (stdout
, "Calls executed:%s of %d\n",
1296 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
1299 fnotice (stdout
, "No calls\n");
1303 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1304 affect name generation. With preserve_paths we create a filename
1305 from all path components of the source file, replacing '/' with
1306 '#', without it we simply take the basename component. With
1307 long_output_names we prepend the processed name of the input file
1308 to each output name (except when the current source file is the
1309 input file, so you don't get a double concatenation). The two
1310 components are separated by '##'. Also '.' filename components are
1311 removed and '..' components are renamed to '^'. */
1314 make_gcov_file_name (input_name
, src_name
)
1315 const char *input_name
;
1316 const char *src_name
;
1319 char *name
= xmalloc (strlen (src_name
) + strlen (input_name
) + 10);
1322 if (flag_long_names
&& strcmp (src_name
, input_name
))
1324 /* Generate the input filename part. */
1325 cptr
= flag_preserve_paths
? NULL
: strrchr (input_name
, '/');
1326 strcat (name
, cptr
? cptr
+ 1 : input_name
);
1327 strcat (name
, "##");
1330 /* Generate the source filename part. */
1331 cptr
= flag_preserve_paths
? NULL
: strrchr (src_name
, '/');
1332 strcat (name
, cptr
? cptr
+ 1 : src_name
);
1334 if (flag_preserve_paths
)
1336 /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1339 for (cptr
= name
; (cptr
= strchr ((prev
= cptr
), '/'));)
1343 if (prev
+ 1 == cptr
&& prev
[0] == '.')
1348 else if (prev
+ 2 == cptr
&& prev
[0] == '.' && prev
[1] == '.')
1360 prev
[0] = prev
[shift
];
1366 strcat (name
, ".gcov");
1370 /* Scan through the bb_data for each line in the block, increment
1371 the line number execution count indicated by the execution count of
1372 the appropriate basic block. */
1375 add_line_counts (coverage
, fn
)
1376 coverage_t
*coverage
;
1377 const function_t
*fn
;
1380 line_t
*line
= NULL
; /* this is propagated from one iteration to the
1383 /* Scan each basic block. */
1384 for (ix
= 0; ix
!= fn
->num_blocks
; ix
++)
1386 const block_t
*block
= &fn
->blocks
[ix
];
1388 const source_t
*src
= NULL
;
1391 for (jx
= 0, encoding
= block
->encoding
;
1392 jx
!= block
->num_encodings
; jx
++, encoding
++)
1395 unsigned src_n
= *++encoding
;
1397 for (src
= sources
; src
->index
!= src_n
; src
= src
->next
)
1403 line
= &src
->lines
[*encoding
];
1409 if (!line
->count
&& block
->count
)
1410 coverage
->lines_executed
++;
1413 line
->count
+= block
->count
;
1416 if (line
&& flag_branches
)
1420 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
1422 /* Ignore fall through arcs as they aren't really branches. */
1423 if (arc
->fall_through
)
1426 arc
->line_next
= line
->branches
;
1427 line
->branches
= arc
;
1429 add_branch_counts (coverage
, arc
);
1434 fnotice (stderr
, "%s:no lines for `%s'\n", bbg_file_name
, fn
->name
);
1437 /* Accumulate the line counts of a file. */
1440 accumulate_line_counts (src
)
1446 for (ix
= src
->num_lines
, line
= src
->lines
; ix
--; line
++)
1448 arc_t
*arc
, *arc_p
, *arc_n
;
1450 /* Total and reverse the branch information. */
1451 for (arc
= line
->branches
, arc_p
= NULL
; arc
; arc_p
= arc
, arc
= arc_n
)
1453 arc_n
= arc
->line_next
;
1454 arc
->line_next
= arc_p
;
1456 add_branch_counts (&src
->coverage
, arc
);
1458 line
->branches
= arc_p
;
1462 src
->coverage
.lines
++;
1464 src
->coverage
.lines_executed
++;
1469 /* Read in the source file one line at a time, and output that line to
1470 the gcov file preceded by its execution count and other
1474 output_lines (gcov_file
, src
)
1476 const source_t
*src
;
1479 unsigned line_num
; /* current line number. */
1480 const line_t
*line
; /* current line info ptr. */
1481 char string
[STRING_SIZE
]; /* line buffer. */
1482 char const *retval
= ""; /* status of source file reading. */
1484 fprintf (gcov_file
, "%9s:%5d:Source:%s\n", "-", 0, src
->name
);
1485 fprintf (gcov_file
, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name
);
1486 fprintf (gcov_file
, "%9s:%5d:Data:%s\n", "-", 0, da_file_name
);
1488 source_file
= fopen (src
->name
, "r");
1491 fnotice (stderr
, "%s:cannot open source file\n", src
->name
);
1498 if (!fstat (fileno (source_file
), &status
)
1499 && status
.st_mtime
> bbg_file_time
)
1501 fnotice (stderr
, "%s:source file is newer than graph file `%s'\n",
1502 src
->name
, bbg_file_name
);
1503 fprintf (gcov_file
, "%9s:%5d:Source is newer than graph\n",
1508 for (line_num
= 1, line
= &src
->lines
[line_num
];
1509 line_num
< src
->num_lines
; line_num
++, line
++)
1511 /* For lines which don't exist in the .bb file, print '-' before
1512 the source line. For lines which exist but were never
1513 executed, print '#####' before the source line. Otherwise,
1514 print the execution count before the source line. There are
1515 16 spaces of indentation added before the source line so that
1516 tabs won't be messed up. */
1517 fprintf (gcov_file
, "%9s:%5u:",
1518 !line
->exists
? "-" : !line
->count
? "#####"
1519 : format_gcov (line
->count
, 0, -1), line_num
);
1523 /* Copy source line. */
1526 retval
= fgets (string
, STRING_SIZE
, source_file
);
1529 fnotice (stderr
, "%s:unexpected EOF\n", src
->name
);
1532 fputs (retval
, gcov_file
);
1534 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n');
1537 fputs ("??\n", gcov_file
);
1544 for (ix
= 0, arc
= line
->branches
; arc
; arc
= arc
->line_next
, ix
++)
1548 if (arc
->src
->count
)
1550 (gcov_file
, "call %2d returns %s\n", ix
,
1551 format_gcov (arc
->src
->count
- arc
->count
,
1555 fnotice (gcov_file
, "call %2d never executed\n", ix
);
1559 if (arc
->src
->count
)
1561 (gcov_file
, "branch %2d taken %s\n", ix
,
1562 format_gcov (arc
->count
, arc
->src
->count
,
1565 fnotice (gcov_file
, "branch %2d never executed\n", ix
);
1571 /* Handle all remaining source lines. There may be lines after the
1572 last line of code. */
1575 for (; (retval
= fgets (string
, STRING_SIZE
, source_file
)); line_num
++)
1577 fprintf (gcov_file
, "%9s:%5u:%s", "-", line_num
, retval
);
1579 while (!retval
[0] || retval
[strlen (retval
) - 1] != '\n')
1581 retval
= fgets (string
, STRING_SIZE
, source_file
);
1584 fputs (retval
, gcov_file
);
1590 fclose (source_file
);