Skip several gcc.dg/builtin-dynamic-object-size tests on hppa*-*-hpux*
[official-gcc.git] / gcc / gcov.cc
blobfad704eb7c94dd4dd0cd5f7f2bc6c4c9e8e1cf71
1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file.
3 Copyright (C) 1990-2024 Free Software Foundation, Inc.
4 Contributed by James E. Wilson of Cygnus Support.
5 Mangled by Bob Manson of Cygnus Support.
6 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
8 Gcov is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
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 2024 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_integer ("line_number", line_num);
1113 if (function_name != NULL)
1114 lineo->set_string ("function_name", function_name);
1115 lineo->set_integer ("count", line->count);
1116 lineo->set_bool ("unexecuted_block", line->has_unexecuted_block);
1118 json::array *bb_ids = new json::array ();
1119 for (const block_info *block : line->blocks)
1120 bb_ids->append (new json::integer_number (block->id));
1121 lineo->set ("block_ids", bb_ids);
1123 json::array *branches = new json::array ();
1124 lineo->set ("branches", branches);
1126 json::array *calls = new json::array ();
1127 lineo->set ("calls", calls);
1129 vector<arc_info *>::const_iterator it;
1130 if (flag_branches)
1131 for (it = line->branches.begin (); it != line->branches.end ();
1132 it++)
1134 if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
1136 json::object *branch = new json::object ();
1137 branch->set_integer ("count", (*it)->count);
1138 branch->set_bool ("throw", (*it)->is_throw);
1139 branch->set_bool ("fallthrough", (*it)->fall_through);
1140 branch->set_integer ("source_block_id", (*it)->src->id);
1141 branch->set_integer ("destination_block_id", (*it)->dst->id);
1142 branches->append (branch);
1144 else if ((*it)->is_call_non_return)
1146 json::object *call = new json::object ();
1147 gcov_type returns = (*it)->src->count - (*it)->count;
1148 call->set_integer ("source_block_id", (*it)->src->id);
1149 call->set_integer ("destination_block_id", (*it)->dst->id);
1150 call->set_integer ("returned", returns);
1151 calls->append (call);
1155 object->append (lineo);
1158 /* Strip filename extension in STR. */
1160 static string
1161 strip_extention (string str)
1163 string::size_type pos = str.rfind ('.');
1164 if (pos != string::npos)
1165 str = str.substr (0, pos);
1167 return str;
1170 /* Calcualte md5sum for INPUT string and return it in hex string format. */
1172 static string
1173 get_md5sum (const char *input)
1175 md5_ctx ctx;
1176 char md5sum[16];
1177 string str;
1179 md5_init_ctx (&ctx);
1180 md5_process_bytes (input, strlen (input), &ctx);
1181 md5_finish_ctx (&ctx, md5sum);
1183 for (unsigned i = 0; i < 16; i++)
1185 char b[3];
1186 sprintf (b, "%02x", (unsigned char)md5sum[i]);
1187 str += b;
1190 return str;
1193 /* Get the name of the gcov file. The return value must be free'd.
1195 It appends the '.gcov' extension to the *basename* of the file.
1196 The resulting file name will be in PWD.
1198 e.g.,
1199 input: foo.da, output: foo.da.gcov
1200 input: a/b/foo.cc, output: foo.cc.gcov */
1202 static string
1203 get_gcov_intermediate_filename (const char *input_file_name)
1205 string base = basename (input_file_name);
1206 string str = strip_extention (base);
1208 if (flag_hash_filenames)
1210 str += "##";
1211 str += get_md5sum (input_file_name);
1213 else if (flag_preserve_paths && base != input_file_name)
1215 str += "##";
1216 str += mangle_path (input_file_name);
1217 str = strip_extention (str);
1220 str += ".gcov.json.gz";
1221 return str.c_str ();
1224 /* Output the result in JSON intermediate format.
1225 Source info SRC is dumped into JSON_FILES which is JSON array. */
1227 static void
1228 output_json_intermediate_file (json::array *json_files, source_info *src)
1230 json::object *root = new json::object ();
1231 json_files->append (root);
1233 root->set_string ("file", src->name);
1235 json::array *functions = new json::array ();
1236 root->set ("functions", functions);
1238 std::sort (src->functions.begin (), src->functions.end (),
1239 function_line_start_cmp ());
1240 for (vector<function_info *>::iterator it = src->functions.begin ();
1241 it != src->functions.end (); it++)
1243 json::object *function = new json::object ();
1244 function->set_string ("name", (*it)->m_name);
1245 function->set_string ("demangled_name", (*it)->get_demangled_name ());
1246 function->set_integer ("start_line", (*it)->start_line);
1247 function->set_integer ("start_column", (*it)->start_column);
1248 function->set_integer ("end_line", (*it)->end_line);
1249 function->set_integer ("end_column", (*it)->end_column);
1250 function->set_integer ("blocks", (*it)->get_block_count ());
1251 function->set_integer ("blocks_executed", (*it)->blocks_executed);
1252 function->set_integer ("execution_count", (*it)->blocks[0].count);
1254 functions->append (function);
1257 json::array *lineso = new json::array ();
1258 root->set ("lines", lineso);
1260 vector<function_info *> last_non_group_fns;
1262 for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
1264 vector<function_info *> *fns = src->get_functions_at_location (line_num);
1266 if (fns != NULL)
1267 /* Print info for all group functions that begin on the line. */
1268 for (vector<function_info *>::iterator it2 = fns->begin ();
1269 it2 != fns->end (); it2++)
1271 if (!(*it2)->is_group)
1272 last_non_group_fns.push_back (*it2);
1274 vector<line_info> &lines = (*it2)->lines;
1275 /* The LINES array is allocated only for group functions. */
1276 for (unsigned i = 0; i < lines.size (); i++)
1278 line_info *line = &lines[i];
1279 output_intermediate_json_line (lineso, line, line_num + i,
1280 (*it2)->m_name);
1284 /* Follow with lines associated with the source file. */
1285 if (line_num < src->lines.size ())
1287 unsigned size = last_non_group_fns.size ();
1288 function_info *last_fn = size > 0 ? last_non_group_fns[size - 1] : NULL;
1289 const char *fname = last_fn ? last_fn->m_name : NULL;
1290 output_intermediate_json_line (lineso, &src->lines[line_num], line_num,
1291 fname);
1293 /* Pop ending function from stack. */
1294 if (last_fn != NULL && last_fn->end_line == line_num)
1295 last_non_group_fns.pop_back ();
1300 /* Function start pair. */
1301 struct function_start
1303 unsigned source_file_idx;
1304 unsigned start_line;
1307 /* Traits class for function start hash maps below. */
1309 struct function_start_pair_hash : typed_noop_remove <function_start>
1311 typedef function_start value_type;
1312 typedef function_start compare_type;
1314 static hashval_t
1315 hash (const function_start &ref)
1317 inchash::hash hstate (0);
1318 hstate.add_int (ref.source_file_idx);
1319 hstate.add_int (ref.start_line);
1320 return hstate.end ();
1323 static bool
1324 equal (const function_start &ref1, const function_start &ref2)
1326 return (ref1.source_file_idx == ref2.source_file_idx
1327 && ref1.start_line == ref2.start_line);
1330 static void
1331 mark_deleted (function_start &ref)
1333 ref.start_line = ~1U;
1336 static const bool empty_zero_p = false;
1338 static void
1339 mark_empty (function_start &ref)
1341 ref.start_line = ~2U;
1344 static bool
1345 is_deleted (const function_start &ref)
1347 return ref.start_line == ~1U;
1350 static bool
1351 is_empty (const function_start &ref)
1353 return ref.start_line == ~2U;
1357 /* Process a single input file. */
1359 static void
1360 process_file (const char *file_name)
1362 create_file_names (file_name);
1364 for (unsigned i = 0; i < processed_files.size (); i++)
1365 if (strcmp (da_file_name, processed_files[i]) == 0)
1367 fnotice (stderr, "'%s' file is already processed\n",
1368 file_name);
1369 return;
1372 processed_files.push_back (xstrdup (da_file_name));
1374 read_graph_file ();
1375 read_count_file ();
1378 /* Process all functions in all files. */
1380 static void
1381 process_all_functions (void)
1383 hash_map<function_start_pair_hash, function_info *> fn_map;
1385 /* Identify group functions. */
1386 for (vector<function_info *>::iterator it = functions.begin ();
1387 it != functions.end (); it++)
1388 if (!(*it)->artificial)
1390 function_start needle;
1391 needle.source_file_idx = (*it)->src;
1392 needle.start_line = (*it)->start_line;
1394 function_info **slot = fn_map.get (needle);
1395 if (slot)
1397 (*slot)->is_group = 1;
1398 (*it)->is_group = 1;
1400 else
1401 fn_map.put (needle, *it);
1404 /* Remove all artificial function. */
1405 functions.erase (remove_if (functions.begin (), functions.end (),
1406 function_info::is_artificial), functions.end ());
1408 for (vector<function_info *>::iterator it = functions.begin ();
1409 it != functions.end (); it++)
1411 function_info *fn = *it;
1412 unsigned src = fn->src;
1414 if (!fn->counts.empty () || no_data_file)
1416 source_info *s = &sources[src];
1417 s->add_function (fn);
1419 /* Mark last line in files touched by function. */
1420 for (unsigned block_no = 0; block_no != fn->blocks.size ();
1421 block_no++)
1423 block_info *block = &fn->blocks[block_no];
1424 for (unsigned i = 0; i < block->locations.size (); i++)
1426 /* Sort lines of locations. */
1427 sort (block->locations[i].lines.begin (),
1428 block->locations[i].lines.end ());
1430 if (!block->locations[i].lines.empty ())
1432 s = &sources[block->locations[i].source_file_idx];
1433 unsigned last_line
1434 = block->locations[i].lines.back ();
1436 /* Record new lines for the function. */
1437 if (last_line >= s->lines.size ())
1439 s = &sources[block->locations[i].source_file_idx];
1440 unsigned last_line
1441 = block->locations[i].lines.back ();
1443 /* Record new lines for the function. */
1444 if (last_line >= s->lines.size ())
1446 /* Record new lines for a source file. */
1447 s->lines.resize (last_line + 1);
1454 /* Allocate lines for group function, following start_line
1455 and end_line information of the function. */
1456 if (fn->is_group)
1457 fn->lines.resize (fn->end_line - fn->start_line + 1);
1459 solve_flow_graph (fn);
1460 if (fn->has_catch)
1461 find_exception_blocks (fn);
1463 else
1465 /* The function was not in the executable -- some other
1466 instance must have been selected. */
1471 static void
1472 output_gcov_file (const char *file_name, source_info *src)
1474 string gcov_file_name_str
1475 = make_gcov_file_name (file_name, src->coverage.name);
1476 const char *gcov_file_name = gcov_file_name_str.c_str ();
1478 if (src->coverage.lines)
1480 FILE *gcov_file = fopen (gcov_file_name, "w");
1481 if (gcov_file)
1483 fnotice (stdout, "Creating '%s'\n", gcov_file_name);
1484 output_lines (gcov_file, src);
1485 if (ferror (gcov_file))
1487 fnotice (stderr, "Error writing output file '%s'\n",
1488 gcov_file_name);
1489 return_code = 6;
1491 fclose (gcov_file);
1493 else
1495 fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
1496 return_code = 6;
1499 else
1501 unlink (gcov_file_name);
1502 fnotice (stdout, "Removing '%s'\n", gcov_file_name);
1506 static void
1507 generate_results (const char *file_name)
1509 string gcov_intermediate_filename;
1511 for (vector<function_info *>::iterator it = functions.begin ();
1512 it != functions.end (); it++)
1514 function_info *fn = *it;
1515 coverage_info coverage;
1517 memset (&coverage, 0, sizeof (coverage));
1518 coverage.name = fn->get_name ();
1519 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
1520 if (flag_function_summary)
1522 function_summary (&coverage);
1523 fnotice (stdout, "\n");
1527 name_map needle;
1528 needle.name = file_name;
1529 vector<name_map>::iterator it
1530 = std::find (names.begin (), names.end (), needle);
1531 if (it != names.end ())
1532 file_name = sources[it->src].coverage.name;
1533 else
1534 file_name = canonicalize_name (file_name);
1536 gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
1538 json::object *root = new json::object ();
1539 root->set_string ("format_version", GCOV_JSON_FORMAT_VERSION);
1540 root->set_string ("gcc_version", version_string);
1542 if (bbg_cwd != NULL)
1543 root->set_string ("current_working_directory", bbg_cwd);
1544 root->set_string ("data_file", file_name);
1546 json::array *json_files = new json::array ();
1547 root->set ("files", json_files);
1549 for (vector<source_info>::iterator it = sources.begin ();
1550 it != sources.end (); it++)
1552 source_info *src = &(*it);
1553 if (flag_relative_only)
1555 /* Ignore this source, if it is an absolute path (after
1556 source prefix removal). */
1557 char first = src->coverage.name[0];
1559 #if HAVE_DOS_BASED_FILE_SYSTEM
1560 if (first && src->coverage.name[1] == ':')
1561 first = src->coverage.name[2];
1562 #endif
1563 if (IS_DIR_SEPARATOR (first))
1564 continue;
1567 accumulate_line_counts (src);
1568 if (flag_debug)
1569 src->debug ();
1571 if (!flag_use_stdout)
1572 file_summary (&src->coverage);
1573 total_lines += src->coverage.lines;
1574 total_executed += src->coverage.lines_executed;
1575 if (flag_gcov_file)
1577 if (flag_json_format)
1579 output_json_intermediate_file (json_files, src);
1580 if (!flag_use_stdout)
1581 fnotice (stdout, "\n");
1583 else
1585 if (flag_use_stdout)
1587 if (src->coverage.lines)
1588 output_lines (stdout, src);
1590 else
1592 output_gcov_file (file_name, src);
1593 fnotice (stdout, "\n");
1599 if (flag_gcov_file && flag_json_format)
1601 if (flag_use_stdout)
1603 root->dump (stdout, false);
1604 printf ("\n");
1606 else
1608 pretty_printer pp;
1609 root->print (&pp, false);
1610 pp_formatted_text (&pp);
1612 fnotice (stdout, "Creating '%s'\n",
1613 gcov_intermediate_filename.c_str ());
1614 gzFile output = gzopen (gcov_intermediate_filename.c_str (), "w");
1615 if (output == NULL)
1617 fnotice (stderr, "Cannot open JSON output file %s\n",
1618 gcov_intermediate_filename.c_str ());
1619 return_code = 6;
1620 return;
1623 if (gzputs (output, pp_formatted_text (&pp)) == EOF
1624 || gzclose (output))
1626 fnotice (stderr, "Error writing JSON output file %s\n",
1627 gcov_intermediate_filename.c_str ());
1628 return_code = 6;
1629 return;
1635 /* Release all memory used. */
1637 static void
1638 release_structures (void)
1640 for (vector<function_info *>::iterator it = functions.begin ();
1641 it != functions.end (); it++)
1642 delete (*it);
1644 sources.resize (0);
1645 names.resize (0);
1646 functions.resize (0);
1647 ident_to_fn.clear ();
1650 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
1651 is not specified, these are named from FILE_NAME sans extension. If
1652 OBJECT_DIRECTORY is specified and is a directory, the files are in that
1653 directory, but named from the basename of the FILE_NAME, sans extension.
1654 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
1655 and the data files are named from that. */
1657 static void
1658 create_file_names (const char *file_name)
1660 char *cptr;
1661 char *name;
1662 int length = strlen (file_name);
1663 int base;
1665 /* Free previous file names. */
1666 free (bbg_file_name);
1667 free (da_file_name);
1668 da_file_name = bbg_file_name = NULL;
1669 bbg_file_time = 0;
1670 bbg_stamp = 0;
1672 if (object_directory && object_directory[0])
1674 struct stat status;
1676 length += strlen (object_directory) + 2;
1677 name = XNEWVEC (char, length);
1678 name[0] = 0;
1680 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
1681 strcat (name, object_directory);
1682 if (base && (!IS_DIR_SEPARATOR (name[strlen (name) - 1])))
1683 strcat (name, "/");
1685 else
1687 name = XNEWVEC (char, length + 1);
1688 strcpy (name, file_name);
1689 base = 0;
1692 if (base)
1694 /* Append source file name. */
1695 const char *cptr = lbasename (file_name);
1696 strcat (name, cptr ? cptr : file_name);
1699 /* Remove the extension. */
1700 cptr = strrchr (CONST_CAST (char *, lbasename (name)), '.');
1701 if (cptr)
1702 *cptr = 0;
1704 length = strlen (name);
1706 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
1707 strcpy (bbg_file_name, name);
1708 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
1710 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
1711 strcpy (da_file_name, name);
1712 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
1714 free (name);
1715 return;
1718 /* Find or create a source file structure for FILE_NAME. Copies
1719 FILE_NAME on creation */
1721 static unsigned
1722 find_source (const char *file_name)
1724 char *canon;
1725 unsigned idx;
1726 struct stat status;
1728 if (!file_name)
1729 file_name = "<unknown>";
1731 name_map needle;
1732 needle.name = file_name;
1734 vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1735 needle);
1736 if (it != names.end ())
1738 idx = it->src;
1739 goto check_date;
1742 /* Not found, try the canonical name. */
1743 canon = canonicalize_name (file_name);
1744 needle.name = canon;
1745 it = std::find (names.begin (), names.end (), needle);
1746 if (it == names.end ())
1748 /* Not found with canonical name, create a new source. */
1749 source_info *src;
1751 idx = sources.size ();
1752 needle = name_map (canon, idx);
1753 names.push_back (needle);
1755 sources.push_back (source_info ());
1756 src = &sources.back ();
1757 src->name = canon;
1758 src->coverage.name = src->name;
1759 src->index = idx;
1760 if (source_length
1761 #if HAVE_DOS_BASED_FILE_SYSTEM
1762 /* You lose if separators don't match exactly in the
1763 prefix. */
1764 && !strncasecmp (source_prefix, src->coverage.name, source_length)
1765 #else
1766 && !strncmp (source_prefix, src->coverage.name, source_length)
1767 #endif
1768 && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
1769 src->coverage.name += source_length + 1;
1770 if (!stat (src->name, &status))
1771 src->file_time = status.st_mtime;
1773 else
1774 idx = it->src;
1776 needle.name = file_name;
1777 if (std::find (names.begin (), names.end (), needle) == names.end ())
1779 /* Append the non-canonical name. */
1780 names.push_back (name_map (xstrdup (file_name), idx));
1783 /* Resort the name map. */
1784 std::sort (names.begin (), names.end ());
1786 check_date:
1787 if (sources[idx].file_time > bbg_file_time)
1789 static int info_emitted;
1791 fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
1792 file_name, bbg_file_name);
1793 if (!info_emitted)
1795 fnotice (stderr,
1796 "(the message is displayed only once per source file)\n");
1797 info_emitted = 1;
1799 sources[idx].file_time = 0;
1802 return idx;
1805 /* Read the notes file. Save functions to FUNCTIONS global vector. */
1807 static void
1808 read_graph_file (void)
1810 unsigned version;
1811 unsigned current_tag = 0;
1812 unsigned tag;
1814 if (!gcov_open (bbg_file_name, 1))
1816 fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1817 return_code = 1;
1818 return;
1820 bbg_file_time = gcov_time ();
1821 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1823 fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
1824 return_code = 2;
1825 gcov_close ();
1826 return;
1829 version = gcov_read_unsigned ();
1830 if (version != GCOV_VERSION)
1832 char v[4], e[4];
1834 GCOV_UNSIGNED2STRING (v, version);
1835 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1837 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1838 bbg_file_name, v, e);
1839 return_code = 3;
1841 bbg_stamp = gcov_read_unsigned ();
1842 /* Read checksum. */
1843 gcov_read_unsigned ();
1844 bbg_cwd = xstrdup (gcov_read_string ());
1845 bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
1847 function_info *fn = NULL;
1848 while ((tag = gcov_read_unsigned ()))
1850 unsigned length = gcov_read_unsigned ();
1851 gcov_position_t base = gcov_position ();
1853 if (tag == GCOV_TAG_FUNCTION)
1855 char *function_name;
1856 unsigned ident;
1857 unsigned lineno_checksum, cfg_checksum;
1859 ident = gcov_read_unsigned ();
1860 lineno_checksum = gcov_read_unsigned ();
1861 cfg_checksum = gcov_read_unsigned ();
1862 function_name = xstrdup (gcov_read_string ());
1863 unsigned artificial = gcov_read_unsigned ();
1864 unsigned src_idx = find_source (gcov_read_string ());
1865 unsigned start_line = gcov_read_unsigned ();
1866 unsigned start_column = gcov_read_unsigned ();
1867 unsigned end_line = gcov_read_unsigned ();
1868 unsigned end_column = gcov_read_unsigned ();
1870 fn = new function_info ();
1871 functions.push_back (fn);
1872 ident_to_fn[ident] = fn;
1874 fn->m_name = function_name;
1875 fn->ident = ident;
1876 fn->lineno_checksum = lineno_checksum;
1877 fn->cfg_checksum = cfg_checksum;
1878 fn->src = src_idx;
1879 fn->start_line = start_line;
1880 fn->start_column = start_column;
1881 fn->end_line = end_line;
1882 fn->end_column = end_column;
1883 fn->artificial = artificial;
1885 current_tag = tag;
1887 else if (fn && tag == GCOV_TAG_BLOCKS)
1889 if (!fn->blocks.empty ())
1890 fnotice (stderr, "%s:already seen blocks for '%s'\n",
1891 bbg_file_name, fn->get_name ());
1892 else
1893 fn->blocks.resize (gcov_read_unsigned ());
1895 else if (fn && tag == GCOV_TAG_ARCS)
1897 unsigned src = gcov_read_unsigned ();
1898 fn->blocks[src].id = src;
1899 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1900 block_info *src_blk = &fn->blocks[src];
1901 unsigned mark_catches = 0;
1902 struct arc_info *arc;
1904 if (src >= fn->blocks.size () || fn->blocks[src].succ)
1905 goto corrupt;
1907 while (num_dests--)
1909 unsigned dest = gcov_read_unsigned ();
1910 unsigned flags = gcov_read_unsigned ();
1912 if (dest >= fn->blocks.size ())
1913 goto corrupt;
1914 arc = XCNEW (arc_info);
1916 arc->dst = &fn->blocks[dest];
1917 /* Set id in order to find EXIT_BLOCK. */
1918 arc->dst->id = dest;
1919 arc->src = src_blk;
1921 arc->count = 0;
1922 arc->count_valid = 0;
1923 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
1924 arc->fake = !!(flags & GCOV_ARC_FAKE);
1925 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
1927 arc->succ_next = src_blk->succ;
1928 src_blk->succ = arc;
1929 src_blk->num_succ++;
1931 arc->pred_next = fn->blocks[dest].pred;
1932 fn->blocks[dest].pred = arc;
1933 fn->blocks[dest].num_pred++;
1935 if (arc->fake)
1937 if (src)
1939 /* Exceptional exit from this function, the
1940 source block must be a call. */
1941 fn->blocks[src].is_call_site = 1;
1942 arc->is_call_non_return = 1;
1943 mark_catches = 1;
1945 else
1947 /* Non-local return from a callee of this
1948 function. The destination block is a setjmp. */
1949 arc->is_nonlocal_return = 1;
1950 fn->blocks[dest].is_nonlocal_return = 1;
1954 if (!arc->on_tree)
1955 fn->counts.push_back (0);
1958 if (mark_catches)
1960 /* We have a fake exit from this block. The other
1961 non-fall through exits must be to catch handlers.
1962 Mark them as catch arcs. */
1964 for (arc = src_blk->succ; arc; arc = arc->succ_next)
1965 if (!arc->fake && !arc->fall_through)
1967 arc->is_throw = 1;
1968 fn->has_catch = 1;
1972 else if (fn && tag == GCOV_TAG_LINES)
1974 unsigned blockno = gcov_read_unsigned ();
1975 block_info *block = &fn->blocks[blockno];
1977 if (blockno >= fn->blocks.size ())
1978 goto corrupt;
1980 while (true)
1982 unsigned lineno = gcov_read_unsigned ();
1984 if (lineno)
1985 block->locations.back ().lines.push_back (lineno);
1986 else
1988 const char *file_name = gcov_read_string ();
1990 if (!file_name)
1991 break;
1992 block->locations.push_back (block_location_info
1993 (find_source (file_name)));
1997 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
1999 fn = NULL;
2000 current_tag = 0;
2002 gcov_sync (base, length);
2003 if (gcov_is_error ())
2005 corrupt:;
2006 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
2007 return_code = 4;
2008 break;
2011 gcov_close ();
2013 if (functions.empty ())
2014 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
2017 /* Reads profiles from the count file and attach to each
2018 function. Return nonzero if fatal error. */
2020 static int
2021 read_count_file (void)
2023 unsigned ix;
2024 unsigned version;
2025 unsigned tag;
2026 function_info *fn = NULL;
2027 int error = 0;
2028 map<unsigned, function_info *>::iterator it;
2030 if (!gcov_open (da_file_name, 1))
2032 fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
2033 da_file_name);
2034 no_data_file = 1;
2035 return 0;
2037 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
2039 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
2040 return_code = 2;
2041 cleanup:;
2042 gcov_close ();
2043 return 1;
2045 version = gcov_read_unsigned ();
2046 if (version != GCOV_VERSION)
2048 char v[4], e[4];
2050 GCOV_UNSIGNED2STRING (v, version);
2051 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
2053 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
2054 da_file_name, v, e);
2055 return_code = 3;
2057 tag = gcov_read_unsigned ();
2058 if (tag != bbg_stamp)
2060 fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
2061 return_code = 5;
2062 goto cleanup;
2065 /* Read checksum. */
2066 gcov_read_unsigned ();
2068 while ((tag = gcov_read_unsigned ()))
2070 unsigned length = gcov_read_unsigned ();
2071 int read_length = (int)length;
2072 unsigned long base = gcov_position ();
2074 if (tag == GCOV_TAG_OBJECT_SUMMARY)
2076 struct gcov_summary summary;
2077 gcov_read_summary (&summary);
2078 object_runs = summary.runs;
2080 else if (tag == GCOV_TAG_FUNCTION && !length)
2081 ; /* placeholder */
2082 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
2084 unsigned ident;
2085 ident = gcov_read_unsigned ();
2086 fn = NULL;
2087 it = ident_to_fn.find (ident);
2088 if (it != ident_to_fn.end ())
2089 fn = it->second;
2091 if (!fn)
2093 else if (gcov_read_unsigned () != fn->lineno_checksum
2094 || gcov_read_unsigned () != fn->cfg_checksum)
2096 mismatch:;
2097 fnotice (stderr, "%s:profile mismatch for '%s'\n",
2098 da_file_name, fn->get_name ());
2099 goto cleanup;
2102 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
2104 length = abs (read_length);
2105 if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
2106 goto mismatch;
2108 if (read_length > 0)
2109 for (ix = 0; ix != fn->counts.size (); ix++)
2110 fn->counts[ix] += gcov_read_counter ();
2112 if (read_length < 0)
2113 read_length = 0;
2114 gcov_sync (base, read_length);
2115 if ((error = gcov_is_error ()))
2117 fnotice (stderr,
2118 error < 0
2119 ? N_("%s:overflowed\n")
2120 : N_("%s:corrupted\n"),
2121 da_file_name);
2122 return_code = 4;
2123 goto cleanup;
2127 gcov_close ();
2128 return 0;
2131 /* Solve the flow graph. Propagate counts from the instrumented arcs
2132 to the blocks and the uninstrumented arcs. */
2134 static void
2135 solve_flow_graph (function_info *fn)
2137 unsigned ix;
2138 arc_info *arc;
2139 gcov_type *count_ptr = &fn->counts.front ();
2140 block_info *blk;
2141 block_info *valid_blocks = NULL; /* valid, but unpropagated blocks. */
2142 block_info *invalid_blocks = NULL; /* invalid, but inferable blocks. */
2144 /* The arcs were built in reverse order. Fix that now. */
2145 for (ix = fn->blocks.size (); ix--;)
2147 arc_info *arc_p, *arc_n;
2149 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
2150 arc_p = arc, arc = arc_n)
2152 arc_n = arc->succ_next;
2153 arc->succ_next = arc_p;
2155 fn->blocks[ix].succ = arc_p;
2157 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
2158 arc_p = arc, arc = arc_n)
2160 arc_n = arc->pred_next;
2161 arc->pred_next = arc_p;
2163 fn->blocks[ix].pred = arc_p;
2166 if (fn->blocks.size () < 2)
2167 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
2168 bbg_file_name, fn->get_name ());
2169 else
2171 if (fn->blocks[ENTRY_BLOCK].num_pred)
2172 fnotice (stderr, "%s:'%s' has arcs to entry block\n",
2173 bbg_file_name, fn->get_name ());
2174 else
2175 /* We can't deduce the entry block counts from the lack of
2176 predecessors. */
2177 fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
2179 if (fn->blocks[EXIT_BLOCK].num_succ)
2180 fnotice (stderr, "%s:'%s' has arcs from exit block\n",
2181 bbg_file_name, fn->get_name ());
2182 else
2183 /* Likewise, we can't deduce exit block counts from the lack
2184 of its successors. */
2185 fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
2188 /* Propagate the measured counts, this must be done in the same
2189 order as the code in profile.cc */
2190 for (unsigned i = 0; i < fn->blocks.size (); i++)
2192 blk = &fn->blocks[i];
2193 block_info const *prev_dst = NULL;
2194 int out_of_order = 0;
2195 int non_fake_succ = 0;
2197 for (arc = blk->succ; arc; arc = arc->succ_next)
2199 if (!arc->fake)
2200 non_fake_succ++;
2202 if (!arc->on_tree)
2204 if (count_ptr)
2205 arc->count = *count_ptr++;
2206 arc->count_valid = 1;
2207 blk->num_succ--;
2208 arc->dst->num_pred--;
2210 if (prev_dst && prev_dst > arc->dst)
2211 out_of_order = 1;
2212 prev_dst = arc->dst;
2214 if (non_fake_succ == 1)
2216 /* If there is only one non-fake exit, it is an
2217 unconditional branch. */
2218 for (arc = blk->succ; arc; arc = arc->succ_next)
2219 if (!arc->fake)
2221 arc->is_unconditional = 1;
2222 /* If this block is instrumenting a call, it might be
2223 an artificial block. It is not artificial if it has
2224 a non-fallthrough exit, or the destination of this
2225 arc has more than one entry. Mark the destination
2226 block as a return site, if none of those conditions
2227 hold. */
2228 if (blk->is_call_site && arc->fall_through
2229 && arc->dst->pred == arc && !arc->pred_next)
2230 arc->dst->is_call_return = 1;
2234 /* Sort the successor arcs into ascending dst order. profile.cc
2235 normally produces arcs in the right order, but sometimes with
2236 one or two out of order. We're not using a particularly
2237 smart sort. */
2238 if (out_of_order)
2240 arc_info *start = blk->succ;
2241 unsigned changes = 1;
2243 while (changes)
2245 arc_info *arc, *arc_p, *arc_n;
2247 changes = 0;
2248 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
2250 if (arc->dst > arc_n->dst)
2252 changes = 1;
2253 if (arc_p)
2254 arc_p->succ_next = arc_n;
2255 else
2256 start = arc_n;
2257 arc->succ_next = arc_n->succ_next;
2258 arc_n->succ_next = arc;
2259 arc_p = arc_n;
2261 else
2263 arc_p = arc;
2264 arc = arc_n;
2268 blk->succ = start;
2271 /* Place it on the invalid chain, it will be ignored if that's
2272 wrong. */
2273 blk->invalid_chain = 1;
2274 blk->chain = invalid_blocks;
2275 invalid_blocks = blk;
2278 while (invalid_blocks || valid_blocks)
2280 while ((blk = invalid_blocks))
2282 gcov_type total = 0;
2283 const arc_info *arc;
2285 invalid_blocks = blk->chain;
2286 blk->invalid_chain = 0;
2287 if (!blk->num_succ)
2288 for (arc = blk->succ; arc; arc = arc->succ_next)
2289 total += arc->count;
2290 else if (!blk->num_pred)
2291 for (arc = blk->pred; arc; arc = arc->pred_next)
2292 total += arc->count;
2293 else
2294 continue;
2296 blk->count = total;
2297 blk->count_valid = 1;
2298 blk->chain = valid_blocks;
2299 blk->valid_chain = 1;
2300 valid_blocks = blk;
2302 while ((blk = valid_blocks))
2304 gcov_type total;
2305 arc_info *arc, *inv_arc;
2307 valid_blocks = blk->chain;
2308 blk->valid_chain = 0;
2309 if (blk->num_succ == 1)
2311 block_info *dst;
2313 total = blk->count;
2314 inv_arc = NULL;
2315 for (arc = blk->succ; arc; arc = arc->succ_next)
2317 total -= arc->count;
2318 if (!arc->count_valid)
2319 inv_arc = arc;
2321 dst = inv_arc->dst;
2322 inv_arc->count_valid = 1;
2323 inv_arc->count = total;
2324 blk->num_succ--;
2325 dst->num_pred--;
2326 if (dst->count_valid)
2328 if (dst->num_pred == 1 && !dst->valid_chain)
2330 dst->chain = valid_blocks;
2331 dst->valid_chain = 1;
2332 valid_blocks = dst;
2335 else
2337 if (!dst->num_pred && !dst->invalid_chain)
2339 dst->chain = invalid_blocks;
2340 dst->invalid_chain = 1;
2341 invalid_blocks = dst;
2345 if (blk->num_pred == 1)
2347 block_info *src;
2349 total = blk->count;
2350 inv_arc = NULL;
2351 for (arc = blk->pred; arc; arc = arc->pred_next)
2353 total -= arc->count;
2354 if (!arc->count_valid)
2355 inv_arc = arc;
2357 src = inv_arc->src;
2358 inv_arc->count_valid = 1;
2359 inv_arc->count = total;
2360 blk->num_pred--;
2361 src->num_succ--;
2362 if (src->count_valid)
2364 if (src->num_succ == 1 && !src->valid_chain)
2366 src->chain = valid_blocks;
2367 src->valid_chain = 1;
2368 valid_blocks = src;
2371 else
2373 if (!src->num_succ && !src->invalid_chain)
2375 src->chain = invalid_blocks;
2376 src->invalid_chain = 1;
2377 invalid_blocks = src;
2384 /* If the graph has been correctly solved, every block will have a
2385 valid count. */
2386 for (unsigned i = 0; ix < fn->blocks.size (); i++)
2387 if (!fn->blocks[i].count_valid)
2389 fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
2390 bbg_file_name, fn->get_name ());
2391 break;
2395 /* Mark all the blocks only reachable via an incoming catch. */
2397 static void
2398 find_exception_blocks (function_info *fn)
2400 unsigned ix;
2401 block_info **queue = XALLOCAVEC (block_info *, fn->blocks.size ());
2403 /* First mark all blocks as exceptional. */
2404 for (ix = fn->blocks.size (); ix--;)
2405 fn->blocks[ix].exceptional = 1;
2407 /* Now mark all the blocks reachable via non-fake edges */
2408 queue[0] = &fn->blocks[0];
2409 queue[0]->exceptional = 0;
2410 for (ix = 1; ix;)
2412 block_info *block = queue[--ix];
2413 const arc_info *arc;
2415 for (arc = block->succ; arc; arc = arc->succ_next)
2416 if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
2418 arc->dst->exceptional = 0;
2419 queue[ix++] = arc->dst;
2425 /* Increment totals in COVERAGE according to arc ARC. */
2427 static void
2428 add_branch_counts (coverage_info *coverage, const arc_info *arc)
2430 if (arc->is_call_non_return)
2432 coverage->calls++;
2433 if (arc->src->count)
2434 coverage->calls_executed++;
2436 else if (!arc->is_unconditional)
2438 coverage->branches++;
2439 if (arc->src->count)
2440 coverage->branches_executed++;
2441 if (arc->count)
2442 coverage->branches_taken++;
2446 /* Format COUNT, if flag_human_readable_numbers is set, return it human
2447 readable format. */
2449 static char const *
2450 format_count (gcov_type count)
2452 static char buffer[64];
2453 const char *units = " kMGTPEZY";
2455 if (count < 1000 || !flag_human_readable_numbers)
2457 sprintf (buffer, "%" PRId64, count);
2458 return buffer;
2461 unsigned i;
2462 gcov_type divisor = 1;
2463 for (i = 0; units[i+1]; i++, divisor *= 1000)
2465 if (count + divisor / 2 < 1000 * divisor)
2466 break;
2468 float r = 1.0f * count / divisor;
2469 sprintf (buffer, "%.1f%c", r, units[i]);
2470 return buffer;
2473 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
2474 count. If DECIMAL_PLACES >= 0, format TOP/BOTTOM * 100 to DECIMAL_PLACES.
2475 If DECIMAL_PLACES is zero, no decimal point is printed. Only print 100% when
2476 TOP==BOTTOM and only print 0% when TOP=0. If DECIMAL_PLACES < 0, then simply
2477 format TOP. Return pointer to a static string. */
2479 static char const *
2480 format_gcov (gcov_type top, gcov_type bottom, int decimal_places)
2482 static char buffer[20];
2484 if (decimal_places >= 0)
2486 float ratio = bottom ? 100.0f * top / bottom: 0;
2488 /* Round up to 1% if there's a small non-zero value. */
2489 if (ratio > 0.0f && ratio < 0.5f && decimal_places == 0)
2490 ratio = 1.0f;
2491 sprintf (buffer, "%.*f%%", decimal_places, ratio);
2493 else
2494 return format_count (top);
2496 return buffer;
2499 /* Summary of execution */
2501 static void
2502 executed_summary (unsigned lines, unsigned executed)
2504 if (lines)
2505 fnotice (stdout, "Lines executed:%s of %d\n",
2506 format_gcov (executed, lines, 2), lines);
2507 else
2508 fnotice (stdout, "No executable lines\n");
2511 /* Output summary info for a function. */
2513 static void
2514 function_summary (const coverage_info *coverage)
2516 fnotice (stdout, "%s '%s'\n", "Function", coverage->name);
2517 executed_summary (coverage->lines, coverage->lines_executed);
2520 /* Output summary info for a file. */
2522 static void
2523 file_summary (const coverage_info *coverage)
2525 fnotice (stdout, "%s '%s'\n", "File", coverage->name);
2526 executed_summary (coverage->lines, coverage->lines_executed);
2528 if (flag_branches)
2530 if (coverage->branches)
2532 fnotice (stdout, "Branches executed:%s of %d\n",
2533 format_gcov (coverage->branches_executed,
2534 coverage->branches, 2),
2535 coverage->branches);
2536 fnotice (stdout, "Taken at least once:%s of %d\n",
2537 format_gcov (coverage->branches_taken,
2538 coverage->branches, 2),
2539 coverage->branches);
2541 else
2542 fnotice (stdout, "No branches\n");
2543 if (coverage->calls)
2544 fnotice (stdout, "Calls executed:%s of %d\n",
2545 format_gcov (coverage->calls_executed, coverage->calls, 2),
2546 coverage->calls);
2547 else
2548 fnotice (stdout, "No calls\n");
2552 /* Canonicalize the filename NAME by canonicalizing directory
2553 separators, eliding . components and resolving .. components
2554 appropriately. Always returns a unique string. */
2556 static char *
2557 canonicalize_name (const char *name)
2559 /* The canonical name cannot be longer than the incoming name. */
2560 char *result = XNEWVEC (char, strlen (name) + 1);
2561 const char *base = name, *probe;
2562 char *ptr = result;
2563 char *dd_base;
2564 int slash = 0;
2566 #if HAVE_DOS_BASED_FILE_SYSTEM
2567 if (base[0] && base[1] == ':')
2569 result[0] = base[0];
2570 result[1] = ':';
2571 base += 2;
2572 ptr += 2;
2574 #endif
2575 for (dd_base = ptr; *base; base = probe)
2577 size_t len;
2579 for (probe = base; *probe; probe++)
2580 if (IS_DIR_SEPARATOR (*probe))
2581 break;
2583 len = probe - base;
2584 if (len == 1 && base[0] == '.')
2585 /* Elide a '.' directory */
2587 else if (len == 2 && base[0] == '.' && base[1] == '.')
2589 /* '..', we can only elide it and the previous directory, if
2590 we're not a symlink. */
2591 struct stat ATTRIBUTE_UNUSED buf;
2593 *ptr = 0;
2594 if (dd_base == ptr
2595 #if defined (S_ISLNK)
2596 /* S_ISLNK is not POSIX.1-1996. */
2597 || stat (result, &buf) || S_ISLNK (buf.st_mode)
2598 #endif
2601 /* Cannot elide, or unreadable or a symlink. */
2602 dd_base = ptr + 2 + slash;
2603 goto regular;
2605 while (ptr != dd_base && *ptr != '/')
2606 ptr--;
2607 slash = ptr != result;
2609 else
2611 regular:
2612 /* Regular pathname component. */
2613 if (slash)
2614 *ptr++ = '/';
2615 memcpy (ptr, base, len);
2616 ptr += len;
2617 slash = 1;
2620 for (; IS_DIR_SEPARATOR (*probe); probe++)
2621 continue;
2623 *ptr = 0;
2625 return result;
2628 /* Generate an output file name. INPUT_NAME is the canonicalized main
2629 input file and SRC_NAME is the canonicalized file name.
2630 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
2631 long_output_names we prepend the processed name of the input file
2632 to each output name (except when the current source file is the
2633 input file, so you don't get a double concatenation). The two
2634 components are separated by '##'. With preserve_paths we create a
2635 filename from all path components of the source file, replacing '/'
2636 with '#', and .. with '^', without it we simply take the basename
2637 component. (Remember, the canonicalized name will already have
2638 elided '.' components and converted \\ separators.) */
2640 static string
2641 make_gcov_file_name (const char *input_name, const char *src_name)
2643 string str;
2645 /* When hashing filenames, we shorten them by only using the filename
2646 component and appending a hash of the full (mangled) pathname. */
2647 if (flag_hash_filenames)
2648 str = (string (mangle_name (src_name)) + "##"
2649 + get_md5sum (src_name) + ".gcov");
2650 else
2652 if (flag_long_names && input_name && strcmp (src_name, input_name) != 0)
2654 str += mangle_name (input_name);
2655 str += "##";
2658 str += mangle_name (src_name);
2659 str += ".gcov";
2662 return str;
2665 /* Mangle BASE name, copy it at the beginning of PTR buffer and
2666 return address of the \0 character of the buffer. */
2668 static char *
2669 mangle_name (char const *base)
2671 /* Generate the source filename part. */
2672 if (!flag_preserve_paths)
2673 return xstrdup (lbasename (base));
2674 else
2675 return mangle_path (base);
2678 /* Scan through the bb_data for each line in the block, increment
2679 the line number execution count indicated by the execution count of
2680 the appropriate basic block. */
2682 static void
2683 add_line_counts (coverage_info *coverage, function_info *fn)
2685 bool has_any_line = false;
2686 /* Scan each basic block. */
2687 for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
2689 line_info *line = NULL;
2690 block_info *block = &fn->blocks[ix];
2691 if (block->count && ix && ix + 1 != fn->blocks.size ())
2692 fn->blocks_executed++;
2693 for (unsigned i = 0; i < block->locations.size (); i++)
2695 unsigned src_idx = block->locations[i].source_file_idx;
2696 vector<unsigned> &lines = block->locations[i].lines;
2698 block->cycle.arc = NULL;
2699 block->cycle.ident = ~0U;
2701 for (unsigned j = 0; j < lines.size (); j++)
2703 unsigned ln = lines[j];
2705 /* Line belongs to a function that is in a group. */
2706 if (fn->group_line_p (ln, src_idx))
2708 gcc_assert (lines[j] - fn->start_line < fn->lines.size ());
2709 line = &(fn->lines[lines[j] - fn->start_line]);
2710 if (coverage)
2712 if (!line->exists)
2713 coverage->lines++;
2714 if (!line->count && block->count)
2715 coverage->lines_executed++;
2717 line->exists = 1;
2718 if (!block->exceptional)
2720 line->unexceptional = 1;
2721 if (block->count == 0)
2722 line->has_unexecuted_block = 1;
2724 line->count += block->count;
2726 else
2728 gcc_assert (ln < sources[src_idx].lines.size ());
2729 line = &(sources[src_idx].lines[ln]);
2730 if (coverage)
2732 if (!line->exists)
2733 coverage->lines++;
2734 if (!line->count && block->count)
2735 coverage->lines_executed++;
2737 line->exists = 1;
2738 if (!block->exceptional)
2740 line->unexceptional = 1;
2741 if (block->count == 0)
2742 line->has_unexecuted_block = 1;
2744 line->count += block->count;
2748 has_any_line = true;
2750 if (!ix || ix + 1 == fn->blocks.size ())
2751 /* Entry or exit block. */;
2752 else if (line != NULL)
2754 line->blocks.push_back (block);
2756 if (flag_branches)
2758 arc_info *arc;
2760 for (arc = block->succ; arc; arc = arc->succ_next)
2761 line->branches.push_back (arc);
2767 if (!has_any_line)
2768 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name,
2769 fn->get_name ());
2772 /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE
2773 is set to true, update source file summary. */
2775 static void accumulate_line_info (line_info *line, source_info *src,
2776 bool add_coverage)
2778 if (add_coverage)
2779 for (vector<arc_info *>::iterator it = line->branches.begin ();
2780 it != line->branches.end (); it++)
2781 add_branch_counts (&src->coverage, *it);
2783 if (!line->blocks.empty ())
2785 /* The user expects the line count to be the number of times
2786 a line has been executed. Simply summing the block count
2787 will give an artificially high number. The Right Thing
2788 is to sum the entry counts to the graph of blocks on this
2789 line, then find the elementary cycles of the local graph
2790 and add the transition counts of those cycles. */
2791 gcov_type count = 0;
2793 /* Cycle detection. */
2794 for (vector<block_info *>::iterator it = line->blocks.begin ();
2795 it != line->blocks.end (); it++)
2797 for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next)
2798 if (!line->has_block (arc->src))
2799 count += arc->count;
2800 for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next)
2801 arc->cs_count = arc->count;
2804 /* Now, add the count of loops entirely on this line. */
2805 count += get_cycles_count (*line);
2806 line->count = count;
2808 if (line->count > src->maximum_count)
2809 src->maximum_count = line->count;
2812 if (line->exists && add_coverage)
2814 src->coverage.lines++;
2815 if (line->count)
2816 src->coverage.lines_executed++;
2820 /* Accumulate the line counts of a file. */
2822 static void
2823 accumulate_line_counts (source_info *src)
2825 /* First work on group functions. */
2826 for (vector<function_info *>::iterator it = src->functions.begin ();
2827 it != src->functions.end (); it++)
2829 function_info *fn = *it;
2831 if (fn->src != src->index || !fn->is_group)
2832 continue;
2834 for (vector<line_info>::iterator it2 = fn->lines.begin ();
2835 it2 != fn->lines.end (); it2++)
2837 line_info *line = &(*it2);
2838 accumulate_line_info (line, src, true);
2842 /* Work on global lines that line in source file SRC. */
2843 for (vector<line_info>::iterator it = src->lines.begin ();
2844 it != src->lines.end (); it++)
2845 accumulate_line_info (&(*it), src, true);
2847 /* If not using intermediate mode, sum lines of group functions and
2848 add them to lines that live in a source file. */
2849 if (!flag_json_format)
2850 for (vector<function_info *>::iterator it = src->functions.begin ();
2851 it != src->functions.end (); it++)
2853 function_info *fn = *it;
2855 if (fn->src != src->index || !fn->is_group)
2856 continue;
2858 for (unsigned i = 0; i < fn->lines.size (); i++)
2860 line_info *fn_line = &fn->lines[i];
2861 if (fn_line->exists)
2863 unsigned ln = fn->start_line + i;
2864 line_info *src_line = &src->lines[ln];
2866 if (!src_line->exists)
2867 src->coverage.lines++;
2868 if (!src_line->count && fn_line->count)
2869 src->coverage.lines_executed++;
2871 src_line->count += fn_line->count;
2872 src_line->exists = 1;
2874 if (fn_line->has_unexecuted_block)
2875 src_line->has_unexecuted_block = 1;
2877 if (fn_line->unexceptional)
2878 src_line->unexceptional = 1;
2884 /* Output information about ARC number IX. Returns nonzero if
2885 anything is output. */
2887 static int
2888 output_branch_count (FILE *gcov_file, int ix, const arc_info *arc)
2890 if (arc->is_call_non_return)
2892 if (arc->src->count)
2894 fnotice (gcov_file, "call %2d returned %s\n", ix,
2895 format_gcov (arc->src->count - arc->count,
2896 arc->src->count, -flag_counts));
2898 else
2899 fnotice (gcov_file, "call %2d never executed\n", ix);
2901 else if (!arc->is_unconditional)
2903 if (arc->src->count)
2904 fnotice (gcov_file, "branch %2d taken %s%s", ix,
2905 format_gcov (arc->count, arc->src->count, -flag_counts),
2906 arc->fall_through ? " (fallthrough)"
2907 : arc->is_throw ? " (throw)" : "");
2908 else
2909 fnotice (gcov_file, "branch %2d never executed%s", ix,
2910 (arc->fall_through ? " (fallthrough)"
2911 : arc->is_throw ? " (throw)" : ""));
2913 if (flag_verbose)
2914 fnotice (gcov_file, " (BB %d)", arc->dst->id);
2916 fnotice (gcov_file, "\n");
2918 else if (flag_unconditional && !arc->dst->is_call_return)
2920 if (arc->src->count)
2921 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
2922 format_gcov (arc->count, arc->src->count, -flag_counts));
2923 else
2924 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
2926 else
2927 return 0;
2928 return 1;
2931 static const char *
2932 read_line (FILE *file)
2934 static char *string;
2935 static size_t string_len;
2936 size_t pos = 0;
2938 if (!string_len)
2940 string_len = 200;
2941 string = XNEWVEC (char, string_len);
2944 while (fgets (string + pos, string_len - pos, file))
2946 size_t len = strlen (string + pos);
2948 if (len && string[pos + len - 1] == '\n')
2950 string[pos + len - 1] = 0;
2951 return string;
2953 pos += len;
2954 /* If the file contains NUL characters or an incomplete
2955 last line, which can happen more than once in one run,
2956 we have to avoid doubling the STRING_LEN unnecessarily. */
2957 if (pos > string_len / 2)
2959 string_len *= 2;
2960 string = XRESIZEVEC (char, string, string_len);
2964 return pos ? string : NULL;
2967 /* Pad string S with spaces from left to have total width equal to 9. */
2969 static void
2970 pad_count_string (string &s)
2972 if (s.size () < 9)
2973 s.insert (0, 9 - s.size (), ' ');
2976 /* Print GCOV line beginning to F stream. If EXISTS is set to true, the
2977 line exists in source file. UNEXCEPTIONAL indicated that it's not in
2978 an exceptional statement. The output is printed for LINE_NUM of given
2979 COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
2980 used to indicate non-executed blocks. */
2982 static void
2983 output_line_beginning (FILE *f, bool exists, bool unexceptional,
2984 bool has_unexecuted_block,
2985 gcov_type count, unsigned line_num,
2986 const char *exceptional_string,
2987 const char *unexceptional_string,
2988 unsigned int maximum_count)
2990 string s;
2991 if (exists)
2993 if (count > 0)
2995 s = format_gcov (count, 0, -1);
2996 if (has_unexecuted_block
2997 && bbg_supports_has_unexecuted_blocks)
2999 if (flag_use_colors)
3001 pad_count_string (s);
3002 s.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
3003 COLOR_SEPARATOR COLOR_FG_WHITE));
3004 s += SGR_RESET;
3006 else
3007 s += "*";
3009 pad_count_string (s);
3011 else
3013 if (flag_use_colors)
3015 s = "0";
3016 pad_count_string (s);
3017 if (unexceptional)
3018 s.insert (0, SGR_SEQ (COLOR_BG_RED
3019 COLOR_SEPARATOR COLOR_FG_WHITE));
3020 else
3021 s.insert (0, SGR_SEQ (COLOR_BG_CYAN
3022 COLOR_SEPARATOR COLOR_FG_WHITE));
3023 s += SGR_RESET;
3025 else
3027 s = unexceptional ? unexceptional_string : exceptional_string;
3028 pad_count_string (s);
3032 else
3034 s = "-";
3035 pad_count_string (s);
3038 /* Format line number in output. */
3039 char buffer[16];
3040 sprintf (buffer, "%5u", line_num);
3041 string linestr (buffer);
3043 if (flag_use_hotness_colors && maximum_count)
3045 if (count * 2 > maximum_count) /* > 50%. */
3046 linestr.insert (0, SGR_SEQ (COLOR_BG_RED));
3047 else if (count * 5 > maximum_count) /* > 20%. */
3048 linestr.insert (0, SGR_SEQ (COLOR_BG_YELLOW));
3049 else if (count * 10 > maximum_count) /* > 10%. */
3050 linestr.insert (0, SGR_SEQ (COLOR_BG_GREEN));
3051 linestr += SGR_RESET;
3054 fprintf (f, "%s:%s", s.c_str (), linestr.c_str ());
3057 static void
3058 print_source_line (FILE *f, const vector<const char *> &source_lines,
3059 unsigned line)
3061 gcc_assert (line >= 1);
3062 gcc_assert (line <= source_lines.size ());
3064 fprintf (f, ":%s\n", source_lines[line - 1]);
3067 /* Output line details for LINE and print it to F file. LINE lives on
3068 LINE_NUM. */
3070 static void
3071 output_line_details (FILE *f, const line_info *line, unsigned line_num)
3073 if (flag_all_blocks)
3075 arc_info *arc;
3076 int jx = 0;
3077 for (vector<block_info *>::const_iterator it = line->blocks.begin ();
3078 it != line->blocks.end (); it++)
3080 if (!(*it)->is_call_return)
3082 output_line_beginning (f, line->exists,
3083 (*it)->exceptional, false,
3084 (*it)->count, line_num,
3085 "%%%%%", "$$$$$", 0);
3086 fprintf (f, "-block %d", (*it)->id);
3087 if (flag_verbose)
3088 fprintf (f, " (BB %u)", (*it)->id);
3089 fprintf (f, "\n");
3091 if (flag_branches)
3092 for (arc = (*it)->succ; arc; arc = arc->succ_next)
3093 jx += output_branch_count (f, jx, arc);
3096 else if (flag_branches)
3098 int ix;
3100 ix = 0;
3101 for (vector<arc_info *>::const_iterator it = line->branches.begin ();
3102 it != line->branches.end (); it++)
3103 ix += output_branch_count (f, ix, (*it));
3107 /* Output detail statistics about function FN to file F. */
3109 static void
3110 output_function_details (FILE *f, function_info *fn)
3112 if (!flag_branches)
3113 return;
3115 arc_info *arc = fn->blocks[EXIT_BLOCK].pred;
3116 gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
3117 gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
3119 for (; arc; arc = arc->pred_next)
3120 if (arc->fake)
3121 return_count -= arc->count;
3123 fprintf (f, "function %s", fn->get_name ());
3124 fprintf (f, " called %s",
3125 format_gcov (called_count, 0, -1));
3126 fprintf (f, " returned %s",
3127 format_gcov (return_count, called_count, 0));
3128 fprintf (f, " blocks executed %s",
3129 format_gcov (fn->blocks_executed, fn->get_block_count (), 0));
3130 fprintf (f, "\n");
3133 /* Read in the source file one line at a time, and output that line to
3134 the gcov file preceded by its execution count and other
3135 information. */
3137 static void
3138 output_lines (FILE *gcov_file, const source_info *src)
3140 #define DEFAULT_LINE_START " -: 0:"
3141 #define FN_SEPARATOR "------------------\n"
3143 FILE *source_file;
3144 const char *retval;
3146 /* Print colorization legend. */
3147 if (flag_use_colors)
3148 fprintf (gcov_file, "%s",
3149 DEFAULT_LINE_START "Colorization: profile count: " \
3150 SGR_SEQ (COLOR_BG_CYAN) "zero coverage (exceptional)" SGR_RESET \
3151 " " \
3152 SGR_SEQ (COLOR_BG_RED) "zero coverage (unexceptional)" SGR_RESET \
3153 " " \
3154 SGR_SEQ (COLOR_BG_MAGENTA) "unexecuted block" SGR_RESET "\n");
3156 if (flag_use_hotness_colors)
3157 fprintf (gcov_file, "%s",
3158 DEFAULT_LINE_START "Colorization: line numbers: hotness: " \
3159 SGR_SEQ (COLOR_BG_RED) "> 50%" SGR_RESET " " \
3160 SGR_SEQ (COLOR_BG_YELLOW) "> 20%" SGR_RESET " " \
3161 SGR_SEQ (COLOR_BG_GREEN) "> 10%" SGR_RESET "\n");
3163 fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
3164 if (!multiple_files)
3166 fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
3167 fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
3168 no_data_file ? "-" : da_file_name);
3169 fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
3172 source_file = fopen (src->name, "r");
3173 if (!source_file)
3174 fnotice (stderr, "Cannot open source file %s\n", src->name);
3175 else if (src->file_time == 0)
3176 fprintf (gcov_file, DEFAULT_LINE_START "Source is newer than graph\n");
3178 vector<const char *> source_lines;
3179 if (source_file)
3180 while ((retval = read_line (source_file)) != NULL)
3181 source_lines.push_back (xstrdup (retval));
3183 unsigned line_start_group = 0;
3184 vector<function_info *> *fns;
3186 for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
3188 if (line_num >= src->lines.size ())
3190 fprintf (gcov_file, "%9s:%5u", "-", line_num);
3191 print_source_line (gcov_file, source_lines, line_num);
3192 continue;
3195 const line_info *line = &src->lines[line_num];
3197 if (line_start_group == 0)
3199 fns = src->get_functions_at_location (line_num);
3200 if (fns != NULL && fns->size () > 1)
3202 /* It's possible to have functions that partially overlap,
3203 thus take the maximum end_line of functions starting
3204 at LINE_NUM. */
3205 for (unsigned i = 0; i < fns->size (); i++)
3206 if ((*fns)[i]->end_line > line_start_group)
3207 line_start_group = (*fns)[i]->end_line;
3209 else if (fns != NULL && fns->size () == 1)
3211 function_info *fn = (*fns)[0];
3212 output_function_details (gcov_file, fn);
3216 /* For lines which don't exist in the .bb file, print '-' before
3217 the source line. For lines which exist but were never
3218 executed, print '#####' or '=====' before the source line.
3219 Otherwise, print the execution count before the source line.
3220 There are 16 spaces of indentation added before the source
3221 line so that tabs won't be messed up. */
3222 output_line_beginning (gcov_file, line->exists, line->unexceptional,
3223 line->has_unexecuted_block, line->count,
3224 line_num, "=====", "#####", src->maximum_count);
3226 print_source_line (gcov_file, source_lines, line_num);
3227 output_line_details (gcov_file, line, line_num);
3229 if (line_start_group == line_num)
3231 for (vector<function_info *>::iterator it = fns->begin ();
3232 it != fns->end (); it++)
3234 function_info *fn = *it;
3235 vector<line_info> &lines = fn->lines;
3237 fprintf (gcov_file, FN_SEPARATOR);
3239 string fn_name = fn->get_name ();
3240 if (flag_use_colors)
3242 fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN));
3243 fn_name += SGR_RESET;
3246 fprintf (gcov_file, "%s:\n", fn_name.c_str ());
3248 output_function_details (gcov_file, fn);
3250 /* Print all lines covered by the function. */
3251 for (unsigned i = 0; i < lines.size (); i++)
3253 line_info *line = &lines[i];
3254 unsigned l = fn->start_line + i;
3256 /* For lines which don't exist in the .bb file, print '-'
3257 before the source line. For lines which exist but
3258 were never executed, print '#####' or '=====' before
3259 the source line. Otherwise, print the execution count
3260 before the source line.
3261 There are 16 spaces of indentation added before the source
3262 line so that tabs won't be messed up. */
3263 output_line_beginning (gcov_file, line->exists,
3264 line->unexceptional,
3265 line->has_unexecuted_block,
3266 line->count,
3267 l, "=====", "#####",
3268 src->maximum_count);
3270 print_source_line (gcov_file, source_lines, l);
3271 output_line_details (gcov_file, line, l);
3275 fprintf (gcov_file, FN_SEPARATOR);
3276 line_start_group = 0;
3280 if (source_file)
3281 fclose (source_file);