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