[AArch64] Avoid GET_MODE_NUNITS in v8.4 support
[official-gcc.git] / gcc / gcov.c
blob37f431c0e91b43cb5477da0c462b26f208a209e0
1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file.
3 Copyright (C) 1990-2018 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"
48 #include <getopt.h>
50 #include "md5.h"
52 using namespace std;
54 #define IN_GCOV 1
55 #include "gcov-io.h"
56 #include "gcov-io.c"
58 /* The gcno file is generated by -ftest-coverage option. The gcda file is
59 generated by a program compiled with -fprofile-arcs. Their formats
60 are documented in gcov-io.h. */
62 /* The functions in this file for creating and solution program flow graphs
63 are very similar to functions in the gcc source file profile.c. In
64 some places we make use of the knowledge of how profile.c works to
65 select particular algorithms here. */
67 /* The code validates that the profile information read in corresponds
68 to the code currently being compiled. Rather than checking for
69 identical files, the code below compares a checksum on the CFG
70 (based on the order of basic blocks and the arcs in the CFG). If
71 the CFG checksum in the gcda file match the CFG checksum in the
72 gcno file, the profile data will be used. */
74 /* This is the size of the buffer used to read in source file lines. */
76 struct function_info;
77 struct block_info;
78 struct source_info;
80 /* Describes an arc between two basic blocks. */
82 struct arc_info
84 /* source and destination blocks. */
85 struct block_info *src;
86 struct block_info *dst;
88 /* transition counts. */
89 gcov_type count;
90 /* used in cycle search, so that we do not clobber original counts. */
91 gcov_type cs_count;
93 unsigned int count_valid : 1;
94 unsigned int on_tree : 1;
95 unsigned int fake : 1;
96 unsigned int fall_through : 1;
98 /* Arc to a catch handler. */
99 unsigned int is_throw : 1;
101 /* Arc is for a function that abnormally returns. */
102 unsigned int is_call_non_return : 1;
104 /* Arc is for catch/setjmp. */
105 unsigned int is_nonlocal_return : 1;
107 /* Is an unconditional branch. */
108 unsigned int is_unconditional : 1;
110 /* Loop making arc. */
111 unsigned int cycle : 1;
113 /* Links to next arc on src and dst lists. */
114 struct arc_info *succ_next;
115 struct arc_info *pred_next;
118 /* Describes which locations (lines and files) are associated with
119 a basic block. */
121 struct block_location_info
123 block_location_info (unsigned _source_file_idx):
124 source_file_idx (_source_file_idx)
127 unsigned source_file_idx;
128 vector<unsigned> lines;
131 /* Describes a basic block. Contains lists of arcs to successor and
132 predecessor blocks. */
134 struct block_info
136 /* Constructor. */
137 block_info ();
139 /* Chain of exit and entry arcs. */
140 arc_info *succ;
141 arc_info *pred;
143 /* Number of unprocessed exit and entry arcs. */
144 gcov_type num_succ;
145 gcov_type num_pred;
147 unsigned id;
149 /* Block execution count. */
150 gcov_type count;
151 unsigned count_valid : 1;
152 unsigned valid_chain : 1;
153 unsigned invalid_chain : 1;
154 unsigned exceptional : 1;
156 /* Block is a call instrumenting site. */
157 unsigned is_call_site : 1; /* Does the call. */
158 unsigned is_call_return : 1; /* Is the return. */
160 /* Block is a landing pad for longjmp or throw. */
161 unsigned is_nonlocal_return : 1;
163 vector<block_location_info> locations;
165 struct
167 /* Single line graph cycle workspace. Used for all-blocks
168 mode. */
169 arc_info *arc;
170 unsigned ident;
171 } cycle; /* Used in all-blocks mode, after blocks are linked onto
172 lines. */
174 /* Temporary chain for solving graph, and for chaining blocks on one
175 line. */
176 struct block_info *chain;
180 block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0),
181 id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
182 exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
183 locations (), chain (NULL)
185 cycle.arc = NULL;
188 /* Describes a single line of source. Contains a chain of basic blocks
189 with code on it. */
191 struct line_info
193 /* Default constructor. */
194 line_info ();
196 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
197 bool has_block (block_info *needle);
199 /* Execution count. */
200 gcov_type count;
202 /* Branches from blocks that end on this line. */
203 vector<arc_info *> branches;
205 /* blocks which start on this line. Used in all-blocks mode. */
206 vector<block_info *> blocks;
208 unsigned exists : 1;
209 unsigned unexceptional : 1;
210 unsigned has_unexecuted_block : 1;
213 line_info::line_info (): count (0), branches (), blocks (), exists (false),
214 unexceptional (0), has_unexecuted_block (0)
218 bool
219 line_info::has_block (block_info *needle)
221 return std::find (blocks.begin (), blocks.end (), needle) != blocks.end ();
224 /* Describes a single function. Contains an array of basic blocks. */
226 struct function_info
228 function_info ();
229 ~function_info ();
231 /* Return true when line N belongs to the function in source file SRC_IDX.
232 The line must be defined in body of the function, can't be inlined. */
233 bool group_line_p (unsigned n, unsigned src_idx);
235 /* Function filter based on function_info::artificial variable. */
237 static inline bool
238 is_artificial (function_info *fn)
240 return fn->artificial;
243 /* Name of function. */
244 char *name;
245 char *demangled_name;
246 unsigned ident;
247 unsigned lineno_checksum;
248 unsigned cfg_checksum;
250 /* The graph contains at least one fake incoming edge. */
251 unsigned has_catch : 1;
253 /* True when the function is artificial and does not exist
254 in a source file. */
255 unsigned artificial : 1;
257 /* True when multiple functions start at a line in a source file. */
258 unsigned is_group : 1;
260 /* Array of basic blocks. Like in GCC, the entry block is
261 at blocks[0] and the exit block is at blocks[1]. */
262 #define ENTRY_BLOCK (0)
263 #define EXIT_BLOCK (1)
264 vector<block_info> blocks;
265 unsigned blocks_executed;
267 /* Raw arc coverage counts. */
268 vector<gcov_type> counts;
270 /* First line number. */
271 unsigned start_line;
273 /* First line column. */
274 unsigned start_column;
276 /* Last line number. */
277 unsigned end_line;
279 /* Index of source file where the function is defined. */
280 unsigned src;
282 /* Vector of line information. */
283 vector<line_info> lines;
285 /* Next function. */
286 struct function_info *next;
289 /* Function info comparer that will sort functions according to starting
290 line. */
292 struct function_line_start_cmp
294 inline bool operator() (const function_info *lhs,
295 const function_info *rhs)
297 return (lhs->start_line == rhs->start_line
298 ? lhs->start_column < rhs->start_column
299 : lhs->start_line < rhs->start_line);
303 /* Describes coverage of a file or function. */
305 struct coverage_info
307 int lines;
308 int lines_executed;
310 int branches;
311 int branches_executed;
312 int branches_taken;
314 int calls;
315 int calls_executed;
317 char *name;
320 /* Describes a file mentioned in the block graph. Contains an array
321 of line info. */
323 struct source_info
325 /* Default constructor. */
326 source_info ();
328 vector<function_info *> get_functions_at_location (unsigned line_num) const;
330 /* Index of the source_info in sources vector. */
331 unsigned index;
333 /* Canonical name of source file. */
334 char *name;
335 time_t file_time;
337 /* Vector of line information. */
338 vector<line_info> lines;
340 coverage_info coverage;
342 /* Functions in this source file. These are in ascending line
343 number order. */
344 vector <function_info *> functions;
347 source_info::source_info (): index (0), name (NULL), file_time (),
348 lines (), coverage (), functions ()
352 vector<function_info *>
353 source_info::get_functions_at_location (unsigned line_num) const
355 vector<function_info *> r;
357 for (vector<function_info *>::const_iterator it = functions.begin ();
358 it != functions.end (); it++)
360 if ((*it)->start_line == line_num && (*it)->src == index)
361 r.push_back (*it);
364 std::sort (r.begin (), r.end (), function_line_start_cmp ());
366 return r;
369 class name_map
371 public:
372 name_map ()
376 name_map (char *_name, unsigned _src): name (_name), src (_src)
380 bool operator== (const name_map &rhs) const
382 #if HAVE_DOS_BASED_FILE_SYSTEM
383 return strcasecmp (this->name, rhs.name) == 0;
384 #else
385 return strcmp (this->name, rhs.name) == 0;
386 #endif
389 bool operator< (const name_map &rhs) const
391 #if HAVE_DOS_BASED_FILE_SYSTEM
392 return strcasecmp (this->name, rhs.name) < 0;
393 #else
394 return strcmp (this->name, rhs.name) < 0;
395 #endif
398 const char *name; /* Source file name */
399 unsigned src; /* Source file */
402 /* Vector of all functions. */
403 static vector<function_info *> functions;
405 /* Vector of source files. */
406 static vector<source_info> sources;
408 /* Mapping of file names to sources */
409 static vector<name_map> names;
411 /* This holds data summary information. */
413 static unsigned object_runs;
414 static unsigned program_count;
416 static unsigned total_lines;
417 static unsigned total_executed;
419 /* Modification time of graph file. */
421 static time_t bbg_file_time;
423 /* Name of the notes (gcno) output file. The "bbg" prefix is for
424 historical reasons, when the notes file contained only the
425 basic block graph notes. */
427 static char *bbg_file_name;
429 /* Stamp of the bbg file */
430 static unsigned bbg_stamp;
432 /* Supports has_unexecuted_blocks functionality. */
433 static unsigned bbg_supports_has_unexecuted_blocks;
435 /* Name and file pointer of the input file for the count data (gcda). */
437 static char *da_file_name;
439 /* Data file is missing. */
441 static int no_data_file;
443 /* If there is several input files, compute and display results after
444 reading all data files. This way if two or more gcda file refer to
445 the same source file (eg inline subprograms in a .h file), the
446 counts are added. */
448 static int multiple_files = 0;
450 /* Output branch probabilities. */
452 static int flag_branches = 0;
454 /* Show unconditional branches too. */
455 static int flag_unconditional = 0;
457 /* Output a gcov file if this is true. This is on by default, and can
458 be turned off by the -n option. */
460 static int flag_gcov_file = 1;
462 /* Output progress indication if this is true. This is off by default
463 and can be turned on by the -d option. */
465 static int flag_display_progress = 0;
467 /* Output *.gcov file in intermediate format used by 'lcov'. */
469 static int flag_intermediate_format = 0;
471 /* Output demangled function names. */
473 static int flag_demangled_names = 0;
475 /* For included files, make the gcov output file name include the name
476 of the input source file. For example, if x.h is included in a.c,
477 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
479 static int flag_long_names = 0;
481 /* For situations when a long name can potentially hit filesystem path limit,
482 let's calculate md5sum of the path and append it to a file name. */
484 static int flag_hash_filenames = 0;
486 /* Print verbose informations. */
488 static int flag_verbose = 0;
490 /* Print colored output. */
492 static int flag_use_colors = 0;
494 /* Output count information for every basic block, not merely those
495 that contain line number information. */
497 static int flag_all_blocks = 0;
499 /* Output human readable numbers. */
501 static int flag_human_readable_numbers = 0;
503 /* Output summary info for each function. */
505 static int flag_function_summary = 0;
507 /* Object directory file prefix. This is the directory/file where the
508 graph and data files are looked for, if nonzero. */
510 static char *object_directory = 0;
512 /* Source directory prefix. This is removed from source pathnames
513 that match, when generating the output file name. */
515 static char *source_prefix = 0;
516 static size_t source_length = 0;
518 /* Only show data for sources with relative pathnames. Absolute ones
519 usually indicate a system header file, which although it may
520 contain inline functions, is usually uninteresting. */
521 static int flag_relative_only = 0;
523 /* Preserve all pathname components. Needed when object files and
524 source files are in subdirectories. '/' is mangled as '#', '.' is
525 elided and '..' mangled to '^'. */
527 static int flag_preserve_paths = 0;
529 /* Output the number of times a branch was taken as opposed to the percentage
530 of times it was taken. */
532 static int flag_counts = 0;
534 /* Forward declarations. */
535 static int process_args (int, char **);
536 static void print_usage (int) ATTRIBUTE_NORETURN;
537 static void print_version (void) ATTRIBUTE_NORETURN;
538 static void process_file (const char *);
539 static void generate_results (const char *);
540 static void create_file_names (const char *);
541 static char *canonicalize_name (const char *);
542 static unsigned find_source (const char *);
543 static void read_graph_file (void);
544 static int read_count_file (void);
545 static void solve_flow_graph (function_info *);
546 static void find_exception_blocks (function_info *);
547 static void add_branch_counts (coverage_info *, const arc_info *);
548 static void add_line_counts (coverage_info *, function_info *);
549 static void executed_summary (unsigned, unsigned);
550 static void function_summary (const coverage_info *, const char *);
551 static const char *format_gcov (gcov_type, gcov_type, int);
552 static void accumulate_line_counts (source_info *);
553 static void output_gcov_file (const char *, source_info *);
554 static int output_branch_count (FILE *, int, const arc_info *);
555 static void output_lines (FILE *, const source_info *);
556 static char *make_gcov_file_name (const char *, const char *);
557 static char *mangle_name (const char *, char *);
558 static void release_structures (void);
559 extern int main (int, char **);
561 function_info::function_info (): name (NULL), demangled_name (NULL),
562 ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
563 artificial (0), is_group (0),
564 blocks (), blocks_executed (0), counts (),
565 start_line (0), start_column (), end_line (0), src (0), lines (), next (NULL)
569 function_info::~function_info ()
571 for (int i = blocks.size () - 1; i >= 0; i--)
573 arc_info *arc, *arc_n;
575 for (arc = blocks[i].succ; arc; arc = arc_n)
577 arc_n = arc->succ_next;
578 free (arc);
581 if (flag_demangled_names && demangled_name != name)
582 free (demangled_name);
583 free (name);
586 bool function_info::group_line_p (unsigned n, unsigned src_idx)
588 return is_group && src == src_idx && start_line <= n && n <= end_line;
591 /* Cycle detection!
592 There are a bajillion algorithms that do this. Boost's function is named
593 hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
594 "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
595 (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
597 The basic algorithm is simple: effectively, we're finding all simple paths
598 in a subgraph (that shrinks every iteration). Duplicates are filtered by
599 "blocking" a path when a node is added to the path (this also prevents non-
600 simple paths)--the node is unblocked only when it participates in a cycle.
603 typedef vector<arc_info *> arc_vector_t;
604 typedef vector<const block_info *> block_vector_t;
606 /* Enum with types of loop in CFG. */
608 enum loop_type
610 NO_LOOP = 0,
611 LOOP = 1,
612 NEGATIVE_LOOP = 3
615 /* Loop_type operator that merges two values: A and B. */
617 inline loop_type& operator |= (loop_type& a, loop_type b)
619 return a = static_cast<loop_type> (a | b);
622 /* Handle cycle identified by EDGES, where the function finds minimum cs_count
623 and subtract the value from all counts. The subtracted value is added
624 to COUNT. Returns type of loop. */
626 static loop_type
627 handle_cycle (const arc_vector_t &edges, int64_t &count)
629 /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
630 that amount. */
631 int64_t cycle_count = INTTYPE_MAXIMUM (int64_t);
632 for (unsigned i = 0; i < edges.size (); i++)
634 int64_t ecount = edges[i]->cs_count;
635 if (cycle_count > ecount)
636 cycle_count = ecount;
638 count += cycle_count;
639 for (unsigned i = 0; i < edges.size (); i++)
640 edges[i]->cs_count -= cycle_count;
642 return cycle_count < 0 ? NEGATIVE_LOOP : LOOP;
645 /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
646 blocked by U in BLOCK_LISTS. */
648 static void
649 unblock (const block_info *u, block_vector_t &blocked,
650 vector<block_vector_t > &block_lists)
652 block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u);
653 if (it == blocked.end ())
654 return;
656 unsigned index = it - blocked.begin ();
657 blocked.erase (it);
659 block_vector_t to_unblock (block_lists[index]);
661 block_lists.erase (block_lists.begin () + index);
663 for (block_vector_t::iterator it = to_unblock.begin ();
664 it != to_unblock.end (); it++)
665 unblock (*it, blocked, block_lists);
668 /* Find circuit going to block V, PATH is provisional seen cycle.
669 BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
670 blocked by a block. COUNT is accumulated count of the current LINE.
671 Returns what type of loop it contains. */
673 static loop_type
674 circuit (block_info *v, arc_vector_t &path, block_info *start,
675 block_vector_t &blocked, vector<block_vector_t> &block_lists,
676 line_info &linfo, int64_t &count)
678 loop_type result = NO_LOOP;
680 /* Add v to the block list. */
681 gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
682 blocked.push_back (v);
683 block_lists.push_back (block_vector_t ());
685 for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
687 block_info *w = arc->dst;
688 if (w < start || !linfo.has_block (w))
689 continue;
691 path.push_back (arc);
692 if (w == start)
693 /* Cycle has been found. */
694 result |= handle_cycle (path, count);
695 else if (find (blocked.begin (), blocked.end (), w) == blocked.end ())
696 result |= circuit (w, path, start, blocked, block_lists, linfo, count);
698 path.pop_back ();
701 if (result != NO_LOOP)
702 unblock (v, blocked, block_lists);
703 else
704 for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
706 block_info *w = arc->dst;
707 if (w < start || !linfo.has_block (w))
708 continue;
710 size_t index
711 = find (blocked.begin (), blocked.end (), w) - blocked.begin ();
712 gcc_assert (index < blocked.size ());
713 block_vector_t &list = block_lists[index];
714 if (find (list.begin (), list.end (), v) == list.end ())
715 list.push_back (v);
718 return result;
721 /* Find cycles for a LINFO. If HANDLE_NEGATIVE_CYCLES is set and the line
722 contains a negative loop, then perform the same function once again. */
724 static gcov_type
725 get_cycles_count (line_info &linfo, bool handle_negative_cycles = true)
727 /* Note that this algorithm works even if blocks aren't in sorted order.
728 Each iteration of the circuit detection is completely independent
729 (except for reducing counts, but that shouldn't matter anyways).
730 Therefore, operating on a permuted order (i.e., non-sorted) only
731 has the effect of permuting the output cycles. */
733 loop_type result = NO_LOOP;
734 gcov_type count = 0;
735 for (vector<block_info *>::iterator it = linfo.blocks.begin ();
736 it != linfo.blocks.end (); it++)
738 arc_vector_t path;
739 block_vector_t blocked;
740 vector<block_vector_t > block_lists;
741 result |= circuit (*it, path, *it, blocked, block_lists, linfo,
742 count);
745 /* If we have a negative cycle, repeat the find_cycles routine. */
746 if (result == NEGATIVE_LOOP && handle_negative_cycles)
747 count += get_cycles_count (linfo, false);
749 return count;
753 main (int argc, char **argv)
755 int argno;
756 int first_arg;
757 const char *p;
759 p = argv[0] + strlen (argv[0]);
760 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
761 --p;
762 progname = p;
764 xmalloc_set_program_name (progname);
766 /* Unlock the stdio streams. */
767 unlock_std_streams ();
769 gcc_init_libintl ();
771 diagnostic_initialize (global_dc, 0);
773 /* Handle response files. */
774 expandargv (&argc, &argv);
776 argno = process_args (argc, argv);
777 if (optind == argc)
778 print_usage (true);
780 if (argc - argno > 1)
781 multiple_files = 1;
783 first_arg = argno;
785 for (; argno != argc; argno++)
787 if (flag_display_progress)
788 printf ("Processing file %d out of %d\n", argno - first_arg + 1,
789 argc - first_arg);
790 process_file (argv[argno]);
792 if (flag_intermediate_format || argno == argc - 1)
794 generate_results (argv[argno]);
795 release_structures ();
799 return 0;
802 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
803 otherwise the output of --help. */
805 static void
806 print_usage (int error_p)
808 FILE *file = error_p ? stderr : stdout;
809 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
811 fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
812 fnotice (file, "Print code coverage information.\n\n");
813 fnotice (file, " -a, --all-blocks Show information for every basic block\n");
814 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
815 fnotice (file, " -c, --branch-counts Output counts of branches taken\n\
816 rather than percentages\n");
817 fnotice (file, " -d, --display-progress Display progress information\n");
818 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
819 fnotice (file, " -h, --help Print this help, then exit\n");
820 fnotice (file, " -i, --intermediate-format Output .gcov file in intermediate text format\n");
821 fnotice (file, " -j, --human-readable Output human readable numbers\n");
822 fnotice (file, " -k, --use-colors Emit colored output\n");
823 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
824 source files\n");
825 fnotice (file, " -m, --demangled-names Output demangled function names\n");
826 fnotice (file, " -n, --no-output Do not create an output file\n");
827 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
828 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
829 fnotice (file, " -r, --relative-only Only show data for relative sources\n");
830 fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n");
831 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
832 fnotice (file, " -v, --version Print version number, then exit\n");
833 fnotice (file, " -w, --verbose Print verbose informations\n");
834 fnotice (file, " -x, --hash-filenames Hash long pathnames\n");
835 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
836 bug_report_url);
837 exit (status);
840 /* Print version information and exit. */
842 static void
843 print_version (void)
845 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
846 fprintf (stdout, "Copyright %s 2018 Free Software Foundation, Inc.\n",
847 _("(C)"));
848 fnotice (stdout,
849 _("This is free software; see the source for copying conditions.\n"
850 "There is NO warranty; not even for MERCHANTABILITY or \n"
851 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
852 exit (SUCCESS_EXIT_CODE);
855 static const struct option options[] =
857 { "help", no_argument, NULL, 'h' },
858 { "version", no_argument, NULL, 'v' },
859 { "verbose", no_argument, NULL, 'w' },
860 { "all-blocks", no_argument, NULL, 'a' },
861 { "branch-probabilities", no_argument, NULL, 'b' },
862 { "branch-counts", no_argument, NULL, 'c' },
863 { "intermediate-format", no_argument, NULL, 'i' },
864 { "human-readable", no_argument, NULL, 'j' },
865 { "no-output", no_argument, NULL, 'n' },
866 { "long-file-names", no_argument, NULL, 'l' },
867 { "function-summaries", no_argument, NULL, 'f' },
868 { "demangled-names", no_argument, NULL, 'm' },
869 { "preserve-paths", no_argument, NULL, 'p' },
870 { "relative-only", no_argument, NULL, 'r' },
871 { "object-directory", required_argument, NULL, 'o' },
872 { "object-file", required_argument, NULL, 'o' },
873 { "source-prefix", required_argument, NULL, 's' },
874 { "unconditional-branches", no_argument, NULL, 'u' },
875 { "display-progress", no_argument, NULL, 'd' },
876 { "hash-filenames", no_argument, NULL, 'x' },
877 { "use-colors", no_argument, NULL, 'k' },
878 { 0, 0, 0, 0 }
881 /* Process args, return index to first non-arg. */
883 static int
884 process_args (int argc, char **argv)
886 int opt;
888 const char *opts = "abcdfhijklmno:prs:uvwx";
889 while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
891 switch (opt)
893 case 'a':
894 flag_all_blocks = 1;
895 break;
896 case 'b':
897 flag_branches = 1;
898 break;
899 case 'c':
900 flag_counts = 1;
901 break;
902 case 'f':
903 flag_function_summary = 1;
904 break;
905 case 'h':
906 print_usage (false);
907 /* print_usage will exit. */
908 case 'l':
909 flag_long_names = 1;
910 break;
911 case 'j':
912 flag_human_readable_numbers = 1;
913 break;
914 case 'k':
915 flag_use_colors = 1;
916 break;
917 case 'm':
918 flag_demangled_names = 1;
919 break;
920 case 'n':
921 flag_gcov_file = 0;
922 break;
923 case 'o':
924 object_directory = optarg;
925 break;
926 case 's':
927 source_prefix = optarg;
928 source_length = strlen (source_prefix);
929 break;
930 case 'r':
931 flag_relative_only = 1;
932 break;
933 case 'p':
934 flag_preserve_paths = 1;
935 break;
936 case 'u':
937 flag_unconditional = 1;
938 break;
939 case 'i':
940 flag_intermediate_format = 1;
941 flag_gcov_file = 1;
942 break;
943 case 'd':
944 flag_display_progress = 1;
945 break;
946 case 'x':
947 flag_hash_filenames = 1;
948 break;
949 case 'w':
950 flag_verbose = 1;
951 break;
952 case 'v':
953 print_version ();
954 /* print_version will exit. */
955 default:
956 print_usage (true);
957 /* print_usage will exit. */
961 return optind;
964 /* Output intermediate LINE sitting on LINE_NUM to output file F. */
966 static void
967 output_intermediate_line (FILE *f, line_info *line, unsigned line_num)
969 if (!line->exists)
970 return;
972 fprintf (f, "lcount:%u,%s,%d\n", line_num,
973 format_gcov (line->count, 0, -1),
974 line->has_unexecuted_block);
976 vector<arc_info *>::const_iterator it;
977 if (flag_branches)
978 for (it = line->branches.begin (); it != line->branches.end ();
979 it++)
981 if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
983 const char *branch_type;
984 /* branch:<line_num>,<branch_coverage_infoype>
985 branch_coverage_infoype
986 : notexec (Branch not executed)
987 : taken (Branch executed and taken)
988 : nottaken (Branch executed, but not taken)
990 if ((*it)->src->count)
991 branch_type
992 = ((*it)->count > 0) ? "taken" : "nottaken";
993 else
994 branch_type = "notexec";
995 fprintf (f, "branch:%d,%s\n", line_num, branch_type);
1000 /* Get the name of the gcov file. The return value must be free'd.
1002 It appends the '.gcov' extension to the *basename* of the file.
1003 The resulting file name will be in PWD.
1005 e.g.,
1006 input: foo.da, output: foo.da.gcov
1007 input: a/b/foo.cc, output: foo.cc.gcov */
1009 static char *
1010 get_gcov_intermediate_filename (const char *file_name)
1012 const char *gcov = ".gcov";
1013 char *result;
1014 const char *cptr;
1016 /* Find the 'basename'. */
1017 cptr = lbasename (file_name);
1019 result = XNEWVEC (char, strlen (cptr) + strlen (gcov) + 1);
1020 sprintf (result, "%s%s", cptr, gcov);
1022 return result;
1025 /* Output the result in intermediate format used by 'lcov'.
1027 The intermediate format contains a single file named 'foo.cc.gcov',
1028 with no source code included.
1030 The default gcov outputs multiple files: 'foo.cc.gcov',
1031 'iostream.gcov', 'ios_base.h.gcov', etc. with source code
1032 included. Instead the intermediate format here outputs only a single
1033 file 'foo.cc.gcov' similar to the above example. */
1035 static void
1036 output_intermediate_file (FILE *gcov_file, source_info *src)
1038 fprintf (gcov_file, "version:%s\n", version_string);
1039 fprintf (gcov_file, "file:%s\n", src->name); /* source file name */
1041 std::sort (src->functions.begin (), src->functions.end (),
1042 function_line_start_cmp ());
1043 for (vector<function_info *>::iterator it = src->functions.begin ();
1044 it != src->functions.end (); it++)
1046 /* function:<name>,<line_number>,<execution_count> */
1047 fprintf (gcov_file, "function:%d,%d,%s,%s\n", (*it)->start_line,
1048 (*it)->end_line, format_gcov ((*it)->blocks[0].count, 0, -1),
1049 flag_demangled_names ? (*it)->demangled_name : (*it)->name);
1052 for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
1054 vector<function_info *> fns = src->get_functions_at_location (line_num);
1056 /* Print first group functions that begin on the line. */
1057 for (vector<function_info *>::iterator it2 = fns.begin ();
1058 it2 != fns.end (); it2++)
1060 vector<line_info> &lines = (*it2)->lines;
1061 for (unsigned i = 0; i < lines.size (); i++)
1063 line_info *line = &lines[i];
1064 output_intermediate_line (gcov_file, line, line_num + i);
1068 /* Follow with lines associated with the source file. */
1069 output_intermediate_line (gcov_file, &src->lines[line_num], line_num);
1073 /* Function start pair. */
1074 struct function_start
1076 unsigned source_file_idx;
1077 unsigned start_line;
1080 /* Traits class for function start hash maps below. */
1082 struct function_start_pair_hash : typed_noop_remove <function_start>
1084 typedef function_start value_type;
1085 typedef function_start compare_type;
1087 static hashval_t
1088 hash (const function_start &ref)
1090 inchash::hash hstate (0);
1091 hstate.add_int (ref.source_file_idx);
1092 hstate.add_int (ref.start_line);
1093 return hstate.end ();
1096 static bool
1097 equal (const function_start &ref1, const function_start &ref2)
1099 return (ref1.source_file_idx == ref2.source_file_idx
1100 && ref1.start_line == ref2.start_line);
1103 static void
1104 mark_deleted (function_start &ref)
1106 ref.start_line = ~1U;
1109 static void
1110 mark_empty (function_start &ref)
1112 ref.start_line = ~2U;
1115 static bool
1116 is_deleted (const function_start &ref)
1118 return ref.start_line == ~1U;
1121 static bool
1122 is_empty (const function_start &ref)
1124 return ref.start_line == ~2U;
1128 /* Process a single input file. */
1130 static void
1131 process_file (const char *file_name)
1133 create_file_names (file_name);
1134 read_graph_file ();
1135 if (functions.empty ())
1136 return;
1138 read_count_file ();
1140 hash_map<function_start_pair_hash, function_info *> fn_map;
1142 /* Identify group functions. */
1143 for (vector<function_info *>::iterator it = functions.begin ();
1144 it != functions.end (); it++)
1145 if (!(*it)->artificial)
1147 function_start needle;
1148 needle.source_file_idx = (*it)->src;
1149 needle.start_line = (*it)->start_line;
1151 function_info **slot = fn_map.get (needle);
1152 if (slot)
1154 gcc_assert ((*slot)->end_line == (*it)->end_line);
1155 (*slot)->is_group = 1;
1156 (*it)->is_group = 1;
1158 else
1159 fn_map.put (needle, *it);
1162 /* Remove all artificial function. */
1163 functions.erase (remove_if (functions.begin (), functions.end (),
1164 function_info::is_artificial), functions.end ());
1166 for (vector<function_info *>::iterator it = functions.begin ();
1167 it != functions.end (); it++)
1169 function_info *fn = *it;
1170 unsigned src = fn->src;
1172 if (!fn->counts.empty () || no_data_file)
1174 source_info *s = &sources[src];
1175 s->functions.push_back (fn);
1177 /* Mark last line in files touched by function. */
1178 for (unsigned block_no = 0; block_no != fn->blocks.size ();
1179 block_no++)
1181 block_info *block = &fn->blocks[block_no];
1182 for (unsigned i = 0; i < block->locations.size (); i++)
1184 /* Sort lines of locations. */
1185 sort (block->locations[i].lines.begin (),
1186 block->locations[i].lines.end ());
1188 if (!block->locations[i].lines.empty ())
1190 s = &sources[block->locations[i].source_file_idx];
1191 unsigned last_line
1192 = block->locations[i].lines.back ();
1194 /* Record new lines for the function. */
1195 if (last_line >= s->lines.size ())
1197 s = &sources[block->locations[i].source_file_idx];
1198 unsigned last_line
1199 = block->locations[i].lines.back ();
1201 /* Record new lines for the function. */
1202 if (last_line >= s->lines.size ())
1204 /* Record new lines for a source file. */
1205 s->lines.resize (last_line + 1);
1212 /* Allocate lines for group function, following start_line
1213 and end_line information of the function. */
1214 if (fn->is_group)
1215 fn->lines.resize (fn->end_line - fn->start_line + 1);
1218 solve_flow_graph (fn);
1219 if (fn->has_catch)
1220 find_exception_blocks (fn);
1222 else
1224 /* The function was not in the executable -- some other
1225 instance must have been selected. */
1230 static void
1231 output_gcov_file (const char *file_name, source_info *src)
1233 char *gcov_file_name = make_gcov_file_name (file_name, src->coverage.name);
1235 if (src->coverage.lines)
1237 FILE *gcov_file = fopen (gcov_file_name, "w");
1238 if (gcov_file)
1240 fnotice (stdout, "Creating '%s'\n", gcov_file_name);
1241 output_lines (gcov_file, src);
1242 if (ferror (gcov_file))
1243 fnotice (stderr, "Error writing output file '%s'\n",
1244 gcov_file_name);
1245 fclose (gcov_file);
1247 else
1248 fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
1250 else
1252 unlink (gcov_file_name);
1253 fnotice (stdout, "Removing '%s'\n", gcov_file_name);
1255 free (gcov_file_name);
1258 static void
1259 generate_results (const char *file_name)
1261 FILE *gcov_intermediate_file = NULL;
1262 char *gcov_intermediate_filename = NULL;
1264 for (vector<function_info *>::iterator it = functions.begin ();
1265 it != functions.end (); it++)
1267 function_info *fn = *it;
1268 coverage_info coverage;
1270 memset (&coverage, 0, sizeof (coverage));
1271 coverage.name = flag_demangled_names ? fn->demangled_name : fn->name;
1272 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
1273 if (flag_function_summary)
1275 function_summary (&coverage, "Function");
1276 fnotice (stdout, "\n");
1280 name_map needle;
1282 if (file_name)
1284 needle.name = file_name;
1285 vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1286 needle);
1287 if (it != names.end ())
1288 file_name = sources[it->src].coverage.name;
1289 else
1290 file_name = canonicalize_name (file_name);
1293 if (flag_gcov_file && flag_intermediate_format)
1295 /* Open the intermediate file. */
1296 gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
1297 gcov_intermediate_file = fopen (gcov_intermediate_filename, "w");
1298 if (!gcov_intermediate_file)
1300 fnotice (stderr, "Cannot open intermediate output file %s\n",
1301 gcov_intermediate_filename);
1302 return;
1306 for (vector<source_info>::iterator it = sources.begin ();
1307 it != sources.end (); it++)
1309 source_info *src = &(*it);
1310 if (flag_relative_only)
1312 /* Ignore this source, if it is an absolute path (after
1313 source prefix removal). */
1314 char first = src->coverage.name[0];
1316 #if HAVE_DOS_BASED_FILE_SYSTEM
1317 if (first && src->coverage.name[1] == ':')
1318 first = src->coverage.name[2];
1319 #endif
1320 if (IS_DIR_SEPARATOR (first))
1321 continue;
1324 accumulate_line_counts (src);
1325 function_summary (&src->coverage, "File");
1326 total_lines += src->coverage.lines;
1327 total_executed += src->coverage.lines_executed;
1328 if (flag_gcov_file)
1330 if (flag_intermediate_format)
1331 /* Output the intermediate format without requiring source
1332 files. This outputs a section to a *single* file. */
1333 output_intermediate_file (gcov_intermediate_file, src);
1334 else
1335 output_gcov_file (file_name, src);
1336 fnotice (stdout, "\n");
1340 if (flag_gcov_file && flag_intermediate_format)
1342 /* Now we've finished writing the intermediate file. */
1343 fclose (gcov_intermediate_file);
1344 XDELETEVEC (gcov_intermediate_filename);
1347 if (!file_name)
1348 executed_summary (total_lines, total_executed);
1351 /* Release all memory used. */
1353 static void
1354 release_structures (void)
1356 for (vector<function_info *>::iterator it = functions.begin ();
1357 it != functions.end (); it++)
1358 delete (*it);
1360 sources.resize (0);
1361 names.resize (0);
1362 functions.resize (0);
1365 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
1366 is not specified, these are named from FILE_NAME sans extension. If
1367 OBJECT_DIRECTORY is specified and is a directory, the files are in that
1368 directory, but named from the basename of the FILE_NAME, sans extension.
1369 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
1370 and the data files are named from that. */
1372 static void
1373 create_file_names (const char *file_name)
1375 char *cptr;
1376 char *name;
1377 int length = strlen (file_name);
1378 int base;
1380 /* Free previous file names. */
1381 free (bbg_file_name);
1382 free (da_file_name);
1383 da_file_name = bbg_file_name = NULL;
1384 bbg_file_time = 0;
1385 bbg_stamp = 0;
1387 if (object_directory && object_directory[0])
1389 struct stat status;
1391 length += strlen (object_directory) + 2;
1392 name = XNEWVEC (char, length);
1393 name[0] = 0;
1395 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
1396 strcat (name, object_directory);
1397 if (base && (!IS_DIR_SEPARATOR (name[strlen (name) - 1])))
1398 strcat (name, "/");
1400 else
1402 name = XNEWVEC (char, length + 1);
1403 strcpy (name, file_name);
1404 base = 0;
1407 if (base)
1409 /* Append source file name. */
1410 const char *cptr = lbasename (file_name);
1411 strcat (name, cptr ? cptr : file_name);
1414 /* Remove the extension. */
1415 cptr = strrchr (CONST_CAST (char *, lbasename (name)), '.');
1416 if (cptr)
1417 *cptr = 0;
1419 length = strlen (name);
1421 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
1422 strcpy (bbg_file_name, name);
1423 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
1425 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
1426 strcpy (da_file_name, name);
1427 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
1429 free (name);
1430 return;
1433 /* Find or create a source file structure for FILE_NAME. Copies
1434 FILE_NAME on creation */
1436 static unsigned
1437 find_source (const char *file_name)
1439 char *canon;
1440 unsigned idx;
1441 struct stat status;
1443 if (!file_name)
1444 file_name = "<unknown>";
1446 name_map needle;
1447 needle.name = file_name;
1449 vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1450 needle);
1451 if (it != names.end ())
1453 idx = it->src;
1454 goto check_date;
1457 /* Not found, try the canonical name. */
1458 canon = canonicalize_name (file_name);
1459 needle.name = canon;
1460 it = std::find (names.begin (), names.end (), needle);
1461 if (it == names.end ())
1463 /* Not found with canonical name, create a new source. */
1464 source_info *src;
1466 idx = sources.size ();
1467 needle = name_map (canon, idx);
1468 names.push_back (needle);
1470 sources.push_back (source_info ());
1471 src = &sources.back ();
1472 src->name = canon;
1473 src->coverage.name = src->name;
1474 src->index = idx;
1475 if (source_length
1476 #if HAVE_DOS_BASED_FILE_SYSTEM
1477 /* You lose if separators don't match exactly in the
1478 prefix. */
1479 && !strncasecmp (source_prefix, src->coverage.name, source_length)
1480 #else
1481 && !strncmp (source_prefix, src->coverage.name, source_length)
1482 #endif
1483 && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
1484 src->coverage.name += source_length + 1;
1485 if (!stat (src->name, &status))
1486 src->file_time = status.st_mtime;
1488 else
1489 idx = it->src;
1491 needle.name = file_name;
1492 if (std::find (names.begin (), names.end (), needle) == names.end ())
1494 /* Append the non-canonical name. */
1495 names.push_back (name_map (xstrdup (file_name), idx));
1498 /* Resort the name map. */
1499 std::sort (names.begin (), names.end ());
1501 check_date:
1502 if (sources[idx].file_time > bbg_file_time)
1504 static int info_emitted;
1506 fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
1507 file_name, bbg_file_name);
1508 if (!info_emitted)
1510 fnotice (stderr,
1511 "(the message is displayed only once per source file)\n");
1512 info_emitted = 1;
1514 sources[idx].file_time = 0;
1517 return idx;
1520 /* Read the notes file. Save functions to FUNCTIONS global vector. */
1522 static void
1523 read_graph_file (void)
1525 unsigned version;
1526 unsigned current_tag = 0;
1527 unsigned tag;
1529 if (!gcov_open (bbg_file_name, 1))
1531 fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1532 return;
1534 bbg_file_time = gcov_time ();
1535 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1537 fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
1538 gcov_close ();
1539 return;
1542 version = gcov_read_unsigned ();
1543 if (version != GCOV_VERSION)
1545 char v[4], e[4];
1547 GCOV_UNSIGNED2STRING (v, version);
1548 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1550 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1551 bbg_file_name, v, e);
1553 bbg_stamp = gcov_read_unsigned ();
1554 bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
1556 function_info *fn = NULL;
1557 while ((tag = gcov_read_unsigned ()))
1559 unsigned length = gcov_read_unsigned ();
1560 gcov_position_t base = gcov_position ();
1562 if (tag == GCOV_TAG_FUNCTION)
1564 char *function_name;
1565 unsigned ident;
1566 unsigned lineno_checksum, cfg_checksum;
1568 ident = gcov_read_unsigned ();
1569 lineno_checksum = gcov_read_unsigned ();
1570 cfg_checksum = gcov_read_unsigned ();
1571 function_name = xstrdup (gcov_read_string ());
1572 unsigned artificial = gcov_read_unsigned ();
1573 unsigned src_idx = find_source (gcov_read_string ());
1574 unsigned start_line = gcov_read_unsigned ();
1575 unsigned start_column = gcov_read_unsigned ();
1576 unsigned end_line = gcov_read_unsigned ();
1578 fn = new function_info ();
1579 functions.push_back (fn);
1580 fn->name = function_name;
1581 if (flag_demangled_names)
1583 fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS);
1584 if (!fn->demangled_name)
1585 fn->demangled_name = fn->name;
1587 fn->ident = ident;
1588 fn->lineno_checksum = lineno_checksum;
1589 fn->cfg_checksum = cfg_checksum;
1590 fn->src = src_idx;
1591 fn->start_line = start_line;
1592 fn->start_column = start_column;
1593 fn->end_line = end_line;
1594 fn->artificial = artificial;
1596 current_tag = tag;
1598 else if (fn && tag == GCOV_TAG_BLOCKS)
1600 if (!fn->blocks.empty ())
1601 fnotice (stderr, "%s:already seen blocks for '%s'\n",
1602 bbg_file_name, fn->name);
1603 else
1604 fn->blocks.resize (gcov_read_unsigned ());
1606 else if (fn && tag == GCOV_TAG_ARCS)
1608 unsigned src = gcov_read_unsigned ();
1609 fn->blocks[src].id = src;
1610 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1611 block_info *src_blk = &fn->blocks[src];
1612 unsigned mark_catches = 0;
1613 struct arc_info *arc;
1615 if (src >= fn->blocks.size () || fn->blocks[src].succ)
1616 goto corrupt;
1618 while (num_dests--)
1620 unsigned dest = gcov_read_unsigned ();
1621 unsigned flags = gcov_read_unsigned ();
1623 if (dest >= fn->blocks.size ())
1624 goto corrupt;
1625 arc = XCNEW (arc_info);
1627 arc->dst = &fn->blocks[dest];
1628 arc->src = src_blk;
1630 arc->count = 0;
1631 arc->count_valid = 0;
1632 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
1633 arc->fake = !!(flags & GCOV_ARC_FAKE);
1634 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
1636 arc->succ_next = src_blk->succ;
1637 src_blk->succ = arc;
1638 src_blk->num_succ++;
1640 arc->pred_next = fn->blocks[dest].pred;
1641 fn->blocks[dest].pred = arc;
1642 fn->blocks[dest].num_pred++;
1644 if (arc->fake)
1646 if (src)
1648 /* Exceptional exit from this function, the
1649 source block must be a call. */
1650 fn->blocks[src].is_call_site = 1;
1651 arc->is_call_non_return = 1;
1652 mark_catches = 1;
1654 else
1656 /* Non-local return from a callee of this
1657 function. The destination block is a setjmp. */
1658 arc->is_nonlocal_return = 1;
1659 fn->blocks[dest].is_nonlocal_return = 1;
1663 if (!arc->on_tree)
1664 fn->counts.push_back (0);
1667 if (mark_catches)
1669 /* We have a fake exit from this block. The other
1670 non-fall through exits must be to catch handlers.
1671 Mark them as catch arcs. */
1673 for (arc = src_blk->succ; arc; arc = arc->succ_next)
1674 if (!arc->fake && !arc->fall_through)
1676 arc->is_throw = 1;
1677 fn->has_catch = 1;
1681 else if (fn && tag == GCOV_TAG_LINES)
1683 unsigned blockno = gcov_read_unsigned ();
1684 block_info *block = &fn->blocks[blockno];
1686 if (blockno >= fn->blocks.size ())
1687 goto corrupt;
1689 while (true)
1691 unsigned lineno = gcov_read_unsigned ();
1693 if (lineno)
1694 block->locations.back ().lines.push_back (lineno);
1695 else
1697 const char *file_name = gcov_read_string ();
1699 if (!file_name)
1700 break;
1701 block->locations.push_back (block_location_info
1702 (find_source (file_name)));
1706 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
1708 fn = NULL;
1709 current_tag = 0;
1711 gcov_sync (base, length);
1712 if (gcov_is_error ())
1714 corrupt:;
1715 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
1716 break;
1719 gcov_close ();
1721 if (functions.empty ())
1722 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
1725 /* Reads profiles from the count file and attach to each
1726 function. Return nonzero if fatal error. */
1728 static int
1729 read_count_file (void)
1731 unsigned ix;
1732 unsigned version;
1733 unsigned tag;
1734 function_info *fn = NULL;
1735 int error = 0;
1737 if (!gcov_open (da_file_name, 1))
1739 fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
1740 da_file_name);
1741 no_data_file = 1;
1742 return 0;
1744 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
1746 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
1747 cleanup:;
1748 gcov_close ();
1749 return 1;
1751 version = gcov_read_unsigned ();
1752 if (version != GCOV_VERSION)
1754 char v[4], e[4];
1756 GCOV_UNSIGNED2STRING (v, version);
1757 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1759 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
1760 da_file_name, v, e);
1762 tag = gcov_read_unsigned ();
1763 if (tag != bbg_stamp)
1765 fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
1766 goto cleanup;
1769 while ((tag = gcov_read_unsigned ()))
1771 unsigned length = gcov_read_unsigned ();
1772 unsigned long base = gcov_position ();
1774 if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1776 struct gcov_summary summary;
1777 gcov_read_summary (&summary);
1778 object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs;
1779 program_count++;
1781 else if (tag == GCOV_TAG_FUNCTION && !length)
1782 ; /* placeholder */
1783 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
1785 unsigned ident;
1787 /* Try to find the function in the list. To speed up the
1788 search, first start from the last function found. */
1789 ident = gcov_read_unsigned ();
1791 fn = NULL;
1792 for (vector<function_info *>::reverse_iterator it
1793 = functions.rbegin (); it != functions.rend (); it++)
1795 if ((*it)->ident == ident)
1797 fn = *it;
1798 break;
1802 if (!fn)
1804 else if (gcov_read_unsigned () != fn->lineno_checksum
1805 || gcov_read_unsigned () != fn->cfg_checksum)
1807 mismatch:;
1808 fnotice (stderr, "%s:profile mismatch for '%s'\n",
1809 da_file_name, fn->name);
1810 goto cleanup;
1813 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1815 if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
1816 goto mismatch;
1818 for (ix = 0; ix != fn->counts.size (); ix++)
1819 fn->counts[ix] += gcov_read_counter ();
1821 gcov_sync (base, length);
1822 if ((error = gcov_is_error ()))
1824 fnotice (stderr,
1825 error < 0
1826 ? N_("%s:overflowed\n")
1827 : N_("%s:corrupted\n"),
1828 da_file_name);
1829 goto cleanup;
1833 gcov_close ();
1834 return 0;
1837 /* Solve the flow graph. Propagate counts from the instrumented arcs
1838 to the blocks and the uninstrumented arcs. */
1840 static void
1841 solve_flow_graph (function_info *fn)
1843 unsigned ix;
1844 arc_info *arc;
1845 gcov_type *count_ptr = &fn->counts.front ();
1846 block_info *blk;
1847 block_info *valid_blocks = NULL; /* valid, but unpropagated blocks. */
1848 block_info *invalid_blocks = NULL; /* invalid, but inferable blocks. */
1850 /* The arcs were built in reverse order. Fix that now. */
1851 for (ix = fn->blocks.size (); ix--;)
1853 arc_info *arc_p, *arc_n;
1855 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
1856 arc_p = arc, arc = arc_n)
1858 arc_n = arc->succ_next;
1859 arc->succ_next = arc_p;
1861 fn->blocks[ix].succ = arc_p;
1863 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
1864 arc_p = arc, arc = arc_n)
1866 arc_n = arc->pred_next;
1867 arc->pred_next = arc_p;
1869 fn->blocks[ix].pred = arc_p;
1872 if (fn->blocks.size () < 2)
1873 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
1874 bbg_file_name, fn->name);
1875 else
1877 if (fn->blocks[ENTRY_BLOCK].num_pred)
1878 fnotice (stderr, "%s:'%s' has arcs to entry block\n",
1879 bbg_file_name, fn->name);
1880 else
1881 /* We can't deduce the entry block counts from the lack of
1882 predecessors. */
1883 fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
1885 if (fn->blocks[EXIT_BLOCK].num_succ)
1886 fnotice (stderr, "%s:'%s' has arcs from exit block\n",
1887 bbg_file_name, fn->name);
1888 else
1889 /* Likewise, we can't deduce exit block counts from the lack
1890 of its successors. */
1891 fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
1894 /* Propagate the measured counts, this must be done in the same
1895 order as the code in profile.c */
1896 for (unsigned i = 0; i < fn->blocks.size (); i++)
1898 blk = &fn->blocks[i];
1899 block_info const *prev_dst = NULL;
1900 int out_of_order = 0;
1901 int non_fake_succ = 0;
1903 for (arc = blk->succ; arc; arc = arc->succ_next)
1905 if (!arc->fake)
1906 non_fake_succ++;
1908 if (!arc->on_tree)
1910 if (count_ptr)
1911 arc->count = *count_ptr++;
1912 arc->count_valid = 1;
1913 blk->num_succ--;
1914 arc->dst->num_pred--;
1916 if (prev_dst && prev_dst > arc->dst)
1917 out_of_order = 1;
1918 prev_dst = arc->dst;
1920 if (non_fake_succ == 1)
1922 /* If there is only one non-fake exit, it is an
1923 unconditional branch. */
1924 for (arc = blk->succ; arc; arc = arc->succ_next)
1925 if (!arc->fake)
1927 arc->is_unconditional = 1;
1928 /* If this block is instrumenting a call, it might be
1929 an artificial block. It is not artificial if it has
1930 a non-fallthrough exit, or the destination of this
1931 arc has more than one entry. Mark the destination
1932 block as a return site, if none of those conditions
1933 hold. */
1934 if (blk->is_call_site && arc->fall_through
1935 && arc->dst->pred == arc && !arc->pred_next)
1936 arc->dst->is_call_return = 1;
1940 /* Sort the successor arcs into ascending dst order. profile.c
1941 normally produces arcs in the right order, but sometimes with
1942 one or two out of order. We're not using a particularly
1943 smart sort. */
1944 if (out_of_order)
1946 arc_info *start = blk->succ;
1947 unsigned changes = 1;
1949 while (changes)
1951 arc_info *arc, *arc_p, *arc_n;
1953 changes = 0;
1954 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1956 if (arc->dst > arc_n->dst)
1958 changes = 1;
1959 if (arc_p)
1960 arc_p->succ_next = arc_n;
1961 else
1962 start = arc_n;
1963 arc->succ_next = arc_n->succ_next;
1964 arc_n->succ_next = arc;
1965 arc_p = arc_n;
1967 else
1969 arc_p = arc;
1970 arc = arc_n;
1974 blk->succ = start;
1977 /* Place it on the invalid chain, it will be ignored if that's
1978 wrong. */
1979 blk->invalid_chain = 1;
1980 blk->chain = invalid_blocks;
1981 invalid_blocks = blk;
1984 while (invalid_blocks || valid_blocks)
1986 while ((blk = invalid_blocks))
1988 gcov_type total = 0;
1989 const arc_info *arc;
1991 invalid_blocks = blk->chain;
1992 blk->invalid_chain = 0;
1993 if (!blk->num_succ)
1994 for (arc = blk->succ; arc; arc = arc->succ_next)
1995 total += arc->count;
1996 else if (!blk->num_pred)
1997 for (arc = blk->pred; arc; arc = arc->pred_next)
1998 total += arc->count;
1999 else
2000 continue;
2002 blk->count = total;
2003 blk->count_valid = 1;
2004 blk->chain = valid_blocks;
2005 blk->valid_chain = 1;
2006 valid_blocks = blk;
2008 while ((blk = valid_blocks))
2010 gcov_type total;
2011 arc_info *arc, *inv_arc;
2013 valid_blocks = blk->chain;
2014 blk->valid_chain = 0;
2015 if (blk->num_succ == 1)
2017 block_info *dst;
2019 total = blk->count;
2020 inv_arc = NULL;
2021 for (arc = blk->succ; arc; arc = arc->succ_next)
2023 total -= arc->count;
2024 if (!arc->count_valid)
2025 inv_arc = arc;
2027 dst = inv_arc->dst;
2028 inv_arc->count_valid = 1;
2029 inv_arc->count = total;
2030 blk->num_succ--;
2031 dst->num_pred--;
2032 if (dst->count_valid)
2034 if (dst->num_pred == 1 && !dst->valid_chain)
2036 dst->chain = valid_blocks;
2037 dst->valid_chain = 1;
2038 valid_blocks = dst;
2041 else
2043 if (!dst->num_pred && !dst->invalid_chain)
2045 dst->chain = invalid_blocks;
2046 dst->invalid_chain = 1;
2047 invalid_blocks = dst;
2051 if (blk->num_pred == 1)
2053 block_info *src;
2055 total = blk->count;
2056 inv_arc = NULL;
2057 for (arc = blk->pred; arc; arc = arc->pred_next)
2059 total -= arc->count;
2060 if (!arc->count_valid)
2061 inv_arc = arc;
2063 src = inv_arc->src;
2064 inv_arc->count_valid = 1;
2065 inv_arc->count = total;
2066 blk->num_pred--;
2067 src->num_succ--;
2068 if (src->count_valid)
2070 if (src->num_succ == 1 && !src->valid_chain)
2072 src->chain = valid_blocks;
2073 src->valid_chain = 1;
2074 valid_blocks = src;
2077 else
2079 if (!src->num_succ && !src->invalid_chain)
2081 src->chain = invalid_blocks;
2082 src->invalid_chain = 1;
2083 invalid_blocks = src;
2090 /* If the graph has been correctly solved, every block will have a
2091 valid count. */
2092 for (unsigned i = 0; ix < fn->blocks.size (); i++)
2093 if (!fn->blocks[i].count_valid)
2095 fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
2096 bbg_file_name, fn->name);
2097 break;
2101 /* Mark all the blocks only reachable via an incoming catch. */
2103 static void
2104 find_exception_blocks (function_info *fn)
2106 unsigned ix;
2107 block_info **queue = XALLOCAVEC (block_info *, fn->blocks.size ());
2109 /* First mark all blocks as exceptional. */
2110 for (ix = fn->blocks.size (); ix--;)
2111 fn->blocks[ix].exceptional = 1;
2113 /* Now mark all the blocks reachable via non-fake edges */
2114 queue[0] = &fn->blocks[0];
2115 queue[0]->exceptional = 0;
2116 for (ix = 1; ix;)
2118 block_info *block = queue[--ix];
2119 const arc_info *arc;
2121 for (arc = block->succ; arc; arc = arc->succ_next)
2122 if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
2124 arc->dst->exceptional = 0;
2125 queue[ix++] = arc->dst;
2131 /* Increment totals in COVERAGE according to arc ARC. */
2133 static void
2134 add_branch_counts (coverage_info *coverage, const arc_info *arc)
2136 if (arc->is_call_non_return)
2138 coverage->calls++;
2139 if (arc->src->count)
2140 coverage->calls_executed++;
2142 else if (!arc->is_unconditional)
2144 coverage->branches++;
2145 if (arc->src->count)
2146 coverage->branches_executed++;
2147 if (arc->count)
2148 coverage->branches_taken++;
2152 /* Format COUNT, if flag_human_readable_numbers is set, return it human
2153 readable format. */
2155 static char const *
2156 format_count (gcov_type count)
2158 static char buffer[64];
2159 const char *units = " kMGTPEZY";
2161 if (count < 1000 || !flag_human_readable_numbers)
2163 sprintf (buffer, "%" PRId64, count);
2164 return buffer;
2167 unsigned i;
2168 gcov_type divisor = 1;
2169 for (i = 0; units[i+1]; i++, divisor *= 1000)
2171 if (count + divisor / 2 < 1000 * divisor)
2172 break;
2174 gcov_type r = (count + divisor / 2) / divisor;
2175 sprintf (buffer, "%" PRId64 "%c", r, units[i]);
2176 return buffer;
2179 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
2180 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
2181 If DP is zero, no decimal point is printed. Only print 100% when
2182 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
2183 format TOP. Return pointer to a static string. */
2185 static char const *
2186 format_gcov (gcov_type top, gcov_type bottom, int dp)
2188 static char buffer[20];
2190 /* Handle invalid values that would result in a misleading value. */
2191 if (bottom != 0 && top > bottom && dp >= 0)
2193 sprintf (buffer, "NAN %%");
2194 return buffer;
2197 if (dp >= 0)
2199 float ratio = bottom ? (float)top / bottom : 0;
2200 int ix;
2201 unsigned limit = 100;
2202 unsigned percent;
2204 for (ix = dp; ix--; )
2205 limit *= 10;
2207 percent = (unsigned) (ratio * limit + (float)0.5);
2208 if (percent <= 0 && top)
2209 percent = 1;
2210 else if (percent >= limit && top != bottom)
2211 percent = limit - 1;
2212 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
2213 if (dp)
2215 dp++;
2218 buffer[ix+1] = buffer[ix];
2219 ix--;
2221 while (dp--);
2222 buffer[ix + 1] = '.';
2225 else
2226 return format_count (top);
2228 return buffer;
2231 /* Summary of execution */
2233 static void
2234 executed_summary (unsigned lines, unsigned executed)
2236 if (lines)
2237 fnotice (stdout, "Lines executed:%s of %d\n",
2238 format_gcov (executed, lines, 2), lines);
2239 else
2240 fnotice (stdout, "No executable lines\n");
2243 /* Output summary info for a function or file. */
2245 static void
2246 function_summary (const coverage_info *coverage, const char *title)
2248 fnotice (stdout, "%s '%s'\n", title, coverage->name);
2249 executed_summary (coverage->lines, coverage->lines_executed);
2251 if (flag_branches)
2253 if (coverage->branches)
2255 fnotice (stdout, "Branches executed:%s of %d\n",
2256 format_gcov (coverage->branches_executed,
2257 coverage->branches, 2),
2258 coverage->branches);
2259 fnotice (stdout, "Taken at least once:%s of %d\n",
2260 format_gcov (coverage->branches_taken,
2261 coverage->branches, 2),
2262 coverage->branches);
2264 else
2265 fnotice (stdout, "No branches\n");
2266 if (coverage->calls)
2267 fnotice (stdout, "Calls executed:%s of %d\n",
2268 format_gcov (coverage->calls_executed, coverage->calls, 2),
2269 coverage->calls);
2270 else
2271 fnotice (stdout, "No calls\n");
2275 /* Canonicalize the filename NAME by canonicalizing directory
2276 separators, eliding . components and resolving .. components
2277 appropriately. Always returns a unique string. */
2279 static char *
2280 canonicalize_name (const char *name)
2282 /* The canonical name cannot be longer than the incoming name. */
2283 char *result = XNEWVEC (char, strlen (name) + 1);
2284 const char *base = name, *probe;
2285 char *ptr = result;
2286 char *dd_base;
2287 int slash = 0;
2289 #if HAVE_DOS_BASED_FILE_SYSTEM
2290 if (base[0] && base[1] == ':')
2292 result[0] = base[0];
2293 result[1] = ':';
2294 base += 2;
2295 ptr += 2;
2297 #endif
2298 for (dd_base = ptr; *base; base = probe)
2300 size_t len;
2302 for (probe = base; *probe; probe++)
2303 if (IS_DIR_SEPARATOR (*probe))
2304 break;
2306 len = probe - base;
2307 if (len == 1 && base[0] == '.')
2308 /* Elide a '.' directory */
2310 else if (len == 2 && base[0] == '.' && base[1] == '.')
2312 /* '..', we can only elide it and the previous directory, if
2313 we're not a symlink. */
2314 struct stat ATTRIBUTE_UNUSED buf;
2316 *ptr = 0;
2317 if (dd_base == ptr
2318 #if defined (S_ISLNK)
2319 /* S_ISLNK is not POSIX.1-1996. */
2320 || stat (result, &buf) || S_ISLNK (buf.st_mode)
2321 #endif
2324 /* Cannot elide, or unreadable or a symlink. */
2325 dd_base = ptr + 2 + slash;
2326 goto regular;
2328 while (ptr != dd_base && *ptr != '/')
2329 ptr--;
2330 slash = ptr != result;
2332 else
2334 regular:
2335 /* Regular pathname component. */
2336 if (slash)
2337 *ptr++ = '/';
2338 memcpy (ptr, base, len);
2339 ptr += len;
2340 slash = 1;
2343 for (; IS_DIR_SEPARATOR (*probe); probe++)
2344 continue;
2346 *ptr = 0;
2348 return result;
2351 /* Print hex representation of 16 bytes from SUM and write it to BUFFER. */
2353 static void
2354 md5sum_to_hex (const char *sum, char *buffer)
2356 for (unsigned i = 0; i < 16; i++)
2357 sprintf (buffer + (2 * i), "%02x", (unsigned char)sum[i]);
2360 /* Generate an output file name. INPUT_NAME is the canonicalized main
2361 input file and SRC_NAME is the canonicalized file name.
2362 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
2363 long_output_names we prepend the processed name of the input file
2364 to each output name (except when the current source file is the
2365 input file, so you don't get a double concatenation). The two
2366 components are separated by '##'. With preserve_paths we create a
2367 filename from all path components of the source file, replacing '/'
2368 with '#', and .. with '^', without it we simply take the basename
2369 component. (Remember, the canonicalized name will already have
2370 elided '.' components and converted \\ separators.) */
2372 static char *
2373 make_gcov_file_name (const char *input_name, const char *src_name)
2375 char *ptr;
2376 char *result;
2378 if (flag_long_names && input_name && strcmp (src_name, input_name))
2380 /* Generate the input filename part. */
2381 result = XNEWVEC (char, strlen (input_name) + strlen (src_name) + 10);
2383 ptr = result;
2384 ptr = mangle_name (input_name, ptr);
2385 ptr[0] = ptr[1] = '#';
2386 ptr += 2;
2388 else
2390 result = XNEWVEC (char, strlen (src_name) + 10);
2391 ptr = result;
2394 ptr = mangle_name (src_name, ptr);
2395 strcpy (ptr, ".gcov");
2397 /* When hashing filenames, we shorten them by only using the filename
2398 component and appending a hash of the full (mangled) pathname. */
2399 if (flag_hash_filenames)
2401 md5_ctx ctx;
2402 char md5sum[16];
2403 char md5sum_hex[33];
2405 md5_init_ctx (&ctx);
2406 md5_process_bytes (src_name, strlen (src_name), &ctx);
2407 md5_finish_ctx (&ctx, md5sum);
2408 md5sum_to_hex (md5sum, md5sum_hex);
2409 free (result);
2411 result = XNEWVEC (char, strlen (src_name) + 50);
2412 ptr = result;
2413 ptr = mangle_name (src_name, ptr);
2414 ptr[0] = ptr[1] = '#';
2415 ptr += 2;
2416 memcpy (ptr, md5sum_hex, 32);
2417 ptr += 32;
2418 strcpy (ptr, ".gcov");
2421 return result;
2424 static char *
2425 mangle_name (char const *base, char *ptr)
2427 size_t len;
2429 /* Generate the source filename part. */
2430 if (!flag_preserve_paths)
2432 base = lbasename (base);
2433 len = strlen (base);
2434 memcpy (ptr, base, len);
2435 ptr += len;
2437 else
2439 /* Convert '/' to '#', convert '..' to '^',
2440 convert ':' to '~' on DOS based file system. */
2441 const char *probe;
2443 #if HAVE_DOS_BASED_FILE_SYSTEM
2444 if (base[0] && base[1] == ':')
2446 ptr[0] = base[0];
2447 ptr[1] = '~';
2448 ptr += 2;
2449 base += 2;
2451 #endif
2452 for (; *base; base = probe)
2454 size_t len;
2456 for (probe = base; *probe; probe++)
2457 if (*probe == '/')
2458 break;
2459 len = probe - base;
2460 if (len == 2 && base[0] == '.' && base[1] == '.')
2461 *ptr++ = '^';
2462 else
2464 memcpy (ptr, base, len);
2465 ptr += len;
2467 if (*probe)
2469 *ptr++ = '#';
2470 probe++;
2475 return ptr;
2478 /* Scan through the bb_data for each line in the block, increment
2479 the line number execution count indicated by the execution count of
2480 the appropriate basic block. */
2482 static void
2483 add_line_counts (coverage_info *coverage, function_info *fn)
2485 bool has_any_line = false;
2486 /* Scan each basic block. */
2487 for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
2489 line_info *line = NULL;
2490 block_info *block = &fn->blocks[ix];
2491 if (block->count && ix && ix + 1 != fn->blocks.size ())
2492 fn->blocks_executed++;
2493 for (unsigned i = 0; i < block->locations.size (); i++)
2495 unsigned src_idx = block->locations[i].source_file_idx;
2496 vector<unsigned> &lines = block->locations[i].lines;
2498 block->cycle.arc = NULL;
2499 block->cycle.ident = ~0U;
2501 for (unsigned j = 0; j < lines.size (); j++)
2503 unsigned ln = lines[j];
2505 /* Line belongs to a function that is in a group. */
2506 if (fn->group_line_p (ln, src_idx))
2508 gcc_assert (lines[j] - fn->start_line < fn->lines.size ());
2509 line = &(fn->lines[lines[j] - fn->start_line]);
2510 line->exists = 1;
2511 if (!block->exceptional)
2513 line->unexceptional = 1;
2514 if (block->count == 0)
2515 line->has_unexecuted_block = 1;
2517 line->count += block->count;
2519 else
2521 gcc_assert (ln < sources[src_idx].lines.size ());
2522 line = &(sources[src_idx].lines[ln]);
2523 if (coverage)
2525 if (!line->exists)
2526 coverage->lines++;
2527 if (!line->count && block->count)
2528 coverage->lines_executed++;
2530 line->exists = 1;
2531 if (!block->exceptional)
2533 line->unexceptional = 1;
2534 if (block->count == 0)
2535 line->has_unexecuted_block = 1;
2537 line->count += block->count;
2541 has_any_line = true;
2543 if (!ix || ix + 1 == fn->blocks.size ())
2544 /* Entry or exit block. */;
2545 else if (line != NULL)
2547 line->blocks.push_back (block);
2549 if (flag_branches)
2551 arc_info *arc;
2553 for (arc = block->succ; arc; arc = arc->succ_next)
2554 line->branches.push_back (arc);
2560 if (!has_any_line)
2561 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
2564 /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE
2565 is set to true, update source file summary. */
2567 static void accumulate_line_info (line_info *line, source_info *src,
2568 bool add_coverage)
2570 if (add_coverage)
2571 for (vector<arc_info *>::iterator it = line->branches.begin ();
2572 it != line->branches.end (); it++)
2573 add_branch_counts (&src->coverage, *it);
2575 if (!line->blocks.empty ())
2577 /* The user expects the line count to be the number of times
2578 a line has been executed. Simply summing the block count
2579 will give an artificially high number. The Right Thing
2580 is to sum the entry counts to the graph of blocks on this
2581 line, then find the elementary cycles of the local graph
2582 and add the transition counts of those cycles. */
2583 gcov_type count = 0;
2585 /* Cycle detection. */
2586 for (vector<block_info *>::iterator it = line->blocks.begin ();
2587 it != line->blocks.end (); it++)
2589 for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next)
2590 if (!line->has_block (arc->src))
2591 count += arc->count;
2592 for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next)
2593 arc->cs_count = arc->count;
2596 /* Now, add the count of loops entirely on this line. */
2597 count += get_cycles_count (*line);
2598 line->count = count;
2601 if (line->exists && add_coverage)
2603 src->coverage.lines++;
2604 if (line->count)
2605 src->coverage.lines_executed++;
2609 /* Accumulate the line counts of a file. */
2611 static void
2612 accumulate_line_counts (source_info *src)
2614 /* First work on group functions. */
2615 for (vector<function_info *>::iterator it = src->functions.begin ();
2616 it != src->functions.end (); it++)
2618 function_info *fn = *it;
2620 if (fn->src != src->index || !fn->is_group)
2621 continue;
2623 for (vector<line_info>::iterator it2 = fn->lines.begin ();
2624 it2 != fn->lines.end (); it2++)
2626 line_info *line = &(*it2);
2627 accumulate_line_info (line, src, false);
2631 /* Work on global lines that line in source file SRC. */
2632 for (vector<line_info>::iterator it = src->lines.begin ();
2633 it != src->lines.end (); it++)
2634 accumulate_line_info (&(*it), src, true);
2636 /* If not using intermediate mode, sum lines of group functions and
2637 add them to lines that live in a source file. */
2638 if (!flag_intermediate_format)
2639 for (vector<function_info *>::iterator it = src->functions.begin ();
2640 it != src->functions.end (); it++)
2642 function_info *fn = *it;
2644 if (fn->src != src->index || !fn->is_group)
2645 continue;
2647 for (unsigned i = 0; i < fn->lines.size (); i++)
2649 line_info *fn_line = &fn->lines[i];
2650 if (fn_line->exists)
2652 unsigned ln = fn->start_line + i;
2653 line_info *src_line = &src->lines[ln];
2655 if (!src_line->exists)
2656 src->coverage.lines++;
2657 if (!src_line->count && fn_line->count)
2658 src->coverage.lines_executed++;
2660 src_line->count += fn_line->count;
2661 src_line->exists = 1;
2663 if (fn_line->has_unexecuted_block)
2664 src_line->has_unexecuted_block = 1;
2666 if (fn_line->unexceptional)
2667 src_line->unexceptional = 1;
2673 /* Output information about ARC number IX. Returns nonzero if
2674 anything is output. */
2676 static int
2677 output_branch_count (FILE *gcov_file, int ix, const arc_info *arc)
2679 if (arc->is_call_non_return)
2681 if (arc->src->count)
2683 fnotice (gcov_file, "call %2d returned %s\n", ix,
2684 format_gcov (arc->src->count - arc->count,
2685 arc->src->count, -flag_counts));
2687 else
2688 fnotice (gcov_file, "call %2d never executed\n", ix);
2690 else if (!arc->is_unconditional)
2692 if (arc->src->count)
2693 fnotice (gcov_file, "branch %2d taken %s%s", ix,
2694 format_gcov (arc->count, arc->src->count, -flag_counts),
2695 arc->fall_through ? " (fallthrough)"
2696 : arc->is_throw ? " (throw)" : "");
2697 else
2698 fnotice (gcov_file, "branch %2d never executed", ix);
2700 if (flag_verbose)
2701 fnotice (gcov_file, " (BB %d)", arc->dst->id);
2703 fnotice (gcov_file, "\n");
2705 else if (flag_unconditional && !arc->dst->is_call_return)
2707 if (arc->src->count)
2708 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
2709 format_gcov (arc->count, arc->src->count, -flag_counts));
2710 else
2711 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
2713 else
2714 return 0;
2715 return 1;
2718 static const char *
2719 read_line (FILE *file)
2721 static char *string;
2722 static size_t string_len;
2723 size_t pos = 0;
2724 char *ptr;
2726 if (!string_len)
2728 string_len = 200;
2729 string = XNEWVEC (char, string_len);
2732 while ((ptr = fgets (string + pos, string_len - pos, file)))
2734 size_t len = strlen (string + pos);
2736 if (len && string[pos + len - 1] == '\n')
2738 string[pos + len - 1] = 0;
2739 return string;
2741 pos += len;
2742 /* If the file contains NUL characters or an incomplete
2743 last line, which can happen more than once in one run,
2744 we have to avoid doubling the STRING_LEN unnecessarily. */
2745 if (pos > string_len / 2)
2747 string_len *= 2;
2748 string = XRESIZEVEC (char, string, string_len);
2752 return pos ? string : NULL;
2755 /* Pad string S with spaces from left to have total width equal to 9. */
2757 static void
2758 pad_count_string (string &s)
2760 if (s.size () < 9)
2761 s.insert (0, 9 - s.size (), ' ');
2764 /* Print GCOV line beginning to F stream. If EXISTS is set to true, the
2765 line exists in source file. UNEXCEPTIONAL indicated that it's not in
2766 an exceptional statement. The output is printed for LINE_NUM of given
2767 COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
2768 used to indicate non-executed blocks. */
2770 static void
2771 output_line_beginning (FILE *f, bool exists, bool unexceptional,
2772 bool has_unexecuted_block,
2773 gcov_type count, unsigned line_num,
2774 const char *exceptional_string,
2775 const char *unexceptional_string)
2777 string s;
2778 if (exists)
2780 if (count > 0)
2782 s = format_gcov (count, 0, -1);
2783 if (has_unexecuted_block
2784 && bbg_supports_has_unexecuted_blocks)
2786 if (flag_use_colors)
2788 pad_count_string (s);
2789 s.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
2790 COLOR_SEPARATOR COLOR_FG_WHITE));
2791 s += SGR_RESET;
2793 else
2794 s += "*";
2796 pad_count_string (s);
2798 else
2800 if (flag_use_colors)
2802 s = "0";
2803 pad_count_string (s);
2804 if (unexceptional)
2805 s.insert (0, SGR_SEQ (COLOR_BG_RED
2806 COLOR_SEPARATOR COLOR_FG_WHITE));
2807 else
2808 s.insert (0, SGR_SEQ (COLOR_BG_CYAN
2809 COLOR_SEPARATOR COLOR_FG_WHITE));
2810 s += SGR_RESET;
2812 else
2814 s = unexceptional ? unexceptional_string : exceptional_string;
2815 pad_count_string (s);
2819 else
2821 s = "-";
2822 pad_count_string (s);
2825 fprintf (f, "%s:%5u", s.c_str (), line_num);
2828 static void
2829 print_source_line (FILE *f, const vector<const char *> &source_lines,
2830 unsigned line)
2832 gcc_assert (line >= 1);
2833 gcc_assert (line <= source_lines.size ());
2835 fprintf (f, ":%s\n", source_lines[line - 1]);
2838 /* Output line details for LINE and print it to F file. LINE lives on
2839 LINE_NUM. */
2841 static void
2842 output_line_details (FILE *f, const line_info *line, unsigned line_num)
2844 if (flag_all_blocks)
2846 arc_info *arc;
2847 int ix, jx;
2849 ix = jx = 0;
2850 for (vector<block_info *>::const_iterator it = line->blocks.begin ();
2851 it != line->blocks.end (); it++)
2853 if (!(*it)->is_call_return)
2855 output_line_beginning (f, line->exists,
2856 (*it)->exceptional, false,
2857 (*it)->count, line_num,
2858 "%%%%%", "$$$$$");
2859 fprintf (f, "-block %2d", ix++);
2860 if (flag_verbose)
2861 fprintf (f, " (BB %u)", (*it)->id);
2862 fprintf (f, "\n");
2864 if (flag_branches)
2865 for (arc = (*it)->succ; arc; arc = arc->succ_next)
2866 jx += output_branch_count (f, jx, arc);
2869 else if (flag_branches)
2871 int ix;
2873 ix = 0;
2874 for (vector<arc_info *>::const_iterator it = line->branches.begin ();
2875 it != line->branches.end (); it++)
2876 ix += output_branch_count (f, ix, (*it));
2880 /* Output detail statistics about function FN to file F. */
2882 static void
2883 output_function_details (FILE *f, const function_info *fn)
2885 if (!flag_branches)
2886 return;
2888 arc_info *arc = fn->blocks[EXIT_BLOCK].pred;
2889 gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
2890 gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
2892 for (; arc; arc = arc->pred_next)
2893 if (arc->fake)
2894 return_count -= arc->count;
2896 fprintf (f, "function %s",
2897 flag_demangled_names ? fn->demangled_name : fn->name);
2898 fprintf (f, " called %s",
2899 format_gcov (called_count, 0, -1));
2900 fprintf (f, " returned %s",
2901 format_gcov (return_count, called_count, 0));
2902 fprintf (f, " blocks executed %s",
2903 format_gcov (fn->blocks_executed, fn->blocks.size () - 2,
2904 0));
2905 fprintf (f, "\n");
2908 /* Read in the source file one line at a time, and output that line to
2909 the gcov file preceded by its execution count and other
2910 information. */
2912 static void
2913 output_lines (FILE *gcov_file, const source_info *src)
2915 #define DEFAULT_LINE_START " -: 0:"
2916 #define FN_SEPARATOR "------------------\n"
2918 FILE *source_file;
2919 const char *retval;
2921 fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
2922 if (!multiple_files)
2924 fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
2925 fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
2926 no_data_file ? "-" : da_file_name);
2927 fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
2929 fprintf (gcov_file, DEFAULT_LINE_START "Programs:%u\n", program_count);
2931 source_file = fopen (src->name, "r");
2932 if (!source_file)
2933 fnotice (stderr, "Cannot open source file %s\n", src->name);
2934 else if (src->file_time == 0)
2935 fprintf (gcov_file, DEFAULT_LINE_START "Source is newer than graph\n");
2937 vector<const char *> source_lines;
2938 if (source_file)
2939 while ((retval = read_line (source_file)) != NULL)
2940 source_lines.push_back (xstrdup (retval));
2942 unsigned line_start_group = 0;
2943 vector<function_info *> fns;
2945 for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
2947 if (line_num >= src->lines.size ())
2949 fprintf (gcov_file, "%9s:%5u", "-", line_num);
2950 print_source_line (gcov_file, source_lines, line_num);
2951 continue;
2954 const line_info *line = &src->lines[line_num];
2956 if (line_start_group == 0)
2958 fns = src->get_functions_at_location (line_num);
2959 if (fns.size () > 1)
2960 line_start_group = fns[0]->end_line;
2961 else if (fns.size () == 1)
2963 function_info *fn = fns[0];
2964 output_function_details (gcov_file, fn);
2968 /* For lines which don't exist in the .bb file, print '-' before
2969 the source line. For lines which exist but were never
2970 executed, print '#####' or '=====' before the source line.
2971 Otherwise, print the execution count before the source line.
2972 There are 16 spaces of indentation added before the source
2973 line so that tabs won't be messed up. */
2974 output_line_beginning (gcov_file, line->exists, line->unexceptional,
2975 line->has_unexecuted_block, line->count,
2976 line_num, "=====", "#####");
2978 print_source_line (gcov_file, source_lines, line_num);
2979 output_line_details (gcov_file, line, line_num);
2981 if (line_start_group == line_num)
2983 for (vector<function_info *>::iterator it = fns.begin ();
2984 it != fns.end (); it++)
2986 function_info *fn = *it;
2987 vector<line_info> &lines = fn->lines;
2989 fprintf (gcov_file, FN_SEPARATOR);
2991 string fn_name
2992 = flag_demangled_names ? fn->demangled_name : fn->name;
2994 if (flag_use_colors)
2996 fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN));
2997 fn_name += SGR_RESET;
3000 fprintf (gcov_file, "%s:\n", fn_name.c_str ());
3002 output_function_details (gcov_file, fn);
3004 /* Print all lines covered by the function. */
3005 for (unsigned i = 0; i < lines.size (); i++)
3007 line_info *line = &lines[i];
3008 unsigned l = fn->start_line + i;
3010 /* For lines which don't exist in the .bb file, print '-'
3011 before the source line. For lines which exist but
3012 were never executed, print '#####' or '=====' before
3013 the source line. Otherwise, print the execution count
3014 before the source line.
3015 There are 16 spaces of indentation added before the source
3016 line so that tabs won't be messed up. */
3017 output_line_beginning (gcov_file, line->exists,
3018 line->unexceptional,
3019 line->has_unexecuted_block,
3020 line->count,
3021 l, "=====", "#####");
3023 print_source_line (gcov_file, source_lines, l);
3024 output_line_details (gcov_file, line, l);
3028 fprintf (gcov_file, FN_SEPARATOR);
3029 line_start_group = 0;
3033 if (source_file)
3034 fclose (source_file);