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