1 /* Gcov.c: prepend line execution counts and branch probabilities to a
3 Copyright (C) 1990-2025 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"
63 #define GCOV_JSON_FORMAT_VERSION "2"
65 /* The gcno file is generated by -ftest-coverage option. The gcda file is
66 generated by a program compiled with -fprofile-arcs. Their formats
67 are documented in gcov-io.h. */
69 /* The functions in this file for creating and solution program flow graphs
70 are very similar to functions in the gcc source file profile.cc. In
71 some places we make use of the knowledge of how profile.cc works to
72 select particular algorithms here. */
74 /* The code validates that the profile information read in corresponds
75 to the code currently being compiled. Rather than checking for
76 identical files, the code below compares a checksum on the CFG
77 (based on the order of basic blocks and the arcs in the CFG). If
78 the CFG checksum in the gcda file match the CFG checksum in the
79 gcno file, the profile data will be used. */
81 /* This is the size of the buffer used to read in source file lines. */
88 /* Describes an arc between two basic blocks. */
92 /* source and destination blocks. */
93 class block_info
*src
;
94 class block_info
*dst
;
96 /* transition counts. */
98 /* used in cycle search, so that we do not clobber original counts. */
101 unsigned int count_valid
: 1;
102 unsigned int on_tree
: 1;
103 unsigned int fake
: 1;
104 unsigned int fall_through
: 1;
106 /* Arc to a catch handler. */
107 unsigned int is_throw
: 1;
109 /* Arc is for a function that abnormally returns. */
110 unsigned int is_call_non_return
: 1;
112 /* Arc is for catch/setjmp. */
113 unsigned int is_nonlocal_return
: 1;
115 /* Is an unconditional branch. */
116 unsigned int is_unconditional
: 1;
118 /* Loop making arc. */
119 unsigned int cycle
: 1;
122 unsigned int true_value
: 1;
124 /* Is a false arc. */
125 unsigned int false_value
: 1;
127 /* Links to next arc on src and dst lists. */
128 struct arc_info
*succ_next
;
129 struct arc_info
*pred_next
;
132 /* Describes which locations (lines and files) are associated with
135 class block_location_info
138 block_location_info (unsigned _source_file_idx
):
139 source_file_idx (_source_file_idx
)
142 unsigned source_file_idx
;
143 vector
<unsigned> lines
;
146 /* Describes a single conditional expression and the (recorded) conditions
147 shown to independently affect the outcome. */
153 int popcount () const;
155 /* Bitsets storing the independently significant outcomes for true and false,
157 gcov_type_unsigned truev
;
158 gcov_type_unsigned falsev
;
160 /* Number of terms in the expression; if (x) -> 1, if (x && y) -> 2 etc. */
164 condition_info::condition_info (): truev (0), falsev (0), n_terms (0)
168 int condition_info::popcount () const
170 return popcount_hwi (truev
) + popcount_hwi (falsev
);
173 /* Describes a basic block. Contains lists of arcs to successor and
174 predecessor blocks. */
182 /* Chain of exit and entry arcs. */
186 /* Number of unprocessed exit and entry arcs. */
192 /* Block execution count. */
194 unsigned count_valid
: 1;
195 unsigned valid_chain
: 1;
196 unsigned invalid_chain
: 1;
197 unsigned exceptional
: 1;
199 /* Block is a call instrumenting site. */
200 unsigned is_call_site
: 1; /* Does the call. */
201 unsigned is_call_return
: 1; /* Is the return. */
203 /* Block is a landing pad for longjmp or throw. */
204 unsigned is_nonlocal_return
: 1;
206 condition_info conditions
;
208 vector
<block_location_info
> locations
;
212 /* Single line graph cycle workspace. Used for all-blocks
216 } cycle
; /* Used in all-blocks mode, after blocks are linked onto
219 /* Temporary chain for solving graph, and for chaining blocks on one
221 class block_info
*chain
;
225 block_info::block_info (): succ (NULL
), pred (NULL
), num_succ (0), num_pred (0),
226 id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
227 exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
228 locations (), chain (NULL
)
233 /* Describes a single line of source. Contains a chain of basic blocks
239 /* Default constructor. */
242 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
243 bool has_block (block_info
*needle
);
245 /* Execution count. */
248 /* Branches from blocks that end on this line. */
249 vector
<arc_info
*> branches
;
251 /* blocks which start on this line. Used in all-blocks mode. */
252 vector
<block_info
*> blocks
;
255 unsigned unexceptional
: 1;
256 unsigned has_unexecuted_block
: 1;
259 line_info::line_info (): count (0), branches (), blocks (), exists (false),
260 unexceptional (0), has_unexecuted_block (0)
265 line_info::has_block (block_info
*needle
)
267 return std::find (blocks
.begin (), blocks
.end (), needle
) != blocks
.end ();
270 /* Output demangled function names. */
272 static int flag_demangled_names
= 0;
274 /* Describes a single function. Contains an array of basic blocks. */
282 /* Return true when line N belongs to the function in source file SRC_IDX.
283 The line must be defined in body of the function, can't be inlined. */
284 bool group_line_p (unsigned n
, unsigned src_idx
);
286 /* Function filter based on function_info::artificial variable. */
289 is_artificial (function_info
*fn
)
291 return fn
->artificial
;
294 /* Name of function. */
296 char *m_demangled_name
;
298 unsigned lineno_checksum
;
299 unsigned cfg_checksum
;
301 /* The graph contains at least one fake incoming edge. */
302 unsigned has_catch
: 1;
304 /* True when the function is artificial and does not exist
306 unsigned artificial
: 1;
308 /* True when multiple functions start at a line in a source file. */
309 unsigned is_group
: 1;
311 /* Array of basic blocks. Like in GCC, the entry block is
312 at blocks[0] and the exit block is at blocks[1]. */
313 #define ENTRY_BLOCK (0)
314 #define EXIT_BLOCK (1)
315 vector
<block_info
> blocks
;
316 unsigned blocks_executed
;
318 vector
<condition_info
*> conditions
;
320 /* Raw arc coverage counts. */
321 vector
<gcov_type
> counts
;
323 /* First line number. */
326 /* First line column. */
327 unsigned start_column
;
329 /* Last line number. */
332 /* Last line column. */
335 /* Index of source file where the function is defined. */
338 /* Vector of line information (used only for group functions). */
339 vector
<line_info
> lines
;
342 class function_info
*next
;
344 /* Get demangled name of a function. The demangled name
345 is converted when it is used for the first time. */
346 char *get_demangled_name ()
348 if (m_demangled_name
== NULL
)
350 m_demangled_name
= cplus_demangle (m_name
, DMGL_PARAMS
);
351 if (!m_demangled_name
)
352 m_demangled_name
= m_name
;
355 return m_demangled_name
;
358 /* Get name of the function based on flag_demangled_names. */
361 return flag_demangled_names
? get_demangled_name () : m_name
;
364 /* Return number of basic blocks (without entry and exit block). */
365 unsigned get_block_count ()
367 return blocks
.size () - 2;
371 /* Function info comparer that will sort functions according to starting
374 struct function_line_start_cmp
376 inline bool operator() (const function_info
*lhs
,
377 const function_info
*rhs
)
379 return (lhs
->start_line
== rhs
->start_line
380 ? lhs
->start_column
< rhs
->start_column
381 : lhs
->start_line
< rhs
->start_line
);
385 /* Describes coverage of a file or function. */
393 int branches_executed
;
397 int conditions_covered
;
405 /* Describes a file mentioned in the block graph. Contains an array
411 /* Default constructor. */
414 vector
<function_info
*> *get_functions_at_location (unsigned line_num
) const;
416 /* Register a new function. */
417 void add_function (function_info
*fn
);
419 /* Debug the source file. */
422 /* Index of the source_info in sources vector. */
425 /* Canonical name of source file. */
429 /* Vector of line information. */
430 vector
<line_info
> lines
;
432 coverage_info coverage
;
434 /* Maximum line count in the source file. */
435 unsigned int maximum_count
;
437 /* Functions in this source file. These are in ascending line
439 vector
<function_info
*> functions
;
441 /* Line number to functions map. */
442 vector
<vector
<function_info
*> *> line_to_function_map
;
445 source_info::source_info (): index (0), name (NULL
), file_time (),
446 lines (), coverage (), maximum_count (0), functions ()
450 /* Register a new function. */
452 source_info::add_function (function_info
*fn
)
454 functions
.push_back (fn
);
456 if (fn
->start_line
>= line_to_function_map
.size ())
457 line_to_function_map
.resize (fn
->start_line
+ 1);
459 vector
<function_info
*> **slot
= &line_to_function_map
[fn
->start_line
];
461 *slot
= new vector
<function_info
*> ();
463 (*slot
)->push_back (fn
);
466 vector
<function_info
*> *
467 source_info::get_functions_at_location (unsigned line_num
) const
469 if (line_num
>= line_to_function_map
.size ())
472 vector
<function_info
*> *slot
= line_to_function_map
[line_num
];
474 std::sort (slot
->begin (), slot
->end (), function_line_start_cmp ());
479 void source_info::debug ()
481 fprintf (stderr
, "source_info: %s\n", name
);
482 for (vector
<function_info
*>::iterator it
= functions
.begin ();
483 it
!= functions
.end (); it
++)
485 function_info
*fn
= *it
;
486 fprintf (stderr
, " function_info: %s\n", fn
->get_name ());
487 for (vector
<block_info
>::iterator bit
= fn
->blocks
.begin ();
488 bit
!= fn
->blocks
.end (); bit
++)
490 fprintf (stderr
, " block_info id=%d, count=%" PRId64
" \n",
491 bit
->id
, bit
->count
);
495 for (unsigned lineno
= 1; lineno
< lines
.size (); ++lineno
)
497 line_info
&line
= lines
[lineno
];
498 fprintf (stderr
, " line_info=%d, count=%" PRId64
"\n", lineno
, line
.count
);
501 fprintf (stderr
, "\n");
511 name_map (char *_name
, unsigned _src
): name (_name
), src (_src
)
515 bool operator== (const name_map
&rhs
) const
517 #if HAVE_DOS_BASED_FILE_SYSTEM
518 return strcasecmp (this->name
, rhs
.name
) == 0;
520 return strcmp (this->name
, rhs
.name
) == 0;
524 bool operator< (const name_map
&rhs
) const
526 #if HAVE_DOS_BASED_FILE_SYSTEM
527 return strcasecmp (this->name
, rhs
.name
) < 0;
529 return strcmp (this->name
, rhs
.name
) < 0;
533 const char *name
; /* Source file name */
534 unsigned src
; /* Source file */
537 /* Vector of all functions. */
538 static vector
<function_info
*> functions
;
540 /* Function ident to function_info * map. */
541 static map
<unsigned, function_info
*> ident_to_fn
;
543 /* Vector of source files. */
544 static vector
<source_info
> sources
;
546 /* Mapping of file names to sources */
547 static vector
<name_map
> names
;
549 /* Record all processed files in order to warn about
550 a file being read multiple times. */
551 static vector
<char *> processed_files
;
553 /* The contents of a source file. The nth SOURCE_LINES entry is the
554 contents of the nth SOURCES, or empty if it has not or could not be
556 static vector
<vector
<const char *>*> source_lines
;
558 /* This holds data summary information. */
560 static unsigned object_runs
;
562 static unsigned total_lines
;
563 static unsigned total_executed
;
565 /* Modification time of graph file. */
567 static time_t bbg_file_time
;
569 /* Name of the notes (gcno) output file. The "bbg" prefix is for
570 historical reasons, when the notes file contained only the
571 basic block graph notes. */
573 static char *bbg_file_name
;
575 /* Stamp of the bbg file */
576 static unsigned bbg_stamp
;
578 /* Supports has_unexecuted_blocks functionality. */
579 static unsigned bbg_supports_has_unexecuted_blocks
;
581 /* Working directory in which a TU was compiled. */
582 static const char *bbg_cwd
;
584 /* Name and file pointer of the input file for the count data (gcda). */
586 static char *da_file_name
;
588 /* Data file is missing. */
590 static int no_data_file
;
592 /* If there is several input files, compute and display results after
593 reading all data files. This way if two or more gcda file refer to
594 the same source file (eg inline subprograms in a .h file), the
597 static int multiple_files
= 0;
599 /* Output branch probabilities. */
601 static int flag_branches
= 0;
603 /* Output conditions (modified condition/decision coverage). */
605 static bool flag_conditions
= 0;
607 /* Show unconditional branches too. */
608 static int flag_unconditional
= 0;
610 /* Output a gcov file if this is true. This is on by default, and can
611 be turned off by the -n option. */
613 static int flag_gcov_file
= 1;
615 /* Output to stdout instead to a gcov file. */
617 static int flag_use_stdout
= 0;
619 /* Output progress indication if this is true. This is off by default
620 and can be turned on by the -d option. */
622 static int flag_display_progress
= 0;
624 /* Output *.gcov file in JSON intermediate format used by consumers. */
626 static int flag_json_format
= 0;
628 /* For included files, make the gcov output file name include the name
629 of the input source file. For example, if x.h is included in a.c,
630 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
632 static int flag_long_names
= 0;
634 /* For situations when a long name can potentially hit filesystem path limit,
635 let's calculate md5sum of the path and append it to a file name. */
637 static int flag_hash_filenames
= 0;
639 /* Print verbose informations. */
641 static int flag_verbose
= 0;
643 /* Print colored output. */
645 static int flag_use_colors
= 0;
647 /* Use perf-like colors to indicate hot lines. */
649 static int flag_use_hotness_colors
= 0;
651 /* Output count information for every basic block, not merely those
652 that contain line number information. */
654 static int flag_all_blocks
= 0;
656 /* Output human readable numbers. */
658 static int flag_human_readable_numbers
= 0;
660 /* Output summary info for each function. */
662 static int flag_function_summary
= 0;
664 /* Print debugging dumps. */
666 static int flag_debug
= 0;
668 /* Object directory file prefix. This is the directory/file where the
669 graph and data files are looked for, if nonzero. */
671 static char *object_directory
= 0;
673 /* Source directory prefix. This is removed from source pathnames
674 that match, when generating the output file name. */
676 static char *source_prefix
= 0;
677 static size_t source_length
= 0;
679 /* Only show data for sources with relative pathnames. Absolute ones
680 usually indicate a system header file, which although it may
681 contain inline functions, is usually uninteresting. */
682 static int flag_relative_only
= 0;
684 /* Preserve all pathname components. Needed when object files and
685 source files are in subdirectories. '/' is mangled as '#', '.' is
686 elided and '..' mangled to '^'. */
688 static int flag_preserve_paths
= 0;
690 /* Output the number of times a branch was taken as opposed to the percentage
691 of times it was taken. */
693 static int flag_counts
= 0;
695 /* Return code of the tool invocation. */
696 static int return_code
= 0;
698 /* "Keep policy" when adding functions to the global function table. This will
699 be set to false when --include is used, otherwise every function should be
700 added to the table. Used for --include/exclude. */
701 static bool default_keep
= true;
703 /* Include/exclude filters function based on matching the (de)mangled name.
704 The default is to match the mangled name. Note that flag_demangled_names
705 does not affect this. */
706 static bool flag_filter_on_demangled
= false;
708 /* A 'function filter', a filter and action for determining if a function
709 should be included in the output or not. Used for --include/--exclude
713 /* The (extended) compiled regex for this filter. */
716 /* The action when this filter (regex) matches - if true, the function should
717 be kept, otherwise discarded. */
720 /* Compile the regex EXPR, or exit if pattern is malformed. */
721 void compile (const char *expr
)
723 int err
= regcomp (®ex
, expr
, REG_NOSUB
| REG_EXTENDED
);
726 size_t len
= regerror (err
, ®ex
, nullptr, 0);
727 char *msg
= XNEWVEC (char, len
);
728 regerror (err
, ®ex
, msg
, len
);
729 fprintf (stderr
, "Bad regular expression: %s\n", msg
);
736 /* A collection of filter functions for including/exclude functions in the
737 output. This is empty unless --include/--exclude is used. */
738 static vector
<fnfilter
> filters
;
740 /* Forward declarations. */
741 static int process_args (int, char **);
742 static void print_usage (int) ATTRIBUTE_NORETURN
;
743 static void print_version (void) ATTRIBUTE_NORETURN
;
744 static void process_file (const char *);
745 static void process_all_functions (void);
746 static void generate_results (const char *);
747 static void create_file_names (const char *);
748 static char *canonicalize_name (const char *);
749 static unsigned find_source (const char *);
750 static void read_graph_file (void);
751 static int read_count_file (void);
752 static void solve_flow_graph (function_info
*);
753 static void find_exception_blocks (function_info
*);
754 static void add_branch_counts (coverage_info
*, const arc_info
*);
755 static void add_condition_counts (coverage_info
*, const block_info
*);
756 static void add_line_counts (coverage_info
*, function_info
*);
757 static void executed_summary (unsigned, unsigned);
758 static void function_summary (const coverage_info
*);
759 static void file_summary (const coverage_info
*);
760 static const char *format_gcov (gcov_type
, gcov_type
, int);
761 static void accumulate_line_counts (source_info
*);
762 static void output_gcov_file (const char *, source_info
*);
763 static int output_branch_count (FILE *, int, const arc_info
*);
764 static void output_conditions (FILE *, const block_info
*);
765 static void output_lines (FILE *, const source_info
*);
766 static string
make_gcov_file_name (const char *, const char *);
767 static char *mangle_name (const char *);
768 static void release_structures (void);
769 extern int main (int, char **);
770 static const vector
<const char *>&
771 slurp (const source_info
&src
, FILE *gcov_file
, const char *line_start
);
773 function_info::function_info (): m_name (NULL
), m_demangled_name (NULL
),
774 ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
775 artificial (0), is_group (0),
776 blocks (), blocks_executed (0), counts (),
777 start_line (0), start_column (0), end_line (0), end_column (0),
778 src (0), lines (), next (NULL
)
782 function_info::~function_info ()
784 for (int i
= blocks
.size () - 1; i
>= 0; i
--)
786 arc_info
*arc
, *arc_n
;
788 for (arc
= blocks
[i
].succ
; arc
; arc
= arc_n
)
790 arc_n
= arc
->succ_next
;
794 if (m_demangled_name
!= m_name
)
795 free (m_demangled_name
);
799 bool function_info::group_line_p (unsigned n
, unsigned src_idx
)
801 return is_group
&& src
== src_idx
&& start_line
<= n
&& n
<= end_line
;
805 There are a bajillion algorithms that do this. Boost's function is named
806 hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
807 "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
808 (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
810 The basic algorithm is simple: effectively, we're finding all simple paths
811 in a subgraph (that shrinks every iteration). Duplicates are filtered by
812 "blocking" a path when a node is added to the path (this also prevents non-
813 simple paths)--the node is unblocked only when it participates in a cycle.
816 typedef vector
<arc_info
*> arc_vector_t
;
817 typedef vector
<const block_info
*> block_vector_t
;
819 /* Handle cycle identified by EDGES, where the function finds minimum cs_count
820 and subtract the value from all counts. The subtracted value is added
821 to COUNT. Returns type of loop. */
824 handle_cycle (const arc_vector_t
&edges
, int64_t &count
)
826 /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
828 int64_t cycle_count
= INTTYPE_MAXIMUM (int64_t);
829 for (unsigned i
= 0; i
< edges
.size (); i
++)
831 int64_t ecount
= edges
[i
]->cs_count
;
832 if (cycle_count
> ecount
)
833 cycle_count
= ecount
;
835 count
+= cycle_count
;
836 for (unsigned i
= 0; i
< edges
.size (); i
++)
837 edges
[i
]->cs_count
-= cycle_count
;
839 gcc_assert (cycle_count
> 0);
842 /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
843 blocked by U in BLOCK_LISTS. */
846 unblock (const block_info
*u
, block_vector_t
&blocked
,
847 vector
<block_vector_t
> &block_lists
)
849 block_vector_t::iterator it
= find (blocked
.begin (), blocked
.end (), u
);
850 if (it
== blocked
.end ())
853 unsigned index
= it
- blocked
.begin ();
856 block_vector_t
to_unblock (block_lists
[index
]);
858 block_lists
.erase (block_lists
.begin () + index
);
860 for (block_vector_t::iterator it
= to_unblock
.begin ();
861 it
!= to_unblock
.end (); it
++)
862 unblock (*it
, blocked
, block_lists
);
865 /* Return true when PATH contains a zero cycle arc count. */
868 path_contains_zero_or_negative_cycle_arc (arc_vector_t
&path
)
870 for (unsigned i
= 0; i
< path
.size (); i
++)
871 if (path
[i
]->cs_count
<= 0)
876 /* Find circuit going to block V, PATH is provisional seen cycle.
877 BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
878 blocked by a block. COUNT is accumulated count of the current LINE.
879 Returns what type of loop it contains. */
882 circuit (block_info
*v
, arc_vector_t
&path
, block_info
*start
,
883 block_vector_t
&blocked
, vector
<block_vector_t
> &block_lists
,
884 line_info
&linfo
, int64_t &count
)
886 bool loop_found
= false;
888 /* Add v to the block list. */
889 gcc_assert (find (blocked
.begin (), blocked
.end (), v
) == blocked
.end ());
890 blocked
.push_back (v
);
891 block_lists
.push_back (block_vector_t ());
893 for (arc_info
*arc
= v
->succ
; arc
; arc
= arc
->succ_next
)
895 block_info
*w
= arc
->dst
;
897 || arc
->cs_count
<= 0
898 || !linfo
.has_block (w
))
901 path
.push_back (arc
);
904 /* Cycle has been found. */
905 handle_cycle (path
, count
);
908 else if (!path_contains_zero_or_negative_cycle_arc (path
)
909 && find (blocked
.begin (), blocked
.end (), w
) == blocked
.end ())
910 loop_found
|= circuit (w
, path
, start
, blocked
, block_lists
, linfo
,
917 unblock (v
, blocked
, block_lists
);
919 for (arc_info
*arc
= v
->succ
; arc
; arc
= arc
->succ_next
)
921 block_info
*w
= arc
->dst
;
923 || arc
->cs_count
<= 0
924 || !linfo
.has_block (w
))
928 = find (blocked
.begin (), blocked
.end (), w
) - blocked
.begin ();
929 gcc_assert (index
< blocked
.size ());
930 block_vector_t
&list
= block_lists
[index
];
931 if (find (list
.begin (), list
.end (), v
) == list
.end ())
938 /* Find cycles for a LINFO. */
941 get_cycles_count (line_info
&linfo
)
943 /* Note that this algorithm works even if blocks aren't in sorted order.
944 Each iteration of the circuit detection is completely independent
945 (except for reducing counts, but that shouldn't matter anyways).
946 Therefore, operating on a permuted order (i.e., non-sorted) only
947 has the effect of permuting the output cycles. */
950 for (vector
<block_info
*>::iterator it
= linfo
.blocks
.begin ();
951 it
!= linfo
.blocks
.end (); it
++)
954 block_vector_t blocked
;
955 vector
<block_vector_t
> block_lists
;
956 circuit (*it
, path
, *it
, blocked
, block_lists
, linfo
, count
);
963 main (int argc
, char **argv
)
969 p
= argv
[0] + strlen (argv
[0]);
970 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
974 xmalloc_set_program_name (progname
);
976 /* Unlock the stdio streams. */
977 unlock_std_streams ();
981 diagnostic_initialize (global_dc
, 0);
983 /* Handle response files. */
984 expandargv (&argc
, &argv
);
986 argno
= process_args (argc
, argv
);
990 if (argc
- argno
> 1)
995 for (; argno
!= argc
; argno
++)
997 if (flag_display_progress
)
998 printf ("Processing file %d out of %d\n", argno
- first_arg
+ 1,
1000 process_file (argv
[argno
]);
1002 if (flag_json_format
|| argno
== argc
- 1)
1004 process_all_functions ();
1005 generate_results (argv
[argno
]);
1006 release_structures ();
1010 if (!flag_use_stdout
)
1011 executed_summary (total_lines
, total_executed
);
1016 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
1017 otherwise the output of --help. */
1020 print_usage (int error_p
)
1022 FILE *file
= error_p
? stderr
: stdout
;
1023 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
1025 fnotice (file
, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
1026 fnotice (file
, "Print code coverage information.\n\n");
1027 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
1028 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
1029 fnotice (file
, " -c, --branch-counts Output counts of branches taken\n\
1030 rather than percentages\n");
1031 fnotice (file
, " -g, --conditions Include modified condition/decision\n\
1032 coverage (masking MC/DC) in output\n");
1033 fnotice (file
, " -d, --display-progress Display progress information\n");
1034 fnotice (file
, " -D, --debug Display debugging dumps\n");
1035 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
1036 fnotice (file
, " --include Include functions matching this regex\n");
1037 fnotice (file
, " --exclude Exclude functions matching this regex\n");
1038 fnotice (file
, " -h, --help Print this help, then exit\n");
1039 fnotice (file
, " -j, --json-format Output JSON intermediate format\n\
1040 into .gcov.json.gz file\n");
1041 fnotice (file
, " -H, --human-readable Output human readable numbers\n");
1042 fnotice (file
, " -k, --use-colors Emit colored output\n");
1043 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
1045 fnotice (file
, " -m, --demangled-names Output demangled function names\n");
1046 fnotice (file
, " -M, --filter-on-demangled Make --include/--exclude match on demangled\n\
1047 names. This does not imply -m\n");
1048 fnotice (file
, " -n, --no-output Do not create an output file\n");
1049 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
1050 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
1051 fnotice (file
, " -q, --use-hotness-colors Emit perf-like colored output for hot lines\n");
1052 fnotice (file
, " -r, --relative-only Only show data for relative sources\n");
1053 fnotice (file
, " -s, --source-prefix DIR Source prefix to elide\n");
1054 fnotice (file
, " -t, --stdout Output to stdout instead of a file\n");
1055 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
1056 fnotice (file
, " -v, --version Print version number, then exit\n");
1057 fnotice (file
, " -w, --verbose Print verbose informations\n");
1058 fnotice (file
, " -x, --hash-filenames Hash long pathnames\n");
1059 fnotice (file
, "\nObsolete options:\n");
1060 fnotice (file
, " -i, --json-format Replaced with -j, --json-format\n");
1061 fnotice (file
, " -j, --human-readable Replaced with -H, --human-readable\n");
1062 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
1067 /* Print version information and exit. */
1070 print_version (void)
1072 fnotice (stdout
, "gcov %s%s\n", pkgversion_string
, version_string
);
1073 fnotice (stdout
, "JSON format version: %s\n", GCOV_JSON_FORMAT_VERSION
);
1074 fprintf (stdout
, "Copyright %s 2025 Free Software Foundation, Inc.\n",
1077 _("This is free software; see the source for copying conditions. There is NO\n\
1078 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
1079 exit (SUCCESS_EXIT_CODE
);
1082 static const struct option options
[] =
1084 { "help", no_argument
, NULL
, 'h' },
1085 { "version", no_argument
, NULL
, 'v' },
1086 { "verbose", no_argument
, NULL
, 'w' },
1087 { "all-blocks", no_argument
, NULL
, 'a' },
1088 { "branch-probabilities", no_argument
, NULL
, 'b' },
1089 { "branch-counts", no_argument
, NULL
, 'c' },
1090 { "conditions", no_argument
, NULL
, 'g' },
1091 { "json-format", no_argument
, NULL
, 'j' },
1092 { "include", required_argument
, NULL
, 'I' },
1093 { "exclude", required_argument
, NULL
, 'E' },
1094 { "human-readable", no_argument
, NULL
, 'H' },
1095 { "no-output", no_argument
, NULL
, 'n' },
1096 { "long-file-names", no_argument
, NULL
, 'l' },
1097 { "function-summaries", no_argument
, NULL
, 'f' },
1098 { "demangled-names", no_argument
, NULL
, 'm' },
1099 { "filter-on-demangled", no_argument
, NULL
, 'M' },
1100 { "preserve-paths", no_argument
, NULL
, 'p' },
1101 { "relative-only", no_argument
, NULL
, 'r' },
1102 { "object-directory", required_argument
, NULL
, 'o' },
1103 { "object-file", required_argument
, NULL
, 'o' },
1104 { "source-prefix", required_argument
, NULL
, 's' },
1105 { "stdout", no_argument
, NULL
, 't' },
1106 { "unconditional-branches", no_argument
, NULL
, 'u' },
1107 { "display-progress", no_argument
, NULL
, 'd' },
1108 { "hash-filenames", no_argument
, NULL
, 'x' },
1109 { "use-colors", no_argument
, NULL
, 'k' },
1110 { "use-hotness-colors", no_argument
, NULL
, 'q' },
1111 { "debug", no_argument
, NULL
, 'D' },
1115 /* Process args, return index to first non-arg. */
1118 process_args (int argc
, char **argv
)
1122 const char *opts
= "abcdDfghHijklmMno:pqrs:tuvwx";
1123 while ((opt
= getopt_long (argc
, argv
, opts
, options
, NULL
)) != -1)
1128 flag_all_blocks
= 1;
1137 flag_function_summary
= 1;
1140 flag_conditions
= 1;
1143 print_usage (false);
1144 /* print_usage will exit. */
1146 flag_long_names
= 1;
1149 default_keep
= false;
1150 filters
.push_back (fnfilter
{});
1151 filters
.back ().keep
= true;
1152 filters
.back ().compile (optarg
);
1155 filters
.push_back (fnfilter
{});
1156 filters
.back ().keep
= false;
1157 filters
.back ().compile (optarg
);
1160 flag_human_readable_numbers
= 1;
1163 flag_use_colors
= 1;
1166 flag_use_hotness_colors
= 1;
1169 flag_demangled_names
= 1;
1172 flag_filter_on_demangled
= true;
1178 object_directory
= optarg
;
1181 source_prefix
= optarg
;
1182 source_length
= strlen (source_prefix
);
1185 flag_relative_only
= 1;
1188 flag_preserve_paths
= 1;
1191 flag_unconditional
= 1;
1195 flag_json_format
= 1;
1199 flag_display_progress
= 1;
1202 flag_hash_filenames
= 1;
1208 flag_use_stdout
= 1;
1215 /* print_version will exit. */
1218 /* print_usage will exit. */
1225 /* Output intermediate LINE sitting on LINE_NUM to JSON OBJECT.
1226 Add FUNCTION_NAME to the LINE. */
1229 output_intermediate_json_line (json::array
*object
,
1230 line_info
*line
, unsigned line_num
,
1231 const char *function_name
)
1236 json::object
*lineo
= new json::object ();
1237 lineo
->set_integer ("line_number", line_num
);
1238 if (function_name
!= NULL
)
1239 lineo
->set_string ("function_name", function_name
);
1240 lineo
->set_integer ("count", line
->count
);
1241 lineo
->set_bool ("unexecuted_block", line
->has_unexecuted_block
);
1243 json::array
*bb_ids
= new json::array ();
1244 for (const block_info
*block
: line
->blocks
)
1245 bb_ids
->append (new json::integer_number (block
->id
));
1246 lineo
->set ("block_ids", bb_ids
);
1248 json::array
*branches
= new json::array ();
1249 lineo
->set ("branches", branches
);
1251 json::array
*calls
= new json::array ();
1252 lineo
->set ("calls", calls
);
1254 vector
<arc_info
*>::const_iterator it
;
1256 for (it
= line
->branches
.begin (); it
!= line
->branches
.end ();
1259 if (!(*it
)->is_unconditional
&& !(*it
)->is_call_non_return
)
1261 json::object
*branch
= new json::object ();
1262 branch
->set_integer ("count", (*it
)->count
);
1263 branch
->set_bool ("throw", (*it
)->is_throw
);
1264 branch
->set_bool ("fallthrough", (*it
)->fall_through
);
1265 branch
->set_integer ("source_block_id", (*it
)->src
->id
);
1266 branch
->set_integer ("destination_block_id", (*it
)->dst
->id
);
1267 branches
->append (branch
);
1269 else if ((*it
)->is_call_non_return
)
1271 json::object
*call
= new json::object ();
1272 gcov_type returns
= (*it
)->src
->count
- (*it
)->count
;
1273 call
->set_integer ("source_block_id", (*it
)->src
->id
);
1274 call
->set_integer ("destination_block_id", (*it
)->dst
->id
);
1275 call
->set_integer ("returned", returns
);
1276 calls
->append (call
);
1280 json::array
*conditions
= new json::array ();
1281 lineo
->set ("conditions", conditions
);
1282 if (flag_conditions
)
1284 vector
<block_info
*>::const_iterator it
;
1285 for (it
= line
->blocks
.begin (); it
!= line
->blocks
.end (); it
++)
1287 const condition_info
& info
= (*it
)->conditions
;
1288 if (info
.n_terms
== 0)
1291 const int count
= 2 * info
.n_terms
;
1292 const int covered
= info
.popcount ();
1294 json::object
*cond
= new json::object ();
1295 cond
->set_integer ("count", count
);
1296 cond
->set_integer ("covered", covered
);
1298 json::array
*mtrue
= new json::array ();
1299 json::array
*mfalse
= new json::array ();
1300 cond
->set ("not_covered_true", mtrue
);
1301 cond
->set ("not_covered_false", mfalse
);
1303 if (count
!= covered
)
1305 for (unsigned i
= 0; i
< info
.n_terms
; i
++)
1307 gcov_type_unsigned index
= 1;
1309 if (!(index
& info
.truev
))
1310 mtrue
->append (new json::integer_number (i
));
1311 if (!(index
& info
.falsev
))
1312 mfalse
->append (new json::integer_number (i
));
1315 conditions
->append (cond
);
1319 object
->append (lineo
);
1322 /* Strip filename extension in STR. */
1325 strip_extention (string str
)
1327 string::size_type pos
= str
.rfind ('.');
1328 if (pos
!= string::npos
)
1329 str
= str
.substr (0, pos
);
1334 /* Calcualte md5sum for INPUT string and return it in hex string format. */
1337 get_md5sum (const char *input
)
1343 md5_init_ctx (&ctx
);
1344 md5_process_bytes (input
, strlen (input
), &ctx
);
1345 md5_finish_ctx (&ctx
, md5sum
);
1347 for (unsigned i
= 0; i
< 16; i
++)
1350 sprintf (b
, "%02x", (unsigned char)md5sum
[i
]);
1357 /* Get the name of the gcov file. The return value must be free'd.
1359 It appends the '.gcov' extension to the *basename* of the file.
1360 The resulting file name will be in PWD.
1363 input: foo.da, output: foo.da.gcov
1364 input: a/b/foo.cc, output: foo.cc.gcov */
1367 get_gcov_intermediate_filename (const char *input_file_name
)
1369 string base
= basename (input_file_name
);
1370 string str
= strip_extention (base
);
1372 if (flag_hash_filenames
)
1375 str
+= get_md5sum (input_file_name
);
1377 else if (flag_preserve_paths
&& base
!= input_file_name
)
1380 str
+= mangle_path (input_file_name
);
1381 str
= strip_extention (str
);
1384 str
+= ".gcov.json.gz";
1385 return str
.c_str ();
1388 /* Output the result in JSON intermediate format.
1389 Source info SRC is dumped into JSON_FILES which is JSON array. */
1392 output_json_intermediate_file (json::array
*json_files
, source_info
*src
)
1394 json::object
*root
= new json::object ();
1395 json_files
->append (root
);
1397 root
->set_string ("file", src
->name
);
1399 json::array
*functions
= new json::array ();
1400 root
->set ("functions", functions
);
1402 std::sort (src
->functions
.begin (), src
->functions
.end (),
1403 function_line_start_cmp ());
1404 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
1405 it
!= src
->functions
.end (); it
++)
1407 json::object
*function
= new json::object ();
1408 function
->set_string ("name", (*it
)->m_name
);
1409 function
->set_string ("demangled_name", (*it
)->get_demangled_name ());
1410 function
->set_integer ("start_line", (*it
)->start_line
);
1411 function
->set_integer ("start_column", (*it
)->start_column
);
1412 function
->set_integer ("end_line", (*it
)->end_line
);
1413 function
->set_integer ("end_column", (*it
)->end_column
);
1414 function
->set_integer ("blocks", (*it
)->get_block_count ());
1415 function
->set_integer ("blocks_executed", (*it
)->blocks_executed
);
1416 function
->set_integer ("execution_count", (*it
)->blocks
[0].count
);
1418 functions
->append (function
);
1421 json::array
*lineso
= new json::array ();
1422 root
->set ("lines", lineso
);
1424 vector
<function_info
*> last_non_group_fns
;
1426 for (unsigned line_num
= 1; line_num
<= src
->lines
.size (); line_num
++)
1428 vector
<function_info
*> *fns
= src
->get_functions_at_location (line_num
);
1431 /* Print info for all group functions that begin on the line. */
1432 for (vector
<function_info
*>::iterator it2
= fns
->begin ();
1433 it2
!= fns
->end (); it2
++)
1435 if (!(*it2
)->is_group
)
1436 last_non_group_fns
.push_back (*it2
);
1438 vector
<line_info
> &lines
= (*it2
)->lines
;
1439 /* The LINES array is allocated only for group functions. */
1440 for (unsigned i
= 0; i
< lines
.size (); i
++)
1442 line_info
*line
= &lines
[i
];
1443 output_intermediate_json_line (lineso
, line
, line_num
+ i
,
1448 /* Follow with lines associated with the source file. */
1449 if (line_num
< src
->lines
.size ())
1451 unsigned size
= last_non_group_fns
.size ();
1452 function_info
*last_fn
= size
> 0 ? last_non_group_fns
[size
- 1] : NULL
;
1453 const char *fname
= last_fn
? last_fn
->m_name
: NULL
;
1454 output_intermediate_json_line (lineso
, &src
->lines
[line_num
], line_num
,
1457 /* Pop ending function from stack. */
1458 if (last_fn
!= NULL
&& last_fn
->end_line
== line_num
)
1459 last_non_group_fns
.pop_back ();
1464 /* Function start pair. */
1465 struct function_start
1467 unsigned source_file_idx
;
1468 unsigned start_line
;
1471 /* Traits class for function start hash maps below. */
1473 struct function_start_pair_hash
: typed_noop_remove
<function_start
>
1475 typedef function_start value_type
;
1476 typedef function_start compare_type
;
1479 hash (const function_start
&ref
)
1481 inchash::hash
hstate (0);
1482 hstate
.add_int (ref
.source_file_idx
);
1483 hstate
.add_int (ref
.start_line
);
1484 return hstate
.end ();
1488 equal (const function_start
&ref1
, const function_start
&ref2
)
1490 return (ref1
.source_file_idx
== ref2
.source_file_idx
1491 && ref1
.start_line
== ref2
.start_line
);
1495 mark_deleted (function_start
&ref
)
1497 ref
.start_line
= ~1U;
1500 static const bool empty_zero_p
= false;
1503 mark_empty (function_start
&ref
)
1505 ref
.start_line
= ~2U;
1509 is_deleted (const function_start
&ref
)
1511 return ref
.start_line
== ~1U;
1515 is_empty (const function_start
&ref
)
1517 return ref
.start_line
== ~2U;
1521 /* Process a single input file. */
1524 process_file (const char *file_name
)
1526 create_file_names (file_name
);
1528 for (unsigned i
= 0; i
< processed_files
.size (); i
++)
1529 if (strcmp (da_file_name
, processed_files
[i
]) == 0)
1531 fnotice (stderr
, "'%s' file is already processed\n",
1536 processed_files
.push_back (xstrdup (da_file_name
));
1542 /* Process all functions in all files. */
1545 process_all_functions (void)
1547 hash_map
<function_start_pair_hash
, function_info
*> fn_map
;
1549 /* Identify group functions. */
1550 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1551 it
!= functions
.end (); it
++)
1552 if (!(*it
)->artificial
)
1554 function_start needle
;
1555 needle
.source_file_idx
= (*it
)->src
;
1556 needle
.start_line
= (*it
)->start_line
;
1558 function_info
**slot
= fn_map
.get (needle
);
1561 (*slot
)->is_group
= 1;
1562 (*it
)->is_group
= 1;
1565 fn_map
.put (needle
, *it
);
1568 /* Remove all artificial function. */
1569 functions
.erase (remove_if (functions
.begin (), functions
.end (),
1570 function_info::is_artificial
), functions
.end ());
1572 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1573 it
!= functions
.end (); it
++)
1575 function_info
*fn
= *it
;
1576 unsigned src
= fn
->src
;
1578 if (!fn
->counts
.empty () || no_data_file
)
1580 source_info
*s
= &sources
[src
];
1581 s
->add_function (fn
);
1583 /* Mark last line in files touched by function. */
1584 for (unsigned block_no
= 0; block_no
!= fn
->blocks
.size ();
1587 block_info
*block
= &fn
->blocks
[block_no
];
1588 for (unsigned i
= 0; i
< block
->locations
.size (); i
++)
1590 /* Sort lines of locations. */
1591 sort (block
->locations
[i
].lines
.begin (),
1592 block
->locations
[i
].lines
.end ());
1594 if (!block
->locations
[i
].lines
.empty ())
1596 s
= &sources
[block
->locations
[i
].source_file_idx
];
1598 = block
->locations
[i
].lines
.back ();
1600 /* Record new lines for the function. */
1601 if (last_line
>= s
->lines
.size ())
1603 s
= &sources
[block
->locations
[i
].source_file_idx
];
1605 = block
->locations
[i
].lines
.back ();
1607 /* Record new lines for the function. */
1608 if (last_line
>= s
->lines
.size ())
1610 /* Record new lines for a source file. */
1611 s
->lines
.resize (last_line
+ 1);
1618 /* Make sure to include the last line for this function even when it
1619 is not directly covered by a basic block, for example when } is on
1621 if (sources
[fn
->src
].lines
.size () <= fn
->end_line
)
1622 sources
[fn
->src
].lines
.resize (fn
->end_line
+ 1);
1624 /* Allocate lines for group function, following start_line
1625 and end_line information of the function. */
1627 fn
->lines
.resize (fn
->end_line
- fn
->start_line
+ 1);
1629 solve_flow_graph (fn
);
1631 find_exception_blocks (fn
);
1635 /* The function was not in the executable -- some other
1636 instance must have been selected. */
1642 output_gcov_file (const char *file_name
, source_info
*src
)
1644 string gcov_file_name_str
1645 = make_gcov_file_name (file_name
, src
->coverage
.name
);
1646 const char *gcov_file_name
= gcov_file_name_str
.c_str ();
1648 if (src
->coverage
.lines
)
1650 FILE *gcov_file
= fopen (gcov_file_name
, "w");
1653 fnotice (stdout
, "Creating '%s'\n", gcov_file_name
);
1654 output_lines (gcov_file
, src
);
1655 if (ferror (gcov_file
))
1657 fnotice (stderr
, "Error writing output file '%s'\n",
1665 fnotice (stderr
, "Could not open output file '%s'\n", gcov_file_name
);
1671 unlink (gcov_file_name
);
1672 fnotice (stdout
, "Removing '%s'\n", gcov_file_name
);
1677 generate_results (const char *file_name
)
1679 string gcov_intermediate_filename
;
1681 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1682 it
!= functions
.end (); it
++)
1684 function_info
*fn
= *it
;
1685 coverage_info coverage
;
1687 memset (&coverage
, 0, sizeof (coverage
));
1688 coverage
.name
= fn
->get_name ();
1689 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
1690 if (flag_function_summary
)
1692 function_summary (&coverage
);
1693 fnotice (stdout
, "\n");
1698 needle
.name
= file_name
;
1699 vector
<name_map
>::iterator it
1700 = std::find (names
.begin (), names
.end (), needle
);
1701 if (it
!= names
.end ())
1702 file_name
= sources
[it
->src
].coverage
.name
;
1704 file_name
= canonicalize_name (file_name
);
1706 gcov_intermediate_filename
= get_gcov_intermediate_filename (file_name
);
1708 json::object
*root
= new json::object ();
1709 root
->set_string ("format_version", GCOV_JSON_FORMAT_VERSION
);
1710 root
->set_string ("gcc_version", version_string
);
1712 if (bbg_cwd
!= NULL
)
1713 root
->set_string ("current_working_directory", bbg_cwd
);
1714 root
->set_string ("data_file", file_name
);
1716 json::array
*json_files
= new json::array ();
1717 root
->set ("files", json_files
);
1719 for (vector
<source_info
>::iterator it
= sources
.begin ();
1720 it
!= sources
.end (); it
++)
1722 source_info
*src
= &(*it
);
1723 if (flag_relative_only
)
1725 /* Ignore this source, if it is an absolute path (after
1726 source prefix removal). */
1727 char first
= src
->coverage
.name
[0];
1729 #if HAVE_DOS_BASED_FILE_SYSTEM
1730 if (first
&& src
->coverage
.name
[1] == ':')
1731 first
= src
->coverage
.name
[2];
1733 if (IS_DIR_SEPARATOR (first
))
1737 accumulate_line_counts (src
);
1741 if (!flag_use_stdout
)
1742 file_summary (&src
->coverage
);
1743 total_lines
+= src
->coverage
.lines
;
1744 total_executed
+= src
->coverage
.lines_executed
;
1747 if (flag_json_format
)
1749 output_json_intermediate_file (json_files
, src
);
1750 if (!flag_use_stdout
)
1751 fnotice (stdout
, "\n");
1755 if (flag_use_stdout
)
1757 if (src
->coverage
.lines
)
1758 output_lines (stdout
, src
);
1762 output_gcov_file (file_name
, src
);
1763 fnotice (stdout
, "\n");
1769 if (flag_gcov_file
&& flag_json_format
)
1771 if (flag_use_stdout
)
1773 root
->dump (stdout
, false);
1779 root
->print (&pp
, false);
1780 pp_formatted_text (&pp
);
1782 fnotice (stdout
, "Creating '%s'\n",
1783 gcov_intermediate_filename
.c_str ());
1784 gzFile output
= gzopen (gcov_intermediate_filename
.c_str (), "w");
1787 fnotice (stderr
, "Cannot open JSON output file %s\n",
1788 gcov_intermediate_filename
.c_str ());
1793 if (gzputs (output
, pp_formatted_text (&pp
)) == EOF
1794 || gzclose (output
))
1796 fnotice (stderr
, "Error writing JSON output file %s\n",
1797 gcov_intermediate_filename
.c_str ());
1805 /* Release all memory used. */
1808 release_structures (void)
1810 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1811 it
!= functions
.end (); it
++)
1814 for (vector
<const char *> *lines
: source_lines
)
1817 for (const char *line
: *lines
)
1818 free (const_cast <char*> (line
));
1821 source_lines
.resize (0);
1823 for (fnfilter
&filter
: filters
)
1824 regfree (&filter
.regex
);
1828 functions
.resize (0);
1830 ident_to_fn
.clear ();
1833 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
1834 is not specified, these are named from FILE_NAME sans extension. If
1835 OBJECT_DIRECTORY is specified and is a directory, the files are in that
1836 directory, but named from the basename of the FILE_NAME, sans extension.
1837 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
1838 and the data files are named from that. */
1841 create_file_names (const char *file_name
)
1845 int length
= strlen (file_name
);
1848 /* Free previous file names. */
1849 free (bbg_file_name
);
1850 free (da_file_name
);
1851 da_file_name
= bbg_file_name
= NULL
;
1855 if (object_directory
&& object_directory
[0])
1859 length
+= strlen (object_directory
) + 2;
1860 name
= XNEWVEC (char, length
);
1863 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
1864 strcat (name
, object_directory
);
1865 if (base
&& (!IS_DIR_SEPARATOR (name
[strlen (name
) - 1])))
1870 name
= XNEWVEC (char, length
+ 1);
1871 strcpy (name
, file_name
);
1877 /* Append source file name. */
1878 const char *cptr
= lbasename (file_name
);
1879 strcat (name
, cptr
? cptr
: file_name
);
1882 /* Remove the extension. */
1883 cptr
= strrchr (CONST_CAST (char *, lbasename (name
)), '.');
1887 length
= strlen (name
);
1889 bbg_file_name
= XNEWVEC (char, length
+ strlen (GCOV_NOTE_SUFFIX
) + 1);
1890 strcpy (bbg_file_name
, name
);
1891 strcpy (bbg_file_name
+ length
, GCOV_NOTE_SUFFIX
);
1893 da_file_name
= XNEWVEC (char, length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
1894 strcpy (da_file_name
, name
);
1895 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
1901 /* Find or create a source file structure for FILE_NAME. Copies
1902 FILE_NAME on creation */
1905 find_source (const char *file_name
)
1912 file_name
= "<unknown>";
1915 needle
.name
= file_name
;
1917 vector
<name_map
>::iterator it
= std::find (names
.begin (), names
.end (),
1919 if (it
!= names
.end ())
1925 /* Not found, try the canonical name. */
1926 canon
= canonicalize_name (file_name
);
1927 needle
.name
= canon
;
1928 it
= std::find (names
.begin (), names
.end (), needle
);
1929 if (it
== names
.end ())
1931 /* Not found with canonical name, create a new source. */
1934 idx
= sources
.size ();
1935 needle
= name_map (canon
, idx
);
1936 names
.push_back (needle
);
1938 sources
.push_back (source_info ());
1939 src
= &sources
.back ();
1941 src
->coverage
.name
= src
->name
;
1944 #if HAVE_DOS_BASED_FILE_SYSTEM
1945 /* You lose if separators don't match exactly in the
1947 && !strncasecmp (source_prefix
, src
->coverage
.name
, source_length
)
1949 && !strncmp (source_prefix
, src
->coverage
.name
, source_length
)
1951 && IS_DIR_SEPARATOR (src
->coverage
.name
[source_length
]))
1952 src
->coverage
.name
+= source_length
+ 1;
1953 if (!stat (src
->name
, &status
))
1954 src
->file_time
= status
.st_mtime
;
1959 needle
.name
= file_name
;
1960 if (std::find (names
.begin (), names
.end (), needle
) == names
.end ())
1962 /* Append the non-canonical name. */
1963 names
.push_back (name_map (xstrdup (file_name
), idx
));
1966 /* Resort the name map. */
1967 std::sort (names
.begin (), names
.end ());
1970 if (sources
[idx
].file_time
> bbg_file_time
)
1972 static int info_emitted
;
1974 fnotice (stderr
, "%s:source file is newer than notes file '%s'\n",
1975 file_name
, bbg_file_name
);
1979 "(the message is displayed only once per source file)\n");
1982 sources
[idx
].file_time
= 0;
1988 /* Read the notes file. Save functions to FUNCTIONS global vector. */
1991 read_graph_file (void)
1994 unsigned current_tag
= 0;
1997 if (!gcov_open (bbg_file_name
, 1))
1999 fnotice (stderr
, "%s:cannot open notes file\n", bbg_file_name
);
2003 bbg_file_time
= gcov_time ();
2004 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC
))
2006 fnotice (stderr
, "%s:not a gcov notes file\n", bbg_file_name
);
2012 version
= gcov_read_unsigned ();
2013 if (version
!= GCOV_VERSION
)
2017 GCOV_UNSIGNED2STRING (v
, version
);
2018 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
2020 fnotice (stderr
, "%s:version '%.4s', prefer '%.4s'\n",
2021 bbg_file_name
, v
, e
);
2024 bbg_stamp
= gcov_read_unsigned ();
2025 /* Read checksum. */
2026 gcov_read_unsigned ();
2027 bbg_cwd
= xstrdup (gcov_read_string ());
2028 bbg_supports_has_unexecuted_blocks
= gcov_read_unsigned ();
2030 function_info
*fn
= NULL
;
2031 while ((tag
= gcov_read_unsigned ()))
2033 unsigned length
= gcov_read_unsigned ();
2034 gcov_position_t base
= gcov_position ();
2036 if (tag
== GCOV_TAG_FUNCTION
)
2038 char *function_name
;
2040 unsigned lineno_checksum
, cfg_checksum
;
2042 ident
= gcov_read_unsigned ();
2043 lineno_checksum
= gcov_read_unsigned ();
2044 cfg_checksum
= gcov_read_unsigned ();
2045 function_name
= xstrdup (gcov_read_string ());
2046 unsigned artificial
= gcov_read_unsigned ();
2047 unsigned src_idx
= find_source (gcov_read_string ());
2048 unsigned start_line
= gcov_read_unsigned ();
2049 unsigned start_column
= gcov_read_unsigned ();
2050 unsigned end_line
= gcov_read_unsigned ();
2051 unsigned end_column
= gcov_read_unsigned ();
2053 fn
= new function_info ();
2055 fn
->m_name
= function_name
;
2057 fn
->lineno_checksum
= lineno_checksum
;
2058 fn
->cfg_checksum
= cfg_checksum
;
2060 fn
->start_line
= start_line
;
2061 fn
->start_column
= start_column
;
2062 fn
->end_line
= end_line
;
2063 fn
->end_column
= end_column
;
2064 fn
->artificial
= artificial
;
2068 /* This is separate from flag_demangled_names to support filtering on
2069 mangled names while printing demangled names, or filtering on
2070 demangled names while printing mangled names. An independent flag
2071 makes sure the function selection does not change even if
2072 demangling is turned on/off. */
2073 const char *fname
= function_name
;
2074 if (flag_filter_on_demangled
)
2075 fname
= fn
->get_demangled_name ();
2077 bool keep
= default_keep
;
2078 for (const fnfilter
&fn
: filters
)
2079 if (regexec (&fn
.regex
, fname
, 0, nullptr, 0) == 0)
2084 functions
.push_back (fn
);
2085 ident_to_fn
[ident
] = fn
;
2088 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
2090 if (!fn
->blocks
.empty ())
2091 fnotice (stderr
, "%s:already seen blocks for '%s'\n",
2092 bbg_file_name
, fn
->get_name ());
2094 fn
->blocks
.resize (gcov_read_unsigned ());
2096 else if (fn
&& tag
== GCOV_TAG_ARCS
)
2098 unsigned src
= gcov_read_unsigned ();
2099 fn
->blocks
[src
].id
= src
;
2100 unsigned num_dests
= GCOV_TAG_ARCS_NUM (length
);
2101 block_info
*src_blk
= &fn
->blocks
[src
];
2102 unsigned mark_catches
= 0;
2103 struct arc_info
*arc
;
2105 if (src
>= fn
->blocks
.size () || fn
->blocks
[src
].succ
)
2110 unsigned dest
= gcov_read_unsigned ();
2111 unsigned flags
= gcov_read_unsigned ();
2113 if (dest
>= fn
->blocks
.size ())
2115 arc
= XCNEW (arc_info
);
2117 arc
->dst
= &fn
->blocks
[dest
];
2118 /* Set id in order to find EXIT_BLOCK. */
2119 arc
->dst
->id
= dest
;
2123 arc
->count_valid
= 0;
2124 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
2125 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
2126 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
2127 arc
->true_value
= !!(flags
& GCOV_ARC_TRUE
);
2128 arc
->false_value
= !!(flags
& GCOV_ARC_FALSE
);
2130 arc
->succ_next
= src_blk
->succ
;
2131 src_blk
->succ
= arc
;
2132 src_blk
->num_succ
++;
2134 arc
->pred_next
= fn
->blocks
[dest
].pred
;
2135 fn
->blocks
[dest
].pred
= arc
;
2136 fn
->blocks
[dest
].num_pred
++;
2142 /* Exceptional exit from this function, the
2143 source block must be a call. */
2144 fn
->blocks
[src
].is_call_site
= 1;
2145 arc
->is_call_non_return
= 1;
2150 /* Non-local return from a callee of this
2151 function. The destination block is a setjmp. */
2152 arc
->is_nonlocal_return
= 1;
2153 fn
->blocks
[dest
].is_nonlocal_return
= 1;
2158 fn
->counts
.push_back (0);
2163 /* We have a fake exit from this block. The other
2164 non-fall through exits must be to catch handlers.
2165 Mark them as catch arcs. */
2167 for (arc
= src_blk
->succ
; arc
; arc
= arc
->succ_next
)
2168 if (!arc
->fake
&& !arc
->fall_through
)
2175 else if (fn
&& tag
== GCOV_TAG_CONDS
)
2177 unsigned num_dests
= GCOV_TAG_CONDS_NUM (length
);
2179 if (!fn
->conditions
.empty ())
2180 fnotice (stderr
, "%s:already seen conditions for '%s'\n",
2181 bbg_file_name
, fn
->get_name ());
2183 fn
->conditions
.resize (num_dests
);
2185 for (unsigned i
= 0; i
< num_dests
; ++i
)
2187 unsigned idx
= gcov_read_unsigned ();
2189 if (idx
>= fn
->blocks
.size ())
2192 condition_info
*info
= &fn
->blocks
[idx
].conditions
;
2193 info
->n_terms
= gcov_read_unsigned ();
2194 fn
->conditions
[i
] = info
;
2197 else if (fn
&& tag
== GCOV_TAG_LINES
)
2199 unsigned blockno
= gcov_read_unsigned ();
2200 block_info
*block
= &fn
->blocks
[blockno
];
2202 if (blockno
>= fn
->blocks
.size ())
2207 unsigned lineno
= gcov_read_unsigned ();
2210 block
->locations
.back ().lines
.push_back (lineno
);
2213 const char *file_name
= gcov_read_string ();
2217 block
->locations
.push_back (block_location_info
2218 (find_source (file_name
)));
2222 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
2227 gcov_sync (base
, length
);
2228 if (gcov_is_error ())
2231 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
2238 if (functions
.empty ())
2239 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
2242 /* Reads profiles from the count file and attach to each
2243 function. Return nonzero if fatal error. */
2246 read_count_file (void)
2251 function_info
*fn
= NULL
;
2253 map
<unsigned, function_info
*>::iterator it
;
2255 if (!gcov_open (da_file_name
, 1))
2257 fnotice (stderr
, "%s:cannot open data file, assuming not executed\n",
2262 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
2264 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
2270 version
= gcov_read_unsigned ();
2271 if (version
!= GCOV_VERSION
)
2275 GCOV_UNSIGNED2STRING (v
, version
);
2276 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
2278 fnotice (stderr
, "%s:version '%.4s', prefer version '%.4s'\n",
2279 da_file_name
, v
, e
);
2282 tag
= gcov_read_unsigned ();
2283 if (tag
!= bbg_stamp
)
2285 fnotice (stderr
, "%s:stamp mismatch with notes file\n", da_file_name
);
2290 /* Read checksum. */
2291 gcov_read_unsigned ();
2293 while ((tag
= gcov_read_unsigned ()))
2295 unsigned length
= gcov_read_unsigned ();
2296 int read_length
= (int)length
;
2297 unsigned long base
= gcov_position ();
2299 if (tag
== GCOV_TAG_OBJECT_SUMMARY
)
2301 struct gcov_summary summary
;
2302 gcov_read_summary (&summary
);
2303 object_runs
= summary
.runs
;
2305 else if (tag
== GCOV_TAG_FUNCTION
&& !length
)
2307 else if (tag
== GCOV_TAG_FUNCTION
&& length
== GCOV_TAG_FUNCTION_LENGTH
)
2310 ident
= gcov_read_unsigned ();
2312 it
= ident_to_fn
.find (ident
);
2313 if (it
!= ident_to_fn
.end ())
2318 else if (gcov_read_unsigned () != fn
->lineno_checksum
2319 || gcov_read_unsigned () != fn
->cfg_checksum
)
2322 fnotice (stderr
, "%s:profile mismatch for '%s'\n",
2323 da_file_name
, fn
->get_name ());
2327 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_CONDS
) && fn
)
2329 length
= abs (read_length
);
2330 if (length
!= GCOV_TAG_COUNTER_LENGTH (2 * fn
->conditions
.size ()))
2333 if (read_length
> 0)
2335 for (ix
= 0; ix
!= fn
->conditions
.size (); ix
++)
2337 fn
->conditions
[ix
]->truev
|= gcov_read_counter ();
2338 fn
->conditions
[ix
]->falsev
|= gcov_read_counter ();
2342 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
2344 length
= abs (read_length
);
2345 if (length
!= GCOV_TAG_COUNTER_LENGTH (fn
->counts
.size ()))
2348 if (read_length
> 0)
2349 for (ix
= 0; ix
!= fn
->counts
.size (); ix
++)
2350 fn
->counts
[ix
] += gcov_read_counter ();
2352 if (read_length
< 0)
2354 gcov_sync (base
, read_length
);
2355 if ((error
= gcov_is_error ()))
2359 ? N_("%s:overflowed\n")
2360 : N_("%s:corrupted\n"),
2371 /* Solve the flow graph. Propagate counts from the instrumented arcs
2372 to the blocks and the uninstrumented arcs. */
2375 solve_flow_graph (function_info
*fn
)
2379 gcov_type
*count_ptr
= &fn
->counts
.front ();
2381 block_info
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
2382 block_info
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
2384 /* The arcs were built in reverse order. Fix that now. */
2385 for (ix
= fn
->blocks
.size (); ix
--;)
2387 arc_info
*arc_p
, *arc_n
;
2389 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
2390 arc_p
= arc
, arc
= arc_n
)
2392 arc_n
= arc
->succ_next
;
2393 arc
->succ_next
= arc_p
;
2395 fn
->blocks
[ix
].succ
= arc_p
;
2397 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
2398 arc_p
= arc
, arc
= arc_n
)
2400 arc_n
= arc
->pred_next
;
2401 arc
->pred_next
= arc_p
;
2403 fn
->blocks
[ix
].pred
= arc_p
;
2406 if (fn
->blocks
.size () < 2)
2407 fnotice (stderr
, "%s:'%s' lacks entry and/or exit blocks\n",
2408 bbg_file_name
, fn
->get_name ());
2411 if (fn
->blocks
[ENTRY_BLOCK
].num_pred
)
2412 fnotice (stderr
, "%s:'%s' has arcs to entry block\n",
2413 bbg_file_name
, fn
->get_name ());
2415 /* We can't deduce the entry block counts from the lack of
2417 fn
->blocks
[ENTRY_BLOCK
].num_pred
= ~(unsigned)0;
2419 if (fn
->blocks
[EXIT_BLOCK
].num_succ
)
2420 fnotice (stderr
, "%s:'%s' has arcs from exit block\n",
2421 bbg_file_name
, fn
->get_name ());
2423 /* Likewise, we can't deduce exit block counts from the lack
2424 of its successors. */
2425 fn
->blocks
[EXIT_BLOCK
].num_succ
= ~(unsigned)0;
2428 /* Propagate the measured counts, this must be done in the same
2429 order as the code in profile.cc */
2430 for (unsigned i
= 0; i
< fn
->blocks
.size (); i
++)
2432 blk
= &fn
->blocks
[i
];
2433 block_info
const *prev_dst
= NULL
;
2434 int out_of_order
= 0;
2435 int non_fake_succ
= 0;
2437 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2445 arc
->count
= *count_ptr
++;
2446 arc
->count_valid
= 1;
2448 arc
->dst
->num_pred
--;
2450 if (prev_dst
&& prev_dst
> arc
->dst
)
2452 prev_dst
= arc
->dst
;
2454 if (non_fake_succ
== 1)
2456 /* If there is only one non-fake exit, it is an
2457 unconditional branch. */
2458 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2461 arc
->is_unconditional
= 1;
2462 /* If this block is instrumenting a call, it might be
2463 an artificial block. It is not artificial if it has
2464 a non-fallthrough exit, or the destination of this
2465 arc has more than one entry. Mark the destination
2466 block as a return site, if none of those conditions
2468 if (blk
->is_call_site
&& arc
->fall_through
2469 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
2470 arc
->dst
->is_call_return
= 1;
2474 /* Sort the successor arcs into ascending dst order. profile.cc
2475 normally produces arcs in the right order, but sometimes with
2476 one or two out of order. We're not using a particularly
2480 arc_info
*start
= blk
->succ
;
2481 unsigned changes
= 1;
2485 arc_info
*arc
, *arc_p
, *arc_n
;
2488 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
2490 if (arc
->dst
> arc_n
->dst
)
2494 arc_p
->succ_next
= arc_n
;
2497 arc
->succ_next
= arc_n
->succ_next
;
2498 arc_n
->succ_next
= arc
;
2511 /* Place it on the invalid chain, it will be ignored if that's
2513 blk
->invalid_chain
= 1;
2514 blk
->chain
= invalid_blocks
;
2515 invalid_blocks
= blk
;
2518 while (invalid_blocks
|| valid_blocks
)
2520 while ((blk
= invalid_blocks
))
2522 gcov_type total
= 0;
2523 const arc_info
*arc
;
2525 invalid_blocks
= blk
->chain
;
2526 blk
->invalid_chain
= 0;
2528 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2529 total
+= arc
->count
;
2530 else if (!blk
->num_pred
)
2531 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
2532 total
+= arc
->count
;
2537 blk
->count_valid
= 1;
2538 blk
->chain
= valid_blocks
;
2539 blk
->valid_chain
= 1;
2542 while ((blk
= valid_blocks
))
2545 arc_info
*arc
, *inv_arc
;
2547 valid_blocks
= blk
->chain
;
2548 blk
->valid_chain
= 0;
2549 if (blk
->num_succ
== 1)
2555 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2557 total
-= arc
->count
;
2558 if (!arc
->count_valid
)
2562 inv_arc
->count_valid
= 1;
2563 inv_arc
->count
= total
;
2566 if (dst
->count_valid
)
2568 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
2570 dst
->chain
= valid_blocks
;
2571 dst
->valid_chain
= 1;
2577 if (!dst
->num_pred
&& !dst
->invalid_chain
)
2579 dst
->chain
= invalid_blocks
;
2580 dst
->invalid_chain
= 1;
2581 invalid_blocks
= dst
;
2585 if (blk
->num_pred
== 1)
2591 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
2593 total
-= arc
->count
;
2594 if (!arc
->count_valid
)
2598 inv_arc
->count_valid
= 1;
2599 inv_arc
->count
= total
;
2602 if (src
->count_valid
)
2604 if (src
->num_succ
== 1 && !src
->valid_chain
)
2606 src
->chain
= valid_blocks
;
2607 src
->valid_chain
= 1;
2613 if (!src
->num_succ
&& !src
->invalid_chain
)
2615 src
->chain
= invalid_blocks
;
2616 src
->invalid_chain
= 1;
2617 invalid_blocks
= src
;
2624 /* If the graph has been correctly solved, every block will have a
2626 for (unsigned i
= 0; ix
< fn
->blocks
.size (); i
++)
2627 if (!fn
->blocks
[i
].count_valid
)
2629 fnotice (stderr
, "%s:graph is unsolvable for '%s'\n",
2630 bbg_file_name
, fn
->get_name ());
2635 /* Mark all the blocks only reachable via an incoming catch. */
2638 find_exception_blocks (function_info
*fn
)
2641 block_info
**queue
= XALLOCAVEC (block_info
*, fn
->blocks
.size ());
2643 /* First mark all blocks as exceptional. */
2644 for (ix
= fn
->blocks
.size (); ix
--;)
2645 fn
->blocks
[ix
].exceptional
= 1;
2647 /* Now mark all the blocks reachable via non-fake edges */
2648 queue
[0] = &fn
->blocks
[0];
2649 queue
[0]->exceptional
= 0;
2652 block_info
*block
= queue
[--ix
];
2653 const arc_info
*arc
;
2655 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2656 if (!arc
->fake
&& !arc
->is_throw
&& arc
->dst
->exceptional
)
2658 arc
->dst
->exceptional
= 0;
2659 queue
[ix
++] = arc
->dst
;
2665 /* Increment totals in COVERAGE according to arc ARC. */
2668 add_branch_counts (coverage_info
*coverage
, const arc_info
*arc
)
2670 if (arc
->is_call_non_return
)
2673 if (arc
->src
->count
)
2674 coverage
->calls_executed
++;
2676 else if (!arc
->is_unconditional
)
2678 coverage
->branches
++;
2679 if (arc
->src
->count
)
2680 coverage
->branches_executed
++;
2682 coverage
->branches_taken
++;
2686 /* Increment totals in COVERAGE according to block BLOCK. */
2689 add_condition_counts (coverage_info
*coverage
, const block_info
*block
)
2691 coverage
->conditions
+= 2 * block
->conditions
.n_terms
;
2692 coverage
->conditions_covered
+= block
->conditions
.popcount ();
2695 /* Format COUNT, if flag_human_readable_numbers is set, return it human
2699 format_count (gcov_type count
)
2701 static char buffer
[64];
2702 const char *units
= " kMGTPEZY";
2704 if (count
< 1000 || !flag_human_readable_numbers
)
2706 sprintf (buffer
, "%" PRId64
, count
);
2711 gcov_type divisor
= 1;
2712 for (i
= 0; units
[i
+1]; i
++, divisor
*= 1000)
2714 if (count
+ divisor
/ 2 < 1000 * divisor
)
2717 float r
= 1.0f
* count
/ divisor
;
2718 sprintf (buffer
, "%.1f%c", r
, units
[i
]);
2722 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
2723 count. If DECIMAL_PLACES >= 0, format TOP/BOTTOM * 100 to DECIMAL_PLACES.
2724 If DECIMAL_PLACES is zero, no decimal point is printed. Only print 100% when
2725 TOP==BOTTOM and only print 0% when TOP=0. If DECIMAL_PLACES < 0, then simply
2726 format TOP. Return pointer to a static string. */
2729 format_gcov (gcov_type top
, gcov_type bottom
, int decimal_places
)
2731 static char buffer
[20];
2733 if (decimal_places
>= 0)
2735 float ratio
= bottom
? 100.0f
* top
/ bottom
: 0;
2737 /* Round up to 1% if there's a small non-zero value. */
2738 if (ratio
> 0.0f
&& ratio
< 0.5f
&& decimal_places
== 0)
2740 sprintf (buffer
, "%.*f%%", decimal_places
, ratio
);
2743 return format_count (top
);
2748 /* Summary of execution */
2751 executed_summary (unsigned lines
, unsigned executed
)
2754 fnotice (stdout
, "Lines executed:%s of %d\n",
2755 format_gcov (executed
, lines
, 2), lines
);
2757 fnotice (stdout
, "No executable lines\n");
2760 /* Output summary info for a function. */
2763 function_summary (const coverage_info
*coverage
)
2765 fnotice (stdout
, "%s '%s'\n", "Function", coverage
->name
);
2766 executed_summary (coverage
->lines
, coverage
->lines_executed
);
2769 /* Output summary info for a file. */
2772 file_summary (const coverage_info
*coverage
)
2774 fnotice (stdout
, "%s '%s'\n", "File", coverage
->name
);
2775 executed_summary (coverage
->lines
, coverage
->lines_executed
);
2779 if (coverage
->branches
)
2781 fnotice (stdout
, "Branches executed:%s of %d\n",
2782 format_gcov (coverage
->branches_executed
,
2783 coverage
->branches
, 2),
2784 coverage
->branches
);
2785 fnotice (stdout
, "Taken at least once:%s of %d\n",
2786 format_gcov (coverage
->branches_taken
,
2787 coverage
->branches
, 2),
2788 coverage
->branches
);
2791 fnotice (stdout
, "No branches\n");
2792 if (coverage
->calls
)
2793 fnotice (stdout
, "Calls executed:%s of %d\n",
2794 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
2797 fnotice (stdout
, "No calls\n");
2801 if (flag_conditions
)
2803 if (coverage
->conditions
)
2804 fnotice (stdout
, "Condition outcomes covered:%s of %d\n",
2805 format_gcov (coverage
->conditions_covered
,
2806 coverage
->conditions
, 2),
2807 coverage
->conditions
);
2809 fnotice (stdout
, "No conditions\n");
2813 /* Canonicalize the filename NAME by canonicalizing directory
2814 separators, eliding . components and resolving .. components
2815 appropriately. Always returns a unique string. */
2818 canonicalize_name (const char *name
)
2820 /* The canonical name cannot be longer than the incoming name. */
2821 char *result
= XNEWVEC (char, strlen (name
) + 1);
2822 const char *base
= name
, *probe
;
2827 #if HAVE_DOS_BASED_FILE_SYSTEM
2828 if (base
[0] && base
[1] == ':')
2830 result
[0] = base
[0];
2836 for (dd_base
= ptr
; *base
; base
= probe
)
2840 for (probe
= base
; *probe
; probe
++)
2841 if (IS_DIR_SEPARATOR (*probe
))
2845 if (len
== 1 && base
[0] == '.')
2846 /* Elide a '.' directory */
2848 else if (len
== 2 && base
[0] == '.' && base
[1] == '.')
2850 /* '..', we can only elide it and the previous directory, if
2851 we're not a symlink. */
2852 struct stat ATTRIBUTE_UNUSED buf
;
2856 #if defined (S_ISLNK)
2857 /* S_ISLNK is not POSIX.1-1996. */
2858 || stat (result
, &buf
) || S_ISLNK (buf
.st_mode
)
2862 /* Cannot elide, or unreadable or a symlink. */
2863 dd_base
= ptr
+ 2 + slash
;
2866 while (ptr
!= dd_base
&& *ptr
!= '/')
2868 slash
= ptr
!= result
;
2873 /* Regular pathname component. */
2876 memcpy (ptr
, base
, len
);
2881 for (; IS_DIR_SEPARATOR (*probe
); probe
++)
2889 /* Generate an output file name. INPUT_NAME is the canonicalized main
2890 input file and SRC_NAME is the canonicalized file name.
2891 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
2892 long_output_names we prepend the processed name of the input file
2893 to each output name (except when the current source file is the
2894 input file, so you don't get a double concatenation). The two
2895 components are separated by '##'. With preserve_paths we create a
2896 filename from all path components of the source file, replacing '/'
2897 with '#', and .. with '^', without it we simply take the basename
2898 component. (Remember, the canonicalized name will already have
2899 elided '.' components and converted \\ separators.) */
2902 make_gcov_file_name (const char *input_name
, const char *src_name
)
2906 /* When hashing filenames, we shorten them by only using the filename
2907 component and appending a hash of the full (mangled) pathname. */
2908 if (flag_hash_filenames
)
2909 str
= (string (mangle_name (src_name
)) + "##"
2910 + get_md5sum (src_name
) + ".gcov");
2913 if (flag_long_names
&& input_name
&& strcmp (src_name
, input_name
) != 0)
2915 str
+= mangle_name (input_name
);
2919 str
+= mangle_name (src_name
);
2926 /* Mangle BASE name, copy it at the beginning of PTR buffer and
2927 return address of the \0 character of the buffer. */
2930 mangle_name (char const *base
)
2932 /* Generate the source filename part. */
2933 if (!flag_preserve_paths
)
2934 return xstrdup (lbasename (base
));
2936 return mangle_path (base
);
2939 /* Scan through the bb_data for each line in the block, increment
2940 the line number execution count indicated by the execution count of
2941 the appropriate basic block. */
2944 add_line_counts (coverage_info
*coverage
, function_info
*fn
)
2946 bool has_any_line
= false;
2947 /* Scan each basic block. */
2948 for (unsigned ix
= 0; ix
!= fn
->blocks
.size (); ix
++)
2950 line_info
*line
= NULL
;
2951 block_info
*block
= &fn
->blocks
[ix
];
2952 if (block
->count
&& ix
&& ix
+ 1 != fn
->blocks
.size ())
2953 fn
->blocks_executed
++;
2954 for (unsigned i
= 0; i
< block
->locations
.size (); i
++)
2956 unsigned src_idx
= block
->locations
[i
].source_file_idx
;
2957 vector
<unsigned> &lines
= block
->locations
[i
].lines
;
2959 block
->cycle
.arc
= NULL
;
2960 block
->cycle
.ident
= ~0U;
2962 for (unsigned j
= 0; j
< lines
.size (); j
++)
2964 unsigned ln
= lines
[j
];
2966 /* Line belongs to a function that is in a group. */
2967 if (fn
->group_line_p (ln
, src_idx
))
2969 gcc_assert (lines
[j
] - fn
->start_line
< fn
->lines
.size ());
2970 line
= &(fn
->lines
[lines
[j
] - fn
->start_line
]);
2975 if (!line
->count
&& block
->count
)
2976 coverage
->lines_executed
++;
2979 if (!block
->exceptional
)
2981 line
->unexceptional
= 1;
2982 if (block
->count
== 0)
2983 line
->has_unexecuted_block
= 1;
2985 line
->count
+= block
->count
;
2989 gcc_assert (ln
< sources
[src_idx
].lines
.size ());
2990 line
= &(sources
[src_idx
].lines
[ln
]);
2995 if (!line
->count
&& block
->count
)
2996 coverage
->lines_executed
++;
2999 if (!block
->exceptional
)
3001 line
->unexceptional
= 1;
3002 if (block
->count
== 0)
3003 line
->has_unexecuted_block
= 1;
3005 line
->count
+= block
->count
;
3009 has_any_line
= true;
3011 if (!ix
|| ix
+ 1 == fn
->blocks
.size ())
3012 /* Entry or exit block. */;
3013 else if (line
!= NULL
)
3015 line
->blocks
.push_back (block
);
3021 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
3022 line
->branches
.push_back (arc
);
3029 fnotice (stderr
, "%s:no lines for '%s'\n", bbg_file_name
,
3033 /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE
3034 is set to true, update source file summary. */
3036 static void accumulate_line_info (line_info
*line
, source_info
*src
,
3040 for (vector
<arc_info
*>::iterator it
= line
->branches
.begin ();
3041 it
!= line
->branches
.end (); it
++)
3042 add_branch_counts (&src
->coverage
, *it
);
3045 for (vector
<block_info
*>::iterator it
= line
->blocks
.begin ();
3046 it
!= line
->blocks
.end (); it
++)
3047 add_condition_counts (&src
->coverage
, *it
);
3050 if (!line
->blocks
.empty ())
3052 /* The user expects the line count to be the number of times
3053 a line has been executed. Simply summing the block count
3054 will give an artificially high number. The Right Thing
3055 is to sum the entry counts to the graph of blocks on this
3056 line, then find the elementary cycles of the local graph
3057 and add the transition counts of those cycles. */
3058 gcov_type count
= 0;
3060 /* Cycle detection. */
3061 for (vector
<block_info
*>::iterator it
= line
->blocks
.begin ();
3062 it
!= line
->blocks
.end (); it
++)
3064 for (arc_info
*arc
= (*it
)->pred
; arc
; arc
= arc
->pred_next
)
3065 if (!line
->has_block (arc
->src
))
3066 count
+= arc
->count
;
3067 for (arc_info
*arc
= (*it
)->succ
; arc
; arc
= arc
->succ_next
)
3068 arc
->cs_count
= arc
->count
;
3071 /* Now, add the count of loops entirely on this line. */
3072 count
+= get_cycles_count (*line
);
3073 line
->count
= count
;
3075 if (line
->count
> src
->maximum_count
)
3076 src
->maximum_count
= line
->count
;
3079 if (line
->exists
&& add_coverage
)
3081 src
->coverage
.lines
++;
3083 src
->coverage
.lines_executed
++;
3087 /* Accumulate the line counts of a file. */
3090 accumulate_line_counts (source_info
*src
)
3092 /* First work on group functions. */
3093 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
3094 it
!= src
->functions
.end (); it
++)
3096 function_info
*fn
= *it
;
3098 if (fn
->src
!= src
->index
|| !fn
->is_group
)
3101 for (vector
<line_info
>::iterator it2
= fn
->lines
.begin ();
3102 it2
!= fn
->lines
.end (); it2
++)
3104 line_info
*line
= &(*it2
);
3105 accumulate_line_info (line
, src
, true);
3109 /* Work on global lines that line in source file SRC. */
3110 for (vector
<line_info
>::iterator it
= src
->lines
.begin ();
3111 it
!= src
->lines
.end (); it
++)
3112 accumulate_line_info (&(*it
), src
, true);
3114 /* If not using intermediate mode, sum lines of group functions and
3115 add them to lines that live in a source file. */
3116 if (!flag_json_format
)
3117 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
3118 it
!= src
->functions
.end (); it
++)
3120 function_info
*fn
= *it
;
3122 if (fn
->src
!= src
->index
|| !fn
->is_group
)
3125 for (unsigned i
= 0; i
< fn
->lines
.size (); i
++)
3127 line_info
*fn_line
= &fn
->lines
[i
];
3128 if (fn_line
->exists
)
3130 unsigned ln
= fn
->start_line
+ i
;
3131 line_info
*src_line
= &src
->lines
[ln
];
3133 if (!src_line
->exists
)
3134 src
->coverage
.lines
++;
3135 if (!src_line
->count
&& fn_line
->count
)
3136 src
->coverage
.lines_executed
++;
3138 src_line
->count
+= fn_line
->count
;
3139 src_line
->exists
= 1;
3141 if (fn_line
->has_unexecuted_block
)
3142 src_line
->has_unexecuted_block
= 1;
3144 if (fn_line
->unexceptional
)
3145 src_line
->unexceptional
= 1;
3151 /* Output information about the conditions in block BINFO. The output includes
3152 * a summary (n/m outcomes covered) and a list of the missing (uncovered)
3156 output_conditions (FILE *gcov_file
, const block_info
*binfo
)
3158 const condition_info
& info
= binfo
->conditions
;
3159 if (info
.n_terms
== 0)
3162 const int expected
= 2 * info
.n_terms
;
3163 const int got
= info
.popcount ();
3165 fnotice (gcov_file
, "condition outcomes covered %d/%d\n", got
, expected
);
3166 if (expected
== got
)
3169 for (unsigned i
= 0; i
< info
.n_terms
; i
++)
3171 gcov_type_unsigned index
= 1;
3173 if ((index
& info
.truev
& info
.falsev
))
3176 const char *t
= (index
& info
.truev
) ? "" : "true";
3177 const char *f
= (index
& info
.falsev
) ? "" : " false";
3178 fnotice (gcov_file
, "condition %2u not covered (%s%s)\n", i
, t
, f
+ !t
[0]);
3182 /* Output information about ARC number IX. Returns nonzero if
3183 anything is output. */
3186 output_branch_count (FILE *gcov_file
, int ix
, const arc_info
*arc
)
3188 if (arc
->is_call_non_return
)
3190 if (arc
->src
->count
)
3192 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
3193 format_gcov (arc
->src
->count
- arc
->count
,
3194 arc
->src
->count
, -flag_counts
));
3197 fnotice (gcov_file
, "call %2d never executed\n", ix
);
3199 else if (!arc
->is_unconditional
)
3201 if (arc
->src
->count
)
3202 fnotice (gcov_file
, "branch %2d taken %s%s", ix
,
3203 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
3204 arc
->fall_through
? " (fallthrough)"
3205 : arc
->is_throw
? " (throw)" : "");
3207 fnotice (gcov_file
, "branch %2d never executed%s", ix
,
3208 (arc
->fall_through
? " (fallthrough)"
3209 : arc
->is_throw
? " (throw)" : ""));
3212 fnotice (gcov_file
, " (BB %d)", arc
->dst
->id
);
3214 fnotice (gcov_file
, "\n");
3216 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
3218 if (arc
->src
->count
)
3219 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
3220 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
3222 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
3230 read_line (FILE *file
)
3232 static char *string
;
3233 static size_t string_len
;
3239 string
= XNEWVEC (char, string_len
);
3242 while (fgets (string
+ pos
, string_len
- pos
, file
))
3244 size_t len
= strlen (string
+ pos
);
3246 if (len
&& string
[pos
+ len
- 1] == '\n')
3248 string
[pos
+ len
- 1] = 0;
3252 /* If the file contains NUL characters or an incomplete
3253 last line, which can happen more than once in one run,
3254 we have to avoid doubling the STRING_LEN unnecessarily. */
3255 if (pos
> string_len
/ 2)
3258 string
= XRESIZEVEC (char, string
, string_len
);
3262 return pos
? string
: NULL
;
3265 /* Get the vector with the contents SRC, possibly from a cache. If
3266 the reading fails, a message prefixed with LINE_START is written to
3268 static const vector
<const char *>&
3269 slurp (const source_info
&src
, FILE *gcov_file
,
3270 const char *line_start
)
3272 if (source_lines
.size () <= src
.index
)
3273 source_lines
.resize (src
.index
+ 1);
3275 /* Store vector pointers so that the returned references remain
3276 stable and won't be broken by successive calls to slurp. */
3277 if (!source_lines
[src
.index
])
3278 source_lines
[src
.index
] = new vector
<const char *> ();
3280 if (!source_lines
[src
.index
]->empty ())
3281 return *source_lines
[src
.index
];
3283 FILE *source_file
= fopen (src
.name
, "r");
3285 fnotice (stderr
, "Cannot open source file %s\n", src
.name
);
3286 else if (src
.file_time
== 0)
3287 fprintf (gcov_file
, "%sSource is newer than graph\n", line_start
);
3290 vector
<const char *> &lines
= *source_lines
[src
.index
];
3292 while ((retval
= read_line (source_file
)))
3293 lines
.push_back (xstrdup (retval
));
3296 fclose (source_file
);
3300 /* Pad string S with spaces from left to have total width equal to 9. */
3303 pad_count_string (string
&s
)
3306 s
.insert (0, 9 - s
.size (), ' ');
3309 /* Print GCOV line beginning to F stream. If EXISTS is set to true, the
3310 line exists in source file. UNEXCEPTIONAL indicated that it's not in
3311 an exceptional statement. The output is printed for LINE_NUM of given
3312 COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
3313 used to indicate non-executed blocks. */
3316 output_line_beginning (FILE *f
, bool exists
, bool unexceptional
,
3317 bool has_unexecuted_block
,
3318 gcov_type count
, unsigned line_num
,
3319 const char *exceptional_string
,
3320 const char *unexceptional_string
,
3321 unsigned int maximum_count
)
3328 s
= format_gcov (count
, 0, -1);
3329 if (has_unexecuted_block
3330 && bbg_supports_has_unexecuted_blocks
)
3332 if (flag_use_colors
)
3334 pad_count_string (s
);
3335 s
.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
3336 COLOR_SEPARATOR COLOR_FG_WHITE
));
3342 pad_count_string (s
);
3346 if (flag_use_colors
)
3349 pad_count_string (s
);
3351 s
.insert (0, SGR_SEQ (COLOR_BG_RED
3352 COLOR_SEPARATOR COLOR_FG_WHITE
));
3354 s
.insert (0, SGR_SEQ (COLOR_BG_CYAN
3355 COLOR_SEPARATOR COLOR_FG_WHITE
));
3360 s
= unexceptional
? unexceptional_string
: exceptional_string
;
3361 pad_count_string (s
);
3368 pad_count_string (s
);
3371 /* Format line number in output. */
3373 sprintf (buffer
, "%5u", line_num
);
3374 string
linestr (buffer
);
3376 if (flag_use_hotness_colors
&& maximum_count
)
3378 if (count
* 2 > maximum_count
) /* > 50%. */
3379 linestr
.insert (0, SGR_SEQ (COLOR_BG_RED
));
3380 else if (count
* 5 > maximum_count
) /* > 20%. */
3381 linestr
.insert (0, SGR_SEQ (COLOR_BG_YELLOW
));
3382 else if (count
* 10 > maximum_count
) /* > 10%. */
3383 linestr
.insert (0, SGR_SEQ (COLOR_BG_GREEN
));
3384 linestr
+= SGR_RESET
;
3387 fprintf (f
, "%s:%s", s
.c_str (), linestr
.c_str ());
3391 print_source_line (FILE *f
, const vector
<const char *> &source_lines
,
3394 gcc_assert (line
>= 1);
3395 gcc_assert (line
<= source_lines
.size ());
3397 fprintf (f
, ":%s\n", source_lines
[line
- 1]);
3400 /* Output line details for LINE and print it to F file. LINE lives on
3404 output_line_details (FILE *f
, const line_info
*line
, unsigned line_num
)
3406 if (flag_all_blocks
)
3410 for (vector
<block_info
*>::const_iterator it
= line
->blocks
.begin ();
3411 it
!= line
->blocks
.end (); it
++)
3413 if (!(*it
)->is_call_return
)
3415 output_line_beginning (f
, line
->exists
,
3416 (*it
)->exceptional
, false,
3417 (*it
)->count
, line_num
,
3418 "%%%%%", "$$$$$", 0);
3419 fprintf (f
, "-block %d", (*it
)->id
);
3421 fprintf (f
, " (BB %u)", (*it
)->id
);
3425 for (arc
= (*it
)->succ
; arc
; arc
= arc
->succ_next
)
3426 jx
+= output_branch_count (f
, jx
, arc
);
3428 if (flag_conditions
)
3429 output_conditions (f
, *it
);
3439 for (vector
<arc_info
*>::const_iterator it
= line
->branches
.begin ();
3440 it
!= line
->branches
.end (); it
++)
3441 ix
+= output_branch_count (f
, ix
, (*it
));
3444 if (flag_conditions
)
3446 for (vector
<block_info
*>::const_iterator it
= line
->blocks
.begin ();
3447 it
!= line
->blocks
.end (); it
++)
3448 output_conditions (f
, *it
);
3453 /* Output detail statistics about function FN to file F. */
3456 output_function_details (FILE *f
, function_info
*fn
)
3461 arc_info
*arc
= fn
->blocks
[EXIT_BLOCK
].pred
;
3462 gcov_type return_count
= fn
->blocks
[EXIT_BLOCK
].count
;
3463 gcov_type called_count
= fn
->blocks
[ENTRY_BLOCK
].count
;
3465 for (; arc
; arc
= arc
->pred_next
)
3467 return_count
-= arc
->count
;
3469 fprintf (f
, "function %s", fn
->get_name ());
3470 fprintf (f
, " called %s",
3471 format_gcov (called_count
, 0, -1));
3472 fprintf (f
, " returned %s",
3473 format_gcov (return_count
, called_count
, 0));
3474 fprintf (f
, " blocks executed %s",
3475 format_gcov (fn
->blocks_executed
, fn
->get_block_count (), 0));
3479 /* Read in the source file one line at a time, and output that line to
3480 the gcov file preceded by its execution count and other
3484 output_lines (FILE *gcov_file
, const source_info
*src
)
3486 #define DEFAULT_LINE_START " -: 0:"
3487 #define FN_SEPARATOR "------------------\n"
3489 /* Print colorization legend. */
3490 if (flag_use_colors
)
3491 fprintf (gcov_file
, "%s",
3492 DEFAULT_LINE_START
"Colorization: profile count: " \
3493 SGR_SEQ (COLOR_BG_CYAN
) "zero coverage (exceptional)" SGR_RESET \
3495 SGR_SEQ (COLOR_BG_RED
) "zero coverage (unexceptional)" SGR_RESET \
3497 SGR_SEQ (COLOR_BG_MAGENTA
) "unexecuted block" SGR_RESET
"\n");
3499 if (flag_use_hotness_colors
)
3500 fprintf (gcov_file
, "%s",
3501 DEFAULT_LINE_START
"Colorization: line numbers: hotness: " \
3502 SGR_SEQ (COLOR_BG_RED
) "> 50%" SGR_RESET
" " \
3503 SGR_SEQ (COLOR_BG_YELLOW
) "> 20%" SGR_RESET
" " \
3504 SGR_SEQ (COLOR_BG_GREEN
) "> 10%" SGR_RESET
"\n");
3506 fprintf (gcov_file
, DEFAULT_LINE_START
"Source:%s\n", src
->coverage
.name
);
3507 if (!multiple_files
)
3509 fprintf (gcov_file
, DEFAULT_LINE_START
"Graph:%s\n", bbg_file_name
);
3510 fprintf (gcov_file
, DEFAULT_LINE_START
"Data:%s\n",
3511 no_data_file
? "-" : da_file_name
);
3512 fprintf (gcov_file
, DEFAULT_LINE_START
"Runs:%u\n", object_runs
);
3515 const vector
<const char *> &source_lines
= slurp (*src
, gcov_file
,
3516 DEFAULT_LINE_START
);
3517 unsigned line_start_group
= 0;
3518 vector
<function_info
*> *fns
;
3519 unsigned filtered_line_end
= !filters
.empty () ? 0 : source_lines
.size ();
3521 for (unsigned line_num
= 1; line_num
<= source_lines
.size (); line_num
++)
3523 if (line_num
>= src
->lines
.size ())
3525 /* If the src->lines is truncated because the rest of the functions
3526 are filtered out we must stop here, and not fall back to printing
3527 the rest of the file. */
3528 if (!filters
.empty ())
3530 fprintf (gcov_file
, "%9s:%5u", "-", line_num
);
3531 print_source_line (gcov_file
, source_lines
, line_num
);
3535 const line_info
*line
= &src
->lines
[line_num
];
3537 if (line_start_group
== 0)
3539 fns
= src
->get_functions_at_location (line_num
);
3540 if (fns
!= NULL
&& fns
->size () > 1)
3542 /* It's possible to have functions that partially overlap,
3543 thus take the maximum end_line of functions starting
3545 for (unsigned i
= 0; i
< fns
->size (); i
++)
3546 if ((*fns
)[i
]->end_line
> line_start_group
)
3547 line_start_group
= (*fns
)[i
]->end_line
;
3549 /* When filtering, src->lines will be cut short for the last
3550 selected function. To make sure the "overlapping function"
3551 section is printed too, adjust the end so that it is within
3553 if (line_start_group
>= src
->lines
.size ())
3554 line_start_group
= src
->lines
.size () - 1;
3556 if (!filters
.empty ())
3557 filtered_line_end
= line_start_group
;
3559 else if (fns
!= NULL
&& fns
->size () == 1)
3561 function_info
*fn
= (*fns
)[0];
3562 output_function_details (gcov_file
, fn
);
3564 /* If functions are filtered, only the matching functions will be in
3565 fns and there is no need for extra checking. */
3566 if (!filters
.empty ())
3567 filtered_line_end
= fn
->end_line
;
3571 /* For lines which don't exist in the .bb file, print '-' before
3572 the source line. For lines which exist but were never
3573 executed, print '#####' or '=====' before the source line.
3574 Otherwise, print the execution count before the source line.
3575 There are 16 spaces of indentation added before the source
3576 line so that tabs won't be messed up. */
3577 if (line_num
<= filtered_line_end
)
3579 output_line_beginning (gcov_file
, line
->exists
, line
->unexceptional
,
3580 line
->has_unexecuted_block
, line
->count
,
3581 line_num
, "=====", "#####",
3582 src
->maximum_count
);
3584 print_source_line (gcov_file
, source_lines
, line_num
);
3585 output_line_details (gcov_file
, line
, line_num
);
3588 if (line_start_group
== line_num
)
3590 for (vector
<function_info
*>::iterator it
= fns
->begin ();
3591 it
!= fns
->end (); it
++)
3593 function_info
*fn
= *it
;
3594 vector
<line_info
> &lines
= fn
->lines
;
3596 fprintf (gcov_file
, FN_SEPARATOR
);
3598 string fn_name
= fn
->get_name ();
3599 if (flag_use_colors
)
3601 fn_name
.insert (0, SGR_SEQ (COLOR_FG_CYAN
));
3602 fn_name
+= SGR_RESET
;
3605 fprintf (gcov_file
, "%s:\n", fn_name
.c_str ());
3607 output_function_details (gcov_file
, fn
);
3609 /* Print all lines covered by the function. */
3610 for (unsigned i
= 0; i
< lines
.size (); i
++)
3612 line_info
*line
= &lines
[i
];
3613 unsigned l
= fn
->start_line
+ i
;
3615 /* For lines which don't exist in the .bb file, print '-'
3616 before the source line. For lines which exist but
3617 were never executed, print '#####' or '=====' before
3618 the source line. Otherwise, print the execution count
3619 before the source line.
3620 There are 16 spaces of indentation added before the source
3621 line so that tabs won't be messed up. */
3622 output_line_beginning (gcov_file
, line
->exists
,
3623 line
->unexceptional
,
3624 line
->has_unexecuted_block
,
3626 l
, "=====", "#####",
3627 src
->maximum_count
);
3629 print_source_line (gcov_file
, source_lines
, l
);
3630 output_line_details (gcov_file
, line
, l
);
3634 fprintf (gcov_file
, FN_SEPARATOR
);
3635 line_start_group
= 0;