Line data Source code
1 : /* Gcov.c: prepend line execution counts and branch probabilities to a
2 : source file.
3 : Copyright (C) 1990-2026 Free Software Foundation, Inc.
4 : Contributed by James E. Wilson of Cygnus Support.
5 : Mangled by Bob Manson of Cygnus Support.
6 : Mangled further by Nathan Sidwell <nathan@codesourcery.com>
7 :
8 : Gcov is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3, or (at your option)
11 : any later version.
12 :
13 : Gcov is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with Gcov; see the file COPYING3. If not see
20 : <http://www.gnu.org/licenses/>. */
21 :
22 : /* ??? Print a list of the ten blocks with the highest execution counts,
23 : and list the line numbers corresponding to those blocks. Also, perhaps
24 : list the line numbers with the highest execution counts, only printing
25 : the first if there are several which are all listed in the same block. */
26 :
27 : /* ??? Should have an option to print the number of basic blocks, and the
28 : percent of them that are covered. */
29 :
30 : /* Need an option to show individual block counts, and show
31 : probabilities of fall through arcs. */
32 :
33 : #include "config.h"
34 : #define INCLUDE_ALGORITHM
35 : #define INCLUDE_VECTOR
36 : #define INCLUDE_STRING
37 : #define INCLUDE_MAP
38 : #define INCLUDE_SET
39 : #include "system.h"
40 : #include "coretypes.h"
41 : #include "tm.h"
42 : #include "intl.h"
43 : #include "diagnostic.h"
44 : #include "version.h"
45 : #include "demangle.h"
46 : #include "color-macros.h"
47 : #include "pretty-print.h"
48 : #include "json.h"
49 : #include "hwint.h"
50 : #include "xregex.h"
51 : #include "graphds.h"
52 :
53 : #include <zlib.h>
54 : #include <getopt.h>
55 :
56 : #include "md5.h"
57 :
58 : using namespace std;
59 :
60 : #define IN_GCOV 1
61 : #include "gcov-io.h"
62 : #include "gcov-io.cc"
63 :
64 : #define GCOV_JSON_FORMAT_VERSION "2"
65 :
66 : /* The gcno file is generated by -ftest-coverage option. The gcda file is
67 : generated by a program compiled with -fprofile-arcs. Their formats
68 : are documented in gcov-io.h. */
69 :
70 : /* The functions in this file for creating and solution program flow graphs
71 : are very similar to functions in the gcc source file profile.cc. In
72 : some places we make use of the knowledge of how profile.cc works to
73 : select particular algorithms here. */
74 :
75 : /* The code validates that the profile information read in corresponds
76 : to the code currently being compiled. Rather than checking for
77 : identical files, the code below compares a checksum on the CFG
78 : (based on the order of basic blocks and the arcs in the CFG). If
79 : the CFG checksum in the gcda file match the CFG checksum in the
80 : gcno file, the profile data will be used. */
81 :
82 : /* This is the size of the buffer used to read in source file lines. */
83 :
84 : class function_info;
85 : class block_info;
86 : class source_info;
87 : class condition_info;
88 : class path_info;
89 :
90 : /* Describes an arc between two basic blocks. */
91 :
92 : struct arc_info
93 : {
94 : /* source and destination blocks. */
95 : class block_info *src;
96 : class block_info *dst;
97 :
98 : /* transition counts. */
99 : gcov_type count;
100 : /* used in cycle search, so that we do not clobber original counts. */
101 : gcov_type cs_count;
102 :
103 : unsigned int count_valid : 1;
104 : unsigned int on_tree : 1;
105 : unsigned int fake : 1;
106 : unsigned int fall_through : 1;
107 :
108 : /* Arc to a catch handler. */
109 : unsigned int is_throw : 1;
110 :
111 : /* Arc is for a function that abnormally returns. */
112 : unsigned int is_call_non_return : 1;
113 :
114 : /* Arc is for catch/setjmp. */
115 : unsigned int is_nonlocal_return : 1;
116 :
117 : /* Is an unconditional branch. */
118 : unsigned int is_unconditional : 1;
119 :
120 : /* Loop making arc. */
121 : unsigned int cycle : 1;
122 :
123 : /* Is a true arc. */
124 : unsigned int true_value : 1;
125 :
126 : /* Is a false arc. */
127 : unsigned int false_value : 1;
128 :
129 : /* 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 946 : class path_info
136 : {
137 : public:
138 1032 : 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 1220 : unsigned covered_paths () const
155 : {
156 1220 : unsigned cnt = 0;
157 1778 : for (gcov_type_unsigned v : covered)
158 558 : cnt += popcount_hwi (v);
159 1220 : return cnt;
160 : }
161 :
162 : /* Check if the nth path is covered. */
163 1850 : bool covered_p (size_t n) const
164 : {
165 1850 : if (covered.empty ())
166 : return false;
167 1850 : const size_t bucket = n / bucketsize;
168 1850 : const uint64_t bit = n % bucketsize;
169 1850 : 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 12448 : class block_location_info
177 : {
178 : public:
179 6302 : block_location_info (unsigned _source_file_idx):
180 6302 : 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 8677 : condition_info::condition_info (): truev (0), falsev (0), n_terms (0)
206 : {
207 8677 : }
208 :
209 5566 : int condition_info::popcount () const
210 : {
211 5566 : 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 8276 : 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 8677 : block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0),
267 8677 : id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
268 8677 : exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
269 8677 : locations (), chain (NULL)
270 : {
271 8677 : cycle.arc = NULL;
272 8677 : }
273 :
274 : /* Describes a single line of source. Contains a chain of basic blocks
275 : with code on it. */
276 :
277 78317 : 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 42363 : line_info::line_info (): count (0), branches (), blocks (), exists (false),
301 42363 : unexceptional (0), has_unexecuted_block (0)
302 : {
303 42363 : }
304 :
305 : bool
306 13598 : line_info::has_block (block_info *needle)
307 : {
308 13598 : 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 990 : is_artificial (function_info *fn)
331 : {
332 990 : 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 1233 : char *get_name ()
404 : {
405 1233 : 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 170 : inline bool operator() (const function_info *lhs,
421 : const function_info *rhs)
422 : {
423 170 : return (lhs->start_line == rhs->start_line
424 170 : ? lhs->start_column < rhs->start_column
425 170 : : 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 207 : source_info::source_info (): index (0), name (NULL), file_time (),
493 207 : lines (), coverage (), maximum_count (0), functions ()
494 : {
495 207 : }
496 :
497 : /* Register a new function. */
498 : void
499 946 : source_info::add_function (function_info *fn)
500 : {
501 946 : functions.push_back (fn);
502 :
503 946 : if (fn->start_line >= line_to_function_map.size ())
504 233 : line_to_function_map.resize (fn->start_line + 1);
505 :
506 946 : vector<function_info *> **slot = &line_to_function_map[fn->start_line];
507 946 : if (*slot == NULL)
508 866 : *slot = new vector<function_info *> ();
509 :
510 946 : (*slot)->push_back (fn);
511 946 : }
512 :
513 : vector<function_info *> *
514 40599 : source_info::get_functions_at_location (unsigned line_num) const
515 : {
516 40599 : if (line_num >= line_to_function_map.size ())
517 : return NULL;
518 :
519 29683 : vector<function_info *> *slot = line_to_function_map[line_num];
520 29683 : 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 7474 : name_map ()
555 0 : {
556 : }
557 :
558 208 : name_map (char *_name, unsigned _src): name (_name), src (_src)
559 : {
560 : }
561 :
562 14798 : 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 14798 : return strcmp (this->name, rhs.name) == 0;
568 : #endif
569 : }
570 :
571 942 : 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 940 : 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 1032 : function_info::function_info (): m_name (NULL), m_demangled_name (NULL),
834 1032 : ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
835 1032 : artificial (0), is_group (0),
836 1032 : blocks (), blocks_executed (0), counts (),
837 1032 : start_line (0), start_column (0), end_line (0), end_column (0),
838 1032 : src (0), lines (), next (NULL)
839 : {
840 1032 : }
841 :
842 946 : function_info::~function_info ()
843 : {
844 9222 : for (int i = blocks.size () - 1; i >= 0; i--)
845 : {
846 8276 : arc_info *arc, *arc_n;
847 :
848 19348 : for (arc = blocks[i].succ; arc; arc = arc_n)
849 : {
850 11072 : arc_n = arc->succ_next;
851 11072 : free (arc);
852 : }
853 : }
854 946 : if (m_demangled_name != m_name)
855 944 : free (m_demangled_name);
856 946 : free (m_name);
857 1892 : }
858 :
859 7696 : bool function_info::group_line_p (unsigned n, unsigned src_idx)
860 : {
861 7696 : 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 8108 : find_arc (const block_info &block, unsigned dest)
868 : {
869 34141 : for (const arc_info *arc = block.succ; arc; arc = arc->succ_next)
870 34141 : if (arc->dst->id == dest)
871 8108 : 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 1292 : path_contains_zero_or_negative_cycle_arc (arc_vector_t &path)
940 : {
941 10634 : for (unsigned i = 0; i < path.size (); i++)
942 9342 : 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 6603 : 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 6603 : bool loop_found = false;
958 :
959 : /* Add v to the block list. */
960 13206 : gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
961 6603 : blocked.push_back (v);
962 6603 : block_lists.push_back (block_vector_t ());
963 :
964 18356 : for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
965 : {
966 11753 : block_info *w = arc->dst;
967 22202 : if (w < start
968 8907 : || arc->cs_count <= 0
969 15394 : || !linfo.has_block (w))
970 10449 : continue;
971 :
972 1304 : path.push_back (arc);
973 1304 : if (w == start)
974 : {
975 : /* Cycle has been found. */
976 12 : handle_cycle (path, count);
977 12 : loop_found = true;
978 : }
979 1292 : else if (!path_contains_zero_or_negative_cycle_arc (path)
980 2584 : && find (blocked.begin (), blocked.end (), w) == blocked.end ())
981 1277 : loop_found |= circuit (w, path, start, blocked, block_lists, linfo,
982 : count);
983 :
984 1304 : path.pop_back ();
985 : }
986 :
987 6603 : if (loop_found)
988 26 : unblock (v, blocked, block_lists);
989 : else
990 18284 : for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
991 : {
992 11707 : block_info *w = arc->dst;
993 22139 : if (w < start
994 8867 : || arc->cs_count <= 0
995 15308 : || !linfo.has_block (w))
996 10432 : continue;
997 :
998 1275 : size_t index
999 2550 : = find (blocked.begin (), blocked.end (), w) - blocked.begin ();
1000 1275 : gcc_assert (index < blocked.size ());
1001 1275 : block_vector_t &list = block_lists[index];
1002 2550 : if (find (list.begin (), list.end (), v) == list.end ())
1003 1275 : list.push_back (v);
1004 : }
1005 :
1006 6603 : return loop_found;
1007 : }
1008 :
1009 : /* Find cycles for a LINFO. */
1010 :
1011 : static gcov_type
1012 3789 : 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 3789 : gcov_type count = 0;
1021 3789 : for (vector<block_info *>::iterator it = linfo.blocks.begin ();
1022 9115 : it != linfo.blocks.end (); it++)
1023 : {
1024 5326 : arc_vector_t path;
1025 5326 : block_vector_t blocked;
1026 5326 : vector<block_vector_t > block_lists;
1027 5326 : circuit (*it, path, *it, blocked, block_lists, linfo, count);
1028 5326 : }
1029 :
1030 3789 : return count;
1031 : }
1032 :
1033 : int
1034 140 : main (int argc, char **argv)
1035 : {
1036 140 : int argno;
1037 140 : int first_arg;
1038 140 : const char *p;
1039 :
1040 140 : p = argv[0] + strlen (argv[0]);
1041 700 : while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
1042 560 : --p;
1043 140 : progname = p;
1044 :
1045 140 : xmalloc_set_program_name (progname);
1046 :
1047 : /* Unlock the stdio streams. */
1048 140 : unlock_std_streams ();
1049 :
1050 140 : gcc_init_libintl ();
1051 :
1052 140 : diagnostic_initialize (global_dc, 0);
1053 :
1054 : /* Handle response files. */
1055 140 : expandargv (&argc, &argv);
1056 :
1057 140 : argno = process_args (argc, argv);
1058 140 : if (optind == argc)
1059 0 : print_usage (true);
1060 :
1061 140 : if (argc - argno > 1)
1062 0 : multiple_files = 1;
1063 :
1064 : first_arg = argno;
1065 :
1066 280 : for (; argno != argc; argno++)
1067 : {
1068 140 : if (flag_display_progress)
1069 0 : printf ("Processing file %d out of %d\n", argno - first_arg + 1,
1070 : argc - first_arg);
1071 140 : process_file (argv[argno]);
1072 :
1073 140 : if (flag_json_format || argno == argc - 1)
1074 : {
1075 140 : process_all_functions ();
1076 140 : generate_results (argv[argno]);
1077 140 : release_structures ();
1078 : }
1079 : }
1080 :
1081 140 : if (!flag_use_stdout)
1082 140 : executed_summary (total_lines, total_executed);
1083 :
1084 140 : 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 2026 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 140 : process_args (int argc, char **argv)
1202 : {
1203 140 : int opt;
1204 :
1205 140 : const char *opts = "abcdDefghHijklmMno:pqrs:tuvwx";
1206 220 : 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 140 : 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 140 : strip_extention (string str)
1454 : {
1455 140 : string::size_type pos = str.rfind ('.');
1456 140 : if (pos != string::npos)
1457 140 : str = str.substr (0, pos);
1458 :
1459 140 : 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 140 : get_gcov_intermediate_filename (const char *input_file_name)
1496 : {
1497 140 : string base = lbasename (input_file_name);
1498 280 : string str = strip_extention (base);
1499 :
1500 140 : if (flag_hash_filenames)
1501 : {
1502 0 : str += "##";
1503 0 : str += get_md5sum (input_file_name);
1504 : }
1505 140 : 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 140 : str += ".gcov.json.gz";
1513 140 : return str.c_str ();
1514 140 : }
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 2406 : hash (const function_start &ref)
1675 : {
1676 2406 : inchash::hash hstate (0);
1677 2406 : hstate.add_int (ref.source_file_idx);
1678 2406 : hstate.add_int (ref.start_line);
1679 2406 : return hstate.end ();
1680 : }
1681 :
1682 : static bool
1683 1600 : equal (const function_start &ref1, const function_start &ref2)
1684 : {
1685 1600 : return (ref1.source_file_idx == ref2.source_file_idx
1686 1600 : && 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 3463 : mark_empty (function_start &ref)
1699 : {
1700 3463 : ref.start_line = ~2U;
1701 : }
1702 :
1703 : static bool
1704 3205 : is_deleted (const function_start &ref)
1705 : {
1706 3205 : return ref.start_line == ~1U;
1707 : }
1708 :
1709 : static bool
1710 15149 : is_empty (const function_start &ref)
1711 : {
1712 14283 : return ref.start_line == ~2U;
1713 : }
1714 : };
1715 :
1716 : /* Process a single input file. */
1717 :
1718 : static void
1719 140 : process_file (const char *file_name)
1720 : {
1721 140 : create_file_names (file_name);
1722 :
1723 140 : 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 140 : processed_files.push_back (xstrdup (da_file_name));
1732 :
1733 140 : read_graph_file ();
1734 140 : read_count_file ();
1735 : }
1736 :
1737 : /* Process all functions in all files. */
1738 :
1739 : static void
1740 140 : process_all_functions (void)
1741 : {
1742 140 : hash_map<function_start_pair_hash, function_info *> fn_map;
1743 :
1744 : /* Identify group functions. */
1745 1130 : for (vector<function_info *>::iterator it = functions.begin ();
1746 1130 : it != functions.end (); it++)
1747 990 : if (!(*it)->artificial)
1748 : {
1749 946 : function_start needle;
1750 946 : needle.source_file_idx = (*it)->src;
1751 946 : needle.start_line = (*it)->start_line;
1752 :
1753 946 : function_info **slot = fn_map.get (needle);
1754 946 : if (slot)
1755 : {
1756 80 : (*slot)->is_group = 1;
1757 80 : (*it)->is_group = 1;
1758 : }
1759 : else
1760 866 : fn_map.put (needle, *it);
1761 : }
1762 :
1763 : /* Remove all artificial function. */
1764 140 : functions.erase (remove_if (functions.begin (), functions.end (),
1765 140 : 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 946 : function_info *fn = *it;
1771 946 : unsigned src = fn->src;
1772 :
1773 946 : if (!fn->counts.empty () || no_data_file)
1774 : {
1775 946 : source_info *s = &sources[src];
1776 946 : s->add_function (fn);
1777 :
1778 : /* Mark last line in files touched by function. */
1779 9222 : for (unsigned block_no = 0; block_no != fn->blocks.size ();
1780 : block_no++)
1781 : {
1782 8276 : block_info *block = &fn->blocks[block_no];
1783 14343 : for (unsigned i = 0; i < block->locations.size (); i++)
1784 : {
1785 : /* Sort lines of locations. */
1786 12134 : sort (block->locations[i].lines.begin (),
1787 6067 : block->locations[i].lines.end ());
1788 :
1789 6067 : if (!block->locations[i].lines.empty ())
1790 : {
1791 6064 : s = &sources[block->locations[i].source_file_idx];
1792 6064 : unsigned last_line
1793 6064 : = block->locations[i].lines.back ();
1794 :
1795 : /* Record new lines for the function. */
1796 6064 : 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 946 : if (sources[fn->src].lines.size () <= fn->end_line)
1817 152 : 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 946 : if (fn->is_group)
1822 133 : fn->lines.resize (fn->end_line - fn->start_line + 1);
1823 :
1824 946 : solve_flow_graph (fn);
1825 946 : if (fn->has_catch)
1826 60 : find_exception_blocks (fn);
1827 :
1828 : /* For path coverage. */
1829 946 : 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 140 : }
1838 :
1839 : static void
1840 205 : output_gcov_file (const char *file_name, source_info *src)
1841 : {
1842 205 : string gcov_file_name_str
1843 205 : = make_gcov_file_name (file_name, src->coverage.name);
1844 205 : const char *gcov_file_name = gcov_file_name_str.c_str ();
1845 :
1846 205 : if (src->coverage.lines)
1847 : {
1848 205 : FILE *gcov_file = fopen (gcov_file_name, "w");
1849 205 : if (gcov_file)
1850 : {
1851 205 : fnotice (stdout, "Creating '%s'\n", gcov_file_name);
1852 205 : output_lines (gcov_file, src);
1853 205 : 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 205 : 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 205 : }
1873 :
1874 : static void
1875 140 : generate_results (const char *file_name)
1876 : {
1877 140 : string gcov_intermediate_filename;
1878 :
1879 1086 : for (vector<function_info *>::iterator it = functions.begin ();
1880 1086 : it != functions.end (); it++)
1881 : {
1882 946 : function_info *fn = *it;
1883 946 : coverage_info coverage;
1884 :
1885 946 : memset (&coverage, 0, sizeof (coverage));
1886 946 : coverage.name = fn->get_name ();
1887 1892 : add_line_counts (flag_function_summary ? &coverage : NULL, fn);
1888 :
1889 946 : if (!flag_function_summary)
1890 946 : 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 140 : name_map needle;
1906 140 : needle.name = file_name;
1907 140 : vector<name_map>::iterator it
1908 140 : = std::find (names.begin (), names.end (), needle);
1909 140 : if (it != names.end ())
1910 3 : file_name = sources[it->src].coverage.name;
1911 : else
1912 137 : file_name = canonicalize_name (file_name);
1913 :
1914 140 : gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
1915 :
1916 140 : json::object *root = new json::object ();
1917 140 : root->set_string ("format_version", GCOV_JSON_FORMAT_VERSION);
1918 140 : root->set_string ("gcc_version", version_string);
1919 :
1920 140 : if (bbg_cwd != NULL)
1921 140 : root->set_string ("current_working_directory", bbg_cwd);
1922 140 : root->set_string ("data_file", file_name);
1923 :
1924 140 : json::array *json_files = new json::array ();
1925 140 : root->set ("files", json_files);
1926 :
1927 347 : for (vector<source_info>::iterator it = sources.begin ();
1928 347 : it != sources.end (); it++)
1929 : {
1930 207 : source_info *src = &(*it);
1931 207 : 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 1153 : for (function_info *fn : src->functions)
1946 946 : add_path_counts (src->coverage, *fn);
1947 :
1948 207 : accumulate_line_counts (src);
1949 207 : if (flag_debug)
1950 0 : src->debug ();
1951 :
1952 207 : if (!flag_use_stdout)
1953 207 : file_summary (&src->coverage);
1954 207 : total_lines += src->coverage.lines;
1955 207 : total_executed += src->coverage.lines_executed;
1956 207 : if (flag_gcov_file)
1957 : {
1958 207 : 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 205 : if (flag_use_stdout)
1967 : {
1968 0 : if (src->coverage.lines)
1969 0 : output_lines (stdout, src);
1970 : }
1971 : else
1972 : {
1973 205 : output_gcov_file (file_name, src);
1974 205 : fnotice (stdout, "\n");
1975 : }
1976 : }
1977 : }
1978 : }
1979 :
1980 140 : 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 140 : }
2015 :
2016 : /* Release all memory used. */
2017 :
2018 : static void
2019 140 : release_structures (void)
2020 : {
2021 1086 : for (vector<function_info *>::iterator it = functions.begin ();
2022 1086 : it != functions.end (); it++)
2023 946 : delete (*it);
2024 :
2025 345 : for (vector<const char *> *lines : source_lines)
2026 : {
2027 205 : if (lines)
2028 82928 : for (const char *line : *lines)
2029 82723 : free (const_cast <char*> (line));
2030 205 : delete (lines);
2031 : }
2032 140 : source_lines.resize (0);
2033 :
2034 155 : for (fnfilter &filter : filters)
2035 15 : regfree (&filter.regex);
2036 :
2037 140 : sources.resize (0);
2038 140 : names.resize (0);
2039 140 : functions.resize (0);
2040 140 : filters.resize (0);
2041 140 : ident_to_fn.clear ();
2042 140 : }
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 140 : create_file_names (const char *file_name)
2053 : {
2054 140 : char *cptr;
2055 140 : char *name;
2056 140 : int length = strlen (file_name);
2057 140 : int base;
2058 :
2059 : /* Free previous file names. */
2060 140 : free (bbg_file_name);
2061 140 : free (da_file_name);
2062 140 : da_file_name = bbg_file_name = NULL;
2063 140 : bbg_file_time = 0;
2064 140 : bbg_stamp = 0;
2065 :
2066 140 : 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 140 : name = XNEWVEC (char, length + 1);
2082 140 : strcpy (name, file_name);
2083 140 : base = 0;
2084 : }
2085 :
2086 140 : 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 140 : cptr = strrchr (const_cast<char *> (lbasename (name)), '.');
2095 140 : if (cptr)
2096 140 : *cptr = 0;
2097 :
2098 140 : length = strlen (name);
2099 :
2100 140 : bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
2101 140 : strcpy (bbg_file_name, name);
2102 140 : strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
2103 :
2104 140 : da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
2105 140 : strcpy (da_file_name, name);
2106 140 : strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
2107 :
2108 140 : free (name);
2109 140 : 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 7334 : find_source (const char *file_name)
2117 : {
2118 7334 : char *canon;
2119 7334 : unsigned idx;
2120 7334 : struct stat status;
2121 :
2122 7334 : if (!file_name)
2123 0 : file_name = "<unknown>";
2124 :
2125 7334 : name_map needle;
2126 7334 : needle.name = file_name;
2127 :
2128 7334 : vector<name_map>::iterator it = std::find (names.begin (), names.end (),
2129 : needle);
2130 7334 : if (it != names.end ())
2131 : {
2132 7126 : idx = it->src;
2133 7126 : goto check_date;
2134 : }
2135 :
2136 : /* Not found, try the canonical name. */
2137 208 : canon = canonicalize_name (file_name);
2138 208 : needle.name = canon;
2139 208 : it = std::find (names.begin (), names.end (), needle);
2140 208 : if (it == names.end ())
2141 : {
2142 : /* Not found with canonical name, create a new source. */
2143 207 : source_info *src;
2144 :
2145 207 : idx = sources.size ();
2146 207 : needle = name_map (canon, idx);
2147 207 : names.push_back (needle);
2148 :
2149 207 : sources.push_back (source_info ());
2150 207 : src = &sources.back ();
2151 207 : src->name = canon;
2152 207 : src->coverage.name = src->name;
2153 207 : src->index = idx;
2154 207 : 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 207 : if (!stat (src->name, &status))
2165 204 : src->file_time = status.st_mtime;
2166 : }
2167 : else
2168 1 : idx = it->src;
2169 :
2170 208 : needle.name = file_name;
2171 208 : 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 208 : std::sort (names.begin (), names.end ());
2179 :
2180 7334 : check_date:
2181 7334 : 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 7334 : return idx;
2197 : }
2198 :
2199 : /* Read the notes file. Save functions to FUNCTIONS global vector. */
2200 :
2201 : static void
2202 140 : read_graph_file (void)
2203 : {
2204 140 : unsigned version;
2205 140 : unsigned current_tag = 0;
2206 140 : unsigned tag;
2207 :
2208 140 : 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 140 : bbg_file_time = gcov_time ();
2215 140 : 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 140 : version = gcov_read_unsigned ();
2224 140 : 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 140 : bbg_stamp = gcov_read_unsigned ();
2236 : /* Read checksum. */
2237 140 : gcov_read_unsigned ();
2238 140 : bbg_cwd = xstrdup (gcov_read_string ());
2239 140 : bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
2240 :
2241 140 : function_info *fn = NULL;
2242 16494 : while ((tag = gcov_read_unsigned ()))
2243 : {
2244 16354 : unsigned length = gcov_read_unsigned ();
2245 16354 : gcov_position_t base = gcov_position ();
2246 :
2247 16354 : if (tag == GCOV_TAG_FUNCTION)
2248 : {
2249 1032 : char *function_name;
2250 1032 : unsigned ident;
2251 1032 : unsigned lineno_checksum, cfg_checksum;
2252 :
2253 1032 : ident = gcov_read_unsigned ();
2254 1032 : lineno_checksum = gcov_read_unsigned ();
2255 1032 : cfg_checksum = gcov_read_unsigned ();
2256 1032 : function_name = xstrdup (gcov_read_string ());
2257 1032 : unsigned artificial = gcov_read_unsigned ();
2258 1032 : unsigned src_idx = find_source (gcov_read_string ());
2259 1032 : unsigned start_line = gcov_read_unsigned ();
2260 1032 : unsigned start_column = gcov_read_unsigned ();
2261 1032 : unsigned end_line = gcov_read_unsigned ();
2262 1032 : unsigned end_column = gcov_read_unsigned ();
2263 :
2264 1032 : fn = new function_info ();
2265 :
2266 1032 : fn->m_name = function_name;
2267 1032 : fn->ident = ident;
2268 1032 : fn->lineno_checksum = lineno_checksum;
2269 1032 : fn->cfg_checksum = cfg_checksum;
2270 1032 : fn->src = src_idx;
2271 1032 : fn->start_line = start_line;
2272 1032 : fn->start_column = start_column;
2273 1032 : fn->end_line = end_line;
2274 1032 : fn->end_column = end_column;
2275 1032 : fn->artificial = artificial;
2276 :
2277 1032 : 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 1032 : const char *fname = function_name;
2285 1032 : if (flag_filter_on_demangled)
2286 12 : fname = fn->get_demangled_name ();
2287 :
2288 1032 : bool keep = default_keep;
2289 1104 : for (const fnfilter &fn : filters)
2290 72 : if (regexec (&fn.regex, fname, 0, nullptr, 0) == 0)
2291 26 : keep = fn.keep;
2292 :
2293 1032 : if (keep)
2294 : {
2295 990 : functions.push_back (fn);
2296 990 : ident_to_fn[ident] = fn;
2297 : }
2298 : }
2299 15322 : else if (fn && tag == GCOV_TAG_BLOCKS)
2300 : {
2301 1032 : 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 1032 : fn->blocks.resize (gcov_read_unsigned ());
2306 : }
2307 14290 : else if (fn && tag == GCOV_TAG_ARCS)
2308 : {
2309 7645 : unsigned src = gcov_read_unsigned ();
2310 7645 : fn->blocks[src].id = src;
2311 7645 : unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
2312 7645 : block_info *src_blk = &fn->blocks[src];
2313 7645 : unsigned mark_catches = 0;
2314 7645 : struct arc_info *arc;
2315 :
2316 7645 : if (src >= fn->blocks.size () || fn->blocks[src].succ)
2317 0 : goto corrupt;
2318 :
2319 19130 : while (num_dests--)
2320 : {
2321 11485 : unsigned dest = gcov_read_unsigned ();
2322 11485 : unsigned flags = gcov_read_unsigned ();
2323 :
2324 11485 : if (dest >= fn->blocks.size ())
2325 0 : goto corrupt;
2326 11485 : arc = XCNEW (arc_info);
2327 :
2328 11485 : arc->dst = &fn->blocks[dest];
2329 : /* Set id in order to find EXIT_BLOCK. */
2330 11485 : arc->dst->id = dest;
2331 11485 : arc->src = src_blk;
2332 :
2333 11485 : arc->count = 0;
2334 11485 : arc->count_valid = 0;
2335 11485 : arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
2336 11485 : arc->fake = !!(flags & GCOV_ARC_FAKE);
2337 11485 : arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
2338 11485 : arc->true_value = !!(flags & GCOV_ARC_TRUE);
2339 11485 : arc->false_value = !!(flags & GCOV_ARC_FALSE);
2340 :
2341 11485 : arc->succ_next = src_blk->succ;
2342 11485 : src_blk->succ = arc;
2343 11485 : src_blk->num_succ++;
2344 :
2345 11485 : arc->pred_next = fn->blocks[dest].pred;
2346 11485 : fn->blocks[dest].pred = arc;
2347 11485 : fn->blocks[dest].num_pred++;
2348 :
2349 11485 : if (arc->fake)
2350 : {
2351 1896 : if (src)
2352 : {
2353 : /* Exceptional exit from this function, the
2354 : source block must be a call. */
2355 1892 : fn->blocks[src].is_call_site = 1;
2356 1892 : arc->is_call_non_return = 1;
2357 1892 : 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 11485 : if (!arc->on_tree)
2369 4872 : fn->counts.push_back (0);
2370 : }
2371 :
2372 7645 : 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 5633 : for (arc = src_blk->succ; arc; arc = arc->succ_next)
2379 3741 : if (!arc->fake && !arc->fall_through)
2380 : {
2381 126 : arc->is_throw = 1;
2382 126 : fn->has_catch = 1;
2383 : }
2384 : }
2385 : }
2386 6645 : 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 6508 : else if (fn && tag == GCOV_TAG_PATHS)
2409 : {
2410 285 : const unsigned npaths = gcov_read_unsigned ();
2411 285 : const size_t nbits = path_info::bucketsize;
2412 285 : const size_t nbuckets = (npaths + (nbits - 1)) / nbits;
2413 285 : fn->paths.covered.assign (nbuckets, 0);
2414 285 : }
2415 6223 : else if (fn && tag == GCOV_TAG_LINES)
2416 : {
2417 6223 : unsigned blockno = gcov_read_unsigned ();
2418 6223 : block_info *block = &fn->blocks[blockno];
2419 :
2420 6223 : if (blockno >= fn->blocks.size ())
2421 0 : goto corrupt;
2422 :
2423 34783 : while (true)
2424 : {
2425 20503 : unsigned lineno = gcov_read_unsigned ();
2426 :
2427 20503 : if (lineno)
2428 7978 : block->locations.back ().lines.push_back (lineno);
2429 : else
2430 : {
2431 12525 : const char *file_name = gcov_read_string ();
2432 :
2433 12525 : if (!file_name)
2434 : break;
2435 6302 : block->locations.push_back (block_location_info
2436 6302 : (find_source (file_name)));
2437 : }
2438 14280 : }
2439 6223 : }
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 16354 : gcov_sync (base, length);
2446 16354 : 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 140 : gcov_close ();
2455 :
2456 140 : 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 140 : read_count_file (void)
2465 : {
2466 140 : unsigned ix;
2467 140 : unsigned version;
2468 140 : unsigned tag;
2469 140 : function_info *fn = NULL;
2470 140 : int error = 0;
2471 140 : map<unsigned, function_info *>::iterator it;
2472 :
2473 140 : if (!gcov_open (da_file_name, 1))
2474 : {
2475 11 : fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
2476 : da_file_name);
2477 11 : no_data_file = 1;
2478 11 : 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 2412 : while ((tag = gcov_read_unsigned ()))
2512 : {
2513 2154 : unsigned length = gcov_read_unsigned ();
2514 2154 : int read_length = (int)length;
2515 2154 : unsigned long base = gcov_position ();
2516 :
2517 2154 : 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 2025 : else if (tag == GCOV_TAG_FUNCTION && !length)
2524 : ; /* placeholder */
2525 2025 : else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
2526 : {
2527 925 : unsigned ident;
2528 925 : ident = gcov_read_unsigned ();
2529 925 : fn = NULL;
2530 925 : it = ident_to_fn.find (ident);
2531 925 : if (it != ident_to_fn.end ())
2532 883 : fn = it->second;
2533 :
2534 883 : if (!fn)
2535 : ;
2536 883 : else if (gcov_read_unsigned () != fn->lineno_checksum
2537 883 : || 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 1100 : else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_CONDS) && fn)
2546 : {
2547 118 : length = abs (read_length);
2548 118 : if (length != GCOV_TAG_COUNTER_LENGTH (2 * fn->conditions.size ()))
2549 0 : goto mismatch;
2550 :
2551 118 : 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 982 : else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
2561 : {
2562 731 : length = abs (read_length);
2563 731 : if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
2564 0 : goto mismatch;
2565 :
2566 731 : if (read_length > 0)
2567 3262 : for (ix = 0; ix != fn->counts.size (); ix++)
2568 2627 : fn->counts[ix] += gcov_read_counter ();
2569 : }
2570 251 : else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_PATHS) && fn)
2571 : {
2572 203 : vector<gcov_type_unsigned> &covered = fn->paths.covered;
2573 203 : length = abs (read_length);
2574 203 : if (length != GCOV_TAG_COUNTER_LENGTH (covered.size ()))
2575 0 : goto mismatch;
2576 :
2577 203 : if (read_length > 0)
2578 256 : for (ix = 0; ix != covered.size (); ix++)
2579 132 : covered[ix] = gcov_read_counter ();
2580 : }
2581 2154 : if (read_length < 0)
2582 : read_length = 0;
2583 2154 : gcov_sync (base, read_length);
2584 2154 : 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 946 : solve_flow_graph (function_info *fn)
2605 : {
2606 946 : unsigned ix;
2607 946 : arc_info *arc;
2608 946 : gcov_type *count_ptr = &fn->counts.front ();
2609 946 : block_info *blk;
2610 946 : block_info *valid_blocks = NULL; /* valid, but unpropagated blocks. */
2611 946 : block_info *invalid_blocks = NULL; /* invalid, but inferable blocks. */
2612 :
2613 : /* The arcs were built in reverse order. Fix that now. */
2614 9222 : for (ix = fn->blocks.size (); ix--;)
2615 : {
2616 8276 : arc_info *arc_p, *arc_n;
2617 :
2618 19348 : for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
2619 11072 : arc_p = arc, arc = arc_n)
2620 : {
2621 11072 : arc_n = arc->succ_next;
2622 11072 : arc->succ_next = arc_p;
2623 : }
2624 8276 : fn->blocks[ix].succ = arc_p;
2625 :
2626 19348 : for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
2627 11072 : arc_p = arc, arc = arc_n)
2628 : {
2629 11072 : arc_n = arc->pred_next;
2630 11072 : arc->pred_next = arc_p;
2631 : }
2632 8276 : fn->blocks[ix].pred = arc_p;
2633 : }
2634 :
2635 946 : 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 946 : 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 946 : fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
2647 :
2648 946 : 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 946 : 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 9222 : for (unsigned i = 0; i < fn->blocks.size (); i++)
2660 : {
2661 8276 : blk = &fn->blocks[i];
2662 8276 : block_info const *prev_dst = NULL;
2663 8276 : int out_of_order = 0;
2664 8276 : int non_fake_succ = 0;
2665 :
2666 19348 : for (arc = blk->succ; arc; arc = arc->succ_next)
2667 : {
2668 11072 : if (!arc->fake)
2669 9272 : non_fake_succ++;
2670 :
2671 11072 : if (!arc->on_tree)
2672 : {
2673 4688 : if (count_ptr)
2674 4688 : arc->count = *count_ptr++;
2675 4688 : arc->count_valid = 1;
2676 4688 : blk->num_succ--;
2677 4688 : arc->dst->num_pred--;
2678 : }
2679 11072 : if (prev_dst && prev_dst > arc->dst)
2680 11072 : out_of_order = 1;
2681 11072 : prev_dst = arc->dst;
2682 : }
2683 8276 : if (non_fake_succ == 1)
2684 : {
2685 : /* If there is only one non-fake exit, it is an
2686 : unconditional branch. */
2687 12977 : for (arc = blk->succ; arc; arc = arc->succ_next)
2688 7249 : if (!arc->fake)
2689 : {
2690 5728 : 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 5728 : if (blk->is_call_site && arc->fall_through
2698 1511 : && arc->dst->pred == arc && !arc->pred_next)
2699 1304 : 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 8276 : if (out_of_order)
2708 : {
2709 : arc_info *start = blk->succ;
2710 : unsigned changes = 1;
2711 :
2712 5995 : while (changes)
2713 : {
2714 : arc_info *arc, *arc_p, *arc_n;
2715 :
2716 : changes = 0;
2717 9750 : for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
2718 : {
2719 5714 : if (arc->dst > arc_n->dst)
2720 : {
2721 2857 : changes = 1;
2722 2857 : if (arc_p)
2723 780 : arc_p->succ_next = arc_n;
2724 : else
2725 : start = arc_n;
2726 2857 : arc->succ_next = arc_n->succ_next;
2727 2857 : arc_n->succ_next = arc;
2728 2857 : arc_p = arc_n;
2729 : }
2730 : else
2731 : {
2732 : arc_p = arc;
2733 : arc = arc_n;
2734 : }
2735 : }
2736 : }
2737 1959 : blk->succ = start;
2738 : }
2739 :
2740 : /* Place it on the invalid chain, it will be ignored if that's
2741 : wrong. */
2742 8276 : blk->invalid_chain = 1;
2743 8276 : blk->chain = invalid_blocks;
2744 8276 : invalid_blocks = blk;
2745 : }
2746 :
2747 4232 : while (invalid_blocks || valid_blocks)
2748 : {
2749 14227 : while ((blk = invalid_blocks))
2750 : {
2751 10941 : gcov_type total = 0;
2752 10941 : const arc_info *arc;
2753 :
2754 10941 : invalid_blocks = blk->chain;
2755 10941 : blk->invalid_chain = 0;
2756 10941 : if (!blk->num_succ)
2757 3104 : for (arc = blk->succ; arc; arc = arc->succ_next)
2758 1646 : total += arc->count;
2759 9483 : else if (!blk->num_pred)
2760 17093 : for (arc = blk->pred; arc; arc = arc->pred_next)
2761 10275 : total += arc->count;
2762 : else
2763 2665 : continue;
2764 :
2765 8276 : blk->count = total;
2766 8276 : blk->count_valid = 1;
2767 8276 : blk->chain = valid_blocks;
2768 8276 : blk->valid_chain = 1;
2769 8276 : valid_blocks = blk;
2770 : }
2771 11820 : while ((blk = valid_blocks))
2772 : {
2773 8534 : gcov_type total;
2774 8534 : arc_info *arc, *inv_arc;
2775 :
2776 8534 : valid_blocks = blk->chain;
2777 8534 : blk->valid_chain = 0;
2778 8534 : if (blk->num_succ == 1)
2779 : {
2780 5872 : block_info *dst;
2781 :
2782 5872 : total = blk->count;
2783 5872 : inv_arc = NULL;
2784 15298 : for (arc = blk->succ; arc; arc = arc->succ_next)
2785 : {
2786 9426 : total -= arc->count;
2787 9426 : if (!arc->count_valid)
2788 5872 : inv_arc = arc;
2789 : }
2790 5872 : dst = inv_arc->dst;
2791 5872 : inv_arc->count_valid = 1;
2792 5872 : inv_arc->count = total;
2793 5872 : blk->num_succ--;
2794 5872 : dst->num_pred--;
2795 5872 : 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 5735 : if (!dst->num_pred && !dst->invalid_chain)
2807 : {
2808 2519 : dst->chain = invalid_blocks;
2809 2519 : dst->invalid_chain = 1;
2810 2519 : invalid_blocks = dst;
2811 : }
2812 : }
2813 : }
2814 8534 : if (blk->num_pred == 1)
2815 : {
2816 512 : block_info *src;
2817 :
2818 512 : total = blk->count;
2819 512 : inv_arc = NULL;
2820 1309 : for (arc = blk->pred; arc; arc = arc->pred_next)
2821 : {
2822 797 : total -= arc->count;
2823 797 : if (!arc->count_valid)
2824 512 : inv_arc = arc;
2825 : }
2826 512 : src = inv_arc->src;
2827 512 : inv_arc->count_valid = 1;
2828 512 : inv_arc->count = total;
2829 512 : blk->num_pred--;
2830 512 : src->num_succ--;
2831 512 : if (src->count_valid)
2832 : {
2833 248 : if (src->num_succ == 1 && !src->valid_chain)
2834 : {
2835 221 : src->chain = valid_blocks;
2836 221 : src->valid_chain = 1;
2837 221 : valid_blocks = src;
2838 : }
2839 : }
2840 : else
2841 : {
2842 264 : if (!src->num_succ && !src->invalid_chain)
2843 : {
2844 146 : src->chain = invalid_blocks;
2845 146 : src->invalid_chain = 1;
2846 146 : 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 946 : 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 946 : }
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 946 : find_prime_paths (function_info *fn)
2874 : {
2875 946 : if (!flag_prime_paths)
2876 681 : 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 268 : if (fn->paths.covered.empty ())
2883 : return;
2884 :
2885 265 : struct graph *cfg = new_graph (fn->blocks.size ());
2886 2778 : for (block_info &block : fn->blocks)
2887 : {
2888 2513 : cfg->vertices[block.id].data = █
2889 6117 : for (arc_info *arc = block.succ; arc; arc = arc->succ_next)
2890 3604 : if (!arc->fake)
2891 3139 : add_edge (cfg, arc->src->id, arc->dst->id)->data = arc;
2892 : }
2893 :
2894 265 : 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 265 : vec<vec<int>> paths = prime_paths (cfg, (size_t)-1);
2899 530 : fn->paths.paths.reserve (paths.length ());
2900 2703 : for (vec<int> &path : paths)
2901 : {
2902 1908 : const int *begin = path.begin ();
2903 1908 : const int *end = path.end ();
2904 3816 : if (begin != end && path.last () == EXIT_BLOCK)
2905 1304 : --end;
2906 1908 : if (begin != end && *begin == ENTRY_BLOCK)
2907 1394 : ++begin;
2908 :
2909 1908 : 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 1884 : if (end - begin == 1 && !cfg->vertices[*begin].succ
2915 24 : && !cfg->vertices[*begin].pred)
2916 21 : continue;
2917 :
2918 1863 : fn->paths.paths.emplace_back (begin, end);
2919 : }
2920 :
2921 265 : release_vec_vec (paths);
2922 265 : 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 999 : for (ix = fn->blocks.size (); ix--;)
2935 939 : 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 692 : for (ix = 1; ix;)
2941 : {
2942 632 : block_info *block = queue[--ix];
2943 632 : const arc_info *arc;
2944 :
2945 1648 : for (arc = block->succ; arc; arc = arc->succ_next)
2946 1016 : if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
2947 : {
2948 572 : arc->dst->exceptional = 0;
2949 572 : 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 5326 : add_condition_counts (coverage_info *coverage, const block_info *block)
2980 : {
2981 5326 : coverage->conditions += 2 * block->conditions.n_terms;
2982 5326 : coverage->conditions_covered += block->conditions.popcount ();
2983 5326 : }
2984 :
2985 : /* Increment path totals, number of paths and number of covered paths,
2986 : in COVERAGE according to FN. */
2987 :
2988 : static void
2989 946 : add_path_counts (coverage_info &coverage, const function_info &fn)
2990 : {
2991 946 : coverage.paths += fn.paths.paths.size ();
2992 946 : coverage.paths_covered += fn.paths.covered_paths ();
2993 946 : }
2994 :
2995 : /* Format COUNT, if flag_human_readable_numbers is set, return it human
2996 : readable format. */
2997 :
2998 : static char const *
2999 2889 : format_count (gcov_type count)
3000 : {
3001 2889 : static char buffer[64];
3002 2889 : const char *units = " kMGTPEZY";
3003 :
3004 2889 : if (count < 1000 || !flag_human_readable_numbers)
3005 : {
3006 2847 : sprintf (buffer, "%" PRId64, count);
3007 2847 : 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 4362 : format_gcov (gcov_type top, gcov_type bottom, int decimal_places)
3030 : {
3031 4362 : static char buffer[20];
3032 :
3033 1473 : if (decimal_places >= 0)
3034 : {
3035 1473 : float ratio = bottom ? 100.0f * top / bottom : 0;
3036 :
3037 : /* Round up to 1% if there's a small non-zero value. */
3038 1464 : if (ratio > 0.0f && ratio < 0.5f && decimal_places == 0)
3039 1473 : ratio = 1.0f;
3040 1473 : sprintf (buffer, "%.*f%%", decimal_places, ratio);
3041 : }
3042 : else
3043 0 : return format_count (top);
3044 :
3045 1473 : return buffer;
3046 : }
3047 :
3048 : /* Summary of execution */
3049 :
3050 : static void
3051 347 : executed_summary (unsigned lines, unsigned executed)
3052 : {
3053 347 : if (lines)
3054 344 : 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 347 : }
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 207 : file_summary (const coverage_info *coverage)
3113 : {
3114 207 : fnotice (stdout, "%s '%s'\n", "File", coverage->name);
3115 207 : executed_summary (coverage->lines, coverage->lines_executed);
3116 :
3117 207 : 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 207 : 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 207 : if (flag_prime_paths)
3153 : {
3154 58 : if (coverage->paths)
3155 44 : fnotice (stdout, "Prime paths covered:%s of %d\n",
3156 44 : format_gcov (coverage->paths_covered, coverage->paths, 2),
3157 : coverage->paths);
3158 : else
3159 14 : fnotice (stdout, "No path information\n");
3160 : }
3161 207 : }
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 345 : canonicalize_name (const char *name)
3169 : {
3170 : /* The canonical name cannot be longer than the incoming name. */
3171 345 : char *result = XNEWVEC (char, strlen (name) + 1);
3172 345 : const char *base = name, *probe;
3173 345 : char *ptr = result;
3174 345 : char *dd_base;
3175 345 : 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 2690 : for (dd_base = ptr; *base; base = probe)
3187 : {
3188 : size_t len;
3189 :
3190 18799 : for (probe = base; *probe; probe++)
3191 18454 : if (IS_DIR_SEPARATOR (*probe))
3192 : break;
3193 :
3194 2345 : len = probe - base;
3195 2345 : if (len == 1 && base[0] == '.')
3196 : /* Elide a '.' directory */
3197 : ;
3198 2344 : 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 2344 : regular:
3223 : /* Regular pathname component. */
3224 2344 : if (slash)
3225 1999 : *ptr++ = '/';
3226 2344 : memcpy (ptr, base, len);
3227 2344 : ptr += len;
3228 2344 : slash = 1;
3229 : }
3230 :
3231 4345 : for (; IS_DIR_SEPARATOR (*probe); probe++)
3232 2000 : continue;
3233 2000 : }
3234 345 : *ptr = 0;
3235 :
3236 345 : 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 205 : make_gcov_file_name (const char *input_name, const char *src_name)
3253 : {
3254 205 : 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 205 : if (flag_hash_filenames)
3259 0 : str = (string (mangle_name (src_name)) + "##"
3260 0 : + get_md5sum (src_name) + ".gcov");
3261 : else
3262 : {
3263 205 : 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 205 : str += mangle_name (src_name);
3270 205 : str += ".gcov";
3271 : }
3272 :
3273 205 : 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 205 : mangle_name (char const *base)
3281 : {
3282 : /* Generate the source filename part. */
3283 205 : if (!flag_preserve_paths)
3284 205 : 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 946 : add_line_counts (coverage_info *coverage, function_info *fn)
3295 : {
3296 946 : bool has_any_line = false;
3297 : /* Scan each basic block. */
3298 9222 : for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
3299 : {
3300 8276 : line_info *line = NULL;
3301 8276 : block_info *block = &fn->blocks[ix];
3302 8276 : if (block->count && ix && ix + 1 != fn->blocks.size ())
3303 2811 : fn->blocks_executed++;
3304 14343 : for (unsigned i = 0; i < block->locations.size (); i++)
3305 : {
3306 6067 : unsigned src_idx = block->locations[i].source_file_idx;
3307 6067 : vector<unsigned> &lines = block->locations[i].lines;
3308 :
3309 6067 : block->cycle.arc = NULL;
3310 6067 : block->cycle.ident = ~0U;
3311 :
3312 13763 : for (unsigned j = 0; j < lines.size (); j++)
3313 : {
3314 7696 : unsigned ln = lines[j];
3315 :
3316 : /* Line belongs to a function that is in a group. */
3317 7696 : if (fn->group_line_p (ln, src_idx))
3318 : {
3319 599 : gcc_assert (lines[j] - fn->start_line < fn->lines.size ());
3320 599 : line = &(fn->lines[lines[j] - fn->start_line]);
3321 599 : 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 599 : line->exists = 1;
3329 599 : if (!block->exceptional)
3330 : {
3331 582 : line->unexceptional = 1;
3332 582 : if (block->count == 0)
3333 25 : line->has_unexecuted_block = 1;
3334 : }
3335 599 : line->count += block->count;
3336 : }
3337 : else
3338 : {
3339 7097 : gcc_assert (ln < sources[src_idx].lines.size ());
3340 7097 : line = &(sources[src_idx].lines[ln]);
3341 7097 : 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 7097 : line->exists = 1;
3349 7097 : if (!block->exceptional)
3350 : {
3351 6886 : line->unexceptional = 1;
3352 6886 : if (block->count == 0)
3353 3785 : line->has_unexecuted_block = 1;
3354 : }
3355 7097 : line->count += block->count;
3356 : }
3357 : }
3358 :
3359 6067 : has_any_line = true;
3360 :
3361 6067 : if (!ix || ix + 1 == fn->blocks.size ())
3362 : /* Entry or exit block. */;
3363 5326 : else if (line != NULL)
3364 : {
3365 5326 : line->blocks.push_back (block);
3366 :
3367 5326 : 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 946 : if (!has_any_line)
3379 0 : fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name,
3380 : fn->get_name ());
3381 946 : }
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 42363 : static void accumulate_line_info (line_info *line, source_info *src,
3387 : bool add_coverage)
3388 : {
3389 42363 : if (add_coverage)
3390 43676 : for (vector<arc_info *>::iterator it = line->branches.begin ();
3391 43676 : it != line->branches.end (); it++)
3392 1313 : add_branch_counts (&src->coverage, *it);
3393 :
3394 42363 : if (add_coverage)
3395 47689 : for (vector<block_info *>::iterator it = line->blocks.begin ();
3396 47689 : it != line->blocks.end (); it++)
3397 5326 : add_condition_counts (&src->coverage, *it);
3398 :
3399 :
3400 42363 : 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 5326 : for (vector<block_info *>::iterator it = line->blocks.begin ();
3412 9115 : it != line->blocks.end (); it++)
3413 : {
3414 11682 : for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next)
3415 6356 : if (!line->has_block (arc->src))
3416 4850 : count += arc->count;
3417 14399 : for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next)
3418 9073 : arc->cs_count = arc->count;
3419 : }
3420 :
3421 : /* Now, add the count of loops entirely on this line. */
3422 3789 : count += get_cycles_count (*line);
3423 3789 : line->count = count;
3424 :
3425 3789 : if (line->count > src->maximum_count)
3426 213 : src->maximum_count = line->count;
3427 : }
3428 :
3429 42363 : if (line->exists && add_coverage)
3430 : {
3431 5425 : src->coverage.lines++;
3432 5425 : if (line->count)
3433 2557 : src->coverage.lines_executed++;
3434 : }
3435 42363 : }
3436 :
3437 : /* Accumulate the line counts of a file. */
3438 :
3439 : static void
3440 207 : accumulate_line_counts (source_info *src)
3441 : {
3442 : /* First work on group functions. */
3443 1153 : for (vector<function_info *>::iterator it = src->functions.begin ();
3444 1153 : it != src->functions.end (); it++)
3445 : {
3446 946 : function_info *fn = *it;
3447 :
3448 946 : if (fn->src != src->index || !fn->is_group)
3449 813 : continue;
3450 :
3451 1332 : for (vector<line_info>::iterator it2 = fn->lines.begin ();
3452 1332 : it2 != fn->lines.end (); it2++)
3453 : {
3454 1199 : line_info *line = &(*it2);
3455 1199 : accumulate_line_info (line, src, true);
3456 : }
3457 : }
3458 :
3459 : /* Work on global lines that line in source file SRC. */
3460 41371 : for (vector<line_info>::iterator it = src->lines.begin ();
3461 41371 : it != src->lines.end (); it++)
3462 41164 : 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 207 : if (!flag_json_format)
3467 1142 : for (vector<function_info *>::iterator it = src->functions.begin ();
3468 1142 : it != src->functions.end (); it++)
3469 : {
3470 937 : function_info *fn = *it;
3471 :
3472 937 : if (fn->src != src->index || !fn->is_group)
3473 808 : continue;
3474 :
3475 1324 : for (unsigned i = 0; i < fn->lines.size (); i++)
3476 : {
3477 1195 : line_info *fn_line = &fn->lines[i];
3478 1195 : if (fn_line->exists)
3479 : {
3480 385 : unsigned ln = fn->start_line + i;
3481 385 : line_info *src_line = &src->lines[ln];
3482 :
3483 385 : if (!src_line->exists)
3484 159 : src->coverage.lines++;
3485 385 : if (!src_line->count && fn_line->count)
3486 152 : src->coverage.lines_executed++;
3487 :
3488 385 : src_line->count += fn_line->count;
3489 385 : src_line->exists = 1;
3490 :
3491 385 : if (fn_line->has_unexecuted_block)
3492 23 : src_line->has_unexecuted_block = 1;
3493 :
3494 385 : if (fn_line->unexceptional)
3495 385 : src_line->unexceptional = 1;
3496 : }
3497 : }
3498 : }
3499 207 : }
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 1233 : output_conditions (FILE *gcov_file, const block_info *binfo)
3507 : {
3508 1233 : const condition_info& info = binfo->conditions;
3509 1233 : 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 1408 : print_prime_path_lines (FILE *gcov_file, const function_info &fn,
3594 : const vector<unsigned> &path, unsigned pathno)
3595 : {
3596 1408 : const bool is_covered = fn.paths.covered_p (pathno);
3597 1408 : if (is_covered && !flag_prime_paths_lines_covered)
3598 : return 0;
3599 1368 : if (!is_covered && !flag_prime_paths_lines_uncovered)
3600 : return 0;
3601 :
3602 1284 : if (is_covered)
3603 83 : fprintf (gcov_file, "path %u covered: lines", pathno);
3604 : else
3605 1284 : fprintf (gcov_file, "path %u not covered: lines", pathno);
3606 :
3607 7851 : for (size_t k = 0; k != path.size (); ++k)
3608 : {
3609 6484 : const block_info &block = fn.blocks[path[k]];
3610 6484 : const char *edge_kind = "";
3611 6484 : if (k + 1 != path.size ())
3612 : {
3613 5117 : gcc_checking_assert (block.id == path[k]);
3614 5117 : const arc_info &arc = find_arc (block, path[k+1]);
3615 5117 : if (arc.true_value)
3616 : edge_kind = "(true)";
3617 4113 : else if (arc.false_value)
3618 : edge_kind = "(false)";
3619 3295 : else if (arc.is_throw)
3620 6484 : edge_kind = "(throw)";
3621 : }
3622 :
3623 12856 : 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 6372 : if (loc.lines.empty ())
3629 3 : continue;
3630 6369 : if (loc.source_file_idx == fn.src)
3631 6333 : fprintf (gcov_file, " %u%s", loc.lines.back (), edge_kind);
3632 : else
3633 36 : fprintf (gcov_file, " %s:%u%s", sources[loc.source_file_idx].name,
3634 36 : loc.lines.back (), edge_kind);
3635 : }
3636 : }
3637 :
3638 1367 : fprintf (gcov_file, "\n");
3639 1367 : return 1;
3640 : }
3641 :
3642 : static unsigned
3643 3334 : print_inlined_separator (FILE *gcov_file, unsigned current_index, const
3644 : block_location_info &loc, const function_info &fn)
3645 : {
3646 3334 : if (loc.source_file_idx != current_index && loc.source_file_idx == fn.src)
3647 14 : fprintf (gcov_file, "------------------\n");
3648 3334 : if (loc.source_file_idx != current_index && loc.source_file_idx != fn.src)
3649 25 : fprintf (gcov_file, "== inlined from %s ==\n",
3650 25 : sources[loc.source_file_idx].name);
3651 3334 : 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 442 : print_prime_path_source (FILE *gcov_file, const function_info &fn,
3661 : const vector<unsigned> &path, unsigned pathno)
3662 : {
3663 442 : const bool is_covered = fn.paths.covered_p (pathno);
3664 442 : if (is_covered && !flag_prime_paths_source_covered)
3665 : return 0;
3666 442 : if (!is_covered && !flag_prime_paths_source_uncovered)
3667 : return 0;
3668 :
3669 363 : if (is_covered)
3670 79 : fprintf (gcov_file, "path %u covered:\n", pathno);
3671 : else
3672 363 : fprintf (gcov_file, "path %u not covered:\n", pathno);
3673 442 : unsigned current = fn.src;
3674 3875 : for (size_t k = 0; k != path.size (); ++k)
3675 : {
3676 3433 : const unsigned bb = path[k];
3677 3433 : const block_info &block = fn.blocks[bb];
3678 3433 : gcc_checking_assert (block.id == bb);
3679 :
3680 3433 : const char *edge_kind = "";
3681 3433 : if (k + 1 != path.size ())
3682 : {
3683 2991 : const arc_info &arc = find_arc (block, path[k+1]);
3684 2991 : if (arc.true_value)
3685 : edge_kind = "(true)";
3686 2237 : else if (arc.false_value)
3687 : edge_kind = "(false)";
3688 1672 : else if (arc.is_throw)
3689 3433 : edge_kind = "(throw)";
3690 : }
3691 :
3692 6770 : 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 3337 : if (loc.lines.empty ())
3698 3 : continue;
3699 3334 : const source_info &src = sources[loc.source_file_idx];
3700 3334 : const vector<const char *> &lines = slurp (src, gcov_file, "");
3701 3334 : current = print_inlined_separator (gcov_file, current, loc, fn);
3702 4264 : for (unsigned i = 0; i != loc.lines.size () - 1; ++i)
3703 : {
3704 930 : const unsigned line = loc.lines[i];
3705 930 : fprintf (gcov_file, "BB %2d: %-7s %3d", bb, "", line);
3706 930 : print_source_line (gcov_file, lines, line);
3707 : }
3708 :
3709 3334 : const unsigned line = loc.lines.back ();
3710 3334 : fprintf (gcov_file, "BB %2d: %-7s %3d", bb, edge_kind, line);
3711 3334 : print_source_line (gcov_file, lines, line);
3712 : }
3713 : }
3714 :
3715 442 : fputc ('\n', gcov_file);
3716 442 : 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 928 : output_path_coverage (FILE *gcov_file, const function_info *fn)
3724 : {
3725 928 : if (!flag_prime_paths)
3726 : return 0;
3727 :
3728 268 : if (fn->paths.paths.empty ())
3729 3 : fnotice (gcov_file, "path coverage omitted\n");
3730 : else
3731 265 : fnotice (gcov_file, "paths covered %u of " HOST_SIZE_T_PRINT_UNSIGNED "\n",
3732 265 : fn->paths.covered_paths (), (fmt_size_t)fn->paths.paths.size ());
3733 :
3734 268 : if (flag_prime_paths_lines_uncovered || flag_prime_paths_lines_covered)
3735 : {
3736 192 : unsigned pathno = 0;
3737 1600 : for (const vector<unsigned> &path : fn->paths.paths)
3738 1408 : print_prime_path_lines (gcov_file, *fn, path, pathno++);
3739 : }
3740 :
3741 268 : if (flag_prime_paths_source_uncovered || flag_prime_paths_source_covered)
3742 : {
3743 120 : unsigned pathno = 0;
3744 562 : for (const vector<unsigned> &path : fn->paths.paths)
3745 442 : print_prime_path_source (gcov_file, *fn, path, pathno++);
3746 : }
3747 : return 1;
3748 : }
3749 :
3750 : static const char *
3751 82925 : read_line (FILE *file)
3752 : {
3753 82925 : static char *string;
3754 82925 : static size_t string_len;
3755 82925 : size_t pos = 0;
3756 :
3757 82925 : if (!string_len)
3758 : {
3759 132 : string_len = 200;
3760 132 : string = XNEWVEC (char, string_len);
3761 : }
3762 :
3763 82926 : while (fgets (string + pos, string_len - pos, file))
3764 : {
3765 82724 : size_t len = strlen (string + pos);
3766 :
3767 82724 : if (len && string[pos + len - 1] == '\n')
3768 : {
3769 82723 : string[pos + len - 1] = 0;
3770 82723 : 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 202 : 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 3539 : slurp (const source_info &src, FILE *gcov_file,
3791 : const char *line_start)
3792 : {
3793 3539 : if (source_lines.size () <= src.index)
3794 201 : 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 3539 : if (!source_lines[src.index])
3799 205 : source_lines[src.index] = new vector<const char *> ();
3800 :
3801 3539 : if (!source_lines[src.index]->empty ())
3802 : return *source_lines[src.index];
3803 :
3804 205 : FILE *source_file = fopen (src.name, "r");
3805 205 : if (!source_file)
3806 3 : fnotice (stderr, "Cannot open source file %s\n", src.name);
3807 202 : else if (src.file_time == 0)
3808 0 : fprintf (gcov_file, "%sSource is newer than graph\n", line_start);
3809 :
3810 205 : const char *retval;
3811 205 : vector<const char *> &lines = *source_lines[src.index];
3812 205 : if (source_file)
3813 82925 : while ((retval = read_line (source_file)))
3814 82723 : lines.push_back (xstrdup (retval));
3815 :
3816 202 : if (source_file)
3817 202 : 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 42012 : pad_count_string (string &s)
3825 : {
3826 42012 : if (s.size () < 9)
3827 42012 : s.insert (0, 9 - s.size (), ' ');
3828 42012 : }
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 42012 : 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 42012 : string s;
3845 42012 : if (exists)
3846 : {
3847 5599 : if (count > 0)
3848 : {
3849 2728 : s = format_gcov (count, 0, -1);
3850 2728 : if (has_unexecuted_block
3851 36 : && bbg_supports_has_unexecuted_blocks)
3852 : {
3853 36 : 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 36 : s += "*";
3862 : }
3863 2728 : pad_count_string (s);
3864 : }
3865 : else
3866 : {
3867 2871 : 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 2871 : s = unexceptional ? unexceptional_string : exceptional_string;
3882 2871 : pad_count_string (s);
3883 : }
3884 : }
3885 : }
3886 : else
3887 : {
3888 36413 : s = "-";
3889 36413 : pad_count_string (s);
3890 : }
3891 :
3892 : /* Format line number in output. */
3893 42012 : char buffer[16];
3894 42012 : sprintf (buffer, "%5u", line_num);
3895 42012 : string linestr (buffer);
3896 :
3897 42012 : 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 42012 : fprintf (f, "%s:%s", s.c_str (), linestr.c_str ());
3909 42012 : }
3910 :
3911 : static void
3912 87843 : print_source_line (FILE *f, const vector<const char *> &source_lines,
3913 : unsigned line)
3914 : {
3915 87843 : gcc_assert (line >= 1);
3916 87843 : gcc_assert (line <= source_lines.size ());
3917 :
3918 87843 : fprintf (f, ":%s\n", source_lines[line - 1]);
3919 87843 : }
3920 :
3921 : /* Output line details for LINE and print it to F file. LINE lives on
3922 : LINE_NUM. */
3923 :
3924 : static void
3925 41954 : output_line_details (FILE *f, const line_info *line, unsigned line_num)
3926 : {
3927 41954 : 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 41681 : if (flag_branches)
3956 : {
3957 1899 : int ix;
3958 :
3959 1899 : ix = 0;
3960 1899 : for (vector<arc_info *>::const_iterator it = line->branches.begin ();
3961 3138 : it != line->branches.end (); it++)
3962 1239 : ix += output_branch_count (f, ix, (*it));
3963 : }
3964 :
3965 41681 : if (flag_conditions)
3966 : {
3967 3424 : for (vector<block_info *>::const_iterator it = line->blocks.begin ();
3968 3424 : it != line->blocks.end (); it++)
3969 1233 : output_conditions (f, *it);
3970 : }
3971 : }
3972 41954 : }
3973 :
3974 : /* Output detail statistics about function FN to file F. */
3975 :
3976 : static void
3977 928 : output_function_details (FILE *f, function_info *fn)
3978 : {
3979 928 : 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 205 : 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 205 : 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 205 : 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 205 : fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
4028 205 : if (!multiple_files)
4029 : {
4030 205 : fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
4031 205 : fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
4032 205 : no_data_file ? "-" : da_file_name);
4033 205 : fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
4034 : }
4035 :
4036 205 : const vector<const char *> &source_lines = slurp (*src, gcov_file,
4037 : DEFAULT_LINE_START);
4038 205 : unsigned line_start_group = 0;
4039 205 : vector<function_info *> *fns;
4040 397 : unsigned filtered_line_end = !filters.empty () ? 0 : source_lines.size ();
4041 :
4042 82708 : for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
4043 : {
4044 82516 : 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 41638 : if (!filters.empty ())
4050 : break;
4051 41625 : fprintf (gcov_file, "%9s:%5u", "-", line_num);
4052 41625 : print_source_line (gcov_file, source_lines, line_num);
4053 41625 : continue;
4054 : }
4055 :
4056 40878 : const line_info *line = &src->lines[line_num];
4057 :
4058 40878 : if (line_start_group == 0)
4059 : {
4060 40530 : fns = src->get_functions_at_location (line_num);
4061 41382 : 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 176 : for (unsigned i = 0; i < fns->size (); i++)
4067 126 : 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 50 : if (line_start_group >= src->lines.size ())
4075 0 : line_start_group = src->lines.size () - 1;
4076 :
4077 50 : if (!filters.empty ())
4078 6 : filtered_line_end = line_start_group;
4079 : }
4080 41282 : else if (fns != NULL && fns->size () == 1)
4081 : {
4082 802 : function_info *fn = (*fns)[0];
4083 802 : output_function_details (gcov_file, fn);
4084 802 : 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 802 : 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 40878 : if (line_num <= filtered_line_end)
4100 : {
4101 40762 : output_line_beginning (gcov_file, line->exists, line->unexceptional,
4102 40762 : line->has_unexecuted_block, line->count,
4103 : line_num, "=====", "#####",
4104 40762 : src->maximum_count);
4105 :
4106 40762 : print_source_line (gcov_file, source_lines, line_num);
4107 40762 : output_line_details (gcov_file, line, line_num);
4108 : }
4109 :
4110 40878 : if (line_start_group == line_num)
4111 : {
4112 50 : for (vector<function_info *>::iterator it = fns->begin ();
4113 176 : it != fns->end (); it++)
4114 : {
4115 126 : function_info *fn = *it;
4116 126 : vector<line_info> &lines = fn->lines;
4117 :
4118 126 : fprintf (gcov_file, FN_SEPARATOR);
4119 :
4120 126 : string fn_name = fn->get_name ();
4121 126 : 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 126 : fprintf (gcov_file, "%s:\n", fn_name.c_str ());
4128 :
4129 126 : output_function_details (gcov_file, fn);
4130 126 : output_path_coverage (gcov_file, fn);
4131 :
4132 : /* Print all lines covered by the function. */
4133 1318 : for (unsigned i = 0; i < lines.size (); i++)
4134 : {
4135 1192 : line_info *line = &lines[i];
4136 1192 : 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 1192 : output_line_beginning (gcov_file, line->exists,
4146 : line->unexceptional,
4147 1192 : line->has_unexecuted_block,
4148 : line->count,
4149 : l, "=====", "#####",
4150 1192 : src->maximum_count);
4151 :
4152 1192 : print_source_line (gcov_file, source_lines, l);
4153 1192 : output_line_details (gcov_file, line, l);
4154 : }
4155 126 : }
4156 :
4157 50 : fprintf (gcov_file, FN_SEPARATOR);
4158 50 : line_start_group = 0;
4159 : }
4160 : }
4161 205 : }
|