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