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