xref: /netbsd-src/external/gpl3/gcc/dist/gcc/gcov.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2    source file.
3    Copyright (C) 1990-2022 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>
7 
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.
12 
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.
17 
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/>.  */
21 
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.  */
26 
27 /* ??? Should have an option to print the number of basic blocks, and the
28    percent of them that are covered.  */
29 
30 /* Need an option to show individual block counts, and show
31    probabilities of fall through arcs.  */
32 
33 #include "config.h"
34 #define INCLUDE_ALGORITHM
35 #define INCLUDE_VECTOR
36 #define INCLUDE_STRING
37 #define INCLUDE_MAP
38 #define INCLUDE_SET
39 #include "system.h"
40 #include "coretypes.h"
41 #include "tm.h"
42 #include "intl.h"
43 #include "diagnostic.h"
44 #include "version.h"
45 #include "demangle.h"
46 #include "color-macros.h"
47 #include "pretty-print.h"
48 #include "json.h"
49 
50 #include <zlib.h>
51 #include <getopt.h>
52 
53 #include "md5.h"
54 
55 using namespace std;
56 
57 #define IN_GCOV 1
58 #include "gcov-io.h"
59 #include "gcov-io.cc"
60 
61 /* The gcno file is generated by -ftest-coverage option. The gcda file is
62    generated by a program compiled with -fprofile-arcs. Their formats
63    are documented in gcov-io.h.  */
64 
65 /* The functions in this file for creating and solution program flow graphs
66    are very similar to functions in the gcc source file profile.cc.  In
67    some places we make use of the knowledge of how profile.cc works to
68    select particular algorithms here.  */
69 
70 /* The code validates that the profile information read in corresponds
71    to the code currently being compiled.  Rather than checking for
72    identical files, the code below compares a checksum on the CFG
73    (based on the order of basic blocks and the arcs in the CFG).  If
74    the CFG checksum in the gcda file match the CFG checksum in the
75    gcno file, the profile data will be used.  */
76 
77 /* This is the size of the buffer used to read in source file lines.  */
78 
79 class function_info;
80 class block_info;
81 class source_info;
82 
83 /* Describes an arc between two basic blocks.  */
84 
85 struct arc_info
86 {
87   /* source and destination blocks.  */
88   class block_info *src;
89   class block_info *dst;
90 
91   /* transition counts.  */
92   gcov_type count;
93   /* used in cycle search, so that we do not clobber original counts.  */
94   gcov_type cs_count;
95 
96   unsigned int count_valid : 1;
97   unsigned int on_tree : 1;
98   unsigned int fake : 1;
99   unsigned int fall_through : 1;
100 
101   /* Arc to a catch handler.  */
102   unsigned int is_throw : 1;
103 
104   /* Arc is for a function that abnormally returns.  */
105   unsigned int is_call_non_return : 1;
106 
107   /* Arc is for catch/setjmp.  */
108   unsigned int is_nonlocal_return : 1;
109 
110   /* Is an unconditional branch.  */
111   unsigned int is_unconditional : 1;
112 
113   /* Loop making arc.  */
114   unsigned int cycle : 1;
115 
116   /* Links to next arc on src and dst lists.  */
117   struct arc_info *succ_next;
118   struct arc_info *pred_next;
119 };
120 
121 /* Describes which locations (lines and files) are associated with
122    a basic block.  */
123 
124 class block_location_info
125 {
126 public:
block_location_info(unsigned _source_file_idx)127   block_location_info (unsigned _source_file_idx):
128     source_file_idx (_source_file_idx)
129   {}
130 
131   unsigned source_file_idx;
132   vector<unsigned> lines;
133 };
134 
135 /* Describes a basic block. Contains lists of arcs to successor and
136    predecessor blocks.  */
137 
138 class block_info
139 {
140 public:
141   /* Constructor.  */
142   block_info ();
143 
144   /* Chain of exit and entry arcs.  */
145   arc_info *succ;
146   arc_info *pred;
147 
148   /* Number of unprocessed exit and entry arcs.  */
149   gcov_type num_succ;
150   gcov_type num_pred;
151 
152   unsigned id;
153 
154   /* Block execution count.  */
155   gcov_type count;
156   unsigned count_valid : 1;
157   unsigned valid_chain : 1;
158   unsigned invalid_chain : 1;
159   unsigned exceptional : 1;
160 
161   /* Block is a call instrumenting site.  */
162   unsigned is_call_site : 1; /* Does the call.  */
163   unsigned is_call_return : 1; /* Is the return.  */
164 
165   /* Block is a landing pad for longjmp or throw.  */
166   unsigned is_nonlocal_return : 1;
167 
168   vector<block_location_info> locations;
169 
170   struct
171   {
172     /* Single line graph cycle workspace.  Used for all-blocks
173        mode.  */
174     arc_info *arc;
175     unsigned ident;
176   } cycle; /* Used in all-blocks mode, after blocks are linked onto
177 	     lines.  */
178 
179   /* Temporary chain for solving graph, and for chaining blocks on one
180      line.  */
181   class block_info *chain;
182 
183 };
184 
block_info()185 block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0),
186   id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
187   exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
188   locations (), chain (NULL)
189 {
190   cycle.arc = NULL;
191 }
192 
193 /* Describes a single line of source.  Contains a chain of basic blocks
194    with code on it.  */
195 
196 class line_info
197 {
198 public:
199   /* Default constructor.  */
200   line_info ();
201 
202   /* Return true when NEEDLE is one of basic blocks the line belongs to.  */
203   bool has_block (block_info *needle);
204 
205   /* Execution count.  */
206   gcov_type count;
207 
208   /* Branches from blocks that end on this line.  */
209   vector<arc_info *> branches;
210 
211   /* blocks which start on this line.  Used in all-blocks mode.  */
212   vector<block_info *> blocks;
213 
214   unsigned exists : 1;
215   unsigned unexceptional : 1;
216   unsigned has_unexecuted_block : 1;
217 };
218 
line_info()219 line_info::line_info (): count (0), branches (), blocks (), exists (false),
220   unexceptional (0), has_unexecuted_block (0)
221 {
222 }
223 
224 bool
has_block(block_info * needle)225 line_info::has_block (block_info *needle)
226 {
227   return std::find (blocks.begin (), blocks.end (), needle) != blocks.end ();
228 }
229 
230 /* Output demangled function names.  */
231 
232 static int flag_demangled_names = 0;
233 
234 /* Describes a single function. Contains an array of basic blocks.  */
235 
236 class function_info
237 {
238 public:
239   function_info ();
240   ~function_info ();
241 
242   /* Return true when line N belongs to the function in source file SRC_IDX.
243      The line must be defined in body of the function, can't be inlined.  */
244   bool group_line_p (unsigned n, unsigned src_idx);
245 
246   /* Function filter based on function_info::artificial variable.  */
247 
248   static inline bool
is_artificial(function_info * fn)249   is_artificial (function_info *fn)
250   {
251     return fn->artificial;
252   }
253 
254   /* Name of function.  */
255   char *m_name;
256   char *m_demangled_name;
257   unsigned ident;
258   unsigned lineno_checksum;
259   unsigned cfg_checksum;
260 
261   /* The graph contains at least one fake incoming edge.  */
262   unsigned has_catch : 1;
263 
264   /* True when the function is artificial and does not exist
265      in a source file.  */
266   unsigned artificial : 1;
267 
268   /* True when multiple functions start at a line in a source file.  */
269   unsigned is_group : 1;
270 
271   /* Array of basic blocks.  Like in GCC, the entry block is
272      at blocks[0] and the exit block is at blocks[1].  */
273 #define ENTRY_BLOCK (0)
274 #define EXIT_BLOCK (1)
275   vector<block_info> blocks;
276   unsigned blocks_executed;
277 
278   /* Raw arc coverage counts.  */
279   vector<gcov_type> counts;
280 
281   /* First line number.  */
282   unsigned start_line;
283 
284   /* First line column.  */
285   unsigned start_column;
286 
287   /* Last line number.  */
288   unsigned end_line;
289 
290   /* Last line column.  */
291   unsigned end_column;
292 
293   /* Index of source file where the function is defined.  */
294   unsigned src;
295 
296   /* Vector of line information (used only for group functions).  */
297   vector<line_info> lines;
298 
299   /* Next function.  */
300   class function_info *next;
301 
302   /*  Get demangled name of a function.  The demangled name
303       is converted when it is used for the first time.  */
get_demangled_name()304   char *get_demangled_name ()
305   {
306     if (m_demangled_name == NULL)
307       {
308 	m_demangled_name = cplus_demangle (m_name, DMGL_PARAMS);
309 	if (!m_demangled_name)
310 	  m_demangled_name = m_name;
311       }
312 
313     return m_demangled_name;
314   }
315 
316   /* Get name of the function based on flag_demangled_names.  */
get_name()317   char *get_name ()
318   {
319     return flag_demangled_names ? get_demangled_name () : m_name;
320   }
321 
322   /* Return number of basic blocks (without entry and exit block).  */
get_block_count()323   unsigned get_block_count ()
324   {
325     return blocks.size () - 2;
326   }
327 };
328 
329 /* Function info comparer that will sort functions according to starting
330    line.  */
331 
332 struct function_line_start_cmp
333 {
operator ()function_line_start_cmp334   inline bool operator() (const function_info *lhs,
335 			  const function_info *rhs)
336     {
337       return (lhs->start_line == rhs->start_line
338 	      ? lhs->start_column < rhs->start_column
339 	      : lhs->start_line < rhs->start_line);
340     }
341 };
342 
343 /* Describes coverage of a file or function.  */
344 
345 struct coverage_info
346 {
347   int lines;
348   int lines_executed;
349 
350   int branches;
351   int branches_executed;
352   int branches_taken;
353 
354   int calls;
355   int calls_executed;
356 
357   char *name;
358 };
359 
360 /* Describes a file mentioned in the block graph.  Contains an array
361    of line info.  */
362 
363 class source_info
364 {
365 public:
366   /* Default constructor.  */
367   source_info ();
368 
369   vector<function_info *> *get_functions_at_location (unsigned line_num) const;
370 
371   /* Register a new function.  */
372   void add_function (function_info *fn);
373 
374   /* Debug the source file.  */
375   void debug ();
376 
377   /* Index of the source_info in sources vector.  */
378   unsigned index;
379 
380   /* Canonical name of source file.  */
381   char *name;
382   time_t file_time;
383 
384   /* Vector of line information.  */
385   vector<line_info> lines;
386 
387   coverage_info coverage;
388 
389   /* Maximum line count in the source file.  */
390   unsigned int maximum_count;
391 
392   /* Functions in this source file.  These are in ascending line
393      number order.  */
394   vector<function_info *> functions;
395 
396   /* Line number to functions map.  */
397   vector<vector<function_info *> *> line_to_function_map;
398 };
399 
source_info()400 source_info::source_info (): index (0), name (NULL), file_time (),
401   lines (), coverage (), maximum_count (0), functions ()
402 {
403 }
404 
405 /* Register a new function.  */
406 void
add_function(function_info * fn)407 source_info::add_function (function_info *fn)
408 {
409   functions.push_back (fn);
410 
411   if (fn->start_line >= line_to_function_map.size ())
412     line_to_function_map.resize (fn->start_line + 1);
413 
414   vector<function_info *> **slot = &line_to_function_map[fn->start_line];
415   if (*slot == NULL)
416     *slot = new vector<function_info *> ();
417 
418   (*slot)->push_back (fn);
419 }
420 
421 vector<function_info *> *
get_functions_at_location(unsigned line_num) const422 source_info::get_functions_at_location (unsigned line_num) const
423 {
424   if (line_num >= line_to_function_map.size ())
425     return NULL;
426 
427   vector<function_info *> *slot = line_to_function_map[line_num];
428   if (slot != NULL)
429     std::sort (slot->begin (), slot->end (), function_line_start_cmp ());
430 
431   return slot;
432 }
433 
debug()434 void source_info::debug ()
435 {
436   fprintf (stderr, "source_info: %s\n", name);
437   for (vector<function_info *>::iterator it = functions.begin ();
438        it != functions.end (); it++)
439     {
440       function_info *fn = *it;
441       fprintf (stderr, "  function_info: %s\n", fn->get_name ());
442       for (vector<block_info>::iterator bit = fn->blocks.begin ();
443 	   bit != fn->blocks.end (); bit++)
444 	{
445 	  fprintf (stderr, "    block_info id=%d, count=%" PRId64 " \n",
446 		   bit->id, bit->count);
447 	}
448     }
449 
450   for (unsigned lineno = 1; lineno < lines.size (); ++lineno)
451     {
452       line_info &line = lines[lineno];
453       fprintf (stderr, "  line_info=%d, count=%" PRId64 "\n", lineno, line.count);
454     }
455 
456   fprintf (stderr, "\n");
457 }
458 
459 class name_map
460 {
461 public:
name_map()462   name_map ()
463   {
464   }
465 
name_map(char * _name,unsigned _src)466   name_map (char *_name, unsigned _src): name (_name), src (_src)
467   {
468   }
469 
operator ==(const name_map & rhs) const470   bool operator== (const name_map &rhs) const
471   {
472 #if HAVE_DOS_BASED_FILE_SYSTEM
473     return strcasecmp (this->name, rhs.name) == 0;
474 #else
475     return strcmp (this->name, rhs.name) == 0;
476 #endif
477   }
478 
operator <(const name_map & rhs) const479   bool operator< (const name_map &rhs) const
480   {
481 #if HAVE_DOS_BASED_FILE_SYSTEM
482     return strcasecmp (this->name, rhs.name) < 0;
483 #else
484     return strcmp (this->name, rhs.name) < 0;
485 #endif
486   }
487 
488   const char *name;  /* Source file name */
489   unsigned src;  /* Source file */
490 };
491 
492 /* Vector of all functions.  */
493 static vector<function_info *> functions;
494 
495 /* Function ident to function_info * map.  */
496 static map<unsigned, function_info *> ident_to_fn;
497 
498 /* Vector of source files.  */
499 static vector<source_info> sources;
500 
501 /* Mapping of file names to sources */
502 static vector<name_map> names;
503 
504 /* Record all processed files in order to warn about
505    a file being read multiple times.  */
506 static vector<char *> processed_files;
507 
508 /* This holds data summary information.  */
509 
510 static unsigned object_runs;
511 
512 static unsigned total_lines;
513 static unsigned total_executed;
514 
515 /* Modification time of graph file.  */
516 
517 static time_t bbg_file_time;
518 
519 /* Name of the notes (gcno) output file.  The "bbg" prefix is for
520    historical reasons, when the notes file contained only the
521    basic block graph notes.  */
522 
523 static char *bbg_file_name;
524 
525 /* Stamp of the bbg file */
526 static unsigned bbg_stamp;
527 
528 /* Supports has_unexecuted_blocks functionality.  */
529 static unsigned bbg_supports_has_unexecuted_blocks;
530 
531 /* Working directory in which a TU was compiled.  */
532 static const char *bbg_cwd;
533 
534 /* Name and file pointer of the input file for the count data (gcda).  */
535 
536 static char *da_file_name;
537 
538 /* Data file is missing.  */
539 
540 static int no_data_file;
541 
542 /* If there is several input files, compute and display results after
543    reading all data files.  This way if two or more gcda file refer to
544    the same source file (eg inline subprograms in a .h file), the
545    counts are added.  */
546 
547 static int multiple_files = 0;
548 
549 /* Output branch probabilities.  */
550 
551 static int flag_branches = 0;
552 
553 /* Show unconditional branches too.  */
554 static int flag_unconditional = 0;
555 
556 /* Output a gcov file if this is true.  This is on by default, and can
557    be turned off by the -n option.  */
558 
559 static int flag_gcov_file = 1;
560 
561 /* Output to stdout instead to a gcov file.  */
562 
563 static int flag_use_stdout = 0;
564 
565 /* Output progress indication if this is true.  This is off by default
566    and can be turned on by the -d option.  */
567 
568 static int flag_display_progress = 0;
569 
570 /* Output *.gcov file in JSON intermediate format used by consumers.  */
571 
572 static int flag_json_format = 0;
573 
574 /* For included files, make the gcov output file name include the name
575    of the input source file.  For example, if x.h is included in a.c,
576    then the output file name is a.c##x.h.gcov instead of x.h.gcov.  */
577 
578 static int flag_long_names = 0;
579 
580 /* For situations when a long name can potentially hit filesystem path limit,
581    let's calculate md5sum of the path and append it to a file name.  */
582 
583 static int flag_hash_filenames = 0;
584 
585 /* Print verbose informations.  */
586 
587 static int flag_verbose = 0;
588 
589 /* Print colored output.  */
590 
591 static int flag_use_colors = 0;
592 
593 /* Use perf-like colors to indicate hot lines.  */
594 
595 static int flag_use_hotness_colors = 0;
596 
597 /* Output count information for every basic block, not merely those
598    that contain line number information.  */
599 
600 static int flag_all_blocks = 0;
601 
602 /* Output human readable numbers.  */
603 
604 static int flag_human_readable_numbers = 0;
605 
606 /* Output summary info for each function.  */
607 
608 static int flag_function_summary = 0;
609 
610 /* Print debugging dumps.  */
611 
612 static int flag_debug = 0;
613 
614 /* Object directory file prefix.  This is the directory/file where the
615    graph and data files are looked for, if nonzero.  */
616 
617 static char *object_directory = 0;
618 
619 /* Source directory prefix.  This is removed from source pathnames
620    that match, when generating the output file name.  */
621 
622 static char *source_prefix = 0;
623 static size_t source_length = 0;
624 
625 /* Only show data for sources with relative pathnames.  Absolute ones
626    usually indicate a system header file, which although it may
627    contain inline functions, is usually uninteresting.  */
628 static int flag_relative_only = 0;
629 
630 /* Preserve all pathname components. Needed when object files and
631    source files are in subdirectories. '/' is mangled as '#', '.' is
632    elided and '..' mangled to '^'.  */
633 
634 static int flag_preserve_paths = 0;
635 
636 /* Output the number of times a branch was taken as opposed to the percentage
637    of times it was taken.  */
638 
639 static int flag_counts = 0;
640 
641 /* Return code of the tool invocation.  */
642 static int return_code = 0;
643 
644 /* Forward declarations.  */
645 static int process_args (int, char **);
646 static void print_usage (int) ATTRIBUTE_NORETURN;
647 static void print_version (void) ATTRIBUTE_NORETURN;
648 static void process_file (const char *);
649 static void process_all_functions (void);
650 static void generate_results (const char *);
651 static void create_file_names (const char *);
652 static char *canonicalize_name (const char *);
653 static unsigned find_source (const char *);
654 static void read_graph_file (void);
655 static int read_count_file (void);
656 static void solve_flow_graph (function_info *);
657 static void find_exception_blocks (function_info *);
658 static void add_branch_counts (coverage_info *, const arc_info *);
659 static void add_line_counts (coverage_info *, function_info *);
660 static void executed_summary (unsigned, unsigned);
661 static void function_summary (const coverage_info *);
662 static void file_summary (const coverage_info *);
663 static const char *format_gcov (gcov_type, gcov_type, int);
664 static void accumulate_line_counts (source_info *);
665 static void output_gcov_file (const char *, source_info *);
666 static int output_branch_count (FILE *, int, const arc_info *);
667 static void output_lines (FILE *, const source_info *);
668 static string make_gcov_file_name (const char *, const char *);
669 static char *mangle_name (const char *);
670 static void release_structures (void);
671 extern int main (int, char **);
672 
function_info()673 function_info::function_info (): m_name (NULL), m_demangled_name (NULL),
674   ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
675   artificial (0), is_group (0),
676   blocks (), blocks_executed (0), counts (),
677   start_line (0), start_column (0), end_line (0), end_column (0),
678   src (0), lines (), next (NULL)
679 {
680 }
681 
~function_info()682 function_info::~function_info ()
683 {
684   for (int i = blocks.size () - 1; i >= 0; i--)
685     {
686       arc_info *arc, *arc_n;
687 
688       for (arc = blocks[i].succ; arc; arc = arc_n)
689 	{
690 	  arc_n = arc->succ_next;
691 	  free (arc);
692 	}
693     }
694   if (m_demangled_name != m_name)
695     free (m_demangled_name);
696   free (m_name);
697 }
698 
group_line_p(unsigned n,unsigned src_idx)699 bool function_info::group_line_p (unsigned n, unsigned src_idx)
700 {
701   return is_group && src == src_idx && start_line <= n && n <= end_line;
702 }
703 
704 /* Cycle detection!
705    There are a bajillion algorithms that do this.  Boost's function is named
706    hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
707    "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
708    (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
709 
710    The basic algorithm is simple: effectively, we're finding all simple paths
711    in a subgraph (that shrinks every iteration).  Duplicates are filtered by
712    "blocking" a path when a node is added to the path (this also prevents non-
713    simple paths)--the node is unblocked only when it participates in a cycle.
714    */
715 
716 typedef vector<arc_info *> arc_vector_t;
717 typedef vector<const block_info *> block_vector_t;
718 
719 /* Handle cycle identified by EDGES, where the function finds minimum cs_count
720    and subtract the value from all counts.  The subtracted value is added
721    to COUNT.  Returns type of loop.  */
722 
723 static void
handle_cycle(const arc_vector_t & edges,int64_t & count)724 handle_cycle (const arc_vector_t &edges, int64_t &count)
725 {
726   /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
727      that amount.  */
728   int64_t cycle_count = INTTYPE_MAXIMUM (int64_t);
729   for (unsigned i = 0; i < edges.size (); i++)
730     {
731       int64_t ecount = edges[i]->cs_count;
732       if (cycle_count > ecount)
733 	cycle_count = ecount;
734     }
735   count += cycle_count;
736   for (unsigned i = 0; i < edges.size (); i++)
737     edges[i]->cs_count -= cycle_count;
738 
739   gcc_assert (cycle_count > 0);
740 }
741 
742 /* Unblock a block U from BLOCKED.  Apart from that, iterate all blocks
743    blocked by U in BLOCK_LISTS.  */
744 
745 static void
unblock(const block_info * u,block_vector_t & blocked,vector<block_vector_t> & block_lists)746 unblock (const block_info *u, block_vector_t &blocked,
747 	 vector<block_vector_t > &block_lists)
748 {
749   block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u);
750   if (it == blocked.end ())
751     return;
752 
753   unsigned index = it - blocked.begin ();
754   blocked.erase (it);
755 
756   block_vector_t to_unblock (block_lists[index]);
757 
758   block_lists.erase (block_lists.begin () + index);
759 
760   for (block_vector_t::iterator it = to_unblock.begin ();
761        it != to_unblock.end (); it++)
762     unblock (*it, blocked, block_lists);
763 }
764 
765 /* Return true when PATH contains a zero cycle arc count.  */
766 
767 static bool
path_contains_zero_or_negative_cycle_arc(arc_vector_t & path)768 path_contains_zero_or_negative_cycle_arc (arc_vector_t &path)
769 {
770   for (unsigned i = 0; i < path.size (); i++)
771     if (path[i]->cs_count <= 0)
772       return true;
773   return false;
774 }
775 
776 /* Find circuit going to block V, PATH is provisional seen cycle.
777    BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
778    blocked by a block.  COUNT is accumulated count of the current LINE.
779    Returns what type of loop it contains.  */
780 
781 static bool
circuit(block_info * v,arc_vector_t & path,block_info * start,block_vector_t & blocked,vector<block_vector_t> & block_lists,line_info & linfo,int64_t & count)782 circuit (block_info *v, arc_vector_t &path, block_info *start,
783 	 block_vector_t &blocked, vector<block_vector_t> &block_lists,
784 	 line_info &linfo, int64_t &count)
785 {
786   bool loop_found = false;
787 
788   /* Add v to the block list.  */
789   gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
790   blocked.push_back (v);
791   block_lists.push_back (block_vector_t ());
792 
793   for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
794     {
795       block_info *w = arc->dst;
796       if (w < start
797 	  || arc->cs_count <= 0
798 	  || !linfo.has_block (w))
799 	continue;
800 
801       path.push_back (arc);
802       if (w == start)
803 	{
804 	  /* Cycle has been found.  */
805 	  handle_cycle (path, count);
806 	  loop_found = true;
807 	}
808       else if (!path_contains_zero_or_negative_cycle_arc (path)
809 	       &&  find (blocked.begin (), blocked.end (), w) == blocked.end ())
810 	loop_found |= circuit (w, path, start, blocked, block_lists, linfo,
811 			       count);
812 
813       path.pop_back ();
814     }
815 
816   if (loop_found)
817     unblock (v, blocked, block_lists);
818   else
819     for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
820       {
821 	block_info *w = arc->dst;
822 	if (w < start
823 	    || arc->cs_count <= 0
824 	    || !linfo.has_block (w))
825 	  continue;
826 
827 	size_t index
828 	  = find (blocked.begin (), blocked.end (), w) - blocked.begin ();
829 	gcc_assert (index < blocked.size ());
830 	block_vector_t &list = block_lists[index];
831 	if (find (list.begin (), list.end (), v) == list.end ())
832 	  list.push_back (v);
833       }
834 
835   return loop_found;
836 }
837 
838 /* Find cycles for a LINFO.  */
839 
840 static gcov_type
get_cycles_count(line_info & linfo)841 get_cycles_count (line_info &linfo)
842 {
843   /* Note that this algorithm works even if blocks aren't in sorted order.
844      Each iteration of the circuit detection is completely independent
845      (except for reducing counts, but that shouldn't matter anyways).
846      Therefore, operating on a permuted order (i.e., non-sorted) only
847      has the effect of permuting the output cycles.  */
848 
849   gcov_type count = 0;
850   for (vector<block_info *>::iterator it = linfo.blocks.begin ();
851        it != linfo.blocks.end (); it++)
852     {
853       arc_vector_t path;
854       block_vector_t blocked;
855       vector<block_vector_t > block_lists;
856       circuit (*it, path, *it, blocked, block_lists, linfo, count);
857     }
858 
859   return count;
860 }
861 
862 int
main(int argc,char ** argv)863 main (int argc, char **argv)
864 {
865   int argno;
866   int first_arg;
867   const char *p;
868 
869   p = argv[0] + strlen (argv[0]);
870   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
871     --p;
872   progname = p;
873 
874   xmalloc_set_program_name (progname);
875 
876   /* Unlock the stdio streams.  */
877   unlock_std_streams ();
878 
879   gcc_init_libintl ();
880 
881   diagnostic_initialize (global_dc, 0);
882 
883   /* Handle response files.  */
884   expandargv (&argc, &argv);
885 
886   argno = process_args (argc, argv);
887   if (optind == argc)
888     print_usage (true);
889 
890   if (argc - argno > 1)
891     multiple_files = 1;
892 
893   first_arg = argno;
894 
895   for (; argno != argc; argno++)
896     {
897       if (flag_display_progress)
898 	printf ("Processing file %d out of %d\n", argno - first_arg + 1,
899 		argc - first_arg);
900       process_file (argv[argno]);
901 
902       if (flag_json_format || argno == argc - 1)
903 	{
904 	  process_all_functions ();
905 	  generate_results (argv[argno]);
906 	  release_structures ();
907 	}
908     }
909 
910   if (!flag_use_stdout)
911     executed_summary (total_lines, total_executed);
912 
913   return return_code;
914 }
915 
916 /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
917    otherwise the output of --help.  */
918 
919 static void
print_usage(int error_p)920 print_usage (int error_p)
921 {
922   FILE *file = error_p ? stderr : stdout;
923   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
924 
925   fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
926   fnotice (file, "Print code coverage information.\n\n");
927   fnotice (file, "  -a, --all-blocks                Show information for every basic block\n");
928   fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output\n");
929   fnotice (file, "  -c, --branch-counts             Output counts of branches taken\n\
930                                     rather than percentages\n");
931   fnotice (file, "  -d, --display-progress          Display progress information\n");
932   fnotice (file, "  -D, --debug			    Display debugging dumps\n");
933   fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
934   fnotice (file, "  -h, --help                      Print this help, then exit\n");
935   fnotice (file, "  -j, --json-format               Output JSON intermediate format\n\
936                                     into .gcov.json.gz file\n");
937   fnotice (file, "  -H, --human-readable            Output human readable numbers\n");
938   fnotice (file, "  -k, --use-colors                Emit colored output\n");
939   fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
940                                     source files\n");
941   fnotice (file, "  -m, --demangled-names           Output demangled function names\n");
942   fnotice (file, "  -n, --no-output                 Do not create an output file\n");
943   fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
944   fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
945   fnotice (file, "  -q, --use-hotness-colors        Emit perf-like colored output for hot lines\n");
946   fnotice (file, "  -r, --relative-only             Only show data for relative sources\n");
947   fnotice (file, "  -s, --source-prefix DIR         Source prefix to elide\n");
948   fnotice (file, "  -t, --stdout                    Output to stdout instead of a file\n");
949   fnotice (file, "  -u, --unconditional-branches    Show unconditional branch counts too\n");
950   fnotice (file, "  -v, --version                   Print version number, then exit\n");
951   fnotice (file, "  -w, --verbose                   Print verbose informations\n");
952   fnotice (file, "  -x, --hash-filenames            Hash long pathnames\n");
953   fnotice (file, "\nObsolete options:\n");
954   fnotice (file, "  -i, --json-format               Replaced with -j, --json-format\n");
955   fnotice (file, "  -j, --human-readable            Replaced with -H, --human-readable\n");
956   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
957 	   bug_report_url);
958   exit (status);
959 }
960 
961 /* Print version information and exit.  */
962 
963 static void
print_version(void)964 print_version (void)
965 {
966   fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
967   fprintf (stdout, "Copyright %s 2022 Free Software Foundation, Inc.\n",
968 	   _("(C)"));
969   fnotice (stdout,
970 	   _("This is free software; see the source for copying conditions.  There is NO\n\
971 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
972   exit (SUCCESS_EXIT_CODE);
973 }
974 
975 static const struct option options[] =
976 {
977   { "help",                 no_argument,       NULL, 'h' },
978   { "version",              no_argument,       NULL, 'v' },
979   { "verbose",              no_argument,       NULL, 'w' },
980   { "all-blocks",           no_argument,       NULL, 'a' },
981   { "branch-probabilities", no_argument,       NULL, 'b' },
982   { "branch-counts",        no_argument,       NULL, 'c' },
983   { "json-format",	    no_argument,       NULL, 'j' },
984   { "human-readable",	    no_argument,       NULL, 'H' },
985   { "no-output",            no_argument,       NULL, 'n' },
986   { "long-file-names",      no_argument,       NULL, 'l' },
987   { "function-summaries",   no_argument,       NULL, 'f' },
988   { "demangled-names",      no_argument,       NULL, 'm' },
989   { "preserve-paths",       no_argument,       NULL, 'p' },
990   { "relative-only",        no_argument,       NULL, 'r' },
991   { "object-directory",     required_argument, NULL, 'o' },
992   { "object-file",          required_argument, NULL, 'o' },
993   { "source-prefix",        required_argument, NULL, 's' },
994   { "stdout",		    no_argument,       NULL, 't' },
995   { "unconditional-branches", no_argument,     NULL, 'u' },
996   { "display-progress",     no_argument,       NULL, 'd' },
997   { "hash-filenames",	    no_argument,       NULL, 'x' },
998   { "use-colors",	    no_argument,       NULL, 'k' },
999   { "use-hotness-colors",   no_argument,       NULL, 'q' },
1000   { "debug",		    no_argument,       NULL, 'D' },
1001   { 0, 0, 0, 0 }
1002 };
1003 
1004 /* Process args, return index to first non-arg.  */
1005 
1006 static int
process_args(int argc,char ** argv)1007 process_args (int argc, char **argv)
1008 {
1009   int opt;
1010 
1011   const char *opts = "abcdDfhHijklmno:pqrs:tuvwx";
1012   while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
1013     {
1014       switch (opt)
1015 	{
1016 	case 'a':
1017 	  flag_all_blocks = 1;
1018 	  break;
1019 	case 'b':
1020 	  flag_branches = 1;
1021 	  break;
1022 	case 'c':
1023 	  flag_counts = 1;
1024 	  break;
1025 	case 'f':
1026 	  flag_function_summary = 1;
1027 	  break;
1028 	case 'h':
1029 	  print_usage (false);
1030 	  /* print_usage will exit.  */
1031 	case 'l':
1032 	  flag_long_names = 1;
1033 	  break;
1034 	case 'H':
1035 	  flag_human_readable_numbers = 1;
1036 	  break;
1037 	case 'k':
1038 	  flag_use_colors = 1;
1039 	  break;
1040 	case 'q':
1041 	  flag_use_hotness_colors = 1;
1042 	  break;
1043 	case 'm':
1044 	  flag_demangled_names = 1;
1045 	  break;
1046 	case 'n':
1047 	  flag_gcov_file = 0;
1048 	  break;
1049 	case 'o':
1050 	  object_directory = optarg;
1051 	  break;
1052 	case 's':
1053 	  source_prefix = optarg;
1054 	  source_length = strlen (source_prefix);
1055 	  break;
1056 	case 'r':
1057 	  flag_relative_only = 1;
1058 	  break;
1059 	case 'p':
1060 	  flag_preserve_paths = 1;
1061 	  break;
1062 	case 'u':
1063 	  flag_unconditional = 1;
1064 	  break;
1065 	case 'i':
1066 	case 'j':
1067 	  flag_json_format = 1;
1068 	  flag_gcov_file = 1;
1069 	  break;
1070 	case 'd':
1071 	  flag_display_progress = 1;
1072 	  break;
1073 	case 'x':
1074 	  flag_hash_filenames = 1;
1075 	  break;
1076 	case 'w':
1077 	  flag_verbose = 1;
1078 	  break;
1079 	case 't':
1080 	  flag_use_stdout = 1;
1081 	  break;
1082 	case 'D':
1083 	  flag_debug = 1;
1084 	  break;
1085 	case 'v':
1086 	  print_version ();
1087 	  /* print_version will exit.  */
1088 	default:
1089 	  print_usage (true);
1090 	  /* print_usage will exit.  */
1091 	}
1092     }
1093 
1094   return optind;
1095 }
1096 
1097 /* Output intermediate LINE sitting on LINE_NUM to JSON OBJECT.
1098    Add FUNCTION_NAME to the LINE.  */
1099 
1100 static void
output_intermediate_json_line(json::array * object,line_info * line,unsigned line_num,const char * function_name)1101 output_intermediate_json_line (json::array *object,
1102 			       line_info *line, unsigned line_num,
1103 			       const char *function_name)
1104 {
1105   if (!line->exists)
1106     return;
1107 
1108   json::object *lineo = new json::object ();
1109   lineo->set ("line_number", new json::integer_number (line_num));
1110   if (function_name != NULL)
1111     lineo->set ("function_name", new json::string (function_name));
1112   lineo->set ("count", new json::integer_number (line->count));
1113   lineo->set ("unexecuted_block",
1114 	      new json::literal (line->has_unexecuted_block));
1115 
1116   json::array *branches = new json::array ();
1117   lineo->set ("branches", branches);
1118 
1119   vector<arc_info *>::const_iterator it;
1120   if (flag_branches)
1121     for (it = line->branches.begin (); it != line->branches.end ();
1122 	 it++)
1123       {
1124 	if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
1125 	  {
1126 	    json::object *branch = new json::object ();
1127 	    branch->set ("count", new json::integer_number ((*it)->count));
1128 	    branch->set ("throw", new json::literal ((*it)->is_throw));
1129 	    branch->set ("fallthrough",
1130 			 new json::literal ((*it)->fall_through));
1131 	    branches->append (branch);
1132 	  }
1133       }
1134 
1135   object->append (lineo);
1136 }
1137 
1138 /* Strip filename extension in STR.  */
1139 
1140 static string
strip_extention(string str)1141 strip_extention (string str)
1142 {
1143   string::size_type pos = str.rfind ('.');
1144   if (pos != string::npos)
1145     str = str.substr (0, pos);
1146 
1147   return str;
1148 }
1149 
1150 /* Calcualte md5sum for INPUT string and return it in hex string format.  */
1151 
1152 static string
get_md5sum(const char * input)1153 get_md5sum (const char *input)
1154 {
1155   md5_ctx ctx;
1156   char md5sum[16];
1157   string str;
1158 
1159   md5_init_ctx (&ctx);
1160   md5_process_bytes (input, strlen (input), &ctx);
1161   md5_finish_ctx (&ctx, md5sum);
1162 
1163   for (unsigned i = 0; i < 16; i++)
1164     {
1165       char b[3];
1166       sprintf (b, "%02x", (unsigned char)md5sum[i]);
1167       str += b;
1168     }
1169 
1170   return str;
1171 }
1172 
1173 /* Get the name of the gcov file.  The return value must be free'd.
1174 
1175    It appends the '.gcov' extension to the *basename* of the file.
1176    The resulting file name will be in PWD.
1177 
1178    e.g.,
1179    input: foo.da,       output: foo.da.gcov
1180    input: a/b/foo.cc,   output: foo.cc.gcov  */
1181 
1182 static string
get_gcov_intermediate_filename(const char * input_file_name)1183 get_gcov_intermediate_filename (const char *input_file_name)
1184 {
1185   string base = basename (input_file_name);
1186   string str = strip_extention (base);
1187 
1188   if (flag_hash_filenames)
1189     {
1190       str += "##";
1191       str += get_md5sum (input_file_name);
1192     }
1193   else if (flag_preserve_paths && base != input_file_name)
1194     {
1195       str += "##";
1196       str += mangle_path (input_file_name);
1197       str = strip_extention (str);
1198     }
1199 
1200   str += ".gcov.json.gz";
1201   return str.c_str ();
1202 }
1203 
1204 /* Output the result in JSON intermediate format.
1205    Source info SRC is dumped into JSON_FILES which is JSON array.  */
1206 
1207 static void
output_json_intermediate_file(json::array * json_files,source_info * src)1208 output_json_intermediate_file (json::array *json_files, source_info *src)
1209 {
1210   json::object *root = new json::object ();
1211   json_files->append (root);
1212 
1213   root->set ("file", new json::string (src->name));
1214 
1215   json::array *functions = new json::array ();
1216   root->set ("functions", functions);
1217 
1218   std::sort (src->functions.begin (), src->functions.end (),
1219 	     function_line_start_cmp ());
1220   for (vector<function_info *>::iterator it = src->functions.begin ();
1221        it != src->functions.end (); it++)
1222     {
1223       json::object *function = new json::object ();
1224       function->set ("name", new json::string ((*it)->m_name));
1225       function->set ("demangled_name",
1226 		     new json::string ((*it)->get_demangled_name ()));
1227       function->set ("start_line",
1228 		     new json::integer_number ((*it)->start_line));
1229       function->set ("start_column",
1230 		     new json::integer_number ((*it)->start_column));
1231       function->set ("end_line", new json::integer_number ((*it)->end_line));
1232       function->set ("end_column",
1233 		     new json::integer_number ((*it)->end_column));
1234       function->set ("blocks",
1235 		     new json::integer_number ((*it)->get_block_count ()));
1236       function->set ("blocks_executed",
1237 		     new json::integer_number ((*it)->blocks_executed));
1238       function->set ("execution_count",
1239 		     new json::integer_number ((*it)->blocks[0].count));
1240 
1241       functions->append (function);
1242     }
1243 
1244   json::array *lineso = new json::array ();
1245   root->set ("lines", lineso);
1246 
1247   vector<function_info *> last_non_group_fns;
1248 
1249   for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
1250     {
1251       vector<function_info *> *fns = src->get_functions_at_location (line_num);
1252 
1253       if (fns != NULL)
1254 	/* Print info for all group functions that begin on the line.  */
1255 	for (vector<function_info *>::iterator it2 = fns->begin ();
1256 	     it2 != fns->end (); it2++)
1257 	  {
1258 	    if (!(*it2)->is_group)
1259 	      last_non_group_fns.push_back (*it2);
1260 
1261 	    vector<line_info> &lines = (*it2)->lines;
1262 	    /* The LINES array is allocated only for group functions.  */
1263 	    for (unsigned i = 0; i < lines.size (); i++)
1264 	      {
1265 		line_info *line = &lines[i];
1266 		output_intermediate_json_line (lineso, line, line_num + i,
1267 					       (*it2)->m_name);
1268 	      }
1269 	  }
1270 
1271       /* Follow with lines associated with the source file.  */
1272       if (line_num < src->lines.size ())
1273 	{
1274 	  unsigned size = last_non_group_fns.size ();
1275 	  function_info *last_fn = size > 0 ? last_non_group_fns[size - 1] : NULL;
1276 	  const char *fname = last_fn ? last_fn->m_name : NULL;
1277 	  output_intermediate_json_line (lineso, &src->lines[line_num], line_num,
1278 					 fname);
1279 
1280 	  /* Pop ending function from stack.  */
1281 	  if (last_fn != NULL && last_fn->end_line == line_num)
1282 	    last_non_group_fns.pop_back ();
1283 	}
1284     }
1285 }
1286 
1287 /* Function start pair.  */
1288 struct function_start
1289 {
1290   unsigned source_file_idx;
1291   unsigned start_line;
1292 };
1293 
1294 /* Traits class for function start hash maps below.  */
1295 
1296 struct function_start_pair_hash : typed_noop_remove <function_start>
1297 {
1298   typedef function_start value_type;
1299   typedef function_start compare_type;
1300 
1301   static hashval_t
hashfunction_start_pair_hash1302   hash (const function_start &ref)
1303   {
1304     inchash::hash hstate (0);
1305     hstate.add_int (ref.source_file_idx);
1306     hstate.add_int (ref.start_line);
1307     return hstate.end ();
1308   }
1309 
1310   static bool
equalfunction_start_pair_hash1311   equal (const function_start &ref1, const function_start &ref2)
1312   {
1313     return (ref1.source_file_idx == ref2.source_file_idx
1314 	    && ref1.start_line == ref2.start_line);
1315   }
1316 
1317   static void
mark_deletedfunction_start_pair_hash1318   mark_deleted (function_start &ref)
1319   {
1320     ref.start_line = ~1U;
1321   }
1322 
1323   static const bool empty_zero_p = false;
1324 
1325   static void
mark_emptyfunction_start_pair_hash1326   mark_empty (function_start &ref)
1327   {
1328     ref.start_line = ~2U;
1329   }
1330 
1331   static bool
is_deletedfunction_start_pair_hash1332   is_deleted (const function_start &ref)
1333   {
1334     return ref.start_line == ~1U;
1335   }
1336 
1337   static bool
is_emptyfunction_start_pair_hash1338   is_empty (const function_start &ref)
1339   {
1340     return ref.start_line == ~2U;
1341   }
1342 };
1343 
1344 /* Process a single input file.  */
1345 
1346 static void
process_file(const char * file_name)1347 process_file (const char *file_name)
1348 {
1349   create_file_names (file_name);
1350 
1351   for (unsigned i = 0; i < processed_files.size (); i++)
1352     if (strcmp (da_file_name, processed_files[i]) == 0)
1353       {
1354 	fnotice (stderr, "'%s' file is already processed\n",
1355 		 file_name);
1356 	return;
1357       }
1358 
1359   processed_files.push_back (xstrdup (da_file_name));
1360 
1361   read_graph_file ();
1362   read_count_file ();
1363 }
1364 
1365 /* Process all functions in all files.  */
1366 
1367 static void
process_all_functions(void)1368 process_all_functions (void)
1369 {
1370   hash_map<function_start_pair_hash, function_info *> fn_map;
1371 
1372   /* Identify group functions.  */
1373   for (vector<function_info *>::iterator it = functions.begin ();
1374        it != functions.end (); it++)
1375     if (!(*it)->artificial)
1376       {
1377 	function_start needle;
1378 	needle.source_file_idx = (*it)->src;
1379 	needle.start_line = (*it)->start_line;
1380 
1381 	function_info **slot = fn_map.get (needle);
1382 	if (slot)
1383 	  {
1384 	    (*slot)->is_group = 1;
1385 	    (*it)->is_group = 1;
1386 	  }
1387 	else
1388 	  fn_map.put (needle, *it);
1389       }
1390 
1391   /* Remove all artificial function.  */
1392   functions.erase (remove_if (functions.begin (), functions.end (),
1393 			      function_info::is_artificial), functions.end ());
1394 
1395   for (vector<function_info *>::iterator it = functions.begin ();
1396        it != functions.end (); it++)
1397     {
1398       function_info *fn = *it;
1399       unsigned src = fn->src;
1400 
1401       if (!fn->counts.empty () || no_data_file)
1402 	{
1403 	  source_info *s = &sources[src];
1404 	  s->add_function (fn);
1405 
1406 	  /* Mark last line in files touched by function.  */
1407 	  for (unsigned block_no = 0; block_no != fn->blocks.size ();
1408 	       block_no++)
1409 	    {
1410 	      block_info *block = &fn->blocks[block_no];
1411 	      for (unsigned i = 0; i < block->locations.size (); i++)
1412 		{
1413 		  /* Sort lines of locations.  */
1414 		  sort (block->locations[i].lines.begin (),
1415 			block->locations[i].lines.end ());
1416 
1417 		  if (!block->locations[i].lines.empty ())
1418 		    {
1419 		      s = &sources[block->locations[i].source_file_idx];
1420 		      unsigned last_line
1421 			= block->locations[i].lines.back ();
1422 
1423 		      /* Record new lines for the function.  */
1424 		      if (last_line >= s->lines.size ())
1425 			{
1426 			  s = &sources[block->locations[i].source_file_idx];
1427 			  unsigned last_line
1428 			    = block->locations[i].lines.back ();
1429 
1430 			  /* Record new lines for the function.  */
1431 			  if (last_line >= s->lines.size ())
1432 			    {
1433 			      /* Record new lines for a source file.  */
1434 			      s->lines.resize (last_line + 1);
1435 			    }
1436 			}
1437 		    }
1438 		}
1439 	    }
1440 
1441 	  /* Allocate lines for group function, following start_line
1442 	     and end_line information of the function.  */
1443 	  if (fn->is_group)
1444 	    fn->lines.resize (fn->end_line - fn->start_line + 1);
1445 
1446 	  solve_flow_graph (fn);
1447 	  if (fn->has_catch)
1448 	    find_exception_blocks (fn);
1449 	}
1450       else
1451 	{
1452 	  /* The function was not in the executable -- some other
1453 	     instance must have been selected.  */
1454 	}
1455     }
1456 }
1457 
1458 static void
output_gcov_file(const char * file_name,source_info * src)1459 output_gcov_file (const char *file_name, source_info *src)
1460 {
1461   string gcov_file_name_str
1462     = make_gcov_file_name (file_name, src->coverage.name);
1463   const char *gcov_file_name = gcov_file_name_str.c_str ();
1464 
1465   if (src->coverage.lines)
1466     {
1467       FILE *gcov_file = fopen (gcov_file_name, "w");
1468       if (gcov_file)
1469 	{
1470 	  fnotice (stdout, "Creating '%s'\n", gcov_file_name);
1471 	  output_lines (gcov_file, src);
1472 	  if (ferror (gcov_file))
1473 	    {
1474 	      fnotice (stderr, "Error writing output file '%s'\n",
1475 		       gcov_file_name);
1476 	      return_code = 6;
1477 	    }
1478 	  fclose (gcov_file);
1479 	}
1480       else
1481 	{
1482 	  fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
1483 	  return_code = 6;
1484 	}
1485     }
1486   else
1487     {
1488       unlink (gcov_file_name);
1489       fnotice (stdout, "Removing '%s'\n", gcov_file_name);
1490     }
1491 }
1492 
1493 static void
generate_results(const char * file_name)1494 generate_results (const char *file_name)
1495 {
1496   string gcov_intermediate_filename;
1497 
1498   for (vector<function_info *>::iterator it = functions.begin ();
1499        it != functions.end (); it++)
1500     {
1501       function_info *fn = *it;
1502       coverage_info coverage;
1503 
1504       memset (&coverage, 0, sizeof (coverage));
1505       coverage.name = fn->get_name ();
1506       add_line_counts (flag_function_summary ? &coverage : NULL, fn);
1507       if (flag_function_summary)
1508 	{
1509 	  function_summary (&coverage);
1510 	  fnotice (stdout, "\n");
1511 	}
1512     }
1513 
1514   name_map needle;
1515   needle.name = file_name;
1516   vector<name_map>::iterator it
1517     = std::find (names.begin (), names.end (), needle);
1518   if (it != names.end ())
1519     file_name = sources[it->src].coverage.name;
1520   else
1521     file_name = canonicalize_name (file_name);
1522 
1523   gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
1524 
1525   json::object *root = new json::object ();
1526   root->set ("format_version", new json::string ("1"));
1527   root->set ("gcc_version", new json::string (version_string));
1528 
1529   if (bbg_cwd != NULL)
1530     root->set ("current_working_directory", new json::string (bbg_cwd));
1531   root->set ("data_file", new json::string (file_name));
1532 
1533   json::array *json_files = new json::array ();
1534   root->set ("files", json_files);
1535 
1536   for (vector<source_info>::iterator it = sources.begin ();
1537        it != sources.end (); it++)
1538     {
1539       source_info *src = &(*it);
1540       if (flag_relative_only)
1541 	{
1542 	  /* Ignore this source, if it is an absolute path (after
1543 	     source prefix removal).  */
1544 	  char first = src->coverage.name[0];
1545 
1546 #if HAVE_DOS_BASED_FILE_SYSTEM
1547 	  if (first && src->coverage.name[1] == ':')
1548 	    first = src->coverage.name[2];
1549 #endif
1550 	  if (IS_DIR_SEPARATOR (first))
1551 	    continue;
1552 	}
1553 
1554       accumulate_line_counts (src);
1555       if (flag_debug)
1556 	src->debug ();
1557 
1558       if (!flag_use_stdout)
1559 	file_summary (&src->coverage);
1560       total_lines += src->coverage.lines;
1561       total_executed += src->coverage.lines_executed;
1562       if (flag_gcov_file)
1563 	{
1564 	  if (flag_json_format)
1565 	    {
1566 	      output_json_intermediate_file (json_files, src);
1567 	      if (!flag_use_stdout)
1568 		fnotice (stdout, "\n");
1569 	    }
1570 	  else
1571 	    {
1572 	      if (flag_use_stdout)
1573 		{
1574 		  if (src->coverage.lines)
1575 		    output_lines (stdout, src);
1576 		}
1577 	      else
1578 		{
1579 		  output_gcov_file (file_name, src);
1580 		  fnotice (stdout, "\n");
1581 		}
1582 	    }
1583 	}
1584     }
1585 
1586   if (flag_gcov_file && flag_json_format)
1587     {
1588       if (flag_use_stdout)
1589 	{
1590 	  root->dump (stdout);
1591 	  printf ("\n");
1592 	}
1593       else
1594 	{
1595 	  pretty_printer pp;
1596 	  root->print (&pp);
1597 	  pp_formatted_text (&pp);
1598 
1599 	  fnotice (stdout, "Creating '%s'\n",
1600 		   gcov_intermediate_filename.c_str ());
1601 	  gzFile output = gzopen (gcov_intermediate_filename.c_str (), "w");
1602 	  if (output == NULL)
1603 	    {
1604 	      fnotice (stderr, "Cannot open JSON output file %s\n",
1605 		       gcov_intermediate_filename.c_str ());
1606 	      return_code = 6;
1607 	      return;
1608 	    }
1609 
1610 	  if (gzputs (output, pp_formatted_text (&pp)) == EOF
1611 	      || gzclose (output))
1612 	    {
1613 	      fnotice (stderr, "Error writing JSON output file %s\n",
1614 		       gcov_intermediate_filename.c_str ());
1615 	      return_code = 6;
1616 	      return;
1617 	    }
1618 	}
1619     }
1620 }
1621 
1622 /* Release all memory used.  */
1623 
1624 static void
release_structures(void)1625 release_structures (void)
1626 {
1627   for (vector<function_info *>::iterator it = functions.begin ();
1628        it != functions.end (); it++)
1629     delete (*it);
1630 
1631   sources.resize (0);
1632   names.resize (0);
1633   functions.resize (0);
1634   ident_to_fn.clear ();
1635 }
1636 
1637 /* Generate the names of the graph and data files.  If OBJECT_DIRECTORY
1638    is not specified, these are named from FILE_NAME sans extension.  If
1639    OBJECT_DIRECTORY is specified and is a directory, the files are in that
1640    directory, but named from the basename of the FILE_NAME, sans extension.
1641    Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
1642    and the data files are named from that.  */
1643 
1644 static void
create_file_names(const char * file_name)1645 create_file_names (const char *file_name)
1646 {
1647   char *cptr;
1648   char *name;
1649   int length = strlen (file_name);
1650   int base;
1651 
1652   /* Free previous file names.  */
1653   free (bbg_file_name);
1654   free (da_file_name);
1655   da_file_name = bbg_file_name = NULL;
1656   bbg_file_time = 0;
1657   bbg_stamp = 0;
1658 
1659   if (object_directory && object_directory[0])
1660     {
1661       struct stat status;
1662 
1663       length += strlen (object_directory) + 2;
1664       name = XNEWVEC (char, length);
1665       name[0] = 0;
1666 
1667       base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
1668       strcat (name, object_directory);
1669       if (base && (!IS_DIR_SEPARATOR (name[strlen (name) - 1])))
1670 	strcat (name, "/");
1671     }
1672   else
1673     {
1674       name = XNEWVEC (char, length + 1);
1675       strcpy (name, file_name);
1676       base = 0;
1677     }
1678 
1679   if (base)
1680     {
1681       /* Append source file name.  */
1682       const char *cptr = lbasename (file_name);
1683       strcat (name, cptr ? cptr : file_name);
1684     }
1685 
1686   /* Remove the extension.  */
1687   cptr = strrchr (CONST_CAST (char *, lbasename (name)), '.');
1688   if (cptr)
1689     *cptr = 0;
1690 
1691   length = strlen (name);
1692 
1693   bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
1694   strcpy (bbg_file_name, name);
1695   strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
1696 
1697   da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
1698   strcpy (da_file_name, name);
1699   strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
1700 
1701   free (name);
1702   return;
1703 }
1704 
1705 /* Find or create a source file structure for FILE_NAME. Copies
1706    FILE_NAME on creation */
1707 
1708 static unsigned
find_source(const char * file_name)1709 find_source (const char *file_name)
1710 {
1711   char *canon;
1712   unsigned idx;
1713   struct stat status;
1714 
1715   if (!file_name)
1716     file_name = "<unknown>";
1717 
1718   name_map needle;
1719   needle.name = file_name;
1720 
1721   vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1722 					     needle);
1723   if (it != names.end ())
1724     {
1725       idx = it->src;
1726       goto check_date;
1727     }
1728 
1729   /* Not found, try the canonical name. */
1730   canon = canonicalize_name (file_name);
1731   needle.name = canon;
1732   it = std::find (names.begin (), names.end (), needle);
1733   if (it == names.end ())
1734     {
1735       /* Not found with canonical name, create a new source.  */
1736       source_info *src;
1737 
1738       idx = sources.size ();
1739       needle = name_map (canon, idx);
1740       names.push_back (needle);
1741 
1742       sources.push_back (source_info ());
1743       src = &sources.back ();
1744       src->name = canon;
1745       src->coverage.name = src->name;
1746       src->index = idx;
1747       if (source_length
1748 #if HAVE_DOS_BASED_FILE_SYSTEM
1749 	  /* You lose if separators don't match exactly in the
1750 	     prefix.  */
1751 	  && !strncasecmp (source_prefix, src->coverage.name, source_length)
1752 #else
1753 	  && !strncmp (source_prefix, src->coverage.name, source_length)
1754 #endif
1755 	  && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
1756 	src->coverage.name += source_length + 1;
1757       if (!stat (src->name, &status))
1758 	src->file_time = status.st_mtime;
1759     }
1760   else
1761     idx = it->src;
1762 
1763   needle.name = file_name;
1764   if (std::find (names.begin (), names.end (), needle) == names.end ())
1765     {
1766       /* Append the non-canonical name.  */
1767       names.push_back (name_map (xstrdup (file_name), idx));
1768     }
1769 
1770   /* Resort the name map.  */
1771   std::sort (names.begin (), names.end ());
1772 
1773  check_date:
1774   if (sources[idx].file_time > bbg_file_time)
1775     {
1776       static int info_emitted;
1777 
1778       fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
1779 	       file_name, bbg_file_name);
1780       if (!info_emitted)
1781 	{
1782 	  fnotice (stderr,
1783 		   "(the message is displayed only once per source file)\n");
1784 	  info_emitted = 1;
1785 	}
1786       sources[idx].file_time = 0;
1787     }
1788 
1789   return idx;
1790 }
1791 
1792 /* Read the notes file.  Save functions to FUNCTIONS global vector.  */
1793 
1794 static void
read_graph_file(void)1795 read_graph_file (void)
1796 {
1797   unsigned version;
1798   unsigned current_tag = 0;
1799   unsigned tag;
1800 
1801   if (!gcov_open (bbg_file_name, 1))
1802     {
1803       fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1804       return_code = 1;
1805       return;
1806     }
1807   bbg_file_time = gcov_time ();
1808   if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1809     {
1810       fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
1811       return_code = 2;
1812       gcov_close ();
1813       return;
1814     }
1815 
1816   version = gcov_read_unsigned ();
1817   if (version != GCOV_VERSION)
1818     {
1819       char v[4], e[4];
1820 
1821       GCOV_UNSIGNED2STRING (v, version);
1822       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1823 
1824       fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1825 	       bbg_file_name, v, e);
1826       return_code = 3;
1827     }
1828   bbg_stamp = gcov_read_unsigned ();
1829   /* Read checksum.  */
1830   gcov_read_unsigned ();
1831   bbg_cwd = xstrdup (gcov_read_string ());
1832   bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
1833 
1834   function_info *fn = NULL;
1835   while ((tag = gcov_read_unsigned ()))
1836     {
1837       unsigned length = gcov_read_unsigned ();
1838       gcov_position_t base = gcov_position ();
1839 
1840       if (tag == GCOV_TAG_FUNCTION)
1841 	{
1842 	  char *function_name;
1843 	  unsigned ident;
1844 	  unsigned lineno_checksum, cfg_checksum;
1845 
1846 	  ident = gcov_read_unsigned ();
1847 	  lineno_checksum = gcov_read_unsigned ();
1848 	  cfg_checksum = gcov_read_unsigned ();
1849 	  function_name = xstrdup (gcov_read_string ());
1850 	  unsigned artificial = gcov_read_unsigned ();
1851 	  unsigned src_idx = find_source (gcov_read_string ());
1852 	  unsigned start_line = gcov_read_unsigned ();
1853 	  unsigned start_column = gcov_read_unsigned ();
1854 	  unsigned end_line = gcov_read_unsigned ();
1855 	  unsigned end_column = gcov_read_unsigned ();
1856 
1857 	  fn = new function_info ();
1858 	  functions.push_back (fn);
1859 	  ident_to_fn[ident] = fn;
1860 
1861 	  fn->m_name = function_name;
1862 	  fn->ident = ident;
1863 	  fn->lineno_checksum = lineno_checksum;
1864 	  fn->cfg_checksum = cfg_checksum;
1865 	  fn->src = src_idx;
1866 	  fn->start_line = start_line;
1867 	  fn->start_column = start_column;
1868 	  fn->end_line = end_line;
1869 	  fn->end_column = end_column;
1870 	  fn->artificial = artificial;
1871 
1872 	  current_tag = tag;
1873 	}
1874       else if (fn && tag == GCOV_TAG_BLOCKS)
1875 	{
1876 	  if (!fn->blocks.empty ())
1877 	    fnotice (stderr, "%s:already seen blocks for '%s'\n",
1878 		     bbg_file_name, fn->get_name ());
1879 	  else
1880 	    fn->blocks.resize (gcov_read_unsigned ());
1881 	}
1882       else if (fn && tag == GCOV_TAG_ARCS)
1883 	{
1884 	  unsigned src = gcov_read_unsigned ();
1885 	  fn->blocks[src].id = src;
1886 	  unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1887 	  block_info *src_blk = &fn->blocks[src];
1888 	  unsigned mark_catches = 0;
1889 	  struct arc_info *arc;
1890 
1891 	  if (src >= fn->blocks.size () || fn->blocks[src].succ)
1892 	    goto corrupt;
1893 
1894 	  while (num_dests--)
1895 	    {
1896 	      unsigned dest = gcov_read_unsigned ();
1897 	      unsigned flags = gcov_read_unsigned ();
1898 
1899 	      if (dest >= fn->blocks.size ())
1900 		goto corrupt;
1901 	      arc = XCNEW (arc_info);
1902 
1903 	      arc->dst = &fn->blocks[dest];
1904 	      /* Set id in order to find EXIT_BLOCK.  */
1905 	      arc->dst->id = dest;
1906 	      arc->src = src_blk;
1907 
1908 	      arc->count = 0;
1909 	      arc->count_valid = 0;
1910 	      arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
1911 	      arc->fake = !!(flags & GCOV_ARC_FAKE);
1912 	      arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
1913 
1914 	      arc->succ_next = src_blk->succ;
1915 	      src_blk->succ = arc;
1916 	      src_blk->num_succ++;
1917 
1918 	      arc->pred_next = fn->blocks[dest].pred;
1919 	      fn->blocks[dest].pred = arc;
1920 	      fn->blocks[dest].num_pred++;
1921 
1922 	      if (arc->fake)
1923 		{
1924 		  if (src)
1925 		    {
1926 		      /* Exceptional exit from this function, the
1927 			 source block must be a call.  */
1928 		      fn->blocks[src].is_call_site = 1;
1929 		      arc->is_call_non_return = 1;
1930 		      mark_catches = 1;
1931 		    }
1932 		  else
1933 		    {
1934 		      /* Non-local return from a callee of this
1935 			 function.  The destination block is a setjmp.  */
1936 		      arc->is_nonlocal_return = 1;
1937 		      fn->blocks[dest].is_nonlocal_return = 1;
1938 		    }
1939 		}
1940 
1941 	      if (!arc->on_tree)
1942 		fn->counts.push_back (0);
1943 	    }
1944 
1945 	  if (mark_catches)
1946 	    {
1947 	      /* We have a fake exit from this block.  The other
1948 		 non-fall through exits must be to catch handlers.
1949 		 Mark them as catch arcs.  */
1950 
1951 	      for (arc = src_blk->succ; arc; arc = arc->succ_next)
1952 		if (!arc->fake && !arc->fall_through)
1953 		  {
1954 		    arc->is_throw = 1;
1955 		    fn->has_catch = 1;
1956 		  }
1957 	    }
1958 	}
1959       else if (fn && tag == GCOV_TAG_LINES)
1960 	{
1961 	  unsigned blockno = gcov_read_unsigned ();
1962 	  block_info *block = &fn->blocks[blockno];
1963 
1964 	  if (blockno >= fn->blocks.size ())
1965 	    goto corrupt;
1966 
1967 	  while (true)
1968 	    {
1969 	      unsigned lineno = gcov_read_unsigned ();
1970 
1971 	      if (lineno)
1972 		block->locations.back ().lines.push_back (lineno);
1973 	      else
1974 		{
1975 		  const char *file_name = gcov_read_string ();
1976 
1977 		  if (!file_name)
1978 		    break;
1979 		  block->locations.push_back (block_location_info
1980 					      (find_source (file_name)));
1981 		}
1982 	    }
1983 	}
1984       else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
1985 	{
1986 	  fn = NULL;
1987 	  current_tag = 0;
1988 	}
1989       gcov_sync (base, length);
1990       if (gcov_is_error ())
1991 	{
1992 	corrupt:;
1993 	  fnotice (stderr, "%s:corrupted\n", bbg_file_name);
1994 	  return_code = 4;
1995 	  break;
1996 	}
1997     }
1998   gcov_close ();
1999 
2000   if (functions.empty ())
2001     fnotice (stderr, "%s:no functions found\n", bbg_file_name);
2002 }
2003 
2004 /* Reads profiles from the count file and attach to each
2005    function. Return nonzero if fatal error.  */
2006 
2007 static int
read_count_file(void)2008 read_count_file (void)
2009 {
2010   unsigned ix;
2011   unsigned version;
2012   unsigned tag;
2013   function_info *fn = NULL;
2014   int error = 0;
2015   map<unsigned, function_info *>::iterator it;
2016 
2017   if (!gcov_open (da_file_name, 1))
2018     {
2019       fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
2020 	       da_file_name);
2021       no_data_file = 1;
2022       return 0;
2023     }
2024   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
2025     {
2026       fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
2027       return_code = 2;
2028     cleanup:;
2029       gcov_close ();
2030       return 1;
2031     }
2032   version = gcov_read_unsigned ();
2033   if (version != GCOV_VERSION)
2034     {
2035       char v[4], e[4];
2036 
2037       GCOV_UNSIGNED2STRING (v, version);
2038       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
2039 
2040       fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
2041 	       da_file_name, v, e);
2042       return_code = 3;
2043     }
2044   tag = gcov_read_unsigned ();
2045   if (tag != bbg_stamp)
2046     {
2047       fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
2048       return_code = 5;
2049       goto cleanup;
2050     }
2051 
2052   /* Read checksum.  */
2053   gcov_read_unsigned ();
2054 
2055   while ((tag = gcov_read_unsigned ()))
2056     {
2057       unsigned length = gcov_read_unsigned ();
2058       int read_length = (int)length;
2059       unsigned long base = gcov_position ();
2060 
2061       if (tag == GCOV_TAG_OBJECT_SUMMARY)
2062 	{
2063 	  struct gcov_summary summary;
2064 	  gcov_read_summary (&summary);
2065 	  object_runs = summary.runs;
2066 	}
2067       else if (tag == GCOV_TAG_FUNCTION && !length)
2068 	; /* placeholder  */
2069       else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
2070 	{
2071 	  unsigned ident;
2072 	  ident = gcov_read_unsigned ();
2073 	  fn = NULL;
2074 	  it = ident_to_fn.find (ident);
2075 	  if (it != ident_to_fn.end ())
2076 	    fn = it->second;
2077 
2078 	  if (!fn)
2079 	    ;
2080 	  else if (gcov_read_unsigned () != fn->lineno_checksum
2081 		   || gcov_read_unsigned () != fn->cfg_checksum)
2082 	    {
2083 	    mismatch:;
2084 	      fnotice (stderr, "%s:profile mismatch for '%s'\n",
2085 		       da_file_name, fn->get_name ());
2086 	      goto cleanup;
2087 	    }
2088 	}
2089       else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
2090 	{
2091 	  length = abs (read_length);
2092 	  if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
2093 	    goto mismatch;
2094 
2095 	  if (read_length > 0)
2096 	    for (ix = 0; ix != fn->counts.size (); ix++)
2097 	      fn->counts[ix] += gcov_read_counter ();
2098 	}
2099       if (read_length < 0)
2100 	read_length = 0;
2101       gcov_sync (base, read_length);
2102       if ((error = gcov_is_error ()))
2103 	{
2104 	  fnotice (stderr,
2105 		   error < 0
2106 		   ? N_("%s:overflowed\n")
2107 		   : N_("%s:corrupted\n"),
2108 		   da_file_name);
2109 	  return_code = 4;
2110 	  goto cleanup;
2111 	}
2112     }
2113 
2114   gcov_close ();
2115   return 0;
2116 }
2117 
2118 /* Solve the flow graph. Propagate counts from the instrumented arcs
2119    to the blocks and the uninstrumented arcs.  */
2120 
2121 static void
solve_flow_graph(function_info * fn)2122 solve_flow_graph (function_info *fn)
2123 {
2124   unsigned ix;
2125   arc_info *arc;
2126   gcov_type *count_ptr = &fn->counts.front ();
2127   block_info *blk;
2128   block_info *valid_blocks = NULL;    /* valid, but unpropagated blocks.  */
2129   block_info *invalid_blocks = NULL;  /* invalid, but inferable blocks.  */
2130 
2131   /* The arcs were built in reverse order.  Fix that now.  */
2132   for (ix = fn->blocks.size (); ix--;)
2133     {
2134       arc_info *arc_p, *arc_n;
2135 
2136       for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
2137 	   arc_p = arc, arc = arc_n)
2138 	{
2139 	  arc_n = arc->succ_next;
2140 	  arc->succ_next = arc_p;
2141 	}
2142       fn->blocks[ix].succ = arc_p;
2143 
2144       for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
2145 	   arc_p = arc, arc = arc_n)
2146 	{
2147 	  arc_n = arc->pred_next;
2148 	  arc->pred_next = arc_p;
2149 	}
2150       fn->blocks[ix].pred = arc_p;
2151     }
2152 
2153   if (fn->blocks.size () < 2)
2154     fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
2155 	     bbg_file_name, fn->get_name ());
2156   else
2157     {
2158       if (fn->blocks[ENTRY_BLOCK].num_pred)
2159 	fnotice (stderr, "%s:'%s' has arcs to entry block\n",
2160 		 bbg_file_name, fn->get_name ());
2161       else
2162 	/* We can't deduce the entry block counts from the lack of
2163 	   predecessors.  */
2164 	fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
2165 
2166       if (fn->blocks[EXIT_BLOCK].num_succ)
2167 	fnotice (stderr, "%s:'%s' has arcs from exit block\n",
2168 		 bbg_file_name, fn->get_name ());
2169       else
2170 	/* Likewise, we can't deduce exit block counts from the lack
2171 	   of its successors.  */
2172 	fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
2173     }
2174 
2175   /* Propagate the measured counts, this must be done in the same
2176      order as the code in profile.cc  */
2177   for (unsigned i = 0; i < fn->blocks.size (); i++)
2178     {
2179       blk = &fn->blocks[i];
2180       block_info const *prev_dst = NULL;
2181       int out_of_order = 0;
2182       int non_fake_succ = 0;
2183 
2184       for (arc = blk->succ; arc; arc = arc->succ_next)
2185 	{
2186 	  if (!arc->fake)
2187 	    non_fake_succ++;
2188 
2189 	  if (!arc->on_tree)
2190 	    {
2191 	      if (count_ptr)
2192 		arc->count = *count_ptr++;
2193 	      arc->count_valid = 1;
2194 	      blk->num_succ--;
2195 	      arc->dst->num_pred--;
2196 	    }
2197 	  if (prev_dst && prev_dst > arc->dst)
2198 	    out_of_order = 1;
2199 	  prev_dst = arc->dst;
2200 	}
2201       if (non_fake_succ == 1)
2202 	{
2203 	  /* If there is only one non-fake exit, it is an
2204 	     unconditional branch.  */
2205 	  for (arc = blk->succ; arc; arc = arc->succ_next)
2206 	    if (!arc->fake)
2207 	      {
2208 		arc->is_unconditional = 1;
2209 		/* If this block is instrumenting a call, it might be
2210 		   an artificial block. It is not artificial if it has
2211 		   a non-fallthrough exit, or the destination of this
2212 		   arc has more than one entry.  Mark the destination
2213 		   block as a return site, if none of those conditions
2214 		   hold.  */
2215 		if (blk->is_call_site && arc->fall_through
2216 		    && arc->dst->pred == arc && !arc->pred_next)
2217 		  arc->dst->is_call_return = 1;
2218 	      }
2219 	}
2220 
2221       /* Sort the successor arcs into ascending dst order. profile.cc
2222 	 normally produces arcs in the right order, but sometimes with
2223 	 one or two out of order.  We're not using a particularly
2224 	 smart sort.  */
2225       if (out_of_order)
2226 	{
2227 	  arc_info *start = blk->succ;
2228 	  unsigned changes = 1;
2229 
2230 	  while (changes)
2231 	    {
2232 	      arc_info *arc, *arc_p, *arc_n;
2233 
2234 	      changes = 0;
2235 	      for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
2236 		{
2237 		  if (arc->dst > arc_n->dst)
2238 		    {
2239 		      changes = 1;
2240 		      if (arc_p)
2241 			arc_p->succ_next = arc_n;
2242 		      else
2243 			start = arc_n;
2244 		      arc->succ_next = arc_n->succ_next;
2245 		      arc_n->succ_next = arc;
2246 		      arc_p = arc_n;
2247 		    }
2248 		  else
2249 		    {
2250 		      arc_p = arc;
2251 		      arc = arc_n;
2252 		    }
2253 		}
2254 	    }
2255 	  blk->succ = start;
2256 	}
2257 
2258       /* Place it on the invalid chain, it will be ignored if that's
2259 	 wrong.  */
2260       blk->invalid_chain = 1;
2261       blk->chain = invalid_blocks;
2262       invalid_blocks = blk;
2263     }
2264 
2265   while (invalid_blocks || valid_blocks)
2266     {
2267       while ((blk = invalid_blocks))
2268 	{
2269 	  gcov_type total = 0;
2270 	  const arc_info *arc;
2271 
2272 	  invalid_blocks = blk->chain;
2273 	  blk->invalid_chain = 0;
2274 	  if (!blk->num_succ)
2275 	    for (arc = blk->succ; arc; arc = arc->succ_next)
2276 	      total += arc->count;
2277 	  else if (!blk->num_pred)
2278 	    for (arc = blk->pred; arc; arc = arc->pred_next)
2279 	      total += arc->count;
2280 	  else
2281 	    continue;
2282 
2283 	  blk->count = total;
2284 	  blk->count_valid = 1;
2285 	  blk->chain = valid_blocks;
2286 	  blk->valid_chain = 1;
2287 	  valid_blocks = blk;
2288 	}
2289       while ((blk = valid_blocks))
2290 	{
2291 	  gcov_type total;
2292 	  arc_info *arc, *inv_arc;
2293 
2294 	  valid_blocks = blk->chain;
2295 	  blk->valid_chain = 0;
2296 	  if (blk->num_succ == 1)
2297 	    {
2298 	      block_info *dst;
2299 
2300 	      total = blk->count;
2301 	      inv_arc = NULL;
2302 	      for (arc = blk->succ; arc; arc = arc->succ_next)
2303 		{
2304 		  total -= arc->count;
2305 		  if (!arc->count_valid)
2306 		    inv_arc = arc;
2307 		}
2308 	      dst = inv_arc->dst;
2309 	      inv_arc->count_valid = 1;
2310 	      inv_arc->count = total;
2311 	      blk->num_succ--;
2312 	      dst->num_pred--;
2313 	      if (dst->count_valid)
2314 		{
2315 		  if (dst->num_pred == 1 && !dst->valid_chain)
2316 		    {
2317 		      dst->chain = valid_blocks;
2318 		      dst->valid_chain = 1;
2319 		      valid_blocks = dst;
2320 		    }
2321 		}
2322 	      else
2323 		{
2324 		  if (!dst->num_pred && !dst->invalid_chain)
2325 		    {
2326 		      dst->chain = invalid_blocks;
2327 		      dst->invalid_chain = 1;
2328 		      invalid_blocks = dst;
2329 		    }
2330 		}
2331 	    }
2332 	  if (blk->num_pred == 1)
2333 	    {
2334 	      block_info *src;
2335 
2336 	      total = blk->count;
2337 	      inv_arc = NULL;
2338 	      for (arc = blk->pred; arc; arc = arc->pred_next)
2339 		{
2340 		  total -= arc->count;
2341 		  if (!arc->count_valid)
2342 		    inv_arc = arc;
2343 		}
2344 	      src = inv_arc->src;
2345 	      inv_arc->count_valid = 1;
2346 	      inv_arc->count = total;
2347 	      blk->num_pred--;
2348 	      src->num_succ--;
2349 	      if (src->count_valid)
2350 		{
2351 		  if (src->num_succ == 1 && !src->valid_chain)
2352 		    {
2353 		      src->chain = valid_blocks;
2354 		      src->valid_chain = 1;
2355 		      valid_blocks = src;
2356 		    }
2357 		}
2358 	      else
2359 		{
2360 		  if (!src->num_succ && !src->invalid_chain)
2361 		    {
2362 		      src->chain = invalid_blocks;
2363 		      src->invalid_chain = 1;
2364 		      invalid_blocks = src;
2365 		    }
2366 		}
2367 	    }
2368 	}
2369     }
2370 
2371   /* If the graph has been correctly solved, every block will have a
2372      valid count.  */
2373   for (unsigned i = 0; ix < fn->blocks.size (); i++)
2374     if (!fn->blocks[i].count_valid)
2375       {
2376 	fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
2377 		 bbg_file_name, fn->get_name ());
2378 	break;
2379       }
2380 }
2381 
2382 /* Mark all the blocks only reachable via an incoming catch.  */
2383 
2384 static void
find_exception_blocks(function_info * fn)2385 find_exception_blocks (function_info *fn)
2386 {
2387   unsigned ix;
2388   block_info **queue = XALLOCAVEC (block_info *, fn->blocks.size ());
2389 
2390   /* First mark all blocks as exceptional.  */
2391   for (ix = fn->blocks.size (); ix--;)
2392     fn->blocks[ix].exceptional = 1;
2393 
2394   /* Now mark all the blocks reachable via non-fake edges */
2395   queue[0] = &fn->blocks[0];
2396   queue[0]->exceptional = 0;
2397   for (ix = 1; ix;)
2398     {
2399       block_info *block = queue[--ix];
2400       const arc_info *arc;
2401 
2402       for (arc = block->succ; arc; arc = arc->succ_next)
2403 	if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
2404 	  {
2405 	    arc->dst->exceptional = 0;
2406 	    queue[ix++] = arc->dst;
2407 	  }
2408     }
2409 }
2410 
2411 
2412 /* Increment totals in COVERAGE according to arc ARC.  */
2413 
2414 static void
add_branch_counts(coverage_info * coverage,const arc_info * arc)2415 add_branch_counts (coverage_info *coverage, const arc_info *arc)
2416 {
2417   if (arc->is_call_non_return)
2418     {
2419       coverage->calls++;
2420       if (arc->src->count)
2421 	coverage->calls_executed++;
2422     }
2423   else if (!arc->is_unconditional)
2424     {
2425       coverage->branches++;
2426       if (arc->src->count)
2427 	coverage->branches_executed++;
2428       if (arc->count)
2429 	coverage->branches_taken++;
2430     }
2431 }
2432 
2433 /* Format COUNT, if flag_human_readable_numbers is set, return it human
2434    readable format.  */
2435 
2436 static char const *
format_count(gcov_type count)2437 format_count (gcov_type count)
2438 {
2439   static char buffer[64];
2440   const char *units = " kMGTPEZY";
2441 
2442   if (count < 1000 || !flag_human_readable_numbers)
2443     {
2444       sprintf (buffer, "%" PRId64, count);
2445       return buffer;
2446     }
2447 
2448   unsigned i;
2449   gcov_type divisor = 1;
2450   for (i = 0; units[i+1]; i++, divisor *= 1000)
2451     {
2452       if (count + divisor / 2 < 1000 * divisor)
2453 	break;
2454     }
2455   float r = 1.0f * count / divisor;
2456   sprintf (buffer, "%.1f%c", r, units[i]);
2457   return buffer;
2458 }
2459 
2460 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
2461    count.  If DECIMAL_PLACES >= 0, format TOP/BOTTOM * 100 to DECIMAL_PLACES.
2462    If DECIMAL_PLACES is zero, no decimal point is printed. Only print 100% when
2463    TOP==BOTTOM and only print 0% when TOP=0.  If DECIMAL_PLACES < 0, then simply
2464    format TOP.  Return pointer to a static string.  */
2465 
2466 static char const *
format_gcov(gcov_type top,gcov_type bottom,int decimal_places)2467 format_gcov (gcov_type top, gcov_type bottom, int decimal_places)
2468 {
2469   static char buffer[20];
2470 
2471   if (decimal_places >= 0)
2472     {
2473       float ratio = bottom ? 100.0f * top / bottom: 0;
2474 
2475       /* Round up to 1% if there's a small non-zero value.  */
2476       if (ratio > 0.0f && ratio < 0.5f && decimal_places == 0)
2477 	ratio = 1.0f;
2478       sprintf (buffer, "%.*f%%", decimal_places, ratio);
2479     }
2480   else
2481     return format_count (top);
2482 
2483   return buffer;
2484 }
2485 
2486 /* Summary of execution */
2487 
2488 static void
executed_summary(unsigned lines,unsigned executed)2489 executed_summary (unsigned lines, unsigned executed)
2490 {
2491   if (lines)
2492     fnotice (stdout, "Lines executed:%s of %d\n",
2493 	     format_gcov (executed, lines, 2), lines);
2494   else
2495     fnotice (stdout, "No executable lines\n");
2496 }
2497 
2498 /* Output summary info for a function.  */
2499 
2500 static void
function_summary(const coverage_info * coverage)2501 function_summary (const coverage_info *coverage)
2502 {
2503   fnotice (stdout, "%s '%s'\n", "Function", coverage->name);
2504   executed_summary (coverage->lines, coverage->lines_executed);
2505 }
2506 
2507 /* Output summary info for a file.  */
2508 
2509 static void
file_summary(const coverage_info * coverage)2510 file_summary (const coverage_info *coverage)
2511 {
2512   fnotice (stdout, "%s '%s'\n", "File", coverage->name);
2513   executed_summary (coverage->lines, coverage->lines_executed);
2514 
2515   if (flag_branches)
2516     {
2517       if (coverage->branches)
2518 	{
2519 	  fnotice (stdout, "Branches executed:%s of %d\n",
2520 		   format_gcov (coverage->branches_executed,
2521 				coverage->branches, 2),
2522 		   coverage->branches);
2523 	  fnotice (stdout, "Taken at least once:%s of %d\n",
2524 		   format_gcov (coverage->branches_taken,
2525 				coverage->branches, 2),
2526 		   coverage->branches);
2527 	}
2528       else
2529 	fnotice (stdout, "No branches\n");
2530       if (coverage->calls)
2531 	fnotice (stdout, "Calls executed:%s of %d\n",
2532 		 format_gcov (coverage->calls_executed, coverage->calls, 2),
2533 		 coverage->calls);
2534       else
2535 	fnotice (stdout, "No calls\n");
2536     }
2537 }
2538 
2539 /* Canonicalize the filename NAME by canonicalizing directory
2540    separators, eliding . components and resolving .. components
2541    appropriately.  Always returns a unique string.  */
2542 
2543 static char *
canonicalize_name(const char * name)2544 canonicalize_name (const char *name)
2545 {
2546   /* The canonical name cannot be longer than the incoming name.  */
2547   char *result = XNEWVEC (char, strlen (name) + 1);
2548   const char *base = name, *probe;
2549   char *ptr = result;
2550   char *dd_base;
2551   int slash = 0;
2552 
2553 #if HAVE_DOS_BASED_FILE_SYSTEM
2554   if (base[0] && base[1] == ':')
2555     {
2556       result[0] = base[0];
2557       result[1] = ':';
2558       base += 2;
2559       ptr += 2;
2560     }
2561 #endif
2562   for (dd_base = ptr; *base; base = probe)
2563     {
2564       size_t len;
2565 
2566       for (probe = base; *probe; probe++)
2567 	if (IS_DIR_SEPARATOR (*probe))
2568 	  break;
2569 
2570       len = probe - base;
2571       if (len == 1 && base[0] == '.')
2572 	/* Elide a '.' directory */
2573 	;
2574       else if (len == 2 && base[0] == '.' && base[1] == '.')
2575 	{
2576 	  /* '..', we can only elide it and the previous directory, if
2577 	     we're not a symlink.  */
2578 	  struct stat ATTRIBUTE_UNUSED buf;
2579 
2580 	  *ptr = 0;
2581 	  if (dd_base == ptr
2582 #if defined (S_ISLNK)
2583 	      /* S_ISLNK is not POSIX.1-1996.  */
2584 	      || stat (result, &buf) || S_ISLNK (buf.st_mode)
2585 #endif
2586 		)
2587 	    {
2588 	      /* Cannot elide, or unreadable or a symlink.  */
2589 	      dd_base = ptr + 2 + slash;
2590 	      goto regular;
2591 	    }
2592 	  while (ptr != dd_base && *ptr != '/')
2593 	    ptr--;
2594 	  slash = ptr != result;
2595 	}
2596       else
2597 	{
2598 	regular:
2599 	  /* Regular pathname component.  */
2600 	  if (slash)
2601 	    *ptr++ = '/';
2602 	  memcpy (ptr, base, len);
2603 	  ptr += len;
2604 	  slash = 1;
2605 	}
2606 
2607       for (; IS_DIR_SEPARATOR (*probe); probe++)
2608 	continue;
2609     }
2610   *ptr = 0;
2611 
2612   return result;
2613 }
2614 
2615 /* Generate an output file name. INPUT_NAME is the canonicalized main
2616    input file and SRC_NAME is the canonicalized file name.
2617    LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation.  With
2618    long_output_names we prepend the processed name of the input file
2619    to each output name (except when the current source file is the
2620    input file, so you don't get a double concatenation). The two
2621    components are separated by '##'.  With preserve_paths we create a
2622    filename from all path components of the source file, replacing '/'
2623    with '#', and .. with '^', without it we simply take the basename
2624    component.  (Remember, the canonicalized name will already have
2625    elided '.' components and converted \\ separators.)  */
2626 
2627 static string
make_gcov_file_name(const char * input_name,const char * src_name)2628 make_gcov_file_name (const char *input_name, const char *src_name)
2629 {
2630   string str;
2631 
2632   /* When hashing filenames, we shorten them by only using the filename
2633      component and appending a hash of the full (mangled) pathname.  */
2634   if (flag_hash_filenames)
2635     str = (string (mangle_name (src_name)) + "##"
2636 	   + get_md5sum (src_name) + ".gcov");
2637   else
2638     {
2639       if (flag_long_names && input_name && strcmp (src_name, input_name) != 0)
2640 	{
2641 	  str += mangle_name (input_name);
2642 	  str += "##";
2643 	}
2644 
2645       str += mangle_name (src_name);
2646       str += ".gcov";
2647     }
2648 
2649   return str;
2650 }
2651 
2652 /* Mangle BASE name, copy it at the beginning of PTR buffer and
2653    return address of the \0 character of the buffer.  */
2654 
2655 static char *
mangle_name(char const * base)2656 mangle_name (char const *base)
2657 {
2658   /* Generate the source filename part.  */
2659   if (!flag_preserve_paths)
2660     return xstrdup (lbasename (base));
2661   else
2662     return mangle_path (base);
2663 }
2664 
2665 /* Scan through the bb_data for each line in the block, increment
2666    the line number execution count indicated by the execution count of
2667    the appropriate basic block.  */
2668 
2669 static void
add_line_counts(coverage_info * coverage,function_info * fn)2670 add_line_counts (coverage_info *coverage, function_info *fn)
2671 {
2672   bool has_any_line = false;
2673   /* Scan each basic block.  */
2674   for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
2675     {
2676       line_info *line = NULL;
2677       block_info *block = &fn->blocks[ix];
2678       if (block->count && ix && ix + 1 != fn->blocks.size ())
2679 	fn->blocks_executed++;
2680       for (unsigned i = 0; i < block->locations.size (); i++)
2681 	{
2682 	  unsigned src_idx = block->locations[i].source_file_idx;
2683 	  vector<unsigned> &lines = block->locations[i].lines;
2684 
2685 	  block->cycle.arc = NULL;
2686 	  block->cycle.ident = ~0U;
2687 
2688 	  for (unsigned j = 0; j < lines.size (); j++)
2689 	    {
2690 	      unsigned ln = lines[j];
2691 
2692 	      /* Line belongs to a function that is in a group.  */
2693 	      if (fn->group_line_p (ln, src_idx))
2694 		{
2695 		  gcc_assert (lines[j] - fn->start_line < fn->lines.size ());
2696 		  line = &(fn->lines[lines[j] - fn->start_line]);
2697 		  line->exists = 1;
2698 		  if (!block->exceptional)
2699 		    {
2700 		      line->unexceptional = 1;
2701 		      if (block->count == 0)
2702 			line->has_unexecuted_block = 1;
2703 		    }
2704 		  line->count += block->count;
2705 		}
2706 	      else
2707 		{
2708 		  gcc_assert (ln < sources[src_idx].lines.size ());
2709 		  line = &(sources[src_idx].lines[ln]);
2710 		  if (coverage)
2711 		    {
2712 		      if (!line->exists)
2713 			coverage->lines++;
2714 		      if (!line->count && block->count)
2715 			coverage->lines_executed++;
2716 		    }
2717 		  line->exists = 1;
2718 		  if (!block->exceptional)
2719 		    {
2720 		      line->unexceptional = 1;
2721 		      if (block->count == 0)
2722 			line->has_unexecuted_block = 1;
2723 		    }
2724 		  line->count += block->count;
2725 		}
2726 	    }
2727 
2728 	  has_any_line = true;
2729 
2730 	  if (!ix || ix + 1 == fn->blocks.size ())
2731 	    /* Entry or exit block.  */;
2732 	  else if (line != NULL)
2733 	    {
2734 	      line->blocks.push_back (block);
2735 
2736 	      if (flag_branches)
2737 		{
2738 		  arc_info *arc;
2739 
2740 		  for (arc = block->succ; arc; arc = arc->succ_next)
2741 		    line->branches.push_back (arc);
2742 		}
2743 	    }
2744 	}
2745     }
2746 
2747   if (!has_any_line)
2748     fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name,
2749 	     fn->get_name ());
2750 }
2751 
2752 /* Accumulate info for LINE that belongs to SRC source file.  If ADD_COVERAGE
2753    is set to true, update source file summary.  */
2754 
accumulate_line_info(line_info * line,source_info * src,bool add_coverage)2755 static void accumulate_line_info (line_info *line, source_info *src,
2756 				  bool add_coverage)
2757 {
2758   if (add_coverage)
2759     for (vector<arc_info *>::iterator it = line->branches.begin ();
2760 	 it != line->branches.end (); it++)
2761       add_branch_counts (&src->coverage, *it);
2762 
2763   if (!line->blocks.empty ())
2764     {
2765       /* The user expects the line count to be the number of times
2766 	 a line has been executed.  Simply summing the block count
2767 	 will give an artificially high number.  The Right Thing
2768 	 is to sum the entry counts to the graph of blocks on this
2769 	 line, then find the elementary cycles of the local graph
2770 	 and add the transition counts of those cycles.  */
2771       gcov_type count = 0;
2772 
2773       /* Cycle detection.  */
2774       for (vector<block_info *>::iterator it = line->blocks.begin ();
2775 	   it != line->blocks.end (); it++)
2776 	{
2777 	  for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next)
2778 	    if (!line->has_block (arc->src))
2779 	      count += arc->count;
2780 	  for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next)
2781 	    arc->cs_count = arc->count;
2782 	}
2783 
2784       /* Now, add the count of loops entirely on this line.  */
2785       count += get_cycles_count (*line);
2786       line->count = count;
2787 
2788       if (line->count > src->maximum_count)
2789 	src->maximum_count = line->count;
2790     }
2791 
2792   if (line->exists && add_coverage)
2793     {
2794       src->coverage.lines++;
2795       if (line->count)
2796 	src->coverage.lines_executed++;
2797     }
2798 }
2799 
2800 /* Accumulate the line counts of a file.  */
2801 
2802 static void
accumulate_line_counts(source_info * src)2803 accumulate_line_counts (source_info *src)
2804 {
2805   /* First work on group functions.  */
2806   for (vector<function_info *>::iterator it = src->functions.begin ();
2807        it != src->functions.end (); it++)
2808     {
2809       function_info *fn = *it;
2810 
2811       if (fn->src != src->index || !fn->is_group)
2812 	continue;
2813 
2814       for (vector<line_info>::iterator it2 = fn->lines.begin ();
2815 	   it2 != fn->lines.end (); it2++)
2816 	  {
2817 	    line_info *line = &(*it2);
2818 	    accumulate_line_info (line, src, false);
2819 	  }
2820     }
2821 
2822   /* Work on global lines that line in source file SRC.  */
2823   for (vector<line_info>::iterator it = src->lines.begin ();
2824        it != src->lines.end (); it++)
2825     accumulate_line_info (&(*it), src, true);
2826 
2827   /* If not using intermediate mode, sum lines of group functions and
2828      add them to lines that live in a source file.  */
2829   if (!flag_json_format)
2830     for (vector<function_info *>::iterator it = src->functions.begin ();
2831 	 it != src->functions.end (); it++)
2832       {
2833 	function_info *fn = *it;
2834 
2835 	if (fn->src != src->index || !fn->is_group)
2836 	  continue;
2837 
2838 	for (unsigned i = 0; i < fn->lines.size (); i++)
2839 	  {
2840 	    line_info *fn_line = &fn->lines[i];
2841 	    if (fn_line->exists)
2842 	      {
2843 		unsigned ln = fn->start_line + i;
2844 		line_info *src_line = &src->lines[ln];
2845 
2846 		if (!src_line->exists)
2847 		  src->coverage.lines++;
2848 		if (!src_line->count && fn_line->count)
2849 		  src->coverage.lines_executed++;
2850 
2851 		src_line->count += fn_line->count;
2852 		src_line->exists = 1;
2853 
2854 		if (fn_line->has_unexecuted_block)
2855 		  src_line->has_unexecuted_block = 1;
2856 
2857 		if (fn_line->unexceptional)
2858 		  src_line->unexceptional = 1;
2859 	      }
2860 	  }
2861       }
2862 }
2863 
2864 /* Output information about ARC number IX.  Returns nonzero if
2865    anything is output.  */
2866 
2867 static int
output_branch_count(FILE * gcov_file,int ix,const arc_info * arc)2868 output_branch_count (FILE *gcov_file, int ix, const arc_info *arc)
2869 {
2870   if (arc->is_call_non_return)
2871     {
2872       if (arc->src->count)
2873 	{
2874 	  fnotice (gcov_file, "call   %2d returned %s\n", ix,
2875 		   format_gcov (arc->src->count - arc->count,
2876 				arc->src->count, -flag_counts));
2877 	}
2878       else
2879 	fnotice (gcov_file, "call   %2d never executed\n", ix);
2880     }
2881   else if (!arc->is_unconditional)
2882     {
2883       if (arc->src->count)
2884 	fnotice (gcov_file, "branch %2d taken %s%s", ix,
2885 		 format_gcov (arc->count, arc->src->count, -flag_counts),
2886 		 arc->fall_through ? " (fallthrough)"
2887 		 : arc->is_throw ? " (throw)" : "");
2888       else
2889 	fnotice (gcov_file, "branch %2d never executed", ix);
2890 
2891       if (flag_verbose)
2892 	fnotice (gcov_file, " (BB %d)", arc->dst->id);
2893 
2894       fnotice (gcov_file, "\n");
2895     }
2896   else if (flag_unconditional && !arc->dst->is_call_return)
2897     {
2898       if (arc->src->count)
2899 	fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
2900 		 format_gcov (arc->count, arc->src->count, -flag_counts));
2901       else
2902 	fnotice (gcov_file, "unconditional %2d never executed\n", ix);
2903     }
2904   else
2905     return 0;
2906   return 1;
2907 }
2908 
2909 static const char *
read_line(FILE * file)2910 read_line (FILE *file)
2911 {
2912   static char *string;
2913   static size_t string_len;
2914   size_t pos = 0;
2915 
2916   if (!string_len)
2917     {
2918       string_len = 200;
2919       string = XNEWVEC (char, string_len);
2920     }
2921 
2922   while (fgets (string + pos, string_len - pos, file))
2923     {
2924       size_t len = strlen (string + pos);
2925 
2926       if (len && string[pos + len - 1] == '\n')
2927 	{
2928 	  string[pos + len - 1] = 0;
2929 	  return string;
2930 	}
2931       pos += len;
2932       /* If the file contains NUL characters or an incomplete
2933 	 last line, which can happen more than once in one run,
2934 	 we have to avoid doubling the STRING_LEN unnecessarily.  */
2935       if (pos > string_len / 2)
2936 	{
2937 	  string_len *= 2;
2938 	  string = XRESIZEVEC (char, string, string_len);
2939 	}
2940     }
2941 
2942   return pos ? string : NULL;
2943 }
2944 
2945 /* Pad string S with spaces from left to have total width equal to 9.  */
2946 
2947 static void
pad_count_string(string & s)2948 pad_count_string (string &s)
2949 {
2950   if (s.size () < 9)
2951     s.insert (0, 9 - s.size (), ' ');
2952 }
2953 
2954 /* Print GCOV line beginning to F stream.  If EXISTS is set to true, the
2955    line exists in source file.  UNEXCEPTIONAL indicated that it's not in
2956    an exceptional statement.  The output is printed for LINE_NUM of given
2957    COUNT of executions.  EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
2958    used to indicate non-executed blocks.  */
2959 
2960 static void
output_line_beginning(FILE * f,bool exists,bool unexceptional,bool has_unexecuted_block,gcov_type count,unsigned line_num,const char * exceptional_string,const char * unexceptional_string,unsigned int maximum_count)2961 output_line_beginning (FILE *f, bool exists, bool unexceptional,
2962 		       bool has_unexecuted_block,
2963 		       gcov_type count, unsigned line_num,
2964 		       const char *exceptional_string,
2965 		       const char *unexceptional_string,
2966 		       unsigned int maximum_count)
2967 {
2968   string s;
2969   if (exists)
2970     {
2971       if (count > 0)
2972 	{
2973 	  s = format_gcov (count, 0, -1);
2974 	  if (has_unexecuted_block
2975 	      && bbg_supports_has_unexecuted_blocks)
2976 	    {
2977 	      if (flag_use_colors)
2978 		{
2979 		  pad_count_string (s);
2980 		  s.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
2981 					COLOR_SEPARATOR COLOR_FG_WHITE));
2982 		  s += SGR_RESET;
2983 		}
2984 	      else
2985 		s += "*";
2986 	    }
2987 	  pad_count_string (s);
2988 	}
2989       else
2990 	{
2991 	  if (flag_use_colors)
2992 	    {
2993 	      s = "0";
2994 	      pad_count_string (s);
2995 	      if (unexceptional)
2996 		s.insert (0, SGR_SEQ (COLOR_BG_RED
2997 				      COLOR_SEPARATOR COLOR_FG_WHITE));
2998 	      else
2999 		s.insert (0, SGR_SEQ (COLOR_BG_CYAN
3000 				      COLOR_SEPARATOR COLOR_FG_WHITE));
3001 	      s += SGR_RESET;
3002 	    }
3003 	  else
3004 	    {
3005 	      s = unexceptional ? unexceptional_string : exceptional_string;
3006 	      pad_count_string (s);
3007 	    }
3008 	}
3009     }
3010   else
3011     {
3012       s = "-";
3013       pad_count_string (s);
3014     }
3015 
3016   /* Format line number in output.  */
3017   char buffer[16];
3018   sprintf (buffer, "%5u", line_num);
3019   string linestr (buffer);
3020 
3021   if (flag_use_hotness_colors && maximum_count)
3022     {
3023       if (count * 2 > maximum_count) /* > 50%.  */
3024 	linestr.insert (0, SGR_SEQ (COLOR_BG_RED));
3025       else if (count * 5 > maximum_count) /* > 20%.  */
3026 	linestr.insert (0, SGR_SEQ (COLOR_BG_YELLOW));
3027       else if (count * 10 > maximum_count) /* > 10%.  */
3028 	linestr.insert (0, SGR_SEQ (COLOR_BG_GREEN));
3029       linestr += SGR_RESET;
3030     }
3031 
3032   fprintf (f, "%s:%s", s.c_str (), linestr.c_str ());
3033 }
3034 
3035 static void
print_source_line(FILE * f,const vector<const char * > & source_lines,unsigned line)3036 print_source_line (FILE *f, const vector<const char *> &source_lines,
3037 		   unsigned line)
3038 {
3039   gcc_assert (line >= 1);
3040   gcc_assert (line <= source_lines.size ());
3041 
3042   fprintf (f, ":%s\n", source_lines[line - 1]);
3043 }
3044 
3045 /* Output line details for LINE and print it to F file.  LINE lives on
3046    LINE_NUM.  */
3047 
3048 static void
output_line_details(FILE * f,const line_info * line,unsigned line_num)3049 output_line_details (FILE *f, const line_info *line, unsigned line_num)
3050 {
3051   if (flag_all_blocks)
3052     {
3053       arc_info *arc;
3054       int ix, jx;
3055 
3056       ix = jx = 0;
3057       for (vector<block_info *>::const_iterator it = line->blocks.begin ();
3058 	   it != line->blocks.end (); it++)
3059 	{
3060 	  if (!(*it)->is_call_return)
3061 	    {
3062 	      output_line_beginning (f, line->exists,
3063 				     (*it)->exceptional, false,
3064 				     (*it)->count, line_num,
3065 				     "%%%%%", "$$$$$", 0);
3066 	      fprintf (f, "-block %2d", ix++);
3067 	      if (flag_verbose)
3068 		fprintf (f, " (BB %u)", (*it)->id);
3069 	      fprintf (f, "\n");
3070 	    }
3071 	  if (flag_branches)
3072 	    for (arc = (*it)->succ; arc; arc = arc->succ_next)
3073 	      jx += output_branch_count (f, jx, arc);
3074 	}
3075     }
3076   else if (flag_branches)
3077     {
3078       int ix;
3079 
3080       ix = 0;
3081       for (vector<arc_info *>::const_iterator it = line->branches.begin ();
3082 	   it != line->branches.end (); it++)
3083 	ix += output_branch_count (f, ix, (*it));
3084     }
3085 }
3086 
3087 /* Output detail statistics about function FN to file F.  */
3088 
3089 static void
output_function_details(FILE * f,function_info * fn)3090 output_function_details (FILE *f, function_info *fn)
3091 {
3092   if (!flag_branches)
3093     return;
3094 
3095   arc_info *arc = fn->blocks[EXIT_BLOCK].pred;
3096   gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
3097   gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
3098 
3099   for (; arc; arc = arc->pred_next)
3100     if (arc->fake)
3101       return_count -= arc->count;
3102 
3103   fprintf (f, "function %s", fn->get_name ());
3104   fprintf (f, " called %s",
3105 	   format_gcov (called_count, 0, -1));
3106   fprintf (f, " returned %s",
3107 	   format_gcov (return_count, called_count, 0));
3108   fprintf (f, " blocks executed %s",
3109 	   format_gcov (fn->blocks_executed, fn->get_block_count (), 0));
3110   fprintf (f, "\n");
3111 }
3112 
3113 /* Read in the source file one line at a time, and output that line to
3114    the gcov file preceded by its execution count and other
3115    information.  */
3116 
3117 static void
output_lines(FILE * gcov_file,const source_info * src)3118 output_lines (FILE *gcov_file, const source_info *src)
3119 {
3120 #define  DEFAULT_LINE_START "        -:    0:"
3121 #define FN_SEPARATOR "------------------\n"
3122 
3123   FILE *source_file;
3124   const char *retval;
3125 
3126   /* Print colorization legend.  */
3127   if (flag_use_colors)
3128     fprintf (gcov_file, "%s",
3129 	     DEFAULT_LINE_START "Colorization: profile count: " \
3130 	     SGR_SEQ (COLOR_BG_CYAN) "zero coverage (exceptional)" SGR_RESET \
3131 	     " " \
3132 	     SGR_SEQ (COLOR_BG_RED) "zero coverage (unexceptional)" SGR_RESET \
3133 	     " " \
3134 	     SGR_SEQ (COLOR_BG_MAGENTA) "unexecuted block" SGR_RESET "\n");
3135 
3136   if (flag_use_hotness_colors)
3137     fprintf (gcov_file, "%s",
3138 	     DEFAULT_LINE_START "Colorization: line numbers: hotness: " \
3139 	     SGR_SEQ (COLOR_BG_RED) "> 50%" SGR_RESET " " \
3140 	     SGR_SEQ (COLOR_BG_YELLOW) "> 20%" SGR_RESET " " \
3141 	     SGR_SEQ (COLOR_BG_GREEN) "> 10%" SGR_RESET "\n");
3142 
3143   fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
3144   if (!multiple_files)
3145     {
3146       fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
3147       fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
3148 	       no_data_file ? "-" : da_file_name);
3149       fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
3150     }
3151 
3152   source_file = fopen (src->name, "r");
3153   if (!source_file)
3154     fnotice (stderr, "Cannot open source file %s\n", src->name);
3155   else if (src->file_time == 0)
3156     fprintf (gcov_file, DEFAULT_LINE_START "Source is newer than graph\n");
3157 
3158   vector<const char *> source_lines;
3159   if (source_file)
3160     while ((retval = read_line (source_file)) != NULL)
3161       source_lines.push_back (xstrdup (retval));
3162 
3163   unsigned line_start_group = 0;
3164   vector<function_info *> *fns;
3165 
3166   for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
3167     {
3168       if (line_num >= src->lines.size ())
3169 	{
3170 	  fprintf (gcov_file, "%9s:%5u", "-", line_num);
3171 	  print_source_line (gcov_file, source_lines, line_num);
3172 	  continue;
3173 	}
3174 
3175       const line_info *line = &src->lines[line_num];
3176 
3177       if (line_start_group == 0)
3178 	{
3179 	  fns = src->get_functions_at_location (line_num);
3180 	  if (fns != NULL && fns->size () > 1)
3181 	    {
3182 	      /* It's possible to have functions that partially overlap,
3183 		 thus take the maximum end_line of functions starting
3184 		 at LINE_NUM.  */
3185 	      for (unsigned i = 0; i < fns->size (); i++)
3186 		if ((*fns)[i]->end_line > line_start_group)
3187 		  line_start_group = (*fns)[i]->end_line;
3188 	    }
3189 	  else if (fns != NULL && fns->size () == 1)
3190 	    {
3191 	      function_info *fn = (*fns)[0];
3192 	      output_function_details (gcov_file, fn);
3193 	    }
3194 	}
3195 
3196       /* For lines which don't exist in the .bb file, print '-' before
3197 	 the source line.  For lines which exist but were never
3198 	 executed, print '#####' or '=====' before the source line.
3199 	 Otherwise, print the execution count before the source line.
3200 	 There are 16 spaces of indentation added before the source
3201 	 line so that tabs won't be messed up.  */
3202       output_line_beginning (gcov_file, line->exists, line->unexceptional,
3203 			     line->has_unexecuted_block, line->count,
3204 			     line_num, "=====", "#####", src->maximum_count);
3205 
3206       print_source_line (gcov_file, source_lines, line_num);
3207       output_line_details (gcov_file, line, line_num);
3208 
3209       if (line_start_group == line_num)
3210 	{
3211 	  for (vector<function_info *>::iterator it = fns->begin ();
3212 	       it != fns->end (); it++)
3213 	    {
3214 	      function_info *fn = *it;
3215 	      vector<line_info> &lines = fn->lines;
3216 
3217 	      fprintf (gcov_file, FN_SEPARATOR);
3218 
3219 	      string fn_name = fn->get_name ();
3220 	      if (flag_use_colors)
3221 		{
3222 		  fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN));
3223 		  fn_name += SGR_RESET;
3224 		}
3225 
3226 	      fprintf (gcov_file, "%s:\n", fn_name.c_str ());
3227 
3228 	      output_function_details (gcov_file, fn);
3229 
3230 	      /* Print all lines covered by the function.  */
3231 	      for (unsigned i = 0; i < lines.size (); i++)
3232 		{
3233 		  line_info *line = &lines[i];
3234 		  unsigned l = fn->start_line + i;
3235 
3236 		  /* For lines which don't exist in the .bb file, print '-'
3237 		     before the source line.  For lines which exist but
3238 		     were never executed, print '#####' or '=====' before
3239 		     the source line.  Otherwise, print the execution count
3240 		     before the source line.
3241 		     There are 16 spaces of indentation added before the source
3242 		     line so that tabs won't be messed up.  */
3243 		  output_line_beginning (gcov_file, line->exists,
3244 					 line->unexceptional,
3245 					 line->has_unexecuted_block,
3246 					 line->count,
3247 					 l, "=====", "#####",
3248 					 src->maximum_count);
3249 
3250 		  print_source_line (gcov_file, source_lines, l);
3251 		  output_line_details (gcov_file, line, l);
3252 		}
3253 	    }
3254 
3255 	  fprintf (gcov_file, FN_SEPARATOR);
3256 	  line_start_group = 0;
3257 	}
3258     }
3259 
3260   if (source_file)
3261     fclose (source_file);
3262 }
3263