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