Fix memory barrier patterns for pre PA8800 processors
[official-gcc.git] / gcc / gcov.cc
blob2fad6aa7edec477e5d0e46a778782c4942282424
1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file.
3 Copyright (C) 1990-2023 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"
50 #include <zlib.h>
51 #include <getopt.h>
53 #include "md5.h"
55 using namespace std;
57 #define IN_GCOV 1
58 #include "gcov-io.h"
59 #include "gcov-io.cc"
61 #define GCOV_JSON_FORMAT_VERSION "2"
63 /* The gcno file is generated by -ftest-coverage option. The gcda file is
64 generated by a program compiled with -fprofile-arcs. Their formats
65 are documented in gcov-io.h. */
67 /* The functions in this file for creating and solution program flow graphs
68 are very similar to functions in the gcc source file profile.cc. In
69 some places we make use of the knowledge of how profile.cc works to
70 select particular algorithms here. */
72 /* The code validates that the profile information read in corresponds
73 to the code currently being compiled. Rather than checking for
74 identical files, the code below compares a checksum on the CFG
75 (based on the order of basic blocks and the arcs in the CFG). If
76 the CFG checksum in the gcda file match the CFG checksum in the
77 gcno file, the profile data will be used. */
79 /* This is the size of the buffer used to read in source file lines. */
81 class function_info;
82 class block_info;
83 class source_info;
85 /* Describes an arc between two basic blocks. */
87 struct arc_info
89 /* source and destination blocks. */
90 class block_info *src;
91 class block_info *dst;
93 /* transition counts. */
94 gcov_type count;
95 /* used in cycle search, so that we do not clobber original counts. */
96 gcov_type cs_count;
98 unsigned int count_valid : 1;
99 unsigned int on_tree : 1;
100 unsigned int fake : 1;
101 unsigned int fall_through : 1;
103 /* Arc to a catch handler. */
104 unsigned int is_throw : 1;
106 /* Arc is for a function that abnormally returns. */
107 unsigned int is_call_non_return : 1;
109 /* Arc is for catch/setjmp. */
110 unsigned int is_nonlocal_return : 1;
112 /* Is an unconditional branch. */
113 unsigned int is_unconditional : 1;
115 /* Loop making arc. */
116 unsigned int cycle : 1;
118 /* Links to next arc on src and dst lists. */
119 struct arc_info *succ_next;
120 struct arc_info *pred_next;
123 /* Describes which locations (lines and files) are associated with
124 a basic block. */
126 class block_location_info
128 public:
129 block_location_info (unsigned _source_file_idx):
130 source_file_idx (_source_file_idx)
133 unsigned source_file_idx;
134 vector<unsigned> lines;
137 /* Describes a basic block. Contains lists of arcs to successor and
138 predecessor blocks. */
140 class block_info
142 public:
143 /* Constructor. */
144 block_info ();
146 /* Chain of exit and entry arcs. */
147 arc_info *succ;
148 arc_info *pred;
150 /* Number of unprocessed exit and entry arcs. */
151 gcov_type num_succ;
152 gcov_type num_pred;
154 unsigned id;
156 /* Block execution count. */
157 gcov_type count;
158 unsigned count_valid : 1;
159 unsigned valid_chain : 1;
160 unsigned invalid_chain : 1;
161 unsigned exceptional : 1;
163 /* Block is a call instrumenting site. */
164 unsigned is_call_site : 1; /* Does the call. */
165 unsigned is_call_return : 1; /* Is the return. */
167 /* Block is a landing pad for longjmp or throw. */
168 unsigned is_nonlocal_return : 1;
170 vector<block_location_info> locations;
172 struct
174 /* Single line graph cycle workspace. Used for all-blocks
175 mode. */
176 arc_info *arc;
177 unsigned ident;
178 } cycle; /* Used in all-blocks mode, after blocks are linked onto
179 lines. */
181 /* Temporary chain for solving graph, and for chaining blocks on one
182 line. */
183 class block_info *chain;
187 block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0),
188 id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
189 exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
190 locations (), chain (NULL)
192 cycle.arc = NULL;
195 /* Describes a single line of source. Contains a chain of basic blocks
196 with code on it. */
198 class line_info
200 public:
201 /* Default constructor. */
202 line_info ();
204 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
205 bool has_block (block_info *needle);
207 /* Execution count. */
208 gcov_type count;
210 /* Branches from blocks that end on this line. */
211 vector<arc_info *> branches;
213 /* blocks which start on this line. Used in all-blocks mode. */
214 vector<block_info *> blocks;
216 unsigned exists : 1;
217 unsigned unexceptional : 1;
218 unsigned has_unexecuted_block : 1;
221 line_info::line_info (): count (0), branches (), blocks (), exists (false),
222 unexceptional (0), has_unexecuted_block (0)
226 bool
227 line_info::has_block (block_info *needle)
229 return std::find (blocks.begin (), blocks.end (), needle) != blocks.end ();
232 /* Output demangled function names. */
234 static int flag_demangled_names = 0;
236 /* Describes a single function. Contains an array of basic blocks. */
238 class function_info
240 public:
241 function_info ();
242 ~function_info ();
244 /* Return true when line N belongs to the function in source file SRC_IDX.
245 The line must be defined in body of the function, can't be inlined. */
246 bool group_line_p (unsigned n, unsigned src_idx);
248 /* Function filter based on function_info::artificial variable. */
250 static inline bool
251 is_artificial (function_info *fn)
253 return fn->artificial;
256 /* Name of function. */
257 char *m_name;
258 char *m_demangled_name;
259 unsigned ident;
260 unsigned lineno_checksum;
261 unsigned cfg_checksum;
263 /* The graph contains at least one fake incoming edge. */
264 unsigned has_catch : 1;
266 /* True when the function is artificial and does not exist
267 in a source file. */
268 unsigned artificial : 1;
270 /* True when multiple functions start at a line in a source file. */
271 unsigned is_group : 1;
273 /* Array of basic blocks. Like in GCC, the entry block is
274 at blocks[0] and the exit block is at blocks[1]. */
275 #define ENTRY_BLOCK (0)
276 #define EXIT_BLOCK (1)
277 vector<block_info> blocks;
278 unsigned blocks_executed;
280 /* Raw arc coverage counts. */
281 vector<gcov_type> counts;
283 /* First line number. */
284 unsigned start_line;
286 /* First line column. */
287 unsigned start_column;
289 /* Last line number. */
290 unsigned end_line;
292 /* Last line column. */
293 unsigned end_column;
295 /* Index of source file where the function is defined. */
296 unsigned src;
298 /* Vector of line information (used only for group functions). */
299 vector<line_info> lines;
301 /* Next function. */
302 class function_info *next;
304 /* Get demangled name of a function. The demangled name
305 is converted when it is used for the first time. */
306 char *get_demangled_name ()
308 if (m_demangled_name == NULL)
310 m_demangled_name = cplus_demangle (m_name, DMGL_PARAMS);
311 if (!m_demangled_name)
312 m_demangled_name = m_name;
315 return m_demangled_name;
318 /* Get name of the function based on flag_demangled_names. */
319 char *get_name ()
321 return flag_demangled_names ? get_demangled_name () : m_name;
324 /* Return number of basic blocks (without entry and exit block). */
325 unsigned get_block_count ()
327 return blocks.size () - 2;
331 /* Function info comparer that will sort functions according to starting
332 line. */
334 struct function_line_start_cmp
336 inline bool operator() (const function_info *lhs,
337 const function_info *rhs)
339 return (lhs->start_line == rhs->start_line
340 ? lhs->start_column < rhs->start_column
341 : lhs->start_line < rhs->start_line);
345 /* Describes coverage of a file or function. */
347 struct coverage_info
349 int lines;
350 int lines_executed;
352 int branches;
353 int branches_executed;
354 int branches_taken;
356 int calls;
357 int calls_executed;
359 char *name;
362 /* Describes a file mentioned in the block graph. Contains an array
363 of line info. */
365 class source_info
367 public:
368 /* Default constructor. */
369 source_info ();
371 vector<function_info *> *get_functions_at_location (unsigned line_num) const;
373 /* Register a new function. */
374 void add_function (function_info *fn);
376 /* Debug the source file. */
377 void debug ();
379 /* Index of the source_info in sources vector. */
380 unsigned index;
382 /* Canonical name of source file. */
383 char *name;
384 time_t file_time;
386 /* Vector of line information. */
387 vector<line_info> lines;
389 coverage_info coverage;
391 /* Maximum line count in the source file. */
392 unsigned int maximum_count;
394 /* Functions in this source file. These are in ascending line
395 number order. */
396 vector<function_info *> functions;
398 /* Line number to functions map. */
399 vector<vector<function_info *> *> line_to_function_map;
402 source_info::source_info (): index (0), name (NULL), file_time (),
403 lines (), coverage (), maximum_count (0), functions ()
407 /* Register a new function. */
408 void
409 source_info::add_function (function_info *fn)
411 functions.push_back (fn);
413 if (fn->start_line >= line_to_function_map.size ())
414 line_to_function_map.resize (fn->start_line + 1);
416 vector<function_info *> **slot = &line_to_function_map[fn->start_line];
417 if (*slot == NULL)
418 *slot = new vector<function_info *> ();
420 (*slot)->push_back (fn);
423 vector<function_info *> *
424 source_info::get_functions_at_location (unsigned line_num) const
426 if (line_num >= line_to_function_map.size ())
427 return NULL;
429 vector<function_info *> *slot = line_to_function_map[line_num];
430 if (slot != NULL)
431 std::sort (slot->begin (), slot->end (), function_line_start_cmp ());
433 return slot;
436 void source_info::debug ()
438 fprintf (stderr, "source_info: %s\n", name);
439 for (vector<function_info *>::iterator it = functions.begin ();
440 it != functions.end (); it++)
442 function_info *fn = *it;
443 fprintf (stderr, " function_info: %s\n", fn->get_name ());
444 for (vector<block_info>::iterator bit = fn->blocks.begin ();
445 bit != fn->blocks.end (); bit++)
447 fprintf (stderr, " block_info id=%d, count=%" PRId64 " \n",
448 bit->id, bit->count);
452 for (unsigned lineno = 1; lineno < lines.size (); ++lineno)
454 line_info &line = lines[lineno];
455 fprintf (stderr, " line_info=%d, count=%" PRId64 "\n", lineno, line.count);
458 fprintf (stderr, "\n");
461 class name_map
463 public:
464 name_map ()
468 name_map (char *_name, unsigned _src): name (_name), src (_src)
472 bool operator== (const name_map &rhs) const
474 #if HAVE_DOS_BASED_FILE_SYSTEM
475 return strcasecmp (this->name, rhs.name) == 0;
476 #else
477 return strcmp (this->name, rhs.name) == 0;
478 #endif
481 bool operator< (const name_map &rhs) const
483 #if HAVE_DOS_BASED_FILE_SYSTEM
484 return strcasecmp (this->name, rhs.name) < 0;
485 #else
486 return strcmp (this->name, rhs.name) < 0;
487 #endif
490 const char *name; /* Source file name */
491 unsigned src; /* Source file */
494 /* Vector of all functions. */
495 static vector<function_info *> functions;
497 /* Function ident to function_info * map. */
498 static map<unsigned, function_info *> ident_to_fn;
500 /* Vector of source files. */
501 static vector<source_info> sources;
503 /* Mapping of file names to sources */
504 static vector<name_map> names;
506 /* Record all processed files in order to warn about
507 a file being read multiple times. */
508 static vector<char *> processed_files;
510 /* This holds data summary information. */
512 static unsigned object_runs;
514 static unsigned total_lines;
515 static unsigned total_executed;
517 /* Modification time of graph file. */
519 static time_t bbg_file_time;
521 /* Name of the notes (gcno) output file. The "bbg" prefix is for
522 historical reasons, when the notes file contained only the
523 basic block graph notes. */
525 static char *bbg_file_name;
527 /* Stamp of the bbg file */
528 static unsigned bbg_stamp;
530 /* Supports has_unexecuted_blocks functionality. */
531 static unsigned bbg_supports_has_unexecuted_blocks;
533 /* Working directory in which a TU was compiled. */
534 static const char *bbg_cwd;
536 /* Name and file pointer of the input file for the count data (gcda). */
538 static char *da_file_name;
540 /* Data file is missing. */
542 static int no_data_file;
544 /* If there is several input files, compute and display results after
545 reading all data files. This way if two or more gcda file refer to
546 the same source file (eg inline subprograms in a .h file), the
547 counts are added. */
549 static int multiple_files = 0;
551 /* Output branch probabilities. */
553 static int flag_branches = 0;
555 /* Show unconditional branches too. */
556 static int flag_unconditional = 0;
558 /* Output a gcov file if this is true. This is on by default, and can
559 be turned off by the -n option. */
561 static int flag_gcov_file = 1;
563 /* Output to stdout instead to a gcov file. */
565 static int flag_use_stdout = 0;
567 /* Output progress indication if this is true. This is off by default
568 and can be turned on by the -d option. */
570 static int flag_display_progress = 0;
572 /* Output *.gcov file in JSON intermediate format used by consumers. */
574 static int flag_json_format = 0;
576 /* For included files, make the gcov output file name include the name
577 of the input source file. For example, if x.h is included in a.c,
578 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
580 static int flag_long_names = 0;
582 /* For situations when a long name can potentially hit filesystem path limit,
583 let's calculate md5sum of the path and append it to a file name. */
585 static int flag_hash_filenames = 0;
587 /* Print verbose informations. */
589 static int flag_verbose = 0;
591 /* Print colored output. */
593 static int flag_use_colors = 0;
595 /* Use perf-like colors to indicate hot lines. */
597 static int flag_use_hotness_colors = 0;
599 /* Output count information for every basic block, not merely those
600 that contain line number information. */
602 static int flag_all_blocks = 0;
604 /* Output human readable numbers. */
606 static int flag_human_readable_numbers = 0;
608 /* Output summary info for each function. */
610 static int flag_function_summary = 0;
612 /* Print debugging dumps. */
614 static int flag_debug = 0;
616 /* Object directory file prefix. This is the directory/file where the
617 graph and data files are looked for, if nonzero. */
619 static char *object_directory = 0;
621 /* Source directory prefix. This is removed from source pathnames
622 that match, when generating the output file name. */
624 static char *source_prefix = 0;
625 static size_t source_length = 0;
627 /* Only show data for sources with relative pathnames. Absolute ones
628 usually indicate a system header file, which although it may
629 contain inline functions, is usually uninteresting. */
630 static int flag_relative_only = 0;
632 /* Preserve all pathname components. Needed when object files and
633 source files are in subdirectories. '/' is mangled as '#', '.' is
634 elided and '..' mangled to '^'. */
636 static int flag_preserve_paths = 0;
638 /* Output the number of times a branch was taken as opposed to the percentage
639 of times it was taken. */
641 static int flag_counts = 0;
643 /* Return code of the tool invocation. */
644 static int return_code = 0;
646 /* Forward declarations. */
647 static int process_args (int, char **);
648 static void print_usage (int) ATTRIBUTE_NORETURN;
649 static void print_version (void) ATTRIBUTE_NORETURN;
650 static void process_file (const char *);
651 static void process_all_functions (void);
652 static void generate_results (const char *);
653 static void create_file_names (const char *);
654 static char *canonicalize_name (const char *);
655 static unsigned find_source (const char *);
656 static void read_graph_file (void);
657 static int read_count_file (void);
658 static void solve_flow_graph (function_info *);
659 static void find_exception_blocks (function_info *);
660 static void add_branch_counts (coverage_info *, const arc_info *);
661 static void add_line_counts (coverage_info *, function_info *);
662 static void executed_summary (unsigned, unsigned);
663 static void function_summary (const coverage_info *);
664 static void file_summary (const coverage_info *);
665 static const char *format_gcov (gcov_type, gcov_type, int);
666 static void accumulate_line_counts (source_info *);
667 static void output_gcov_file (const char *, source_info *);
668 static int output_branch_count (FILE *, int, const arc_info *);
669 static void output_lines (FILE *, const source_info *);
670 static string make_gcov_file_name (const char *, const char *);
671 static char *mangle_name (const char *);
672 static void release_structures (void);
673 extern int main (int, char **);
675 function_info::function_info (): m_name (NULL), m_demangled_name (NULL),
676 ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
677 artificial (0), is_group (0),
678 blocks (), blocks_executed (0), counts (),
679 start_line (0), start_column (0), end_line (0), end_column (0),
680 src (0), lines (), next (NULL)
684 function_info::~function_info ()
686 for (int i = blocks.size () - 1; i >= 0; i--)
688 arc_info *arc, *arc_n;
690 for (arc = blocks[i].succ; arc; arc = arc_n)
692 arc_n = arc->succ_next;
693 free (arc);
696 if (m_demangled_name != m_name)
697 free (m_demangled_name);
698 free (m_name);
701 bool function_info::group_line_p (unsigned n, unsigned src_idx)
703 return is_group && src == src_idx && start_line <= n && n <= end_line;
706 /* Cycle detection!
707 There are a bajillion algorithms that do this. Boost's function is named
708 hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
709 "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
710 (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
712 The basic algorithm is simple: effectively, we're finding all simple paths
713 in a subgraph (that shrinks every iteration). Duplicates are filtered by
714 "blocking" a path when a node is added to the path (this also prevents non-
715 simple paths)--the node is unblocked only when it participates in a cycle.
718 typedef vector<arc_info *> arc_vector_t;
719 typedef vector<const block_info *> block_vector_t;
721 /* Handle cycle identified by EDGES, where the function finds minimum cs_count
722 and subtract the value from all counts. The subtracted value is added
723 to COUNT. Returns type of loop. */
725 static void
726 handle_cycle (const arc_vector_t &edges, int64_t &count)
728 /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
729 that amount. */
730 int64_t cycle_count = INTTYPE_MAXIMUM (int64_t);
731 for (unsigned i = 0; i < edges.size (); i++)
733 int64_t ecount = edges[i]->cs_count;
734 if (cycle_count > ecount)
735 cycle_count = ecount;
737 count += cycle_count;
738 for (unsigned i = 0; i < edges.size (); i++)
739 edges[i]->cs_count -= cycle_count;
741 gcc_assert (cycle_count > 0);
744 /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
745 blocked by U in BLOCK_LISTS. */
747 static void
748 unblock (const block_info *u, block_vector_t &blocked,
749 vector<block_vector_t > &block_lists)
751 block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u);
752 if (it == blocked.end ())
753 return;
755 unsigned index = it - blocked.begin ();
756 blocked.erase (it);
758 block_vector_t to_unblock (block_lists[index]);
760 block_lists.erase (block_lists.begin () + index);
762 for (block_vector_t::iterator it = to_unblock.begin ();
763 it != to_unblock.end (); it++)
764 unblock (*it, blocked, block_lists);
767 /* Return true when PATH contains a zero cycle arc count. */
769 static bool
770 path_contains_zero_or_negative_cycle_arc (arc_vector_t &path)
772 for (unsigned i = 0; i < path.size (); i++)
773 if (path[i]->cs_count <= 0)
774 return true;
775 return false;
778 /* Find circuit going to block V, PATH is provisional seen cycle.
779 BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
780 blocked by a block. COUNT is accumulated count of the current LINE.
781 Returns what type of loop it contains. */
783 static bool
784 circuit (block_info *v, arc_vector_t &path, block_info *start,
785 block_vector_t &blocked, vector<block_vector_t> &block_lists,
786 line_info &linfo, int64_t &count)
788 bool loop_found = false;
790 /* Add v to the block list. */
791 gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
792 blocked.push_back (v);
793 block_lists.push_back (block_vector_t ());
795 for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
797 block_info *w = arc->dst;
798 if (w < start
799 || arc->cs_count <= 0
800 || !linfo.has_block (w))
801 continue;
803 path.push_back (arc);
804 if (w == start)
806 /* Cycle has been found. */
807 handle_cycle (path, count);
808 loop_found = true;
810 else if (!path_contains_zero_or_negative_cycle_arc (path)
811 && find (blocked.begin (), blocked.end (), w) == blocked.end ())
812 loop_found |= circuit (w, path, start, blocked, block_lists, linfo,
813 count);
815 path.pop_back ();
818 if (loop_found)
819 unblock (v, blocked, block_lists);
820 else
821 for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
823 block_info *w = arc->dst;
824 if (w < start
825 || arc->cs_count <= 0
826 || !linfo.has_block (w))
827 continue;
829 size_t index
830 = find (blocked.begin (), blocked.end (), w) - blocked.begin ();
831 gcc_assert (index < blocked.size ());
832 block_vector_t &list = block_lists[index];
833 if (find (list.begin (), list.end (), v) == list.end ())
834 list.push_back (v);
837 return loop_found;
840 /* Find cycles for a LINFO. */
842 static gcov_type
843 get_cycles_count (line_info &linfo)
845 /* Note that this algorithm works even if blocks aren't in sorted order.
846 Each iteration of the circuit detection is completely independent
847 (except for reducing counts, but that shouldn't matter anyways).
848 Therefore, operating on a permuted order (i.e., non-sorted) only
849 has the effect of permuting the output cycles. */
851 gcov_type count = 0;
852 for (vector<block_info *>::iterator it = linfo.blocks.begin ();
853 it != linfo.blocks.end (); it++)
855 arc_vector_t path;
856 block_vector_t blocked;
857 vector<block_vector_t > block_lists;
858 circuit (*it, path, *it, blocked, block_lists, linfo, count);
861 return count;
865 main (int argc, char **argv)
867 int argno;
868 int first_arg;
869 const char *p;
871 p = argv[0] + strlen (argv[0]);
872 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
873 --p;
874 progname = p;
876 xmalloc_set_program_name (progname);
878 /* Unlock the stdio streams. */
879 unlock_std_streams ();
881 gcc_init_libintl ();
883 diagnostic_initialize (global_dc, 0);
885 /* Handle response files. */
886 expandargv (&argc, &argv);
888 argno = process_args (argc, argv);
889 if (optind == argc)
890 print_usage (true);
892 if (argc - argno > 1)
893 multiple_files = 1;
895 first_arg = argno;
897 for (; argno != argc; argno++)
899 if (flag_display_progress)
900 printf ("Processing file %d out of %d\n", argno - first_arg + 1,
901 argc - first_arg);
902 process_file (argv[argno]);
904 if (flag_json_format || argno == argc - 1)
906 process_all_functions ();
907 generate_results (argv[argno]);
908 release_structures ();
912 if (!flag_use_stdout)
913 executed_summary (total_lines, total_executed);
915 return return_code;
918 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
919 otherwise the output of --help. */
921 static void
922 print_usage (int error_p)
924 FILE *file = error_p ? stderr : stdout;
925 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
927 fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
928 fnotice (file, "Print code coverage information.\n\n");
929 fnotice (file, " -a, --all-blocks Show information for every basic block\n");
930 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
931 fnotice (file, " -c, --branch-counts Output counts of branches taken\n\
932 rather than percentages\n");
933 fnotice (file, " -d, --display-progress Display progress information\n");
934 fnotice (file, " -D, --debug Display debugging dumps\n");
935 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
936 fnotice (file, " -h, --help Print this help, then exit\n");
937 fnotice (file, " -j, --json-format Output JSON intermediate format\n\
938 into .gcov.json.gz file\n");
939 fnotice (file, " -H, --human-readable Output human readable numbers\n");
940 fnotice (file, " -k, --use-colors Emit colored output\n");
941 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
942 source files\n");
943 fnotice (file, " -m, --demangled-names Output demangled function names\n");
944 fnotice (file, " -n, --no-output Do not create an output file\n");
945 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
946 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
947 fnotice (file, " -q, --use-hotness-colors Emit perf-like colored output for hot lines\n");
948 fnotice (file, " -r, --relative-only Only show data for relative sources\n");
949 fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n");
950 fnotice (file, " -t, --stdout Output to stdout instead of a file\n");
951 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
952 fnotice (file, " -v, --version Print version number, then exit\n");
953 fnotice (file, " -w, --verbose Print verbose informations\n");
954 fnotice (file, " -x, --hash-filenames Hash long pathnames\n");
955 fnotice (file, "\nObsolete options:\n");
956 fnotice (file, " -i, --json-format Replaced with -j, --json-format\n");
957 fnotice (file, " -j, --human-readable Replaced with -H, --human-readable\n");
958 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
959 bug_report_url);
960 exit (status);
963 /* Print version information and exit. */
965 static void
966 print_version (void)
968 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
969 fnotice (stdout, "JSON format version: %s\n", GCOV_JSON_FORMAT_VERSION);
970 fprintf (stdout, "Copyright %s 2023 Free Software Foundation, Inc.\n",
971 _("(C)"));
972 fnotice (stdout,
973 _("This is free software; see the source for copying conditions. There is NO\n\
974 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
975 exit (SUCCESS_EXIT_CODE);
978 static const struct option options[] =
980 { "help", no_argument, NULL, 'h' },
981 { "version", no_argument, NULL, 'v' },
982 { "verbose", no_argument, NULL, 'w' },
983 { "all-blocks", no_argument, NULL, 'a' },
984 { "branch-probabilities", no_argument, NULL, 'b' },
985 { "branch-counts", no_argument, NULL, 'c' },
986 { "json-format", no_argument, NULL, 'j' },
987 { "human-readable", no_argument, NULL, 'H' },
988 { "no-output", no_argument, NULL, 'n' },
989 { "long-file-names", no_argument, NULL, 'l' },
990 { "function-summaries", no_argument, NULL, 'f' },
991 { "demangled-names", no_argument, NULL, 'm' },
992 { "preserve-paths", no_argument, NULL, 'p' },
993 { "relative-only", no_argument, NULL, 'r' },
994 { "object-directory", required_argument, NULL, 'o' },
995 { "object-file", required_argument, NULL, 'o' },
996 { "source-prefix", required_argument, NULL, 's' },
997 { "stdout", no_argument, NULL, 't' },
998 { "unconditional-branches", no_argument, NULL, 'u' },
999 { "display-progress", no_argument, NULL, 'd' },
1000 { "hash-filenames", no_argument, NULL, 'x' },
1001 { "use-colors", no_argument, NULL, 'k' },
1002 { "use-hotness-colors", no_argument, NULL, 'q' },
1003 { "debug", no_argument, NULL, 'D' },
1004 { 0, 0, 0, 0 }
1007 /* Process args, return index to first non-arg. */
1009 static int
1010 process_args (int argc, char **argv)
1012 int opt;
1014 const char *opts = "abcdDfhHijklmno:pqrs:tuvwx";
1015 while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
1017 switch (opt)
1019 case 'a':
1020 flag_all_blocks = 1;
1021 break;
1022 case 'b':
1023 flag_branches = 1;
1024 break;
1025 case 'c':
1026 flag_counts = 1;
1027 break;
1028 case 'f':
1029 flag_function_summary = 1;
1030 break;
1031 case 'h':
1032 print_usage (false);
1033 /* print_usage will exit. */
1034 case 'l':
1035 flag_long_names = 1;
1036 break;
1037 case 'H':
1038 flag_human_readable_numbers = 1;
1039 break;
1040 case 'k':
1041 flag_use_colors = 1;
1042 break;
1043 case 'q':
1044 flag_use_hotness_colors = 1;
1045 break;
1046 case 'm':
1047 flag_demangled_names = 1;
1048 break;
1049 case 'n':
1050 flag_gcov_file = 0;
1051 break;
1052 case 'o':
1053 object_directory = optarg;
1054 break;
1055 case 's':
1056 source_prefix = optarg;
1057 source_length = strlen (source_prefix);
1058 break;
1059 case 'r':
1060 flag_relative_only = 1;
1061 break;
1062 case 'p':
1063 flag_preserve_paths = 1;
1064 break;
1065 case 'u':
1066 flag_unconditional = 1;
1067 break;
1068 case 'i':
1069 case 'j':
1070 flag_json_format = 1;
1071 flag_gcov_file = 1;
1072 break;
1073 case 'd':
1074 flag_display_progress = 1;
1075 break;
1076 case 'x':
1077 flag_hash_filenames = 1;
1078 break;
1079 case 'w':
1080 flag_verbose = 1;
1081 break;
1082 case 't':
1083 flag_use_stdout = 1;
1084 break;
1085 case 'D':
1086 flag_debug = 1;
1087 break;
1088 case 'v':
1089 print_version ();
1090 /* print_version will exit. */
1091 default:
1092 print_usage (true);
1093 /* print_usage will exit. */
1097 return optind;
1100 /* Output intermediate LINE sitting on LINE_NUM to JSON OBJECT.
1101 Add FUNCTION_NAME to the LINE. */
1103 static void
1104 output_intermediate_json_line (json::array *object,
1105 line_info *line, unsigned line_num,
1106 const char *function_name)
1108 if (!line->exists)
1109 return;
1111 json::object *lineo = new json::object ();
1112 lineo->set ("line_number", new json::integer_number (line_num));
1113 if (function_name != NULL)
1114 lineo->set ("function_name", new json::string (function_name));
1115 lineo->set ("count", new json::integer_number (line->count));
1116 lineo->set ("unexecuted_block",
1117 new json::literal (line->has_unexecuted_block));
1119 json::array *bb_ids = new json::array ();
1120 for (const block_info *block : line->blocks)
1121 bb_ids->append (new json::integer_number (block->id));
1122 lineo->set ("block_ids", bb_ids);
1124 json::array *branches = new json::array ();
1125 lineo->set ("branches", branches);
1127 json::array *calls = new json::array ();
1128 lineo->set ("calls", calls);
1130 vector<arc_info *>::const_iterator it;
1131 if (flag_branches)
1132 for (it = line->branches.begin (); it != line->branches.end ();
1133 it++)
1135 if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
1137 json::object *branch = new json::object ();
1138 branch->set ("count", new json::integer_number ((*it)->count));
1139 branch->set ("throw", new json::literal ((*it)->is_throw));
1140 branch->set ("fallthrough",
1141 new json::literal ((*it)->fall_through));
1142 branch->set ("source_block_id",
1143 new json::integer_number ((*it)->src->id));
1144 branch->set ("destination_block_id",
1145 new json::integer_number ((*it)->dst->id));
1146 branches->append (branch);
1148 else if ((*it)->is_call_non_return)
1150 json::object *call = new json::object ();
1151 gcov_type returns = (*it)->src->count - (*it)->count;
1152 call->set ("source_block_id",
1153 new json::integer_number ((*it)->src->id));
1154 call->set ("destination_block_id",
1155 new json::integer_number ((*it)->dst->id));
1156 call->set ("returned", new json::integer_number (returns));
1157 calls->append (call);
1161 object->append (lineo);
1164 /* Strip filename extension in STR. */
1166 static string
1167 strip_extention (string str)
1169 string::size_type pos = str.rfind ('.');
1170 if (pos != string::npos)
1171 str = str.substr (0, pos);
1173 return str;
1176 /* Calcualte md5sum for INPUT string and return it in hex string format. */
1178 static string
1179 get_md5sum (const char *input)
1181 md5_ctx ctx;
1182 char md5sum[16];
1183 string str;
1185 md5_init_ctx (&ctx);
1186 md5_process_bytes (input, strlen (input), &ctx);
1187 md5_finish_ctx (&ctx, md5sum);
1189 for (unsigned i = 0; i < 16; i++)
1191 char b[3];
1192 sprintf (b, "%02x", (unsigned char)md5sum[i]);
1193 str += b;
1196 return str;
1199 /* Get the name of the gcov file. The return value must be free'd.
1201 It appends the '.gcov' extension to the *basename* of the file.
1202 The resulting file name will be in PWD.
1204 e.g.,
1205 input: foo.da, output: foo.da.gcov
1206 input: a/b/foo.cc, output: foo.cc.gcov */
1208 static string
1209 get_gcov_intermediate_filename (const char *input_file_name)
1211 string base = basename (input_file_name);
1212 string str = strip_extention (base);
1214 if (flag_hash_filenames)
1216 str += "##";
1217 str += get_md5sum (input_file_name);
1219 else if (flag_preserve_paths && base != input_file_name)
1221 str += "##";
1222 str += mangle_path (input_file_name);
1223 str = strip_extention (str);
1226 str += ".gcov.json.gz";
1227 return str.c_str ();
1230 /* Output the result in JSON intermediate format.
1231 Source info SRC is dumped into JSON_FILES which is JSON array. */
1233 static void
1234 output_json_intermediate_file (json::array *json_files, source_info *src)
1236 json::object *root = new json::object ();
1237 json_files->append (root);
1239 root->set ("file", new json::string (src->name));
1241 json::array *functions = new json::array ();
1242 root->set ("functions", functions);
1244 std::sort (src->functions.begin (), src->functions.end (),
1245 function_line_start_cmp ());
1246 for (vector<function_info *>::iterator it = src->functions.begin ();
1247 it != src->functions.end (); it++)
1249 json::object *function = new json::object ();
1250 function->set ("name", new json::string ((*it)->m_name));
1251 function->set ("demangled_name",
1252 new json::string ((*it)->get_demangled_name ()));
1253 function->set ("start_line",
1254 new json::integer_number ((*it)->start_line));
1255 function->set ("start_column",
1256 new json::integer_number ((*it)->start_column));
1257 function->set ("end_line", new json::integer_number ((*it)->end_line));
1258 function->set ("end_column",
1259 new json::integer_number ((*it)->end_column));
1260 function->set ("blocks",
1261 new json::integer_number ((*it)->get_block_count ()));
1262 function->set ("blocks_executed",
1263 new json::integer_number ((*it)->blocks_executed));
1264 function->set ("execution_count",
1265 new json::integer_number ((*it)->blocks[0].count));
1267 functions->append (function);
1270 json::array *lineso = new json::array ();
1271 root->set ("lines", lineso);
1273 vector<function_info *> last_non_group_fns;
1275 for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
1277 vector<function_info *> *fns = src->get_functions_at_location (line_num);
1279 if (fns != NULL)
1280 /* Print info for all group functions that begin on the line. */
1281 for (vector<function_info *>::iterator it2 = fns->begin ();
1282 it2 != fns->end (); it2++)
1284 if (!(*it2)->is_group)
1285 last_non_group_fns.push_back (*it2);
1287 vector<line_info> &lines = (*it2)->lines;
1288 /* The LINES array is allocated only for group functions. */
1289 for (unsigned i = 0; i < lines.size (); i++)
1291 line_info *line = &lines[i];
1292 output_intermediate_json_line (lineso, line, line_num + i,
1293 (*it2)->m_name);
1297 /* Follow with lines associated with the source file. */
1298 if (line_num < src->lines.size ())
1300 unsigned size = last_non_group_fns.size ();
1301 function_info *last_fn = size > 0 ? last_non_group_fns[size - 1] : NULL;
1302 const char *fname = last_fn ? last_fn->m_name : NULL;
1303 output_intermediate_json_line (lineso, &src->lines[line_num], line_num,
1304 fname);
1306 /* Pop ending function from stack. */
1307 if (last_fn != NULL && last_fn->end_line == line_num)
1308 last_non_group_fns.pop_back ();
1313 /* Function start pair. */
1314 struct function_start
1316 unsigned source_file_idx;
1317 unsigned start_line;
1320 /* Traits class for function start hash maps below. */
1322 struct function_start_pair_hash : typed_noop_remove <function_start>
1324 typedef function_start value_type;
1325 typedef function_start compare_type;
1327 static hashval_t
1328 hash (const function_start &ref)
1330 inchash::hash hstate (0);
1331 hstate.add_int (ref.source_file_idx);
1332 hstate.add_int (ref.start_line);
1333 return hstate.end ();
1336 static bool
1337 equal (const function_start &ref1, const function_start &ref2)
1339 return (ref1.source_file_idx == ref2.source_file_idx
1340 && ref1.start_line == ref2.start_line);
1343 static void
1344 mark_deleted (function_start &ref)
1346 ref.start_line = ~1U;
1349 static const bool empty_zero_p = false;
1351 static void
1352 mark_empty (function_start &ref)
1354 ref.start_line = ~2U;
1357 static bool
1358 is_deleted (const function_start &ref)
1360 return ref.start_line == ~1U;
1363 static bool
1364 is_empty (const function_start &ref)
1366 return ref.start_line == ~2U;
1370 /* Process a single input file. */
1372 static void
1373 process_file (const char *file_name)
1375 create_file_names (file_name);
1377 for (unsigned i = 0; i < processed_files.size (); i++)
1378 if (strcmp (da_file_name, processed_files[i]) == 0)
1380 fnotice (stderr, "'%s' file is already processed\n",
1381 file_name);
1382 return;
1385 processed_files.push_back (xstrdup (da_file_name));
1387 read_graph_file ();
1388 read_count_file ();
1391 /* Process all functions in all files. */
1393 static void
1394 process_all_functions (void)
1396 hash_map<function_start_pair_hash, function_info *> fn_map;
1398 /* Identify group functions. */
1399 for (vector<function_info *>::iterator it = functions.begin ();
1400 it != functions.end (); it++)
1401 if (!(*it)->artificial)
1403 function_start needle;
1404 needle.source_file_idx = (*it)->src;
1405 needle.start_line = (*it)->start_line;
1407 function_info **slot = fn_map.get (needle);
1408 if (slot)
1410 (*slot)->is_group = 1;
1411 (*it)->is_group = 1;
1413 else
1414 fn_map.put (needle, *it);
1417 /* Remove all artificial function. */
1418 functions.erase (remove_if (functions.begin (), functions.end (),
1419 function_info::is_artificial), functions.end ());
1421 for (vector<function_info *>::iterator it = functions.begin ();
1422 it != functions.end (); it++)
1424 function_info *fn = *it;
1425 unsigned src = fn->src;
1427 if (!fn->counts.empty () || no_data_file)
1429 source_info *s = &sources[src];
1430 s->add_function (fn);
1432 /* Mark last line in files touched by function. */
1433 for (unsigned block_no = 0; block_no != fn->blocks.size ();
1434 block_no++)
1436 block_info *block = &fn->blocks[block_no];
1437 for (unsigned i = 0; i < block->locations.size (); i++)
1439 /* Sort lines of locations. */
1440 sort (block->locations[i].lines.begin (),
1441 block->locations[i].lines.end ());
1443 if (!block->locations[i].lines.empty ())
1445 s = &sources[block->locations[i].source_file_idx];
1446 unsigned last_line
1447 = block->locations[i].lines.back ();
1449 /* Record new lines for the function. */
1450 if (last_line >= s->lines.size ())
1452 s = &sources[block->locations[i].source_file_idx];
1453 unsigned last_line
1454 = block->locations[i].lines.back ();
1456 /* Record new lines for the function. */
1457 if (last_line >= s->lines.size ())
1459 /* Record new lines for a source file. */
1460 s->lines.resize (last_line + 1);
1467 /* Allocate lines for group function, following start_line
1468 and end_line information of the function. */
1469 if (fn->is_group)
1470 fn->lines.resize (fn->end_line - fn->start_line + 1);
1472 solve_flow_graph (fn);
1473 if (fn->has_catch)
1474 find_exception_blocks (fn);
1476 else
1478 /* The function was not in the executable -- some other
1479 instance must have been selected. */
1484 static void
1485 output_gcov_file (const char *file_name, source_info *src)
1487 string gcov_file_name_str
1488 = make_gcov_file_name (file_name, src->coverage.name);
1489 const char *gcov_file_name = gcov_file_name_str.c_str ();
1491 if (src->coverage.lines)
1493 FILE *gcov_file = fopen (gcov_file_name, "w");
1494 if (gcov_file)
1496 fnotice (stdout, "Creating '%s'\n", gcov_file_name);
1497 output_lines (gcov_file, src);
1498 if (ferror (gcov_file))
1500 fnotice (stderr, "Error writing output file '%s'\n",
1501 gcov_file_name);
1502 return_code = 6;
1504 fclose (gcov_file);
1506 else
1508 fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
1509 return_code = 6;
1512 else
1514 unlink (gcov_file_name);
1515 fnotice (stdout, "Removing '%s'\n", gcov_file_name);
1519 static void
1520 generate_results (const char *file_name)
1522 string gcov_intermediate_filename;
1524 for (vector<function_info *>::iterator it = functions.begin ();
1525 it != functions.end (); it++)
1527 function_info *fn = *it;
1528 coverage_info coverage;
1530 memset (&coverage, 0, sizeof (coverage));
1531 coverage.name = fn->get_name ();
1532 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
1533 if (flag_function_summary)
1535 function_summary (&coverage);
1536 fnotice (stdout, "\n");
1540 name_map needle;
1541 needle.name = file_name;
1542 vector<name_map>::iterator it
1543 = std::find (names.begin (), names.end (), needle);
1544 if (it != names.end ())
1545 file_name = sources[it->src].coverage.name;
1546 else
1547 file_name = canonicalize_name (file_name);
1549 gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
1551 json::object *root = new json::object ();
1552 root->set ("format_version", new json::string (GCOV_JSON_FORMAT_VERSION));
1553 root->set ("gcc_version", new json::string (version_string));
1555 if (bbg_cwd != NULL)
1556 root->set ("current_working_directory", new json::string (bbg_cwd));
1557 root->set ("data_file", new json::string (file_name));
1559 json::array *json_files = new json::array ();
1560 root->set ("files", json_files);
1562 for (vector<source_info>::iterator it = sources.begin ();
1563 it != sources.end (); it++)
1565 source_info *src = &(*it);
1566 if (flag_relative_only)
1568 /* Ignore this source, if it is an absolute path (after
1569 source prefix removal). */
1570 char first = src->coverage.name[0];
1572 #if HAVE_DOS_BASED_FILE_SYSTEM
1573 if (first && src->coverage.name[1] == ':')
1574 first = src->coverage.name[2];
1575 #endif
1576 if (IS_DIR_SEPARATOR (first))
1577 continue;
1580 accumulate_line_counts (src);
1581 if (flag_debug)
1582 src->debug ();
1584 if (!flag_use_stdout)
1585 file_summary (&src->coverage);
1586 total_lines += src->coverage.lines;
1587 total_executed += src->coverage.lines_executed;
1588 if (flag_gcov_file)
1590 if (flag_json_format)
1592 output_json_intermediate_file (json_files, src);
1593 if (!flag_use_stdout)
1594 fnotice (stdout, "\n");
1596 else
1598 if (flag_use_stdout)
1600 if (src->coverage.lines)
1601 output_lines (stdout, src);
1603 else
1605 output_gcov_file (file_name, src);
1606 fnotice (stdout, "\n");
1612 if (flag_gcov_file && flag_json_format)
1614 if (flag_use_stdout)
1616 root->dump (stdout);
1617 printf ("\n");
1619 else
1621 pretty_printer pp;
1622 root->print (&pp);
1623 pp_formatted_text (&pp);
1625 fnotice (stdout, "Creating '%s'\n",
1626 gcov_intermediate_filename.c_str ());
1627 gzFile output = gzopen (gcov_intermediate_filename.c_str (), "w");
1628 if (output == NULL)
1630 fnotice (stderr, "Cannot open JSON output file %s\n",
1631 gcov_intermediate_filename.c_str ());
1632 return_code = 6;
1633 return;
1636 if (gzputs (output, pp_formatted_text (&pp)) == EOF
1637 || gzclose (output))
1639 fnotice (stderr, "Error writing JSON output file %s\n",
1640 gcov_intermediate_filename.c_str ());
1641 return_code = 6;
1642 return;
1648 /* Release all memory used. */
1650 static void
1651 release_structures (void)
1653 for (vector<function_info *>::iterator it = functions.begin ();
1654 it != functions.end (); it++)
1655 delete (*it);
1657 sources.resize (0);
1658 names.resize (0);
1659 functions.resize (0);
1660 ident_to_fn.clear ();
1663 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
1664 is not specified, these are named from FILE_NAME sans extension. If
1665 OBJECT_DIRECTORY is specified and is a directory, the files are in that
1666 directory, but named from the basename of the FILE_NAME, sans extension.
1667 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
1668 and the data files are named from that. */
1670 static void
1671 create_file_names (const char *file_name)
1673 char *cptr;
1674 char *name;
1675 int length = strlen (file_name);
1676 int base;
1678 /* Free previous file names. */
1679 free (bbg_file_name);
1680 free (da_file_name);
1681 da_file_name = bbg_file_name = NULL;
1682 bbg_file_time = 0;
1683 bbg_stamp = 0;
1685 if (object_directory && object_directory[0])
1687 struct stat status;
1689 length += strlen (object_directory) + 2;
1690 name = XNEWVEC (char, length);
1691 name[0] = 0;
1693 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
1694 strcat (name, object_directory);
1695 if (base && (!IS_DIR_SEPARATOR (name[strlen (name) - 1])))
1696 strcat (name, "/");
1698 else
1700 name = XNEWVEC (char, length + 1);
1701 strcpy (name, file_name);
1702 base = 0;
1705 if (base)
1707 /* Append source file name. */
1708 const char *cptr = lbasename (file_name);
1709 strcat (name, cptr ? cptr : file_name);
1712 /* Remove the extension. */
1713 cptr = strrchr (CONST_CAST (char *, lbasename (name)), '.');
1714 if (cptr)
1715 *cptr = 0;
1717 length = strlen (name);
1719 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
1720 strcpy (bbg_file_name, name);
1721 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
1723 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
1724 strcpy (da_file_name, name);
1725 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
1727 free (name);
1728 return;
1731 /* Find or create a source file structure for FILE_NAME. Copies
1732 FILE_NAME on creation */
1734 static unsigned
1735 find_source (const char *file_name)
1737 char *canon;
1738 unsigned idx;
1739 struct stat status;
1741 if (!file_name)
1742 file_name = "<unknown>";
1744 name_map needle;
1745 needle.name = file_name;
1747 vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1748 needle);
1749 if (it != names.end ())
1751 idx = it->src;
1752 goto check_date;
1755 /* Not found, try the canonical name. */
1756 canon = canonicalize_name (file_name);
1757 needle.name = canon;
1758 it = std::find (names.begin (), names.end (), needle);
1759 if (it == names.end ())
1761 /* Not found with canonical name, create a new source. */
1762 source_info *src;
1764 idx = sources.size ();
1765 needle = name_map (canon, idx);
1766 names.push_back (needle);
1768 sources.push_back (source_info ());
1769 src = &sources.back ();
1770 src->name = canon;
1771 src->coverage.name = src->name;
1772 src->index = idx;
1773 if (source_length
1774 #if HAVE_DOS_BASED_FILE_SYSTEM
1775 /* You lose if separators don't match exactly in the
1776 prefix. */
1777 && !strncasecmp (source_prefix, src->coverage.name, source_length)
1778 #else
1779 && !strncmp (source_prefix, src->coverage.name, source_length)
1780 #endif
1781 && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
1782 src->coverage.name += source_length + 1;
1783 if (!stat (src->name, &status))
1784 src->file_time = status.st_mtime;
1786 else
1787 idx = it->src;
1789 needle.name = file_name;
1790 if (std::find (names.begin (), names.end (), needle) == names.end ())
1792 /* Append the non-canonical name. */
1793 names.push_back (name_map (xstrdup (file_name), idx));
1796 /* Resort the name map. */
1797 std::sort (names.begin (), names.end ());
1799 check_date:
1800 if (sources[idx].file_time > bbg_file_time)
1802 static int info_emitted;
1804 fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
1805 file_name, bbg_file_name);
1806 if (!info_emitted)
1808 fnotice (stderr,
1809 "(the message is displayed only once per source file)\n");
1810 info_emitted = 1;
1812 sources[idx].file_time = 0;
1815 return idx;
1818 /* Read the notes file. Save functions to FUNCTIONS global vector. */
1820 static void
1821 read_graph_file (void)
1823 unsigned version;
1824 unsigned current_tag = 0;
1825 unsigned tag;
1827 if (!gcov_open (bbg_file_name, 1))
1829 fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1830 return_code = 1;
1831 return;
1833 bbg_file_time = gcov_time ();
1834 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1836 fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
1837 return_code = 2;
1838 gcov_close ();
1839 return;
1842 version = gcov_read_unsigned ();
1843 if (version != GCOV_VERSION)
1845 char v[4], e[4];
1847 GCOV_UNSIGNED2STRING (v, version);
1848 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1850 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1851 bbg_file_name, v, e);
1852 return_code = 3;
1854 bbg_stamp = gcov_read_unsigned ();
1855 /* Read checksum. */
1856 gcov_read_unsigned ();
1857 bbg_cwd = xstrdup (gcov_read_string ());
1858 bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
1860 function_info *fn = NULL;
1861 while ((tag = gcov_read_unsigned ()))
1863 unsigned length = gcov_read_unsigned ();
1864 gcov_position_t base = gcov_position ();
1866 if (tag == GCOV_TAG_FUNCTION)
1868 char *function_name;
1869 unsigned ident;
1870 unsigned lineno_checksum, cfg_checksum;
1872 ident = gcov_read_unsigned ();
1873 lineno_checksum = gcov_read_unsigned ();
1874 cfg_checksum = gcov_read_unsigned ();
1875 function_name = xstrdup (gcov_read_string ());
1876 unsigned artificial = gcov_read_unsigned ();
1877 unsigned src_idx = find_source (gcov_read_string ());
1878 unsigned start_line = gcov_read_unsigned ();
1879 unsigned start_column = gcov_read_unsigned ();
1880 unsigned end_line = gcov_read_unsigned ();
1881 unsigned end_column = gcov_read_unsigned ();
1883 fn = new function_info ();
1884 functions.push_back (fn);
1885 ident_to_fn[ident] = fn;
1887 fn->m_name = function_name;
1888 fn->ident = ident;
1889 fn->lineno_checksum = lineno_checksum;
1890 fn->cfg_checksum = cfg_checksum;
1891 fn->src = src_idx;
1892 fn->start_line = start_line;
1893 fn->start_column = start_column;
1894 fn->end_line = end_line;
1895 fn->end_column = end_column;
1896 fn->artificial = artificial;
1898 current_tag = tag;
1900 else if (fn && tag == GCOV_TAG_BLOCKS)
1902 if (!fn->blocks.empty ())
1903 fnotice (stderr, "%s:already seen blocks for '%s'\n",
1904 bbg_file_name, fn->get_name ());
1905 else
1906 fn->blocks.resize (gcov_read_unsigned ());
1908 else if (fn && tag == GCOV_TAG_ARCS)
1910 unsigned src = gcov_read_unsigned ();
1911 fn->blocks[src].id = src;
1912 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1913 block_info *src_blk = &fn->blocks[src];
1914 unsigned mark_catches = 0;
1915 struct arc_info *arc;
1917 if (src >= fn->blocks.size () || fn->blocks[src].succ)
1918 goto corrupt;
1920 while (num_dests--)
1922 unsigned dest = gcov_read_unsigned ();
1923 unsigned flags = gcov_read_unsigned ();
1925 if (dest >= fn->blocks.size ())
1926 goto corrupt;
1927 arc = XCNEW (arc_info);
1929 arc->dst = &fn->blocks[dest];
1930 /* Set id in order to find EXIT_BLOCK. */
1931 arc->dst->id = dest;
1932 arc->src = src_blk;
1934 arc->count = 0;
1935 arc->count_valid = 0;
1936 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
1937 arc->fake = !!(flags & GCOV_ARC_FAKE);
1938 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
1940 arc->succ_next = src_blk->succ;
1941 src_blk->succ = arc;
1942 src_blk->num_succ++;
1944 arc->pred_next = fn->blocks[dest].pred;
1945 fn->blocks[dest].pred = arc;
1946 fn->blocks[dest].num_pred++;
1948 if (arc->fake)
1950 if (src)
1952 /* Exceptional exit from this function, the
1953 source block must be a call. */
1954 fn->blocks[src].is_call_site = 1;
1955 arc->is_call_non_return = 1;
1956 mark_catches = 1;
1958 else
1960 /* Non-local return from a callee of this
1961 function. The destination block is a setjmp. */
1962 arc->is_nonlocal_return = 1;
1963 fn->blocks[dest].is_nonlocal_return = 1;
1967 if (!arc->on_tree)
1968 fn->counts.push_back (0);
1971 if (mark_catches)
1973 /* We have a fake exit from this block. The other
1974 non-fall through exits must be to catch handlers.
1975 Mark them as catch arcs. */
1977 for (arc = src_blk->succ; arc; arc = arc->succ_next)
1978 if (!arc->fake && !arc->fall_through)
1980 arc->is_throw = 1;
1981 fn->has_catch = 1;
1985 else if (fn && tag == GCOV_TAG_LINES)
1987 unsigned blockno = gcov_read_unsigned ();
1988 block_info *block = &fn->blocks[blockno];
1990 if (blockno >= fn->blocks.size ())
1991 goto corrupt;
1993 while (true)
1995 unsigned lineno = gcov_read_unsigned ();
1997 if (lineno)
1998 block->locations.back ().lines.push_back (lineno);
1999 else
2001 const char *file_name = gcov_read_string ();
2003 if (!file_name)
2004 break;
2005 block->locations.push_back (block_location_info
2006 (find_source (file_name)));
2010 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
2012 fn = NULL;
2013 current_tag = 0;
2015 gcov_sync (base, length);
2016 if (gcov_is_error ())
2018 corrupt:;
2019 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
2020 return_code = 4;
2021 break;
2024 gcov_close ();
2026 if (functions.empty ())
2027 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
2030 /* Reads profiles from the count file and attach to each
2031 function. Return nonzero if fatal error. */
2033 static int
2034 read_count_file (void)
2036 unsigned ix;
2037 unsigned version;
2038 unsigned tag;
2039 function_info *fn = NULL;
2040 int error = 0;
2041 map<unsigned, function_info *>::iterator it;
2043 if (!gcov_open (da_file_name, 1))
2045 fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
2046 da_file_name);
2047 no_data_file = 1;
2048 return 0;
2050 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
2052 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
2053 return_code = 2;
2054 cleanup:;
2055 gcov_close ();
2056 return 1;
2058 version = gcov_read_unsigned ();
2059 if (version != GCOV_VERSION)
2061 char v[4], e[4];
2063 GCOV_UNSIGNED2STRING (v, version);
2064 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
2066 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
2067 da_file_name, v, e);
2068 return_code = 3;
2070 tag = gcov_read_unsigned ();
2071 if (tag != bbg_stamp)
2073 fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
2074 return_code = 5;
2075 goto cleanup;
2078 /* Read checksum. */
2079 gcov_read_unsigned ();
2081 while ((tag = gcov_read_unsigned ()))
2083 unsigned length = gcov_read_unsigned ();
2084 int read_length = (int)length;
2085 unsigned long base = gcov_position ();
2087 if (tag == GCOV_TAG_OBJECT_SUMMARY)
2089 struct gcov_summary summary;
2090 gcov_read_summary (&summary);
2091 object_runs = summary.runs;
2093 else if (tag == GCOV_TAG_FUNCTION && !length)
2094 ; /* placeholder */
2095 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
2097 unsigned ident;
2098 ident = gcov_read_unsigned ();
2099 fn = NULL;
2100 it = ident_to_fn.find (ident);
2101 if (it != ident_to_fn.end ())
2102 fn = it->second;
2104 if (!fn)
2106 else if (gcov_read_unsigned () != fn->lineno_checksum
2107 || gcov_read_unsigned () != fn->cfg_checksum)
2109 mismatch:;
2110 fnotice (stderr, "%s:profile mismatch for '%s'\n",
2111 da_file_name, fn->get_name ());
2112 goto cleanup;
2115 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
2117 length = abs (read_length);
2118 if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
2119 goto mismatch;
2121 if (read_length > 0)
2122 for (ix = 0; ix != fn->counts.size (); ix++)
2123 fn->counts[ix] += gcov_read_counter ();
2125 if (read_length < 0)
2126 read_length = 0;
2127 gcov_sync (base, read_length);
2128 if ((error = gcov_is_error ()))
2130 fnotice (stderr,
2131 error < 0
2132 ? N_("%s:overflowed\n")
2133 : N_("%s:corrupted\n"),
2134 da_file_name);
2135 return_code = 4;
2136 goto cleanup;
2140 gcov_close ();
2141 return 0;
2144 /* Solve the flow graph. Propagate counts from the instrumented arcs
2145 to the blocks and the uninstrumented arcs. */
2147 static void
2148 solve_flow_graph (function_info *fn)
2150 unsigned ix;
2151 arc_info *arc;
2152 gcov_type *count_ptr = &fn->counts.front ();
2153 block_info *blk;
2154 block_info *valid_blocks = NULL; /* valid, but unpropagated blocks. */
2155 block_info *invalid_blocks = NULL; /* invalid, but inferable blocks. */
2157 /* The arcs were built in reverse order. Fix that now. */
2158 for (ix = fn->blocks.size (); ix--;)
2160 arc_info *arc_p, *arc_n;
2162 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
2163 arc_p = arc, arc = arc_n)
2165 arc_n = arc->succ_next;
2166 arc->succ_next = arc_p;
2168 fn->blocks[ix].succ = arc_p;
2170 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
2171 arc_p = arc, arc = arc_n)
2173 arc_n = arc->pred_next;
2174 arc->pred_next = arc_p;
2176 fn->blocks[ix].pred = arc_p;
2179 if (fn->blocks.size () < 2)
2180 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
2181 bbg_file_name, fn->get_name ());
2182 else
2184 if (fn->blocks[ENTRY_BLOCK].num_pred)
2185 fnotice (stderr, "%s:'%s' has arcs to entry block\n",
2186 bbg_file_name, fn->get_name ());
2187 else
2188 /* We can't deduce the entry block counts from the lack of
2189 predecessors. */
2190 fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
2192 if (fn->blocks[EXIT_BLOCK].num_succ)
2193 fnotice (stderr, "%s:'%s' has arcs from exit block\n",
2194 bbg_file_name, fn->get_name ());
2195 else
2196 /* Likewise, we can't deduce exit block counts from the lack
2197 of its successors. */
2198 fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
2201 /* Propagate the measured counts, this must be done in the same
2202 order as the code in profile.cc */
2203 for (unsigned i = 0; i < fn->blocks.size (); i++)
2205 blk = &fn->blocks[i];
2206 block_info const *prev_dst = NULL;
2207 int out_of_order = 0;
2208 int non_fake_succ = 0;
2210 for (arc = blk->succ; arc; arc = arc->succ_next)
2212 if (!arc->fake)
2213 non_fake_succ++;
2215 if (!arc->on_tree)
2217 if (count_ptr)
2218 arc->count = *count_ptr++;
2219 arc->count_valid = 1;
2220 blk->num_succ--;
2221 arc->dst->num_pred--;
2223 if (prev_dst && prev_dst > arc->dst)
2224 out_of_order = 1;
2225 prev_dst = arc->dst;
2227 if (non_fake_succ == 1)
2229 /* If there is only one non-fake exit, it is an
2230 unconditional branch. */
2231 for (arc = blk->succ; arc; arc = arc->succ_next)
2232 if (!arc->fake)
2234 arc->is_unconditional = 1;
2235 /* If this block is instrumenting a call, it might be
2236 an artificial block. It is not artificial if it has
2237 a non-fallthrough exit, or the destination of this
2238 arc has more than one entry. Mark the destination
2239 block as a return site, if none of those conditions
2240 hold. */
2241 if (blk->is_call_site && arc->fall_through
2242 && arc->dst->pred == arc && !arc->pred_next)
2243 arc->dst->is_call_return = 1;
2247 /* Sort the successor arcs into ascending dst order. profile.cc
2248 normally produces arcs in the right order, but sometimes with
2249 one or two out of order. We're not using a particularly
2250 smart sort. */
2251 if (out_of_order)
2253 arc_info *start = blk->succ;
2254 unsigned changes = 1;
2256 while (changes)
2258 arc_info *arc, *arc_p, *arc_n;
2260 changes = 0;
2261 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
2263 if (arc->dst > arc_n->dst)
2265 changes = 1;
2266 if (arc_p)
2267 arc_p->succ_next = arc_n;
2268 else
2269 start = arc_n;
2270 arc->succ_next = arc_n->succ_next;
2271 arc_n->succ_next = arc;
2272 arc_p = arc_n;
2274 else
2276 arc_p = arc;
2277 arc = arc_n;
2281 blk->succ = start;
2284 /* Place it on the invalid chain, it will be ignored if that's
2285 wrong. */
2286 blk->invalid_chain = 1;
2287 blk->chain = invalid_blocks;
2288 invalid_blocks = blk;
2291 while (invalid_blocks || valid_blocks)
2293 while ((blk = invalid_blocks))
2295 gcov_type total = 0;
2296 const arc_info *arc;
2298 invalid_blocks = blk->chain;
2299 blk->invalid_chain = 0;
2300 if (!blk->num_succ)
2301 for (arc = blk->succ; arc; arc = arc->succ_next)
2302 total += arc->count;
2303 else if (!blk->num_pred)
2304 for (arc = blk->pred; arc; arc = arc->pred_next)
2305 total += arc->count;
2306 else
2307 continue;
2309 blk->count = total;
2310 blk->count_valid = 1;
2311 blk->chain = valid_blocks;
2312 blk->valid_chain = 1;
2313 valid_blocks = blk;
2315 while ((blk = valid_blocks))
2317 gcov_type total;
2318 arc_info *arc, *inv_arc;
2320 valid_blocks = blk->chain;
2321 blk->valid_chain = 0;
2322 if (blk->num_succ == 1)
2324 block_info *dst;
2326 total = blk->count;
2327 inv_arc = NULL;
2328 for (arc = blk->succ; arc; arc = arc->succ_next)
2330 total -= arc->count;
2331 if (!arc->count_valid)
2332 inv_arc = arc;
2334 dst = inv_arc->dst;
2335 inv_arc->count_valid = 1;
2336 inv_arc->count = total;
2337 blk->num_succ--;
2338 dst->num_pred--;
2339 if (dst->count_valid)
2341 if (dst->num_pred == 1 && !dst->valid_chain)
2343 dst->chain = valid_blocks;
2344 dst->valid_chain = 1;
2345 valid_blocks = dst;
2348 else
2350 if (!dst->num_pred && !dst->invalid_chain)
2352 dst->chain = invalid_blocks;
2353 dst->invalid_chain = 1;
2354 invalid_blocks = dst;
2358 if (blk->num_pred == 1)
2360 block_info *src;
2362 total = blk->count;
2363 inv_arc = NULL;
2364 for (arc = blk->pred; arc; arc = arc->pred_next)
2366 total -= arc->count;
2367 if (!arc->count_valid)
2368 inv_arc = arc;
2370 src = inv_arc->src;
2371 inv_arc->count_valid = 1;
2372 inv_arc->count = total;
2373 blk->num_pred--;
2374 src->num_succ--;
2375 if (src->count_valid)
2377 if (src->num_succ == 1 && !src->valid_chain)
2379 src->chain = valid_blocks;
2380 src->valid_chain = 1;
2381 valid_blocks = src;
2384 else
2386 if (!src->num_succ && !src->invalid_chain)
2388 src->chain = invalid_blocks;
2389 src->invalid_chain = 1;
2390 invalid_blocks = src;
2397 /* If the graph has been correctly solved, every block will have a
2398 valid count. */
2399 for (unsigned i = 0; ix < fn->blocks.size (); i++)
2400 if (!fn->blocks[i].count_valid)
2402 fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
2403 bbg_file_name, fn->get_name ());
2404 break;
2408 /* Mark all the blocks only reachable via an incoming catch. */
2410 static void
2411 find_exception_blocks (function_info *fn)
2413 unsigned ix;
2414 block_info **queue = XALLOCAVEC (block_info *, fn->blocks.size ());
2416 /* First mark all blocks as exceptional. */
2417 for (ix = fn->blocks.size (); ix--;)
2418 fn->blocks[ix].exceptional = 1;
2420 /* Now mark all the blocks reachable via non-fake edges */
2421 queue[0] = &fn->blocks[0];
2422 queue[0]->exceptional = 0;
2423 for (ix = 1; ix;)
2425 block_info *block = queue[--ix];
2426 const arc_info *arc;
2428 for (arc = block->succ; arc; arc = arc->succ_next)
2429 if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
2431 arc->dst->exceptional = 0;
2432 queue[ix++] = arc->dst;
2438 /* Increment totals in COVERAGE according to arc ARC. */
2440 static void
2441 add_branch_counts (coverage_info *coverage, const arc_info *arc)
2443 if (arc->is_call_non_return)
2445 coverage->calls++;
2446 if (arc->src->count)
2447 coverage->calls_executed++;
2449 else if (!arc->is_unconditional)
2451 coverage->branches++;
2452 if (arc->src->count)
2453 coverage->branches_executed++;
2454 if (arc->count)
2455 coverage->branches_taken++;
2459 /* Format COUNT, if flag_human_readable_numbers is set, return it human
2460 readable format. */
2462 static char const *
2463 format_count (gcov_type count)
2465 static char buffer[64];
2466 const char *units = " kMGTPEZY";
2468 if (count < 1000 || !flag_human_readable_numbers)
2470 sprintf (buffer, "%" PRId64, count);
2471 return buffer;
2474 unsigned i;
2475 gcov_type divisor = 1;
2476 for (i = 0; units[i+1]; i++, divisor *= 1000)
2478 if (count + divisor / 2 < 1000 * divisor)
2479 break;
2481 float r = 1.0f * count / divisor;
2482 sprintf (buffer, "%.1f%c", r, units[i]);
2483 return buffer;
2486 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
2487 count. If DECIMAL_PLACES >= 0, format TOP/BOTTOM * 100 to DECIMAL_PLACES.
2488 If DECIMAL_PLACES is zero, no decimal point is printed. Only print 100% when
2489 TOP==BOTTOM and only print 0% when TOP=0. If DECIMAL_PLACES < 0, then simply
2490 format TOP. Return pointer to a static string. */
2492 static char const *
2493 format_gcov (gcov_type top, gcov_type bottom, int decimal_places)
2495 static char buffer[20];
2497 if (decimal_places >= 0)
2499 float ratio = bottom ? 100.0f * top / bottom: 0;
2501 /* Round up to 1% if there's a small non-zero value. */
2502 if (ratio > 0.0f && ratio < 0.5f && decimal_places == 0)
2503 ratio = 1.0f;
2504 sprintf (buffer, "%.*f%%", decimal_places, ratio);
2506 else
2507 return format_count (top);
2509 return buffer;
2512 /* Summary of execution */
2514 static void
2515 executed_summary (unsigned lines, unsigned executed)
2517 if (lines)
2518 fnotice (stdout, "Lines executed:%s of %d\n",
2519 format_gcov (executed, lines, 2), lines);
2520 else
2521 fnotice (stdout, "No executable lines\n");
2524 /* Output summary info for a function. */
2526 static void
2527 function_summary (const coverage_info *coverage)
2529 fnotice (stdout, "%s '%s'\n", "Function", coverage->name);
2530 executed_summary (coverage->lines, coverage->lines_executed);
2533 /* Output summary info for a file. */
2535 static void
2536 file_summary (const coverage_info *coverage)
2538 fnotice (stdout, "%s '%s'\n", "File", coverage->name);
2539 executed_summary (coverage->lines, coverage->lines_executed);
2541 if (flag_branches)
2543 if (coverage->branches)
2545 fnotice (stdout, "Branches executed:%s of %d\n",
2546 format_gcov (coverage->branches_executed,
2547 coverage->branches, 2),
2548 coverage->branches);
2549 fnotice (stdout, "Taken at least once:%s of %d\n",
2550 format_gcov (coverage->branches_taken,
2551 coverage->branches, 2),
2552 coverage->branches);
2554 else
2555 fnotice (stdout, "No branches\n");
2556 if (coverage->calls)
2557 fnotice (stdout, "Calls executed:%s of %d\n",
2558 format_gcov (coverage->calls_executed, coverage->calls, 2),
2559 coverage->calls);
2560 else
2561 fnotice (stdout, "No calls\n");
2565 /* Canonicalize the filename NAME by canonicalizing directory
2566 separators, eliding . components and resolving .. components
2567 appropriately. Always returns a unique string. */
2569 static char *
2570 canonicalize_name (const char *name)
2572 /* The canonical name cannot be longer than the incoming name. */
2573 char *result = XNEWVEC (char, strlen (name) + 1);
2574 const char *base = name, *probe;
2575 char *ptr = result;
2576 char *dd_base;
2577 int slash = 0;
2579 #if HAVE_DOS_BASED_FILE_SYSTEM
2580 if (base[0] && base[1] == ':')
2582 result[0] = base[0];
2583 result[1] = ':';
2584 base += 2;
2585 ptr += 2;
2587 #endif
2588 for (dd_base = ptr; *base; base = probe)
2590 size_t len;
2592 for (probe = base; *probe; probe++)
2593 if (IS_DIR_SEPARATOR (*probe))
2594 break;
2596 len = probe - base;
2597 if (len == 1 && base[0] == '.')
2598 /* Elide a '.' directory */
2600 else if (len == 2 && base[0] == '.' && base[1] == '.')
2602 /* '..', we can only elide it and the previous directory, if
2603 we're not a symlink. */
2604 struct stat ATTRIBUTE_UNUSED buf;
2606 *ptr = 0;
2607 if (dd_base == ptr
2608 #if defined (S_ISLNK)
2609 /* S_ISLNK is not POSIX.1-1996. */
2610 || stat (result, &buf) || S_ISLNK (buf.st_mode)
2611 #endif
2614 /* Cannot elide, or unreadable or a symlink. */
2615 dd_base = ptr + 2 + slash;
2616 goto regular;
2618 while (ptr != dd_base && *ptr != '/')
2619 ptr--;
2620 slash = ptr != result;
2622 else
2624 regular:
2625 /* Regular pathname component. */
2626 if (slash)
2627 *ptr++ = '/';
2628 memcpy (ptr, base, len);
2629 ptr += len;
2630 slash = 1;
2633 for (; IS_DIR_SEPARATOR (*probe); probe++)
2634 continue;
2636 *ptr = 0;
2638 return result;
2641 /* Generate an output file name. INPUT_NAME is the canonicalized main
2642 input file and SRC_NAME is the canonicalized file name.
2643 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
2644 long_output_names we prepend the processed name of the input file
2645 to each output name (except when the current source file is the
2646 input file, so you don't get a double concatenation). The two
2647 components are separated by '##'. With preserve_paths we create a
2648 filename from all path components of the source file, replacing '/'
2649 with '#', and .. with '^', without it we simply take the basename
2650 component. (Remember, the canonicalized name will already have
2651 elided '.' components and converted \\ separators.) */
2653 static string
2654 make_gcov_file_name (const char *input_name, const char *src_name)
2656 string str;
2658 /* When hashing filenames, we shorten them by only using the filename
2659 component and appending a hash of the full (mangled) pathname. */
2660 if (flag_hash_filenames)
2661 str = (string (mangle_name (src_name)) + "##"
2662 + get_md5sum (src_name) + ".gcov");
2663 else
2665 if (flag_long_names && input_name && strcmp (src_name, input_name) != 0)
2667 str += mangle_name (input_name);
2668 str += "##";
2671 str += mangle_name (src_name);
2672 str += ".gcov";
2675 return str;
2678 /* Mangle BASE name, copy it at the beginning of PTR buffer and
2679 return address of the \0 character of the buffer. */
2681 static char *
2682 mangle_name (char const *base)
2684 /* Generate the source filename part. */
2685 if (!flag_preserve_paths)
2686 return xstrdup (lbasename (base));
2687 else
2688 return mangle_path (base);
2691 /* Scan through the bb_data for each line in the block, increment
2692 the line number execution count indicated by the execution count of
2693 the appropriate basic block. */
2695 static void
2696 add_line_counts (coverage_info *coverage, function_info *fn)
2698 bool has_any_line = false;
2699 /* Scan each basic block. */
2700 for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
2702 line_info *line = NULL;
2703 block_info *block = &fn->blocks[ix];
2704 if (block->count && ix && ix + 1 != fn->blocks.size ())
2705 fn->blocks_executed++;
2706 for (unsigned i = 0; i < block->locations.size (); i++)
2708 unsigned src_idx = block->locations[i].source_file_idx;
2709 vector<unsigned> &lines = block->locations[i].lines;
2711 block->cycle.arc = NULL;
2712 block->cycle.ident = ~0U;
2714 for (unsigned j = 0; j < lines.size (); j++)
2716 unsigned ln = lines[j];
2718 /* Line belongs to a function that is in a group. */
2719 if (fn->group_line_p (ln, src_idx))
2721 gcc_assert (lines[j] - fn->start_line < fn->lines.size ());
2722 line = &(fn->lines[lines[j] - fn->start_line]);
2723 if (coverage)
2725 if (!line->exists)
2726 coverage->lines++;
2727 if (!line->count && block->count)
2728 coverage->lines_executed++;
2730 line->exists = 1;
2731 if (!block->exceptional)
2733 line->unexceptional = 1;
2734 if (block->count == 0)
2735 line->has_unexecuted_block = 1;
2737 line->count += block->count;
2739 else
2741 gcc_assert (ln < sources[src_idx].lines.size ());
2742 line = &(sources[src_idx].lines[ln]);
2743 if (coverage)
2745 if (!line->exists)
2746 coverage->lines++;
2747 if (!line->count && block->count)
2748 coverage->lines_executed++;
2750 line->exists = 1;
2751 if (!block->exceptional)
2753 line->unexceptional = 1;
2754 if (block->count == 0)
2755 line->has_unexecuted_block = 1;
2757 line->count += block->count;
2761 has_any_line = true;
2763 if (!ix || ix + 1 == fn->blocks.size ())
2764 /* Entry or exit block. */;
2765 else if (line != NULL)
2767 line->blocks.push_back (block);
2769 if (flag_branches)
2771 arc_info *arc;
2773 for (arc = block->succ; arc; arc = arc->succ_next)
2774 line->branches.push_back (arc);
2780 if (!has_any_line)
2781 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name,
2782 fn->get_name ());
2785 /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE
2786 is set to true, update source file summary. */
2788 static void accumulate_line_info (line_info *line, source_info *src,
2789 bool add_coverage)
2791 if (add_coverage)
2792 for (vector<arc_info *>::iterator it = line->branches.begin ();
2793 it != line->branches.end (); it++)
2794 add_branch_counts (&src->coverage, *it);
2796 if (!line->blocks.empty ())
2798 /* The user expects the line count to be the number of times
2799 a line has been executed. Simply summing the block count
2800 will give an artificially high number. The Right Thing
2801 is to sum the entry counts to the graph of blocks on this
2802 line, then find the elementary cycles of the local graph
2803 and add the transition counts of those cycles. */
2804 gcov_type count = 0;
2806 /* Cycle detection. */
2807 for (vector<block_info *>::iterator it = line->blocks.begin ();
2808 it != line->blocks.end (); it++)
2810 for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next)
2811 if (!line->has_block (arc->src))
2812 count += arc->count;
2813 for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next)
2814 arc->cs_count = arc->count;
2817 /* Now, add the count of loops entirely on this line. */
2818 count += get_cycles_count (*line);
2819 line->count = count;
2821 if (line->count > src->maximum_count)
2822 src->maximum_count = line->count;
2825 if (line->exists && add_coverage)
2827 src->coverage.lines++;
2828 if (line->count)
2829 src->coverage.lines_executed++;
2833 /* Accumulate the line counts of a file. */
2835 static void
2836 accumulate_line_counts (source_info *src)
2838 /* First work on group functions. */
2839 for (vector<function_info *>::iterator it = src->functions.begin ();
2840 it != src->functions.end (); it++)
2842 function_info *fn = *it;
2844 if (fn->src != src->index || !fn->is_group)
2845 continue;
2847 for (vector<line_info>::iterator it2 = fn->lines.begin ();
2848 it2 != fn->lines.end (); it2++)
2850 line_info *line = &(*it2);
2851 accumulate_line_info (line, src, true);
2855 /* Work on global lines that line in source file SRC. */
2856 for (vector<line_info>::iterator it = src->lines.begin ();
2857 it != src->lines.end (); it++)
2858 accumulate_line_info (&(*it), src, true);
2860 /* If not using intermediate mode, sum lines of group functions and
2861 add them to lines that live in a source file. */
2862 if (!flag_json_format)
2863 for (vector<function_info *>::iterator it = src->functions.begin ();
2864 it != src->functions.end (); it++)
2866 function_info *fn = *it;
2868 if (fn->src != src->index || !fn->is_group)
2869 continue;
2871 for (unsigned i = 0; i < fn->lines.size (); i++)
2873 line_info *fn_line = &fn->lines[i];
2874 if (fn_line->exists)
2876 unsigned ln = fn->start_line + i;
2877 line_info *src_line = &src->lines[ln];
2879 if (!src_line->exists)
2880 src->coverage.lines++;
2881 if (!src_line->count && fn_line->count)
2882 src->coverage.lines_executed++;
2884 src_line->count += fn_line->count;
2885 src_line->exists = 1;
2887 if (fn_line->has_unexecuted_block)
2888 src_line->has_unexecuted_block = 1;
2890 if (fn_line->unexceptional)
2891 src_line->unexceptional = 1;
2897 /* Output information about ARC number IX. Returns nonzero if
2898 anything is output. */
2900 static int
2901 output_branch_count (FILE *gcov_file, int ix, const arc_info *arc)
2903 if (arc->is_call_non_return)
2905 if (arc->src->count)
2907 fnotice (gcov_file, "call %2d returned %s\n", ix,
2908 format_gcov (arc->src->count - arc->count,
2909 arc->src->count, -flag_counts));
2911 else
2912 fnotice (gcov_file, "call %2d never executed\n", ix);
2914 else if (!arc->is_unconditional)
2916 if (arc->src->count)
2917 fnotice (gcov_file, "branch %2d taken %s%s", ix,
2918 format_gcov (arc->count, arc->src->count, -flag_counts),
2919 arc->fall_through ? " (fallthrough)"
2920 : arc->is_throw ? " (throw)" : "");
2921 else
2922 fnotice (gcov_file, "branch %2d never executed%s", ix,
2923 (arc->fall_through ? " (fallthrough)"
2924 : arc->is_throw ? " (throw)" : ""));
2926 if (flag_verbose)
2927 fnotice (gcov_file, " (BB %d)", arc->dst->id);
2929 fnotice (gcov_file, "\n");
2931 else if (flag_unconditional && !arc->dst->is_call_return)
2933 if (arc->src->count)
2934 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
2935 format_gcov (arc->count, arc->src->count, -flag_counts));
2936 else
2937 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
2939 else
2940 return 0;
2941 return 1;
2944 static const char *
2945 read_line (FILE *file)
2947 static char *string;
2948 static size_t string_len;
2949 size_t pos = 0;
2951 if (!string_len)
2953 string_len = 200;
2954 string = XNEWVEC (char, string_len);
2957 while (fgets (string + pos, string_len - pos, file))
2959 size_t len = strlen (string + pos);
2961 if (len && string[pos + len - 1] == '\n')
2963 string[pos + len - 1] = 0;
2964 return string;
2966 pos += len;
2967 /* If the file contains NUL characters or an incomplete
2968 last line, which can happen more than once in one run,
2969 we have to avoid doubling the STRING_LEN unnecessarily. */
2970 if (pos > string_len / 2)
2972 string_len *= 2;
2973 string = XRESIZEVEC (char, string, string_len);
2977 return pos ? string : NULL;
2980 /* Pad string S with spaces from left to have total width equal to 9. */
2982 static void
2983 pad_count_string (string &s)
2985 if (s.size () < 9)
2986 s.insert (0, 9 - s.size (), ' ');
2989 /* Print GCOV line beginning to F stream. If EXISTS is set to true, the
2990 line exists in source file. UNEXCEPTIONAL indicated that it's not in
2991 an exceptional statement. The output is printed for LINE_NUM of given
2992 COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
2993 used to indicate non-executed blocks. */
2995 static void
2996 output_line_beginning (FILE *f, bool exists, bool unexceptional,
2997 bool has_unexecuted_block,
2998 gcov_type count, unsigned line_num,
2999 const char *exceptional_string,
3000 const char *unexceptional_string,
3001 unsigned int maximum_count)
3003 string s;
3004 if (exists)
3006 if (count > 0)
3008 s = format_gcov (count, 0, -1);
3009 if (has_unexecuted_block
3010 && bbg_supports_has_unexecuted_blocks)
3012 if (flag_use_colors)
3014 pad_count_string (s);
3015 s.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
3016 COLOR_SEPARATOR COLOR_FG_WHITE));
3017 s += SGR_RESET;
3019 else
3020 s += "*";
3022 pad_count_string (s);
3024 else
3026 if (flag_use_colors)
3028 s = "0";
3029 pad_count_string (s);
3030 if (unexceptional)
3031 s.insert (0, SGR_SEQ (COLOR_BG_RED
3032 COLOR_SEPARATOR COLOR_FG_WHITE));
3033 else
3034 s.insert (0, SGR_SEQ (COLOR_BG_CYAN
3035 COLOR_SEPARATOR COLOR_FG_WHITE));
3036 s += SGR_RESET;
3038 else
3040 s = unexceptional ? unexceptional_string : exceptional_string;
3041 pad_count_string (s);
3045 else
3047 s = "-";
3048 pad_count_string (s);
3051 /* Format line number in output. */
3052 char buffer[16];
3053 sprintf (buffer, "%5u", line_num);
3054 string linestr (buffer);
3056 if (flag_use_hotness_colors && maximum_count)
3058 if (count * 2 > maximum_count) /* > 50%. */
3059 linestr.insert (0, SGR_SEQ (COLOR_BG_RED));
3060 else if (count * 5 > maximum_count) /* > 20%. */
3061 linestr.insert (0, SGR_SEQ (COLOR_BG_YELLOW));
3062 else if (count * 10 > maximum_count) /* > 10%. */
3063 linestr.insert (0, SGR_SEQ (COLOR_BG_GREEN));
3064 linestr += SGR_RESET;
3067 fprintf (f, "%s:%s", s.c_str (), linestr.c_str ());
3070 static void
3071 print_source_line (FILE *f, const vector<const char *> &source_lines,
3072 unsigned line)
3074 gcc_assert (line >= 1);
3075 gcc_assert (line <= source_lines.size ());
3077 fprintf (f, ":%s\n", source_lines[line - 1]);
3080 /* Output line details for LINE and print it to F file. LINE lives on
3081 LINE_NUM. */
3083 static void
3084 output_line_details (FILE *f, const line_info *line, unsigned line_num)
3086 if (flag_all_blocks)
3088 arc_info *arc;
3089 int jx = 0;
3090 for (vector<block_info *>::const_iterator it = line->blocks.begin ();
3091 it != line->blocks.end (); it++)
3093 if (!(*it)->is_call_return)
3095 output_line_beginning (f, line->exists,
3096 (*it)->exceptional, false,
3097 (*it)->count, line_num,
3098 "%%%%%", "$$$$$", 0);
3099 fprintf (f, "-block %d", (*it)->id);
3100 if (flag_verbose)
3101 fprintf (f, " (BB %u)", (*it)->id);
3102 fprintf (f, "\n");
3104 if (flag_branches)
3105 for (arc = (*it)->succ; arc; arc = arc->succ_next)
3106 jx += output_branch_count (f, jx, arc);
3109 else if (flag_branches)
3111 int ix;
3113 ix = 0;
3114 for (vector<arc_info *>::const_iterator it = line->branches.begin ();
3115 it != line->branches.end (); it++)
3116 ix += output_branch_count (f, ix, (*it));
3120 /* Output detail statistics about function FN to file F. */
3122 static void
3123 output_function_details (FILE *f, function_info *fn)
3125 if (!flag_branches)
3126 return;
3128 arc_info *arc = fn->blocks[EXIT_BLOCK].pred;
3129 gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
3130 gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
3132 for (; arc; arc = arc->pred_next)
3133 if (arc->fake)
3134 return_count -= arc->count;
3136 fprintf (f, "function %s", fn->get_name ());
3137 fprintf (f, " called %s",
3138 format_gcov (called_count, 0, -1));
3139 fprintf (f, " returned %s",
3140 format_gcov (return_count, called_count, 0));
3141 fprintf (f, " blocks executed %s",
3142 format_gcov (fn->blocks_executed, fn->get_block_count (), 0));
3143 fprintf (f, "\n");
3146 /* Read in the source file one line at a time, and output that line to
3147 the gcov file preceded by its execution count and other
3148 information. */
3150 static void
3151 output_lines (FILE *gcov_file, const source_info *src)
3153 #define DEFAULT_LINE_START " -: 0:"
3154 #define FN_SEPARATOR "------------------\n"
3156 FILE *source_file;
3157 const char *retval;
3159 /* Print colorization legend. */
3160 if (flag_use_colors)
3161 fprintf (gcov_file, "%s",
3162 DEFAULT_LINE_START "Colorization: profile count: " \
3163 SGR_SEQ (COLOR_BG_CYAN) "zero coverage (exceptional)" SGR_RESET \
3164 " " \
3165 SGR_SEQ (COLOR_BG_RED) "zero coverage (unexceptional)" SGR_RESET \
3166 " " \
3167 SGR_SEQ (COLOR_BG_MAGENTA) "unexecuted block" SGR_RESET "\n");
3169 if (flag_use_hotness_colors)
3170 fprintf (gcov_file, "%s",
3171 DEFAULT_LINE_START "Colorization: line numbers: hotness: " \
3172 SGR_SEQ (COLOR_BG_RED) "> 50%" SGR_RESET " " \
3173 SGR_SEQ (COLOR_BG_YELLOW) "> 20%" SGR_RESET " " \
3174 SGR_SEQ (COLOR_BG_GREEN) "> 10%" SGR_RESET "\n");
3176 fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
3177 if (!multiple_files)
3179 fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
3180 fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
3181 no_data_file ? "-" : da_file_name);
3182 fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
3185 source_file = fopen (src->name, "r");
3186 if (!source_file)
3187 fnotice (stderr, "Cannot open source file %s\n", src->name);
3188 else if (src->file_time == 0)
3189 fprintf (gcov_file, DEFAULT_LINE_START "Source is newer than graph\n");
3191 vector<const char *> source_lines;
3192 if (source_file)
3193 while ((retval = read_line (source_file)) != NULL)
3194 source_lines.push_back (xstrdup (retval));
3196 unsigned line_start_group = 0;
3197 vector<function_info *> *fns;
3199 for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
3201 if (line_num >= src->lines.size ())
3203 fprintf (gcov_file, "%9s:%5u", "-", line_num);
3204 print_source_line (gcov_file, source_lines, line_num);
3205 continue;
3208 const line_info *line = &src->lines[line_num];
3210 if (line_start_group == 0)
3212 fns = src->get_functions_at_location (line_num);
3213 if (fns != NULL && fns->size () > 1)
3215 /* It's possible to have functions that partially overlap,
3216 thus take the maximum end_line of functions starting
3217 at LINE_NUM. */
3218 for (unsigned i = 0; i < fns->size (); i++)
3219 if ((*fns)[i]->end_line > line_start_group)
3220 line_start_group = (*fns)[i]->end_line;
3222 else if (fns != NULL && fns->size () == 1)
3224 function_info *fn = (*fns)[0];
3225 output_function_details (gcov_file, fn);
3229 /* For lines which don't exist in the .bb file, print '-' before
3230 the source line. For lines which exist but were never
3231 executed, print '#####' or '=====' before the source line.
3232 Otherwise, print the execution count before the source line.
3233 There are 16 spaces of indentation added before the source
3234 line so that tabs won't be messed up. */
3235 output_line_beginning (gcov_file, line->exists, line->unexceptional,
3236 line->has_unexecuted_block, line->count,
3237 line_num, "=====", "#####", src->maximum_count);
3239 print_source_line (gcov_file, source_lines, line_num);
3240 output_line_details (gcov_file, line, line_num);
3242 if (line_start_group == line_num)
3244 for (vector<function_info *>::iterator it = fns->begin ();
3245 it != fns->end (); it++)
3247 function_info *fn = *it;
3248 vector<line_info> &lines = fn->lines;
3250 fprintf (gcov_file, FN_SEPARATOR);
3252 string fn_name = fn->get_name ();
3253 if (flag_use_colors)
3255 fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN));
3256 fn_name += SGR_RESET;
3259 fprintf (gcov_file, "%s:\n", fn_name.c_str ());
3261 output_function_details (gcov_file, fn);
3263 /* Print all lines covered by the function. */
3264 for (unsigned i = 0; i < lines.size (); i++)
3266 line_info *line = &lines[i];
3267 unsigned l = fn->start_line + i;
3269 /* For lines which don't exist in the .bb file, print '-'
3270 before the source line. For lines which exist but
3271 were never executed, print '#####' or '=====' before
3272 the source line. Otherwise, print the execution count
3273 before the source line.
3274 There are 16 spaces of indentation added before the source
3275 line so that tabs won't be messed up. */
3276 output_line_beginning (gcov_file, line->exists,
3277 line->unexceptional,
3278 line->has_unexecuted_block,
3279 line->count,
3280 l, "=====", "#####",
3281 src->maximum_count);
3283 print_source_line (gcov_file, source_lines, l);
3284 output_line_details (gcov_file, line, l);
3288 fprintf (gcov_file, FN_SEPARATOR);
3289 line_start_group = 0;
3293 if (source_file)
3294 fclose (source_file);