AVR: Provide built-ins for strlen where the string lives in some AS.
[gcc.git] / gcc / gcov.cc
blob3e6f2e4212ac3cb815f262858c0267f41fd4fade
1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file.
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)
11 any later version.
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. */
33 #include "config.h"
34 #define INCLUDE_ALGORITHM
35 #define INCLUDE_VECTOR
36 #define INCLUDE_STRING
37 #define INCLUDE_MAP
38 #define INCLUDE_SET
39 #include "system.h"
40 #include "coretypes.h"
41 #include "tm.h"
42 #include "intl.h"
43 #include "diagnostic.h"
44 #include "version.h"
45 #include "demangle.h"
46 #include "color-macros.h"
47 #include "pretty-print.h"
48 #include "json.h"
49 #include "hwint.h"
50 #include "xregex.h"
52 #include <zlib.h>
53 #include <getopt.h>
55 #include "md5.h"
57 using namespace std;
59 #define IN_GCOV 1
60 #include "gcov-io.h"
61 #include "gcov-io.cc"
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. */
83 class function_info;
84 class block_info;
85 class source_info;
86 class condition_info;
88 /* Describes an arc between two basic blocks. */
90 struct arc_info
92 /* source and destination blocks. */
93 class block_info *src;
94 class block_info *dst;
96 /* transition counts. */
97 gcov_type count;
98 /* used in cycle search, so that we do not clobber original counts. */
99 gcov_type cs_count;
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;
121 /* Is a true arc. */
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
133 a basic block. */
135 class block_location_info
137 public:
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. */
148 class condition_info
150 public:
151 condition_info ();
153 int popcount () const;
155 /* Bitsets storing the independently significant outcomes for true and false,
156 respectively. */
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. */
161 unsigned n_terms;
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. */
176 class block_info
178 public:
179 /* Constructor. */
180 block_info ();
182 /* Chain of exit and entry arcs. */
183 arc_info *succ;
184 arc_info *pred;
186 /* Number of unprocessed exit and entry arcs. */
187 gcov_type num_succ;
188 gcov_type num_pred;
190 unsigned id;
192 /* Block execution count. */
193 gcov_type 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;
210 struct
212 /* Single line graph cycle workspace. Used for all-blocks
213 mode. */
214 arc_info *arc;
215 unsigned ident;
216 } cycle; /* Used in all-blocks mode, after blocks are linked onto
217 lines. */
219 /* Temporary chain for solving graph, and for chaining blocks on one
220 line. */
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)
230 cycle.arc = NULL;
233 /* Describes a single line of source. Contains a chain of basic blocks
234 with code on it. */
236 class line_info
238 public:
239 /* Default constructor. */
240 line_info ();
242 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
243 bool has_block (block_info *needle);
245 /* Execution count. */
246 gcov_type 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;
254 unsigned exists : 1;
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)
264 bool
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. */
276 class function_info
278 public:
279 function_info ();
280 ~function_info ();
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. */
288 static inline bool
289 is_artificial (function_info *fn)
291 return fn->artificial;
294 /* Name of function. */
295 char *m_name;
296 char *m_demangled_name;
297 unsigned ident;
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
305 in a source file. */
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. */
324 unsigned start_line;
326 /* First line column. */
327 unsigned start_column;
329 /* Last line number. */
330 unsigned end_line;
332 /* Last line column. */
333 unsigned end_column;
335 /* Index of source file where the function is defined. */
336 unsigned src;
338 /* Vector of line information (used only for group functions). */
339 vector<line_info> lines;
341 /* Next function. */
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. */
359 char *get_name ()
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
372 line. */
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. */
387 struct coverage_info
389 int lines;
390 int lines_executed;
392 int branches;
393 int branches_executed;
394 int branches_taken;
396 int conditions;
397 int conditions_covered;
399 int calls;
400 int calls_executed;
402 char *name;
405 /* Describes a file mentioned in the block graph. Contains an array
406 of line info. */
408 class source_info
410 public:
411 /* Default constructor. */
412 source_info ();
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. */
420 void debug ();
422 /* Index of the source_info in sources vector. */
423 unsigned index;
425 /* Canonical name of source file. */
426 char *name;
427 time_t file_time;
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
438 number order. */
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. */
451 void
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];
460 if (*slot == NULL)
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 ())
470 return NULL;
472 vector<function_info *> *slot = line_to_function_map[line_num];
473 if (slot != NULL)
474 std::sort (slot->begin (), slot->end (), function_line_start_cmp ());
476 return slot;
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");
504 class name_map
506 public:
507 name_map ()
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;
519 #else
520 return strcmp (this->name, rhs.name) == 0;
521 #endif
524 bool operator< (const name_map &rhs) const
526 #if HAVE_DOS_BASED_FILE_SYSTEM
527 return strcasecmp (this->name, rhs.name) < 0;
528 #else
529 return strcmp (this->name, rhs.name) < 0;
530 #endif
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
555 read. */
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
595 counts are added. */
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
710 filtering. */
711 struct fnfilter
713 /* The (extended) compiled regex for this filter. */
714 regex_t regex;
716 /* The action when this filter (regex) matches - if true, the function should
717 be kept, otherwise discarded. */
718 bool keep;
720 /* Compile the regex EXPR, or exit if pattern is malformed. */
721 void compile (const char *expr)
723 int err = regcomp (&regex, expr, REG_NOSUB | REG_EXTENDED);
724 if (err)
726 size_t len = regerror (err, &regex, nullptr, 0);
727 char *msg = XNEWVEC (char, len);
728 regerror (err, &regex, msg, len);
729 fprintf (stderr, "Bad regular expression: %s\n", msg);
730 free (msg);
731 exit (EXIT_FAILURE);
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;
791 free (arc);
794 if (m_demangled_name != m_name)
795 free (m_demangled_name);
796 free (m_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;
804 /* Cycle detection!
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. */
823 static void
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
827 that amount. */
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. */
845 static void
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 ())
851 return;
853 unsigned index = it - blocked.begin ();
854 blocked.erase (it);
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. */
867 static bool
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)
872 return true;
873 return false;
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. */
881 static bool
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;
896 if (w < start
897 || arc->cs_count <= 0
898 || !linfo.has_block (w))
899 continue;
901 path.push_back (arc);
902 if (w == start)
904 /* Cycle has been found. */
905 handle_cycle (path, count);
906 loop_found = true;
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,
911 count);
913 path.pop_back ();
916 if (loop_found)
917 unblock (v, blocked, block_lists);
918 else
919 for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
921 block_info *w = arc->dst;
922 if (w < start
923 || arc->cs_count <= 0
924 || !linfo.has_block (w))
925 continue;
927 size_t index
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 ())
932 list.push_back (v);
935 return loop_found;
938 /* Find cycles for a LINFO. */
940 static gcov_type
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. */
949 gcov_type count = 0;
950 for (vector<block_info *>::iterator it = linfo.blocks.begin ();
951 it != linfo.blocks.end (); it++)
953 arc_vector_t path;
954 block_vector_t blocked;
955 vector<block_vector_t > block_lists;
956 circuit (*it, path, *it, blocked, block_lists, linfo, count);
959 return count;
963 main (int argc, char **argv)
965 int argno;
966 int first_arg;
967 const char *p;
969 p = argv[0] + strlen (argv[0]);
970 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
971 --p;
972 progname = p;
974 xmalloc_set_program_name (progname);
976 /* Unlock the stdio streams. */
977 unlock_std_streams ();
979 gcc_init_libintl ();
981 diagnostic_initialize (global_dc, 0);
983 /* Handle response files. */
984 expandargv (&argc, &argv);
986 argno = process_args (argc, argv);
987 if (optind == argc)
988 print_usage (true);
990 if (argc - argno > 1)
991 multiple_files = 1;
993 first_arg = argno;
995 for (; argno != argc; argno++)
997 if (flag_display_progress)
998 printf ("Processing file %d out of %d\n", argno - first_arg + 1,
999 argc - first_arg);
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);
1013 return return_code;
1016 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
1017 otherwise the output of --help. */
1019 static void
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\
1044 source files\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",
1063 bug_report_url);
1064 exit (status);
1067 /* Print version information and exit. */
1069 static void
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",
1075 _("(C)"));
1076 fnotice (stdout,
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' },
1112 { 0, 0, 0, 0 }
1115 /* Process args, return index to first non-arg. */
1117 static int
1118 process_args (int argc, char **argv)
1120 int opt;
1122 const char *opts = "abcdDfghHijklmMno:pqrs:tuvwx";
1123 while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
1125 switch (opt)
1127 case 'a':
1128 flag_all_blocks = 1;
1129 break;
1130 case 'b':
1131 flag_branches = 1;
1132 break;
1133 case 'c':
1134 flag_counts = 1;
1135 break;
1136 case 'f':
1137 flag_function_summary = 1;
1138 break;
1139 case 'g':
1140 flag_conditions = 1;
1141 break;
1142 case 'h':
1143 print_usage (false);
1144 /* print_usage will exit. */
1145 case 'l':
1146 flag_long_names = 1;
1147 break;
1148 case 'I':
1149 default_keep = false;
1150 filters.push_back (fnfilter {});
1151 filters.back ().keep = true;
1152 filters.back ().compile (optarg);
1153 break;
1154 case 'E':
1155 filters.push_back (fnfilter {});
1156 filters.back ().keep = false;
1157 filters.back ().compile (optarg);
1158 break;
1159 case 'H':
1160 flag_human_readable_numbers = 1;
1161 break;
1162 case 'k':
1163 flag_use_colors = 1;
1164 break;
1165 case 'q':
1166 flag_use_hotness_colors = 1;
1167 break;
1168 case 'm':
1169 flag_demangled_names = 1;
1170 break;
1171 case 'M':
1172 flag_filter_on_demangled = true;
1173 break;
1174 case 'n':
1175 flag_gcov_file = 0;
1176 break;
1177 case 'o':
1178 object_directory = optarg;
1179 break;
1180 case 's':
1181 source_prefix = optarg;
1182 source_length = strlen (source_prefix);
1183 break;
1184 case 'r':
1185 flag_relative_only = 1;
1186 break;
1187 case 'p':
1188 flag_preserve_paths = 1;
1189 break;
1190 case 'u':
1191 flag_unconditional = 1;
1192 break;
1193 case 'i':
1194 case 'j':
1195 flag_json_format = 1;
1196 flag_gcov_file = 1;
1197 break;
1198 case 'd':
1199 flag_display_progress = 1;
1200 break;
1201 case 'x':
1202 flag_hash_filenames = 1;
1203 break;
1204 case 'w':
1205 flag_verbose = 1;
1206 break;
1207 case 't':
1208 flag_use_stdout = 1;
1209 break;
1210 case 'D':
1211 flag_debug = 1;
1212 break;
1213 case 'v':
1214 print_version ();
1215 /* print_version will exit. */
1216 default:
1217 print_usage (true);
1218 /* print_usage will exit. */
1222 return optind;
1225 /* Output intermediate LINE sitting on LINE_NUM to JSON OBJECT.
1226 Add FUNCTION_NAME to the LINE. */
1228 static void
1229 output_intermediate_json_line (json::array *object,
1230 line_info *line, unsigned line_num,
1231 const char *function_name)
1233 if (!line->exists)
1234 return;
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;
1255 if (flag_branches)
1256 for (it = line->branches.begin (); it != line->branches.end ();
1257 it++)
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)
1289 continue;
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;
1308 index <<= i;
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. */
1324 static string
1325 strip_extention (string str)
1327 string::size_type pos = str.rfind ('.');
1328 if (pos != string::npos)
1329 str = str.substr (0, pos);
1331 return str;
1334 /* Calcualte md5sum for INPUT string and return it in hex string format. */
1336 static string
1337 get_md5sum (const char *input)
1339 md5_ctx ctx;
1340 char md5sum[16];
1341 string str;
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++)
1349 char b[3];
1350 sprintf (b, "%02x", (unsigned char)md5sum[i]);
1351 str += b;
1354 return str;
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.
1362 e.g.,
1363 input: foo.da, output: foo.da.gcov
1364 input: a/b/foo.cc, output: foo.cc.gcov */
1366 static string
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)
1374 str += "##";
1375 str += get_md5sum (input_file_name);
1377 else if (flag_preserve_paths && base != input_file_name)
1379 str += "##";
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. */
1391 static void
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);
1430 if (fns != NULL)
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,
1444 (*it2)->m_name);
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,
1455 fname);
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;
1478 static hashval_t
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 ();
1487 static bool
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);
1494 static void
1495 mark_deleted (function_start &ref)
1497 ref.start_line = ~1U;
1500 static const bool empty_zero_p = false;
1502 static void
1503 mark_empty (function_start &ref)
1505 ref.start_line = ~2U;
1508 static bool
1509 is_deleted (const function_start &ref)
1511 return ref.start_line == ~1U;
1514 static bool
1515 is_empty (const function_start &ref)
1517 return ref.start_line == ~2U;
1521 /* Process a single input file. */
1523 static void
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",
1532 file_name);
1533 return;
1536 processed_files.push_back (xstrdup (da_file_name));
1538 read_graph_file ();
1539 read_count_file ();
1542 /* Process all functions in all files. */
1544 static void
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);
1559 if (slot)
1561 (*slot)->is_group = 1;
1562 (*it)->is_group = 1;
1564 else
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 ();
1585 block_no++)
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];
1597 unsigned last_line
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];
1604 unsigned last_line
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
1620 its own line. */
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. */
1626 if (fn->is_group)
1627 fn->lines.resize (fn->end_line - fn->start_line + 1);
1629 solve_flow_graph (fn);
1630 if (fn->has_catch)
1631 find_exception_blocks (fn);
1633 else
1635 /* The function was not in the executable -- some other
1636 instance must have been selected. */
1641 static void
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");
1651 if (gcov_file)
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",
1658 gcov_file_name);
1659 return_code = 6;
1661 fclose (gcov_file);
1663 else
1665 fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
1666 return_code = 6;
1669 else
1671 unlink (gcov_file_name);
1672 fnotice (stdout, "Removing '%s'\n", gcov_file_name);
1676 static void
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");
1697 name_map needle;
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;
1703 else
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];
1732 #endif
1733 if (IS_DIR_SEPARATOR (first))
1734 continue;
1737 accumulate_line_counts (src);
1738 if (flag_debug)
1739 src->debug ();
1741 if (!flag_use_stdout)
1742 file_summary (&src->coverage);
1743 total_lines += src->coverage.lines;
1744 total_executed += src->coverage.lines_executed;
1745 if (flag_gcov_file)
1747 if (flag_json_format)
1749 output_json_intermediate_file (json_files, src);
1750 if (!flag_use_stdout)
1751 fnotice (stdout, "\n");
1753 else
1755 if (flag_use_stdout)
1757 if (src->coverage.lines)
1758 output_lines (stdout, src);
1760 else
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);
1774 printf ("\n");
1776 else
1778 pretty_printer pp;
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");
1785 if (output == NULL)
1787 fnotice (stderr, "Cannot open JSON output file %s\n",
1788 gcov_intermediate_filename.c_str ());
1789 return_code = 6;
1790 return;
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 ());
1798 return_code = 6;
1799 return;
1805 /* Release all memory used. */
1807 static void
1808 release_structures (void)
1810 for (vector<function_info *>::iterator it = functions.begin ();
1811 it != functions.end (); it++)
1812 delete (*it);
1814 for (vector<const char *> *lines : source_lines)
1816 if (lines)
1817 for (const char *line : *lines)
1818 free (const_cast <char*> (line));
1819 delete (lines);
1821 source_lines.resize (0);
1823 for (fnfilter &filter : filters)
1824 regfree (&filter.regex);
1826 sources.resize (0);
1827 names.resize (0);
1828 functions.resize (0);
1829 filters.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. */
1840 static void
1841 create_file_names (const char *file_name)
1843 char *cptr;
1844 char *name;
1845 int length = strlen (file_name);
1846 int base;
1848 /* Free previous file names. */
1849 free (bbg_file_name);
1850 free (da_file_name);
1851 da_file_name = bbg_file_name = NULL;
1852 bbg_file_time = 0;
1853 bbg_stamp = 0;
1855 if (object_directory && object_directory[0])
1857 struct stat status;
1859 length += strlen (object_directory) + 2;
1860 name = XNEWVEC (char, length);
1861 name[0] = 0;
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])))
1866 strcat (name, "/");
1868 else
1870 name = XNEWVEC (char, length + 1);
1871 strcpy (name, file_name);
1872 base = 0;
1875 if (base)
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)), '.');
1884 if (cptr)
1885 *cptr = 0;
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);
1897 free (name);
1898 return;
1901 /* Find or create a source file structure for FILE_NAME. Copies
1902 FILE_NAME on creation */
1904 static unsigned
1905 find_source (const char *file_name)
1907 char *canon;
1908 unsigned idx;
1909 struct stat status;
1911 if (!file_name)
1912 file_name = "<unknown>";
1914 name_map needle;
1915 needle.name = file_name;
1917 vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1918 needle);
1919 if (it != names.end ())
1921 idx = it->src;
1922 goto check_date;
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. */
1932 source_info *src;
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 ();
1940 src->name = canon;
1941 src->coverage.name = src->name;
1942 src->index = idx;
1943 if (source_length
1944 #if HAVE_DOS_BASED_FILE_SYSTEM
1945 /* You lose if separators don't match exactly in the
1946 prefix. */
1947 && !strncasecmp (source_prefix, src->coverage.name, source_length)
1948 #else
1949 && !strncmp (source_prefix, src->coverage.name, source_length)
1950 #endif
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;
1956 else
1957 idx = it->src;
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 ());
1969 check_date:
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);
1976 if (!info_emitted)
1978 fnotice (stderr,
1979 "(the message is displayed only once per source file)\n");
1980 info_emitted = 1;
1982 sources[idx].file_time = 0;
1985 return idx;
1988 /* Read the notes file. Save functions to FUNCTIONS global vector. */
1990 static void
1991 read_graph_file (void)
1993 unsigned version;
1994 unsigned current_tag = 0;
1995 unsigned tag;
1997 if (!gcov_open (bbg_file_name, 1))
1999 fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
2000 return_code = 1;
2001 return;
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);
2007 return_code = 2;
2008 gcov_close ();
2009 return;
2012 version = gcov_read_unsigned ();
2013 if (version != GCOV_VERSION)
2015 char v[4], e[4];
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);
2022 return_code = 3;
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;
2039 unsigned ident;
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;
2056 fn->ident = ident;
2057 fn->lineno_checksum = lineno_checksum;
2058 fn->cfg_checksum = cfg_checksum;
2059 fn->src = src_idx;
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;
2066 current_tag = tag;
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)
2080 keep = fn.keep;
2082 if (keep)
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 ());
2093 else
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)
2106 goto corrupt;
2108 while (num_dests--)
2110 unsigned dest = gcov_read_unsigned ();
2111 unsigned flags = gcov_read_unsigned ();
2113 if (dest >= fn->blocks.size ())
2114 goto corrupt;
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;
2120 arc->src = src_blk;
2122 arc->count = 0;
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++;
2138 if (arc->fake)
2140 if (src)
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;
2146 mark_catches = 1;
2148 else
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;
2157 if (!arc->on_tree)
2158 fn->counts.push_back (0);
2161 if (mark_catches)
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)
2170 arc->is_throw = 1;
2171 fn->has_catch = 1;
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 ());
2182 else
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 ())
2190 goto corrupt;
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 ())
2203 goto corrupt;
2205 while (true)
2207 unsigned lineno = gcov_read_unsigned ();
2209 if (lineno)
2210 block->locations.back ().lines.push_back (lineno);
2211 else
2213 const char *file_name = gcov_read_string ();
2215 if (!file_name)
2216 break;
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))
2224 fn = NULL;
2225 current_tag = 0;
2227 gcov_sync (base, length);
2228 if (gcov_is_error ())
2230 corrupt:;
2231 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
2232 return_code = 4;
2233 break;
2236 gcov_close ();
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. */
2245 static int
2246 read_count_file (void)
2248 unsigned ix;
2249 unsigned version;
2250 unsigned tag;
2251 function_info *fn = NULL;
2252 int error = 0;
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",
2258 da_file_name);
2259 no_data_file = 1;
2260 return 0;
2262 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
2264 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
2265 return_code = 2;
2266 cleanup:;
2267 gcov_close ();
2268 return 1;
2270 version = gcov_read_unsigned ();
2271 if (version != GCOV_VERSION)
2273 char v[4], e[4];
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);
2280 return_code = 3;
2282 tag = gcov_read_unsigned ();
2283 if (tag != bbg_stamp)
2285 fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
2286 return_code = 5;
2287 goto cleanup;
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)
2306 ; /* placeholder */
2307 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
2309 unsigned ident;
2310 ident = gcov_read_unsigned ();
2311 fn = NULL;
2312 it = ident_to_fn.find (ident);
2313 if (it != ident_to_fn.end ())
2314 fn = it->second;
2316 if (!fn)
2318 else if (gcov_read_unsigned () != fn->lineno_checksum
2319 || gcov_read_unsigned () != fn->cfg_checksum)
2321 mismatch:;
2322 fnotice (stderr, "%s:profile mismatch for '%s'\n",
2323 da_file_name, fn->get_name ());
2324 goto cleanup;
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 ()))
2331 goto mismatch;
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 ()))
2346 goto mismatch;
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)
2353 read_length = 0;
2354 gcov_sync (base, read_length);
2355 if ((error = gcov_is_error ()))
2357 fnotice (stderr,
2358 error < 0
2359 ? N_("%s:overflowed\n")
2360 : N_("%s:corrupted\n"),
2361 da_file_name);
2362 return_code = 4;
2363 goto cleanup;
2367 gcov_close ();
2368 return 0;
2371 /* Solve the flow graph. Propagate counts from the instrumented arcs
2372 to the blocks and the uninstrumented arcs. */
2374 static void
2375 solve_flow_graph (function_info *fn)
2377 unsigned ix;
2378 arc_info *arc;
2379 gcov_type *count_ptr = &fn->counts.front ();
2380 block_info *blk;
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 ());
2409 else
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 ());
2414 else
2415 /* We can't deduce the entry block counts from the lack of
2416 predecessors. */
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 ());
2422 else
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)
2439 if (!arc->fake)
2440 non_fake_succ++;
2442 if (!arc->on_tree)
2444 if (count_ptr)
2445 arc->count = *count_ptr++;
2446 arc->count_valid = 1;
2447 blk->num_succ--;
2448 arc->dst->num_pred--;
2450 if (prev_dst && prev_dst > arc->dst)
2451 out_of_order = 1;
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)
2459 if (!arc->fake)
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
2467 hold. */
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
2477 smart sort. */
2478 if (out_of_order)
2480 arc_info *start = blk->succ;
2481 unsigned changes = 1;
2483 while (changes)
2485 arc_info *arc, *arc_p, *arc_n;
2487 changes = 0;
2488 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
2490 if (arc->dst > arc_n->dst)
2492 changes = 1;
2493 if (arc_p)
2494 arc_p->succ_next = arc_n;
2495 else
2496 start = arc_n;
2497 arc->succ_next = arc_n->succ_next;
2498 arc_n->succ_next = arc;
2499 arc_p = arc_n;
2501 else
2503 arc_p = arc;
2504 arc = arc_n;
2508 blk->succ = start;
2511 /* Place it on the invalid chain, it will be ignored if that's
2512 wrong. */
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;
2527 if (!blk->num_succ)
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;
2533 else
2534 continue;
2536 blk->count = total;
2537 blk->count_valid = 1;
2538 blk->chain = valid_blocks;
2539 blk->valid_chain = 1;
2540 valid_blocks = blk;
2542 while ((blk = valid_blocks))
2544 gcov_type total;
2545 arc_info *arc, *inv_arc;
2547 valid_blocks = blk->chain;
2548 blk->valid_chain = 0;
2549 if (blk->num_succ == 1)
2551 block_info *dst;
2553 total = blk->count;
2554 inv_arc = NULL;
2555 for (arc = blk->succ; arc; arc = arc->succ_next)
2557 total -= arc->count;
2558 if (!arc->count_valid)
2559 inv_arc = arc;
2561 dst = inv_arc->dst;
2562 inv_arc->count_valid = 1;
2563 inv_arc->count = total;
2564 blk->num_succ--;
2565 dst->num_pred--;
2566 if (dst->count_valid)
2568 if (dst->num_pred == 1 && !dst->valid_chain)
2570 dst->chain = valid_blocks;
2571 dst->valid_chain = 1;
2572 valid_blocks = dst;
2575 else
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)
2587 block_info *src;
2589 total = blk->count;
2590 inv_arc = NULL;
2591 for (arc = blk->pred; arc; arc = arc->pred_next)
2593 total -= arc->count;
2594 if (!arc->count_valid)
2595 inv_arc = arc;
2597 src = inv_arc->src;
2598 inv_arc->count_valid = 1;
2599 inv_arc->count = total;
2600 blk->num_pred--;
2601 src->num_succ--;
2602 if (src->count_valid)
2604 if (src->num_succ == 1 && !src->valid_chain)
2606 src->chain = valid_blocks;
2607 src->valid_chain = 1;
2608 valid_blocks = src;
2611 else
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
2625 valid count. */
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 ());
2631 break;
2635 /* Mark all the blocks only reachable via an incoming catch. */
2637 static void
2638 find_exception_blocks (function_info *fn)
2640 unsigned ix;
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;
2650 for (ix = 1; ix;)
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. */
2667 static void
2668 add_branch_counts (coverage_info *coverage, const arc_info *arc)
2670 if (arc->is_call_non_return)
2672 coverage->calls++;
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++;
2681 if (arc->count)
2682 coverage->branches_taken++;
2686 /* Increment totals in COVERAGE according to block BLOCK. */
2688 static void
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
2696 readable format. */
2698 static char const *
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);
2707 return buffer;
2710 unsigned i;
2711 gcov_type divisor = 1;
2712 for (i = 0; units[i+1]; i++, divisor *= 1000)
2714 if (count + divisor / 2 < 1000 * divisor)
2715 break;
2717 float r = 1.0f * count / divisor;
2718 sprintf (buffer, "%.1f%c", r, units[i]);
2719 return buffer;
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. */
2728 static char const *
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)
2739 ratio = 1.0f;
2740 sprintf (buffer, "%.*f%%", decimal_places, ratio);
2742 else
2743 return format_count (top);
2745 return buffer;
2748 /* Summary of execution */
2750 static void
2751 executed_summary (unsigned lines, unsigned executed)
2753 if (lines)
2754 fnotice (stdout, "Lines executed:%s of %d\n",
2755 format_gcov (executed, lines, 2), lines);
2756 else
2757 fnotice (stdout, "No executable lines\n");
2760 /* Output summary info for a function. */
2762 static void
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. */
2771 static void
2772 file_summary (const coverage_info *coverage)
2774 fnotice (stdout, "%s '%s'\n", "File", coverage->name);
2775 executed_summary (coverage->lines, coverage->lines_executed);
2777 if (flag_branches)
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);
2790 else
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),
2795 coverage->calls);
2796 else
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);
2808 else
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. */
2817 static char *
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;
2823 char *ptr = result;
2824 char *dd_base;
2825 int slash = 0;
2827 #if HAVE_DOS_BASED_FILE_SYSTEM
2828 if (base[0] && base[1] == ':')
2830 result[0] = base[0];
2831 result[1] = ':';
2832 base += 2;
2833 ptr += 2;
2835 #endif
2836 for (dd_base = ptr; *base; base = probe)
2838 size_t len;
2840 for (probe = base; *probe; probe++)
2841 if (IS_DIR_SEPARATOR (*probe))
2842 break;
2844 len = probe - base;
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;
2854 *ptr = 0;
2855 if (dd_base == ptr
2856 #if defined (S_ISLNK)
2857 /* S_ISLNK is not POSIX.1-1996. */
2858 || stat (result, &buf) || S_ISLNK (buf.st_mode)
2859 #endif
2862 /* Cannot elide, or unreadable or a symlink. */
2863 dd_base = ptr + 2 + slash;
2864 goto regular;
2866 while (ptr != dd_base && *ptr != '/')
2867 ptr--;
2868 slash = ptr != result;
2870 else
2872 regular:
2873 /* Regular pathname component. */
2874 if (slash)
2875 *ptr++ = '/';
2876 memcpy (ptr, base, len);
2877 ptr += len;
2878 slash = 1;
2881 for (; IS_DIR_SEPARATOR (*probe); probe++)
2882 continue;
2884 *ptr = 0;
2886 return result;
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.) */
2901 static string
2902 make_gcov_file_name (const char *input_name, const char *src_name)
2904 string str;
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");
2911 else
2913 if (flag_long_names && input_name && strcmp (src_name, input_name) != 0)
2915 str += mangle_name (input_name);
2916 str += "##";
2919 str += mangle_name (src_name);
2920 str += ".gcov";
2923 return str;
2926 /* Mangle BASE name, copy it at the beginning of PTR buffer and
2927 return address of the \0 character of the buffer. */
2929 static char *
2930 mangle_name (char const *base)
2932 /* Generate the source filename part. */
2933 if (!flag_preserve_paths)
2934 return xstrdup (lbasename (base));
2935 else
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. */
2943 static void
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]);
2971 if (coverage)
2973 if (!line->exists)
2974 coverage->lines++;
2975 if (!line->count && block->count)
2976 coverage->lines_executed++;
2978 line->exists = 1;
2979 if (!block->exceptional)
2981 line->unexceptional = 1;
2982 if (block->count == 0)
2983 line->has_unexecuted_block = 1;
2985 line->count += block->count;
2987 else
2989 gcc_assert (ln < sources[src_idx].lines.size ());
2990 line = &(sources[src_idx].lines[ln]);
2991 if (coverage)
2993 if (!line->exists)
2994 coverage->lines++;
2995 if (!line->count && block->count)
2996 coverage->lines_executed++;
2998 line->exists = 1;
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);
3017 if (flag_branches)
3019 arc_info *arc;
3021 for (arc = block->succ; arc; arc = arc->succ_next)
3022 line->branches.push_back (arc);
3028 if (!has_any_line)
3029 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name,
3030 fn->get_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,
3037 bool add_coverage)
3039 if (add_coverage)
3040 for (vector<arc_info *>::iterator it = line->branches.begin ();
3041 it != line->branches.end (); it++)
3042 add_branch_counts (&src->coverage, *it);
3044 if (add_coverage)
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++;
3082 if (line->count)
3083 src->coverage.lines_executed++;
3087 /* Accumulate the line counts of a file. */
3089 static void
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)
3099 continue;
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)
3123 continue;
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)
3153 * outcomes. */
3155 static void
3156 output_conditions (FILE *gcov_file, const block_info *binfo)
3158 const condition_info& info = binfo->conditions;
3159 if (info.n_terms == 0)
3160 return;
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)
3167 return;
3169 for (unsigned i = 0; i < info.n_terms; i++)
3171 gcov_type_unsigned index = 1;
3172 index <<= i;
3173 if ((index & info.truev & info.falsev))
3174 continue;
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. */
3185 static int
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));
3196 else
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)" : "");
3206 else
3207 fnotice (gcov_file, "branch %2d never executed%s", ix,
3208 (arc->fall_through ? " (fallthrough)"
3209 : arc->is_throw ? " (throw)" : ""));
3211 if (flag_verbose)
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));
3221 else
3222 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
3224 else
3225 return 0;
3226 return 1;
3229 static const char *
3230 read_line (FILE *file)
3232 static char *string;
3233 static size_t string_len;
3234 size_t pos = 0;
3236 if (!string_len)
3238 string_len = 200;
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;
3249 return string;
3251 pos += len;
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)
3257 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
3267 GCOV_FILE. */
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");
3284 if (!source_file)
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);
3289 const char *retval;
3290 vector<const char *> &lines = *source_lines[src.index];
3291 if (source_file)
3292 while ((retval = read_line (source_file)))
3293 lines.push_back (xstrdup (retval));
3295 if (source_file)
3296 fclose (source_file);
3297 return lines;
3300 /* Pad string S with spaces from left to have total width equal to 9. */
3302 static void
3303 pad_count_string (string &s)
3305 if (s.size () < 9)
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. */
3315 static void
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)
3323 string s;
3324 if (exists)
3326 if (count > 0)
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));
3337 s += SGR_RESET;
3339 else
3340 s += "*";
3342 pad_count_string (s);
3344 else
3346 if (flag_use_colors)
3348 s = "0";
3349 pad_count_string (s);
3350 if (unexceptional)
3351 s.insert (0, SGR_SEQ (COLOR_BG_RED
3352 COLOR_SEPARATOR COLOR_FG_WHITE));
3353 else
3354 s.insert (0, SGR_SEQ (COLOR_BG_CYAN
3355 COLOR_SEPARATOR COLOR_FG_WHITE));
3356 s += SGR_RESET;
3358 else
3360 s = unexceptional ? unexceptional_string : exceptional_string;
3361 pad_count_string (s);
3365 else
3367 s = "-";
3368 pad_count_string (s);
3371 /* Format line number in output. */
3372 char buffer[16];
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 ());
3390 static void
3391 print_source_line (FILE *f, const vector<const char *> &source_lines,
3392 unsigned line)
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
3401 LINE_NUM. */
3403 static void
3404 output_line_details (FILE *f, const line_info *line, unsigned line_num)
3406 if (flag_all_blocks)
3408 arc_info *arc;
3409 int jx = 0;
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);
3420 if (flag_verbose)
3421 fprintf (f, " (BB %u)", (*it)->id);
3422 fprintf (f, "\n");
3424 if (flag_branches)
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);
3432 else
3434 if (flag_branches)
3436 int ix;
3438 ix = 0;
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. */
3455 static void
3456 output_function_details (FILE *f, function_info *fn)
3458 if (!flag_branches)
3459 return;
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)
3466 if (arc->fake)
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));
3476 fprintf (f, "\n");
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
3481 information. */
3483 static void
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 \
3494 " " \
3495 SGR_SEQ (COLOR_BG_RED) "zero coverage (unexceptional)" SGR_RESET \
3496 " " \
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 ())
3529 break;
3530 fprintf (gcov_file, "%9s:%5u", "-", line_num);
3531 print_source_line (gcov_file, source_lines, line_num);
3532 continue;
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
3544 at LINE_NUM. */
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
3552 src->lines. */
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,
3625 line->count,
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;