Line data Source code
1 : /* Gcov.c: prepend line execution counts and branch probabilities to a
2 : source file.
3 : Copyright (C) 1990-2026 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 : #include "hwint.h"
50 : #include "xregex.h"
51 : #include "graphds.h"
52 :
53 : #include <zlib.h>
54 : #include <getopt.h>
55 :
56 : #include "md5.h"
57 :
58 : using namespace std;
59 :
60 : #define IN_GCOV 1
61 : #include "gcov-io.h"
62 : #include "gcov-io.cc"
63 :
64 : #define GCOV_JSON_FORMAT_VERSION "2"
65 :
66 : /* The gcno file is generated by -ftest-coverage option. The gcda file is
67 : generated by a program compiled with -fprofile-arcs. Their formats
68 : are documented in gcov-io.h. */
69 :
70 : /* The functions in this file for creating and solution program flow graphs
71 : are very similar to functions in the gcc source file profile.cc. In
72 : some places we make use of the knowledge of how profile.cc works to
73 : select particular algorithms here. */
74 :
75 : /* The code validates that the profile information read in corresponds
76 : to the code currently being compiled. Rather than checking for
77 : identical files, the code below compares a checksum on the CFG
78 : (based on the order of basic blocks and the arcs in the CFG). If
79 : the CFG checksum in the gcda file match the CFG checksum in the
80 : gcno file, the profile data will be used. */
81 :
82 : /* This is the size of the buffer used to read in source file lines. */
83 :
84 : class function_info;
85 : class block_info;
86 : class source_info;
87 : class condition_info;
88 : class path_info;
89 :
90 : /* Describes an arc between two basic blocks. */
91 :
92 : struct arc_info
93 : {
94 : /* source and destination blocks. */
95 : class block_info *src;
96 : class block_info *dst;
97 :
98 : /* transition counts. */
99 : gcov_type count;
100 : /* used in cycle search, so that we do not clobber original counts. */
101 : gcov_type cs_count;
102 :
103 : unsigned int count_valid : 1;
104 : unsigned int on_tree : 1;
105 : unsigned int fake : 1;
106 : unsigned int fall_through : 1;
107 :
108 : /* Arc to a catch handler. */
109 : unsigned int is_throw : 1;
110 :
111 : /* Arc is for a function that abnormally returns. */
112 : unsigned int is_call_non_return : 1;
113 :
114 : /* Arc is for catch/setjmp. */
115 : unsigned int is_nonlocal_return : 1;
116 :
117 : /* Is an unconditional branch. */
118 : unsigned int is_unconditional : 1;
119 :
120 : /* Loop making arc. */
121 : unsigned int cycle : 1;
122 :
123 : /* Is a true arc. */
124 : unsigned int true_value : 1;
125 :
126 : /* Is a false arc. */
127 : unsigned int false_value : 1;
128 :
129 : /* Is suppressed arc by #pragma GCC suppress_coverage. */
130 : unsigned int suppressed : 1;
131 :
132 : /* Links to next arc on src and dst lists. */
133 : struct arc_info *succ_next;
134 : struct arc_info *pred_next;
135 : };
136 :
137 : /* Describes (prime) path coverage. */
138 : class path_info
139 : {
140 : public:
141 1450 : path_info () : paths (), covered () {}
142 :
143 : /* The prime paths of a function. The paths will be
144 : lexicographically ordered and identified by their index. */
145 : vector<vector<unsigned>> paths;
146 :
147 : /* The covered paths. This is really a large bitset partitioned
148 : into buckets of gcov_type_unsigned, and bit n is set if the nth
149 : path is covered. */
150 : vector<gcov_type_unsigned> covered;
151 :
152 : /* The prime paths after #pragma GCC suppress_coverage has been taken into
153 : account. This is empty unless something is suppressed, in which case it
154 : should be smaller than PATHS. The paths are lexicographically sorted. */
155 : vector<vector<unsigned>> residual_paths;
156 :
157 : /* The covered paths after #pragma GCC suppress_coverage has been taken into
158 : account. Like with COVERED, the bit N is set if the Nth path in
159 : RESIDUAL_PATHS is covered. */
160 : vector<gcov_type_unsigned> residual_covered;
161 :
162 : /* The size (in bits) of each bucket. */
163 : static const size_t
164 : bucketsize = sizeof (gcov_type_unsigned) * BITS_PER_UNIT;
165 :
166 : /* Helper for getting the right path set. */
167 3367 : const vector<vector<unsigned>>& get_paths () const
168 3360 : { return !suppressed_p () ? paths : residual_paths; }
169 :
170 : /* Get the number of paths, accounting for suppressed blocks. */
171 2758 : size_t path_count () const
172 2751 : { return get_paths ().size (); }
173 :
174 : /* Get the number of suppressed paths. This is 0 unless there is a #pragma
175 : GCC suppress_coverage somewhere. */
176 1379 : size_t suppressed_count () const
177 1379 : { return paths.size () - path_count (); }
178 :
179 : /* Check if any paths suppressed by #pragma GCC suppress_coverage. */
180 7233 : bool suppressed_p () const
181 1379 : { return !residual_paths.empty (); }
182 :
183 : /* Count the covered paths, accounting for #pragma GCC suppress_coverage. */
184 1647 : unsigned covered_paths () const
185 : {
186 1647 : unsigned cnt = 0;
187 2225 : for (gcov_type_unsigned v : (!suppressed_p () ? covered : residual_covered))
188 578 : cnt += popcount_hwi (v);
189 1647 : return cnt;
190 : }
191 :
192 : /* Check if the nth path is covered. */
193 1944 : bool covered_p (size_t n) const
194 : {
195 1944 : if (covered.empty ())
196 : return false;
197 :
198 1944 : const auto& cov = !suppressed_p () ? covered : residual_covered;
199 1944 : const size_t bucket = n / bucketsize;
200 1944 : const uint64_t bit = n % bucketsize;
201 1944 : return cov[bucket] & (gcov_type_unsigned (1) << bit);
202 : }
203 :
204 : void suppress_blocks (const vector<bool>& suppressed);
205 : };
206 :
207 : /* Describes which locations (lines and files) are associated with
208 : a basic block. */
209 :
210 18755 : class block_location_info
211 : {
212 : public:
213 9454 : block_location_info (unsigned _source_file_idx):
214 9454 : source_file_idx (_source_file_idx)
215 : {}
216 :
217 : unsigned source_file_idx;
218 : vector<unsigned> lines;
219 : };
220 :
221 : /* Describes a single conditional expression and the (recorded) conditions
222 : shown to independently affect the outcome. */
223 : class condition_info
224 : {
225 : public:
226 : condition_info ();
227 :
228 : int popcount () const;
229 :
230 : /* Bitsets storing the independently significant outcomes for true and false,
231 : respectively. */
232 : gcov_type_unsigned truev;
233 : gcov_type_unsigned falsev;
234 :
235 : /* Number of terms in the expression; if (x) -> 1, if (x && y) -> 2 etc. */
236 : unsigned n_terms;
237 : };
238 :
239 12816 : condition_info::condition_info (): truev (0), falsev (0), n_terms (0)
240 : {
241 12816 : }
242 :
243 7546 : int condition_info::popcount () const
244 : {
245 7546 : return popcount_hwi (truev) + popcount_hwi (falsev);
246 : }
247 :
248 : /* Describes a basic block. Contains lists of arcs to successor and
249 : predecessor blocks. */
250 :
251 12411 : class block_info
252 : {
253 : public:
254 : /* Constructor. */
255 : block_info ();
256 :
257 : /* Chain of exit and entry arcs. */
258 : arc_info *succ;
259 : arc_info *pred;
260 :
261 : /* Number of unprocessed exit and entry arcs. */
262 : gcov_type num_succ;
263 : gcov_type num_pred;
264 :
265 : unsigned id;
266 :
267 : /* Block execution count. */
268 : gcov_type count;
269 : unsigned count_valid : 1;
270 : unsigned valid_chain : 1;
271 : unsigned invalid_chain : 1;
272 : unsigned exceptional : 1;
273 :
274 : /* Block is a call instrumenting site. */
275 : unsigned is_call_site : 1; /* Does the call. */
276 : unsigned is_call_return : 1; /* Is the return. */
277 :
278 : /* Block is a landing pad for longjmp or throw. */
279 : unsigned is_nonlocal_return : 1;
280 :
281 : /* Block is suppressed by #pragma GCC suppress_coverage. */
282 : unsigned suppressed : 1;
283 :
284 : condition_info conditions;
285 :
286 : vector<block_location_info> locations;
287 :
288 : struct
289 : {
290 : /* Single line graph cycle workspace. Used for all-blocks
291 : mode. */
292 : arc_info *arc;
293 : unsigned ident;
294 : } cycle; /* Used in all-blocks mode, after blocks are linked onto
295 : lines. */
296 :
297 : /* Temporary chain for solving graph, and for chaining blocks on one
298 : line. */
299 : class block_info *chain;
300 :
301 : };
302 :
303 12816 : block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0),
304 12816 : id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
305 12816 : exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
306 12816 : suppressed (0), locations (), chain (NULL)
307 : {
308 12816 : cycle.arc = NULL;
309 12816 : }
310 :
311 : /* Describes a single line of source. Contains a chain of basic blocks
312 : with code on it. */
313 :
314 99623 : class line_info
315 : {
316 : public:
317 : /* Default constructor. */
318 : line_info ();
319 :
320 : /* Return true when NEEDLE is one of basic blocks the line belongs to. */
321 : bool has_block (block_info *needle);
322 :
323 : /* Execution count. */
324 : gcov_type count;
325 :
326 : /* Branches from blocks that end on this line. */
327 : vector<arc_info *> branches;
328 :
329 : /* blocks which start on this line. Used in all-blocks mode. */
330 : vector<block_info *> blocks;
331 :
332 : unsigned exists : 1;
333 : unsigned unexceptional : 1;
334 : unsigned has_unexecuted_block : 1;
335 : /* Suppressed by #pragma GCC suppress_coverage. */
336 : unsigned suppressed : 1;
337 : };
338 :
339 53999 : line_info::line_info (): count (0), branches (), blocks (), exists (false),
340 53999 : unexceptional (0), has_unexecuted_block (0), suppressed (0)
341 : {
342 53999 : }
343 :
344 : bool
345 22253 : line_info::has_block (block_info *needle)
346 : {
347 22253 : return std::find (blocks.begin (), blocks.end (), needle) != blocks.end ();
348 : }
349 :
350 : /* Output demangled function names. */
351 :
352 : static int flag_demangled_names = 0;
353 :
354 : /* Describes a single function. Contains an array of basic blocks. */
355 :
356 : class function_info
357 : {
358 : public:
359 : function_info ();
360 : ~function_info ();
361 :
362 : /* Return true when line N belongs to the function in source file SRC_IDX.
363 : The line must be defined in body of the function, can't be inlined. */
364 : bool group_line_p (unsigned n, unsigned src_idx);
365 :
366 : /* Function filter based on function_info::artificial variable. */
367 :
368 : static inline bool
369 1408 : is_artificial (function_info *fn)
370 : {
371 1408 : return fn->artificial;
372 : }
373 :
374 : /* Name of function. */
375 : char *m_name;
376 : char *m_demangled_name;
377 : unsigned ident;
378 : unsigned lineno_checksum;
379 : unsigned cfg_checksum;
380 :
381 : /* The graph contains at least one fake incoming edge. */
382 : unsigned has_catch : 1;
383 :
384 : /* True when the function is artificial and does not exist
385 : in a source file. */
386 : unsigned artificial : 1;
387 :
388 : /* True when multiple functions start at a line in a source file. */
389 : unsigned is_group : 1;
390 :
391 : /* Array of basic blocks. Like in GCC, the entry block is
392 : at blocks[0] and the exit block is at blocks[1]. */
393 : #define ENTRY_BLOCK (0)
394 : #define EXIT_BLOCK (1)
395 : vector<block_info> blocks;
396 : unsigned blocks_executed;
397 :
398 : vector<condition_info*> conditions;
399 :
400 : /* Path coverage information. */
401 : path_info paths;
402 :
403 : /* Raw arc coverage counts. */
404 : vector<gcov_type> counts;
405 :
406 : /* First line number. */
407 : unsigned start_line;
408 :
409 : /* First line column. */
410 : unsigned start_column;
411 :
412 : /* Last line number. */
413 : unsigned end_line;
414 :
415 : /* Last line column. */
416 : unsigned end_column;
417 :
418 : /* Index of source file where the function is defined. */
419 : unsigned src;
420 :
421 : /* Vector of line information (used only for group functions). */
422 : vector<line_info> lines;
423 :
424 : /* Next function. */
425 : class function_info *next;
426 :
427 : /* Blocks suppressed by #pragma GCC suppress_coverage. If any block is
428 : suppressed this is non-empty, and the Nth bit is true if N is suppressed.
429 : If suppressed_blocks[0] is true, the whole function is suppressed. */
430 : vector<bool> suppressed_blocks;
431 :
432 : /* Get demangled name of a function. The demangled name
433 : is converted when it is used for the first time. */
434 21 : char *get_demangled_name ()
435 : {
436 21 : if (m_demangled_name == NULL)
437 : {
438 21 : m_demangled_name = cplus_demangle (m_name, DMGL_PARAMS);
439 21 : if (!m_demangled_name)
440 5 : m_demangled_name = m_name;
441 : }
442 :
443 21 : return m_demangled_name;
444 : }
445 :
446 : /* Get name of the function based on flag_demangled_names. */
447 1692 : char *get_name ()
448 : {
449 1692 : return flag_demangled_names ? get_demangled_name () : m_name;
450 : }
451 :
452 : /* Return number of basic blocks (without entry and exit block). */
453 170 : unsigned get_block_count ()
454 : {
455 340 : return blocks.size () - 2;
456 : }
457 :
458 11715 : bool suppressed_p () const
459 : {
460 13966 : return !suppressed_blocks.empty () && suppressed_blocks.front ();
461 : }
462 : };
463 :
464 : /* Function info comparer that will sort functions according to starting
465 : line. */
466 :
467 : struct function_line_start_cmp
468 : {
469 212 : inline bool operator() (const function_info *lhs,
470 : const function_info *rhs)
471 : {
472 212 : return (lhs->start_line == rhs->start_line
473 212 : ? lhs->start_column < rhs->start_column
474 212 : : lhs->start_line < rhs->start_line);
475 : }
476 : };
477 :
478 : /* Describes coverage of a file or function. */
479 :
480 : struct coverage_info
481 : {
482 : int function_suppressed;
483 :
484 : int lines;
485 : int lines_executed;
486 : int lines_suppressed;
487 :
488 : int branches;
489 : int branches_executed;
490 : int branches_taken;
491 : int branches_suppressed;
492 :
493 : int conditions;
494 : int conditions_covered;
495 : int conditions_suppressed;
496 :
497 : int calls;
498 : int calls_executed;
499 : int calls_suppressed;
500 :
501 : char *name;
502 :
503 : unsigned paths;
504 : unsigned paths_covered;
505 : unsigned paths_suppressed;
506 : };
507 :
508 : /* Describes a file mentioned in the block graph. Contains an array
509 : of line info. */
510 :
511 : class source_info
512 : {
513 : public:
514 : /* Default constructor. */
515 : source_info ();
516 :
517 : vector<function_info *> *get_functions_at_location (unsigned line_num) const;
518 :
519 : /* Register a new function. */
520 : void add_function (function_info *fn);
521 :
522 : /* Debug the source file. */
523 : void debug ();
524 :
525 : /* Index of the source_info in sources vector. */
526 : unsigned index;
527 :
528 : /* Canonical name of source file. */
529 : char *name;
530 : time_t file_time;
531 :
532 : /* Vector of line information. */
533 : vector<line_info> lines;
534 :
535 : coverage_info coverage;
536 :
537 : /* Maximum line count in the source file. */
538 : unsigned int maximum_count;
539 :
540 : /* Functions in this source file. These are in ascending line
541 : number order. */
542 : vector<function_info *> functions;
543 :
544 : /* Line number to functions map. */
545 : vector<vector<function_info *> *> line_to_function_map;
546 : };
547 :
548 238 : source_info::source_info (): index (0), name (NULL), file_time (),
549 238 : lines (), coverage (), maximum_count (0), functions ()
550 : {
551 238 : }
552 :
553 : /* Register a new function. */
554 : void
555 1363 : source_info::add_function (function_info *fn)
556 : {
557 1363 : functions.push_back (fn);
558 :
559 1363 : if (fn->start_line >= line_to_function_map.size ())
560 269 : line_to_function_map.resize (fn->start_line + 1);
561 :
562 1363 : vector<function_info *> **slot = &line_to_function_map[fn->start_line];
563 1363 : if (*slot == NULL)
564 1256 : *slot = new vector<function_info *> ();
565 :
566 1363 : (*slot)->push_back (fn);
567 1363 : }
568 :
569 : vector<function_info *> *
570 51578 : source_info::get_functions_at_location (unsigned line_num) const
571 : {
572 51578 : if (line_num >= line_to_function_map.size ())
573 : return NULL;
574 :
575 39394 : vector<function_info *> *slot = line_to_function_map[line_num];
576 39394 : if (slot != NULL)
577 1243 : std::sort (slot->begin (), slot->end (), function_line_start_cmp ());
578 :
579 : return slot;
580 : }
581 :
582 0 : void source_info::debug ()
583 : {
584 0 : fprintf (stderr, "source_info: %s\n", name);
585 0 : for (vector<function_info *>::iterator it = functions.begin ();
586 0 : it != functions.end (); it++)
587 : {
588 0 : function_info *fn = *it;
589 0 : fprintf (stderr, " function_info: %s\n", fn->get_name ());
590 0 : for (vector<block_info>::iterator bit = fn->blocks.begin ();
591 0 : bit != fn->blocks.end (); bit++)
592 : {
593 0 : fprintf (stderr, " block_info id=%d, count=%" PRId64 " \n",
594 0 : bit->id, bit->count);
595 : }
596 : }
597 :
598 0 : for (unsigned lineno = 1; lineno < lines.size (); ++lineno)
599 : {
600 0 : line_info &line = lines[lineno];
601 0 : fprintf (stderr, " line_info=%d, count=%" PRId64 "\n", lineno, line.count);
602 : }
603 :
604 0 : fprintf (stderr, "\n");
605 0 : }
606 :
607 : class name_map
608 : {
609 : public:
610 0 : name_map ()
611 : {
612 : }
613 :
614 239 : name_map (char *_name, unsigned _src): name (_name), src (_src)
615 : {
616 : }
617 :
618 19310 : bool operator== (const name_map &rhs) const
619 : {
620 : #if HAVE_DOS_BASED_FILE_SYSTEM
621 : return strcasecmp (this->name, rhs.name) == 0;
622 : #else
623 19310 : return strcmp (this->name, rhs.name) == 0;
624 : #endif
625 : }
626 :
627 1071 : bool operator< (const name_map &rhs) const
628 : {
629 : #if HAVE_DOS_BASED_FILE_SYSTEM
630 : return strcasecmp (this->name, rhs.name) < 0;
631 : #else
632 1069 : return strcmp (this->name, rhs.name) < 0;
633 : #endif
634 : }
635 :
636 : const char *name; /* Source file name */
637 : unsigned src; /* Source file */
638 : };
639 :
640 : /* Vector of all functions. */
641 : static vector<function_info *> functions;
642 :
643 : /* Function ident to function_info * map. */
644 : static map<unsigned, function_info *> ident_to_fn;
645 :
646 : /* Vector of source files. */
647 : static vector<source_info> sources;
648 :
649 : /* Mapping of file names to sources */
650 : static vector<name_map> names;
651 :
652 : /* Record all processed files in order to warn about
653 : a file being read multiple times. */
654 : static vector<char *> processed_files;
655 :
656 : /* The contents of a source file. The nth SOURCE_LINES entry is the
657 : contents of the nth SOURCES, or empty if it has not or could not be
658 : read. */
659 : static vector<vector<const char *>*> source_lines;
660 :
661 : /* This holds data summary information. */
662 :
663 : static unsigned object_runs;
664 :
665 : static unsigned total_lines;
666 : static unsigned total_executed;
667 : static unsigned total_suppressed;
668 :
669 : /* Modification time of graph file. */
670 :
671 : static time_t bbg_file_time;
672 :
673 : /* Name of the notes (gcno) output file. The "bbg" prefix is for
674 : historical reasons, when the notes file contained only the
675 : basic block graph notes. */
676 :
677 : static char *bbg_file_name;
678 :
679 : /* Stamp of the bbg file */
680 : static unsigned bbg_stamp;
681 :
682 : /* Supports has_unexecuted_blocks functionality. */
683 : static unsigned bbg_supports_has_unexecuted_blocks;
684 :
685 : /* Working directory in which a TU was compiled. */
686 : static const char *bbg_cwd;
687 :
688 : /* Name and file pointer of the input file for the count data (gcda). */
689 :
690 : static char *da_file_name;
691 :
692 : /* Data file is missing. */
693 :
694 : static int no_data_file;
695 :
696 : /* If there is several input files, compute and display results after
697 : reading all data files. This way if two or more gcda file refer to
698 : the same source file (eg inline subprograms in a .h file), the
699 : counts are added. */
700 :
701 : static int multiple_files = 0;
702 :
703 : /* Output branch probabilities. */
704 :
705 : static int flag_branches = 0;
706 :
707 : /* Output conditions (modified condition/decision coverage). */
708 :
709 : static bool flag_conditions = 0;
710 :
711 : /* Show unconditional branches too. */
712 : static int flag_unconditional = 0;
713 :
714 : /* Output path coverage. */
715 : static bool flag_prime_paths = false;
716 :
717 : /* Output path coverage - lines mode. */
718 : static bool flag_prime_paths_lines_covered = false;
719 : static bool flag_prime_paths_lines_uncovered = false;
720 :
721 : /* Output path coverage - source mode. */
722 : static bool flag_prime_paths_source_covered = false;
723 : static bool flag_prime_paths_source_uncovered = false;
724 :
725 : /* Output a gcov file if this is true. This is on by default, and can
726 : be turned off by the -n option. */
727 :
728 : static int flag_gcov_file = 1;
729 :
730 : /* Output to stdout instead to a gcov file. */
731 :
732 : static int flag_use_stdout = 0;
733 :
734 : /* Output progress indication if this is true. This is off by default
735 : and can be turned on by the -d option. */
736 :
737 : static int flag_display_progress = 0;
738 :
739 : /* Output *.gcov file in JSON intermediate format used by consumers. */
740 :
741 : static int flag_json_format = 0;
742 :
743 : /* For included files, make the gcov output file name include the name
744 : of the input source file. For example, if x.h is included in a.c,
745 : then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
746 :
747 : static int flag_long_names = 0;
748 :
749 : /* For situations when a long name can potentially hit filesystem path limit,
750 : let's calculate md5sum of the path and append it to a file name. */
751 :
752 : static int flag_hash_filenames = 0;
753 :
754 : /* Print verbose information. */
755 :
756 : static int flag_verbose = 0;
757 :
758 : /* Print colored output. */
759 :
760 : static int flag_use_colors = 0;
761 :
762 : /* Use perf-like colors to indicate hot lines. */
763 :
764 : static int flag_use_hotness_colors = 0;
765 :
766 : /* Output count information for every basic block, not merely those
767 : that contain line number information. */
768 :
769 : static int flag_all_blocks = 0;
770 :
771 : /* Output human readable numbers. */
772 :
773 : static int flag_human_readable_numbers = 0;
774 :
775 : /* Output summary info for each function. */
776 :
777 : static int flag_function_summary = 0;
778 :
779 : /* Print debugging dumps. */
780 :
781 : static int flag_debug = 0;
782 :
783 : /* Object directory file prefix. This is the directory/file where the
784 : graph and data files are looked for, if nonzero. */
785 :
786 : static char *object_directory = 0;
787 :
788 : /* Source directory prefix. This is removed from source pathnames
789 : that match, when generating the output file name. */
790 :
791 : static char *source_prefix = 0;
792 : static size_t source_length = 0;
793 :
794 : /* Only show data for sources with relative pathnames. Absolute ones
795 : usually indicate a system header file, which although it may
796 : contain inline functions, is usually uninteresting. */
797 : static int flag_relative_only = 0;
798 :
799 : /* Preserve all pathname components. Needed when object files and
800 : source files are in subdirectories. '/' is mangled as '#', '.' is
801 : elided and '..' mangled to '^'. */
802 :
803 : static int flag_preserve_paths = 0;
804 :
805 : /* Output the number of times a branch was taken as opposed to the percentage
806 : of times it was taken. */
807 :
808 : static int flag_counts = 0;
809 :
810 : /* Return code of the tool invocation. */
811 : static int return_code = 0;
812 :
813 : /* "Keep policy" when adding functions to the global function table. This will
814 : be set to false when --include is used, otherwise every function should be
815 : added to the table. Used for --include/exclude. */
816 : static bool default_keep = true;
817 :
818 : /* Include/exclude filters function based on matching the (de)mangled name.
819 : The default is to match the mangled name. Note that flag_demangled_names
820 : does not affect this. */
821 : static bool flag_filter_on_demangled = false;
822 :
823 : /* A 'function filter', a filter and action for determining if a function
824 : should be included in the output or not. Used for --include/--exclude
825 : filtering. */
826 : struct fnfilter
827 : {
828 : /* The (extended) compiled regex for this filter. */
829 : regex_t regex;
830 :
831 : /* The action when this filter (regex) matches - if true, the function should
832 : be kept, otherwise discarded. */
833 : bool keep;
834 :
835 : /* Compile the regex EXPR, or exit if pattern is malformed. */
836 15 : void compile (const char *expr)
837 : {
838 15 : int err = regcomp (®ex, expr, REG_NOSUB | REG_EXTENDED);
839 15 : if (err)
840 : {
841 0 : size_t len = regerror (err, ®ex, nullptr, 0);
842 0 : char *msg = XNEWVEC (char, len);
843 0 : regerror (err, ®ex, msg, len);
844 0 : fprintf (stderr, "Bad regular expression: %s\n", msg);
845 0 : free (msg);
846 0 : exit (EXIT_FAILURE);
847 : }
848 15 : }
849 : };
850 :
851 : /* A collection of filter functions for including/exclude functions in the
852 : output. This is empty unless --include/--exclude is used. */
853 : static vector<fnfilter> filters;
854 :
855 : /* Forward declarations. */
856 : static int process_args (int, char **);
857 : static void print_usage (int) ATTRIBUTE_NORETURN;
858 : static void print_version (void) ATTRIBUTE_NORETURN;
859 : static void process_file (const char *);
860 : static void process_all_functions (void);
861 : static void generate_results (const char *);
862 : static void create_file_names (const char *);
863 : static char *canonicalize_name (const char *);
864 : static unsigned find_source (const char *);
865 : static void read_graph_file (void);
866 : static int read_count_file (void);
867 : static void solve_flow_graph (function_info *);
868 : static void find_prime_paths (function_info *fn);
869 : static void find_exception_blocks (function_info *);
870 : static void add_branch_counts (coverage_info *, const arc_info *);
871 : static void add_condition_counts (coverage_info *, const block_info *);
872 : static void add_path_counts (coverage_info &, const function_info &);
873 : static void add_line_counts (coverage_info *, function_info *);
874 : static void executed_summary (unsigned, unsigned, unsigned);
875 : static void function_summary (const coverage_info *);
876 : static void file_summary (const coverage_info *);
877 : static const char *format_gcov (gcov_type, gcov_type, int);
878 : static void accumulate_line_counts (source_info *);
879 : static void output_gcov_file (const char *, source_info *);
880 : static int output_branch_count (FILE *, int, const arc_info *);
881 : static void output_conditions (FILE *, const block_info *);
882 : static void output_lines (FILE *, const source_info *);
883 : static string make_gcov_file_name (const char *, const char *);
884 : static char *mangle_name (const char *);
885 : static void release_structures (void);
886 : extern int main (int, char **);
887 : static const vector<const char *>&
888 : slurp (const source_info &src, FILE *gcov_file, const char *line_start);
889 :
890 1450 : function_info::function_info (): m_name (NULL), m_demangled_name (NULL),
891 1450 : ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
892 1450 : artificial (0), is_group (0),
893 1450 : blocks (), blocks_executed (0), counts (),
894 1450 : start_line (0), start_column (0), end_line (0), end_column (0),
895 1450 : src (0), lines (), next (NULL)
896 : {
897 1450 : }
898 :
899 1363 : function_info::~function_info ()
900 : {
901 13774 : for (int i = blocks.size () - 1; i >= 0; i--)
902 : {
903 12411 : arc_info *arc, *arc_n;
904 :
905 29110 : for (arc = blocks[i].succ; arc; arc = arc_n)
906 : {
907 16699 : arc_n = arc->succ_next;
908 16699 : free (arc);
909 : }
910 : }
911 1363 : if (m_demangled_name != m_name)
912 1361 : free (m_demangled_name);
913 1363 : free (m_name);
914 1363 : }
915 :
916 11786 : bool function_info::group_line_p (unsigned n, unsigned src_idx)
917 : {
918 11786 : return is_group && src == src_idx && start_line <= n && n <= end_line;
919 : }
920 :
921 : /* Check if the block ID is a tombstone. */
922 : static bool
923 3418 : tombstone_p (unsigned id)
924 : {
925 3418 : return id == unsigned (-1);
926 : };
927 :
928 : /* Remove tombstones from VEC. Preserves the order of remaining values. */
929 : static vector<unsigned>
930 42 : remove_tombstones (vector<unsigned> vec)
931 : {
932 42 : vec.erase (remove_if (vec.begin (), vec.end (), tombstone_p), vec.end ());
933 42 : return vec;
934 : }
935 :
936 : /* Check if SUB is a a proper contiguous subsequence of SUPER with tombstones
937 : functioning as wildcards.
938 :
939 : If SUB and SUPER would be equal if tombstones are removed, SUB is not a
940 : proper subsequence and this function returns false.
941 :
942 : Examples:
943 :
944 : SUB: 2 -1 12
945 : SUPER: 2 -1 -1 12
946 : Returns false because both sequences become [2 12] without tombstones.
947 :
948 : SUB: 2 -1 12
949 : SUPER: 2 7 12
950 : Returns true because 2 12 appear in that order in SUPER and there is a
951 : tombstone between 2 and 12.
952 :
953 : SUB: 2 12
954 : SUPER: 2 7 12
955 : Returns false because 2 and 12 are not consecutive in SUPER.
956 :
957 : SUB: 12 7
958 : SUPER: 2 7 12
959 : Returns false because 7 is before 12 in SUPER.
960 :
961 : SUB: -1 7 12
962 : SUPER: -1 7 -1 12 -1
963 : Returns false because both sequences are 7 12 once tombstones are removed.
964 : */
965 : static bool
966 645 : tombstone_subsequence_p (const vector<unsigned>& sub,
967 : const vector<unsigned>& super)
968 : {
969 645 : if (&sub == &super)
970 : return false;
971 :
972 593 : auto xend = sub.end ();
973 593 : auto yend = super.end ();
974 593 : auto xitr = find_if_not (sub.begin (), xend, tombstone_p);
975 593 : auto yitr = find_if_not (super.begin (), yend, tombstone_p);
976 :
977 : /* If SUB is empty or all tombstones it is included in any other path. */
978 593 : if (xitr == xend)
979 : return true;
980 : /* If SUPER is empty or all tombstones it does not include anything. */
981 593 : if (yitr == yend)
982 : return false;
983 :
984 584 : bool equivalent = *yitr == *xitr;
985 : /* Find the position in SUPER where the SUB may start. */
986 584 : if (!equivalent)
987 : {
988 434 : yitr = find (yitr, yend, *xitr);
989 434 : if (yitr == yend)
990 : return false;
991 : }
992 :
993 1406 : for (; xitr != xend; ++xitr, ++yitr)
994 1369 : if (tombstone_p (*xitr))
995 : {
996 : /* Skip past any tombstones to find the next value. We need to compare
997 : to the next non-tombstone value in SUPER to know if we skipped any
998 : values to check for equivalence, otherwise this could just be
999 : std::find for SUPER. */
1000 292 : xitr = find_if_not (xitr, xend, tombstone_p);
1001 292 : yitr = find_if_not (yitr, yend, tombstone_p);
1002 :
1003 : /* If there are no more non-tombstone blocks i SUB we're almost done,
1004 : but we still need to if there are more blocks in SUPER. */
1005 292 : if (xitr == xend)
1006 15 : return yitr != yend || !equivalent;
1007 :
1008 277 : if (yitr == yend)
1009 : return false;
1010 :
1011 : /* Now check for equivalence and look for the value in SUPER. This is
1012 : a no-op if we found it already. */
1013 189 : equivalent = equivalent && *yitr == *xitr;
1014 189 : yitr = find (yitr, yend, *xitr);
1015 189 : if (yitr == yend)
1016 : return false;
1017 : }
1018 1077 : else if (*yitr != *xitr)
1019 : return false;
1020 :
1021 37 : yitr = find_if_not (yitr, yend, tombstone_p);
1022 37 : return yitr == yend && !equivalent;
1023 : }
1024 :
1025 : /* Check if NEEDLE is a proper subsequence of any sequence in HAYSTACK except
1026 : itself. Suppressed blocks/tombstones function as wildcards and match any
1027 : subsequence. If two sequences are equal once tombstones are removed they
1028 : are not proper subsequences of eachother.
1029 :
1030 : We may get odd sequence when we remove parts of a path, so we
1031 : extend the when the path A subsumes B to include non-contiguous
1032 : subsequences.
1033 :
1034 : Given a set of prime paths:
1035 : 2 3 4 12
1036 : 2 3 5 6 12
1037 : 2 3 5 7 8 10 12
1038 : 2 3 5 7 8 9 10 12
1039 : 2 3 5 7 8 9 11 12
1040 :
1041 : We have a blacklist of 3 4 5 6 8 9 10 which means these nodes should be
1042 : removed from all paths. If we replace blacklisted nodes with tombstones
1043 : (-1) and remove duplicates we get:
1044 : 2 -1 12
1045 : 2 -1 7 -1 11 12
1046 : 2 -1 7 -1 12
1047 :
1048 : A path is prime if it is not a subpath of any other paths. Suppressed
1049 : segments may be covered by any sequence of nodes, so the path:
1050 : 2 -1 7 -1 11 12
1051 : would subsume (<:) the other paths:
1052 : 2 -1 12 <: 2 [7 11] 12
1053 : 2 -1 7 12 <: 2 7 [11] 12
1054 :
1055 : Thus the only prime path is 2 7 11 12. */
1056 : static bool
1057 75 : subsumed_by_any_p (const vector<unsigned>& needle,
1058 : const vector<vector<unsigned>>& haystack)
1059 : {
1060 75 : if (all_of (needle.begin (), needle.end (), tombstone_p))
1061 : return true;
1062 687 : for (const auto& seq : haystack)
1063 645 : if (tombstone_subsequence_p (needle, seq))
1064 75 : return true;
1065 : return false;
1066 : }
1067 :
1068 : /* Compute the new paths and coverage by ignoring the blocks in SUPPRESSED.
1069 : Does nothing when SUPPRESSED is empty. This only adds the new
1070 : interpretation and does not change the observed path and coverage info. */
1071 : void
1072 1363 : path_info::suppress_blocks (const vector<bool>& suppressed)
1073 : {
1074 1363 : if (suppressed.empty ())
1075 1078 : return;
1076 :
1077 285 : const unsigned tombstone = unsigned (-1);
1078 : /* Clean up the paths by replacing suppressed blocks with tombstones. */
1079 285 : vector<vector<unsigned>> ipaths;
1080 285 : ipaths.reserve (paths.size ());
1081 360 : for (const auto& path : paths)
1082 : {
1083 75 : vector<unsigned> tmp;
1084 75 : tmp.reserve (path.size ());
1085 530 : for (auto v : path)
1086 649 : tmp.push_back (!suppressed[v] ? v : tombstone);
1087 75 : ipaths.push_back (std::move (tmp));
1088 75 : }
1089 :
1090 : /* Changing paths means some paths may turn into subpaths, so we find and
1091 : store the new prime paths mapped to the original indices for later.
1092 : The new paths are map both sorts the paths and filters duplicates
1093 : duplicates. */
1094 285 : map<vector<unsigned> /* path */, vector<size_t> /* indices */> nextpaths;
1095 360 : for (size_t i = 0; i != ipaths.size (); ++i)
1096 75 : if (!subsumed_by_any_p (ipaths[i], ipaths))
1097 42 : nextpaths[remove_tombstones (ipaths[i])].push_back (i);
1098 :
1099 : /* Record the coverage of the new paths. The new paths may be the result
1100 : of merging paths, and if either original path is covered then the merged
1101 : path should be covered. */
1102 285 : vector<gcov_type_unsigned> nextcovered;
1103 285 : const size_t nbits = path_info::bucketsize;
1104 285 : const size_t nbuckets = (nextpaths.size () + (nbits - 1)) / nbits;
1105 285 : nextcovered.resize (nbuckets);
1106 285 : std::size_t n = 0;
1107 320 : for (const auto& np : nextpaths)
1108 : {
1109 35 : const size_t bucket = n / bucketsize;
1110 35 : const uint64_t bit = n % bucketsize;
1111 55 : for (size_t index : np.second)
1112 37 : if (covered_p (index))
1113 : {
1114 17 : nextcovered[bucket] |= (gcov_type_unsigned (1) << bit);
1115 17 : break;
1116 : }
1117 35 : n++;
1118 : }
1119 285 : residual_covered.swap (nextcovered);
1120 :
1121 : /* Store the new paths. The map iteration outputs the paths
1122 : lexicographically ordered. */
1123 320 : for (auto& p : nextpaths)
1124 35 : residual_paths.push_back (std::move (p.first));
1125 285 : }
1126 :
1127 : /* Find the arc that connects BLOCK to the block with id DEST, or nullptr if it
1128 : doesn't exist. */
1129 : static const arc_info*
1130 8279 : find_arc (const block_info &block, unsigned dest)
1131 : {
1132 34431 : for (const arc_info *arc = block.succ; arc; arc = arc->succ_next)
1133 34403 : if (arc->dst->id == dest)
1134 : return arc;
1135 : return nullptr;
1136 : }
1137 :
1138 : /* Cycle detection!
1139 : There are a bajillion algorithms that do this. Boost's function is named
1140 : hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
1141 : "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
1142 : (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
1143 :
1144 : The basic algorithm is simple: effectively, we're finding all simple paths
1145 : in a subgraph (that shrinks every iteration). Duplicates are filtered by
1146 : "blocking" a path when a node is added to the path (this also prevents non-
1147 : simple paths)--the node is unblocked only when it participates in a cycle.
1148 : */
1149 :
1150 : typedef vector<arc_info *> arc_vector_t;
1151 : typedef vector<const block_info *> block_vector_t;
1152 :
1153 : /* Handle cycle identified by EDGES, where the function finds minimum cs_count
1154 : and subtract the value from all counts. The subtracted value is added
1155 : to COUNT. Returns type of loop. */
1156 :
1157 : static void
1158 16 : handle_cycle (const arc_vector_t &edges, int64_t &count)
1159 : {
1160 : /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
1161 : that amount. */
1162 16 : int64_t cycle_count = INTTYPE_MAXIMUM (int64_t);
1163 52 : for (unsigned i = 0; i < edges.size (); i++)
1164 : {
1165 36 : int64_t ecount = edges[i]->cs_count;
1166 36 : if (cycle_count > ecount)
1167 : cycle_count = ecount;
1168 : }
1169 16 : count += cycle_count;
1170 52 : for (unsigned i = 0; i < edges.size (); i++)
1171 36 : edges[i]->cs_count -= cycle_count;
1172 :
1173 16 : gcc_assert (cycle_count > 0);
1174 16 : }
1175 :
1176 : /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
1177 : blocked by U in BLOCK_LISTS. */
1178 :
1179 : static void
1180 34 : unblock (const block_info *u, block_vector_t &blocked,
1181 : vector<block_vector_t > &block_lists)
1182 : {
1183 34 : block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u);
1184 34 : if (it == blocked.end ())
1185 0 : return;
1186 :
1187 34 : unsigned index = it - blocked.begin ();
1188 34 : blocked.erase (it);
1189 :
1190 34 : block_vector_t to_unblock (block_lists[index]);
1191 :
1192 34 : block_lists.erase (block_lists.begin () + index);
1193 :
1194 34 : for (block_vector_t::iterator it = to_unblock.begin ();
1195 34 : it != to_unblock.end (); it++)
1196 0 : unblock (*it, blocked, block_lists);
1197 34 : }
1198 :
1199 : /* Return true when PATH contains a zero cycle arc count. */
1200 :
1201 : static bool
1202 1646 : path_contains_zero_or_negative_cycle_arc (arc_vector_t &path)
1203 : {
1204 11419 : for (unsigned i = 0; i < path.size (); i++)
1205 9773 : if (path[i]->cs_count <= 0)
1206 : return true;
1207 : return false;
1208 : }
1209 :
1210 : /* Find circuit going to block V, PATH is provisional seen cycle.
1211 : BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
1212 : blocked by a block. COUNT is accumulated count of the current LINE.
1213 : Returns what type of loop it contains. */
1214 :
1215 : static bool
1216 9755 : circuit (block_info *v, arc_vector_t &path, block_info *start,
1217 : block_vector_t &blocked, vector<block_vector_t> &block_lists,
1218 : line_info &linfo, int64_t &count)
1219 : {
1220 9755 : bool loop_found = false;
1221 :
1222 : /* Add v to the block list. */
1223 19510 : gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
1224 9755 : blocked.push_back (v);
1225 9755 : block_lists.push_back (block_vector_t ());
1226 :
1227 26784 : for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
1228 : {
1229 17029 : block_info *w = arc->dst;
1230 32396 : if (w < start
1231 12544 : || arc->cs_count <= 0
1232 23367 : || !linfo.has_block (w))
1233 15367 : continue;
1234 :
1235 1662 : path.push_back (arc);
1236 1662 : if (w == start)
1237 : {
1238 : /* Cycle has been found. */
1239 16 : handle_cycle (path, count);
1240 16 : loop_found = true;
1241 : }
1242 1646 : else if (!path_contains_zero_or_negative_cycle_arc (path)
1243 3292 : && find (blocked.begin (), blocked.end (), w) == blocked.end ())
1244 1627 : loop_found |= circuit (w, path, start, blocked, block_lists, linfo,
1245 : count);
1246 :
1247 1662 : path.pop_back ();
1248 : }
1249 :
1250 9755 : if (loop_found)
1251 34 : unblock (v, blocked, block_lists);
1252 : else
1253 26692 : for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
1254 : {
1255 16971 : block_info *w = arc->dst;
1256 32317 : if (w < start
1257 12492 : || arc->cs_count <= 0
1258 23257 : || !linfo.has_block (w))
1259 15346 : continue;
1260 :
1261 1625 : size_t index
1262 3250 : = find (blocked.begin (), blocked.end (), w) - blocked.begin ();
1263 1625 : gcc_assert (index < blocked.size ());
1264 1625 : block_vector_t &list = block_lists[index];
1265 3250 : if (find (list.begin (), list.end (), v) == list.end ())
1266 1625 : list.push_back (v);
1267 : }
1268 :
1269 9755 : return loop_found;
1270 : }
1271 :
1272 : /* Find cycles for a LINFO. */
1273 :
1274 : static gcov_type
1275 6136 : get_cycles_count (line_info &linfo)
1276 : {
1277 : /* Note that this algorithm works even if blocks aren't in sorted order.
1278 : Each iteration of the circuit detection is completely independent
1279 : (except for reducing counts, but that shouldn't matter anyways).
1280 : Therefore, operating on a permuted order (i.e., non-sorted) only
1281 : has the effect of permuting the output cycles. */
1282 :
1283 6136 : gcov_type count = 0;
1284 6136 : for (vector<block_info *>::iterator it = linfo.blocks.begin ();
1285 14264 : it != linfo.blocks.end (); it++)
1286 : {
1287 8128 : arc_vector_t path;
1288 8128 : block_vector_t blocked;
1289 8128 : vector<block_vector_t > block_lists;
1290 8128 : circuit (*it, path, *it, blocked, block_lists, linfo, count);
1291 8128 : }
1292 :
1293 6136 : return count;
1294 : }
1295 :
1296 : int
1297 160 : main (int argc, char **argv)
1298 : {
1299 160 : int argno;
1300 160 : int first_arg;
1301 160 : const char *p;
1302 :
1303 160 : p = argv[0] + strlen (argv[0]);
1304 800 : while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
1305 640 : --p;
1306 160 : progname = p;
1307 :
1308 160 : xmalloc_set_program_name (progname);
1309 :
1310 : /* Unlock the stdio streams. */
1311 160 : unlock_std_streams ();
1312 :
1313 160 : gcc_init_libintl ();
1314 :
1315 160 : diagnostic_initialize (global_dc, 0);
1316 :
1317 : /* Handle response files. */
1318 160 : expandargv (&argc, &argv);
1319 :
1320 160 : argno = process_args (argc, argv);
1321 160 : if (optind == argc)
1322 0 : print_usage (true);
1323 :
1324 160 : if (argc - argno > 1)
1325 0 : multiple_files = 1;
1326 :
1327 160 : first_arg = argno;
1328 :
1329 320 : for (; argno != argc; argno++)
1330 : {
1331 160 : if (flag_display_progress)
1332 0 : printf ("Processing file %d out of %d\n", argno - first_arg + 1,
1333 : argc - first_arg);
1334 160 : process_file (argv[argno]);
1335 :
1336 160 : if (flag_json_format || argno == argc - 1)
1337 : {
1338 160 : process_all_functions ();
1339 160 : generate_results (argv[argno]);
1340 160 : release_structures ();
1341 : }
1342 : }
1343 :
1344 160 : if (!flag_use_stdout)
1345 160 : executed_summary (total_lines, total_executed, total_suppressed);
1346 :
1347 160 : return return_code;
1348 : }
1349 :
1350 : /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
1351 : otherwise the output of --help. */
1352 :
1353 : static void
1354 0 : print_usage (int error_p)
1355 : {
1356 0 : FILE *file = error_p ? stderr : stdout;
1357 0 : int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
1358 :
1359 0 : fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
1360 0 : fnotice (file, "Print code coverage information.\n\n");
1361 0 : fnotice (file, " -a, --all-blocks Show information for every basic block\n");
1362 0 : fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
1363 0 : fnotice (file, " -c, --branch-counts Output counts of branches taken\n\
1364 : rather than percentages\n");
1365 0 : fnotice (file, " -g, --conditions Include modified condition/decision\n\
1366 : coverage (masking MC/DC) in output\n");
1367 0 : fnotice (file, " -e, --prime-paths Show prime path coverage summary\n");
1368 0 : fnotice (file, " --prime-paths-lines[=TYPE] Include paths in output\n\
1369 : line trace mode - does not affect json\n\
1370 : TYPE is 'covered', 'uncovered', or 'both'\n\
1371 : and defaults to 'uncovered'\n");
1372 0 : fnotice (file, " --prime-paths-source[=TYPE] Include paths in output\n\
1373 : source trace mode - does not affect json\n\
1374 : TYPE is 'covered', 'uncovered', or 'both'\n\
1375 : and defaults to 'uncovered'\n");
1376 0 : fnotice (file, " -d, --display-progress Display progress information\n");
1377 0 : fnotice (file, " -D, --debug Display debugging dumps\n");
1378 0 : fnotice (file, " -f, --function-summaries Output summaries for each function\n");
1379 0 : fnotice (file, " --include Include functions matching this regex\n");
1380 0 : fnotice (file, " --exclude Exclude functions matching this regex\n");
1381 0 : fnotice (file, " -h, --help Print this help, then exit\n");
1382 0 : fnotice (file, " -j, --json-format Output JSON intermediate format\n\
1383 : into .gcov.json.gz file\n");
1384 0 : fnotice (file, " -H, --human-readable Output human readable numbers\n");
1385 0 : fnotice (file, " -k, --use-colors Emit colored output\n");
1386 0 : fnotice (file, " -l, --long-file-names Use long output file names for included\n\
1387 : source files\n");
1388 0 : fnotice (file, " -m, --demangled-names Output demangled function names\n");
1389 0 : fnotice (file, " -M, --filter-on-demangled Make --include/--exclude match on demangled\n\
1390 : names. This does not imply -m\n");
1391 0 : fnotice (file, " -n, --no-output Do not create an output file\n");
1392 0 : fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
1393 0 : fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
1394 0 : fnotice (file, " -q, --use-hotness-colors Emit perf-like colored output for hot lines\n");
1395 0 : fnotice (file, " -r, --relative-only Only show data for relative sources\n");
1396 0 : fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n");
1397 0 : fnotice (file, " -t, --stdout Output to stdout instead of a file\n");
1398 0 : fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
1399 0 : fnotice (file, " -v, --version Print version number, then exit\n");
1400 0 : fnotice (file, " -w, --verbose Print verbose information\n");
1401 0 : fnotice (file, " -x, --hash-filenames Hash long pathnames\n");
1402 0 : fnotice (file, "\nObsolete options:\n");
1403 0 : fnotice (file, " -i, --json-format Replaced with -j, --json-format\n");
1404 0 : fnotice (file, " -j, --human-readable Replaced with -H, --human-readable\n");
1405 0 : fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
1406 : bug_report_url);
1407 0 : exit (status);
1408 : }
1409 :
1410 : /* Print version information and exit. */
1411 :
1412 : static void
1413 0 : print_version (void)
1414 : {
1415 0 : fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
1416 0 : fnotice (stdout, "JSON format version: %s\n", GCOV_JSON_FORMAT_VERSION);
1417 0 : fprintf (stdout, "Copyright %s 2026 Free Software Foundation, Inc.\n",
1418 : _("(C)"));
1419 0 : fnotice (stdout,
1420 0 : _("This is free software; see the source for copying conditions. There is NO\n\
1421 : warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
1422 0 : exit (SUCCESS_EXIT_CODE);
1423 : }
1424 :
1425 : static const struct option options[] =
1426 : {
1427 : { "help", no_argument, NULL, 'h' },
1428 : { "version", no_argument, NULL, 'v' },
1429 : { "verbose", no_argument, NULL, 'w' },
1430 : { "all-blocks", no_argument, NULL, 'a' },
1431 : { "branch-probabilities", no_argument, NULL, 'b' },
1432 : { "branch-counts", no_argument, NULL, 'c' },
1433 : { "conditions", no_argument, NULL, 'g' },
1434 : { "prime-paths", no_argument, NULL, 'e' },
1435 : { "prime-paths-lines", optional_argument, NULL, 900 },
1436 : { "prime-paths-source", optional_argument, NULL, 901 },
1437 : { "json-format", no_argument, NULL, 'j' },
1438 : { "include", required_argument, NULL, 'I' },
1439 : { "exclude", required_argument, NULL, 'E' },
1440 : { "human-readable", no_argument, NULL, 'H' },
1441 : { "no-output", no_argument, NULL, 'n' },
1442 : { "long-file-names", no_argument, NULL, 'l' },
1443 : { "function-summaries", no_argument, NULL, 'f' },
1444 : { "demangled-names", no_argument, NULL, 'm' },
1445 : { "filter-on-demangled", no_argument, NULL, 'M' },
1446 : { "preserve-paths", no_argument, NULL, 'p' },
1447 : { "relative-only", no_argument, NULL, 'r' },
1448 : { "object-directory", required_argument, NULL, 'o' },
1449 : { "object-file", required_argument, NULL, 'o' },
1450 : { "source-prefix", required_argument, NULL, 's' },
1451 : { "stdout", no_argument, NULL, 't' },
1452 : { "unconditional-branches", no_argument, NULL, 'u' },
1453 : { "display-progress", no_argument, NULL, 'd' },
1454 : { "hash-filenames", no_argument, NULL, 'x' },
1455 : { "use-colors", no_argument, NULL, 'k' },
1456 : { "use-hotness-colors", no_argument, NULL, 'q' },
1457 : { "debug", no_argument, NULL, 'D' },
1458 : { 0, 0, 0, 0 }
1459 : };
1460 :
1461 : /* Process args, return index to first non-arg. */
1462 :
1463 : static int
1464 160 : process_args (int argc, char **argv)
1465 : {
1466 160 : int opt;
1467 :
1468 160 : const char *opts = "abcdDefghHijklmMno:pqrs:tuvwx";
1469 243 : while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
1470 : {
1471 83 : switch (opt)
1472 : {
1473 15 : case 'a':
1474 15 : flag_all_blocks = 1;
1475 15 : break;
1476 23 : case 'b':
1477 23 : flag_branches = 1;
1478 23 : break;
1479 2 : case 'c':
1480 2 : flag_counts = 1;
1481 2 : break;
1482 3 : case 'e':
1483 3 : flag_prime_paths = true;
1484 3 : break;
1485 8 : case 900:
1486 8 : flag_prime_paths = true;
1487 8 : if (!optarg)
1488 2 : flag_prime_paths_lines_uncovered = true;
1489 6 : else if (strcmp (optarg, "uncovered") == 0)
1490 0 : flag_prime_paths_lines_uncovered = true;
1491 6 : else if (strcmp (optarg, "covered") == 0)
1492 1 : flag_prime_paths_lines_covered = true;
1493 5 : else if (strcmp (optarg, "both") == 0)
1494 : {
1495 5 : flag_prime_paths_lines_covered = true;
1496 5 : flag_prime_paths_lines_uncovered = true;
1497 : }
1498 : else
1499 : {
1500 0 : fnotice (stderr, "invalid argument '%s' for "
1501 : "'--prime-paths-lines'. Valid arguments are: "
1502 : "'covered', 'uncovered', 'both'\n", optarg);
1503 0 : exit (FATAL_EXIT_CODE);
1504 : }
1505 : break;
1506 3 : case 901:
1507 3 : flag_prime_paths = true;
1508 3 : if (!optarg)
1509 0 : flag_prime_paths_source_uncovered = true;
1510 3 : else if (strcmp (optarg, "uncovered") == 0)
1511 0 : flag_prime_paths_source_uncovered = true;
1512 3 : else if (strcmp (optarg, "covered") == 0)
1513 0 : flag_prime_paths_source_covered = true;
1514 3 : else if (strcmp (optarg, "both") == 0)
1515 : {
1516 3 : flag_prime_paths_source_covered = true;
1517 3 : flag_prime_paths_source_uncovered = true;
1518 : }
1519 : else
1520 : {
1521 0 : fnotice (stderr, "invalid argument '%s' for "
1522 : "'--prime-paths-source'. Valid arguments are: "
1523 : "'covered', 'uncovered', 'both'\n", optarg);
1524 0 : exit (FATAL_EXIT_CODE);
1525 : }
1526 : break;
1527 0 : case 'f':
1528 0 : flag_function_summary = 1;
1529 0 : break;
1530 6 : case 'g':
1531 6 : flag_conditions = 1;
1532 6 : break;
1533 0 : case 'h':
1534 0 : print_usage (false);
1535 : /* print_usage will exit. */
1536 0 : case 'l':
1537 0 : flag_long_names = 1;
1538 0 : break;
1539 12 : case 'I':
1540 12 : default_keep = false;
1541 12 : filters.push_back (fnfilter {});
1542 12 : filters.back ().keep = true;
1543 12 : filters.back ().compile (optarg);
1544 12 : break;
1545 3 : case 'E':
1546 3 : filters.push_back (fnfilter {});
1547 3 : filters.back ().keep = false;
1548 3 : filters.back ().compile (optarg);
1549 3 : break;
1550 3 : case 'H':
1551 3 : flag_human_readable_numbers = 1;
1552 3 : break;
1553 0 : case 'k':
1554 0 : flag_use_colors = 1;
1555 0 : break;
1556 0 : case 'q':
1557 0 : flag_use_hotness_colors = 1;
1558 0 : break;
1559 0 : case 'm':
1560 0 : flag_demangled_names = 1;
1561 0 : break;
1562 3 : case 'M':
1563 3 : flag_filter_on_demangled = true;
1564 3 : break;
1565 0 : case 'n':
1566 0 : flag_gcov_file = 0;
1567 0 : break;
1568 0 : case 'o':
1569 0 : object_directory = optarg;
1570 0 : break;
1571 0 : case 's':
1572 0 : source_prefix = optarg;
1573 0 : source_length = strlen (source_prefix);
1574 0 : break;
1575 0 : case 'r':
1576 0 : flag_relative_only = 1;
1577 0 : break;
1578 0 : case 'p':
1579 0 : flag_preserve_paths = 1;
1580 0 : break;
1581 0 : case 'u':
1582 0 : flag_unconditional = 1;
1583 0 : break;
1584 2 : case 'i':
1585 2 : case 'j':
1586 2 : flag_json_format = 1;
1587 2 : flag_gcov_file = 1;
1588 2 : break;
1589 0 : case 'd':
1590 0 : flag_display_progress = 1;
1591 0 : break;
1592 0 : case 'x':
1593 0 : flag_hash_filenames = 1;
1594 0 : break;
1595 0 : case 'w':
1596 0 : flag_verbose = 1;
1597 0 : break;
1598 0 : case 't':
1599 0 : flag_use_stdout = 1;
1600 0 : break;
1601 0 : case 'D':
1602 0 : flag_debug = 1;
1603 0 : break;
1604 0 : case 'v':
1605 0 : print_version ();
1606 : /* print_version will exit. */
1607 0 : default:
1608 0 : print_usage (true);
1609 : /* print_usage will exit. */
1610 : }
1611 : }
1612 :
1613 160 : return optind;
1614 : }
1615 :
1616 : /* Output intermediate LINE sitting on LINE_NUM to JSON OBJECT.
1617 : Add FUNCTION_NAME to the LINE. */
1618 :
1619 : static void
1620 71 : output_intermediate_json_line (json::array *object,
1621 : line_info *line, unsigned line_num,
1622 : const char *function_name)
1623 : {
1624 71 : if (!line->exists)
1625 71 : return;
1626 :
1627 31 : json::object *lineo = new json::object ();
1628 31 : lineo->set_integer ("line_number", line_num);
1629 31 : if (function_name != NULL)
1630 31 : lineo->set_string ("function_name", function_name);
1631 31 : lineo->set_integer ("count", line->count);
1632 31 : lineo->set_bool ("unexecuted_block", line->has_unexecuted_block);
1633 :
1634 31 : json::array *bb_ids = new json::array ();
1635 49 : for (const block_info *block : line->blocks)
1636 18 : bb_ids->append (new json::integer_number (block->id));
1637 31 : lineo->set ("block_ids", bb_ids);
1638 :
1639 31 : json::array *branches = new json::array ();
1640 31 : lineo->set ("branches", branches);
1641 :
1642 31 : json::array *calls = new json::array ();
1643 31 : lineo->set ("calls", calls);
1644 :
1645 31 : vector<arc_info *>::const_iterator it;
1646 31 : if (flag_branches)
1647 63 : for (it = line->branches.begin (); it != line->branches.end ();
1648 32 : it++)
1649 : {
1650 32 : if ((*it)->suppressed)
1651 : {
1652 : /* Skip. */
1653 : }
1654 32 : else if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
1655 : {
1656 10 : json::object *branch = new json::object ();
1657 10 : branch->set_integer ("count", (*it)->count);
1658 10 : branch->set_bool ("throw", (*it)->is_throw);
1659 10 : branch->set_bool ("fallthrough", (*it)->fall_through);
1660 10 : branch->set_integer ("source_block_id", (*it)->src->id);
1661 10 : branch->set_integer ("destination_block_id", (*it)->dst->id);
1662 10 : branches->append (branch);
1663 : }
1664 22 : else if ((*it)->is_call_non_return)
1665 : {
1666 9 : json::object *call = new json::object ();
1667 9 : gcov_type returns = (*it)->src->count - (*it)->count;
1668 9 : call->set_integer ("source_block_id", (*it)->src->id);
1669 9 : call->set_integer ("destination_block_id", (*it)->dst->id);
1670 9 : call->set_integer ("returned", returns);
1671 9 : calls->append (call);
1672 : }
1673 : }
1674 :
1675 31 : json::array *conditions = new json::array ();
1676 31 : lineo->set ("conditions", conditions);
1677 31 : if (flag_conditions)
1678 : {
1679 0 : vector<block_info *>::const_iterator it;
1680 0 : for (it = line->blocks.begin (); it != line->blocks.end (); it++)
1681 : {
1682 0 : if ((*it)->suppressed)
1683 0 : continue;
1684 :
1685 0 : const condition_info& info = (*it)->conditions;
1686 0 : if (info.n_terms == 0)
1687 0 : continue;
1688 :
1689 0 : const int count = 2 * info.n_terms;
1690 0 : const int covered = info.popcount ();
1691 :
1692 0 : json::object *cond = new json::object ();
1693 0 : cond->set_integer ("count", count);
1694 0 : cond->set_integer ("covered", covered);
1695 :
1696 0 : json::array *mtrue = new json::array ();
1697 0 : json::array *mfalse = new json::array ();
1698 0 : cond->set ("not_covered_true", mtrue);
1699 0 : cond->set ("not_covered_false", mfalse);
1700 :
1701 0 : if (count != covered)
1702 : {
1703 0 : for (unsigned i = 0; i < info.n_terms; i++)
1704 : {
1705 0 : gcov_type_unsigned index = 1;
1706 0 : index <<= i;
1707 0 : if (!(index & info.truev))
1708 0 : mtrue->append (new json::integer_number (i));
1709 0 : if (!(index & info.falsev))
1710 0 : mfalse->append (new json::integer_number (i));
1711 : }
1712 : }
1713 0 : conditions->append (cond);
1714 : }
1715 : }
1716 :
1717 31 : object->append (lineo);
1718 : }
1719 :
1720 : /* Strip filename extension in STR. */
1721 :
1722 : static string
1723 160 : strip_extention (string str)
1724 : {
1725 160 : string::size_type pos = str.rfind ('.');
1726 160 : if (pos != string::npos)
1727 160 : str = str.substr (0, pos);
1728 :
1729 160 : return str;
1730 : }
1731 :
1732 : /* Calculate md5sum for INPUT string and return it in hex string format. */
1733 :
1734 : static string
1735 0 : get_md5sum (const char *input)
1736 : {
1737 0 : md5_ctx ctx;
1738 0 : char md5sum[16];
1739 0 : string str;
1740 :
1741 0 : md5_init_ctx (&ctx);
1742 0 : md5_process_bytes (input, strlen (input), &ctx);
1743 0 : md5_finish_ctx (&ctx, md5sum);
1744 :
1745 0 : for (unsigned i = 0; i < 16; i++)
1746 : {
1747 0 : char b[3];
1748 0 : sprintf (b, "%02x", (unsigned char)md5sum[i]);
1749 0 : str += b;
1750 : }
1751 :
1752 0 : return str;
1753 : }
1754 :
1755 : /* Get the name of the gcov file. The return value must be free'd.
1756 :
1757 : It appends the '.gcov' extension to the *basename* of the file.
1758 : The resulting file name will be in PWD.
1759 :
1760 : e.g.,
1761 : input: foo.da, output: foo.da.gcov
1762 : input: a/b/foo.cc, output: foo.cc.gcov */
1763 :
1764 : static string
1765 160 : get_gcov_intermediate_filename (const char *input_file_name)
1766 : {
1767 160 : string base = lbasename (input_file_name);
1768 320 : string str = strip_extention (base);
1769 :
1770 160 : if (flag_hash_filenames)
1771 : {
1772 0 : str += "##";
1773 0 : str += get_md5sum (input_file_name);
1774 : }
1775 160 : else if (flag_preserve_paths && base != input_file_name)
1776 : {
1777 0 : str += "##";
1778 0 : str += mangle_path (input_file_name);
1779 0 : str = strip_extention (str);
1780 : }
1781 :
1782 160 : str += ".gcov.json.gz";
1783 160 : return str.c_str ();
1784 160 : }
1785 :
1786 : /* Add prime path coverage from INFO to FUNCTION. */
1787 : static void
1788 9 : json_set_prime_path_coverage (json::object &function, function_info &info)
1789 : {
1790 9 : json::array *jpaths = new json::array ();
1791 18 : function.set_integer ("total_prime_paths", info.paths.path_count ());
1792 9 : function.set_integer ("covered_prime_paths", info.paths.covered_paths ());
1793 9 : function.set_integer ("suppressed_prime_paths",
1794 9 : info.paths.suppressed_count ());
1795 9 : function.set ("prime_path_coverage", jpaths);
1796 :
1797 9 : size_t pathno = 0;
1798 18 : for (const vector<unsigned> &path : info.paths.get_paths ())
1799 : {
1800 0 : if (info.paths.covered_p (pathno++))
1801 0 : continue;
1802 :
1803 0 : gcc_assert (!path.empty ());
1804 :
1805 0 : json::object *jpath = new json::object ();
1806 0 : jpaths->append (jpath);
1807 0 : jpath->set_integer ("id", pathno - 1);
1808 :
1809 0 : json::array *jlist = new json::array ();
1810 0 : jpath->set ("sequence", jlist);
1811 :
1812 0 : for (size_t i = 0; i != path.size (); ++i)
1813 : {
1814 0 : const unsigned bb = path[i];
1815 0 : const block_info &block = info.blocks[bb];
1816 0 : const char *edge_kind = "";
1817 0 : if (i + 1 != path.size ())
1818 : {
1819 0 : const arc_info *arc = find_arc (block, path[i+1]);
1820 0 : if (!arc)
1821 : edge_kind = "suppress";
1822 0 : else if (arc->true_value)
1823 : edge_kind = "true";
1824 0 : else if (arc->false_value)
1825 : edge_kind = "false";
1826 0 : else if (arc->fall_through)
1827 : edge_kind = "fallthru";
1828 0 : else if (arc->is_throw)
1829 0 : edge_kind = "throw";
1830 : }
1831 :
1832 0 : json::object *jblock = new json::object ();
1833 0 : json::array *jlocs = new json::array ();
1834 0 : jblock->set_integer ("block_id", block.id);
1835 0 : jblock->set ("locations", jlocs);
1836 0 : jblock->set_string ("edge_kind", edge_kind);
1837 0 : jlist->append (jblock);
1838 0 : for (const block_location_info &loc : block.locations)
1839 : {
1840 : /* loc.lines could be empty when a statement is not anchored to a
1841 : source file -- see g++.dg/gcov/gcov-23.C. */
1842 0 : if (loc.lines.empty ())
1843 0 : continue;
1844 0 : json::object *jloc = new json::object ();
1845 0 : json::array *jline_numbers = new json::array ();
1846 0 : jlocs->append (jloc);
1847 0 : jloc->set_string ("file", sources[loc.source_file_idx].name);
1848 0 : jloc->set ("line_numbers", jline_numbers);
1849 0 : for (unsigned line : loc.lines)
1850 0 : jline_numbers->append (new json::integer_number (line));
1851 : }
1852 : }
1853 : }
1854 9 : }
1855 :
1856 : /* Output the result in JSON intermediate format.
1857 : Source info SRC is dumped into JSON_FILES which is JSON array. */
1858 :
1859 : static void
1860 2 : output_json_intermediate_file (json::array *json_files, source_info *src)
1861 : {
1862 2 : json::object *root = new json::object ();
1863 2 : json_files->append (root);
1864 :
1865 2 : root->set_string ("file", src->name);
1866 :
1867 2 : json::array *functions = new json::array ();
1868 2 : root->set ("functions", functions);
1869 :
1870 2 : std::sort (src->functions.begin (), src->functions.end (),
1871 : function_line_start_cmp ());
1872 11 : for (vector<function_info *>::iterator it = src->functions.begin ();
1873 11 : it != src->functions.end (); it++)
1874 : {
1875 9 : json::object *function = new json::object ();
1876 9 : function->set_string ("name", (*it)->m_name);
1877 9 : function->set_string ("demangled_name", (*it)->get_demangled_name ());
1878 9 : function->set_integer ("start_line", (*it)->start_line);
1879 9 : function->set_integer ("start_column", (*it)->start_column);
1880 9 : function->set_integer ("end_line", (*it)->end_line);
1881 9 : function->set_integer ("end_column", (*it)->end_column);
1882 9 : function->set_integer ("blocks", (*it)->get_block_count ());
1883 9 : function->set_integer ("blocks_executed", (*it)->blocks_executed);
1884 9 : function->set_integer ("blocks_suppressed",
1885 9 : count ((*it)->suppressed_blocks.begin (),
1886 9 : (*it)->suppressed_blocks.end (), true));
1887 9 : function->set_integer ("execution_count", (*it)->blocks[0].count);
1888 :
1889 9 : json_set_prime_path_coverage (*function, **it);
1890 9 : functions->append (function);
1891 : }
1892 :
1893 2 : json::array *lineso = new json::array ();
1894 2 : root->set ("lines", lineso);
1895 :
1896 2 : vector<function_info *> last_non_group_fns;
1897 :
1898 71 : for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
1899 : {
1900 69 : vector<function_info *> *fns = src->get_functions_at_location (line_num);
1901 :
1902 69 : if (fns != NULL)
1903 : /* Print info for all group functions that begin on the line. */
1904 16 : for (vector<function_info *>::iterator it2 = fns->begin ();
1905 16 : it2 != fns->end (); it2++)
1906 : {
1907 9 : if (!(*it2)->is_group)
1908 5 : last_non_group_fns.push_back (*it2);
1909 :
1910 9 : vector<line_info> &lines = (*it2)->lines;
1911 : /* The LINES array is allocated only for group functions. */
1912 13 : for (unsigned i = 0; i < lines.size (); i++)
1913 : {
1914 4 : line_info *line = &lines[i];
1915 4 : output_intermediate_json_line (lineso, line, line_num + i,
1916 4 : (*it2)->m_name);
1917 : }
1918 : }
1919 :
1920 : /* Follow with lines associated with the source file. */
1921 69 : if (line_num < src->lines.size ())
1922 : {
1923 67 : unsigned size = last_non_group_fns.size ();
1924 67 : function_info *last_fn = size > 0 ? last_non_group_fns[size - 1] : NULL;
1925 42 : const char *fname = last_fn ? last_fn->m_name : NULL;
1926 67 : output_intermediate_json_line (lineso, &src->lines[line_num], line_num,
1927 : fname);
1928 :
1929 : /* Pop ending function from stack. */
1930 67 : if (last_fn != NULL && last_fn->end_line == line_num)
1931 5 : last_non_group_fns.pop_back ();
1932 : }
1933 : }
1934 2 : }
1935 :
1936 : /* Function start pair. */
1937 : struct function_start
1938 : {
1939 : unsigned source_file_idx;
1940 : unsigned start_line;
1941 : };
1942 :
1943 : /* Traits class for function start hash maps below. */
1944 :
1945 : struct function_start_pair_hash : typed_noop_remove <function_start>
1946 : {
1947 : typedef function_start value_type;
1948 : typedef function_start compare_type;
1949 :
1950 : static hashval_t
1951 3681 : hash (const function_start &ref)
1952 : {
1953 3681 : inchash::hash hstate (0);
1954 3681 : hstate.add_int (ref.source_file_idx);
1955 3681 : hstate.add_int (ref.start_line);
1956 3681 : return hstate.end ();
1957 : }
1958 :
1959 : static bool
1960 2368 : equal (const function_start &ref1, const function_start &ref2)
1961 : {
1962 2368 : return (ref1.source_file_idx == ref2.source_file_idx
1963 2368 : && ref1.start_line == ref2.start_line);
1964 : }
1965 :
1966 : static void
1967 : mark_deleted (function_start &ref)
1968 : {
1969 : ref.start_line = ~1U;
1970 : }
1971 :
1972 : static const bool empty_zero_p = false;
1973 :
1974 : static void
1975 5002 : mark_empty (function_start &ref)
1976 : {
1977 5002 : ref.start_line = ~2U;
1978 : }
1979 :
1980 : static bool
1981 4924 : is_deleted (const function_start &ref)
1982 : {
1983 4924 : return ref.start_line == ~1U;
1984 : }
1985 :
1986 : static bool
1987 22493 : is_empty (const function_start &ref)
1988 : {
1989 21237 : return ref.start_line == ~2U;
1990 : }
1991 : };
1992 :
1993 : /* Process a single input file. */
1994 :
1995 : static void
1996 160 : process_file (const char *file_name)
1997 : {
1998 160 : create_file_names (file_name);
1999 :
2000 320 : for (unsigned i = 0; i < processed_files.size (); i++)
2001 0 : if (strcmp (da_file_name, processed_files[i]) == 0)
2002 : {
2003 0 : fnotice (stderr, "'%s' file is already processed\n",
2004 : file_name);
2005 0 : return;
2006 : }
2007 :
2008 160 : processed_files.push_back (xstrdup (da_file_name));
2009 :
2010 160 : read_graph_file ();
2011 160 : read_count_file ();
2012 : }
2013 :
2014 : /* Process all functions in all files. */
2015 :
2016 : static void
2017 160 : process_all_functions (void)
2018 : {
2019 160 : hash_map<function_start_pair_hash, function_info *> fn_map;
2020 :
2021 : /* Identify group functions. */
2022 1568 : for (vector<function_info *>::iterator it = functions.begin ();
2023 1568 : it != functions.end (); it++)
2024 1408 : if (!(*it)->artificial)
2025 : {
2026 1363 : function_start needle;
2027 1363 : needle.source_file_idx = (*it)->src;
2028 1363 : needle.start_line = (*it)->start_line;
2029 :
2030 1363 : function_info **slot = fn_map.get (needle);
2031 1363 : if (slot)
2032 : {
2033 107 : (*slot)->is_group = 1;
2034 107 : (*it)->is_group = 1;
2035 : }
2036 : else
2037 1256 : fn_map.put (needle, *it);
2038 : }
2039 :
2040 : /* Remove all artificial function. */
2041 160 : functions.erase (remove_if (functions.begin (), functions.end (),
2042 160 : function_info::is_artificial), functions.end ());
2043 :
2044 1523 : for (vector<function_info *>::iterator it = functions.begin ();
2045 1523 : it != functions.end (); it++)
2046 : {
2047 1363 : function_info *fn = *it;
2048 1363 : unsigned src = fn->src;
2049 :
2050 1363 : if (!fn->suppressed_blocks.empty ())
2051 : {
2052 : /* Set the ignore flag on blocks, arcs. */
2053 3152 : for (block_info &b : fn->blocks)
2054 5828 : if (fn->suppressed_blocks[b.id] || fn->suppressed_p ())
2055 : {
2056 951 : b.suppressed = 1;
2057 2381 : for (arc_info *arc = b.succ; arc; arc = arc->succ_next)
2058 1430 : arc->suppressed = 1;
2059 1966 : for (arc_info *arc = b.pred; arc; arc = arc->pred_next)
2060 1015 : arc->suppressed = 1;
2061 : }
2062 : }
2063 1363 : if (!fn->counts.empty () || no_data_file)
2064 : {
2065 1363 : source_info *s = &sources[src];
2066 1363 : s->add_function (fn);
2067 :
2068 : /* Mark last line in files touched by function. */
2069 15137 : for (unsigned block_no = 0; block_no != fn->blocks.size ();
2070 : block_no++)
2071 : {
2072 12411 : block_info *block = &fn->blocks[block_no];
2073 21627 : for (unsigned i = 0; i < block->locations.size (); i++)
2074 : {
2075 : /* Sort lines of locations. */
2076 18432 : sort (block->locations[i].lines.begin (),
2077 9216 : block->locations[i].lines.end ());
2078 :
2079 9216 : if (!block->locations[i].lines.empty ())
2080 : {
2081 9213 : s = &sources[block->locations[i].source_file_idx];
2082 9213 : unsigned last_line
2083 9213 : = block->locations[i].lines.back ();
2084 :
2085 : /* Record new lines for the function. */
2086 9213 : if (last_line >= s->lines.size ())
2087 : {
2088 1329 : s = &sources[block->locations[i].source_file_idx];
2089 1329 : unsigned last_line
2090 1329 : = block->locations[i].lines.back ();
2091 :
2092 : /* Record new lines for the function. */
2093 1329 : if (last_line >= s->lines.size ())
2094 : {
2095 : /* Record new lines for a source file. */
2096 1329 : s->lines.resize (last_line + 1);
2097 : }
2098 : }
2099 : }
2100 :
2101 18432 : if (block->suppressed || fn->suppressed_p ())
2102 2006 : for (unsigned ln : block->locations[i].lines)
2103 1132 : s->lines[ln].suppressed = 1;
2104 : }
2105 : }
2106 :
2107 : /* Make sure to include the last line for this function even when it
2108 : is not directly covered by a basic block, for example when } is on
2109 : its own line. */
2110 1363 : if (sources[fn->src].lines.size () <= fn->end_line)
2111 169 : sources[fn->src].lines.resize (fn->end_line + 1);
2112 :
2113 : /* Allocate lines for group function, following start_line
2114 : and end_line information of the function. */
2115 1363 : if (fn->is_group)
2116 187 : fn->lines.resize (fn->end_line - fn->start_line + 1);
2117 :
2118 : /* Propagate the suppressed flag too. */
2119 1363 : if (fn->is_group)
2120 : {
2121 187 : const auto& source = sources[fn->src];
2122 1832 : for (unsigned ln = fn->start_line, dst = 0; ln <= fn->end_line;
2123 1645 : ++ln, ++dst)
2124 1645 : fn->lines[dst].suppressed = source.lines.at (ln).suppressed;
2125 : }
2126 :
2127 1363 : solve_flow_graph (fn);
2128 1363 : if (fn->has_catch)
2129 112 : find_exception_blocks (fn);
2130 :
2131 : /* For path coverage. */
2132 1363 : find_prime_paths (fn);
2133 1363 : fn->paths.suppress_blocks (fn->suppressed_blocks);
2134 : }
2135 : else
2136 : {
2137 : /* The function was not in the executable -- some other
2138 : instance must have been selected. */
2139 : }
2140 : }
2141 160 : }
2142 :
2143 : static void
2144 236 : output_gcov_file (const char *file_name, source_info *src)
2145 : {
2146 236 : string gcov_file_name_str
2147 236 : = make_gcov_file_name (file_name, src->coverage.name);
2148 236 : const char *gcov_file_name = gcov_file_name_str.c_str ();
2149 :
2150 236 : if (src->coverage.lines)
2151 : {
2152 236 : FILE *gcov_file = fopen (gcov_file_name, "w");
2153 236 : if (gcov_file)
2154 : {
2155 236 : fnotice (stdout, "Creating '%s'\n", gcov_file_name);
2156 236 : output_lines (gcov_file, src);
2157 236 : if (ferror (gcov_file))
2158 : {
2159 0 : fnotice (stderr, "Error writing output file '%s'\n",
2160 : gcov_file_name);
2161 0 : return_code = 6;
2162 : }
2163 236 : fclose (gcov_file);
2164 : }
2165 : else
2166 : {
2167 0 : fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
2168 0 : return_code = 6;
2169 : }
2170 : }
2171 : else
2172 : {
2173 0 : unlink (gcov_file_name);
2174 0 : fnotice (stdout, "Removing '%s'\n", gcov_file_name);
2175 : }
2176 236 : }
2177 :
2178 : static void
2179 160 : generate_results (const char *file_name)
2180 : {
2181 160 : string gcov_intermediate_filename;
2182 :
2183 1523 : for (vector<function_info *>::iterator it = functions.begin ();
2184 1523 : it != functions.end (); it++)
2185 : {
2186 1363 : function_info *fn = *it;
2187 1363 : coverage_info coverage;
2188 :
2189 1363 : memset (&coverage, 0, sizeof (coverage));
2190 1648 : if (fn->suppressed_p ())
2191 32 : coverage.function_suppressed = 1;
2192 1363 : coverage.name = fn->get_name ();
2193 2726 : add_line_counts (flag_function_summary ? &coverage : NULL, fn);
2194 :
2195 1363 : if (!flag_function_summary)
2196 1363 : continue;
2197 :
2198 0 : for (const block_info& block : fn->blocks)
2199 0 : for (arc_info *arc = block.succ; arc; arc = arc->succ_next)
2200 0 : add_branch_counts (&coverage, arc);
2201 :
2202 0 : for (const block_info& block : fn->blocks)
2203 0 : add_condition_counts (&coverage, &block);
2204 :
2205 0 : add_path_counts (coverage, *fn);
2206 :
2207 0 : function_summary (&coverage);
2208 0 : fnotice (stdout, "\n");
2209 : }
2210 :
2211 160 : name_map needle;
2212 160 : needle.name = file_name;
2213 160 : vector<name_map>::iterator it
2214 160 : = std::find (names.begin (), names.end (), needle);
2215 160 : if (it != names.end ())
2216 3 : file_name = sources[it->src].coverage.name;
2217 : else
2218 157 : file_name = canonicalize_name (file_name);
2219 :
2220 160 : gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
2221 :
2222 160 : json::object *root = new json::object ();
2223 160 : root->set_string ("format_version", GCOV_JSON_FORMAT_VERSION);
2224 160 : root->set_string ("gcc_version", version_string);
2225 :
2226 160 : if (bbg_cwd != NULL)
2227 160 : root->set_string ("current_working_directory", bbg_cwd);
2228 160 : root->set_string ("data_file", file_name);
2229 :
2230 160 : json::array *json_files = new json::array ();
2231 160 : root->set ("files", json_files);
2232 :
2233 398 : for (vector<source_info>::iterator it = sources.begin ();
2234 398 : it != sources.end (); it++)
2235 : {
2236 238 : source_info *src = &(*it);
2237 238 : if (flag_relative_only)
2238 : {
2239 : /* Ignore this source, if it is an absolute path (after
2240 : source prefix removal). */
2241 0 : char first = src->coverage.name[0];
2242 :
2243 : #if HAVE_DOS_BASED_FILE_SYSTEM
2244 : if (first && src->coverage.name[1] == ':')
2245 : first = src->coverage.name[2];
2246 : #endif
2247 0 : if (IS_DIR_SEPARATOR (first))
2248 0 : continue;
2249 : }
2250 :
2251 1601 : for (function_info *fn : src->functions)
2252 1363 : add_path_counts (src->coverage, *fn);
2253 :
2254 238 : accumulate_line_counts (src);
2255 238 : if (flag_debug)
2256 0 : src->debug ();
2257 :
2258 238 : if (!flag_use_stdout)
2259 238 : file_summary (&src->coverage);
2260 238 : total_lines += src->coverage.lines;
2261 238 : total_executed += src->coverage.lines_executed;
2262 238 : total_suppressed += src->coverage.lines_suppressed;
2263 238 : if (flag_gcov_file)
2264 : {
2265 238 : if (flag_json_format)
2266 : {
2267 2 : output_json_intermediate_file (json_files, src);
2268 2 : if (!flag_use_stdout)
2269 2 : fnotice (stdout, "\n");
2270 : }
2271 : else
2272 : {
2273 236 : if (flag_use_stdout)
2274 : {
2275 0 : if (src->coverage.lines)
2276 0 : output_lines (stdout, src);
2277 : }
2278 : else
2279 : {
2280 236 : output_gcov_file (file_name, src);
2281 236 : fnotice (stdout, "\n");
2282 : }
2283 : }
2284 : }
2285 : }
2286 :
2287 160 : if (flag_gcov_file && flag_json_format)
2288 : {
2289 2 : if (flag_use_stdout)
2290 : {
2291 0 : root->dump (stdout, false);
2292 0 : printf ("\n");
2293 : }
2294 : else
2295 : {
2296 2 : pretty_printer pp;
2297 2 : root->print (&pp, false);
2298 2 : pp_formatted_text (&pp);
2299 :
2300 2 : fnotice (stdout, "Creating '%s'\n",
2301 : gcov_intermediate_filename.c_str ());
2302 2 : gzFile output = gzopen (gcov_intermediate_filename.c_str (), "w");
2303 2 : if (output == NULL)
2304 : {
2305 0 : fnotice (stderr, "Cannot open JSON output file %s\n",
2306 : gcov_intermediate_filename.c_str ());
2307 0 : return_code = 6;
2308 0 : return;
2309 : }
2310 :
2311 2 : if (gzputs (output, pp_formatted_text (&pp)) == EOF
2312 2 : || gzclose (output))
2313 : {
2314 0 : fnotice (stderr, "Error writing JSON output file %s\n",
2315 : gcov_intermediate_filename.c_str ());
2316 0 : return_code = 6;
2317 0 : return;
2318 : }
2319 2 : }
2320 : }
2321 160 : }
2322 :
2323 : /* Release all memory used. */
2324 :
2325 : static void
2326 160 : release_structures (void)
2327 : {
2328 1523 : for (vector<function_info *>::iterator it = functions.begin ();
2329 1523 : it != functions.end (); it++)
2330 1363 : delete (*it);
2331 :
2332 396 : for (vector<const char *> *lines : source_lines)
2333 : {
2334 236 : if (lines)
2335 102529 : for (const char *line : *lines)
2336 102293 : free (const_cast <char*> (line));
2337 236 : delete (lines);
2338 : }
2339 160 : source_lines.resize (0);
2340 :
2341 175 : for (fnfilter &filter : filters)
2342 15 : regfree (&filter.regex);
2343 :
2344 160 : sources.resize (0);
2345 160 : names.resize (0);
2346 160 : functions.resize (0);
2347 160 : filters.resize (0);
2348 160 : ident_to_fn.clear ();
2349 160 : }
2350 :
2351 : /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
2352 : is not specified, these are named from FILE_NAME sans extension. If
2353 : OBJECT_DIRECTORY is specified and is a directory, the files are in that
2354 : directory, but named from the basename of the FILE_NAME, sans extension.
2355 : Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
2356 : and the data files are named from that. */
2357 :
2358 : static void
2359 160 : create_file_names (const char *file_name)
2360 : {
2361 160 : char *cptr;
2362 160 : char *name;
2363 160 : int length = strlen (file_name);
2364 160 : int base;
2365 :
2366 : /* Free previous file names. */
2367 160 : free (bbg_file_name);
2368 160 : free (da_file_name);
2369 160 : da_file_name = bbg_file_name = NULL;
2370 160 : bbg_file_time = 0;
2371 160 : bbg_stamp = 0;
2372 :
2373 160 : if (object_directory && object_directory[0])
2374 : {
2375 0 : struct stat status;
2376 :
2377 0 : length += strlen (object_directory) + 2;
2378 0 : name = XNEWVEC (char, length);
2379 0 : name[0] = 0;
2380 :
2381 0 : base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
2382 0 : strcat (name, object_directory);
2383 0 : if (base && (!IS_DIR_SEPARATOR (name[strlen (name) - 1])))
2384 0 : strcat (name, "/");
2385 : }
2386 : else
2387 : {
2388 160 : name = XNEWVEC (char, length + 1);
2389 160 : strcpy (name, file_name);
2390 160 : base = 0;
2391 : }
2392 :
2393 160 : if (base)
2394 : {
2395 : /* Append source file name. */
2396 0 : const char *cptr = lbasename (file_name);
2397 0 : strcat (name, cptr ? cptr : file_name);
2398 : }
2399 :
2400 : /* Remove the extension. */
2401 160 : cptr = strrchr (const_cast<char *> (lbasename (name)), '.');
2402 160 : if (cptr)
2403 160 : *cptr = 0;
2404 :
2405 160 : length = strlen (name);
2406 :
2407 160 : bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
2408 160 : strcpy (bbg_file_name, name);
2409 160 : strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
2410 :
2411 160 : da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
2412 160 : strcpy (da_file_name, name);
2413 160 : strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
2414 :
2415 160 : free (name);
2416 160 : return;
2417 : }
2418 :
2419 : /* Find or create a source file structure for FILE_NAME. Copies
2420 : FILE_NAME on creation */
2421 :
2422 : static unsigned
2423 10904 : find_source (const char *file_name)
2424 : {
2425 10904 : char *canon;
2426 10904 : unsigned idx;
2427 10904 : struct stat status;
2428 :
2429 10904 : if (!file_name)
2430 0 : file_name = "<unknown>";
2431 :
2432 10904 : name_map needle;
2433 10904 : needle.name = file_name;
2434 :
2435 10904 : vector<name_map>::iterator it = std::find (names.begin (), names.end (),
2436 : needle);
2437 10904 : if (it != names.end ())
2438 : {
2439 10665 : idx = it->src;
2440 10665 : goto check_date;
2441 : }
2442 :
2443 : /* Not found, try the canonical name. */
2444 239 : canon = canonicalize_name (file_name);
2445 239 : needle.name = canon;
2446 239 : it = std::find (names.begin (), names.end (), needle);
2447 239 : if (it == names.end ())
2448 : {
2449 : /* Not found with canonical name, create a new source. */
2450 238 : source_info *src;
2451 :
2452 238 : idx = sources.size ();
2453 238 : needle = name_map (canon, idx);
2454 238 : names.push_back (needle);
2455 :
2456 238 : sources.push_back (source_info ());
2457 238 : src = &sources.back ();
2458 238 : src->name = canon;
2459 238 : src->coverage.name = src->name;
2460 238 : src->index = idx;
2461 238 : if (source_length
2462 : #if HAVE_DOS_BASED_FILE_SYSTEM
2463 : /* You lose if separators don't match exactly in the
2464 : prefix. */
2465 : && !strncasecmp (source_prefix, src->coverage.name, source_length)
2466 : #else
2467 0 : && !strncmp (source_prefix, src->coverage.name, source_length)
2468 : #endif
2469 0 : && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
2470 0 : src->coverage.name += source_length + 1;
2471 238 : if (!stat (src->name, &status))
2472 235 : src->file_time = status.st_mtime;
2473 : }
2474 : else
2475 1 : idx = it->src;
2476 :
2477 239 : needle.name = file_name;
2478 239 : if (std::find (names.begin (), names.end (), needle) == names.end ())
2479 : {
2480 : /* Append the non-canonical name. */
2481 1 : names.push_back (name_map (xstrdup (file_name), idx));
2482 : }
2483 :
2484 : /* Resort the name map. */
2485 239 : std::sort (names.begin (), names.end ());
2486 :
2487 10904 : check_date:
2488 10904 : if (sources[idx].file_time > bbg_file_time)
2489 : {
2490 0 : static int info_emitted;
2491 :
2492 0 : fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
2493 : file_name, bbg_file_name);
2494 0 : if (!info_emitted)
2495 : {
2496 0 : fnotice (stderr,
2497 : "(the message is displayed only once per source file)\n");
2498 0 : info_emitted = 1;
2499 : }
2500 0 : sources[idx].file_time = 0;
2501 : }
2502 :
2503 10904 : return idx;
2504 : }
2505 :
2506 : /* Read the notes file. Save functions to FUNCTIONS global vector. */
2507 :
2508 : static void
2509 160 : read_graph_file (void)
2510 : {
2511 160 : unsigned version;
2512 160 : unsigned current_tag = 0;
2513 160 : unsigned tag;
2514 :
2515 160 : if (!gcov_open (bbg_file_name, 1))
2516 : {
2517 0 : fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
2518 0 : return_code = 1;
2519 0 : return;
2520 : }
2521 160 : bbg_file_time = gcov_time ();
2522 160 : if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
2523 : {
2524 0 : fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
2525 0 : return_code = 2;
2526 0 : gcov_close ();
2527 0 : return;
2528 : }
2529 :
2530 160 : version = gcov_read_unsigned ();
2531 160 : if (version != GCOV_VERSION)
2532 : {
2533 0 : char v[4], e[4];
2534 :
2535 0 : GCOV_UNSIGNED2STRING (v, version);
2536 0 : GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
2537 :
2538 0 : fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
2539 : bbg_file_name, v, e);
2540 0 : return_code = 3;
2541 : }
2542 160 : bbg_stamp = gcov_read_unsigned ();
2543 : /* Read checksum. */
2544 160 : gcov_read_unsigned ();
2545 160 : bbg_cwd = xstrdup (gcov_read_string ());
2546 160 : bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
2547 :
2548 160 : function_info *fn = NULL;
2549 24519 : while ((tag = gcov_read_unsigned ()))
2550 : {
2551 24359 : unsigned length = gcov_read_unsigned ();
2552 24359 : gcov_position_t base = gcov_position ();
2553 :
2554 24359 : if (tag == GCOV_TAG_FUNCTION)
2555 : {
2556 1450 : char *function_name;
2557 1450 : unsigned ident;
2558 1450 : unsigned lineno_checksum, cfg_checksum;
2559 :
2560 1450 : ident = gcov_read_unsigned ();
2561 1450 : lineno_checksum = gcov_read_unsigned ();
2562 1450 : cfg_checksum = gcov_read_unsigned ();
2563 1450 : function_name = xstrdup (gcov_read_string ());
2564 1450 : unsigned artificial = gcov_read_unsigned ();
2565 1450 : unsigned src_idx = find_source (gcov_read_string ());
2566 1450 : unsigned start_line = gcov_read_unsigned ();
2567 1450 : unsigned start_column = gcov_read_unsigned ();
2568 1450 : unsigned end_line = gcov_read_unsigned ();
2569 1450 : unsigned end_column = gcov_read_unsigned ();
2570 :
2571 1450 : fn = new function_info ();
2572 :
2573 1450 : fn->m_name = function_name;
2574 1450 : fn->ident = ident;
2575 1450 : fn->lineno_checksum = lineno_checksum;
2576 1450 : fn->cfg_checksum = cfg_checksum;
2577 1450 : fn->src = src_idx;
2578 1450 : fn->start_line = start_line;
2579 1450 : fn->start_column = start_column;
2580 1450 : fn->end_line = end_line;
2581 1450 : fn->end_column = end_column;
2582 1450 : fn->artificial = artificial;
2583 :
2584 1450 : current_tag = tag;
2585 :
2586 : /* This is separate from flag_demangled_names to support filtering on
2587 : mangled names while printing demangled names, or filtering on
2588 : demangled names while printing mangled names. An independent flag
2589 : makes sure the function selection does not change even if
2590 : demangling is turned on/off. */
2591 1450 : const char *fname = function_name;
2592 1450 : if (flag_filter_on_demangled)
2593 12 : fname = fn->get_demangled_name ();
2594 :
2595 1450 : bool keep = default_keep;
2596 1522 : for (const fnfilter &fn : filters)
2597 72 : if (regexec (&fn.regex, fname, 0, nullptr, 0) == 0)
2598 26 : keep = fn.keep;
2599 :
2600 1450 : if (keep)
2601 : {
2602 1408 : functions.push_back (fn);
2603 1408 : ident_to_fn[ident] = fn;
2604 : }
2605 : }
2606 22909 : else if (fn && tag == GCOV_TAG_BLOCKS)
2607 : {
2608 1450 : if (!fn->blocks.empty ())
2609 0 : fnotice (stderr, "%s:already seen blocks for '%s'\n",
2610 : bbg_file_name, fn->get_name ());
2611 : else
2612 1450 : fn->blocks.resize (gcov_read_unsigned ());
2613 : }
2614 21459 : else if (fn && tag == GCOV_TAG_ARCS)
2615 : {
2616 11366 : unsigned src = gcov_read_unsigned ();
2617 11366 : fn->blocks[src].id = src;
2618 11366 : unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
2619 11366 : block_info *src_blk = &fn->blocks[src];
2620 11366 : unsigned mark_catches = 0;
2621 11366 : struct arc_info *arc;
2622 :
2623 11366 : if (src >= fn->blocks.size () || fn->blocks[src].succ)
2624 0 : goto corrupt;
2625 :
2626 28482 : while (num_dests--)
2627 : {
2628 17116 : unsigned dest = gcov_read_unsigned ();
2629 17116 : unsigned flags = gcov_read_unsigned ();
2630 :
2631 17116 : if (dest >= fn->blocks.size ())
2632 0 : goto corrupt;
2633 17116 : arc = XCNEW (arc_info);
2634 :
2635 17116 : arc->dst = &fn->blocks[dest];
2636 : /* Set id in order to find EXIT_BLOCK. */
2637 17116 : arc->dst->id = dest;
2638 17116 : arc->src = src_blk;
2639 :
2640 17116 : arc->count = 0;
2641 17116 : arc->count_valid = 0;
2642 17116 : arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
2643 17116 : arc->fake = !!(flags & GCOV_ARC_FAKE);
2644 17116 : arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
2645 17116 : arc->true_value = !!(flags & GCOV_ARC_TRUE);
2646 17116 : arc->false_value = !!(flags & GCOV_ARC_FALSE);
2647 17116 : arc->suppressed = 0;
2648 :
2649 17116 : arc->succ_next = src_blk->succ;
2650 17116 : src_blk->succ = arc;
2651 17116 : src_blk->num_succ++;
2652 :
2653 17116 : arc->pred_next = fn->blocks[dest].pred;
2654 17116 : fn->blocks[dest].pred = arc;
2655 17116 : fn->blocks[dest].num_pred++;
2656 :
2657 17116 : if (arc->fake)
2658 : {
2659 3225 : if (src)
2660 : {
2661 : /* Exceptional exit from this function, the
2662 : source block must be a call. */
2663 3208 : fn->blocks[src].is_call_site = 1;
2664 3208 : arc->is_call_non_return = 1;
2665 3208 : mark_catches = 1;
2666 : }
2667 : else
2668 : {
2669 : /* Non-local return from a callee of this
2670 : function. The destination block is a setjmp. */
2671 17 : arc->is_nonlocal_return = 1;
2672 17 : fn->blocks[dest].is_nonlocal_return = 1;
2673 : }
2674 : }
2675 :
2676 17116 : if (!arc->on_tree)
2677 7200 : fn->counts.push_back (0);
2678 : }
2679 :
2680 11366 : if (mark_catches)
2681 : {
2682 : /* We have a fake exit from this block. The other
2683 : non-fall through exits must be to catch handlers.
2684 : Mark them as catch arcs. */
2685 :
2686 9661 : for (arc = src_blk->succ; arc; arc = arc->succ_next)
2687 6453 : if (!arc->fake && !arc->fall_through)
2688 : {
2689 301 : arc->is_throw = 1;
2690 301 : fn->has_catch = 1;
2691 : }
2692 : }
2693 : }
2694 10093 : else if (fn && tag == GCOV_TAG_SUPPRESS)
2695 : {
2696 285 : const unsigned nblocks = GCOV_TAG_SUPPRESS_NUM (length);
2697 285 : if (!fn->suppressed_blocks.empty ())
2698 0 : fnotice (stderr, "%s:already seen suppressed blocks for '%s'\n",
2699 : bbg_file_name, fn->get_name ());
2700 285 : fn->suppressed_blocks.resize (fn->blocks.size (), false);
2701 1427 : for (unsigned i = 0; i != nblocks; ++i)
2702 : {
2703 857 : const unsigned idx = gcov_read_unsigned ();
2704 857 : if (idx >= fn->blocks.size ())
2705 0 : goto corrupt;
2706 857 : fn->suppressed_blocks[idx] = true;
2707 : }
2708 : }
2709 9808 : else if (fn && tag == GCOV_TAG_CONDS)
2710 : {
2711 144 : unsigned num_dests = GCOV_TAG_CONDS_NUM (length);
2712 :
2713 144 : if (!fn->conditions.empty ())
2714 0 : fnotice (stderr, "%s:already seen conditions for '%s'\n",
2715 : bbg_file_name, fn->get_name ());
2716 : else
2717 144 : fn->conditions.resize (num_dests);
2718 :
2719 389 : for (unsigned i = 0; i < num_dests; ++i)
2720 : {
2721 245 : unsigned idx = gcov_read_unsigned ();
2722 :
2723 245 : if (idx >= fn->blocks.size ())
2724 0 : goto corrupt;
2725 :
2726 245 : condition_info *info = &fn->blocks[idx].conditions;
2727 245 : info->n_terms = gcov_read_unsigned ();
2728 245 : fn->conditions[i] = info;
2729 : }
2730 : }
2731 9664 : else if (fn && tag == GCOV_TAG_PATHS)
2732 : {
2733 295 : const unsigned npaths = gcov_read_unsigned ();
2734 295 : const size_t nbits = path_info::bucketsize;
2735 295 : const size_t nbuckets = (npaths + (nbits - 1)) / nbits;
2736 295 : fn->paths.covered.assign (nbuckets, 0);
2737 295 : }
2738 9369 : else if (fn && tag == GCOV_TAG_LINES)
2739 : {
2740 9369 : unsigned blockno = gcov_read_unsigned ();
2741 9369 : block_info *block = &fn->blocks[blockno];
2742 :
2743 9369 : if (blockno >= fn->blocks.size ())
2744 0 : goto corrupt;
2745 :
2746 52419 : while (true)
2747 : {
2748 30894 : unsigned lineno = gcov_read_unsigned ();
2749 :
2750 30894 : if (lineno)
2751 12071 : block->locations.back ().lines.push_back (lineno);
2752 : else
2753 : {
2754 18823 : const char *file_name = gcov_read_string ();
2755 :
2756 18823 : if (!file_name)
2757 : break;
2758 9454 : block->locations.push_back (block_location_info
2759 9454 : (find_source (file_name)));
2760 : }
2761 21525 : }
2762 9369 : }
2763 0 : else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
2764 : {
2765 0 : fn = NULL;
2766 0 : current_tag = 0;
2767 : }
2768 24359 : gcov_sync (base, length);
2769 24359 : if (gcov_is_error ())
2770 : {
2771 0 : corrupt:;
2772 0 : fnotice (stderr, "%s:corrupted\n", bbg_file_name);
2773 0 : return_code = 4;
2774 0 : break;
2775 : }
2776 : }
2777 160 : gcov_close ();
2778 :
2779 160 : if (functions.empty ())
2780 3 : fnotice (stderr, "%s:no functions found\n", bbg_file_name);
2781 : }
2782 :
2783 : /* Reads profiles from the count file and attach to each
2784 : function. Return nonzero if fatal error. */
2785 :
2786 : static int
2787 160 : read_count_file (void)
2788 : {
2789 160 : unsigned ix;
2790 160 : unsigned version;
2791 160 : unsigned tag;
2792 160 : function_info *fn = NULL;
2793 160 : int error = 0;
2794 160 : map<unsigned, function_info *>::iterator it;
2795 :
2796 160 : if (!gcov_open (da_file_name, 1))
2797 : {
2798 14 : fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
2799 : da_file_name);
2800 14 : no_data_file = 1;
2801 14 : return 0;
2802 : }
2803 146 : if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
2804 : {
2805 0 : fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
2806 0 : return_code = 2;
2807 0 : cleanup:;
2808 0 : gcov_close ();
2809 0 : return 1;
2810 : }
2811 146 : version = gcov_read_unsigned ();
2812 146 : if (version != GCOV_VERSION)
2813 : {
2814 0 : char v[4], e[4];
2815 :
2816 0 : GCOV_UNSIGNED2STRING (v, version);
2817 0 : GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
2818 :
2819 0 : fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
2820 : da_file_name, v, e);
2821 0 : return_code = 3;
2822 : }
2823 146 : tag = gcov_read_unsigned ();
2824 146 : if (tag != bbg_stamp)
2825 : {
2826 0 : fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
2827 0 : return_code = 5;
2828 0 : goto cleanup;
2829 : }
2830 :
2831 : /* Read checksum. */
2832 146 : gcov_read_unsigned ();
2833 :
2834 3299 : while ((tag = gcov_read_unsigned ()))
2835 : {
2836 3007 : unsigned length = gcov_read_unsigned ();
2837 3007 : int read_length = (int)length;
2838 3007 : unsigned long base = gcov_position ();
2839 :
2840 3007 : if (tag == GCOV_TAG_OBJECT_SUMMARY)
2841 : {
2842 146 : struct gcov_summary summary;
2843 146 : gcov_read_summary (&summary);
2844 146 : object_runs = summary.runs;
2845 : }
2846 2861 : else if (tag == GCOV_TAG_FUNCTION && !length)
2847 : ; /* placeholder */
2848 2861 : else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
2849 : {
2850 1338 : unsigned ident;
2851 1338 : ident = gcov_read_unsigned ();
2852 1338 : fn = NULL;
2853 1338 : it = ident_to_fn.find (ident);
2854 1338 : if (it != ident_to_fn.end ())
2855 1296 : fn = it->second;
2856 :
2857 1296 : if (!fn)
2858 : ;
2859 1296 : else if (gcov_read_unsigned () != fn->lineno_checksum
2860 1296 : || gcov_read_unsigned () != fn->cfg_checksum)
2861 : {
2862 0 : mismatch:;
2863 0 : fnotice (stderr, "%s:profile mismatch for '%s'\n",
2864 : da_file_name, fn->get_name ());
2865 0 : goto cleanup;
2866 : }
2867 : }
2868 1523 : else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_CONDS) && fn)
2869 : {
2870 120 : length = abs (read_length);
2871 120 : if (length != GCOV_TAG_COUNTER_LENGTH (2 * fn->conditions.size ()))
2872 0 : goto mismatch;
2873 :
2874 120 : if (read_length > 0)
2875 : {
2876 358 : for (ix = 0; ix != fn->conditions.size (); ix++)
2877 : {
2878 240 : fn->conditions[ix]->truev |= gcov_read_counter ();
2879 240 : fn->conditions[ix]->falsev |= gcov_read_counter ();
2880 : }
2881 : }
2882 : }
2883 1403 : else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
2884 : {
2885 1142 : length = abs (read_length);
2886 1142 : if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
2887 0 : goto mismatch;
2888 :
2889 1142 : if (read_length > 0)
2890 5897 : for (ix = 0; ix != fn->counts.size (); ix++)
2891 4863 : fn->counts[ix] += gcov_read_counter ();
2892 : }
2893 261 : else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_PATHS) && fn)
2894 : {
2895 213 : vector<gcov_type_unsigned> &covered = fn->paths.covered;
2896 213 : length = abs (read_length);
2897 213 : if (length != GCOV_TAG_COUNTER_LENGTH (covered.size ()))
2898 0 : goto mismatch;
2899 :
2900 213 : if (read_length > 0)
2901 276 : for (ix = 0; ix != covered.size (); ix++)
2902 142 : covered[ix] = gcov_read_counter ();
2903 : }
2904 3007 : if (read_length < 0)
2905 : read_length = 0;
2906 3007 : gcov_sync (base, read_length);
2907 3007 : if ((error = gcov_is_error ()))
2908 : {
2909 0 : fnotice (stderr,
2910 : error < 0
2911 : ? N_("%s:overflowed\n")
2912 : : N_("%s:corrupted\n"),
2913 : da_file_name);
2914 0 : return_code = 4;
2915 0 : goto cleanup;
2916 : }
2917 : }
2918 :
2919 146 : gcov_close ();
2920 146 : return 0;
2921 : }
2922 :
2923 : /* Solve the flow graph. Propagate counts from the instrumented arcs
2924 : to the blocks and the uninstrumented arcs. */
2925 :
2926 : static void
2927 1363 : solve_flow_graph (function_info *fn)
2928 : {
2929 1363 : unsigned ix;
2930 1363 : arc_info *arc;
2931 1363 : gcov_type *count_ptr = &fn->counts.front ();
2932 1363 : block_info *blk;
2933 1363 : block_info *valid_blocks = NULL; /* valid, but unpropagated blocks. */
2934 1363 : block_info *invalid_blocks = NULL; /* invalid, but inferable blocks. */
2935 :
2936 : /* The arcs were built in reverse order. Fix that now. */
2937 13774 : for (ix = fn->blocks.size (); ix--;)
2938 : {
2939 12411 : arc_info *arc_p, *arc_n;
2940 :
2941 29110 : for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
2942 16699 : arc_p = arc, arc = arc_n)
2943 : {
2944 16699 : arc_n = arc->succ_next;
2945 16699 : arc->succ_next = arc_p;
2946 : }
2947 12411 : fn->blocks[ix].succ = arc_p;
2948 :
2949 29110 : for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
2950 16699 : arc_p = arc, arc = arc_n)
2951 : {
2952 16699 : arc_n = arc->pred_next;
2953 16699 : arc->pred_next = arc_p;
2954 : }
2955 12411 : fn->blocks[ix].pred = arc_p;
2956 : }
2957 :
2958 1363 : if (fn->blocks.size () < 2)
2959 0 : fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
2960 : bbg_file_name, fn->get_name ());
2961 : else
2962 : {
2963 1363 : if (fn->blocks[ENTRY_BLOCK].num_pred)
2964 0 : fnotice (stderr, "%s:'%s' has arcs to entry block\n",
2965 : bbg_file_name, fn->get_name ());
2966 : else
2967 : /* We can't deduce the entry block counts from the lack of
2968 : predecessors. */
2969 1363 : fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
2970 :
2971 1363 : if (fn->blocks[EXIT_BLOCK].num_succ)
2972 0 : fnotice (stderr, "%s:'%s' has arcs from exit block\n",
2973 : bbg_file_name, fn->get_name ());
2974 : else
2975 : /* Likewise, we can't deduce exit block counts from the lack
2976 : of its successors. */
2977 1363 : fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
2978 : }
2979 :
2980 : /* Propagate the measured counts, this must be done in the same
2981 : order as the code in profile.cc */
2982 13774 : for (unsigned i = 0; i < fn->blocks.size (); i++)
2983 : {
2984 12411 : blk = &fn->blocks[i];
2985 12411 : block_info const *prev_dst = NULL;
2986 12411 : int out_of_order = 0;
2987 12411 : int non_fake_succ = 0;
2988 :
2989 29110 : for (arc = blk->succ; arc; arc = arc->succ_next)
2990 : {
2991 16699 : if (!arc->fake)
2992 13571 : non_fake_succ++;
2993 :
2994 16699 : if (!arc->on_tree)
2995 : {
2996 7014 : if (count_ptr)
2997 7014 : arc->count = *count_ptr++;
2998 7014 : arc->count_valid = 1;
2999 7014 : blk->num_succ--;
3000 7014 : arc->dst->num_pred--;
3001 : }
3002 16699 : if (prev_dst && prev_dst > arc->dst)
3003 16699 : out_of_order = 1;
3004 16699 : prev_dst = arc->dst;
3005 : }
3006 12411 : if (non_fake_succ == 1)
3007 : {
3008 : /* If there is only one non-fake exit, it is an
3009 : unconditional branch. */
3010 20047 : for (arc = blk->succ; arc; arc = arc->succ_next)
3011 11314 : if (!arc->fake)
3012 : {
3013 8733 : arc->is_unconditional = 1;
3014 : /* If this block is instrumenting a call, it might be
3015 : an artificial block. It is not artificial if it has
3016 : a non-fallthrough exit, or the destination of this
3017 : arc has more than one entry. Mark the destination
3018 : block as a return site, if none of those conditions
3019 : hold. */
3020 8733 : if (blk->is_call_site && arc->fall_through
3021 2557 : && arc->dst->pred == arc && !arc->pred_next)
3022 2166 : arc->dst->is_call_return = 1;
3023 : }
3024 : }
3025 :
3026 : /* Sort the successor arcs into ascending dst order. profile.cc
3027 : normally produces arcs in the right order, but sometimes with
3028 : one or two out of order. We're not using a particularly
3029 : smart sort. */
3030 12411 : if (out_of_order)
3031 : {
3032 : arc_info *start = blk->succ;
3033 : unsigned changes = 1;
3034 :
3035 10003 : while (changes)
3036 : {
3037 : arc_info *arc, *arc_p, *arc_n;
3038 :
3039 : changes = 0;
3040 15892 : for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
3041 : {
3042 9120 : if (arc->dst > arc_n->dst)
3043 : {
3044 4522 : changes = 1;
3045 4522 : if (arc_p)
3046 1010 : arc_p->succ_next = arc_n;
3047 : else
3048 : start = arc_n;
3049 4522 : arc->succ_next = arc_n->succ_next;
3050 4522 : arc_n->succ_next = arc;
3051 4522 : arc_p = arc_n;
3052 : }
3053 : else
3054 : {
3055 : arc_p = arc;
3056 : arc = arc_n;
3057 : }
3058 : }
3059 : }
3060 3231 : blk->succ = start;
3061 : }
3062 :
3063 : /* Place it on the invalid chain, it will be ignored if that's
3064 : wrong. */
3065 12411 : blk->invalid_chain = 1;
3066 12411 : blk->chain = invalid_blocks;
3067 12411 : invalid_blocks = blk;
3068 : }
3069 :
3070 6312 : while (invalid_blocks || valid_blocks)
3071 : {
3072 21507 : while ((blk = invalid_blocks))
3073 : {
3074 16558 : gcov_type total = 0;
3075 16558 : const arc_info *arc;
3076 :
3077 16558 : invalid_blocks = blk->chain;
3078 16558 : blk->invalid_chain = 0;
3079 16558 : if (!blk->num_succ)
3080 4473 : for (arc = blk->succ; arc; arc = arc->succ_next)
3081 2369 : total += arc->count;
3082 14454 : else if (!blk->num_pred)
3083 25842 : for (arc = blk->pred; arc; arc = arc->pred_next)
3084 15535 : total += arc->count;
3085 : else
3086 4147 : continue;
3087 :
3088 12411 : blk->count = total;
3089 12411 : blk->count_valid = 1;
3090 12411 : blk->chain = valid_blocks;
3091 12411 : blk->valid_chain = 1;
3092 12411 : valid_blocks = blk;
3093 : }
3094 17788 : while ((blk = valid_blocks))
3095 : {
3096 12839 : gcov_type total;
3097 12839 : arc_info *arc, *inv_arc;
3098 :
3099 12839 : valid_blocks = blk->chain;
3100 12839 : blk->valid_chain = 0;
3101 12839 : if (blk->num_succ == 1)
3102 : {
3103 8944 : block_info *dst;
3104 :
3105 8944 : total = blk->count;
3106 8944 : inv_arc = NULL;
3107 23274 : for (arc = blk->succ; arc; arc = arc->succ_next)
3108 : {
3109 14330 : total -= arc->count;
3110 14330 : if (!arc->count_valid)
3111 8944 : inv_arc = arc;
3112 : }
3113 8944 : dst = inv_arc->dst;
3114 8944 : inv_arc->count_valid = 1;
3115 8944 : inv_arc->count = total;
3116 8944 : blk->num_succ--;
3117 8944 : dst->num_pred--;
3118 8944 : if (dst->count_valid)
3119 : {
3120 206 : if (dst->num_pred == 1 && !dst->valid_chain)
3121 : {
3122 66 : dst->chain = valid_blocks;
3123 66 : dst->valid_chain = 1;
3124 66 : valid_blocks = dst;
3125 : }
3126 : }
3127 : else
3128 : {
3129 8738 : if (!dst->num_pred && !dst->invalid_chain)
3130 : {
3131 3950 : dst->chain = invalid_blocks;
3132 3950 : dst->invalid_chain = 1;
3133 3950 : invalid_blocks = dst;
3134 : }
3135 : }
3136 : }
3137 12839 : if (blk->num_pred == 1)
3138 : {
3139 741 : block_info *src;
3140 :
3141 741 : total = blk->count;
3142 741 : inv_arc = NULL;
3143 1905 : for (arc = blk->pred; arc; arc = arc->pred_next)
3144 : {
3145 1164 : total -= arc->count;
3146 1164 : if (!arc->count_valid)
3147 741 : inv_arc = arc;
3148 : }
3149 741 : src = inv_arc->src;
3150 741 : inv_arc->count_valid = 1;
3151 741 : inv_arc->count = total;
3152 741 : blk->num_pred--;
3153 741 : src->num_succ--;
3154 741 : if (src->count_valid)
3155 : {
3156 401 : if (src->num_succ == 1 && !src->valid_chain)
3157 : {
3158 362 : src->chain = valid_blocks;
3159 362 : src->valid_chain = 1;
3160 362 : valid_blocks = src;
3161 : }
3162 : }
3163 : else
3164 : {
3165 340 : if (!src->num_succ && !src->invalid_chain)
3166 : {
3167 197 : src->chain = invalid_blocks;
3168 197 : src->invalid_chain = 1;
3169 197 : invalid_blocks = src;
3170 : }
3171 : }
3172 : }
3173 : }
3174 : }
3175 :
3176 : /* If the graph has been correctly solved, every block will have a
3177 : valid count. */
3178 13774 : for (unsigned i = 0; i < fn->blocks.size (); i++)
3179 12411 : if (!fn->blocks[i].count_valid)
3180 : {
3181 0 : fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
3182 : bbg_file_name, fn->get_name ());
3183 0 : break;
3184 : }
3185 1363 : }
3186 :
3187 : /* Find the prime paths of the function from the CFG and add to FN
3188 : using the same function as gcc. It relies on gcc recording the CFG
3189 : faithfully. Storing the paths explicitly takes up way too much
3190 : space to be practical, but this means we need to recompute the
3191 : (exact) same paths in gcov. This should give paths in
3192 : lexicographical order so that the nth path in gcc is the nth path
3193 : in gcov. ENTRY_BLOCK and EXIT_BLOCK are both removed from all
3194 : paths. */
3195 : static void
3196 1363 : find_prime_paths (function_info *fn)
3197 : {
3198 1363 : if (!flag_prime_paths)
3199 1088 : return;
3200 :
3201 : /* If paths.covered being empty then this function was not
3202 : instrumented, probably because it exceeded #-of-paths limit. In
3203 : this case we don't want to find the prime paths as it will take
3204 : too long, and covered paths are not measured. */
3205 278 : if (fn->paths.covered.empty ())
3206 : return;
3207 :
3208 275 : struct graph *cfg = new_graph (fn->blocks.size ());
3209 2899 : for (block_info &block : fn->blocks)
3210 : {
3211 2624 : cfg->vertices[block.id].data = █
3212 6374 : for (arc_info *arc = block.succ; arc; arc = arc->succ_next)
3213 3750 : if (!arc->fake)
3214 3264 : add_edge (cfg, arc->src->id, arc->dst->id)->data = arc;
3215 : }
3216 :
3217 275 : vec<vec<int>> prime_paths (struct graph*, size_t);
3218 : /* TODO: Pass extra information in the PATH_TAG section. In case
3219 : that is empty this might still need to be tunable should the
3220 : coverage be requested without instrumentation. */
3221 275 : vec<vec<int>> paths = prime_paths (cfg, (size_t)-1);
3222 550 : fn->paths.paths.reserve (paths.length ());
3223 2828 : for (vec<int> &path : paths)
3224 : {
3225 2003 : const int *begin = path.begin ();
3226 2003 : const int *end = path.end ();
3227 4006 : if (begin != end && path.last () == EXIT_BLOCK)
3228 1340 : --end;
3229 2003 : if (begin != end && *begin == ENTRY_BLOCK)
3230 1430 : ++begin;
3231 :
3232 2003 : if (begin == end)
3233 45 : continue;
3234 :
3235 : /* If this is an isolated vertex because abnormal edges and fake
3236 : edges are removed, don't include it. */
3237 1979 : if (end - begin == 1 && !cfg->vertices[*begin].succ
3238 24 : && !cfg->vertices[*begin].pred)
3239 21 : continue;
3240 :
3241 1958 : fn->paths.paths.emplace_back (begin, end);
3242 : }
3243 :
3244 275 : release_vec_vec (paths);
3245 275 : free_graph (cfg);
3246 : }
3247 :
3248 : /* Mark all the blocks only reachable via an incoming catch. */
3249 :
3250 : static void
3251 112 : find_exception_blocks (function_info *fn)
3252 : {
3253 112 : unsigned ix;
3254 112 : block_info **queue = XALLOCAVEC (block_info *, fn->blocks.size ());
3255 :
3256 : /* First mark all blocks as exceptional. */
3257 2046 : for (ix = fn->blocks.size (); ix--;)
3258 1934 : fn->blocks[ix].exceptional = 1;
3259 :
3260 : /* Now mark all the blocks reachable via non-fake edges */
3261 112 : queue[0] = &fn->blocks[0];
3262 112 : queue[0]->exceptional = 0;
3263 1284 : for (ix = 1; ix;)
3264 : {
3265 1172 : block_info *block = queue[--ix];
3266 1172 : const arc_info *arc;
3267 :
3268 3159 : for (arc = block->succ; arc; arc = arc->succ_next)
3269 1987 : if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
3270 : {
3271 1060 : arc->dst->exceptional = 0;
3272 1060 : queue[ix++] = arc->dst;
3273 : }
3274 : }
3275 112 : }
3276 :
3277 :
3278 : /* Increment totals in COVERAGE according to arc ARC. */
3279 :
3280 : static void
3281 1313 : add_branch_counts (coverage_info *coverage, const arc_info *arc)
3282 : {
3283 1313 : if (arc->is_call_non_return)
3284 : {
3285 381 : coverage->calls++;
3286 381 : if (arc->suppressed)
3287 0 : coverage->calls_suppressed++;
3288 381 : else if (arc->src->count)
3289 348 : coverage->calls_executed++;
3290 : }
3291 932 : else if (!arc->is_unconditional)
3292 : {
3293 376 : coverage->branches++;
3294 376 : if (arc->src->count && !arc->suppressed)
3295 374 : coverage->branches_executed++;
3296 376 : if (arc->count && !arc->suppressed)
3297 304 : coverage->branches_taken++;
3298 376 : if (arc->suppressed)
3299 0 : coverage->branches_suppressed++;
3300 : }
3301 1313 : }
3302 :
3303 : /* Increment totals in COVERAGE according to block BLOCK. */
3304 :
3305 : static void
3306 8128 : add_condition_counts (coverage_info *coverage, const block_info *block)
3307 : {
3308 8128 : coverage->conditions += 2 * block->conditions.n_terms;
3309 8128 : if (block->suppressed)
3310 824 : coverage->conditions_suppressed += 2 * block->conditions.n_terms;
3311 : else
3312 7304 : coverage->conditions_covered += block->conditions.popcount ();
3313 8128 : }
3314 :
3315 : /* Increment path totals, number of paths and number of covered paths,
3316 : in COVERAGE according to FN. */
3317 :
3318 : static void
3319 1363 : add_path_counts (coverage_info &coverage, const function_info &fn)
3320 : {
3321 1363 : coverage.paths += fn.paths.path_count ();
3322 1363 : coverage.paths_covered += fn.paths.covered_paths ();
3323 1363 : coverage.paths_suppressed += fn.paths.suppressed_count ();
3324 1363 : }
3325 :
3326 : /* Format COUNT, if flag_human_readable_numbers is set, return it human
3327 : readable format. */
3328 :
3329 : static char const *
3330 4788 : format_count (gcov_type count)
3331 : {
3332 4788 : static char buffer[64];
3333 4788 : const char *units = " kMGTPEZY";
3334 :
3335 4788 : if (count < 1000 || !flag_human_readable_numbers)
3336 : {
3337 4746 : sprintf (buffer, "%" PRId64, count);
3338 4746 : return buffer;
3339 : }
3340 :
3341 : unsigned i;
3342 : gcov_type divisor = 1;
3343 96 : for (i = 0; units[i+1]; i++, divisor *= 1000)
3344 : {
3345 96 : if (count + divisor / 2 < 1000 * divisor)
3346 : break;
3347 : }
3348 42 : float r = 1.0f * count / divisor;
3349 42 : sprintf (buffer, "%.1f%c", r, units[i]);
3350 42 : return buffer;
3351 : }
3352 :
3353 : /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
3354 : count. If DECIMAL_PLACES >= 0, format TOP/BOTTOM * 100 to DECIMAL_PLACES.
3355 : If DECIMAL_PLACES is zero, no decimal point is printed. Only print 100% when
3356 : TOP==BOTTOM and only print 0% when TOP=0. If DECIMAL_PLACES < 0, then simply
3357 : format TOP. Return pointer to a static string. */
3358 :
3359 : static char const *
3360 6315 : format_gcov (gcov_type top, gcov_type bottom, int decimal_places)
3361 : {
3362 6315 : static char buffer[20];
3363 :
3364 1527 : if (decimal_places >= 0)
3365 : {
3366 1527 : float ratio = bottom ? 100.0f * top / bottom : 0;
3367 :
3368 : /* Round up to 1% if there's a small non-zero value. */
3369 1518 : if (ratio > 0.0f && ratio < 0.5f && decimal_places == 0)
3370 1527 : ratio = 1.0f;
3371 1527 : sprintf (buffer, "%.*f%%", decimal_places, ratio);
3372 : }
3373 : else
3374 0 : return format_count (top);
3375 :
3376 1527 : return buffer;
3377 : }
3378 :
3379 : /* Summary of execution */
3380 :
3381 : static void
3382 398 : executed_summary (unsigned lines, unsigned executed, unsigned suppressed)
3383 : {
3384 398 : if (lines && suppressed == 0)
3385 365 : fnotice (stdout, "Lines executed:%s of %d\n",
3386 : format_gcov (executed, lines, 2), lines);
3387 33 : else if (lines && suppressed > 0)
3388 30 : fnotice (stdout, "Lines executed:%s of %d (%d of %d suppressed)\n",
3389 : format_gcov (executed, lines - suppressed, 2), lines - suppressed,
3390 : suppressed, lines);
3391 : else
3392 3 : fnotice (stdout, "No executable lines\n");
3393 398 : }
3394 :
3395 : /* Output summary info for a function. */
3396 :
3397 : static void
3398 0 : function_summary (const coverage_info *coverage)
3399 : {
3400 0 : if (coverage->function_suppressed)
3401 : {
3402 0 : fnotice (stdout, "Function '%s' suppressed\n", coverage->name);
3403 0 : return;
3404 : }
3405 0 : fnotice (stdout, "%s '%s'\n", "Function", coverage->name);
3406 0 : executed_summary (coverage->lines, coverage->lines_executed,
3407 0 : coverage->lines_suppressed);
3408 :
3409 0 : if (coverage->branches)
3410 : {
3411 0 : const int branches = coverage->branches - coverage->branches_suppressed;
3412 0 : if (coverage->branches_suppressed == 0)
3413 0 : fnotice (stdout, "Branches executed:%s of %d\n",
3414 0 : format_gcov (coverage->branches_executed, coverage->branches,
3415 : 2),
3416 : coverage->branches);
3417 : else
3418 0 : fnotice (stdout, "Branches executed:%s of %d (%d of %d suppressed)\n",
3419 0 : format_gcov (coverage->branches_executed, branches, 2),
3420 : branches, coverage->branches_suppressed, coverage->branches);
3421 0 : fnotice (stdout, "Taken at least once:%s of %d\n",
3422 0 : format_gcov (coverage->branches_taken, branches, 2), branches);
3423 : }
3424 : else
3425 0 : fnotice (stdout, "No branches\n");
3426 :
3427 0 : if (coverage->calls && coverage->calls == 0)
3428 : fnotice (stdout, "Calls executed:%s of %d\n",
3429 : format_gcov (coverage->calls_executed, coverage->calls, 2),
3430 : coverage->calls);
3431 0 : else if (coverage->calls && coverage->calls_suppressed > 0)
3432 0 : fnotice (stdout, "Calls executed:%s of %d (%d of %d suppressed)\n",
3433 0 : format_gcov (coverage->calls_executed, coverage->calls
3434 : - coverage->calls_suppressed, 2),
3435 : coverage->calls - coverage->calls_suppressed,
3436 : coverage->calls_suppressed, coverage->calls);
3437 : else
3438 0 : fnotice (stdout, "No calls\n");
3439 :
3440 0 : if (flag_conditions)
3441 : {
3442 0 : if (coverage->conditions && coverage->conditions_suppressed == 0)
3443 0 : fnotice (stdout, "Condition outcomes covered:%s of %d\n",
3444 0 : format_gcov (coverage->conditions_covered,
3445 : coverage->conditions, 2),
3446 : coverage->conditions);
3447 0 : if (coverage->conditions && coverage->conditions_suppressed > 0)
3448 0 : fnotice (stdout, "Condition outcomes covered:%s of %d"
3449 : " (%d of %d suppressed)\n",
3450 0 : format_gcov (coverage->conditions_covered,
3451 : coverage->conditions
3452 : - coverage->conditions_suppressed, 2),
3453 : coverage->conditions - coverage->conditions_suppressed,
3454 : coverage->conditions_suppressed, coverage->conditions);
3455 : else
3456 0 : fnotice (stdout, "No conditions\n");
3457 : }
3458 :
3459 0 : if (flag_prime_paths)
3460 : {
3461 0 : if (coverage->paths && coverage->paths_suppressed == 0)
3462 0 : fnotice (stdout, "Prime paths covered:%s of %d\n",
3463 0 : format_gcov (coverage->paths_covered, coverage->paths, 2),
3464 : coverage->paths);
3465 0 : else if (coverage->paths && coverage->paths_suppressed > 0)
3466 0 : fnotice (stdout, "Prime paths covered:%s of %d (%u of %u suppressed)\n",
3467 0 : format_gcov (coverage->paths_covered, coverage->paths
3468 : - coverage->paths_suppressed, 2),
3469 : coverage->paths - coverage->paths_suppressed,
3470 : coverage->paths_suppressed, coverage->paths);
3471 : else
3472 0 : fnotice (stdout, "No path information\n");
3473 : }
3474 : }
3475 :
3476 : /* Output summary info for a file. */
3477 :
3478 : static void
3479 238 : file_summary (const coverage_info *coverage)
3480 : {
3481 238 : fnotice (stdout, "%s '%s'\n", "File", coverage->name);
3482 238 : executed_summary (coverage->lines, coverage->lines_executed,
3483 238 : coverage->lines_suppressed);
3484 :
3485 238 : if (flag_branches)
3486 : {
3487 23 : if (coverage->branches)
3488 : {
3489 15 : fnotice (stdout, "Branches executed:%s of %d\n",
3490 15 : format_gcov (coverage->branches_executed,
3491 : coverage->branches, 2),
3492 : coverage->branches);
3493 15 : fnotice (stdout, "Taken at least once:%s of %d\n",
3494 15 : format_gcov (coverage->branches_taken,
3495 : coverage->branches, 2),
3496 15 : coverage->branches);
3497 : }
3498 : else
3499 8 : fnotice (stdout, "No branches\n");
3500 23 : if (coverage->calls)
3501 23 : fnotice (stdout, "Calls executed:%s of %d\n",
3502 23 : format_gcov (coverage->calls_executed, coverage->calls, 2),
3503 : coverage->calls);
3504 : else
3505 0 : fnotice (stdout, "No calls\n");
3506 :
3507 : }
3508 :
3509 238 : if (flag_conditions)
3510 : {
3511 6 : if (coverage->conditions)
3512 6 : fnotice (stdout, "Condition outcomes covered:%s of %d\n",
3513 6 : format_gcov (coverage->conditions_covered,
3514 : coverage->conditions, 2),
3515 : coverage->conditions);
3516 : else
3517 0 : fnotice (stdout, "No conditions\n");
3518 : }
3519 :
3520 238 : if (flag_prime_paths)
3521 : {
3522 59 : if (coverage->paths)
3523 45 : fnotice (stdout, "Prime paths covered:%s of %d\n",
3524 45 : format_gcov (coverage->paths_covered, coverage->paths, 2),
3525 : coverage->paths);
3526 : else
3527 14 : fnotice (stdout, "No path information\n");
3528 : }
3529 238 : }
3530 :
3531 : /* Canonicalize the filename NAME by canonicalizing directory
3532 : separators, eliding . components and resolving .. components
3533 : appropriately. Always returns a unique string. */
3534 :
3535 : static char *
3536 396 : canonicalize_name (const char *name)
3537 : {
3538 : /* The canonical name cannot be longer than the incoming name. */
3539 396 : char *result = XNEWVEC (char, strlen (name) + 1);
3540 396 : const char *base = name, *probe;
3541 396 : char *ptr = result;
3542 396 : char *dd_base;
3543 396 : int slash = 0;
3544 :
3545 : #if HAVE_DOS_BASED_FILE_SYSTEM
3546 : if (base[0] && base[1] == ':')
3547 : {
3548 : result[0] = base[0];
3549 : result[1] = ':';
3550 : base += 2;
3551 : ptr += 2;
3552 : }
3553 : #endif
3554 3491 : for (dd_base = ptr; *base; base = probe)
3555 : {
3556 : size_t len;
3557 :
3558 21662 : for (probe = base; *probe; probe++)
3559 21266 : if (IS_DIR_SEPARATOR (*probe))
3560 : break;
3561 :
3562 2699 : len = probe - base;
3563 2699 : if (len == 1 && base[0] == '.')
3564 : /* Elide a '.' directory */
3565 : ;
3566 2698 : else if (len == 2 && base[0] == '.' && base[1] == '.')
3567 : {
3568 : /* '..', we can only elide it and the previous directory, if
3569 : we're not a symlink. */
3570 0 : struct stat ATTRIBUTE_UNUSED buf;
3571 :
3572 0 : *ptr = 0;
3573 0 : if (dd_base == ptr
3574 : #if defined (S_ISLNK)
3575 : /* S_ISLNK is not POSIX.1-1996. */
3576 0 : || stat (result, &buf) || S_ISLNK (buf.st_mode)
3577 : #endif
3578 : )
3579 : {
3580 : /* Cannot elide, or unreadable or a symlink. */
3581 0 : dd_base = ptr + 2 + slash;
3582 0 : goto regular;
3583 : }
3584 0 : while (ptr != dd_base && *ptr != '/')
3585 0 : ptr--;
3586 0 : slash = ptr != result;
3587 0 : }
3588 : else
3589 : {
3590 2698 : regular:
3591 : /* Regular pathname component. */
3592 2698 : if (slash)
3593 2302 : *ptr++ = '/';
3594 2698 : memcpy (ptr, base, len);
3595 2698 : ptr += len;
3596 2698 : slash = 1;
3597 : }
3598 :
3599 5002 : for (; IS_DIR_SEPARATOR (*probe); probe++)
3600 2303 : continue;
3601 2303 : }
3602 396 : *ptr = 0;
3603 :
3604 396 : return result;
3605 : }
3606 :
3607 : /* Generate an output file name. INPUT_NAME is the canonicalized main
3608 : input file and SRC_NAME is the canonicalized file name.
3609 : LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
3610 : long_output_names we prepend the processed name of the input file
3611 : to each output name (except when the current source file is the
3612 : input file, so you don't get a double concatenation). The two
3613 : components are separated by '##'. With preserve_paths we create a
3614 : filename from all path components of the source file, replacing '/'
3615 : with '#', and .. with '^', without it we simply take the basename
3616 : component. (Remember, the canonicalized name will already have
3617 : elided '.' components and converted \\ separators.) */
3618 :
3619 : static string
3620 236 : make_gcov_file_name (const char *input_name, const char *src_name)
3621 : {
3622 236 : string str;
3623 :
3624 : /* When hashing filenames, we shorten them by only using the filename
3625 : component and appending a hash of the full (mangled) pathname. */
3626 236 : if (flag_hash_filenames)
3627 0 : str = (string (mangle_name (src_name)) + "##"
3628 0 : + get_md5sum (src_name) + ".gcov");
3629 : else
3630 : {
3631 236 : if (flag_long_names && input_name && strcmp (src_name, input_name) != 0)
3632 : {
3633 0 : str += mangle_name (input_name);
3634 0 : str += "##";
3635 : }
3636 :
3637 236 : str += mangle_name (src_name);
3638 236 : str += ".gcov";
3639 : }
3640 :
3641 236 : return str;
3642 : }
3643 :
3644 : /* Mangle BASE name, copy it at the beginning of PTR buffer and
3645 : return address of the \0 character of the buffer. */
3646 :
3647 : static char *
3648 236 : mangle_name (char const *base)
3649 : {
3650 : /* Generate the source filename part. */
3651 236 : if (!flag_preserve_paths)
3652 236 : return xstrdup (lbasename (base));
3653 : else
3654 0 : return mangle_path (base);
3655 : }
3656 :
3657 : /* Scan through the bb_data for each line in the block, increment
3658 : the line number execution count indicated by the execution count of
3659 : the appropriate basic block. */
3660 :
3661 : static void
3662 1363 : add_line_counts (coverage_info *coverage, function_info *fn)
3663 : {
3664 1363 : bool has_any_line = false;
3665 : /* Scan each basic block. */
3666 13774 : for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
3667 : {
3668 12411 : line_info *line = NULL;
3669 12411 : block_info *block = &fn->blocks[ix];
3670 12411 : if (block->count && ix && ix + 1 != fn->blocks.size ())
3671 5506 : fn->blocks_executed++;
3672 21627 : for (unsigned i = 0; i < block->locations.size (); i++)
3673 : {
3674 9216 : unsigned src_idx = block->locations[i].source_file_idx;
3675 9216 : vector<unsigned> &lines = block->locations[i].lines;
3676 :
3677 9216 : block->cycle.arc = NULL;
3678 9216 : block->cycle.ident = ~0U;
3679 :
3680 21002 : for (unsigned j = 0; j < lines.size (); j++)
3681 : {
3682 11786 : unsigned ln = lines[j];
3683 :
3684 : /* Line belongs to a function that is in a group. */
3685 11786 : if (fn->group_line_p (ln, src_idx))
3686 : {
3687 782 : gcc_assert (lines[j] - fn->start_line < fn->lines.size ());
3688 782 : line = &(fn->lines[lines[j] - fn->start_line]);
3689 782 : if (coverage)
3690 : {
3691 0 : if (!line->exists)
3692 0 : coverage->lines++;
3693 0 : if (line->suppressed)
3694 0 : coverage->lines_suppressed++;
3695 0 : if (!line->count && block->count && !line->suppressed)
3696 0 : coverage->lines_executed++;
3697 : }
3698 782 : line->exists = 1;
3699 782 : if (!block->exceptional)
3700 : {
3701 765 : line->unexceptional = 1;
3702 765 : if (block->count == 0)
3703 21 : line->has_unexecuted_block = 1;
3704 : }
3705 782 : line->count += block->count;
3706 : }
3707 : else
3708 : {
3709 11004 : gcc_assert (ln < sources[src_idx].lines.size ());
3710 11004 : line = &(sources[src_idx].lines[ln]);
3711 11004 : if (coverage)
3712 : {
3713 0 : if (!line->exists)
3714 0 : coverage->lines++;
3715 0 : if (!line->exists && line->suppressed)
3716 0 : coverage->lines_suppressed++;
3717 0 : if (!line->count && block->count && !line->suppressed)
3718 0 : coverage->lines_executed++;
3719 : }
3720 11004 : line->exists = 1;
3721 11004 : if (!block->exceptional)
3722 : {
3723 10375 : line->unexceptional = 1;
3724 10375 : if (block->count == 0)
3725 4214 : line->has_unexecuted_block = 1;
3726 : }
3727 11004 : line->count += block->count;
3728 : }
3729 : }
3730 :
3731 9216 : has_any_line = true;
3732 :
3733 9216 : if (!ix || ix + 1 == fn->blocks.size ())
3734 : /* Entry or exit block. */;
3735 8128 : else if (line != NULL)
3736 : {
3737 8128 : line->blocks.push_back (block);
3738 :
3739 8128 : if (flag_branches)
3740 : {
3741 748 : arc_info *arc;
3742 :
3743 2061 : for (arc = block->succ; arc; arc = arc->succ_next)
3744 1313 : line->branches.push_back (arc);
3745 : }
3746 : }
3747 : }
3748 : }
3749 :
3750 1363 : if (!has_any_line)
3751 0 : fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name,
3752 : fn->get_name ());
3753 1363 : }
3754 :
3755 : /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE
3756 : is set to true, update source file summary. */
3757 :
3758 53999 : static void accumulate_line_info (line_info *line, source_info *src,
3759 : bool add_coverage)
3760 : {
3761 53999 : if (add_coverage)
3762 55312 : for (vector<arc_info *>::iterator it = line->branches.begin ();
3763 55312 : it != line->branches.end (); it++)
3764 1313 : add_branch_counts (&src->coverage, *it);
3765 :
3766 53999 : if (add_coverage)
3767 62127 : for (vector<block_info *>::iterator it = line->blocks.begin ();
3768 62127 : it != line->blocks.end (); it++)
3769 8128 : add_condition_counts (&src->coverage, *it);
3770 :
3771 :
3772 53999 : if (!line->blocks.empty ())
3773 : {
3774 : /* The user expects the line count to be the number of times
3775 : a line has been executed. Simply summing the block count
3776 : will give an artificially high number. The Right Thing
3777 : is to sum the entry counts to the graph of blocks on this
3778 : line, then find the elementary cycles of the local graph
3779 : and add the transition counts of those cycles. */
3780 14264 : gcov_type count = 0;
3781 :
3782 : /* Cycle detection. */
3783 8128 : for (vector<block_info *>::iterator it = line->blocks.begin ();
3784 14264 : it != line->blocks.end (); it++)
3785 : {
3786 17757 : for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next)
3787 9629 : if (!line->has_block (arc->src))
3788 7715 : count += arc->count;
3789 21878 : for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next)
3790 13750 : arc->cs_count = arc->count;
3791 : }
3792 :
3793 : /* Now, add the count of loops entirely on this line. */
3794 6136 : count += get_cycles_count (*line);
3795 6136 : line->count = count;
3796 :
3797 6136 : if (line->count > src->maximum_count)
3798 245 : src->maximum_count = line->count;
3799 : }
3800 :
3801 53999 : if (line->exists && add_coverage)
3802 : {
3803 8609 : src->coverage.lines++;
3804 8609 : if (line->suppressed)
3805 957 : src->coverage.lines_suppressed++;
3806 8609 : if (line->count && !line->suppressed)
3807 4438 : src->coverage.lines_executed++;
3808 : }
3809 53999 : }
3810 :
3811 : /* Accumulate the line counts of a file. */
3812 :
3813 : static void
3814 238 : accumulate_line_counts (source_info *src)
3815 : {
3816 : /* First work on group functions. */
3817 1601 : for (vector<function_info *>::iterator it = src->functions.begin ();
3818 1601 : it != src->functions.end (); it++)
3819 : {
3820 1363 : function_info *fn = *it;
3821 :
3822 1363 : if (fn->src != src->index || !fn->is_group)
3823 1176 : continue;
3824 :
3825 1832 : for (vector<line_info>::iterator it2 = fn->lines.begin ();
3826 1832 : it2 != fn->lines.end (); it2++)
3827 : {
3828 1645 : line_info *line = &(*it2);
3829 1645 : accumulate_line_info (line, src, true);
3830 : }
3831 : }
3832 :
3833 : /* Work on global lines that line in source file SRC. */
3834 52592 : for (vector<line_info>::iterator it = src->lines.begin ();
3835 52592 : it != src->lines.end (); it++)
3836 52354 : accumulate_line_info (&(*it), src, true);
3837 :
3838 : /* If not using intermediate mode, sum lines of group functions and
3839 : add them to lines that live in a source file. */
3840 238 : if (!flag_json_format)
3841 1590 : for (vector<function_info *>::iterator it = src->functions.begin ();
3842 1590 : it != src->functions.end (); it++)
3843 : {
3844 1354 : function_info *fn = *it;
3845 :
3846 1354 : if (fn->src != src->index || !fn->is_group)
3847 1171 : continue;
3848 :
3849 1824 : for (unsigned i = 0; i < fn->lines.size (); i++)
3850 : {
3851 1641 : line_info *fn_line = &fn->lines[i];
3852 1641 : if (fn_line->exists)
3853 : {
3854 547 : unsigned ln = fn->start_line + i;
3855 547 : line_info *src_line = &src->lines[ln];
3856 :
3857 547 : if (!src_line->exists)
3858 238 : src->coverage.lines++;
3859 547 : if (!src_line->exists && src_line->suppressed)
3860 57 : src->coverage.lines_suppressed++;
3861 547 : if (!src_line->count && fn_line->count && !src_line->suppressed)
3862 175 : src->coverage.lines_executed++;
3863 :
3864 547 : src_line->count += fn_line->count;
3865 547 : src_line->exists = 1;
3866 :
3867 547 : if (fn_line->has_unexecuted_block)
3868 19 : src_line->has_unexecuted_block = 1;
3869 :
3870 547 : if (fn_line->unexceptional)
3871 547 : src_line->unexceptional = 1;
3872 : }
3873 : }
3874 : }
3875 238 : }
3876 :
3877 : /* Output information about the conditions in block BINFO. The output includes
3878 : * a summary (n/m outcomes covered) and a list of the missing (uncovered)
3879 : * outcomes. */
3880 :
3881 : static void
3882 1249 : output_conditions (FILE *gcov_file, const block_info *binfo)
3883 : {
3884 1249 : const condition_info& info = binfo->conditions;
3885 1249 : if (info.n_terms == 0)
3886 : return;
3887 242 : if (binfo->suppressed)
3888 : return;
3889 :
3890 242 : const int expected = 2 * info.n_terms;
3891 242 : const int got = info.popcount ();
3892 :
3893 242 : fnotice (gcov_file, "condition outcomes covered %d/%d\n", got, expected);
3894 242 : if (expected == got)
3895 : return;
3896 :
3897 579 : for (unsigned i = 0; i < info.n_terms; i++)
3898 : {
3899 414 : gcov_type_unsigned index = 1;
3900 414 : index <<= i;
3901 414 : if ((index & info.truev & info.falsev))
3902 42 : continue;
3903 :
3904 372 : const char *t = (index & info.truev) ? "" : "true";
3905 372 : const char *f = (index & info.falsev) ? "" : " false";
3906 372 : fnotice (gcov_file, "condition %2u not covered (%s%s)\n", i, t, f + !t[0]);
3907 : }
3908 : }
3909 :
3910 : /* Output information about ARC number IX. Returns nonzero if
3911 : anything is output. */
3912 :
3913 : static int
3914 1281 : output_branch_count (FILE *gcov_file, int ix, const arc_info *arc)
3915 : {
3916 1281 : if (arc->suppressed)
3917 : return 0;
3918 1281 : else if (arc->is_call_non_return)
3919 : {
3920 372 : if (arc->src->count)
3921 : {
3922 340 : fnotice (gcov_file, "call %2d returned %s\n", ix,
3923 340 : format_gcov (arc->src->count - arc->count,
3924 : arc->src->count, -flag_counts));
3925 : }
3926 : else
3927 32 : fnotice (gcov_file, "call %2d never executed\n", ix);
3928 : }
3929 909 : else if (!arc->is_unconditional)
3930 : {
3931 366 : if (arc->src->count)
3932 366 : fnotice (gcov_file, "branch %2d taken %s%s", ix,
3933 366 : format_gcov (arc->count, arc->src->count, -flag_counts),
3934 366 : arc->fall_through ? " (fallthrough)"
3935 191 : : arc->is_throw ? " (throw)" : "");
3936 : else
3937 0 : fnotice (gcov_file, "branch %2d never executed%s", ix,
3938 0 : (arc->fall_through ? " (fallthrough)"
3939 0 : : arc->is_throw ? " (throw)" : ""));
3940 :
3941 366 : if (flag_verbose)
3942 0 : fnotice (gcov_file, " (BB %d)", arc->dst->id);
3943 :
3944 366 : fnotice (gcov_file, "\n");
3945 : }
3946 543 : else if (flag_unconditional && !arc->dst->is_call_return)
3947 : {
3948 0 : if (arc->src->count)
3949 0 : fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
3950 0 : format_gcov (arc->count, arc->src->count, -flag_counts));
3951 : else
3952 0 : fnotice (gcov_file, "unconditional %2d never executed\n", ix);
3953 : }
3954 : else
3955 : return 0;
3956 : return 1;
3957 : }
3958 :
3959 : static void
3960 : print_source_line (FILE *f, const vector<const char *> &source_lines,
3961 : unsigned line);
3962 :
3963 :
3964 : /* Print a dense coverage report for PATH of FN to GCOV_FILE. PATH should be
3965 : number PATHNO in the sorted set of paths. This function prints a dense form
3966 : where only the line numbers, and optionally the source file the line comes
3967 : from, in the order they need to be executed to achieve coverage. This
3968 : produces very long lines for large functions, but is a useful and greppable
3969 : output.
3970 :
3971 : Returns 1 if the path was printed, 0 otherwise. */
3972 : static unsigned
3973 1462 : print_prime_path_lines (FILE *gcov_file, const function_info &fn,
3974 : const vector<unsigned> &path, unsigned pathno)
3975 : {
3976 1462 : const bool is_covered = fn.paths.covered_p (pathno);
3977 1462 : if (is_covered && !flag_prime_paths_lines_covered)
3978 : return 0;
3979 1309 : if (!is_covered && !flag_prime_paths_lines_uncovered)
3980 : return 0;
3981 :
3982 1308 : if (is_covered)
3983 113 : fprintf (gcov_file, "path %u covered: lines", pathno);
3984 : else
3985 1308 : fprintf (gcov_file, "path %u not covered: lines", pathno);
3986 :
3987 8146 : for (size_t k = 0; k != path.size (); ++k)
3988 : {
3989 6725 : const block_info &block = fn.blocks[path[k]];
3990 6725 : const char *edge_kind = "";
3991 6725 : if (k + 1 != path.size ())
3992 : {
3993 5304 : const arc_info *arc = find_arc (block, path[k+1]);
3994 5304 : if (!arc)
3995 : edge_kind = "(suppress)";
3996 5276 : else if (arc->true_value)
3997 : edge_kind = "(true)";
3998 4229 : else if (arc->false_value)
3999 : edge_kind = "(false)";
4000 3380 : else if (arc->is_throw)
4001 6725 : edge_kind = "(throw)";
4002 : }
4003 :
4004 13336 : for (const block_location_info &loc : block.locations)
4005 : {
4006 : /* loc.lines could be empty when a statement is not anchored to a
4007 : source file -- see g++.dg/gcov/gcov-23.C. Since there is no
4008 : actual source line to list anyway we can skip this location. */
4009 6611 : if (loc.lines.empty ())
4010 3 : continue;
4011 6608 : if (loc.source_file_idx == fn.src)
4012 6569 : fprintf (gcov_file, " %u%s", loc.lines.back (), edge_kind);
4013 : else
4014 39 : fprintf (gcov_file, " %s:%u%s", sources[loc.source_file_idx].name,
4015 39 : loc.lines.back (), edge_kind);
4016 : }
4017 : }
4018 :
4019 1421 : fprintf (gcov_file, "\n");
4020 1421 : return 1;
4021 : }
4022 :
4023 : static unsigned
4024 3328 : print_inlined_separator (FILE *gcov_file, unsigned current_index, const
4025 : block_location_info &loc, const function_info &fn)
4026 : {
4027 3328 : if (loc.source_file_idx != current_index && loc.source_file_idx == fn.src)
4028 14 : fprintf (gcov_file, "------------------\n");
4029 3328 : if (loc.source_file_idx != current_index && loc.source_file_idx != fn.src)
4030 28 : fprintf (gcov_file, "== inlined from %s ==\n",
4031 28 : sources[loc.source_file_idx].name);
4032 3328 : return loc.source_file_idx;
4033 : }
4034 :
4035 : /* Print a coverage report for PATH of FN to GCOV_FILE. PATH should be number
4036 : PATHNO in the sorted set of paths. This function prints the lines that need
4037 : to be executed (and in what order) to cover it.
4038 :
4039 : Returns 1 if the path was printed, 0 otherwise. */
4040 : static unsigned
4041 445 : print_prime_path_source (FILE *gcov_file, const function_info &fn,
4042 : const vector<unsigned> &path, unsigned pathno)
4043 : {
4044 445 : const bool is_covered = fn.paths.covered_p (pathno);
4045 445 : if (is_covered && !flag_prime_paths_source_covered)
4046 : return 0;
4047 366 : if (!is_covered && !flag_prime_paths_source_uncovered)
4048 : return 0;
4049 :
4050 366 : if (is_covered)
4051 79 : fprintf (gcov_file, "path %u covered:\n", pathno);
4052 : else
4053 366 : fprintf (gcov_file, "path %u not covered:\n", pathno);
4054 445 : unsigned current = fn.src;
4055 3865 : for (size_t k = 0; k != path.size (); ++k)
4056 : {
4057 3420 : const unsigned bb = path[k];
4058 3420 : const block_info &block = fn.blocks[bb];
4059 3420 : gcc_checking_assert (block.id == bb);
4060 :
4061 3420 : const char *edge_kind = "";
4062 3420 : if (k + 1 != path.size ())
4063 : {
4064 2975 : const arc_info *arc = find_arc (block, path[k+1]);
4065 2975 : if (!arc)
4066 : edge_kind = "(suppress)";
4067 2975 : else if (arc->true_value)
4068 : edge_kind = "(true)";
4069 2221 : else if (arc->false_value)
4070 : edge_kind = "(false)";
4071 1656 : else if (arc->is_throw)
4072 3420 : edge_kind = "(throw)";
4073 : }
4074 :
4075 6751 : for (const block_location_info &loc : block.locations)
4076 : {
4077 : /* loc.lines could be empty when a statement is not anchored to a
4078 : source file -- see g++.dg/gcov/gcov-24.C. Since there is no
4079 : actual source line to list anyway we can skip this location. */
4080 3331 : if (loc.lines.empty ())
4081 3 : continue;
4082 3328 : const source_info &src = sources[loc.source_file_idx];
4083 3328 : const vector<const char *> &lines = slurp (src, gcov_file, "");
4084 3328 : current = print_inlined_separator (gcov_file, current, loc, fn);
4085 7511 : for (unsigned i = 0; i != loc.lines.size () - 1; ++i)
4086 : {
4087 855 : const unsigned line = loc.lines[i];
4088 855 : fprintf (gcov_file, "BB %2d: %-10s %3d", bb, "", line);
4089 855 : print_source_line (gcov_file, lines, line);
4090 : }
4091 :
4092 3328 : const unsigned line = loc.lines.back ();
4093 3328 : fprintf (gcov_file, "BB %2d: %-10s %3d", bb, edge_kind, line);
4094 3328 : print_source_line (gcov_file, lines, line);
4095 : }
4096 : }
4097 :
4098 445 : fputc ('\n', gcov_file);
4099 445 : return 1;
4100 : }
4101 :
4102 : /* Print path coverage counts for FN to GCOV_FILE. LINES is the vector of
4103 : source lines for FN. Note that unlike statements, branch counts, and
4104 : conditions, this is not anchored to source lines but the function root. */
4105 : static int
4106 1333 : output_path_coverage (FILE *gcov_file, const function_info *fn)
4107 : {
4108 1333 : if (!flag_prime_paths)
4109 : return 0;
4110 :
4111 278 : const path_info& paths = fn->paths;
4112 556 : if (fn->paths.get_paths ().empty ())
4113 3 : fnotice (gcov_file, "path coverage omitted\n");
4114 275 : else if (paths.suppressed_p ())
4115 14 : fnotice (gcov_file, "Prime paths covered %u of " HOST_SIZE_T_PRINT_UNSIGNED
4116 : " (" HOST_SIZE_T_PRINT_UNSIGNED " of " HOST_SIZE_T_PRINT_UNSIGNED
4117 : " suppressed)\n", fn->paths.covered_paths (),
4118 7 : (fmt_size_t)fn->paths.path_count (),
4119 7 : (fmt_size_t)fn->paths.suppressed_count (),
4120 7 : (fmt_size_t)fn->paths.paths.size ());
4121 : else
4122 536 : fnotice (gcov_file, "paths covered %u of " HOST_SIZE_T_PRINT_UNSIGNED "\n",
4123 268 : fn->paths.covered_paths (), (fmt_size_t)fn->paths.paths.size ());
4124 :
4125 278 : if (flag_prime_paths_lines_uncovered || flag_prime_paths_lines_covered)
4126 : {
4127 202 : unsigned pathno = 0;
4128 1866 : for (const vector<unsigned> &path : fn->paths.get_paths ())
4129 1462 : print_prime_path_lines (gcov_file, *fn, path, pathno++);
4130 : }
4131 :
4132 278 : if (flag_prime_paths_source_uncovered || flag_prime_paths_source_covered)
4133 : {
4134 120 : unsigned pathno = 0;
4135 685 : for (const vector<unsigned> &path : fn->paths.get_paths ())
4136 445 : print_prime_path_source (gcov_file, *fn, path, pathno++);
4137 : }
4138 : return 1;
4139 : }
4140 :
4141 : static const char *
4142 102526 : read_line (FILE *file)
4143 : {
4144 102526 : static char *string;
4145 102526 : static size_t string_len;
4146 102526 : size_t pos = 0;
4147 :
4148 102526 : if (!string_len)
4149 : {
4150 152 : string_len = 200;
4151 152 : string = XNEWVEC (char, string_len);
4152 : }
4153 :
4154 102527 : while (fgets (string + pos, string_len - pos, file))
4155 : {
4156 102294 : size_t len = strlen (string + pos);
4157 :
4158 102294 : if (len && string[pos + len - 1] == '\n')
4159 : {
4160 102293 : string[pos + len - 1] = 0;
4161 102293 : return string;
4162 : }
4163 1 : pos += len;
4164 : /* If the file contains NUL characters or an incomplete
4165 : last line, which can happen more than once in one run,
4166 : we have to avoid doubling the STRING_LEN unnecessarily. */
4167 1 : if (pos > string_len / 2)
4168 : {
4169 1 : string_len *= 2;
4170 1 : string = XRESIZEVEC (char, string, string_len);
4171 : }
4172 : }
4173 :
4174 233 : return pos ? string : NULL;
4175 : }
4176 :
4177 : /* Get the vector with the contents SRC, possibly from a cache. If
4178 : the reading fails, a message prefixed with LINE_START is written to
4179 : GCOV_FILE. */
4180 : static const vector<const char *>&
4181 3564 : slurp (const source_info &src, FILE *gcov_file,
4182 : const char *line_start)
4183 : {
4184 3564 : if (source_lines.size () <= src.index)
4185 232 : source_lines.resize (src.index + 1);
4186 :
4187 : /* Store vector pointers so that the returned references remain
4188 : stable and won't be broken by successive calls to slurp. */
4189 3564 : if (!source_lines[src.index])
4190 236 : source_lines[src.index] = new vector<const char *> ();
4191 :
4192 3564 : if (!source_lines[src.index]->empty ())
4193 : return *source_lines[src.index];
4194 :
4195 236 : FILE *source_file = fopen (src.name, "r");
4196 236 : if (!source_file)
4197 3 : fnotice (stderr, "Cannot open source file %s\n", src.name);
4198 233 : else if (src.file_time == 0)
4199 0 : fprintf (gcov_file, "%sSource is newer than graph\n", line_start);
4200 :
4201 236 : const char *retval;
4202 236 : vector<const char *> &lines = *source_lines[src.index];
4203 236 : if (source_file)
4204 102526 : while ((retval = read_line (source_file)))
4205 102293 : lines.push_back (xstrdup (retval));
4206 :
4207 233 : if (source_file)
4208 233 : fclose (source_file);
4209 : return lines;
4210 : }
4211 :
4212 : /* Pad string S with spaces from left to have total width equal to 9. */
4213 :
4214 : static void
4215 53606 : pad_count_string (string &s)
4216 : {
4217 53606 : if (s.size () < 9)
4218 53606 : s.insert (0, 9 - s.size (), ' ');
4219 53606 : }
4220 :
4221 : /* Print GCOV line beginning to F stream. If EXISTS is set to true, the
4222 : line exists in source file. UNEXCEPTIONAL indicated that it's not in
4223 : an exceptional statement. The output is printed for LINE_NUM of given
4224 : COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
4225 : used to indicate non-executed blocks. */
4226 :
4227 : static void
4228 53606 : output_line_beginning (FILE *f, bool exists, bool unexceptional,
4229 : bool has_unexecuted_block,
4230 : bool suppressed,
4231 : gcov_type count, unsigned line_num,
4232 : const char *exceptional_string,
4233 : const char *unexceptional_string,
4234 : unsigned int maximum_count)
4235 : {
4236 53606 : string s;
4237 53606 : if (suppressed)
4238 : {
4239 1011 : s = "#";
4240 1011 : pad_count_string (s);
4241 : }
4242 52595 : else if (exists)
4243 : {
4244 7843 : if (count > 0)
4245 : {
4246 4627 : s = format_gcov (count, 0, -1);
4247 4627 : if (has_unexecuted_block
4248 37 : && bbg_supports_has_unexecuted_blocks)
4249 : {
4250 37 : if (flag_use_colors)
4251 : {
4252 0 : pad_count_string (s);
4253 0 : s.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
4254 : COLOR_SEPARATOR COLOR_FG_WHITE));
4255 0 : s += SGR_RESET;
4256 : }
4257 : else
4258 37 : s += "*";
4259 : }
4260 4627 : pad_count_string (s);
4261 : }
4262 : else
4263 : {
4264 3216 : if (flag_use_colors)
4265 : {
4266 0 : s = "0";
4267 0 : pad_count_string (s);
4268 0 : if (unexceptional)
4269 0 : s.insert (0, SGR_SEQ (COLOR_BG_RED
4270 : COLOR_SEPARATOR COLOR_FG_WHITE));
4271 : else
4272 0 : s.insert (0, SGR_SEQ (COLOR_BG_CYAN
4273 : COLOR_SEPARATOR COLOR_FG_WHITE));
4274 0 : s += SGR_RESET;
4275 : }
4276 : else
4277 : {
4278 3216 : s = unexceptional ? unexceptional_string : exceptional_string;
4279 3216 : pad_count_string (s);
4280 : }
4281 : }
4282 : }
4283 : else
4284 : {
4285 44752 : s = "-";
4286 44752 : pad_count_string (s);
4287 : }
4288 :
4289 : /* Format line number in output. */
4290 53606 : char buffer[16];
4291 53606 : sprintf (buffer, "%5u", line_num);
4292 53606 : string linestr (buffer);
4293 :
4294 53606 : if (flag_use_hotness_colors && maximum_count)
4295 : {
4296 0 : if (count * 2 > maximum_count) /* > 50%. */
4297 0 : linestr.insert (0, SGR_SEQ (COLOR_BG_RED));
4298 0 : else if (count * 5 > maximum_count) /* > 20%. */
4299 0 : linestr.insert (0, SGR_SEQ (COLOR_BG_YELLOW));
4300 0 : else if (count * 10 > maximum_count) /* > 10%. */
4301 0 : linestr.insert (0, SGR_SEQ (COLOR_BG_GREEN));
4302 0 : linestr += SGR_RESET;
4303 : }
4304 :
4305 53606 : fprintf (f, "%s:%s", s.c_str (), linestr.c_str ());
4306 53606 : }
4307 :
4308 : static void
4309 107766 : print_source_line (FILE *f, const vector<const char *> &source_lines,
4310 : unsigned line)
4311 : {
4312 107766 : gcc_assert (line >= 1);
4313 107766 : gcc_assert (line <= source_lines.size ());
4314 :
4315 107766 : fprintf (f, ":%s\n", source_lines[line - 1]);
4316 107766 : }
4317 :
4318 : /* Output line details for LINE and print it to F file. LINE lives on
4319 : LINE_NUM. */
4320 :
4321 : static void
4322 53547 : output_line_details (FILE *f, const line_info *line, unsigned line_num)
4323 : {
4324 53547 : if (flag_all_blocks)
4325 : {
4326 273 : arc_info *arc;
4327 273 : int jx = 0;
4328 341 : for (vector<block_info *>::const_iterator it = line->blocks.begin ();
4329 341 : it != line->blocks.end (); it++)
4330 : {
4331 68 : if (!(*it)->is_call_return)
4332 : {
4333 59 : output_line_beginning (f, line->exists,
4334 59 : (*it)->exceptional, false,
4335 59 : (*it)->suppressed,
4336 59 : (*it)->count, line_num,
4337 : "%%%%%", "$$$$$", 0);
4338 59 : fprintf (f, "-block %d", (*it)->id);
4339 59 : if (flag_verbose)
4340 0 : fprintf (f, " (BB %u)", (*it)->id);
4341 59 : fprintf (f, "\n");
4342 : }
4343 68 : if (flag_branches)
4344 72 : for (arc = (*it)->succ; arc; arc = arc->succ_next)
4345 42 : jx += output_branch_count (f, jx, arc);
4346 :
4347 68 : if (flag_conditions)
4348 0 : output_conditions (f, *it);
4349 : }
4350 : }
4351 : else
4352 : {
4353 53274 : if (flag_branches)
4354 : {
4355 1899 : int ix;
4356 :
4357 1899 : ix = 0;
4358 1899 : for (vector<arc_info *>::const_iterator it = line->branches.begin ();
4359 3138 : it != line->branches.end (); it++)
4360 1239 : ix += output_branch_count (f, ix, (*it));
4361 : }
4362 :
4363 53274 : if (flag_conditions)
4364 : {
4365 3483 : for (vector<block_info *>::const_iterator it = line->blocks.begin ();
4366 3483 : it != line->blocks.end (); it++)
4367 1249 : output_conditions (f, *it);
4368 : }
4369 : }
4370 53547 : }
4371 :
4372 : /* Output detail statistics about function FN to file F. */
4373 :
4374 : static void
4375 1333 : output_function_details (FILE *f, function_info *fn)
4376 : {
4377 1333 : if (!flag_branches)
4378 : return;
4379 :
4380 161 : arc_info *arc = fn->blocks[EXIT_BLOCK].pred;
4381 161 : gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
4382 161 : gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
4383 :
4384 695 : for (; arc; arc = arc->pred_next)
4385 534 : if (arc->fake)
4386 374 : return_count -= arc->count;
4387 :
4388 161 : fprintf (f, "function %s", fn->get_name ());
4389 161 : fprintf (f, " called %s",
4390 : format_gcov (called_count, 0, -1));
4391 161 : fprintf (f, " returned %s",
4392 : format_gcov (return_count, called_count, 0));
4393 322 : fprintf (f, " blocks executed %s",
4394 161 : format_gcov (fn->blocks_executed, fn->get_block_count (), 0));
4395 161 : fprintf (f, "\n");
4396 : }
4397 :
4398 : /* Read in the source file one line at a time, and output that line to
4399 : the gcov file preceded by its execution count and other
4400 : information. */
4401 :
4402 : static void
4403 236 : output_lines (FILE *gcov_file, const source_info *src)
4404 : {
4405 : #define DEFAULT_LINE_START " -: 0:"
4406 : #define FN_SEPARATOR "------------------\n"
4407 :
4408 : /* Print colorization legend. */
4409 236 : if (flag_use_colors)
4410 0 : fprintf (gcov_file, "%s",
4411 : DEFAULT_LINE_START "Colorization: profile count: " \
4412 : SGR_SEQ (COLOR_BG_CYAN) "zero coverage (exceptional)" SGR_RESET \
4413 : " " \
4414 : SGR_SEQ (COLOR_BG_RED) "zero coverage (unexceptional)" SGR_RESET \
4415 : " " \
4416 : SGR_SEQ (COLOR_BG_MAGENTA) "unexecuted block" SGR_RESET "\n");
4417 :
4418 236 : if (flag_use_hotness_colors)
4419 0 : fprintf (gcov_file, "%s",
4420 : DEFAULT_LINE_START "Colorization: line numbers: hotness: " \
4421 : SGR_SEQ (COLOR_BG_RED) "> 50%" SGR_RESET " " \
4422 : SGR_SEQ (COLOR_BG_YELLOW) "> 20%" SGR_RESET " " \
4423 : SGR_SEQ (COLOR_BG_GREEN) "> 10%" SGR_RESET "\n");
4424 :
4425 236 : fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
4426 236 : if (!multiple_files)
4427 : {
4428 236 : fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
4429 236 : fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
4430 236 : no_data_file ? "-" : da_file_name);
4431 236 : fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
4432 : }
4433 :
4434 236 : const vector<const char *> &source_lines = slurp (*src, gcov_file,
4435 : DEFAULT_LINE_START);
4436 236 : unsigned line_start_group = 0;
4437 236 : vector<function_info *> *fns;
4438 459 : unsigned filtered_line_end = !filters.empty () ? 0 : source_lines.size ();
4439 :
4440 102309 : for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
4441 : {
4442 102086 : if (line_num >= src->lines.size ())
4443 : {
4444 : /* If the src->lines is truncated because the rest of the functions
4445 : are filtered out we must stop here, and not fall back to printing
4446 : the rest of the file. */
4447 50049 : if (!filters.empty ())
4448 : break;
4449 50036 : fprintf (gcov_file, "%9s:%5u", "-", line_num);
4450 50036 : print_source_line (gcov_file, source_lines, line_num);
4451 50036 : continue;
4452 : }
4453 :
4454 52037 : const line_info *line = &src->lines[line_num];
4455 :
4456 52037 : if (line_start_group == 0)
4457 : {
4458 51509 : fns = src->get_functions_at_location (line_num);
4459 52745 : if (fns != NULL && fns->size () > 1)
4460 : {
4461 : /* It's possible to have functions that partially overlap,
4462 : thus take the maximum end_line of functions starting
4463 : at LINE_NUM. */
4464 239 : for (unsigned i = 0; i < fns->size (); i++)
4465 168 : if ((*fns)[i]->end_line > line_start_group)
4466 : line_start_group = (*fns)[i]->end_line;
4467 :
4468 : /* When filtering, src->lines will be cut short for the last
4469 : selected function. To make sure the "overlapping function"
4470 : section is printed too, adjust the end so that it is within
4471 : src->lines. */
4472 71 : if (line_start_group >= src->lines.size ())
4473 0 : line_start_group = src->lines.size () - 1;
4474 :
4475 71 : if (!filters.empty ())
4476 6 : filtered_line_end = line_start_group;
4477 : }
4478 52603 : else if (fns != NULL && fns->size () == 1)
4479 : {
4480 1165 : function_info *fn = (*fns)[0];
4481 1165 : output_function_details (gcov_file, fn);
4482 1165 : output_path_coverage (gcov_file, fn);
4483 :
4484 : /* If functions are filtered, only the matching functions will be in
4485 : fns and there is no need for extra checking. */
4486 1165 : if (!filters.empty ())
4487 9 : filtered_line_end = fn->end_line;
4488 : }
4489 : }
4490 :
4491 : /* For lines which don't exist in the .bb file, print '-' before
4492 : the source line. For lines which exist but were never
4493 : executed, print '#####' or '=====' before the source line. For lines
4494 : that were suppressed, print '#'. Otherwise, print the execution count
4495 : before the source line. There are 16 spaces of indentation added
4496 : before the source line so that tabs won't be messed up. */
4497 52037 : if (line_num <= filtered_line_end)
4498 : {
4499 51921 : output_line_beginning (gcov_file, line->exists, line->unexceptional,
4500 51921 : line->has_unexecuted_block, line->suppressed,
4501 51921 : line->count,
4502 : line_num, "=====", "#####",
4503 51921 : src->maximum_count);
4504 :
4505 51921 : print_source_line (gcov_file, source_lines, line_num);
4506 51921 : output_line_details (gcov_file, line, line_num);
4507 : }
4508 :
4509 52037 : if (line_start_group == line_num)
4510 : {
4511 71 : for (vector<function_info *>::iterator it = fns->begin ();
4512 239 : it != fns->end (); it++)
4513 : {
4514 168 : function_info *fn = *it;
4515 168 : vector<line_info> &lines = fn->lines;
4516 :
4517 168 : fprintf (gcov_file, FN_SEPARATOR);
4518 :
4519 168 : string fn_name = fn->get_name ();
4520 168 : if (flag_use_colors)
4521 : {
4522 0 : fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN));
4523 0 : fn_name += SGR_RESET;
4524 : }
4525 :
4526 168 : fprintf (gcov_file, "%s:\n", fn_name.c_str ());
4527 :
4528 168 : output_function_details (gcov_file, fn);
4529 168 : output_path_coverage (gcov_file, fn);
4530 :
4531 : /* Print all lines covered by the function. */
4532 1962 : for (unsigned i = 0; i < lines.size (); i++)
4533 : {
4534 1626 : line_info *line = &lines[i];
4535 1626 : unsigned l = fn->start_line + i;
4536 :
4537 : /* For lines which don't exist in the .bb file, print '-'
4538 : before the source line. For lines which exist but
4539 : were never executed, print '#####' or '=====' before
4540 : the source line. For suppressed lines, print '#'.
4541 : Otherwise, print the execution count before the source
4542 : line. There are 16 spaces of indentation added before the
4543 : source line so that tabs won't be messed up. */
4544 1626 : output_line_beginning (gcov_file, line->exists,
4545 : line->unexceptional,
4546 : line->has_unexecuted_block,
4547 1626 : line->suppressed,
4548 : line->count,
4549 : l, "=====", "#####",
4550 1626 : src->maximum_count);
4551 :
4552 1626 : print_source_line (gcov_file, source_lines, l);
4553 1626 : output_line_details (gcov_file, line, l);
4554 : }
4555 168 : }
4556 :
4557 71 : fprintf (gcov_file, FN_SEPARATOR);
4558 71 : line_start_group = 0;
4559 : }
4560 : }
4561 236 : }
|