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