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