1 /* Gcov.c: prepend line execution counts and branch probabilities to a
3 Copyright (C) 1990-2024 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"
47 #include "pretty-print.h"
61 #define GCOV_JSON_FORMAT_VERSION "2"
63 /* The gcno file is generated by -ftest-coverage option. The gcda file is
64 generated by a program compiled with -fprofile-arcs. Their formats
65 are documented in gcov-io.h. */
67 /* The functions in this file for creating and solution program flow graphs
68 are very similar to functions in the gcc source file profile.cc. In
69 some places we make use of the knowledge of how profile.cc works to
70 select particular algorithms here. */
72 /* The code validates that the profile information read in corresponds
73 to the code currently being compiled. Rather than checking for
74 identical files, the code below compares a checksum on the CFG
75 (based on the order of basic blocks and the arcs in the CFG). If
76 the CFG checksum in the gcda file match the CFG checksum in the
77 gcno file, the profile data will be used. */
79 /* This is the size of the buffer used to read in source file lines. */
85 /* Describes an arc between two basic blocks. */
89 /* source and destination blocks. */
90 class block_info
*src
;
91 class block_info
*dst
;
93 /* transition counts. */
95 /* used in cycle search, so that we do not clobber original counts. */
98 unsigned int count_valid
: 1;
99 unsigned int on_tree
: 1;
100 unsigned int fake
: 1;
101 unsigned int fall_through
: 1;
103 /* Arc to a catch handler. */
104 unsigned int is_throw
: 1;
106 /* Arc is for a function that abnormally returns. */
107 unsigned int is_call_non_return
: 1;
109 /* Arc is for catch/setjmp. */
110 unsigned int is_nonlocal_return
: 1;
112 /* Is an unconditional branch. */
113 unsigned int is_unconditional
: 1;
115 /* Loop making arc. */
116 unsigned int cycle
: 1;
118 /* Links to next arc on src and dst lists. */
119 struct arc_info
*succ_next
;
120 struct arc_info
*pred_next
;
123 /* Describes which locations (lines and files) are associated with
126 class block_location_info
129 block_location_info (unsigned _source_file_idx
):
130 source_file_idx (_source_file_idx
)
133 unsigned source_file_idx
;
134 vector
<unsigned> lines
;
137 /* Describes a basic block. Contains lists of arcs to successor and
138 predecessor blocks. */
146 /* Chain of exit and entry arcs. */
150 /* Number of unprocessed exit and entry arcs. */
156 /* Block execution count. */
158 unsigned count_valid
: 1;
159 unsigned valid_chain
: 1;
160 unsigned invalid_chain
: 1;
161 unsigned exceptional
: 1;
163 /* Block is a call instrumenting site. */
164 unsigned is_call_site
: 1; /* Does the call. */
165 unsigned is_call_return
: 1; /* Is the return. */
167 /* Block is a landing pad for longjmp or throw. */
168 unsigned is_nonlocal_return
: 1;
170 vector
<block_location_info
> locations
;
174 /* Single line graph cycle workspace. Used for all-blocks
178 } cycle
; /* Used in all-blocks mode, after blocks are linked onto
181 /* Temporary chain for solving graph, and for chaining blocks on one
183 class block_info
*chain
;
187 block_info::block_info (): succ (NULL
), pred (NULL
), num_succ (0), num_pred (0),
188 id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
189 exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
190 locations (), chain (NULL
)
195 /* Describes a single line of source. Contains a chain of basic blocks
201 /* Default constructor. */
204 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
205 bool has_block (block_info
*needle
);
207 /* Execution count. */
210 /* Branches from blocks that end on this line. */
211 vector
<arc_info
*> branches
;
213 /* blocks which start on this line. Used in all-blocks mode. */
214 vector
<block_info
*> blocks
;
217 unsigned unexceptional
: 1;
218 unsigned has_unexecuted_block
: 1;
221 line_info::line_info (): count (0), branches (), blocks (), exists (false),
222 unexceptional (0), has_unexecuted_block (0)
227 line_info::has_block (block_info
*needle
)
229 return std::find (blocks
.begin (), blocks
.end (), needle
) != blocks
.end ();
232 /* Output demangled function names. */
234 static int flag_demangled_names
= 0;
236 /* Describes a single function. Contains an array of basic blocks. */
244 /* Return true when line N belongs to the function in source file SRC_IDX.
245 The line must be defined in body of the function, can't be inlined. */
246 bool group_line_p (unsigned n
, unsigned src_idx
);
248 /* Function filter based on function_info::artificial variable. */
251 is_artificial (function_info
*fn
)
253 return fn
->artificial
;
256 /* Name of function. */
258 char *m_demangled_name
;
260 unsigned lineno_checksum
;
261 unsigned cfg_checksum
;
263 /* The graph contains at least one fake incoming edge. */
264 unsigned has_catch
: 1;
266 /* True when the function is artificial and does not exist
268 unsigned artificial
: 1;
270 /* True when multiple functions start at a line in a source file. */
271 unsigned is_group
: 1;
273 /* Array of basic blocks. Like in GCC, the entry block is
274 at blocks[0] and the exit block is at blocks[1]. */
275 #define ENTRY_BLOCK (0)
276 #define EXIT_BLOCK (1)
277 vector
<block_info
> blocks
;
278 unsigned blocks_executed
;
280 /* Raw arc coverage counts. */
281 vector
<gcov_type
> counts
;
283 /* First line number. */
286 /* First line column. */
287 unsigned start_column
;
289 /* Last line number. */
292 /* Last line column. */
295 /* Index of source file where the function is defined. */
298 /* Vector of line information (used only for group functions). */
299 vector
<line_info
> lines
;
302 class function_info
*next
;
304 /* Get demangled name of a function. The demangled name
305 is converted when it is used for the first time. */
306 char *get_demangled_name ()
308 if (m_demangled_name
== NULL
)
310 m_demangled_name
= cplus_demangle (m_name
, DMGL_PARAMS
);
311 if (!m_demangled_name
)
312 m_demangled_name
= m_name
;
315 return m_demangled_name
;
318 /* Get name of the function based on flag_demangled_names. */
321 return flag_demangled_names
? get_demangled_name () : m_name
;
324 /* Return number of basic blocks (without entry and exit block). */
325 unsigned get_block_count ()
327 return blocks
.size () - 2;
331 /* Function info comparer that will sort functions according to starting
334 struct function_line_start_cmp
336 inline bool operator() (const function_info
*lhs
,
337 const function_info
*rhs
)
339 return (lhs
->start_line
== rhs
->start_line
340 ? lhs
->start_column
< rhs
->start_column
341 : lhs
->start_line
< rhs
->start_line
);
345 /* Describes coverage of a file or function. */
353 int branches_executed
;
362 /* Describes a file mentioned in the block graph. Contains an array
368 /* Default constructor. */
371 vector
<function_info
*> *get_functions_at_location (unsigned line_num
) const;
373 /* Register a new function. */
374 void add_function (function_info
*fn
);
376 /* Debug the source file. */
379 /* Index of the source_info in sources vector. */
382 /* Canonical name of source file. */
386 /* Vector of line information. */
387 vector
<line_info
> lines
;
389 coverage_info coverage
;
391 /* Maximum line count in the source file. */
392 unsigned int maximum_count
;
394 /* Functions in this source file. These are in ascending line
396 vector
<function_info
*> functions
;
398 /* Line number to functions map. */
399 vector
<vector
<function_info
*> *> line_to_function_map
;
402 source_info::source_info (): index (0), name (NULL
), file_time (),
403 lines (), coverage (), maximum_count (0), functions ()
407 /* Register a new function. */
409 source_info::add_function (function_info
*fn
)
411 functions
.push_back (fn
);
413 if (fn
->start_line
>= line_to_function_map
.size ())
414 line_to_function_map
.resize (fn
->start_line
+ 1);
416 vector
<function_info
*> **slot
= &line_to_function_map
[fn
->start_line
];
418 *slot
= new vector
<function_info
*> ();
420 (*slot
)->push_back (fn
);
423 vector
<function_info
*> *
424 source_info::get_functions_at_location (unsigned line_num
) const
426 if (line_num
>= line_to_function_map
.size ())
429 vector
<function_info
*> *slot
= line_to_function_map
[line_num
];
431 std::sort (slot
->begin (), slot
->end (), function_line_start_cmp ());
436 void source_info::debug ()
438 fprintf (stderr
, "source_info: %s\n", name
);
439 for (vector
<function_info
*>::iterator it
= functions
.begin ();
440 it
!= functions
.end (); it
++)
442 function_info
*fn
= *it
;
443 fprintf (stderr
, " function_info: %s\n", fn
->get_name ());
444 for (vector
<block_info
>::iterator bit
= fn
->blocks
.begin ();
445 bit
!= fn
->blocks
.end (); bit
++)
447 fprintf (stderr
, " block_info id=%d, count=%" PRId64
" \n",
448 bit
->id
, bit
->count
);
452 for (unsigned lineno
= 1; lineno
< lines
.size (); ++lineno
)
454 line_info
&line
= lines
[lineno
];
455 fprintf (stderr
, " line_info=%d, count=%" PRId64
"\n", lineno
, line
.count
);
458 fprintf (stderr
, "\n");
468 name_map (char *_name
, unsigned _src
): name (_name
), src (_src
)
472 bool operator== (const name_map
&rhs
) const
474 #if HAVE_DOS_BASED_FILE_SYSTEM
475 return strcasecmp (this->name
, rhs
.name
) == 0;
477 return strcmp (this->name
, rhs
.name
) == 0;
481 bool operator< (const name_map
&rhs
) const
483 #if HAVE_DOS_BASED_FILE_SYSTEM
484 return strcasecmp (this->name
, rhs
.name
) < 0;
486 return strcmp (this->name
, rhs
.name
) < 0;
490 const char *name
; /* Source file name */
491 unsigned src
; /* Source file */
494 /* Vector of all functions. */
495 static vector
<function_info
*> functions
;
497 /* Function ident to function_info * map. */
498 static map
<unsigned, function_info
*> ident_to_fn
;
500 /* Vector of source files. */
501 static vector
<source_info
> sources
;
503 /* Mapping of file names to sources */
504 static vector
<name_map
> names
;
506 /* Record all processed files in order to warn about
507 a file being read multiple times. */
508 static vector
<char *> processed_files
;
510 /* This holds data summary information. */
512 static unsigned object_runs
;
514 static unsigned total_lines
;
515 static unsigned total_executed
;
517 /* Modification time of graph file. */
519 static time_t bbg_file_time
;
521 /* Name of the notes (gcno) output file. The "bbg" prefix is for
522 historical reasons, when the notes file contained only the
523 basic block graph notes. */
525 static char *bbg_file_name
;
527 /* Stamp of the bbg file */
528 static unsigned bbg_stamp
;
530 /* Supports has_unexecuted_blocks functionality. */
531 static unsigned bbg_supports_has_unexecuted_blocks
;
533 /* Working directory in which a TU was compiled. */
534 static const char *bbg_cwd
;
536 /* Name and file pointer of the input file for the count data (gcda). */
538 static char *da_file_name
;
540 /* Data file is missing. */
542 static int no_data_file
;
544 /* If there is several input files, compute and display results after
545 reading all data files. This way if two or more gcda file refer to
546 the same source file (eg inline subprograms in a .h file), the
549 static int multiple_files
= 0;
551 /* Output branch probabilities. */
553 static int flag_branches
= 0;
555 /* Show unconditional branches too. */
556 static int flag_unconditional
= 0;
558 /* Output a gcov file if this is true. This is on by default, and can
559 be turned off by the -n option. */
561 static int flag_gcov_file
= 1;
563 /* Output to stdout instead to a gcov file. */
565 static int flag_use_stdout
= 0;
567 /* Output progress indication if this is true. This is off by default
568 and can be turned on by the -d option. */
570 static int flag_display_progress
= 0;
572 /* Output *.gcov file in JSON intermediate format used by consumers. */
574 static int flag_json_format
= 0;
576 /* For included files, make the gcov output file name include the name
577 of the input source file. For example, if x.h is included in a.c,
578 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
580 static int flag_long_names
= 0;
582 /* For situations when a long name can potentially hit filesystem path limit,
583 let's calculate md5sum of the path and append it to a file name. */
585 static int flag_hash_filenames
= 0;
587 /* Print verbose informations. */
589 static int flag_verbose
= 0;
591 /* Print colored output. */
593 static int flag_use_colors
= 0;
595 /* Use perf-like colors to indicate hot lines. */
597 static int flag_use_hotness_colors
= 0;
599 /* Output count information for every basic block, not merely those
600 that contain line number information. */
602 static int flag_all_blocks
= 0;
604 /* Output human readable numbers. */
606 static int flag_human_readable_numbers
= 0;
608 /* Output summary info for each function. */
610 static int flag_function_summary
= 0;
612 /* Print debugging dumps. */
614 static int flag_debug
= 0;
616 /* Object directory file prefix. This is the directory/file where the
617 graph and data files are looked for, if nonzero. */
619 static char *object_directory
= 0;
621 /* Source directory prefix. This is removed from source pathnames
622 that match, when generating the output file name. */
624 static char *source_prefix
= 0;
625 static size_t source_length
= 0;
627 /* Only show data for sources with relative pathnames. Absolute ones
628 usually indicate a system header file, which although it may
629 contain inline functions, is usually uninteresting. */
630 static int flag_relative_only
= 0;
632 /* Preserve all pathname components. Needed when object files and
633 source files are in subdirectories. '/' is mangled as '#', '.' is
634 elided and '..' mangled to '^'. */
636 static int flag_preserve_paths
= 0;
638 /* Output the number of times a branch was taken as opposed to the percentage
639 of times it was taken. */
641 static int flag_counts
= 0;
643 /* Return code of the tool invocation. */
644 static int return_code
= 0;
646 /* Forward declarations. */
647 static int process_args (int, char **);
648 static void print_usage (int) ATTRIBUTE_NORETURN
;
649 static void print_version (void) ATTRIBUTE_NORETURN
;
650 static void process_file (const char *);
651 static void process_all_functions (void);
652 static void generate_results (const char *);
653 static void create_file_names (const char *);
654 static char *canonicalize_name (const char *);
655 static unsigned find_source (const char *);
656 static void read_graph_file (void);
657 static int read_count_file (void);
658 static void solve_flow_graph (function_info
*);
659 static void find_exception_blocks (function_info
*);
660 static void add_branch_counts (coverage_info
*, const arc_info
*);
661 static void add_line_counts (coverage_info
*, function_info
*);
662 static void executed_summary (unsigned, unsigned);
663 static void function_summary (const coverage_info
*);
664 static void file_summary (const coverage_info
*);
665 static const char *format_gcov (gcov_type
, gcov_type
, int);
666 static void accumulate_line_counts (source_info
*);
667 static void output_gcov_file (const char *, source_info
*);
668 static int output_branch_count (FILE *, int, const arc_info
*);
669 static void output_lines (FILE *, const source_info
*);
670 static string
make_gcov_file_name (const char *, const char *);
671 static char *mangle_name (const char *);
672 static void release_structures (void);
673 extern int main (int, char **);
675 function_info::function_info (): m_name (NULL
), m_demangled_name (NULL
),
676 ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
677 artificial (0), is_group (0),
678 blocks (), blocks_executed (0), counts (),
679 start_line (0), start_column (0), end_line (0), end_column (0),
680 src (0), lines (), next (NULL
)
684 function_info::~function_info ()
686 for (int i
= blocks
.size () - 1; i
>= 0; i
--)
688 arc_info
*arc
, *arc_n
;
690 for (arc
= blocks
[i
].succ
; arc
; arc
= arc_n
)
692 arc_n
= arc
->succ_next
;
696 if (m_demangled_name
!= m_name
)
697 free (m_demangled_name
);
701 bool function_info::group_line_p (unsigned n
, unsigned src_idx
)
703 return is_group
&& src
== src_idx
&& start_line
<= n
&& n
<= end_line
;
707 There are a bajillion algorithms that do this. Boost's function is named
708 hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
709 "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
710 (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
712 The basic algorithm is simple: effectively, we're finding all simple paths
713 in a subgraph (that shrinks every iteration). Duplicates are filtered by
714 "blocking" a path when a node is added to the path (this also prevents non-
715 simple paths)--the node is unblocked only when it participates in a cycle.
718 typedef vector
<arc_info
*> arc_vector_t
;
719 typedef vector
<const block_info
*> block_vector_t
;
721 /* Handle cycle identified by EDGES, where the function finds minimum cs_count
722 and subtract the value from all counts. The subtracted value is added
723 to COUNT. Returns type of loop. */
726 handle_cycle (const arc_vector_t
&edges
, int64_t &count
)
728 /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
730 int64_t cycle_count
= INTTYPE_MAXIMUM (int64_t);
731 for (unsigned i
= 0; i
< edges
.size (); i
++)
733 int64_t ecount
= edges
[i
]->cs_count
;
734 if (cycle_count
> ecount
)
735 cycle_count
= ecount
;
737 count
+= cycle_count
;
738 for (unsigned i
= 0; i
< edges
.size (); i
++)
739 edges
[i
]->cs_count
-= cycle_count
;
741 gcc_assert (cycle_count
> 0);
744 /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
745 blocked by U in BLOCK_LISTS. */
748 unblock (const block_info
*u
, block_vector_t
&blocked
,
749 vector
<block_vector_t
> &block_lists
)
751 block_vector_t::iterator it
= find (blocked
.begin (), blocked
.end (), u
);
752 if (it
== blocked
.end ())
755 unsigned index
= it
- blocked
.begin ();
758 block_vector_t
to_unblock (block_lists
[index
]);
760 block_lists
.erase (block_lists
.begin () + index
);
762 for (block_vector_t::iterator it
= to_unblock
.begin ();
763 it
!= to_unblock
.end (); it
++)
764 unblock (*it
, blocked
, block_lists
);
767 /* Return true when PATH contains a zero cycle arc count. */
770 path_contains_zero_or_negative_cycle_arc (arc_vector_t
&path
)
772 for (unsigned i
= 0; i
< path
.size (); i
++)
773 if (path
[i
]->cs_count
<= 0)
778 /* Find circuit going to block V, PATH is provisional seen cycle.
779 BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
780 blocked by a block. COUNT is accumulated count of the current LINE.
781 Returns what type of loop it contains. */
784 circuit (block_info
*v
, arc_vector_t
&path
, block_info
*start
,
785 block_vector_t
&blocked
, vector
<block_vector_t
> &block_lists
,
786 line_info
&linfo
, int64_t &count
)
788 bool loop_found
= false;
790 /* Add v to the block list. */
791 gcc_assert (find (blocked
.begin (), blocked
.end (), v
) == blocked
.end ());
792 blocked
.push_back (v
);
793 block_lists
.push_back (block_vector_t ());
795 for (arc_info
*arc
= v
->succ
; arc
; arc
= arc
->succ_next
)
797 block_info
*w
= arc
->dst
;
799 || arc
->cs_count
<= 0
800 || !linfo
.has_block (w
))
803 path
.push_back (arc
);
806 /* Cycle has been found. */
807 handle_cycle (path
, count
);
810 else if (!path_contains_zero_or_negative_cycle_arc (path
)
811 && find (blocked
.begin (), blocked
.end (), w
) == blocked
.end ())
812 loop_found
|= circuit (w
, path
, start
, blocked
, block_lists
, linfo
,
819 unblock (v
, blocked
, block_lists
);
821 for (arc_info
*arc
= v
->succ
; arc
; arc
= arc
->succ_next
)
823 block_info
*w
= arc
->dst
;
825 || arc
->cs_count
<= 0
826 || !linfo
.has_block (w
))
830 = find (blocked
.begin (), blocked
.end (), w
) - blocked
.begin ();
831 gcc_assert (index
< blocked
.size ());
832 block_vector_t
&list
= block_lists
[index
];
833 if (find (list
.begin (), list
.end (), v
) == list
.end ())
840 /* Find cycles for a LINFO. */
843 get_cycles_count (line_info
&linfo
)
845 /* Note that this algorithm works even if blocks aren't in sorted order.
846 Each iteration of the circuit detection is completely independent
847 (except for reducing counts, but that shouldn't matter anyways).
848 Therefore, operating on a permuted order (i.e., non-sorted) only
849 has the effect of permuting the output cycles. */
852 for (vector
<block_info
*>::iterator it
= linfo
.blocks
.begin ();
853 it
!= linfo
.blocks
.end (); it
++)
856 block_vector_t blocked
;
857 vector
<block_vector_t
> block_lists
;
858 circuit (*it
, path
, *it
, blocked
, block_lists
, linfo
, count
);
865 main (int argc
, char **argv
)
871 p
= argv
[0] + strlen (argv
[0]);
872 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
876 xmalloc_set_program_name (progname
);
878 /* Unlock the stdio streams. */
879 unlock_std_streams ();
883 diagnostic_initialize (global_dc
, 0);
885 /* Handle response files. */
886 expandargv (&argc
, &argv
);
888 argno
= process_args (argc
, argv
);
892 if (argc
- argno
> 1)
897 for (; argno
!= argc
; argno
++)
899 if (flag_display_progress
)
900 printf ("Processing file %d out of %d\n", argno
- first_arg
+ 1,
902 process_file (argv
[argno
]);
904 if (flag_json_format
|| argno
== argc
- 1)
906 process_all_functions ();
907 generate_results (argv
[argno
]);
908 release_structures ();
912 if (!flag_use_stdout
)
913 executed_summary (total_lines
, total_executed
);
918 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
919 otherwise the output of --help. */
922 print_usage (int error_p
)
924 FILE *file
= error_p
? stderr
: stdout
;
925 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
927 fnotice (file
, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
928 fnotice (file
, "Print code coverage information.\n\n");
929 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
930 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
931 fnotice (file
, " -c, --branch-counts Output counts of branches taken\n\
932 rather than percentages\n");
933 fnotice (file
, " -d, --display-progress Display progress information\n");
934 fnotice (file
, " -D, --debug Display debugging dumps\n");
935 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
936 fnotice (file
, " -h, --help Print this help, then exit\n");
937 fnotice (file
, " -j, --json-format Output JSON intermediate format\n\
938 into .gcov.json.gz file\n");
939 fnotice (file
, " -H, --human-readable Output human readable numbers\n");
940 fnotice (file
, " -k, --use-colors Emit colored output\n");
941 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
943 fnotice (file
, " -m, --demangled-names Output demangled function names\n");
944 fnotice (file
, " -n, --no-output Do not create an output file\n");
945 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
946 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
947 fnotice (file
, " -q, --use-hotness-colors Emit perf-like colored output for hot lines\n");
948 fnotice (file
, " -r, --relative-only Only show data for relative sources\n");
949 fnotice (file
, " -s, --source-prefix DIR Source prefix to elide\n");
950 fnotice (file
, " -t, --stdout Output to stdout instead of a file\n");
951 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
952 fnotice (file
, " -v, --version Print version number, then exit\n");
953 fnotice (file
, " -w, --verbose Print verbose informations\n");
954 fnotice (file
, " -x, --hash-filenames Hash long pathnames\n");
955 fnotice (file
, "\nObsolete options:\n");
956 fnotice (file
, " -i, --json-format Replaced with -j, --json-format\n");
957 fnotice (file
, " -j, --human-readable Replaced with -H, --human-readable\n");
958 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
963 /* Print version information and exit. */
968 fnotice (stdout
, "gcov %s%s\n", pkgversion_string
, version_string
);
969 fnotice (stdout
, "JSON format version: %s\n", GCOV_JSON_FORMAT_VERSION
);
970 fprintf (stdout
, "Copyright %s 2024 Free Software Foundation, Inc.\n",
973 _("This is free software; see the source for copying conditions. There is NO\n\
974 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
975 exit (SUCCESS_EXIT_CODE
);
978 static const struct option options
[] =
980 { "help", no_argument
, NULL
, 'h' },
981 { "version", no_argument
, NULL
, 'v' },
982 { "verbose", no_argument
, NULL
, 'w' },
983 { "all-blocks", no_argument
, NULL
, 'a' },
984 { "branch-probabilities", no_argument
, NULL
, 'b' },
985 { "branch-counts", no_argument
, NULL
, 'c' },
986 { "json-format", no_argument
, NULL
, 'j' },
987 { "human-readable", no_argument
, NULL
, 'H' },
988 { "no-output", no_argument
, NULL
, 'n' },
989 { "long-file-names", no_argument
, NULL
, 'l' },
990 { "function-summaries", no_argument
, NULL
, 'f' },
991 { "demangled-names", no_argument
, NULL
, 'm' },
992 { "preserve-paths", no_argument
, NULL
, 'p' },
993 { "relative-only", no_argument
, NULL
, 'r' },
994 { "object-directory", required_argument
, NULL
, 'o' },
995 { "object-file", required_argument
, NULL
, 'o' },
996 { "source-prefix", required_argument
, NULL
, 's' },
997 { "stdout", no_argument
, NULL
, 't' },
998 { "unconditional-branches", no_argument
, NULL
, 'u' },
999 { "display-progress", no_argument
, NULL
, 'd' },
1000 { "hash-filenames", no_argument
, NULL
, 'x' },
1001 { "use-colors", no_argument
, NULL
, 'k' },
1002 { "use-hotness-colors", no_argument
, NULL
, 'q' },
1003 { "debug", no_argument
, NULL
, 'D' },
1007 /* Process args, return index to first non-arg. */
1010 process_args (int argc
, char **argv
)
1014 const char *opts
= "abcdDfhHijklmno:pqrs:tuvwx";
1015 while ((opt
= getopt_long (argc
, argv
, opts
, options
, NULL
)) != -1)
1020 flag_all_blocks
= 1;
1029 flag_function_summary
= 1;
1032 print_usage (false);
1033 /* print_usage will exit. */
1035 flag_long_names
= 1;
1038 flag_human_readable_numbers
= 1;
1041 flag_use_colors
= 1;
1044 flag_use_hotness_colors
= 1;
1047 flag_demangled_names
= 1;
1053 object_directory
= optarg
;
1056 source_prefix
= optarg
;
1057 source_length
= strlen (source_prefix
);
1060 flag_relative_only
= 1;
1063 flag_preserve_paths
= 1;
1066 flag_unconditional
= 1;
1070 flag_json_format
= 1;
1074 flag_display_progress
= 1;
1077 flag_hash_filenames
= 1;
1083 flag_use_stdout
= 1;
1090 /* print_version will exit. */
1093 /* print_usage will exit. */
1100 /* Output intermediate LINE sitting on LINE_NUM to JSON OBJECT.
1101 Add FUNCTION_NAME to the LINE. */
1104 output_intermediate_json_line (json::array
*object
,
1105 line_info
*line
, unsigned line_num
,
1106 const char *function_name
)
1111 json::object
*lineo
= new json::object ();
1112 lineo
->set_integer ("line_number", line_num
);
1113 if (function_name
!= NULL
)
1114 lineo
->set_string ("function_name", function_name
);
1115 lineo
->set_integer ("count", line
->count
);
1116 lineo
->set_bool ("unexecuted_block", line
->has_unexecuted_block
);
1118 json::array
*bb_ids
= new json::array ();
1119 for (const block_info
*block
: line
->blocks
)
1120 bb_ids
->append (new json::integer_number (block
->id
));
1121 lineo
->set ("block_ids", bb_ids
);
1123 json::array
*branches
= new json::array ();
1124 lineo
->set ("branches", branches
);
1126 json::array
*calls
= new json::array ();
1127 lineo
->set ("calls", calls
);
1129 vector
<arc_info
*>::const_iterator it
;
1131 for (it
= line
->branches
.begin (); it
!= line
->branches
.end ();
1134 if (!(*it
)->is_unconditional
&& !(*it
)->is_call_non_return
)
1136 json::object
*branch
= new json::object ();
1137 branch
->set_integer ("count", (*it
)->count
);
1138 branch
->set_bool ("throw", (*it
)->is_throw
);
1139 branch
->set_bool ("fallthrough", (*it
)->fall_through
);
1140 branch
->set_integer ("source_block_id", (*it
)->src
->id
);
1141 branch
->set_integer ("destination_block_id", (*it
)->dst
->id
);
1142 branches
->append (branch
);
1144 else if ((*it
)->is_call_non_return
)
1146 json::object
*call
= new json::object ();
1147 gcov_type returns
= (*it
)->src
->count
- (*it
)->count
;
1148 call
->set_integer ("source_block_id", (*it
)->src
->id
);
1149 call
->set_integer ("destination_block_id", (*it
)->dst
->id
);
1150 call
->set_integer ("returned", returns
);
1151 calls
->append (call
);
1155 object
->append (lineo
);
1158 /* Strip filename extension in STR. */
1161 strip_extention (string str
)
1163 string::size_type pos
= str
.rfind ('.');
1164 if (pos
!= string::npos
)
1165 str
= str
.substr (0, pos
);
1170 /* Calcualte md5sum for INPUT string and return it in hex string format. */
1173 get_md5sum (const char *input
)
1179 md5_init_ctx (&ctx
);
1180 md5_process_bytes (input
, strlen (input
), &ctx
);
1181 md5_finish_ctx (&ctx
, md5sum
);
1183 for (unsigned i
= 0; i
< 16; i
++)
1186 sprintf (b
, "%02x", (unsigned char)md5sum
[i
]);
1193 /* Get the name of the gcov file. The return value must be free'd.
1195 It appends the '.gcov' extension to the *basename* of the file.
1196 The resulting file name will be in PWD.
1199 input: foo.da, output: foo.da.gcov
1200 input: a/b/foo.cc, output: foo.cc.gcov */
1203 get_gcov_intermediate_filename (const char *input_file_name
)
1205 string base
= basename (input_file_name
);
1206 string str
= strip_extention (base
);
1208 if (flag_hash_filenames
)
1211 str
+= get_md5sum (input_file_name
);
1213 else if (flag_preserve_paths
&& base
!= input_file_name
)
1216 str
+= mangle_path (input_file_name
);
1217 str
= strip_extention (str
);
1220 str
+= ".gcov.json.gz";
1221 return str
.c_str ();
1224 /* Output the result in JSON intermediate format.
1225 Source info SRC is dumped into JSON_FILES which is JSON array. */
1228 output_json_intermediate_file (json::array
*json_files
, source_info
*src
)
1230 json::object
*root
= new json::object ();
1231 json_files
->append (root
);
1233 root
->set_string ("file", src
->name
);
1235 json::array
*functions
= new json::array ();
1236 root
->set ("functions", functions
);
1238 std::sort (src
->functions
.begin (), src
->functions
.end (),
1239 function_line_start_cmp ());
1240 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
1241 it
!= src
->functions
.end (); it
++)
1243 json::object
*function
= new json::object ();
1244 function
->set_string ("name", (*it
)->m_name
);
1245 function
->set_string ("demangled_name", (*it
)->get_demangled_name ());
1246 function
->set_integer ("start_line", (*it
)->start_line
);
1247 function
->set_integer ("start_column", (*it
)->start_column
);
1248 function
->set_integer ("end_line", (*it
)->end_line
);
1249 function
->set_integer ("end_column", (*it
)->end_column
);
1250 function
->set_integer ("blocks", (*it
)->get_block_count ());
1251 function
->set_integer ("blocks_executed", (*it
)->blocks_executed
);
1252 function
->set_integer ("execution_count", (*it
)->blocks
[0].count
);
1254 functions
->append (function
);
1257 json::array
*lineso
= new json::array ();
1258 root
->set ("lines", lineso
);
1260 vector
<function_info
*> last_non_group_fns
;
1262 for (unsigned line_num
= 1; line_num
<= src
->lines
.size (); line_num
++)
1264 vector
<function_info
*> *fns
= src
->get_functions_at_location (line_num
);
1267 /* Print info for all group functions that begin on the line. */
1268 for (vector
<function_info
*>::iterator it2
= fns
->begin ();
1269 it2
!= fns
->end (); it2
++)
1271 if (!(*it2
)->is_group
)
1272 last_non_group_fns
.push_back (*it2
);
1274 vector
<line_info
> &lines
= (*it2
)->lines
;
1275 /* The LINES array is allocated only for group functions. */
1276 for (unsigned i
= 0; i
< lines
.size (); i
++)
1278 line_info
*line
= &lines
[i
];
1279 output_intermediate_json_line (lineso
, line
, line_num
+ i
,
1284 /* Follow with lines associated with the source file. */
1285 if (line_num
< src
->lines
.size ())
1287 unsigned size
= last_non_group_fns
.size ();
1288 function_info
*last_fn
= size
> 0 ? last_non_group_fns
[size
- 1] : NULL
;
1289 const char *fname
= last_fn
? last_fn
->m_name
: NULL
;
1290 output_intermediate_json_line (lineso
, &src
->lines
[line_num
], line_num
,
1293 /* Pop ending function from stack. */
1294 if (last_fn
!= NULL
&& last_fn
->end_line
== line_num
)
1295 last_non_group_fns
.pop_back ();
1300 /* Function start pair. */
1301 struct function_start
1303 unsigned source_file_idx
;
1304 unsigned start_line
;
1307 /* Traits class for function start hash maps below. */
1309 struct function_start_pair_hash
: typed_noop_remove
<function_start
>
1311 typedef function_start value_type
;
1312 typedef function_start compare_type
;
1315 hash (const function_start
&ref
)
1317 inchash::hash
hstate (0);
1318 hstate
.add_int (ref
.source_file_idx
);
1319 hstate
.add_int (ref
.start_line
);
1320 return hstate
.end ();
1324 equal (const function_start
&ref1
, const function_start
&ref2
)
1326 return (ref1
.source_file_idx
== ref2
.source_file_idx
1327 && ref1
.start_line
== ref2
.start_line
);
1331 mark_deleted (function_start
&ref
)
1333 ref
.start_line
= ~1U;
1336 static const bool empty_zero_p
= false;
1339 mark_empty (function_start
&ref
)
1341 ref
.start_line
= ~2U;
1345 is_deleted (const function_start
&ref
)
1347 return ref
.start_line
== ~1U;
1351 is_empty (const function_start
&ref
)
1353 return ref
.start_line
== ~2U;
1357 /* Process a single input file. */
1360 process_file (const char *file_name
)
1362 create_file_names (file_name
);
1364 for (unsigned i
= 0; i
< processed_files
.size (); i
++)
1365 if (strcmp (da_file_name
, processed_files
[i
]) == 0)
1367 fnotice (stderr
, "'%s' file is already processed\n",
1372 processed_files
.push_back (xstrdup (da_file_name
));
1378 /* Process all functions in all files. */
1381 process_all_functions (void)
1383 hash_map
<function_start_pair_hash
, function_info
*> fn_map
;
1385 /* Identify group functions. */
1386 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1387 it
!= functions
.end (); it
++)
1388 if (!(*it
)->artificial
)
1390 function_start needle
;
1391 needle
.source_file_idx
= (*it
)->src
;
1392 needle
.start_line
= (*it
)->start_line
;
1394 function_info
**slot
= fn_map
.get (needle
);
1397 (*slot
)->is_group
= 1;
1398 (*it
)->is_group
= 1;
1401 fn_map
.put (needle
, *it
);
1404 /* Remove all artificial function. */
1405 functions
.erase (remove_if (functions
.begin (), functions
.end (),
1406 function_info::is_artificial
), functions
.end ());
1408 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1409 it
!= functions
.end (); it
++)
1411 function_info
*fn
= *it
;
1412 unsigned src
= fn
->src
;
1414 if (!fn
->counts
.empty () || no_data_file
)
1416 source_info
*s
= &sources
[src
];
1417 s
->add_function (fn
);
1419 /* Mark last line in files touched by function. */
1420 for (unsigned block_no
= 0; block_no
!= fn
->blocks
.size ();
1423 block_info
*block
= &fn
->blocks
[block_no
];
1424 for (unsigned i
= 0; i
< block
->locations
.size (); i
++)
1426 /* Sort lines of locations. */
1427 sort (block
->locations
[i
].lines
.begin (),
1428 block
->locations
[i
].lines
.end ());
1430 if (!block
->locations
[i
].lines
.empty ())
1432 s
= &sources
[block
->locations
[i
].source_file_idx
];
1434 = block
->locations
[i
].lines
.back ();
1436 /* Record new lines for the function. */
1437 if (last_line
>= s
->lines
.size ())
1439 s
= &sources
[block
->locations
[i
].source_file_idx
];
1441 = block
->locations
[i
].lines
.back ();
1443 /* Record new lines for the function. */
1444 if (last_line
>= s
->lines
.size ())
1446 /* Record new lines for a source file. */
1447 s
->lines
.resize (last_line
+ 1);
1454 /* Allocate lines for group function, following start_line
1455 and end_line information of the function. */
1457 fn
->lines
.resize (fn
->end_line
- fn
->start_line
+ 1);
1459 solve_flow_graph (fn
);
1461 find_exception_blocks (fn
);
1465 /* The function was not in the executable -- some other
1466 instance must have been selected. */
1472 output_gcov_file (const char *file_name
, source_info
*src
)
1474 string gcov_file_name_str
1475 = make_gcov_file_name (file_name
, src
->coverage
.name
);
1476 const char *gcov_file_name
= gcov_file_name_str
.c_str ();
1478 if (src
->coverage
.lines
)
1480 FILE *gcov_file
= fopen (gcov_file_name
, "w");
1483 fnotice (stdout
, "Creating '%s'\n", gcov_file_name
);
1484 output_lines (gcov_file
, src
);
1485 if (ferror (gcov_file
))
1487 fnotice (stderr
, "Error writing output file '%s'\n",
1495 fnotice (stderr
, "Could not open output file '%s'\n", gcov_file_name
);
1501 unlink (gcov_file_name
);
1502 fnotice (stdout
, "Removing '%s'\n", gcov_file_name
);
1507 generate_results (const char *file_name
)
1509 string gcov_intermediate_filename
;
1511 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1512 it
!= functions
.end (); it
++)
1514 function_info
*fn
= *it
;
1515 coverage_info coverage
;
1517 memset (&coverage
, 0, sizeof (coverage
));
1518 coverage
.name
= fn
->get_name ();
1519 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
1520 if (flag_function_summary
)
1522 function_summary (&coverage
);
1523 fnotice (stdout
, "\n");
1528 needle
.name
= file_name
;
1529 vector
<name_map
>::iterator it
1530 = std::find (names
.begin (), names
.end (), needle
);
1531 if (it
!= names
.end ())
1532 file_name
= sources
[it
->src
].coverage
.name
;
1534 file_name
= canonicalize_name (file_name
);
1536 gcov_intermediate_filename
= get_gcov_intermediate_filename (file_name
);
1538 json::object
*root
= new json::object ();
1539 root
->set_string ("format_version", GCOV_JSON_FORMAT_VERSION
);
1540 root
->set_string ("gcc_version", version_string
);
1542 if (bbg_cwd
!= NULL
)
1543 root
->set_string ("current_working_directory", bbg_cwd
);
1544 root
->set_string ("data_file", file_name
);
1546 json::array
*json_files
= new json::array ();
1547 root
->set ("files", json_files
);
1549 for (vector
<source_info
>::iterator it
= sources
.begin ();
1550 it
!= sources
.end (); it
++)
1552 source_info
*src
= &(*it
);
1553 if (flag_relative_only
)
1555 /* Ignore this source, if it is an absolute path (after
1556 source prefix removal). */
1557 char first
= src
->coverage
.name
[0];
1559 #if HAVE_DOS_BASED_FILE_SYSTEM
1560 if (first
&& src
->coverage
.name
[1] == ':')
1561 first
= src
->coverage
.name
[2];
1563 if (IS_DIR_SEPARATOR (first
))
1567 accumulate_line_counts (src
);
1571 if (!flag_use_stdout
)
1572 file_summary (&src
->coverage
);
1573 total_lines
+= src
->coverage
.lines
;
1574 total_executed
+= src
->coverage
.lines_executed
;
1577 if (flag_json_format
)
1579 output_json_intermediate_file (json_files
, src
);
1580 if (!flag_use_stdout
)
1581 fnotice (stdout
, "\n");
1585 if (flag_use_stdout
)
1587 if (src
->coverage
.lines
)
1588 output_lines (stdout
, src
);
1592 output_gcov_file (file_name
, src
);
1593 fnotice (stdout
, "\n");
1599 if (flag_gcov_file
&& flag_json_format
)
1601 if (flag_use_stdout
)
1603 root
->dump (stdout
, false);
1609 root
->print (&pp
, false);
1610 pp_formatted_text (&pp
);
1612 fnotice (stdout
, "Creating '%s'\n",
1613 gcov_intermediate_filename
.c_str ());
1614 gzFile output
= gzopen (gcov_intermediate_filename
.c_str (), "w");
1617 fnotice (stderr
, "Cannot open JSON output file %s\n",
1618 gcov_intermediate_filename
.c_str ());
1623 if (gzputs (output
, pp_formatted_text (&pp
)) == EOF
1624 || gzclose (output
))
1626 fnotice (stderr
, "Error writing JSON output file %s\n",
1627 gcov_intermediate_filename
.c_str ());
1635 /* Release all memory used. */
1638 release_structures (void)
1640 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1641 it
!= functions
.end (); it
++)
1646 functions
.resize (0);
1647 ident_to_fn
.clear ();
1650 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
1651 is not specified, these are named from FILE_NAME sans extension. If
1652 OBJECT_DIRECTORY is specified and is a directory, the files are in that
1653 directory, but named from the basename of the FILE_NAME, sans extension.
1654 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
1655 and the data files are named from that. */
1658 create_file_names (const char *file_name
)
1662 int length
= strlen (file_name
);
1665 /* Free previous file names. */
1666 free (bbg_file_name
);
1667 free (da_file_name
);
1668 da_file_name
= bbg_file_name
= NULL
;
1672 if (object_directory
&& object_directory
[0])
1676 length
+= strlen (object_directory
) + 2;
1677 name
= XNEWVEC (char, length
);
1680 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
1681 strcat (name
, object_directory
);
1682 if (base
&& (!IS_DIR_SEPARATOR (name
[strlen (name
) - 1])))
1687 name
= XNEWVEC (char, length
+ 1);
1688 strcpy (name
, file_name
);
1694 /* Append source file name. */
1695 const char *cptr
= lbasename (file_name
);
1696 strcat (name
, cptr
? cptr
: file_name
);
1699 /* Remove the extension. */
1700 cptr
= strrchr (CONST_CAST (char *, lbasename (name
)), '.');
1704 length
= strlen (name
);
1706 bbg_file_name
= XNEWVEC (char, length
+ strlen (GCOV_NOTE_SUFFIX
) + 1);
1707 strcpy (bbg_file_name
, name
);
1708 strcpy (bbg_file_name
+ length
, GCOV_NOTE_SUFFIX
);
1710 da_file_name
= XNEWVEC (char, length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
1711 strcpy (da_file_name
, name
);
1712 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
1718 /* Find or create a source file structure for FILE_NAME. Copies
1719 FILE_NAME on creation */
1722 find_source (const char *file_name
)
1729 file_name
= "<unknown>";
1732 needle
.name
= file_name
;
1734 vector
<name_map
>::iterator it
= std::find (names
.begin (), names
.end (),
1736 if (it
!= names
.end ())
1742 /* Not found, try the canonical name. */
1743 canon
= canonicalize_name (file_name
);
1744 needle
.name
= canon
;
1745 it
= std::find (names
.begin (), names
.end (), needle
);
1746 if (it
== names
.end ())
1748 /* Not found with canonical name, create a new source. */
1751 idx
= sources
.size ();
1752 needle
= name_map (canon
, idx
);
1753 names
.push_back (needle
);
1755 sources
.push_back (source_info ());
1756 src
= &sources
.back ();
1758 src
->coverage
.name
= src
->name
;
1761 #if HAVE_DOS_BASED_FILE_SYSTEM
1762 /* You lose if separators don't match exactly in the
1764 && !strncasecmp (source_prefix
, src
->coverage
.name
, source_length
)
1766 && !strncmp (source_prefix
, src
->coverage
.name
, source_length
)
1768 && IS_DIR_SEPARATOR (src
->coverage
.name
[source_length
]))
1769 src
->coverage
.name
+= source_length
+ 1;
1770 if (!stat (src
->name
, &status
))
1771 src
->file_time
= status
.st_mtime
;
1776 needle
.name
= file_name
;
1777 if (std::find (names
.begin (), names
.end (), needle
) == names
.end ())
1779 /* Append the non-canonical name. */
1780 names
.push_back (name_map (xstrdup (file_name
), idx
));
1783 /* Resort the name map. */
1784 std::sort (names
.begin (), names
.end ());
1787 if (sources
[idx
].file_time
> bbg_file_time
)
1789 static int info_emitted
;
1791 fnotice (stderr
, "%s:source file is newer than notes file '%s'\n",
1792 file_name
, bbg_file_name
);
1796 "(the message is displayed only once per source file)\n");
1799 sources
[idx
].file_time
= 0;
1805 /* Read the notes file. Save functions to FUNCTIONS global vector. */
1808 read_graph_file (void)
1811 unsigned current_tag
= 0;
1814 if (!gcov_open (bbg_file_name
, 1))
1816 fnotice (stderr
, "%s:cannot open notes file\n", bbg_file_name
);
1820 bbg_file_time
= gcov_time ();
1821 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC
))
1823 fnotice (stderr
, "%s:not a gcov notes file\n", bbg_file_name
);
1829 version
= gcov_read_unsigned ();
1830 if (version
!= GCOV_VERSION
)
1834 GCOV_UNSIGNED2STRING (v
, version
);
1835 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1837 fnotice (stderr
, "%s:version '%.4s', prefer '%.4s'\n",
1838 bbg_file_name
, v
, e
);
1841 bbg_stamp
= gcov_read_unsigned ();
1842 /* Read checksum. */
1843 gcov_read_unsigned ();
1844 bbg_cwd
= xstrdup (gcov_read_string ());
1845 bbg_supports_has_unexecuted_blocks
= gcov_read_unsigned ();
1847 function_info
*fn
= NULL
;
1848 while ((tag
= gcov_read_unsigned ()))
1850 unsigned length
= gcov_read_unsigned ();
1851 gcov_position_t base
= gcov_position ();
1853 if (tag
== GCOV_TAG_FUNCTION
)
1855 char *function_name
;
1857 unsigned lineno_checksum
, cfg_checksum
;
1859 ident
= gcov_read_unsigned ();
1860 lineno_checksum
= gcov_read_unsigned ();
1861 cfg_checksum
= gcov_read_unsigned ();
1862 function_name
= xstrdup (gcov_read_string ());
1863 unsigned artificial
= gcov_read_unsigned ();
1864 unsigned src_idx
= find_source (gcov_read_string ());
1865 unsigned start_line
= gcov_read_unsigned ();
1866 unsigned start_column
= gcov_read_unsigned ();
1867 unsigned end_line
= gcov_read_unsigned ();
1868 unsigned end_column
= gcov_read_unsigned ();
1870 fn
= new function_info ();
1871 functions
.push_back (fn
);
1872 ident_to_fn
[ident
] = fn
;
1874 fn
->m_name
= function_name
;
1876 fn
->lineno_checksum
= lineno_checksum
;
1877 fn
->cfg_checksum
= cfg_checksum
;
1879 fn
->start_line
= start_line
;
1880 fn
->start_column
= start_column
;
1881 fn
->end_line
= end_line
;
1882 fn
->end_column
= end_column
;
1883 fn
->artificial
= artificial
;
1887 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
1889 if (!fn
->blocks
.empty ())
1890 fnotice (stderr
, "%s:already seen blocks for '%s'\n",
1891 bbg_file_name
, fn
->get_name ());
1893 fn
->blocks
.resize (gcov_read_unsigned ());
1895 else if (fn
&& tag
== GCOV_TAG_ARCS
)
1897 unsigned src
= gcov_read_unsigned ();
1898 fn
->blocks
[src
].id
= src
;
1899 unsigned num_dests
= GCOV_TAG_ARCS_NUM (length
);
1900 block_info
*src_blk
= &fn
->blocks
[src
];
1901 unsigned mark_catches
= 0;
1902 struct arc_info
*arc
;
1904 if (src
>= fn
->blocks
.size () || fn
->blocks
[src
].succ
)
1909 unsigned dest
= gcov_read_unsigned ();
1910 unsigned flags
= gcov_read_unsigned ();
1912 if (dest
>= fn
->blocks
.size ())
1914 arc
= XCNEW (arc_info
);
1916 arc
->dst
= &fn
->blocks
[dest
];
1917 /* Set id in order to find EXIT_BLOCK. */
1918 arc
->dst
->id
= dest
;
1922 arc
->count_valid
= 0;
1923 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
1924 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
1925 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
1927 arc
->succ_next
= src_blk
->succ
;
1928 src_blk
->succ
= arc
;
1929 src_blk
->num_succ
++;
1931 arc
->pred_next
= fn
->blocks
[dest
].pred
;
1932 fn
->blocks
[dest
].pred
= arc
;
1933 fn
->blocks
[dest
].num_pred
++;
1939 /* Exceptional exit from this function, the
1940 source block must be a call. */
1941 fn
->blocks
[src
].is_call_site
= 1;
1942 arc
->is_call_non_return
= 1;
1947 /* Non-local return from a callee of this
1948 function. The destination block is a setjmp. */
1949 arc
->is_nonlocal_return
= 1;
1950 fn
->blocks
[dest
].is_nonlocal_return
= 1;
1955 fn
->counts
.push_back (0);
1960 /* We have a fake exit from this block. The other
1961 non-fall through exits must be to catch handlers.
1962 Mark them as catch arcs. */
1964 for (arc
= src_blk
->succ
; arc
; arc
= arc
->succ_next
)
1965 if (!arc
->fake
&& !arc
->fall_through
)
1972 else if (fn
&& tag
== GCOV_TAG_LINES
)
1974 unsigned blockno
= gcov_read_unsigned ();
1975 block_info
*block
= &fn
->blocks
[blockno
];
1977 if (blockno
>= fn
->blocks
.size ())
1982 unsigned lineno
= gcov_read_unsigned ();
1985 block
->locations
.back ().lines
.push_back (lineno
);
1988 const char *file_name
= gcov_read_string ();
1992 block
->locations
.push_back (block_location_info
1993 (find_source (file_name
)));
1997 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
2002 gcov_sync (base
, length
);
2003 if (gcov_is_error ())
2006 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
2013 if (functions
.empty ())
2014 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
2017 /* Reads profiles from the count file and attach to each
2018 function. Return nonzero if fatal error. */
2021 read_count_file (void)
2026 function_info
*fn
= NULL
;
2028 map
<unsigned, function_info
*>::iterator it
;
2030 if (!gcov_open (da_file_name
, 1))
2032 fnotice (stderr
, "%s:cannot open data file, assuming not executed\n",
2037 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
2039 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
2045 version
= gcov_read_unsigned ();
2046 if (version
!= GCOV_VERSION
)
2050 GCOV_UNSIGNED2STRING (v
, version
);
2051 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
2053 fnotice (stderr
, "%s:version '%.4s', prefer version '%.4s'\n",
2054 da_file_name
, v
, e
);
2057 tag
= gcov_read_unsigned ();
2058 if (tag
!= bbg_stamp
)
2060 fnotice (stderr
, "%s:stamp mismatch with notes file\n", da_file_name
);
2065 /* Read checksum. */
2066 gcov_read_unsigned ();
2068 while ((tag
= gcov_read_unsigned ()))
2070 unsigned length
= gcov_read_unsigned ();
2071 int read_length
= (int)length
;
2072 unsigned long base
= gcov_position ();
2074 if (tag
== GCOV_TAG_OBJECT_SUMMARY
)
2076 struct gcov_summary summary
;
2077 gcov_read_summary (&summary
);
2078 object_runs
= summary
.runs
;
2080 else if (tag
== GCOV_TAG_FUNCTION
&& !length
)
2082 else if (tag
== GCOV_TAG_FUNCTION
&& length
== GCOV_TAG_FUNCTION_LENGTH
)
2085 ident
= gcov_read_unsigned ();
2087 it
= ident_to_fn
.find (ident
);
2088 if (it
!= ident_to_fn
.end ())
2093 else if (gcov_read_unsigned () != fn
->lineno_checksum
2094 || gcov_read_unsigned () != fn
->cfg_checksum
)
2097 fnotice (stderr
, "%s:profile mismatch for '%s'\n",
2098 da_file_name
, fn
->get_name ());
2102 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
2104 length
= abs (read_length
);
2105 if (length
!= GCOV_TAG_COUNTER_LENGTH (fn
->counts
.size ()))
2108 if (read_length
> 0)
2109 for (ix
= 0; ix
!= fn
->counts
.size (); ix
++)
2110 fn
->counts
[ix
] += gcov_read_counter ();
2112 if (read_length
< 0)
2114 gcov_sync (base
, read_length
);
2115 if ((error
= gcov_is_error ()))
2119 ? N_("%s:overflowed\n")
2120 : N_("%s:corrupted\n"),
2131 /* Solve the flow graph. Propagate counts from the instrumented arcs
2132 to the blocks and the uninstrumented arcs. */
2135 solve_flow_graph (function_info
*fn
)
2139 gcov_type
*count_ptr
= &fn
->counts
.front ();
2141 block_info
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
2142 block_info
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
2144 /* The arcs were built in reverse order. Fix that now. */
2145 for (ix
= fn
->blocks
.size (); ix
--;)
2147 arc_info
*arc_p
, *arc_n
;
2149 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
2150 arc_p
= arc
, arc
= arc_n
)
2152 arc_n
= arc
->succ_next
;
2153 arc
->succ_next
= arc_p
;
2155 fn
->blocks
[ix
].succ
= arc_p
;
2157 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
2158 arc_p
= arc
, arc
= arc_n
)
2160 arc_n
= arc
->pred_next
;
2161 arc
->pred_next
= arc_p
;
2163 fn
->blocks
[ix
].pred
= arc_p
;
2166 if (fn
->blocks
.size () < 2)
2167 fnotice (stderr
, "%s:'%s' lacks entry and/or exit blocks\n",
2168 bbg_file_name
, fn
->get_name ());
2171 if (fn
->blocks
[ENTRY_BLOCK
].num_pred
)
2172 fnotice (stderr
, "%s:'%s' has arcs to entry block\n",
2173 bbg_file_name
, fn
->get_name ());
2175 /* We can't deduce the entry block counts from the lack of
2177 fn
->blocks
[ENTRY_BLOCK
].num_pred
= ~(unsigned)0;
2179 if (fn
->blocks
[EXIT_BLOCK
].num_succ
)
2180 fnotice (stderr
, "%s:'%s' has arcs from exit block\n",
2181 bbg_file_name
, fn
->get_name ());
2183 /* Likewise, we can't deduce exit block counts from the lack
2184 of its successors. */
2185 fn
->blocks
[EXIT_BLOCK
].num_succ
= ~(unsigned)0;
2188 /* Propagate the measured counts, this must be done in the same
2189 order as the code in profile.cc */
2190 for (unsigned i
= 0; i
< fn
->blocks
.size (); i
++)
2192 blk
= &fn
->blocks
[i
];
2193 block_info
const *prev_dst
= NULL
;
2194 int out_of_order
= 0;
2195 int non_fake_succ
= 0;
2197 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2205 arc
->count
= *count_ptr
++;
2206 arc
->count_valid
= 1;
2208 arc
->dst
->num_pred
--;
2210 if (prev_dst
&& prev_dst
> arc
->dst
)
2212 prev_dst
= arc
->dst
;
2214 if (non_fake_succ
== 1)
2216 /* If there is only one non-fake exit, it is an
2217 unconditional branch. */
2218 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2221 arc
->is_unconditional
= 1;
2222 /* If this block is instrumenting a call, it might be
2223 an artificial block. It is not artificial if it has
2224 a non-fallthrough exit, or the destination of this
2225 arc has more than one entry. Mark the destination
2226 block as a return site, if none of those conditions
2228 if (blk
->is_call_site
&& arc
->fall_through
2229 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
2230 arc
->dst
->is_call_return
= 1;
2234 /* Sort the successor arcs into ascending dst order. profile.cc
2235 normally produces arcs in the right order, but sometimes with
2236 one or two out of order. We're not using a particularly
2240 arc_info
*start
= blk
->succ
;
2241 unsigned changes
= 1;
2245 arc_info
*arc
, *arc_p
, *arc_n
;
2248 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
2250 if (arc
->dst
> arc_n
->dst
)
2254 arc_p
->succ_next
= arc_n
;
2257 arc
->succ_next
= arc_n
->succ_next
;
2258 arc_n
->succ_next
= arc
;
2271 /* Place it on the invalid chain, it will be ignored if that's
2273 blk
->invalid_chain
= 1;
2274 blk
->chain
= invalid_blocks
;
2275 invalid_blocks
= blk
;
2278 while (invalid_blocks
|| valid_blocks
)
2280 while ((blk
= invalid_blocks
))
2282 gcov_type total
= 0;
2283 const arc_info
*arc
;
2285 invalid_blocks
= blk
->chain
;
2286 blk
->invalid_chain
= 0;
2288 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2289 total
+= arc
->count
;
2290 else if (!blk
->num_pred
)
2291 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
2292 total
+= arc
->count
;
2297 blk
->count_valid
= 1;
2298 blk
->chain
= valid_blocks
;
2299 blk
->valid_chain
= 1;
2302 while ((blk
= valid_blocks
))
2305 arc_info
*arc
, *inv_arc
;
2307 valid_blocks
= blk
->chain
;
2308 blk
->valid_chain
= 0;
2309 if (blk
->num_succ
== 1)
2315 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2317 total
-= arc
->count
;
2318 if (!arc
->count_valid
)
2322 inv_arc
->count_valid
= 1;
2323 inv_arc
->count
= total
;
2326 if (dst
->count_valid
)
2328 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
2330 dst
->chain
= valid_blocks
;
2331 dst
->valid_chain
= 1;
2337 if (!dst
->num_pred
&& !dst
->invalid_chain
)
2339 dst
->chain
= invalid_blocks
;
2340 dst
->invalid_chain
= 1;
2341 invalid_blocks
= dst
;
2345 if (blk
->num_pred
== 1)
2351 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
2353 total
-= arc
->count
;
2354 if (!arc
->count_valid
)
2358 inv_arc
->count_valid
= 1;
2359 inv_arc
->count
= total
;
2362 if (src
->count_valid
)
2364 if (src
->num_succ
== 1 && !src
->valid_chain
)
2366 src
->chain
= valid_blocks
;
2367 src
->valid_chain
= 1;
2373 if (!src
->num_succ
&& !src
->invalid_chain
)
2375 src
->chain
= invalid_blocks
;
2376 src
->invalid_chain
= 1;
2377 invalid_blocks
= src
;
2384 /* If the graph has been correctly solved, every block will have a
2386 for (unsigned i
= 0; ix
< fn
->blocks
.size (); i
++)
2387 if (!fn
->blocks
[i
].count_valid
)
2389 fnotice (stderr
, "%s:graph is unsolvable for '%s'\n",
2390 bbg_file_name
, fn
->get_name ());
2395 /* Mark all the blocks only reachable via an incoming catch. */
2398 find_exception_blocks (function_info
*fn
)
2401 block_info
**queue
= XALLOCAVEC (block_info
*, fn
->blocks
.size ());
2403 /* First mark all blocks as exceptional. */
2404 for (ix
= fn
->blocks
.size (); ix
--;)
2405 fn
->blocks
[ix
].exceptional
= 1;
2407 /* Now mark all the blocks reachable via non-fake edges */
2408 queue
[0] = &fn
->blocks
[0];
2409 queue
[0]->exceptional
= 0;
2412 block_info
*block
= queue
[--ix
];
2413 const arc_info
*arc
;
2415 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2416 if (!arc
->fake
&& !arc
->is_throw
&& arc
->dst
->exceptional
)
2418 arc
->dst
->exceptional
= 0;
2419 queue
[ix
++] = arc
->dst
;
2425 /* Increment totals in COVERAGE according to arc ARC. */
2428 add_branch_counts (coverage_info
*coverage
, const arc_info
*arc
)
2430 if (arc
->is_call_non_return
)
2433 if (arc
->src
->count
)
2434 coverage
->calls_executed
++;
2436 else if (!arc
->is_unconditional
)
2438 coverage
->branches
++;
2439 if (arc
->src
->count
)
2440 coverage
->branches_executed
++;
2442 coverage
->branches_taken
++;
2446 /* Format COUNT, if flag_human_readable_numbers is set, return it human
2450 format_count (gcov_type count
)
2452 static char buffer
[64];
2453 const char *units
= " kMGTPEZY";
2455 if (count
< 1000 || !flag_human_readable_numbers
)
2457 sprintf (buffer
, "%" PRId64
, count
);
2462 gcov_type divisor
= 1;
2463 for (i
= 0; units
[i
+1]; i
++, divisor
*= 1000)
2465 if (count
+ divisor
/ 2 < 1000 * divisor
)
2468 float r
= 1.0f
* count
/ divisor
;
2469 sprintf (buffer
, "%.1f%c", r
, units
[i
]);
2473 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
2474 count. If DECIMAL_PLACES >= 0, format TOP/BOTTOM * 100 to DECIMAL_PLACES.
2475 If DECIMAL_PLACES is zero, no decimal point is printed. Only print 100% when
2476 TOP==BOTTOM and only print 0% when TOP=0. If DECIMAL_PLACES < 0, then simply
2477 format TOP. Return pointer to a static string. */
2480 format_gcov (gcov_type top
, gcov_type bottom
, int decimal_places
)
2482 static char buffer
[20];
2484 if (decimal_places
>= 0)
2486 float ratio
= bottom
? 100.0f
* top
/ bottom
: 0;
2488 /* Round up to 1% if there's a small non-zero value. */
2489 if (ratio
> 0.0f
&& ratio
< 0.5f
&& decimal_places
== 0)
2491 sprintf (buffer
, "%.*f%%", decimal_places
, ratio
);
2494 return format_count (top
);
2499 /* Summary of execution */
2502 executed_summary (unsigned lines
, unsigned executed
)
2505 fnotice (stdout
, "Lines executed:%s of %d\n",
2506 format_gcov (executed
, lines
, 2), lines
);
2508 fnotice (stdout
, "No executable lines\n");
2511 /* Output summary info for a function. */
2514 function_summary (const coverage_info
*coverage
)
2516 fnotice (stdout
, "%s '%s'\n", "Function", coverage
->name
);
2517 executed_summary (coverage
->lines
, coverage
->lines_executed
);
2520 /* Output summary info for a file. */
2523 file_summary (const coverage_info
*coverage
)
2525 fnotice (stdout
, "%s '%s'\n", "File", coverage
->name
);
2526 executed_summary (coverage
->lines
, coverage
->lines_executed
);
2530 if (coverage
->branches
)
2532 fnotice (stdout
, "Branches executed:%s of %d\n",
2533 format_gcov (coverage
->branches_executed
,
2534 coverage
->branches
, 2),
2535 coverage
->branches
);
2536 fnotice (stdout
, "Taken at least once:%s of %d\n",
2537 format_gcov (coverage
->branches_taken
,
2538 coverage
->branches
, 2),
2539 coverage
->branches
);
2542 fnotice (stdout
, "No branches\n");
2543 if (coverage
->calls
)
2544 fnotice (stdout
, "Calls executed:%s of %d\n",
2545 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
2548 fnotice (stdout
, "No calls\n");
2552 /* Canonicalize the filename NAME by canonicalizing directory
2553 separators, eliding . components and resolving .. components
2554 appropriately. Always returns a unique string. */
2557 canonicalize_name (const char *name
)
2559 /* The canonical name cannot be longer than the incoming name. */
2560 char *result
= XNEWVEC (char, strlen (name
) + 1);
2561 const char *base
= name
, *probe
;
2566 #if HAVE_DOS_BASED_FILE_SYSTEM
2567 if (base
[0] && base
[1] == ':')
2569 result
[0] = base
[0];
2575 for (dd_base
= ptr
; *base
; base
= probe
)
2579 for (probe
= base
; *probe
; probe
++)
2580 if (IS_DIR_SEPARATOR (*probe
))
2584 if (len
== 1 && base
[0] == '.')
2585 /* Elide a '.' directory */
2587 else if (len
== 2 && base
[0] == '.' && base
[1] == '.')
2589 /* '..', we can only elide it and the previous directory, if
2590 we're not a symlink. */
2591 struct stat ATTRIBUTE_UNUSED buf
;
2595 #if defined (S_ISLNK)
2596 /* S_ISLNK is not POSIX.1-1996. */
2597 || stat (result
, &buf
) || S_ISLNK (buf
.st_mode
)
2601 /* Cannot elide, or unreadable or a symlink. */
2602 dd_base
= ptr
+ 2 + slash
;
2605 while (ptr
!= dd_base
&& *ptr
!= '/')
2607 slash
= ptr
!= result
;
2612 /* Regular pathname component. */
2615 memcpy (ptr
, base
, len
);
2620 for (; IS_DIR_SEPARATOR (*probe
); probe
++)
2628 /* Generate an output file name. INPUT_NAME is the canonicalized main
2629 input file and SRC_NAME is the canonicalized file name.
2630 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
2631 long_output_names we prepend the processed name of the input file
2632 to each output name (except when the current source file is the
2633 input file, so you don't get a double concatenation). The two
2634 components are separated by '##'. With preserve_paths we create a
2635 filename from all path components of the source file, replacing '/'
2636 with '#', and .. with '^', without it we simply take the basename
2637 component. (Remember, the canonicalized name will already have
2638 elided '.' components and converted \\ separators.) */
2641 make_gcov_file_name (const char *input_name
, const char *src_name
)
2645 /* When hashing filenames, we shorten them by only using the filename
2646 component and appending a hash of the full (mangled) pathname. */
2647 if (flag_hash_filenames
)
2648 str
= (string (mangle_name (src_name
)) + "##"
2649 + get_md5sum (src_name
) + ".gcov");
2652 if (flag_long_names
&& input_name
&& strcmp (src_name
, input_name
) != 0)
2654 str
+= mangle_name (input_name
);
2658 str
+= mangle_name (src_name
);
2665 /* Mangle BASE name, copy it at the beginning of PTR buffer and
2666 return address of the \0 character of the buffer. */
2669 mangle_name (char const *base
)
2671 /* Generate the source filename part. */
2672 if (!flag_preserve_paths
)
2673 return xstrdup (lbasename (base
));
2675 return mangle_path (base
);
2678 /* Scan through the bb_data for each line in the block, increment
2679 the line number execution count indicated by the execution count of
2680 the appropriate basic block. */
2683 add_line_counts (coverage_info
*coverage
, function_info
*fn
)
2685 bool has_any_line
= false;
2686 /* Scan each basic block. */
2687 for (unsigned ix
= 0; ix
!= fn
->blocks
.size (); ix
++)
2689 line_info
*line
= NULL
;
2690 block_info
*block
= &fn
->blocks
[ix
];
2691 if (block
->count
&& ix
&& ix
+ 1 != fn
->blocks
.size ())
2692 fn
->blocks_executed
++;
2693 for (unsigned i
= 0; i
< block
->locations
.size (); i
++)
2695 unsigned src_idx
= block
->locations
[i
].source_file_idx
;
2696 vector
<unsigned> &lines
= block
->locations
[i
].lines
;
2698 block
->cycle
.arc
= NULL
;
2699 block
->cycle
.ident
= ~0U;
2701 for (unsigned j
= 0; j
< lines
.size (); j
++)
2703 unsigned ln
= lines
[j
];
2705 /* Line belongs to a function that is in a group. */
2706 if (fn
->group_line_p (ln
, src_idx
))
2708 gcc_assert (lines
[j
] - fn
->start_line
< fn
->lines
.size ());
2709 line
= &(fn
->lines
[lines
[j
] - fn
->start_line
]);
2714 if (!line
->count
&& block
->count
)
2715 coverage
->lines_executed
++;
2718 if (!block
->exceptional
)
2720 line
->unexceptional
= 1;
2721 if (block
->count
== 0)
2722 line
->has_unexecuted_block
= 1;
2724 line
->count
+= block
->count
;
2728 gcc_assert (ln
< sources
[src_idx
].lines
.size ());
2729 line
= &(sources
[src_idx
].lines
[ln
]);
2734 if (!line
->count
&& block
->count
)
2735 coverage
->lines_executed
++;
2738 if (!block
->exceptional
)
2740 line
->unexceptional
= 1;
2741 if (block
->count
== 0)
2742 line
->has_unexecuted_block
= 1;
2744 line
->count
+= block
->count
;
2748 has_any_line
= true;
2750 if (!ix
|| ix
+ 1 == fn
->blocks
.size ())
2751 /* Entry or exit block. */;
2752 else if (line
!= NULL
)
2754 line
->blocks
.push_back (block
);
2760 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2761 line
->branches
.push_back (arc
);
2768 fnotice (stderr
, "%s:no lines for '%s'\n", bbg_file_name
,
2772 /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE
2773 is set to true, update source file summary. */
2775 static void accumulate_line_info (line_info
*line
, source_info
*src
,
2779 for (vector
<arc_info
*>::iterator it
= line
->branches
.begin ();
2780 it
!= line
->branches
.end (); it
++)
2781 add_branch_counts (&src
->coverage
, *it
);
2783 if (!line
->blocks
.empty ())
2785 /* The user expects the line count to be the number of times
2786 a line has been executed. Simply summing the block count
2787 will give an artificially high number. The Right Thing
2788 is to sum the entry counts to the graph of blocks on this
2789 line, then find the elementary cycles of the local graph
2790 and add the transition counts of those cycles. */
2791 gcov_type count
= 0;
2793 /* Cycle detection. */
2794 for (vector
<block_info
*>::iterator it
= line
->blocks
.begin ();
2795 it
!= line
->blocks
.end (); it
++)
2797 for (arc_info
*arc
= (*it
)->pred
; arc
; arc
= arc
->pred_next
)
2798 if (!line
->has_block (arc
->src
))
2799 count
+= arc
->count
;
2800 for (arc_info
*arc
= (*it
)->succ
; arc
; arc
= arc
->succ_next
)
2801 arc
->cs_count
= arc
->count
;
2804 /* Now, add the count of loops entirely on this line. */
2805 count
+= get_cycles_count (*line
);
2806 line
->count
= count
;
2808 if (line
->count
> src
->maximum_count
)
2809 src
->maximum_count
= line
->count
;
2812 if (line
->exists
&& add_coverage
)
2814 src
->coverage
.lines
++;
2816 src
->coverage
.lines_executed
++;
2820 /* Accumulate the line counts of a file. */
2823 accumulate_line_counts (source_info
*src
)
2825 /* First work on group functions. */
2826 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
2827 it
!= src
->functions
.end (); it
++)
2829 function_info
*fn
= *it
;
2831 if (fn
->src
!= src
->index
|| !fn
->is_group
)
2834 for (vector
<line_info
>::iterator it2
= fn
->lines
.begin ();
2835 it2
!= fn
->lines
.end (); it2
++)
2837 line_info
*line
= &(*it2
);
2838 accumulate_line_info (line
, src
, true);
2842 /* Work on global lines that line in source file SRC. */
2843 for (vector
<line_info
>::iterator it
= src
->lines
.begin ();
2844 it
!= src
->lines
.end (); it
++)
2845 accumulate_line_info (&(*it
), src
, true);
2847 /* If not using intermediate mode, sum lines of group functions and
2848 add them to lines that live in a source file. */
2849 if (!flag_json_format
)
2850 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
2851 it
!= src
->functions
.end (); it
++)
2853 function_info
*fn
= *it
;
2855 if (fn
->src
!= src
->index
|| !fn
->is_group
)
2858 for (unsigned i
= 0; i
< fn
->lines
.size (); i
++)
2860 line_info
*fn_line
= &fn
->lines
[i
];
2861 if (fn_line
->exists
)
2863 unsigned ln
= fn
->start_line
+ i
;
2864 line_info
*src_line
= &src
->lines
[ln
];
2866 if (!src_line
->exists
)
2867 src
->coverage
.lines
++;
2868 if (!src_line
->count
&& fn_line
->count
)
2869 src
->coverage
.lines_executed
++;
2871 src_line
->count
+= fn_line
->count
;
2872 src_line
->exists
= 1;
2874 if (fn_line
->has_unexecuted_block
)
2875 src_line
->has_unexecuted_block
= 1;
2877 if (fn_line
->unexceptional
)
2878 src_line
->unexceptional
= 1;
2884 /* Output information about ARC number IX. Returns nonzero if
2885 anything is output. */
2888 output_branch_count (FILE *gcov_file
, int ix
, const arc_info
*arc
)
2890 if (arc
->is_call_non_return
)
2892 if (arc
->src
->count
)
2894 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
2895 format_gcov (arc
->src
->count
- arc
->count
,
2896 arc
->src
->count
, -flag_counts
));
2899 fnotice (gcov_file
, "call %2d never executed\n", ix
);
2901 else if (!arc
->is_unconditional
)
2903 if (arc
->src
->count
)
2904 fnotice (gcov_file
, "branch %2d taken %s%s", ix
,
2905 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
2906 arc
->fall_through
? " (fallthrough)"
2907 : arc
->is_throw
? " (throw)" : "");
2909 fnotice (gcov_file
, "branch %2d never executed%s", ix
,
2910 (arc
->fall_through
? " (fallthrough)"
2911 : arc
->is_throw
? " (throw)" : ""));
2914 fnotice (gcov_file
, " (BB %d)", arc
->dst
->id
);
2916 fnotice (gcov_file
, "\n");
2918 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
2920 if (arc
->src
->count
)
2921 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
2922 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
2924 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
2932 read_line (FILE *file
)
2934 static char *string
;
2935 static size_t string_len
;
2941 string
= XNEWVEC (char, string_len
);
2944 while (fgets (string
+ pos
, string_len
- pos
, file
))
2946 size_t len
= strlen (string
+ pos
);
2948 if (len
&& string
[pos
+ len
- 1] == '\n')
2950 string
[pos
+ len
- 1] = 0;
2954 /* If the file contains NUL characters or an incomplete
2955 last line, which can happen more than once in one run,
2956 we have to avoid doubling the STRING_LEN unnecessarily. */
2957 if (pos
> string_len
/ 2)
2960 string
= XRESIZEVEC (char, string
, string_len
);
2964 return pos
? string
: NULL
;
2967 /* Pad string S with spaces from left to have total width equal to 9. */
2970 pad_count_string (string
&s
)
2973 s
.insert (0, 9 - s
.size (), ' ');
2976 /* Print GCOV line beginning to F stream. If EXISTS is set to true, the
2977 line exists in source file. UNEXCEPTIONAL indicated that it's not in
2978 an exceptional statement. The output is printed for LINE_NUM of given
2979 COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
2980 used to indicate non-executed blocks. */
2983 output_line_beginning (FILE *f
, bool exists
, bool unexceptional
,
2984 bool has_unexecuted_block
,
2985 gcov_type count
, unsigned line_num
,
2986 const char *exceptional_string
,
2987 const char *unexceptional_string
,
2988 unsigned int maximum_count
)
2995 s
= format_gcov (count
, 0, -1);
2996 if (has_unexecuted_block
2997 && bbg_supports_has_unexecuted_blocks
)
2999 if (flag_use_colors
)
3001 pad_count_string (s
);
3002 s
.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
3003 COLOR_SEPARATOR COLOR_FG_WHITE
));
3009 pad_count_string (s
);
3013 if (flag_use_colors
)
3016 pad_count_string (s
);
3018 s
.insert (0, SGR_SEQ (COLOR_BG_RED
3019 COLOR_SEPARATOR COLOR_FG_WHITE
));
3021 s
.insert (0, SGR_SEQ (COLOR_BG_CYAN
3022 COLOR_SEPARATOR COLOR_FG_WHITE
));
3027 s
= unexceptional
? unexceptional_string
: exceptional_string
;
3028 pad_count_string (s
);
3035 pad_count_string (s
);
3038 /* Format line number in output. */
3040 sprintf (buffer
, "%5u", line_num
);
3041 string
linestr (buffer
);
3043 if (flag_use_hotness_colors
&& maximum_count
)
3045 if (count
* 2 > maximum_count
) /* > 50%. */
3046 linestr
.insert (0, SGR_SEQ (COLOR_BG_RED
));
3047 else if (count
* 5 > maximum_count
) /* > 20%. */
3048 linestr
.insert (0, SGR_SEQ (COLOR_BG_YELLOW
));
3049 else if (count
* 10 > maximum_count
) /* > 10%. */
3050 linestr
.insert (0, SGR_SEQ (COLOR_BG_GREEN
));
3051 linestr
+= SGR_RESET
;
3054 fprintf (f
, "%s:%s", s
.c_str (), linestr
.c_str ());
3058 print_source_line (FILE *f
, const vector
<const char *> &source_lines
,
3061 gcc_assert (line
>= 1);
3062 gcc_assert (line
<= source_lines
.size ());
3064 fprintf (f
, ":%s\n", source_lines
[line
- 1]);
3067 /* Output line details for LINE and print it to F file. LINE lives on
3071 output_line_details (FILE *f
, const line_info
*line
, unsigned line_num
)
3073 if (flag_all_blocks
)
3077 for (vector
<block_info
*>::const_iterator it
= line
->blocks
.begin ();
3078 it
!= line
->blocks
.end (); it
++)
3080 if (!(*it
)->is_call_return
)
3082 output_line_beginning (f
, line
->exists
,
3083 (*it
)->exceptional
, false,
3084 (*it
)->count
, line_num
,
3085 "%%%%%", "$$$$$", 0);
3086 fprintf (f
, "-block %d", (*it
)->id
);
3088 fprintf (f
, " (BB %u)", (*it
)->id
);
3092 for (arc
= (*it
)->succ
; arc
; arc
= arc
->succ_next
)
3093 jx
+= output_branch_count (f
, jx
, arc
);
3096 else if (flag_branches
)
3101 for (vector
<arc_info
*>::const_iterator it
= line
->branches
.begin ();
3102 it
!= line
->branches
.end (); it
++)
3103 ix
+= output_branch_count (f
, ix
, (*it
));
3107 /* Output detail statistics about function FN to file F. */
3110 output_function_details (FILE *f
, function_info
*fn
)
3115 arc_info
*arc
= fn
->blocks
[EXIT_BLOCK
].pred
;
3116 gcov_type return_count
= fn
->blocks
[EXIT_BLOCK
].count
;
3117 gcov_type called_count
= fn
->blocks
[ENTRY_BLOCK
].count
;
3119 for (; arc
; arc
= arc
->pred_next
)
3121 return_count
-= arc
->count
;
3123 fprintf (f
, "function %s", fn
->get_name ());
3124 fprintf (f
, " called %s",
3125 format_gcov (called_count
, 0, -1));
3126 fprintf (f
, " returned %s",
3127 format_gcov (return_count
, called_count
, 0));
3128 fprintf (f
, " blocks executed %s",
3129 format_gcov (fn
->blocks_executed
, fn
->get_block_count (), 0));
3133 /* Read in the source file one line at a time, and output that line to
3134 the gcov file preceded by its execution count and other
3138 output_lines (FILE *gcov_file
, const source_info
*src
)
3140 #define DEFAULT_LINE_START " -: 0:"
3141 #define FN_SEPARATOR "------------------\n"
3146 /* Print colorization legend. */
3147 if (flag_use_colors
)
3148 fprintf (gcov_file
, "%s",
3149 DEFAULT_LINE_START
"Colorization: profile count: " \
3150 SGR_SEQ (COLOR_BG_CYAN
) "zero coverage (exceptional)" SGR_RESET \
3152 SGR_SEQ (COLOR_BG_RED
) "zero coverage (unexceptional)" SGR_RESET \
3154 SGR_SEQ (COLOR_BG_MAGENTA
) "unexecuted block" SGR_RESET
"\n");
3156 if (flag_use_hotness_colors
)
3157 fprintf (gcov_file
, "%s",
3158 DEFAULT_LINE_START
"Colorization: line numbers: hotness: " \
3159 SGR_SEQ (COLOR_BG_RED
) "> 50%" SGR_RESET
" " \
3160 SGR_SEQ (COLOR_BG_YELLOW
) "> 20%" SGR_RESET
" " \
3161 SGR_SEQ (COLOR_BG_GREEN
) "> 10%" SGR_RESET
"\n");
3163 fprintf (gcov_file
, DEFAULT_LINE_START
"Source:%s\n", src
->coverage
.name
);
3164 if (!multiple_files
)
3166 fprintf (gcov_file
, DEFAULT_LINE_START
"Graph:%s\n", bbg_file_name
);
3167 fprintf (gcov_file
, DEFAULT_LINE_START
"Data:%s\n",
3168 no_data_file
? "-" : da_file_name
);
3169 fprintf (gcov_file
, DEFAULT_LINE_START
"Runs:%u\n", object_runs
);
3172 source_file
= fopen (src
->name
, "r");
3174 fnotice (stderr
, "Cannot open source file %s\n", src
->name
);
3175 else if (src
->file_time
== 0)
3176 fprintf (gcov_file
, DEFAULT_LINE_START
"Source is newer than graph\n");
3178 vector
<const char *> source_lines
;
3180 while ((retval
= read_line (source_file
)) != NULL
)
3181 source_lines
.push_back (xstrdup (retval
));
3183 unsigned line_start_group
= 0;
3184 vector
<function_info
*> *fns
;
3186 for (unsigned line_num
= 1; line_num
<= source_lines
.size (); line_num
++)
3188 if (line_num
>= src
->lines
.size ())
3190 fprintf (gcov_file
, "%9s:%5u", "-", line_num
);
3191 print_source_line (gcov_file
, source_lines
, line_num
);
3195 const line_info
*line
= &src
->lines
[line_num
];
3197 if (line_start_group
== 0)
3199 fns
= src
->get_functions_at_location (line_num
);
3200 if (fns
!= NULL
&& fns
->size () > 1)
3202 /* It's possible to have functions that partially overlap,
3203 thus take the maximum end_line of functions starting
3205 for (unsigned i
= 0; i
< fns
->size (); i
++)
3206 if ((*fns
)[i
]->end_line
> line_start_group
)
3207 line_start_group
= (*fns
)[i
]->end_line
;
3209 else if (fns
!= NULL
&& fns
->size () == 1)
3211 function_info
*fn
= (*fns
)[0];
3212 output_function_details (gcov_file
, fn
);
3216 /* For lines which don't exist in the .bb file, print '-' before
3217 the source line. For lines which exist but were never
3218 executed, print '#####' or '=====' before the source line.
3219 Otherwise, print the execution count before the source line.
3220 There are 16 spaces of indentation added before the source
3221 line so that tabs won't be messed up. */
3222 output_line_beginning (gcov_file
, line
->exists
, line
->unexceptional
,
3223 line
->has_unexecuted_block
, line
->count
,
3224 line_num
, "=====", "#####", src
->maximum_count
);
3226 print_source_line (gcov_file
, source_lines
, line_num
);
3227 output_line_details (gcov_file
, line
, line_num
);
3229 if (line_start_group
== line_num
)
3231 for (vector
<function_info
*>::iterator it
= fns
->begin ();
3232 it
!= fns
->end (); it
++)
3234 function_info
*fn
= *it
;
3235 vector
<line_info
> &lines
= fn
->lines
;
3237 fprintf (gcov_file
, FN_SEPARATOR
);
3239 string fn_name
= fn
->get_name ();
3240 if (flag_use_colors
)
3242 fn_name
.insert (0, SGR_SEQ (COLOR_FG_CYAN
));
3243 fn_name
+= SGR_RESET
;
3246 fprintf (gcov_file
, "%s:\n", fn_name
.c_str ());
3248 output_function_details (gcov_file
, fn
);
3250 /* Print all lines covered by the function. */
3251 for (unsigned i
= 0; i
< lines
.size (); i
++)
3253 line_info
*line
= &lines
[i
];
3254 unsigned l
= fn
->start_line
+ i
;
3256 /* For lines which don't exist in the .bb file, print '-'
3257 before the source line. For lines which exist but
3258 were never executed, print '#####' or '=====' before
3259 the source line. Otherwise, print the execution count
3260 before the source line.
3261 There are 16 spaces of indentation added before the source
3262 line so that tabs won't be messed up. */
3263 output_line_beginning (gcov_file
, line
->exists
,
3264 line
->unexceptional
,
3265 line
->has_unexecuted_block
,
3267 l
, "=====", "#####",
3268 src
->maximum_count
);
3270 print_source_line (gcov_file
, source_lines
, l
);
3271 output_line_details (gcov_file
, line
, l
);
3275 fprintf (gcov_file
, FN_SEPARATOR
);
3276 line_start_group
= 0;
3281 fclose (source_file
);