1 /* Gcov.c: prepend line execution counts and branch probabilities to a
3 Copyright (C) 1990-2018 Free Software Foundation, Inc.
4 Contributed by James E. Wilson of Cygnus Support.
5 Mangled by Bob Manson of Cygnus Support.
6 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
8 Gcov is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 Gcov is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Gcov; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 /* ??? Print a list of the ten blocks with the highest execution counts,
23 and list the line numbers corresponding to those blocks. Also, perhaps
24 list the line numbers with the highest execution counts, only printing
25 the first if there are several which are all listed in the same block. */
27 /* ??? Should have an option to print the number of basic blocks, and the
28 percent of them that are covered. */
30 /* Need an option to show individual block counts, and show
31 probabilities of fall through arcs. */
34 #define INCLUDE_ALGORITHM
35 #define INCLUDE_VECTOR
36 #define INCLUDE_STRING
40 #include "coretypes.h"
43 #include "diagnostic.h"
46 #include "color-macros.h"
58 /* The gcno file is generated by -ftest-coverage option. The gcda file is
59 generated by a program compiled with -fprofile-arcs. Their formats
60 are documented in gcov-io.h. */
62 /* The functions in this file for creating and solution program flow graphs
63 are very similar to functions in the gcc source file profile.c. In
64 some places we make use of the knowledge of how profile.c works to
65 select particular algorithms here. */
67 /* The code validates that the profile information read in corresponds
68 to the code currently being compiled. Rather than checking for
69 identical files, the code below compares a checksum on the CFG
70 (based on the order of basic blocks and the arcs in the CFG). If
71 the CFG checksum in the gcda file match the CFG checksum in the
72 gcno file, the profile data will be used. */
74 /* This is the size of the buffer used to read in source file lines. */
80 /* Describes an arc between two basic blocks. */
84 /* source and destination blocks. */
85 struct block_info
*src
;
86 struct block_info
*dst
;
88 /* transition counts. */
90 /* used in cycle search, so that we do not clobber original counts. */
93 unsigned int count_valid
: 1;
94 unsigned int on_tree
: 1;
95 unsigned int fake
: 1;
96 unsigned int fall_through
: 1;
98 /* Arc to a catch handler. */
99 unsigned int is_throw
: 1;
101 /* Arc is for a function that abnormally returns. */
102 unsigned int is_call_non_return
: 1;
104 /* Arc is for catch/setjmp. */
105 unsigned int is_nonlocal_return
: 1;
107 /* Is an unconditional branch. */
108 unsigned int is_unconditional
: 1;
110 /* Loop making arc. */
111 unsigned int cycle
: 1;
113 /* Links to next arc on src and dst lists. */
114 struct arc_info
*succ_next
;
115 struct arc_info
*pred_next
;
118 /* Describes which locations (lines and files) are associated with
121 struct block_location_info
123 block_location_info (unsigned _source_file_idx
):
124 source_file_idx (_source_file_idx
)
127 unsigned source_file_idx
;
128 vector
<unsigned> lines
;
131 /* Describes a basic block. Contains lists of arcs to successor and
132 predecessor blocks. */
139 /* Chain of exit and entry arcs. */
143 /* Number of unprocessed exit and entry arcs. */
149 /* Block execution count. */
151 unsigned count_valid
: 1;
152 unsigned valid_chain
: 1;
153 unsigned invalid_chain
: 1;
154 unsigned exceptional
: 1;
156 /* Block is a call instrumenting site. */
157 unsigned is_call_site
: 1; /* Does the call. */
158 unsigned is_call_return
: 1; /* Is the return. */
160 /* Block is a landing pad for longjmp or throw. */
161 unsigned is_nonlocal_return
: 1;
163 vector
<block_location_info
> locations
;
167 /* Single line graph cycle workspace. Used for all-blocks
171 } cycle
; /* Used in all-blocks mode, after blocks are linked onto
174 /* Temporary chain for solving graph, and for chaining blocks on one
176 struct block_info
*chain
;
180 block_info::block_info (): succ (NULL
), pred (NULL
), num_succ (0), num_pred (0),
181 id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
182 exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
183 locations (), chain (NULL
)
188 /* Describes a single line of source. Contains a chain of basic blocks
193 /* Default constructor. */
196 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
197 bool has_block (block_info
*needle
);
199 /* Execution count. */
202 /* Branches from blocks that end on this line. */
203 vector
<arc_info
*> branches
;
205 /* blocks which start on this line. Used in all-blocks mode. */
206 vector
<block_info
*> blocks
;
209 unsigned unexceptional
: 1;
210 unsigned has_unexecuted_block
: 1;
213 line_info::line_info (): count (0), branches (), blocks (), exists (false),
214 unexceptional (0), has_unexecuted_block (0)
219 line_info::has_block (block_info
*needle
)
221 return std::find (blocks
.begin (), blocks
.end (), needle
) != blocks
.end ();
224 /* Describes a single function. Contains an array of basic blocks. */
231 /* Return true when line N belongs to the function in source file SRC_IDX.
232 The line must be defined in body of the function, can't be inlined. */
233 bool group_line_p (unsigned n
, unsigned src_idx
);
235 /* Function filter based on function_info::artificial variable. */
238 is_artificial (function_info
*fn
)
240 return fn
->artificial
;
243 /* Name of function. */
245 char *demangled_name
;
247 unsigned lineno_checksum
;
248 unsigned cfg_checksum
;
250 /* The graph contains at least one fake incoming edge. */
251 unsigned has_catch
: 1;
253 /* True when the function is artificial and does not exist
255 unsigned artificial
: 1;
257 /* True when multiple functions start at a line in a source file. */
258 unsigned is_group
: 1;
260 /* Array of basic blocks. Like in GCC, the entry block is
261 at blocks[0] and the exit block is at blocks[1]. */
262 #define ENTRY_BLOCK (0)
263 #define EXIT_BLOCK (1)
264 vector
<block_info
> blocks
;
265 unsigned blocks_executed
;
267 /* Raw arc coverage counts. */
268 vector
<gcov_type
> counts
;
270 /* First line number. */
273 /* First line column. */
274 unsigned start_column
;
276 /* Last line number. */
279 /* Index of source file where the function is defined. */
282 /* Vector of line information. */
283 vector
<line_info
> lines
;
286 struct function_info
*next
;
289 /* Function info comparer that will sort functions according to starting
292 struct function_line_start_cmp
294 inline bool operator() (const function_info
*lhs
,
295 const function_info
*rhs
)
297 return (lhs
->start_line
== rhs
->start_line
298 ? lhs
->start_column
< rhs
->start_column
299 : lhs
->start_line
< rhs
->start_line
);
303 /* Describes coverage of a file or function. */
311 int branches_executed
;
320 /* Describes a file mentioned in the block graph. Contains an array
325 /* Default constructor. */
328 vector
<function_info
*> get_functions_at_location (unsigned line_num
) const;
330 /* Index of the source_info in sources vector. */
333 /* Canonical name of source file. */
337 /* Vector of line information. */
338 vector
<line_info
> lines
;
340 coverage_info coverage
;
342 /* Functions in this source file. These are in ascending line
344 vector
<function_info
*> functions
;
347 source_info::source_info (): index (0), name (NULL
), file_time (),
348 lines (), coverage (), functions ()
352 vector
<function_info
*>
353 source_info::get_functions_at_location (unsigned line_num
) const
355 vector
<function_info
*> r
;
357 for (vector
<function_info
*>::const_iterator it
= functions
.begin ();
358 it
!= functions
.end (); it
++)
360 if ((*it
)->start_line
== line_num
&& (*it
)->src
== index
)
364 std::sort (r
.begin (), r
.end (), function_line_start_cmp ());
376 name_map (char *_name
, unsigned _src
): name (_name
), src (_src
)
380 bool operator== (const name_map
&rhs
) const
382 #if HAVE_DOS_BASED_FILE_SYSTEM
383 return strcasecmp (this->name
, rhs
.name
) == 0;
385 return strcmp (this->name
, rhs
.name
) == 0;
389 bool operator< (const name_map
&rhs
) const
391 #if HAVE_DOS_BASED_FILE_SYSTEM
392 return strcasecmp (this->name
, rhs
.name
) < 0;
394 return strcmp (this->name
, rhs
.name
) < 0;
398 const char *name
; /* Source file name */
399 unsigned src
; /* Source file */
402 /* Vector of all functions. */
403 static vector
<function_info
*> functions
;
405 /* Vector of source files. */
406 static vector
<source_info
> sources
;
408 /* Mapping of file names to sources */
409 static vector
<name_map
> names
;
411 /* This holds data summary information. */
413 static unsigned object_runs
;
414 static unsigned program_count
;
416 static unsigned total_lines
;
417 static unsigned total_executed
;
419 /* Modification time of graph file. */
421 static time_t bbg_file_time
;
423 /* Name of the notes (gcno) output file. The "bbg" prefix is for
424 historical reasons, when the notes file contained only the
425 basic block graph notes. */
427 static char *bbg_file_name
;
429 /* Stamp of the bbg file */
430 static unsigned bbg_stamp
;
432 /* Supports has_unexecuted_blocks functionality. */
433 static unsigned bbg_supports_has_unexecuted_blocks
;
435 /* Name and file pointer of the input file for the count data (gcda). */
437 static char *da_file_name
;
439 /* Data file is missing. */
441 static int no_data_file
;
443 /* If there is several input files, compute and display results after
444 reading all data files. This way if two or more gcda file refer to
445 the same source file (eg inline subprograms in a .h file), the
448 static int multiple_files
= 0;
450 /* Output branch probabilities. */
452 static int flag_branches
= 0;
454 /* Show unconditional branches too. */
455 static int flag_unconditional
= 0;
457 /* Output a gcov file if this is true. This is on by default, and can
458 be turned off by the -n option. */
460 static int flag_gcov_file
= 1;
462 /* Output progress indication if this is true. This is off by default
463 and can be turned on by the -d option. */
465 static int flag_display_progress
= 0;
467 /* Output *.gcov file in intermediate format used by 'lcov'. */
469 static int flag_intermediate_format
= 0;
471 /* Output demangled function names. */
473 static int flag_demangled_names
= 0;
475 /* For included files, make the gcov output file name include the name
476 of the input source file. For example, if x.h is included in a.c,
477 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
479 static int flag_long_names
= 0;
481 /* For situations when a long name can potentially hit filesystem path limit,
482 let's calculate md5sum of the path and append it to a file name. */
484 static int flag_hash_filenames
= 0;
486 /* Print verbose informations. */
488 static int flag_verbose
= 0;
490 /* Print colored output. */
492 static int flag_use_colors
= 0;
494 /* Output count information for every basic block, not merely those
495 that contain line number information. */
497 static int flag_all_blocks
= 0;
499 /* Output human readable numbers. */
501 static int flag_human_readable_numbers
= 0;
503 /* Output summary info for each function. */
505 static int flag_function_summary
= 0;
507 /* Object directory file prefix. This is the directory/file where the
508 graph and data files are looked for, if nonzero. */
510 static char *object_directory
= 0;
512 /* Source directory prefix. This is removed from source pathnames
513 that match, when generating the output file name. */
515 static char *source_prefix
= 0;
516 static size_t source_length
= 0;
518 /* Only show data for sources with relative pathnames. Absolute ones
519 usually indicate a system header file, which although it may
520 contain inline functions, is usually uninteresting. */
521 static int flag_relative_only
= 0;
523 /* Preserve all pathname components. Needed when object files and
524 source files are in subdirectories. '/' is mangled as '#', '.' is
525 elided and '..' mangled to '^'. */
527 static int flag_preserve_paths
= 0;
529 /* Output the number of times a branch was taken as opposed to the percentage
530 of times it was taken. */
532 static int flag_counts
= 0;
534 /* Forward declarations. */
535 static int process_args (int, char **);
536 static void print_usage (int) ATTRIBUTE_NORETURN
;
537 static void print_version (void) ATTRIBUTE_NORETURN
;
538 static void process_file (const char *);
539 static void generate_results (const char *);
540 static void create_file_names (const char *);
541 static char *canonicalize_name (const char *);
542 static unsigned find_source (const char *);
543 static void read_graph_file (void);
544 static int read_count_file (void);
545 static void solve_flow_graph (function_info
*);
546 static void find_exception_blocks (function_info
*);
547 static void add_branch_counts (coverage_info
*, const arc_info
*);
548 static void add_line_counts (coverage_info
*, function_info
*);
549 static void executed_summary (unsigned, unsigned);
550 static void function_summary (const coverage_info
*, const char *);
551 static const char *format_gcov (gcov_type
, gcov_type
, int);
552 static void accumulate_line_counts (source_info
*);
553 static void output_gcov_file (const char *, source_info
*);
554 static int output_branch_count (FILE *, int, const arc_info
*);
555 static void output_lines (FILE *, const source_info
*);
556 static char *make_gcov_file_name (const char *, const char *);
557 static char *mangle_name (const char *, char *);
558 static void release_structures (void);
559 extern int main (int, char **);
561 function_info::function_info (): name (NULL
), demangled_name (NULL
),
562 ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
563 artificial (0), is_group (0),
564 blocks (), blocks_executed (0), counts (),
565 start_line (0), start_column (), end_line (0), src (0), lines (), next (NULL
)
569 function_info::~function_info ()
571 for (int i
= blocks
.size () - 1; i
>= 0; i
--)
573 arc_info
*arc
, *arc_n
;
575 for (arc
= blocks
[i
].succ
; arc
; arc
= arc_n
)
577 arc_n
= arc
->succ_next
;
581 if (flag_demangled_names
&& demangled_name
!= name
)
582 free (demangled_name
);
586 bool function_info::group_line_p (unsigned n
, unsigned src_idx
)
588 return is_group
&& src
== src_idx
&& start_line
<= n
&& n
<= end_line
;
592 There are a bajillion algorithms that do this. Boost's function is named
593 hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
594 "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
595 (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
597 The basic algorithm is simple: effectively, we're finding all simple paths
598 in a subgraph (that shrinks every iteration). Duplicates are filtered by
599 "blocking" a path when a node is added to the path (this also prevents non-
600 simple paths)--the node is unblocked only when it participates in a cycle.
603 typedef vector
<arc_info
*> arc_vector_t
;
604 typedef vector
<const block_info
*> block_vector_t
;
606 /* Enum with types of loop in CFG. */
615 /* Loop_type operator that merges two values: A and B. */
617 inline loop_type
& operator |= (loop_type
& a
, loop_type b
)
619 return a
= static_cast<loop_type
> (a
| b
);
622 /* Handle cycle identified by EDGES, where the function finds minimum cs_count
623 and subtract the value from all counts. The subtracted value is added
624 to COUNT. Returns type of loop. */
627 handle_cycle (const arc_vector_t
&edges
, int64_t &count
)
629 /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
631 int64_t cycle_count
= INTTYPE_MAXIMUM (int64_t);
632 for (unsigned i
= 0; i
< edges
.size (); i
++)
634 int64_t ecount
= edges
[i
]->cs_count
;
635 if (cycle_count
> ecount
)
636 cycle_count
= ecount
;
638 count
+= cycle_count
;
639 for (unsigned i
= 0; i
< edges
.size (); i
++)
640 edges
[i
]->cs_count
-= cycle_count
;
642 return cycle_count
< 0 ? NEGATIVE_LOOP
: LOOP
;
645 /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
646 blocked by U in BLOCK_LISTS. */
649 unblock (const block_info
*u
, block_vector_t
&blocked
,
650 vector
<block_vector_t
> &block_lists
)
652 block_vector_t::iterator it
= find (blocked
.begin (), blocked
.end (), u
);
653 if (it
== blocked
.end ())
656 unsigned index
= it
- blocked
.begin ();
659 block_vector_t
to_unblock (block_lists
[index
]);
661 block_lists
.erase (block_lists
.begin () + index
);
663 for (block_vector_t::iterator it
= to_unblock
.begin ();
664 it
!= to_unblock
.end (); it
++)
665 unblock (*it
, blocked
, block_lists
);
668 /* Find circuit going to block V, PATH is provisional seen cycle.
669 BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
670 blocked by a block. COUNT is accumulated count of the current LINE.
671 Returns what type of loop it contains. */
674 circuit (block_info
*v
, arc_vector_t
&path
, block_info
*start
,
675 block_vector_t
&blocked
, vector
<block_vector_t
> &block_lists
,
676 line_info
&linfo
, int64_t &count
)
678 loop_type result
= NO_LOOP
;
680 /* Add v to the block list. */
681 gcc_assert (find (blocked
.begin (), blocked
.end (), v
) == blocked
.end ());
682 blocked
.push_back (v
);
683 block_lists
.push_back (block_vector_t ());
685 for (arc_info
*arc
= v
->succ
; arc
; arc
= arc
->succ_next
)
687 block_info
*w
= arc
->dst
;
688 if (w
< start
|| !linfo
.has_block (w
))
691 path
.push_back (arc
);
693 /* Cycle has been found. */
694 result
|= handle_cycle (path
, count
);
695 else if (find (blocked
.begin (), blocked
.end (), w
) == blocked
.end ())
696 result
|= circuit (w
, path
, start
, blocked
, block_lists
, linfo
, count
);
701 if (result
!= NO_LOOP
)
702 unblock (v
, blocked
, block_lists
);
704 for (arc_info
*arc
= v
->succ
; arc
; arc
= arc
->succ_next
)
706 block_info
*w
= arc
->dst
;
707 if (w
< start
|| !linfo
.has_block (w
))
711 = find (blocked
.begin (), blocked
.end (), w
) - blocked
.begin ();
712 gcc_assert (index
< blocked
.size ());
713 block_vector_t
&list
= block_lists
[index
];
714 if (find (list
.begin (), list
.end (), v
) == list
.end ())
721 /* Find cycles for a LINFO. If HANDLE_NEGATIVE_CYCLES is set and the line
722 contains a negative loop, then perform the same function once again. */
725 get_cycles_count (line_info
&linfo
, bool handle_negative_cycles
= true)
727 /* Note that this algorithm works even if blocks aren't in sorted order.
728 Each iteration of the circuit detection is completely independent
729 (except for reducing counts, but that shouldn't matter anyways).
730 Therefore, operating on a permuted order (i.e., non-sorted) only
731 has the effect of permuting the output cycles. */
733 loop_type result
= NO_LOOP
;
735 for (vector
<block_info
*>::iterator it
= linfo
.blocks
.begin ();
736 it
!= linfo
.blocks
.end (); it
++)
739 block_vector_t blocked
;
740 vector
<block_vector_t
> block_lists
;
741 result
|= circuit (*it
, path
, *it
, blocked
, block_lists
, linfo
,
745 /* If we have a negative cycle, repeat the find_cycles routine. */
746 if (result
== NEGATIVE_LOOP
&& handle_negative_cycles
)
747 count
+= get_cycles_count (linfo
, false);
753 main (int argc
, char **argv
)
759 p
= argv
[0] + strlen (argv
[0]);
760 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
764 xmalloc_set_program_name (progname
);
766 /* Unlock the stdio streams. */
767 unlock_std_streams ();
771 diagnostic_initialize (global_dc
, 0);
773 /* Handle response files. */
774 expandargv (&argc
, &argv
);
776 argno
= process_args (argc
, argv
);
780 if (argc
- argno
> 1)
785 for (; argno
!= argc
; argno
++)
787 if (flag_display_progress
)
788 printf ("Processing file %d out of %d\n", argno
- first_arg
+ 1,
790 process_file (argv
[argno
]);
792 if (flag_intermediate_format
|| argno
== argc
- 1)
794 generate_results (argv
[argno
]);
795 release_structures ();
802 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
803 otherwise the output of --help. */
806 print_usage (int error_p
)
808 FILE *file
= error_p
? stderr
: stdout
;
809 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
811 fnotice (file
, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
812 fnotice (file
, "Print code coverage information.\n\n");
813 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
814 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
815 fnotice (file
, " -c, --branch-counts Output counts of branches taken\n\
816 rather than percentages\n");
817 fnotice (file
, " -d, --display-progress Display progress information\n");
818 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
819 fnotice (file
, " -h, --help Print this help, then exit\n");
820 fnotice (file
, " -i, --intermediate-format Output .gcov file in intermediate text format\n");
821 fnotice (file
, " -j, --human-readable Output human readable numbers\n");
822 fnotice (file
, " -k, --use-colors Emit colored output\n");
823 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
825 fnotice (file
, " -m, --demangled-names Output demangled function names\n");
826 fnotice (file
, " -n, --no-output Do not create an output file\n");
827 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
828 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
829 fnotice (file
, " -r, --relative-only Only show data for relative sources\n");
830 fnotice (file
, " -s, --source-prefix DIR Source prefix to elide\n");
831 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
832 fnotice (file
, " -v, --version Print version number, then exit\n");
833 fnotice (file
, " -w, --verbose Print verbose informations\n");
834 fnotice (file
, " -x, --hash-filenames Hash long pathnames\n");
835 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
840 /* Print version information and exit. */
845 fnotice (stdout
, "gcov %s%s\n", pkgversion_string
, version_string
);
846 fprintf (stdout
, "Copyright %s 2018 Free Software Foundation, Inc.\n",
849 _("This is free software; see the source for copying conditions.\n"
850 "There is NO warranty; not even for MERCHANTABILITY or \n"
851 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
852 exit (SUCCESS_EXIT_CODE
);
855 static const struct option options
[] =
857 { "help", no_argument
, NULL
, 'h' },
858 { "version", no_argument
, NULL
, 'v' },
859 { "verbose", no_argument
, NULL
, 'w' },
860 { "all-blocks", no_argument
, NULL
, 'a' },
861 { "branch-probabilities", no_argument
, NULL
, 'b' },
862 { "branch-counts", no_argument
, NULL
, 'c' },
863 { "intermediate-format", no_argument
, NULL
, 'i' },
864 { "human-readable", no_argument
, NULL
, 'j' },
865 { "no-output", no_argument
, NULL
, 'n' },
866 { "long-file-names", no_argument
, NULL
, 'l' },
867 { "function-summaries", no_argument
, NULL
, 'f' },
868 { "demangled-names", no_argument
, NULL
, 'm' },
869 { "preserve-paths", no_argument
, NULL
, 'p' },
870 { "relative-only", no_argument
, NULL
, 'r' },
871 { "object-directory", required_argument
, NULL
, 'o' },
872 { "object-file", required_argument
, NULL
, 'o' },
873 { "source-prefix", required_argument
, NULL
, 's' },
874 { "unconditional-branches", no_argument
, NULL
, 'u' },
875 { "display-progress", no_argument
, NULL
, 'd' },
876 { "hash-filenames", no_argument
, NULL
, 'x' },
877 { "use-colors", no_argument
, NULL
, 'k' },
881 /* Process args, return index to first non-arg. */
884 process_args (int argc
, char **argv
)
888 const char *opts
= "abcdfhijklmno:prs:uvwx";
889 while ((opt
= getopt_long (argc
, argv
, opts
, options
, NULL
)) != -1)
903 flag_function_summary
= 1;
907 /* print_usage will exit. */
912 flag_human_readable_numbers
= 1;
918 flag_demangled_names
= 1;
924 object_directory
= optarg
;
927 source_prefix
= optarg
;
928 source_length
= strlen (source_prefix
);
931 flag_relative_only
= 1;
934 flag_preserve_paths
= 1;
937 flag_unconditional
= 1;
940 flag_intermediate_format
= 1;
944 flag_display_progress
= 1;
947 flag_hash_filenames
= 1;
954 /* print_version will exit. */
957 /* print_usage will exit. */
964 /* Output intermediate LINE sitting on LINE_NUM to output file F. */
967 output_intermediate_line (FILE *f
, line_info
*line
, unsigned line_num
)
972 fprintf (f
, "lcount:%u,%s,%d\n", line_num
,
973 format_gcov (line
->count
, 0, -1),
974 line
->has_unexecuted_block
);
976 vector
<arc_info
*>::const_iterator it
;
978 for (it
= line
->branches
.begin (); it
!= line
->branches
.end ();
981 if (!(*it
)->is_unconditional
&& !(*it
)->is_call_non_return
)
983 const char *branch_type
;
984 /* branch:<line_num>,<branch_coverage_infoype>
985 branch_coverage_infoype
986 : notexec (Branch not executed)
987 : taken (Branch executed and taken)
988 : nottaken (Branch executed, but not taken)
990 if ((*it
)->src
->count
)
992 = ((*it
)->count
> 0) ? "taken" : "nottaken";
994 branch_type
= "notexec";
995 fprintf (f
, "branch:%d,%s\n", line_num
, branch_type
);
1000 /* Get the name of the gcov file. The return value must be free'd.
1002 It appends the '.gcov' extension to the *basename* of the file.
1003 The resulting file name will be in PWD.
1006 input: foo.da, output: foo.da.gcov
1007 input: a/b/foo.cc, output: foo.cc.gcov */
1010 get_gcov_intermediate_filename (const char *file_name
)
1012 const char *gcov
= ".gcov";
1016 /* Find the 'basename'. */
1017 cptr
= lbasename (file_name
);
1019 result
= XNEWVEC (char, strlen (cptr
) + strlen (gcov
) + 1);
1020 sprintf (result
, "%s%s", cptr
, gcov
);
1025 /* Output the result in intermediate format used by 'lcov'.
1027 The intermediate format contains a single file named 'foo.cc.gcov',
1028 with no source code included.
1030 The default gcov outputs multiple files: 'foo.cc.gcov',
1031 'iostream.gcov', 'ios_base.h.gcov', etc. with source code
1032 included. Instead the intermediate format here outputs only a single
1033 file 'foo.cc.gcov' similar to the above example. */
1036 output_intermediate_file (FILE *gcov_file
, source_info
*src
)
1038 fprintf (gcov_file
, "version:%s\n", version_string
);
1039 fprintf (gcov_file
, "file:%s\n", src
->name
); /* source file name */
1041 std::sort (src
->functions
.begin (), src
->functions
.end (),
1042 function_line_start_cmp ());
1043 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
1044 it
!= src
->functions
.end (); it
++)
1046 /* function:<name>,<line_number>,<execution_count> */
1047 fprintf (gcov_file
, "function:%d,%d,%s,%s\n", (*it
)->start_line
,
1048 (*it
)->end_line
, format_gcov ((*it
)->blocks
[0].count
, 0, -1),
1049 flag_demangled_names
? (*it
)->demangled_name
: (*it
)->name
);
1052 for (unsigned line_num
= 1; line_num
<= src
->lines
.size (); line_num
++)
1054 vector
<function_info
*> fns
= src
->get_functions_at_location (line_num
);
1056 /* Print first group functions that begin on the line. */
1057 for (vector
<function_info
*>::iterator it2
= fns
.begin ();
1058 it2
!= fns
.end (); it2
++)
1060 vector
<line_info
> &lines
= (*it2
)->lines
;
1061 for (unsigned i
= 0; i
< lines
.size (); i
++)
1063 line_info
*line
= &lines
[i
];
1064 output_intermediate_line (gcov_file
, line
, line_num
+ i
);
1068 /* Follow with lines associated with the source file. */
1069 output_intermediate_line (gcov_file
, &src
->lines
[line_num
], line_num
);
1073 /* Function start pair. */
1074 struct function_start
1076 unsigned source_file_idx
;
1077 unsigned start_line
;
1080 /* Traits class for function start hash maps below. */
1082 struct function_start_pair_hash
: typed_noop_remove
<function_start
>
1084 typedef function_start value_type
;
1085 typedef function_start compare_type
;
1088 hash (const function_start
&ref
)
1090 inchash::hash
hstate (0);
1091 hstate
.add_int (ref
.source_file_idx
);
1092 hstate
.add_int (ref
.start_line
);
1093 return hstate
.end ();
1097 equal (const function_start
&ref1
, const function_start
&ref2
)
1099 return (ref1
.source_file_idx
== ref2
.source_file_idx
1100 && ref1
.start_line
== ref2
.start_line
);
1104 mark_deleted (function_start
&ref
)
1106 ref
.start_line
= ~1U;
1110 mark_empty (function_start
&ref
)
1112 ref
.start_line
= ~2U;
1116 is_deleted (const function_start
&ref
)
1118 return ref
.start_line
== ~1U;
1122 is_empty (const function_start
&ref
)
1124 return ref
.start_line
== ~2U;
1128 /* Process a single input file. */
1131 process_file (const char *file_name
)
1133 create_file_names (file_name
);
1135 if (functions
.empty ())
1140 hash_map
<function_start_pair_hash
, function_info
*> fn_map
;
1142 /* Identify group functions. */
1143 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1144 it
!= functions
.end (); it
++)
1145 if (!(*it
)->artificial
)
1147 function_start needle
;
1148 needle
.source_file_idx
= (*it
)->src
;
1149 needle
.start_line
= (*it
)->start_line
;
1151 function_info
**slot
= fn_map
.get (needle
);
1154 gcc_assert ((*slot
)->end_line
== (*it
)->end_line
);
1155 (*slot
)->is_group
= 1;
1156 (*it
)->is_group
= 1;
1159 fn_map
.put (needle
, *it
);
1162 /* Remove all artificial function. */
1163 functions
.erase (remove_if (functions
.begin (), functions
.end (),
1164 function_info::is_artificial
), functions
.end ());
1166 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1167 it
!= functions
.end (); it
++)
1169 function_info
*fn
= *it
;
1170 unsigned src
= fn
->src
;
1172 if (!fn
->counts
.empty () || no_data_file
)
1174 source_info
*s
= &sources
[src
];
1175 s
->functions
.push_back (fn
);
1177 /* Mark last line in files touched by function. */
1178 for (unsigned block_no
= 0; block_no
!= fn
->blocks
.size ();
1181 block_info
*block
= &fn
->blocks
[block_no
];
1182 for (unsigned i
= 0; i
< block
->locations
.size (); i
++)
1184 /* Sort lines of locations. */
1185 sort (block
->locations
[i
].lines
.begin (),
1186 block
->locations
[i
].lines
.end ());
1188 if (!block
->locations
[i
].lines
.empty ())
1190 s
= &sources
[block
->locations
[i
].source_file_idx
];
1192 = block
->locations
[i
].lines
.back ();
1194 /* Record new lines for the function. */
1195 if (last_line
>= s
->lines
.size ())
1197 s
= &sources
[block
->locations
[i
].source_file_idx
];
1199 = block
->locations
[i
].lines
.back ();
1201 /* Record new lines for the function. */
1202 if (last_line
>= s
->lines
.size ())
1204 /* Record new lines for a source file. */
1205 s
->lines
.resize (last_line
+ 1);
1212 /* Allocate lines for group function, following start_line
1213 and end_line information of the function. */
1215 fn
->lines
.resize (fn
->end_line
- fn
->start_line
+ 1);
1218 solve_flow_graph (fn
);
1220 find_exception_blocks (fn
);
1224 /* The function was not in the executable -- some other
1225 instance must have been selected. */
1231 output_gcov_file (const char *file_name
, source_info
*src
)
1233 char *gcov_file_name
= make_gcov_file_name (file_name
, src
->coverage
.name
);
1235 if (src
->coverage
.lines
)
1237 FILE *gcov_file
= fopen (gcov_file_name
, "w");
1240 fnotice (stdout
, "Creating '%s'\n", gcov_file_name
);
1241 output_lines (gcov_file
, src
);
1242 if (ferror (gcov_file
))
1243 fnotice (stderr
, "Error writing output file '%s'\n",
1248 fnotice (stderr
, "Could not open output file '%s'\n", gcov_file_name
);
1252 unlink (gcov_file_name
);
1253 fnotice (stdout
, "Removing '%s'\n", gcov_file_name
);
1255 free (gcov_file_name
);
1259 generate_results (const char *file_name
)
1261 FILE *gcov_intermediate_file
= NULL
;
1262 char *gcov_intermediate_filename
= NULL
;
1264 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1265 it
!= functions
.end (); it
++)
1267 function_info
*fn
= *it
;
1268 coverage_info coverage
;
1270 memset (&coverage
, 0, sizeof (coverage
));
1271 coverage
.name
= flag_demangled_names
? fn
->demangled_name
: fn
->name
;
1272 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
1273 if (flag_function_summary
)
1275 function_summary (&coverage
, "Function");
1276 fnotice (stdout
, "\n");
1284 needle
.name
= file_name
;
1285 vector
<name_map
>::iterator it
= std::find (names
.begin (), names
.end (),
1287 if (it
!= names
.end ())
1288 file_name
= sources
[it
->src
].coverage
.name
;
1290 file_name
= canonicalize_name (file_name
);
1293 if (flag_gcov_file
&& flag_intermediate_format
)
1295 /* Open the intermediate file. */
1296 gcov_intermediate_filename
= get_gcov_intermediate_filename (file_name
);
1297 gcov_intermediate_file
= fopen (gcov_intermediate_filename
, "w");
1298 if (!gcov_intermediate_file
)
1300 fnotice (stderr
, "Cannot open intermediate output file %s\n",
1301 gcov_intermediate_filename
);
1306 for (vector
<source_info
>::iterator it
= sources
.begin ();
1307 it
!= sources
.end (); it
++)
1309 source_info
*src
= &(*it
);
1310 if (flag_relative_only
)
1312 /* Ignore this source, if it is an absolute path (after
1313 source prefix removal). */
1314 char first
= src
->coverage
.name
[0];
1316 #if HAVE_DOS_BASED_FILE_SYSTEM
1317 if (first
&& src
->coverage
.name
[1] == ':')
1318 first
= src
->coverage
.name
[2];
1320 if (IS_DIR_SEPARATOR (first
))
1324 accumulate_line_counts (src
);
1325 function_summary (&src
->coverage
, "File");
1326 total_lines
+= src
->coverage
.lines
;
1327 total_executed
+= src
->coverage
.lines_executed
;
1330 if (flag_intermediate_format
)
1331 /* Output the intermediate format without requiring source
1332 files. This outputs a section to a *single* file. */
1333 output_intermediate_file (gcov_intermediate_file
, src
);
1335 output_gcov_file (file_name
, src
);
1336 fnotice (stdout
, "\n");
1340 if (flag_gcov_file
&& flag_intermediate_format
)
1342 /* Now we've finished writing the intermediate file. */
1343 fclose (gcov_intermediate_file
);
1344 XDELETEVEC (gcov_intermediate_filename
);
1348 executed_summary (total_lines
, total_executed
);
1351 /* Release all memory used. */
1354 release_structures (void)
1356 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1357 it
!= functions
.end (); it
++)
1362 functions
.resize (0);
1365 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
1366 is not specified, these are named from FILE_NAME sans extension. If
1367 OBJECT_DIRECTORY is specified and is a directory, the files are in that
1368 directory, but named from the basename of the FILE_NAME, sans extension.
1369 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
1370 and the data files are named from that. */
1373 create_file_names (const char *file_name
)
1377 int length
= strlen (file_name
);
1380 /* Free previous file names. */
1381 free (bbg_file_name
);
1382 free (da_file_name
);
1383 da_file_name
= bbg_file_name
= NULL
;
1387 if (object_directory
&& object_directory
[0])
1391 length
+= strlen (object_directory
) + 2;
1392 name
= XNEWVEC (char, length
);
1395 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
1396 strcat (name
, object_directory
);
1397 if (base
&& (!IS_DIR_SEPARATOR (name
[strlen (name
) - 1])))
1402 name
= XNEWVEC (char, length
+ 1);
1403 strcpy (name
, file_name
);
1409 /* Append source file name. */
1410 const char *cptr
= lbasename (file_name
);
1411 strcat (name
, cptr
? cptr
: file_name
);
1414 /* Remove the extension. */
1415 cptr
= strrchr (CONST_CAST (char *, lbasename (name
)), '.');
1419 length
= strlen (name
);
1421 bbg_file_name
= XNEWVEC (char, length
+ strlen (GCOV_NOTE_SUFFIX
) + 1);
1422 strcpy (bbg_file_name
, name
);
1423 strcpy (bbg_file_name
+ length
, GCOV_NOTE_SUFFIX
);
1425 da_file_name
= XNEWVEC (char, length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
1426 strcpy (da_file_name
, name
);
1427 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
1433 /* Find or create a source file structure for FILE_NAME. Copies
1434 FILE_NAME on creation */
1437 find_source (const char *file_name
)
1444 file_name
= "<unknown>";
1447 needle
.name
= file_name
;
1449 vector
<name_map
>::iterator it
= std::find (names
.begin (), names
.end (),
1451 if (it
!= names
.end ())
1457 /* Not found, try the canonical name. */
1458 canon
= canonicalize_name (file_name
);
1459 needle
.name
= canon
;
1460 it
= std::find (names
.begin (), names
.end (), needle
);
1461 if (it
== names
.end ())
1463 /* Not found with canonical name, create a new source. */
1466 idx
= sources
.size ();
1467 needle
= name_map (canon
, idx
);
1468 names
.push_back (needle
);
1470 sources
.push_back (source_info ());
1471 src
= &sources
.back ();
1473 src
->coverage
.name
= src
->name
;
1476 #if HAVE_DOS_BASED_FILE_SYSTEM
1477 /* You lose if separators don't match exactly in the
1479 && !strncasecmp (source_prefix
, src
->coverage
.name
, source_length
)
1481 && !strncmp (source_prefix
, src
->coverage
.name
, source_length
)
1483 && IS_DIR_SEPARATOR (src
->coverage
.name
[source_length
]))
1484 src
->coverage
.name
+= source_length
+ 1;
1485 if (!stat (src
->name
, &status
))
1486 src
->file_time
= status
.st_mtime
;
1491 needle
.name
= file_name
;
1492 if (std::find (names
.begin (), names
.end (), needle
) == names
.end ())
1494 /* Append the non-canonical name. */
1495 names
.push_back (name_map (xstrdup (file_name
), idx
));
1498 /* Resort the name map. */
1499 std::sort (names
.begin (), names
.end ());
1502 if (sources
[idx
].file_time
> bbg_file_time
)
1504 static int info_emitted
;
1506 fnotice (stderr
, "%s:source file is newer than notes file '%s'\n",
1507 file_name
, bbg_file_name
);
1511 "(the message is displayed only once per source file)\n");
1514 sources
[idx
].file_time
= 0;
1520 /* Read the notes file. Save functions to FUNCTIONS global vector. */
1523 read_graph_file (void)
1526 unsigned current_tag
= 0;
1529 if (!gcov_open (bbg_file_name
, 1))
1531 fnotice (stderr
, "%s:cannot open notes file\n", bbg_file_name
);
1534 bbg_file_time
= gcov_time ();
1535 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC
))
1537 fnotice (stderr
, "%s:not a gcov notes file\n", bbg_file_name
);
1542 version
= gcov_read_unsigned ();
1543 if (version
!= GCOV_VERSION
)
1547 GCOV_UNSIGNED2STRING (v
, version
);
1548 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1550 fnotice (stderr
, "%s:version '%.4s', prefer '%.4s'\n",
1551 bbg_file_name
, v
, e
);
1553 bbg_stamp
= gcov_read_unsigned ();
1554 bbg_supports_has_unexecuted_blocks
= gcov_read_unsigned ();
1556 function_info
*fn
= NULL
;
1557 while ((tag
= gcov_read_unsigned ()))
1559 unsigned length
= gcov_read_unsigned ();
1560 gcov_position_t base
= gcov_position ();
1562 if (tag
== GCOV_TAG_FUNCTION
)
1564 char *function_name
;
1566 unsigned lineno_checksum
, cfg_checksum
;
1568 ident
= gcov_read_unsigned ();
1569 lineno_checksum
= gcov_read_unsigned ();
1570 cfg_checksum
= gcov_read_unsigned ();
1571 function_name
= xstrdup (gcov_read_string ());
1572 unsigned artificial
= gcov_read_unsigned ();
1573 unsigned src_idx
= find_source (gcov_read_string ());
1574 unsigned start_line
= gcov_read_unsigned ();
1575 unsigned start_column
= gcov_read_unsigned ();
1576 unsigned end_line
= gcov_read_unsigned ();
1578 fn
= new function_info ();
1579 functions
.push_back (fn
);
1580 fn
->name
= function_name
;
1581 if (flag_demangled_names
)
1583 fn
->demangled_name
= cplus_demangle (fn
->name
, DMGL_PARAMS
);
1584 if (!fn
->demangled_name
)
1585 fn
->demangled_name
= fn
->name
;
1588 fn
->lineno_checksum
= lineno_checksum
;
1589 fn
->cfg_checksum
= cfg_checksum
;
1591 fn
->start_line
= start_line
;
1592 fn
->start_column
= start_column
;
1593 fn
->end_line
= end_line
;
1594 fn
->artificial
= artificial
;
1598 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
1600 if (!fn
->blocks
.empty ())
1601 fnotice (stderr
, "%s:already seen blocks for '%s'\n",
1602 bbg_file_name
, fn
->name
);
1604 fn
->blocks
.resize (gcov_read_unsigned ());
1606 else if (fn
&& tag
== GCOV_TAG_ARCS
)
1608 unsigned src
= gcov_read_unsigned ();
1609 fn
->blocks
[src
].id
= src
;
1610 unsigned num_dests
= GCOV_TAG_ARCS_NUM (length
);
1611 block_info
*src_blk
= &fn
->blocks
[src
];
1612 unsigned mark_catches
= 0;
1613 struct arc_info
*arc
;
1615 if (src
>= fn
->blocks
.size () || fn
->blocks
[src
].succ
)
1620 unsigned dest
= gcov_read_unsigned ();
1621 unsigned flags
= gcov_read_unsigned ();
1623 if (dest
>= fn
->blocks
.size ())
1625 arc
= XCNEW (arc_info
);
1627 arc
->dst
= &fn
->blocks
[dest
];
1631 arc
->count_valid
= 0;
1632 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
1633 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
1634 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
1636 arc
->succ_next
= src_blk
->succ
;
1637 src_blk
->succ
= arc
;
1638 src_blk
->num_succ
++;
1640 arc
->pred_next
= fn
->blocks
[dest
].pred
;
1641 fn
->blocks
[dest
].pred
= arc
;
1642 fn
->blocks
[dest
].num_pred
++;
1648 /* Exceptional exit from this function, the
1649 source block must be a call. */
1650 fn
->blocks
[src
].is_call_site
= 1;
1651 arc
->is_call_non_return
= 1;
1656 /* Non-local return from a callee of this
1657 function. The destination block is a setjmp. */
1658 arc
->is_nonlocal_return
= 1;
1659 fn
->blocks
[dest
].is_nonlocal_return
= 1;
1664 fn
->counts
.push_back (0);
1669 /* We have a fake exit from this block. The other
1670 non-fall through exits must be to catch handlers.
1671 Mark them as catch arcs. */
1673 for (arc
= src_blk
->succ
; arc
; arc
= arc
->succ_next
)
1674 if (!arc
->fake
&& !arc
->fall_through
)
1681 else if (fn
&& tag
== GCOV_TAG_LINES
)
1683 unsigned blockno
= gcov_read_unsigned ();
1684 block_info
*block
= &fn
->blocks
[blockno
];
1686 if (blockno
>= fn
->blocks
.size ())
1691 unsigned lineno
= gcov_read_unsigned ();
1694 block
->locations
.back ().lines
.push_back (lineno
);
1697 const char *file_name
= gcov_read_string ();
1701 block
->locations
.push_back (block_location_info
1702 (find_source (file_name
)));
1706 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
1711 gcov_sync (base
, length
);
1712 if (gcov_is_error ())
1715 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
1721 if (functions
.empty ())
1722 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
1725 /* Reads profiles from the count file and attach to each
1726 function. Return nonzero if fatal error. */
1729 read_count_file (void)
1734 function_info
*fn
= NULL
;
1737 if (!gcov_open (da_file_name
, 1))
1739 fnotice (stderr
, "%s:cannot open data file, assuming not executed\n",
1744 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
1746 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
1751 version
= gcov_read_unsigned ();
1752 if (version
!= GCOV_VERSION
)
1756 GCOV_UNSIGNED2STRING (v
, version
);
1757 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1759 fnotice (stderr
, "%s:version '%.4s', prefer version '%.4s'\n",
1760 da_file_name
, v
, e
);
1762 tag
= gcov_read_unsigned ();
1763 if (tag
!= bbg_stamp
)
1765 fnotice (stderr
, "%s:stamp mismatch with notes file\n", da_file_name
);
1769 while ((tag
= gcov_read_unsigned ()))
1771 unsigned length
= gcov_read_unsigned ();
1772 unsigned long base
= gcov_position ();
1774 if (tag
== GCOV_TAG_PROGRAM_SUMMARY
)
1776 struct gcov_summary summary
;
1777 gcov_read_summary (&summary
);
1778 object_runs
+= summary
.ctrs
[GCOV_COUNTER_ARCS
].runs
;
1781 else if (tag
== GCOV_TAG_FUNCTION
&& !length
)
1783 else if (tag
== GCOV_TAG_FUNCTION
&& length
== GCOV_TAG_FUNCTION_LENGTH
)
1787 /* Try to find the function in the list. To speed up the
1788 search, first start from the last function found. */
1789 ident
= gcov_read_unsigned ();
1792 for (vector
<function_info
*>::reverse_iterator it
1793 = functions
.rbegin (); it
!= functions
.rend (); it
++)
1795 if ((*it
)->ident
== ident
)
1804 else if (gcov_read_unsigned () != fn
->lineno_checksum
1805 || gcov_read_unsigned () != fn
->cfg_checksum
)
1808 fnotice (stderr
, "%s:profile mismatch for '%s'\n",
1809 da_file_name
, fn
->name
);
1813 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
1815 if (length
!= GCOV_TAG_COUNTER_LENGTH (fn
->counts
.size ()))
1818 for (ix
= 0; ix
!= fn
->counts
.size (); ix
++)
1819 fn
->counts
[ix
] += gcov_read_counter ();
1821 gcov_sync (base
, length
);
1822 if ((error
= gcov_is_error ()))
1826 ? N_("%s:overflowed\n")
1827 : N_("%s:corrupted\n"),
1837 /* Solve the flow graph. Propagate counts from the instrumented arcs
1838 to the blocks and the uninstrumented arcs. */
1841 solve_flow_graph (function_info
*fn
)
1845 gcov_type
*count_ptr
= &fn
->counts
.front ();
1847 block_info
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
1848 block_info
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
1850 /* The arcs were built in reverse order. Fix that now. */
1851 for (ix
= fn
->blocks
.size (); ix
--;)
1853 arc_info
*arc_p
, *arc_n
;
1855 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
1856 arc_p
= arc
, arc
= arc_n
)
1858 arc_n
= arc
->succ_next
;
1859 arc
->succ_next
= arc_p
;
1861 fn
->blocks
[ix
].succ
= arc_p
;
1863 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
1864 arc_p
= arc
, arc
= arc_n
)
1866 arc_n
= arc
->pred_next
;
1867 arc
->pred_next
= arc_p
;
1869 fn
->blocks
[ix
].pred
= arc_p
;
1872 if (fn
->blocks
.size () < 2)
1873 fnotice (stderr
, "%s:'%s' lacks entry and/or exit blocks\n",
1874 bbg_file_name
, fn
->name
);
1877 if (fn
->blocks
[ENTRY_BLOCK
].num_pred
)
1878 fnotice (stderr
, "%s:'%s' has arcs to entry block\n",
1879 bbg_file_name
, fn
->name
);
1881 /* We can't deduce the entry block counts from the lack of
1883 fn
->blocks
[ENTRY_BLOCK
].num_pred
= ~(unsigned)0;
1885 if (fn
->blocks
[EXIT_BLOCK
].num_succ
)
1886 fnotice (stderr
, "%s:'%s' has arcs from exit block\n",
1887 bbg_file_name
, fn
->name
);
1889 /* Likewise, we can't deduce exit block counts from the lack
1890 of its successors. */
1891 fn
->blocks
[EXIT_BLOCK
].num_succ
= ~(unsigned)0;
1894 /* Propagate the measured counts, this must be done in the same
1895 order as the code in profile.c */
1896 for (unsigned i
= 0; i
< fn
->blocks
.size (); i
++)
1898 blk
= &fn
->blocks
[i
];
1899 block_info
const *prev_dst
= NULL
;
1900 int out_of_order
= 0;
1901 int non_fake_succ
= 0;
1903 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1911 arc
->count
= *count_ptr
++;
1912 arc
->count_valid
= 1;
1914 arc
->dst
->num_pred
--;
1916 if (prev_dst
&& prev_dst
> arc
->dst
)
1918 prev_dst
= arc
->dst
;
1920 if (non_fake_succ
== 1)
1922 /* If there is only one non-fake exit, it is an
1923 unconditional branch. */
1924 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1927 arc
->is_unconditional
= 1;
1928 /* If this block is instrumenting a call, it might be
1929 an artificial block. It is not artificial if it has
1930 a non-fallthrough exit, or the destination of this
1931 arc has more than one entry. Mark the destination
1932 block as a return site, if none of those conditions
1934 if (blk
->is_call_site
&& arc
->fall_through
1935 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
1936 arc
->dst
->is_call_return
= 1;
1940 /* Sort the successor arcs into ascending dst order. profile.c
1941 normally produces arcs in the right order, but sometimes with
1942 one or two out of order. We're not using a particularly
1946 arc_info
*start
= blk
->succ
;
1947 unsigned changes
= 1;
1951 arc_info
*arc
, *arc_p
, *arc_n
;
1954 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
1956 if (arc
->dst
> arc_n
->dst
)
1960 arc_p
->succ_next
= arc_n
;
1963 arc
->succ_next
= arc_n
->succ_next
;
1964 arc_n
->succ_next
= arc
;
1977 /* Place it on the invalid chain, it will be ignored if that's
1979 blk
->invalid_chain
= 1;
1980 blk
->chain
= invalid_blocks
;
1981 invalid_blocks
= blk
;
1984 while (invalid_blocks
|| valid_blocks
)
1986 while ((blk
= invalid_blocks
))
1988 gcov_type total
= 0;
1989 const arc_info
*arc
;
1991 invalid_blocks
= blk
->chain
;
1992 blk
->invalid_chain
= 0;
1994 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1995 total
+= arc
->count
;
1996 else if (!blk
->num_pred
)
1997 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
1998 total
+= arc
->count
;
2003 blk
->count_valid
= 1;
2004 blk
->chain
= valid_blocks
;
2005 blk
->valid_chain
= 1;
2008 while ((blk
= valid_blocks
))
2011 arc_info
*arc
, *inv_arc
;
2013 valid_blocks
= blk
->chain
;
2014 blk
->valid_chain
= 0;
2015 if (blk
->num_succ
== 1)
2021 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2023 total
-= arc
->count
;
2024 if (!arc
->count_valid
)
2028 inv_arc
->count_valid
= 1;
2029 inv_arc
->count
= total
;
2032 if (dst
->count_valid
)
2034 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
2036 dst
->chain
= valid_blocks
;
2037 dst
->valid_chain
= 1;
2043 if (!dst
->num_pred
&& !dst
->invalid_chain
)
2045 dst
->chain
= invalid_blocks
;
2046 dst
->invalid_chain
= 1;
2047 invalid_blocks
= dst
;
2051 if (blk
->num_pred
== 1)
2057 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
2059 total
-= arc
->count
;
2060 if (!arc
->count_valid
)
2064 inv_arc
->count_valid
= 1;
2065 inv_arc
->count
= total
;
2068 if (src
->count_valid
)
2070 if (src
->num_succ
== 1 && !src
->valid_chain
)
2072 src
->chain
= valid_blocks
;
2073 src
->valid_chain
= 1;
2079 if (!src
->num_succ
&& !src
->invalid_chain
)
2081 src
->chain
= invalid_blocks
;
2082 src
->invalid_chain
= 1;
2083 invalid_blocks
= src
;
2090 /* If the graph has been correctly solved, every block will have a
2092 for (unsigned i
= 0; ix
< fn
->blocks
.size (); i
++)
2093 if (!fn
->blocks
[i
].count_valid
)
2095 fnotice (stderr
, "%s:graph is unsolvable for '%s'\n",
2096 bbg_file_name
, fn
->name
);
2101 /* Mark all the blocks only reachable via an incoming catch. */
2104 find_exception_blocks (function_info
*fn
)
2107 block_info
**queue
= XALLOCAVEC (block_info
*, fn
->blocks
.size ());
2109 /* First mark all blocks as exceptional. */
2110 for (ix
= fn
->blocks
.size (); ix
--;)
2111 fn
->blocks
[ix
].exceptional
= 1;
2113 /* Now mark all the blocks reachable via non-fake edges */
2114 queue
[0] = &fn
->blocks
[0];
2115 queue
[0]->exceptional
= 0;
2118 block_info
*block
= queue
[--ix
];
2119 const arc_info
*arc
;
2121 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2122 if (!arc
->fake
&& !arc
->is_throw
&& arc
->dst
->exceptional
)
2124 arc
->dst
->exceptional
= 0;
2125 queue
[ix
++] = arc
->dst
;
2131 /* Increment totals in COVERAGE according to arc ARC. */
2134 add_branch_counts (coverage_info
*coverage
, const arc_info
*arc
)
2136 if (arc
->is_call_non_return
)
2139 if (arc
->src
->count
)
2140 coverage
->calls_executed
++;
2142 else if (!arc
->is_unconditional
)
2144 coverage
->branches
++;
2145 if (arc
->src
->count
)
2146 coverage
->branches_executed
++;
2148 coverage
->branches_taken
++;
2152 /* Format COUNT, if flag_human_readable_numbers is set, return it human
2156 format_count (gcov_type count
)
2158 static char buffer
[64];
2159 const char *units
= " kMGTPEZY";
2161 if (count
< 1000 || !flag_human_readable_numbers
)
2163 sprintf (buffer
, "%" PRId64
, count
);
2168 gcov_type divisor
= 1;
2169 for (i
= 0; units
[i
+1]; i
++, divisor
*= 1000)
2171 if (count
+ divisor
/ 2 < 1000 * divisor
)
2174 gcov_type r
= (count
+ divisor
/ 2) / divisor
;
2175 sprintf (buffer
, "%" PRId64
"%c", r
, units
[i
]);
2179 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
2180 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
2181 If DP is zero, no decimal point is printed. Only print 100% when
2182 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
2183 format TOP. Return pointer to a static string. */
2186 format_gcov (gcov_type top
, gcov_type bottom
, int dp
)
2188 static char buffer
[20];
2190 /* Handle invalid values that would result in a misleading value. */
2191 if (bottom
!= 0 && top
> bottom
&& dp
>= 0)
2193 sprintf (buffer
, "NAN %%");
2199 float ratio
= bottom
? (float)top
/ bottom
: 0;
2201 unsigned limit
= 100;
2204 for (ix
= dp
; ix
--; )
2207 percent
= (unsigned) (ratio
* limit
+ (float)0.5);
2208 if (percent
<= 0 && top
)
2210 else if (percent
>= limit
&& top
!= bottom
)
2211 percent
= limit
- 1;
2212 ix
= sprintf (buffer
, "%.*u%%", dp
+ 1, percent
);
2218 buffer
[ix
+1] = buffer
[ix
];
2222 buffer
[ix
+ 1] = '.';
2226 return format_count (top
);
2231 /* Summary of execution */
2234 executed_summary (unsigned lines
, unsigned executed
)
2237 fnotice (stdout
, "Lines executed:%s of %d\n",
2238 format_gcov (executed
, lines
, 2), lines
);
2240 fnotice (stdout
, "No executable lines\n");
2243 /* Output summary info for a function or file. */
2246 function_summary (const coverage_info
*coverage
, const char *title
)
2248 fnotice (stdout
, "%s '%s'\n", title
, coverage
->name
);
2249 executed_summary (coverage
->lines
, coverage
->lines_executed
);
2253 if (coverage
->branches
)
2255 fnotice (stdout
, "Branches executed:%s of %d\n",
2256 format_gcov (coverage
->branches_executed
,
2257 coverage
->branches
, 2),
2258 coverage
->branches
);
2259 fnotice (stdout
, "Taken at least once:%s of %d\n",
2260 format_gcov (coverage
->branches_taken
,
2261 coverage
->branches
, 2),
2262 coverage
->branches
);
2265 fnotice (stdout
, "No branches\n");
2266 if (coverage
->calls
)
2267 fnotice (stdout
, "Calls executed:%s of %d\n",
2268 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
2271 fnotice (stdout
, "No calls\n");
2275 /* Canonicalize the filename NAME by canonicalizing directory
2276 separators, eliding . components and resolving .. components
2277 appropriately. Always returns a unique string. */
2280 canonicalize_name (const char *name
)
2282 /* The canonical name cannot be longer than the incoming name. */
2283 char *result
= XNEWVEC (char, strlen (name
) + 1);
2284 const char *base
= name
, *probe
;
2289 #if HAVE_DOS_BASED_FILE_SYSTEM
2290 if (base
[0] && base
[1] == ':')
2292 result
[0] = base
[0];
2298 for (dd_base
= ptr
; *base
; base
= probe
)
2302 for (probe
= base
; *probe
; probe
++)
2303 if (IS_DIR_SEPARATOR (*probe
))
2307 if (len
== 1 && base
[0] == '.')
2308 /* Elide a '.' directory */
2310 else if (len
== 2 && base
[0] == '.' && base
[1] == '.')
2312 /* '..', we can only elide it and the previous directory, if
2313 we're not a symlink. */
2314 struct stat ATTRIBUTE_UNUSED buf
;
2318 #if defined (S_ISLNK)
2319 /* S_ISLNK is not POSIX.1-1996. */
2320 || stat (result
, &buf
) || S_ISLNK (buf
.st_mode
)
2324 /* Cannot elide, or unreadable or a symlink. */
2325 dd_base
= ptr
+ 2 + slash
;
2328 while (ptr
!= dd_base
&& *ptr
!= '/')
2330 slash
= ptr
!= result
;
2335 /* Regular pathname component. */
2338 memcpy (ptr
, base
, len
);
2343 for (; IS_DIR_SEPARATOR (*probe
); probe
++)
2351 /* Print hex representation of 16 bytes from SUM and write it to BUFFER. */
2354 md5sum_to_hex (const char *sum
, char *buffer
)
2356 for (unsigned i
= 0; i
< 16; i
++)
2357 sprintf (buffer
+ (2 * i
), "%02x", (unsigned char)sum
[i
]);
2360 /* Generate an output file name. INPUT_NAME is the canonicalized main
2361 input file and SRC_NAME is the canonicalized file name.
2362 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
2363 long_output_names we prepend the processed name of the input file
2364 to each output name (except when the current source file is the
2365 input file, so you don't get a double concatenation). The two
2366 components are separated by '##'. With preserve_paths we create a
2367 filename from all path components of the source file, replacing '/'
2368 with '#', and .. with '^', without it we simply take the basename
2369 component. (Remember, the canonicalized name will already have
2370 elided '.' components and converted \\ separators.) */
2373 make_gcov_file_name (const char *input_name
, const char *src_name
)
2378 if (flag_long_names
&& input_name
&& strcmp (src_name
, input_name
))
2380 /* Generate the input filename part. */
2381 result
= XNEWVEC (char, strlen (input_name
) + strlen (src_name
) + 10);
2384 ptr
= mangle_name (input_name
, ptr
);
2385 ptr
[0] = ptr
[1] = '#';
2390 result
= XNEWVEC (char, strlen (src_name
) + 10);
2394 ptr
= mangle_name (src_name
, ptr
);
2395 strcpy (ptr
, ".gcov");
2397 /* When hashing filenames, we shorten them by only using the filename
2398 component and appending a hash of the full (mangled) pathname. */
2399 if (flag_hash_filenames
)
2403 char md5sum_hex
[33];
2405 md5_init_ctx (&ctx
);
2406 md5_process_bytes (src_name
, strlen (src_name
), &ctx
);
2407 md5_finish_ctx (&ctx
, md5sum
);
2408 md5sum_to_hex (md5sum
, md5sum_hex
);
2411 result
= XNEWVEC (char, strlen (src_name
) + 50);
2413 ptr
= mangle_name (src_name
, ptr
);
2414 ptr
[0] = ptr
[1] = '#';
2416 memcpy (ptr
, md5sum_hex
, 32);
2418 strcpy (ptr
, ".gcov");
2425 mangle_name (char const *base
, char *ptr
)
2429 /* Generate the source filename part. */
2430 if (!flag_preserve_paths
)
2432 base
= lbasename (base
);
2433 len
= strlen (base
);
2434 memcpy (ptr
, base
, len
);
2439 /* Convert '/' to '#', convert '..' to '^',
2440 convert ':' to '~' on DOS based file system. */
2443 #if HAVE_DOS_BASED_FILE_SYSTEM
2444 if (base
[0] && base
[1] == ':')
2452 for (; *base
; base
= probe
)
2456 for (probe
= base
; *probe
; probe
++)
2460 if (len
== 2 && base
[0] == '.' && base
[1] == '.')
2464 memcpy (ptr
, base
, len
);
2478 /* Scan through the bb_data for each line in the block, increment
2479 the line number execution count indicated by the execution count of
2480 the appropriate basic block. */
2483 add_line_counts (coverage_info
*coverage
, function_info
*fn
)
2485 bool has_any_line
= false;
2486 /* Scan each basic block. */
2487 for (unsigned ix
= 0; ix
!= fn
->blocks
.size (); ix
++)
2489 line_info
*line
= NULL
;
2490 block_info
*block
= &fn
->blocks
[ix
];
2491 if (block
->count
&& ix
&& ix
+ 1 != fn
->blocks
.size ())
2492 fn
->blocks_executed
++;
2493 for (unsigned i
= 0; i
< block
->locations
.size (); i
++)
2495 unsigned src_idx
= block
->locations
[i
].source_file_idx
;
2496 vector
<unsigned> &lines
= block
->locations
[i
].lines
;
2498 block
->cycle
.arc
= NULL
;
2499 block
->cycle
.ident
= ~0U;
2501 for (unsigned j
= 0; j
< lines
.size (); j
++)
2503 unsigned ln
= lines
[j
];
2505 /* Line belongs to a function that is in a group. */
2506 if (fn
->group_line_p (ln
, src_idx
))
2508 gcc_assert (lines
[j
] - fn
->start_line
< fn
->lines
.size ());
2509 line
= &(fn
->lines
[lines
[j
] - fn
->start_line
]);
2511 if (!block
->exceptional
)
2513 line
->unexceptional
= 1;
2514 if (block
->count
== 0)
2515 line
->has_unexecuted_block
= 1;
2517 line
->count
+= block
->count
;
2521 gcc_assert (ln
< sources
[src_idx
].lines
.size ());
2522 line
= &(sources
[src_idx
].lines
[ln
]);
2527 if (!line
->count
&& block
->count
)
2528 coverage
->lines_executed
++;
2531 if (!block
->exceptional
)
2533 line
->unexceptional
= 1;
2534 if (block
->count
== 0)
2535 line
->has_unexecuted_block
= 1;
2537 line
->count
+= block
->count
;
2541 has_any_line
= true;
2543 if (!ix
|| ix
+ 1 == fn
->blocks
.size ())
2544 /* Entry or exit block. */;
2545 else if (line
!= NULL
)
2547 line
->blocks
.push_back (block
);
2553 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2554 line
->branches
.push_back (arc
);
2561 fnotice (stderr
, "%s:no lines for '%s'\n", bbg_file_name
, fn
->name
);
2564 /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE
2565 is set to true, update source file summary. */
2567 static void accumulate_line_info (line_info
*line
, source_info
*src
,
2571 for (vector
<arc_info
*>::iterator it
= line
->branches
.begin ();
2572 it
!= line
->branches
.end (); it
++)
2573 add_branch_counts (&src
->coverage
, *it
);
2575 if (!line
->blocks
.empty ())
2577 /* The user expects the line count to be the number of times
2578 a line has been executed. Simply summing the block count
2579 will give an artificially high number. The Right Thing
2580 is to sum the entry counts to the graph of blocks on this
2581 line, then find the elementary cycles of the local graph
2582 and add the transition counts of those cycles. */
2583 gcov_type count
= 0;
2585 /* Cycle detection. */
2586 for (vector
<block_info
*>::iterator it
= line
->blocks
.begin ();
2587 it
!= line
->blocks
.end (); it
++)
2589 for (arc_info
*arc
= (*it
)->pred
; arc
; arc
= arc
->pred_next
)
2590 if (!line
->has_block (arc
->src
))
2591 count
+= arc
->count
;
2592 for (arc_info
*arc
= (*it
)->succ
; arc
; arc
= arc
->succ_next
)
2593 arc
->cs_count
= arc
->count
;
2596 /* Now, add the count of loops entirely on this line. */
2597 count
+= get_cycles_count (*line
);
2598 line
->count
= count
;
2601 if (line
->exists
&& add_coverage
)
2603 src
->coverage
.lines
++;
2605 src
->coverage
.lines_executed
++;
2609 /* Accumulate the line counts of a file. */
2612 accumulate_line_counts (source_info
*src
)
2614 /* First work on group functions. */
2615 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
2616 it
!= src
->functions
.end (); it
++)
2618 function_info
*fn
= *it
;
2620 if (fn
->src
!= src
->index
|| !fn
->is_group
)
2623 for (vector
<line_info
>::iterator it2
= fn
->lines
.begin ();
2624 it2
!= fn
->lines
.end (); it2
++)
2626 line_info
*line
= &(*it2
);
2627 accumulate_line_info (line
, src
, false);
2631 /* Work on global lines that line in source file SRC. */
2632 for (vector
<line_info
>::iterator it
= src
->lines
.begin ();
2633 it
!= src
->lines
.end (); it
++)
2634 accumulate_line_info (&(*it
), src
, true);
2636 /* If not using intermediate mode, sum lines of group functions and
2637 add them to lines that live in a source file. */
2638 if (!flag_intermediate_format
)
2639 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
2640 it
!= src
->functions
.end (); it
++)
2642 function_info
*fn
= *it
;
2644 if (fn
->src
!= src
->index
|| !fn
->is_group
)
2647 for (unsigned i
= 0; i
< fn
->lines
.size (); i
++)
2649 line_info
*fn_line
= &fn
->lines
[i
];
2650 if (fn_line
->exists
)
2652 unsigned ln
= fn
->start_line
+ i
;
2653 line_info
*src_line
= &src
->lines
[ln
];
2655 if (!src_line
->exists
)
2656 src
->coverage
.lines
++;
2657 if (!src_line
->count
&& fn_line
->count
)
2658 src
->coverage
.lines_executed
++;
2660 src_line
->count
+= fn_line
->count
;
2661 src_line
->exists
= 1;
2663 if (fn_line
->has_unexecuted_block
)
2664 src_line
->has_unexecuted_block
= 1;
2666 if (fn_line
->unexceptional
)
2667 src_line
->unexceptional
= 1;
2673 /* Output information about ARC number IX. Returns nonzero if
2674 anything is output. */
2677 output_branch_count (FILE *gcov_file
, int ix
, const arc_info
*arc
)
2679 if (arc
->is_call_non_return
)
2681 if (arc
->src
->count
)
2683 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
2684 format_gcov (arc
->src
->count
- arc
->count
,
2685 arc
->src
->count
, -flag_counts
));
2688 fnotice (gcov_file
, "call %2d never executed\n", ix
);
2690 else if (!arc
->is_unconditional
)
2692 if (arc
->src
->count
)
2693 fnotice (gcov_file
, "branch %2d taken %s%s", ix
,
2694 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
2695 arc
->fall_through
? " (fallthrough)"
2696 : arc
->is_throw
? " (throw)" : "");
2698 fnotice (gcov_file
, "branch %2d never executed", ix
);
2701 fnotice (gcov_file
, " (BB %d)", arc
->dst
->id
);
2703 fnotice (gcov_file
, "\n");
2705 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
2707 if (arc
->src
->count
)
2708 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
2709 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
2711 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
2719 read_line (FILE *file
)
2721 static char *string
;
2722 static size_t string_len
;
2729 string
= XNEWVEC (char, string_len
);
2732 while ((ptr
= fgets (string
+ pos
, string_len
- pos
, file
)))
2734 size_t len
= strlen (string
+ pos
);
2736 if (len
&& string
[pos
+ len
- 1] == '\n')
2738 string
[pos
+ len
- 1] = 0;
2742 /* If the file contains NUL characters or an incomplete
2743 last line, which can happen more than once in one run,
2744 we have to avoid doubling the STRING_LEN unnecessarily. */
2745 if (pos
> string_len
/ 2)
2748 string
= XRESIZEVEC (char, string
, string_len
);
2752 return pos
? string
: NULL
;
2755 /* Pad string S with spaces from left to have total width equal to 9. */
2758 pad_count_string (string
&s
)
2761 s
.insert (0, 9 - s
.size (), ' ');
2764 /* Print GCOV line beginning to F stream. If EXISTS is set to true, the
2765 line exists in source file. UNEXCEPTIONAL indicated that it's not in
2766 an exceptional statement. The output is printed for LINE_NUM of given
2767 COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
2768 used to indicate non-executed blocks. */
2771 output_line_beginning (FILE *f
, bool exists
, bool unexceptional
,
2772 bool has_unexecuted_block
,
2773 gcov_type count
, unsigned line_num
,
2774 const char *exceptional_string
,
2775 const char *unexceptional_string
)
2782 s
= format_gcov (count
, 0, -1);
2783 if (has_unexecuted_block
2784 && bbg_supports_has_unexecuted_blocks
)
2786 if (flag_use_colors
)
2788 pad_count_string (s
);
2789 s
.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
2790 COLOR_SEPARATOR COLOR_FG_WHITE
));
2796 pad_count_string (s
);
2800 if (flag_use_colors
)
2803 pad_count_string (s
);
2805 s
.insert (0, SGR_SEQ (COLOR_BG_RED
2806 COLOR_SEPARATOR COLOR_FG_WHITE
));
2808 s
.insert (0, SGR_SEQ (COLOR_BG_CYAN
2809 COLOR_SEPARATOR COLOR_FG_WHITE
));
2814 s
= unexceptional
? unexceptional_string
: exceptional_string
;
2815 pad_count_string (s
);
2822 pad_count_string (s
);
2825 fprintf (f
, "%s:%5u", s
.c_str (), line_num
);
2829 print_source_line (FILE *f
, const vector
<const char *> &source_lines
,
2832 gcc_assert (line
>= 1);
2833 gcc_assert (line
<= source_lines
.size ());
2835 fprintf (f
, ":%s\n", source_lines
[line
- 1]);
2838 /* Output line details for LINE and print it to F file. LINE lives on
2842 output_line_details (FILE *f
, const line_info
*line
, unsigned line_num
)
2844 if (flag_all_blocks
)
2850 for (vector
<block_info
*>::const_iterator it
= line
->blocks
.begin ();
2851 it
!= line
->blocks
.end (); it
++)
2853 if (!(*it
)->is_call_return
)
2855 output_line_beginning (f
, line
->exists
,
2856 (*it
)->exceptional
, false,
2857 (*it
)->count
, line_num
,
2859 fprintf (f
, "-block %2d", ix
++);
2861 fprintf (f
, " (BB %u)", (*it
)->id
);
2865 for (arc
= (*it
)->succ
; arc
; arc
= arc
->succ_next
)
2866 jx
+= output_branch_count (f
, jx
, arc
);
2869 else if (flag_branches
)
2874 for (vector
<arc_info
*>::const_iterator it
= line
->branches
.begin ();
2875 it
!= line
->branches
.end (); it
++)
2876 ix
+= output_branch_count (f
, ix
, (*it
));
2880 /* Output detail statistics about function FN to file F. */
2883 output_function_details (FILE *f
, const function_info
*fn
)
2888 arc_info
*arc
= fn
->blocks
[EXIT_BLOCK
].pred
;
2889 gcov_type return_count
= fn
->blocks
[EXIT_BLOCK
].count
;
2890 gcov_type called_count
= fn
->blocks
[ENTRY_BLOCK
].count
;
2892 for (; arc
; arc
= arc
->pred_next
)
2894 return_count
-= arc
->count
;
2896 fprintf (f
, "function %s",
2897 flag_demangled_names
? fn
->demangled_name
: fn
->name
);
2898 fprintf (f
, " called %s",
2899 format_gcov (called_count
, 0, -1));
2900 fprintf (f
, " returned %s",
2901 format_gcov (return_count
, called_count
, 0));
2902 fprintf (f
, " blocks executed %s",
2903 format_gcov (fn
->blocks_executed
, fn
->blocks
.size () - 2,
2908 /* Read in the source file one line at a time, and output that line to
2909 the gcov file preceded by its execution count and other
2913 output_lines (FILE *gcov_file
, const source_info
*src
)
2915 #define DEFAULT_LINE_START " -: 0:"
2916 #define FN_SEPARATOR "------------------\n"
2921 fprintf (gcov_file
, DEFAULT_LINE_START
"Source:%s\n", src
->coverage
.name
);
2922 if (!multiple_files
)
2924 fprintf (gcov_file
, DEFAULT_LINE_START
"Graph:%s\n", bbg_file_name
);
2925 fprintf (gcov_file
, DEFAULT_LINE_START
"Data:%s\n",
2926 no_data_file
? "-" : da_file_name
);
2927 fprintf (gcov_file
, DEFAULT_LINE_START
"Runs:%u\n", object_runs
);
2929 fprintf (gcov_file
, DEFAULT_LINE_START
"Programs:%u\n", program_count
);
2931 source_file
= fopen (src
->name
, "r");
2933 fnotice (stderr
, "Cannot open source file %s\n", src
->name
);
2934 else if (src
->file_time
== 0)
2935 fprintf (gcov_file
, DEFAULT_LINE_START
"Source is newer than graph\n");
2937 vector
<const char *> source_lines
;
2939 while ((retval
= read_line (source_file
)) != NULL
)
2940 source_lines
.push_back (xstrdup (retval
));
2942 unsigned line_start_group
= 0;
2943 vector
<function_info
*> fns
;
2945 for (unsigned line_num
= 1; line_num
<= source_lines
.size (); line_num
++)
2947 if (line_num
>= src
->lines
.size ())
2949 fprintf (gcov_file
, "%9s:%5u", "-", line_num
);
2950 print_source_line (gcov_file
, source_lines
, line_num
);
2954 const line_info
*line
= &src
->lines
[line_num
];
2956 if (line_start_group
== 0)
2958 fns
= src
->get_functions_at_location (line_num
);
2959 if (fns
.size () > 1)
2960 line_start_group
= fns
[0]->end_line
;
2961 else if (fns
.size () == 1)
2963 function_info
*fn
= fns
[0];
2964 output_function_details (gcov_file
, fn
);
2968 /* For lines which don't exist in the .bb file, print '-' before
2969 the source line. For lines which exist but were never
2970 executed, print '#####' or '=====' before the source line.
2971 Otherwise, print the execution count before the source line.
2972 There are 16 spaces of indentation added before the source
2973 line so that tabs won't be messed up. */
2974 output_line_beginning (gcov_file
, line
->exists
, line
->unexceptional
,
2975 line
->has_unexecuted_block
, line
->count
,
2976 line_num
, "=====", "#####");
2978 print_source_line (gcov_file
, source_lines
, line_num
);
2979 output_line_details (gcov_file
, line
, line_num
);
2981 if (line_start_group
== line_num
)
2983 for (vector
<function_info
*>::iterator it
= fns
.begin ();
2984 it
!= fns
.end (); it
++)
2986 function_info
*fn
= *it
;
2987 vector
<line_info
> &lines
= fn
->lines
;
2989 fprintf (gcov_file
, FN_SEPARATOR
);
2992 = flag_demangled_names
? fn
->demangled_name
: fn
->name
;
2994 if (flag_use_colors
)
2996 fn_name
.insert (0, SGR_SEQ (COLOR_FG_CYAN
));
2997 fn_name
+= SGR_RESET
;
3000 fprintf (gcov_file
, "%s:\n", fn_name
.c_str ());
3002 output_function_details (gcov_file
, fn
);
3004 /* Print all lines covered by the function. */
3005 for (unsigned i
= 0; i
< lines
.size (); i
++)
3007 line_info
*line
= &lines
[i
];
3008 unsigned l
= fn
->start_line
+ i
;
3010 /* For lines which don't exist in the .bb file, print '-'
3011 before the source line. For lines which exist but
3012 were never executed, print '#####' or '=====' before
3013 the source line. Otherwise, print the execution count
3014 before the source line.
3015 There are 16 spaces of indentation added before the source
3016 line so that tabs won't be messed up. */
3017 output_line_beginning (gcov_file
, line
->exists
,
3018 line
->unexceptional
,
3019 line
->has_unexecuted_block
,
3021 l
, "=====", "#####");
3023 print_source_line (gcov_file
, source_lines
, l
);
3024 output_line_details (gcov_file
, line
, l
);
3028 fprintf (gcov_file
, FN_SEPARATOR
);
3029 line_start_group
= 0;
3034 fclose (source_file
);