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