GCOV: introduce usage of terminal colors.
[official-gcc.git] / gcc / gcov.c
blobe53bcf0fd88ee57f3c37f18e350e8994ce6ad5fc
1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file.
3 Copyright (C) 1990-2017 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>
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.
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.
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/>. */
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. */
27 /* ??? Should have an option to print the number of basic blocks, and the
28 percent of them that are covered. */
30 /* Need an option to show individual block counts, and show
31 probabilities of fall through arcs. */
33 #include "config.h"
34 #define INCLUDE_ALGORITHM
35 #define INCLUDE_VECTOR
36 #define INCLUDE_STRING
37 #include "system.h"
38 #include "coretypes.h"
39 #include "tm.h"
40 #include "intl.h"
41 #include "diagnostic.h"
42 #include "version.h"
43 #include "demangle.h"
44 #include "color-macros.h"
46 #include <getopt.h>
48 #include "md5.h"
50 using namespace std;
52 #define IN_GCOV 1
53 #include "gcov-io.h"
54 #include "gcov-io.c"
56 /* The gcno file is generated by -ftest-coverage option. The gcda file is
57 generated by a program compiled with -fprofile-arcs. Their formats
58 are documented in gcov-io.h. */
60 /* The functions in this file for creating and solution program flow graphs
61 are very similar to functions in the gcc source file profile.c. In
62 some places we make use of the knowledge of how profile.c works to
63 select particular algorithms here. */
65 /* The code validates that the profile information read in corresponds
66 to the code currently being compiled. Rather than checking for
67 identical files, the code below compares a checksum on the CFG
68 (based on the order of basic blocks and the arcs in the CFG). If
69 the CFG checksum in the gcda file match the CFG checksum in the
70 gcno file, the profile data will be used. */
72 /* This is the size of the buffer used to read in source file lines. */
74 struct function_info;
75 struct block_info;
76 struct source_info;
78 /* Describes an arc between two basic blocks. */
80 typedef struct arc_info
82 /* source and destination blocks. */
83 struct block_info *src;
84 struct block_info *dst;
86 /* transition counts. */
87 gcov_type count;
88 /* used in cycle search, so that we do not clobber original counts. */
89 gcov_type cs_count;
91 unsigned int count_valid : 1;
92 unsigned int on_tree : 1;
93 unsigned int fake : 1;
94 unsigned int fall_through : 1;
96 /* Arc to a catch handler. */
97 unsigned int is_throw : 1;
99 /* Arc is for a function that abnormally returns. */
100 unsigned int is_call_non_return : 1;
102 /* Arc is for catch/setjmp. */
103 unsigned int is_nonlocal_return : 1;
105 /* Is an unconditional branch. */
106 unsigned int is_unconditional : 1;
108 /* Loop making arc. */
109 unsigned int cycle : 1;
111 /* Next branch on line. */
112 struct arc_info *line_next;
114 /* Links to next arc on src and dst lists. */
115 struct arc_info *succ_next;
116 struct arc_info *pred_next;
117 } arc_t;
119 /* Describes which locations (lines and files) are associated with
120 a basic block. */
122 struct block_location_info
124 block_location_info (unsigned _source_file_idx):
125 source_file_idx (_source_file_idx)
128 unsigned source_file_idx;
129 vector<unsigned> lines;
132 /* Describes a basic block. Contains lists of arcs to successor and
133 predecessor blocks. */
135 typedef struct block_info
137 /* Constructor. */
138 block_info ();
140 /* Chain of exit and entry arcs. */
141 arc_t *succ;
142 arc_t *pred;
144 /* Number of unprocessed exit and entry arcs. */
145 gcov_type num_succ;
146 gcov_type num_pred;
148 unsigned id;
150 /* Block execution count. */
151 gcov_type count;
152 unsigned count_valid : 1;
153 unsigned valid_chain : 1;
154 unsigned invalid_chain : 1;
155 unsigned exceptional : 1;
157 /* Block is a call instrumenting site. */
158 unsigned is_call_site : 1; /* Does the call. */
159 unsigned is_call_return : 1; /* Is the return. */
161 /* Block is a landing pad for longjmp or throw. */
162 unsigned is_nonlocal_return : 1;
164 vector<block_location_info> locations;
166 struct
168 /* Single line graph cycle workspace. Used for all-blocks
169 mode. */
170 arc_t *arc;
171 unsigned ident;
172 } cycle; /* Used in all-blocks mode, after blocks are linked onto
173 lines. */
175 /* Temporary chain for solving graph, and for chaining blocks on one
176 line. */
177 struct block_info *chain;
179 } block_t;
181 block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0),
182 id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
183 exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
184 locations (), chain (NULL)
186 cycle.arc = NULL;
189 /* Describes a single function. Contains an array of basic blocks. */
191 typedef struct function_info
193 function_info ();
194 ~function_info ();
196 /* Name of function. */
197 char *name;
198 char *demangled_name;
199 unsigned ident;
200 unsigned lineno_checksum;
201 unsigned cfg_checksum;
203 /* The graph contains at least one fake incoming edge. */
204 unsigned has_catch : 1;
206 /* Array of basic blocks. Like in GCC, the entry block is
207 at blocks[0] and the exit block is at blocks[1]. */
208 #define ENTRY_BLOCK (0)
209 #define EXIT_BLOCK (1)
210 vector<block_t> blocks;
211 unsigned blocks_executed;
213 /* Raw arc coverage counts. */
214 gcov_type *counts;
215 unsigned num_counts;
217 /* First line number & file. */
218 unsigned line;
219 unsigned src;
221 /* Next function in same source file. */
222 struct function_info *next_file_fn;
224 /* Next function. */
225 struct function_info *next;
226 } function_t;
228 /* Describes coverage of a file or function. */
230 typedef struct coverage_info
232 int lines;
233 int lines_executed;
235 int branches;
236 int branches_executed;
237 int branches_taken;
239 int calls;
240 int calls_executed;
242 char *name;
243 } coverage_t;
245 /* Describes a single line of source. Contains a chain of basic blocks
246 with code on it. */
248 typedef struct line_info
250 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
251 bool has_block (block_t *needle);
253 gcov_type count; /* execution count */
254 arc_t *branches; /* branches from blocks that end on this line. */
255 block_t *blocks; /* blocks which start on this line.
256 Used in all-blocks mode. */
257 unsigned exists : 1;
258 unsigned unexceptional : 1;
259 } line_t;
261 bool
262 line_t::has_block (block_t *needle)
264 for (block_t *n = blocks; n; n = n->chain)
265 if (n == needle)
266 return true;
268 return false;
271 /* Describes a file mentioned in the block graph. Contains an array
272 of line info. */
274 typedef struct source_info
276 /* Canonical name of source file. */
277 char *name;
278 time_t file_time;
280 /* Array of line information. */
281 line_t *lines;
282 unsigned num_lines;
284 coverage_t coverage;
286 /* Functions in this source file. These are in ascending line
287 number order. */
288 function_t *functions;
289 } source_t;
291 typedef struct name_map
293 char *name; /* Source file name */
294 unsigned src; /* Source file */
295 } name_map_t;
297 /* Holds a list of function basic block graphs. */
299 static function_t *functions;
300 static function_t **fn_end = &functions;
302 static source_t *sources; /* Array of source files */
303 static unsigned n_sources; /* Number of sources */
304 static unsigned a_sources; /* Allocated sources */
306 static name_map_t *names; /* Mapping of file names to sources */
307 static unsigned n_names; /* Number of names */
308 static unsigned a_names; /* Allocated names */
310 /* This holds data summary information. */
312 static unsigned object_runs;
313 static unsigned program_count;
315 static unsigned total_lines;
316 static unsigned total_executed;
318 /* Modification time of graph file. */
320 static time_t bbg_file_time;
322 /* Name of the notes (gcno) output file. The "bbg" prefix is for
323 historical reasons, when the notes file contained only the
324 basic block graph notes. */
326 static char *bbg_file_name;
328 /* Stamp of the bbg file */
329 static unsigned bbg_stamp;
331 /* Name and file pointer of the input file for the count data (gcda). */
333 static char *da_file_name;
335 /* Data file is missing. */
337 static int no_data_file;
339 /* If there is several input files, compute and display results after
340 reading all data files. This way if two or more gcda file refer to
341 the same source file (eg inline subprograms in a .h file), the
342 counts are added. */
344 static int multiple_files = 0;
346 /* Output branch probabilities. */
348 static int flag_branches = 0;
350 /* Show unconditional branches too. */
351 static int flag_unconditional = 0;
353 /* Output a gcov file if this is true. This is on by default, and can
354 be turned off by the -n option. */
356 static int flag_gcov_file = 1;
358 /* Output progress indication if this is true. This is off by default
359 and can be turned on by the -d option. */
361 static int flag_display_progress = 0;
363 /* Output *.gcov file in intermediate format used by 'lcov'. */
365 static int flag_intermediate_format = 0;
367 /* Output demangled function names. */
369 static int flag_demangled_names = 0;
371 /* For included files, make the gcov output file name include the name
372 of the input source file. For example, if x.h is included in a.c,
373 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
375 static int flag_long_names = 0;
377 /* For situations when a long name can potentially hit filesystem path limit,
378 let's calculate md5sum of the path and append it to a file name. */
380 static int flag_hash_filenames = 0;
382 /* Print verbose informations. */
384 static int flag_verbose = 0;
386 /* Print colored output. */
388 static int flag_use_colors = 0;
390 /* Output count information for every basic block, not merely those
391 that contain line number information. */
393 static int flag_all_blocks = 0;
395 /* Output summary info for each function. */
397 static int flag_function_summary = 0;
399 /* Object directory file prefix. This is the directory/file where the
400 graph and data files are looked for, if nonzero. */
402 static char *object_directory = 0;
404 /* Source directory prefix. This is removed from source pathnames
405 that match, when generating the output file name. */
407 static char *source_prefix = 0;
408 static size_t source_length = 0;
410 /* Only show data for sources with relative pathnames. Absolute ones
411 usually indicate a system header file, which although it may
412 contain inline functions, is usually uninteresting. */
413 static int flag_relative_only = 0;
415 /* Preserve all pathname components. Needed when object files and
416 source files are in subdirectories. '/' is mangled as '#', '.' is
417 elided and '..' mangled to '^'. */
419 static int flag_preserve_paths = 0;
421 /* Output the number of times a branch was taken as opposed to the percentage
422 of times it was taken. */
424 static int flag_counts = 0;
426 /* Forward declarations. */
427 static int process_args (int, char **);
428 static void print_usage (int) ATTRIBUTE_NORETURN;
429 static void print_version (void) ATTRIBUTE_NORETURN;
430 static void process_file (const char *);
431 static void generate_results (const char *);
432 static void create_file_names (const char *);
433 static int name_search (const void *, const void *);
434 static int name_sort (const void *, const void *);
435 static char *canonicalize_name (const char *);
436 static unsigned find_source (const char *);
437 static function_t *read_graph_file (void);
438 static int read_count_file (function_t *);
439 static void solve_flow_graph (function_t *);
440 static void find_exception_blocks (function_t *);
441 static void add_branch_counts (coverage_t *, const arc_t *);
442 static void add_line_counts (coverage_t *, function_t *);
443 static void executed_summary (unsigned, unsigned);
444 static void function_summary (const coverage_t *, const char *);
445 static const char *format_gcov (gcov_type, gcov_type, int);
446 static void accumulate_line_counts (source_t *);
447 static void output_gcov_file (const char *, source_t *);
448 static int output_branch_count (FILE *, int, const arc_t *);
449 static void output_lines (FILE *, const source_t *);
450 static char *make_gcov_file_name (const char *, const char *);
451 static char *mangle_name (const char *, char *);
452 static void release_structures (void);
453 extern int main (int, char **);
455 function_info::function_info (): name (NULL), demangled_name (NULL),
456 ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
457 blocks (), blocks_executed (0), counts (NULL), num_counts (0),
458 line (0), src (0), next_file_fn (NULL), next (NULL)
462 function_info::~function_info ()
464 for (int i = blocks.size () - 1; i >= 0; i--)
466 arc_t *arc, *arc_n;
468 for (arc = blocks[i].succ; arc; arc = arc_n)
470 arc_n = arc->succ_next;
471 free (arc);
474 free (counts);
475 if (flag_demangled_names && demangled_name != name)
476 free (demangled_name);
477 free (name);
480 /* Cycle detection!
481 There are a bajillion algorithms that do this. Boost's function is named
482 hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
483 "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
484 (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
486 The basic algorithm is simple: effectively, we're finding all simple paths
487 in a subgraph (that shrinks every iteration). Duplicates are filtered by
488 "blocking" a path when a node is added to the path (this also prevents non-
489 simple paths)--the node is unblocked only when it participates in a cycle.
492 typedef vector<arc_t *> arc_vector_t;
493 typedef vector<const block_t *> block_vector_t;
495 /* Enum with types of loop in CFG. */
497 enum loop_type
499 NO_LOOP = 0,
500 LOOP = 1,
501 NEGATIVE_LOOP = 3
504 /* Loop_type operator that merges two values: A and B. */
506 inline loop_type& operator |= (loop_type& a, loop_type b)
508 return a = static_cast<loop_type> (a | b);
511 /* Handle cycle identified by EDGES, where the function finds minimum cs_count
512 and subtract the value from all counts. The subtracted value is added
513 to COUNT. Returns type of loop. */
515 static loop_type
516 handle_cycle (const arc_vector_t &edges, int64_t &count)
518 /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
519 that amount. */
520 int64_t cycle_count = INTTYPE_MAXIMUM (int64_t);
521 for (unsigned i = 0; i < edges.size (); i++)
523 int64_t ecount = edges[i]->cs_count;
524 if (cycle_count > ecount)
525 cycle_count = ecount;
527 count += cycle_count;
528 for (unsigned i = 0; i < edges.size (); i++)
529 edges[i]->cs_count -= cycle_count;
531 return cycle_count < 0 ? NEGATIVE_LOOP : LOOP;
534 /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
535 blocked by U in BLOCK_LISTS. */
537 static void
538 unblock (const block_t *u, block_vector_t &blocked,
539 vector<block_vector_t > &block_lists)
541 block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u);
542 if (it == blocked.end ())
543 return;
545 unsigned index = it - blocked.begin ();
546 blocked.erase (it);
548 block_vector_t to_unblock (block_lists[index]);
550 block_lists.erase (block_lists.begin () + index);
552 for (block_vector_t::iterator it = to_unblock.begin ();
553 it != to_unblock.end (); it++)
554 unblock (*it, blocked, block_lists);
557 /* Find circuit going to block V, PATH is provisional seen cycle.
558 BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
559 blocked by a block. COUNT is accumulated count of the current LINE.
560 Returns what type of loop it contains. */
562 static loop_type
563 circuit (block_t *v, arc_vector_t &path, block_t *start,
564 block_vector_t &blocked, vector<block_vector_t> &block_lists,
565 line_t &linfo, int64_t &count)
567 loop_type result = NO_LOOP;
569 /* Add v to the block list. */
570 gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
571 blocked.push_back (v);
572 block_lists.push_back (block_vector_t ());
574 for (arc_t *arc = v->succ; arc; arc = arc->succ_next)
576 block_t *w = arc->dst;
577 if (w < start || !linfo.has_block (w))
578 continue;
580 path.push_back (arc);
581 if (w == start)
582 /* Cycle has been found. */
583 result |= handle_cycle (path, count);
584 else if (find (blocked.begin (), blocked.end (), w) == blocked.end ())
585 result |= circuit (w, path, start, blocked, block_lists, linfo, count);
587 path.pop_back ();
590 if (result != NO_LOOP)
591 unblock (v, blocked, block_lists);
592 else
593 for (arc_t *arc = v->succ; arc; arc = arc->succ_next)
595 block_t *w = arc->dst;
596 if (w < start || !linfo.has_block (w))
597 continue;
599 size_t index
600 = find (blocked.begin (), blocked.end (), w) - blocked.begin ();
601 gcc_assert (index < blocked.size ());
602 block_vector_t &list = block_lists[index];
603 if (find (list.begin (), list.end (), v) == list.end ())
604 list.push_back (v);
607 return result;
610 /* Find cycles for a LINFO. If HANDLE_NEGATIVE_CYCLES is set and the line
611 contains a negative loop, then perform the same function once again. */
613 static gcov_type
614 get_cycles_count (line_t &linfo, bool handle_negative_cycles = true)
616 /* Note that this algorithm works even if blocks aren't in sorted order.
617 Each iteration of the circuit detection is completely independent
618 (except for reducing counts, but that shouldn't matter anyways).
619 Therefore, operating on a permuted order (i.e., non-sorted) only
620 has the effect of permuting the output cycles. */
622 loop_type result = NO_LOOP;
623 gcov_type count = 0;
624 for (block_t *block = linfo.blocks; block; block = block->chain)
626 arc_vector_t path;
627 block_vector_t blocked;
628 vector<block_vector_t > block_lists;
629 result |= circuit (block, path, block, blocked, block_lists, linfo,
630 count);
633 /* If we have a negative cycle, repeat the find_cycles routine. */
634 if (result == NEGATIVE_LOOP && handle_negative_cycles)
635 count += get_cycles_count (linfo, false);
637 return count;
641 main (int argc, char **argv)
643 int argno;
644 int first_arg;
645 const char *p;
647 p = argv[0] + strlen (argv[0]);
648 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
649 --p;
650 progname = p;
652 xmalloc_set_program_name (progname);
654 /* Unlock the stdio streams. */
655 unlock_std_streams ();
657 gcc_init_libintl ();
659 diagnostic_initialize (global_dc, 0);
661 /* Handle response files. */
662 expandargv (&argc, &argv);
664 a_names = 10;
665 names = XNEWVEC (name_map_t, a_names);
666 a_sources = 10;
667 sources = XNEWVEC (source_t, a_sources);
669 argno = process_args (argc, argv);
670 if (optind == argc)
671 print_usage (true);
673 if (argc - argno > 1)
674 multiple_files = 1;
676 first_arg = argno;
678 for (; argno != argc; argno++)
680 if (flag_display_progress)
681 printf ("Processing file %d out of %d\n", argno - first_arg + 1,
682 argc - first_arg);
683 process_file (argv[argno]);
686 generate_results (multiple_files ? NULL : argv[argc - 1]);
688 release_structures ();
690 return 0;
693 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
694 otherwise the output of --help. */
696 static void
697 print_usage (int error_p)
699 FILE *file = error_p ? stderr : stdout;
700 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
702 fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
703 fnotice (file, "Print code coverage information.\n\n");
704 fnotice (file, " -a, --all-blocks Show information for every basic block\n");
705 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
706 fnotice (file, " -c, --branch-counts Output counts of branches taken\n\
707 rather than percentages\n");
708 fnotice (file, " -d, --display-progress Display progress information\n");
709 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
710 fnotice (file, " -h, --help Print this help, then exit\n");
711 fnotice (file, " -i, --intermediate-format Output .gcov file in intermediate text format\n");
712 fnotice (file, " -k, --use-colors Emit colored output\n");
713 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
714 source files\n");
715 fnotice (file, " -m, --demangled-names Output demangled function names\n");
716 fnotice (file, " -n, --no-output Do not create an output file\n");
717 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
718 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
719 fnotice (file, " -r, --relative-only Only show data for relative sources\n");
720 fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n");
721 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
722 fnotice (file, " -v, --version Print version number, then exit\n");
723 fnotice (file, " -w, --verbose Print verbose informations\n");
724 fnotice (file, " -x, --hash-filenames Hash long pathnames\n");
725 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
726 bug_report_url);
727 exit (status);
730 /* Print version information and exit. */
732 static void
733 print_version (void)
735 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
736 fprintf (stdout, "Copyright %s 2017 Free Software Foundation, Inc.\n",
737 _("(C)"));
738 fnotice (stdout,
739 _("This is free software; see the source for copying conditions.\n"
740 "There is NO warranty; not even for MERCHANTABILITY or \n"
741 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
742 exit (SUCCESS_EXIT_CODE);
745 static const struct option options[] =
747 { "help", no_argument, NULL, 'h' },
748 { "version", no_argument, NULL, 'v' },
749 { "verbose", no_argument, NULL, 'w' },
750 { "all-blocks", no_argument, NULL, 'a' },
751 { "branch-probabilities", no_argument, NULL, 'b' },
752 { "branch-counts", no_argument, NULL, 'c' },
753 { "intermediate-format", no_argument, NULL, 'i' },
754 { "no-output", no_argument, NULL, 'n' },
755 { "long-file-names", no_argument, NULL, 'l' },
756 { "function-summaries", no_argument, NULL, 'f' },
757 { "demangled-names", no_argument, NULL, 'm' },
758 { "preserve-paths", no_argument, NULL, 'p' },
759 { "relative-only", no_argument, NULL, 'r' },
760 { "object-directory", required_argument, NULL, 'o' },
761 { "object-file", required_argument, NULL, 'o' },
762 { "source-prefix", required_argument, NULL, 's' },
763 { "unconditional-branches", no_argument, NULL, 'u' },
764 { "display-progress", no_argument, NULL, 'd' },
765 { "hash-filenames", no_argument, NULL, 'x' },
766 { "use-colors", no_argument, NULL, 'k' },
767 { 0, 0, 0, 0 }
770 /* Process args, return index to first non-arg. */
772 static int
773 process_args (int argc, char **argv)
775 int opt;
777 const char *opts = "abcdfhiklmno:prs:uvwx";
778 while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
780 switch (opt)
782 case 'a':
783 flag_all_blocks = 1;
784 break;
785 case 'b':
786 flag_branches = 1;
787 break;
788 case 'c':
789 flag_counts = 1;
790 break;
791 case 'f':
792 flag_function_summary = 1;
793 break;
794 case 'h':
795 print_usage (false);
796 /* print_usage will exit. */
797 case 'l':
798 flag_long_names = 1;
799 break;
800 case 'k':
801 flag_use_colors = 1;
802 break;
803 case 'm':
804 flag_demangled_names = 1;
805 break;
806 case 'n':
807 flag_gcov_file = 0;
808 break;
809 case 'o':
810 object_directory = optarg;
811 break;
812 case 's':
813 source_prefix = optarg;
814 source_length = strlen (source_prefix);
815 break;
816 case 'r':
817 flag_relative_only = 1;
818 break;
819 case 'p':
820 flag_preserve_paths = 1;
821 break;
822 case 'u':
823 flag_unconditional = 1;
824 break;
825 case 'i':
826 flag_intermediate_format = 1;
827 flag_gcov_file = 1;
828 break;
829 case 'd':
830 flag_display_progress = 1;
831 break;
832 case 'x':
833 flag_hash_filenames = 1;
834 break;
835 case 'w':
836 flag_verbose = 1;
837 break;
838 case 'v':
839 print_version ();
840 /* print_version will exit. */
841 default:
842 print_usage (true);
843 /* print_usage will exit. */
847 return optind;
850 /* Output the result in intermediate format used by 'lcov'.
852 The intermediate format contains a single file named 'foo.cc.gcov',
853 with no source code included. A sample output is
855 file:foo.cc
856 function:5,1,_Z3foov
857 function:13,1,main
858 function:19,1,_GLOBAL__sub_I__Z3foov
859 function:19,1,_Z41__static_initialization_and_destruction_0ii
860 lcount:5,1
861 lcount:7,9
862 lcount:9,8
863 lcount:11,1
864 file:/.../iostream
865 lcount:74,1
866 file:/.../basic_ios.h
867 file:/.../ostream
868 file:/.../ios_base.h
869 function:157,0,_ZStorSt12_Ios_IostateS_
870 lcount:157,0
871 file:/.../char_traits.h
872 function:258,0,_ZNSt11char_traitsIcE6lengthEPKc
873 lcount:258,0
876 The default gcov outputs multiple files: 'foo.cc.gcov',
877 'iostream.gcov', 'ios_base.h.gcov', etc. with source code
878 included. Instead the intermediate format here outputs only a single
879 file 'foo.cc.gcov' similar to the above example. */
881 static void
882 output_intermediate_file (FILE *gcov_file, source_t *src)
884 unsigned line_num; /* current line number. */
885 const line_t *line; /* current line info ptr. */
886 function_t *fn; /* current function info ptr. */
888 fprintf (gcov_file, "file:%s\n", src->name); /* source file name */
890 for (fn = src->functions; fn; fn = fn->next_file_fn)
892 /* function:<name>,<line_number>,<execution_count> */
893 fprintf (gcov_file, "function:%d,%s,%s\n", fn->line,
894 format_gcov (fn->blocks[0].count, 0, -1),
895 flag_demangled_names ? fn->demangled_name : fn->name);
898 for (line_num = 1, line = &src->lines[line_num];
899 line_num < src->num_lines;
900 line_num++, line++)
902 arc_t *arc;
903 if (line->exists)
904 fprintf (gcov_file, "lcount:%u,%s\n", line_num,
905 format_gcov (line->count, 0, -1));
906 if (flag_branches)
907 for (arc = line->branches; arc; arc = arc->line_next)
909 if (!arc->is_unconditional && !arc->is_call_non_return)
911 const char *branch_type;
912 /* branch:<line_num>,<branch_coverage_type>
913 branch_coverage_type
914 : notexec (Branch not executed)
915 : taken (Branch executed and taken)
916 : nottaken (Branch executed, but not taken)
918 if (arc->src->count)
919 branch_type = (arc->count > 0) ? "taken" : "nottaken";
920 else
921 branch_type = "notexec";
922 fprintf (gcov_file, "branch:%d,%s\n", line_num, branch_type);
928 /* Process a single input file. */
930 static void
931 process_file (const char *file_name)
933 function_t *fns;
935 create_file_names (file_name);
936 fns = read_graph_file ();
937 if (!fns)
938 return;
940 read_count_file (fns);
941 while (fns)
943 function_t *fn = fns;
945 fns = fn->next;
946 fn->next = NULL;
947 if (fn->counts || no_data_file)
949 unsigned src = fn->src;
950 unsigned line = fn->line;
951 unsigned block_no;
952 function_t *probe, **prev;
954 /* Now insert it into the source file's list of
955 functions. Normally functions will be encountered in
956 ascending order, so a simple scan is quick. Note we're
957 building this list in reverse order. */
958 for (prev = &sources[src].functions;
959 (probe = *prev); prev = &probe->next_file_fn)
960 if (probe->line <= line)
961 break;
962 fn->next_file_fn = probe;
963 *prev = fn;
965 /* Mark last line in files touched by function. */
966 for (block_no = 0; block_no != fn->blocks.size (); block_no++)
968 block_t *block = &fn->blocks[block_no];
969 for (unsigned i = 0; i < block->locations.size (); i++)
971 unsigned s = block->locations[i].source_file_idx;
973 /* Sort lines of locations. */
974 sort (block->locations[i].lines.begin (),
975 block->locations[i].lines.end ());
977 if (!block->locations[i].lines.empty ())
979 unsigned last_line
980 = block->locations[i].lines.back () + 1;
981 if (last_line > sources[s].num_lines)
982 sources[s].num_lines = last_line;
987 solve_flow_graph (fn);
988 if (fn->has_catch)
989 find_exception_blocks (fn);
990 *fn_end = fn;
991 fn_end = &fn->next;
993 else
994 /* The function was not in the executable -- some other
995 instance must have been selected. */
996 delete fn;
1000 static void
1001 output_gcov_file (const char *file_name, source_t *src)
1003 char *gcov_file_name = make_gcov_file_name (file_name, src->coverage.name);
1005 if (src->coverage.lines)
1007 FILE *gcov_file = fopen (gcov_file_name, "w");
1008 if (gcov_file)
1010 fnotice (stdout, "Creating '%s'\n", gcov_file_name);
1012 if (flag_intermediate_format)
1013 output_intermediate_file (gcov_file, src);
1014 else
1015 output_lines (gcov_file, src);
1016 if (ferror (gcov_file))
1017 fnotice (stderr, "Error writing output file '%s'\n", gcov_file_name);
1018 fclose (gcov_file);
1020 else
1021 fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
1023 else
1025 unlink (gcov_file_name);
1026 fnotice (stdout, "Removing '%s'\n", gcov_file_name);
1028 free (gcov_file_name);
1031 static void
1032 generate_results (const char *file_name)
1034 unsigned ix;
1035 source_t *src;
1036 function_t *fn;
1038 for (ix = n_sources, src = sources; ix--; src++)
1039 if (src->num_lines)
1040 src->lines = XCNEWVEC (line_t, src->num_lines);
1042 for (fn = functions; fn; fn = fn->next)
1044 coverage_t coverage;
1046 memset (&coverage, 0, sizeof (coverage));
1047 coverage.name = flag_demangled_names ? fn->demangled_name : fn->name;
1048 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
1049 if (flag_function_summary)
1051 function_summary (&coverage, "Function");
1052 fnotice (stdout, "\n");
1056 if (file_name)
1058 name_map_t *name_map = (name_map_t *)bsearch
1059 (file_name, names, n_names, sizeof (*names), name_search);
1060 if (name_map)
1061 file_name = sources[name_map->src].coverage.name;
1062 else
1063 file_name = canonicalize_name (file_name);
1066 for (ix = n_sources, src = sources; ix--; src++)
1068 if (flag_relative_only)
1070 /* Ignore this source, if it is an absolute path (after
1071 source prefix removal). */
1072 char first = src->coverage.name[0];
1074 #if HAVE_DOS_BASED_FILE_SYSTEM
1075 if (first && src->coverage.name[1] == ':')
1076 first = src->coverage.name[2];
1077 #endif
1078 if (IS_DIR_SEPARATOR (first))
1079 continue;
1082 accumulate_line_counts (src);
1083 function_summary (&src->coverage, "File");
1084 total_lines += src->coverage.lines;
1085 total_executed += src->coverage.lines_executed;
1086 if (flag_gcov_file)
1088 output_gcov_file (file_name, src);
1089 fnotice (stdout, "\n");
1093 if (!file_name)
1094 executed_summary (total_lines, total_executed);
1097 /* Release all memory used. */
1099 static void
1100 release_structures (void)
1102 unsigned ix;
1103 function_t *fn;
1105 for (ix = n_sources; ix--;)
1106 free (sources[ix].lines);
1107 free (sources);
1109 for (ix = n_names; ix--;)
1110 free (names[ix].name);
1111 free (names);
1113 while ((fn = functions))
1115 functions = fn->next;
1116 delete fn;
1120 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
1121 is not specified, these are named from FILE_NAME sans extension. If
1122 OBJECT_DIRECTORY is specified and is a directory, the files are in that
1123 directory, but named from the basename of the FILE_NAME, sans extension.
1124 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
1125 and the data files are named from that. */
1127 static void
1128 create_file_names (const char *file_name)
1130 char *cptr;
1131 char *name;
1132 int length = strlen (file_name);
1133 int base;
1135 /* Free previous file names. */
1136 free (bbg_file_name);
1137 free (da_file_name);
1138 da_file_name = bbg_file_name = NULL;
1139 bbg_file_time = 0;
1140 bbg_stamp = 0;
1142 if (object_directory && object_directory[0])
1144 struct stat status;
1146 length += strlen (object_directory) + 2;
1147 name = XNEWVEC (char, length);
1148 name[0] = 0;
1150 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
1151 strcat (name, object_directory);
1152 if (base && (!IS_DIR_SEPARATOR (name[strlen (name) - 1])))
1153 strcat (name, "/");
1155 else
1157 name = XNEWVEC (char, length + 1);
1158 strcpy (name, file_name);
1159 base = 0;
1162 if (base)
1164 /* Append source file name. */
1165 const char *cptr = lbasename (file_name);
1166 strcat (name, cptr ? cptr : file_name);
1169 /* Remove the extension. */
1170 cptr = strrchr (CONST_CAST (char *, lbasename (name)), '.');
1171 if (cptr)
1172 *cptr = 0;
1174 length = strlen (name);
1176 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
1177 strcpy (bbg_file_name, name);
1178 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
1180 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
1181 strcpy (da_file_name, name);
1182 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
1184 free (name);
1185 return;
1188 /* A is a string and B is a pointer to name_map_t. Compare for file
1189 name orderability. */
1191 static int
1192 name_search (const void *a_, const void *b_)
1194 const char *a = (const char *)a_;
1195 const name_map_t *b = (const name_map_t *)b_;
1197 #if HAVE_DOS_BASED_FILE_SYSTEM
1198 return strcasecmp (a, b->name);
1199 #else
1200 return strcmp (a, b->name);
1201 #endif
1204 /* A and B are a pointer to name_map_t. Compare for file name
1205 orderability. */
1207 static int
1208 name_sort (const void *a_, const void *b_)
1210 const name_map_t *a = (const name_map_t *)a_;
1211 return name_search (a->name, b_);
1214 /* Find or create a source file structure for FILE_NAME. Copies
1215 FILE_NAME on creation */
1217 static unsigned
1218 find_source (const char *file_name)
1220 name_map_t *name_map;
1221 char *canon;
1222 unsigned idx;
1223 struct stat status;
1225 if (!file_name)
1226 file_name = "<unknown>";
1227 name_map = (name_map_t *)bsearch
1228 (file_name, names, n_names, sizeof (*names), name_search);
1229 if (name_map)
1231 idx = name_map->src;
1232 goto check_date;
1235 if (n_names + 2 > a_names)
1237 /* Extend the name map array -- we'll be inserting one or two
1238 entries. */
1239 a_names *= 2;
1240 name_map = XNEWVEC (name_map_t, a_names);
1241 memcpy (name_map, names, n_names * sizeof (*names));
1242 free (names);
1243 names = name_map;
1246 /* Not found, try the canonical name. */
1247 canon = canonicalize_name (file_name);
1248 name_map = (name_map_t *) bsearch (canon, names, n_names, sizeof (*names),
1249 name_search);
1250 if (!name_map)
1252 /* Not found with canonical name, create a new source. */
1253 source_t *src;
1255 if (n_sources == a_sources)
1257 a_sources *= 2;
1258 src = XNEWVEC (source_t, a_sources);
1259 memcpy (src, sources, n_sources * sizeof (*sources));
1260 free (sources);
1261 sources = src;
1264 idx = n_sources;
1266 name_map = &names[n_names++];
1267 name_map->name = canon;
1268 name_map->src = idx;
1270 src = &sources[n_sources++];
1271 memset (src, 0, sizeof (*src));
1272 src->name = canon;
1273 src->coverage.name = src->name;
1274 if (source_length
1275 #if HAVE_DOS_BASED_FILE_SYSTEM
1276 /* You lose if separators don't match exactly in the
1277 prefix. */
1278 && !strncasecmp (source_prefix, src->coverage.name, source_length)
1279 #else
1280 && !strncmp (source_prefix, src->coverage.name, source_length)
1281 #endif
1282 && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
1283 src->coverage.name += source_length + 1;
1284 if (!stat (src->name, &status))
1285 src->file_time = status.st_mtime;
1287 else
1288 idx = name_map->src;
1290 if (name_search (file_name, name_map))
1292 /* Append the non-canonical name. */
1293 name_map = &names[n_names++];
1294 name_map->name = xstrdup (file_name);
1295 name_map->src = idx;
1298 /* Resort the name map. */
1299 qsort (names, n_names, sizeof (*names), name_sort);
1301 check_date:
1302 if (sources[idx].file_time > bbg_file_time)
1304 static int info_emitted;
1306 fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
1307 file_name, bbg_file_name);
1308 if (!info_emitted)
1310 fnotice (stderr,
1311 "(the message is displayed only once per source file)\n");
1312 info_emitted = 1;
1314 sources[idx].file_time = 0;
1317 return idx;
1320 /* Read the notes file. Return list of functions read -- in reverse order. */
1322 static function_t *
1323 read_graph_file (void)
1325 unsigned version;
1326 unsigned current_tag = 0;
1327 function_t *fn = NULL;
1328 function_t *fns = NULL;
1329 function_t **fns_end = &fns;
1330 unsigned tag;
1332 if (!gcov_open (bbg_file_name, 1))
1334 fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1335 return fns;
1337 bbg_file_time = gcov_time ();
1338 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1340 fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
1341 gcov_close ();
1342 return fns;
1345 version = gcov_read_unsigned ();
1346 if (version != GCOV_VERSION)
1348 char v[4], e[4];
1350 GCOV_UNSIGNED2STRING (v, version);
1351 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1353 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1354 bbg_file_name, v, e);
1356 bbg_stamp = gcov_read_unsigned ();
1358 while ((tag = gcov_read_unsigned ()))
1360 unsigned length = gcov_read_unsigned ();
1361 gcov_position_t base = gcov_position ();
1363 if (tag == GCOV_TAG_FUNCTION)
1365 char *function_name;
1366 unsigned ident, lineno;
1367 unsigned lineno_checksum, cfg_checksum;
1369 ident = gcov_read_unsigned ();
1370 lineno_checksum = gcov_read_unsigned ();
1371 cfg_checksum = gcov_read_unsigned ();
1372 function_name = xstrdup (gcov_read_string ());
1373 unsigned src_idx = find_source (gcov_read_string ());
1374 lineno = gcov_read_unsigned ();
1376 fn = new function_t;
1377 fn->name = function_name;
1378 if (flag_demangled_names)
1380 fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS);
1381 if (!fn->demangled_name)
1382 fn->demangled_name = fn->name;
1384 fn->ident = ident;
1385 fn->lineno_checksum = lineno_checksum;
1386 fn->cfg_checksum = cfg_checksum;
1387 fn->src = src_idx;
1388 fn->line = lineno;
1390 fn->next_file_fn = NULL;
1391 fn->next = NULL;
1392 *fns_end = fn;
1393 fns_end = &fn->next;
1394 current_tag = tag;
1396 else if (fn && tag == GCOV_TAG_BLOCKS)
1398 if (!fn->blocks.empty ())
1399 fnotice (stderr, "%s:already seen blocks for '%s'\n",
1400 bbg_file_name, fn->name);
1401 else
1402 fn->blocks.resize (gcov_read_unsigned ());
1404 else if (fn && tag == GCOV_TAG_ARCS)
1406 unsigned src = gcov_read_unsigned ();
1407 fn->blocks[src].id = src;
1408 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1409 block_t *src_blk = &fn->blocks[src];
1410 unsigned mark_catches = 0;
1411 struct arc_info *arc;
1413 if (src >= fn->blocks.size () || fn->blocks[src].succ)
1414 goto corrupt;
1416 while (num_dests--)
1418 unsigned dest = gcov_read_unsigned ();
1419 unsigned flags = gcov_read_unsigned ();
1421 if (dest >= fn->blocks.size ())
1422 goto corrupt;
1423 arc = XCNEW (arc_t);
1425 arc->dst = &fn->blocks[dest];
1426 arc->src = src_blk;
1428 arc->count = 0;
1429 arc->count_valid = 0;
1430 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
1431 arc->fake = !!(flags & GCOV_ARC_FAKE);
1432 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
1434 arc->succ_next = src_blk->succ;
1435 src_blk->succ = arc;
1436 src_blk->num_succ++;
1438 arc->pred_next = fn->blocks[dest].pred;
1439 fn->blocks[dest].pred = arc;
1440 fn->blocks[dest].num_pred++;
1442 if (arc->fake)
1444 if (src)
1446 /* Exceptional exit from this function, the
1447 source block must be a call. */
1448 fn->blocks[src].is_call_site = 1;
1449 arc->is_call_non_return = 1;
1450 mark_catches = 1;
1452 else
1454 /* Non-local return from a callee of this
1455 function. The destination block is a setjmp. */
1456 arc->is_nonlocal_return = 1;
1457 fn->blocks[dest].is_nonlocal_return = 1;
1461 if (!arc->on_tree)
1462 fn->num_counts++;
1465 if (mark_catches)
1467 /* We have a fake exit from this block. The other
1468 non-fall through exits must be to catch handlers.
1469 Mark them as catch arcs. */
1471 for (arc = src_blk->succ; arc; arc = arc->succ_next)
1472 if (!arc->fake && !arc->fall_through)
1474 arc->is_throw = 1;
1475 fn->has_catch = 1;
1479 else if (fn && tag == GCOV_TAG_LINES)
1481 unsigned blockno = gcov_read_unsigned ();
1482 block_t *block = &fn->blocks[blockno];
1484 if (blockno >= fn->blocks.size ())
1485 goto corrupt;
1487 while (true)
1489 unsigned lineno = gcov_read_unsigned ();
1491 if (lineno)
1492 block->locations.back ().lines.push_back (lineno);
1493 else
1495 const char *file_name = gcov_read_string ();
1497 if (!file_name)
1498 break;
1499 block->locations.push_back (block_location_info
1500 (find_source (file_name)));
1504 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
1506 fn = NULL;
1507 current_tag = 0;
1509 gcov_sync (base, length);
1510 if (gcov_is_error ())
1512 corrupt:;
1513 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
1514 break;
1517 gcov_close ();
1519 if (!fns)
1520 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
1522 return fns;
1525 /* Reads profiles from the count file and attach to each
1526 function. Return nonzero if fatal error. */
1528 static int
1529 read_count_file (function_t *fns)
1531 unsigned ix;
1532 unsigned version;
1533 unsigned tag;
1534 function_t *fn = NULL;
1535 int error = 0;
1537 if (!gcov_open (da_file_name, 1))
1539 fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
1540 da_file_name);
1541 no_data_file = 1;
1542 return 0;
1544 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
1546 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
1547 cleanup:;
1548 gcov_close ();
1549 return 1;
1551 version = gcov_read_unsigned ();
1552 if (version != GCOV_VERSION)
1554 char v[4], e[4];
1556 GCOV_UNSIGNED2STRING (v, version);
1557 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1559 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
1560 da_file_name, v, e);
1562 tag = gcov_read_unsigned ();
1563 if (tag != bbg_stamp)
1565 fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
1566 goto cleanup;
1569 while ((tag = gcov_read_unsigned ()))
1571 unsigned length = gcov_read_unsigned ();
1572 unsigned long base = gcov_position ();
1574 if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1576 struct gcov_summary summary;
1577 gcov_read_summary (&summary);
1578 object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs;
1579 program_count++;
1581 else if (tag == GCOV_TAG_FUNCTION && !length)
1582 ; /* placeholder */
1583 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
1585 unsigned ident;
1586 struct function_info *fn_n;
1588 /* Try to find the function in the list. To speed up the
1589 search, first start from the last function found. */
1590 ident = gcov_read_unsigned ();
1591 fn_n = fns;
1592 for (fn = fn ? fn->next : NULL; ; fn = fn->next)
1594 if (fn)
1596 else if ((fn = fn_n))
1597 fn_n = NULL;
1598 else
1600 fnotice (stderr, "%s:unknown function '%u'\n",
1601 da_file_name, ident);
1602 break;
1604 if (fn->ident == ident)
1605 break;
1608 if (!fn)
1610 else if (gcov_read_unsigned () != fn->lineno_checksum
1611 || gcov_read_unsigned () != fn->cfg_checksum)
1613 mismatch:;
1614 fnotice (stderr, "%s:profile mismatch for '%s'\n",
1615 da_file_name, fn->name);
1616 goto cleanup;
1619 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1621 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
1622 goto mismatch;
1624 if (!fn->counts)
1625 fn->counts = XCNEWVEC (gcov_type, fn->num_counts);
1627 for (ix = 0; ix != fn->num_counts; ix++)
1628 fn->counts[ix] += gcov_read_counter ();
1630 gcov_sync (base, length);
1631 if ((error = gcov_is_error ()))
1633 fnotice (stderr,
1634 error < 0
1635 ? N_("%s:overflowed\n")
1636 : N_("%s:corrupted\n"),
1637 da_file_name);
1638 goto cleanup;
1642 gcov_close ();
1643 return 0;
1646 /* Solve the flow graph. Propagate counts from the instrumented arcs
1647 to the blocks and the uninstrumented arcs. */
1649 static void
1650 solve_flow_graph (function_t *fn)
1652 unsigned ix;
1653 arc_t *arc;
1654 gcov_type *count_ptr = fn->counts;
1655 block_t *blk;
1656 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */
1657 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
1659 /* The arcs were built in reverse order. Fix that now. */
1660 for (ix = fn->blocks.size (); ix--;)
1662 arc_t *arc_p, *arc_n;
1664 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
1665 arc_p = arc, arc = arc_n)
1667 arc_n = arc->succ_next;
1668 arc->succ_next = arc_p;
1670 fn->blocks[ix].succ = arc_p;
1672 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
1673 arc_p = arc, arc = arc_n)
1675 arc_n = arc->pred_next;
1676 arc->pred_next = arc_p;
1678 fn->blocks[ix].pred = arc_p;
1681 if (fn->blocks.size () < 2)
1682 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
1683 bbg_file_name, fn->name);
1684 else
1686 if (fn->blocks[ENTRY_BLOCK].num_pred)
1687 fnotice (stderr, "%s:'%s' has arcs to entry block\n",
1688 bbg_file_name, fn->name);
1689 else
1690 /* We can't deduce the entry block counts from the lack of
1691 predecessors. */
1692 fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
1694 if (fn->blocks[EXIT_BLOCK].num_succ)
1695 fnotice (stderr, "%s:'%s' has arcs from exit block\n",
1696 bbg_file_name, fn->name);
1697 else
1698 /* Likewise, we can't deduce exit block counts from the lack
1699 of its successors. */
1700 fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
1703 /* Propagate the measured counts, this must be done in the same
1704 order as the code in profile.c */
1705 for (unsigned i = 0; i < fn->blocks.size (); i++)
1707 blk = &fn->blocks[i];
1708 block_t const *prev_dst = NULL;
1709 int out_of_order = 0;
1710 int non_fake_succ = 0;
1712 for (arc = blk->succ; arc; arc = arc->succ_next)
1714 if (!arc->fake)
1715 non_fake_succ++;
1717 if (!arc->on_tree)
1719 if (count_ptr)
1720 arc->count = *count_ptr++;
1721 arc->count_valid = 1;
1722 blk->num_succ--;
1723 arc->dst->num_pred--;
1725 if (prev_dst && prev_dst > arc->dst)
1726 out_of_order = 1;
1727 prev_dst = arc->dst;
1729 if (non_fake_succ == 1)
1731 /* If there is only one non-fake exit, it is an
1732 unconditional branch. */
1733 for (arc = blk->succ; arc; arc = arc->succ_next)
1734 if (!arc->fake)
1736 arc->is_unconditional = 1;
1737 /* If this block is instrumenting a call, it might be
1738 an artificial block. It is not artificial if it has
1739 a non-fallthrough exit, or the destination of this
1740 arc has more than one entry. Mark the destination
1741 block as a return site, if none of those conditions
1742 hold. */
1743 if (blk->is_call_site && arc->fall_through
1744 && arc->dst->pred == arc && !arc->pred_next)
1745 arc->dst->is_call_return = 1;
1749 /* Sort the successor arcs into ascending dst order. profile.c
1750 normally produces arcs in the right order, but sometimes with
1751 one or two out of order. We're not using a particularly
1752 smart sort. */
1753 if (out_of_order)
1755 arc_t *start = blk->succ;
1756 unsigned changes = 1;
1758 while (changes)
1760 arc_t *arc, *arc_p, *arc_n;
1762 changes = 0;
1763 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1765 if (arc->dst > arc_n->dst)
1767 changes = 1;
1768 if (arc_p)
1769 arc_p->succ_next = arc_n;
1770 else
1771 start = arc_n;
1772 arc->succ_next = arc_n->succ_next;
1773 arc_n->succ_next = arc;
1774 arc_p = arc_n;
1776 else
1778 arc_p = arc;
1779 arc = arc_n;
1783 blk->succ = start;
1786 /* Place it on the invalid chain, it will be ignored if that's
1787 wrong. */
1788 blk->invalid_chain = 1;
1789 blk->chain = invalid_blocks;
1790 invalid_blocks = blk;
1793 while (invalid_blocks || valid_blocks)
1795 while ((blk = invalid_blocks))
1797 gcov_type total = 0;
1798 const arc_t *arc;
1800 invalid_blocks = blk->chain;
1801 blk->invalid_chain = 0;
1802 if (!blk->num_succ)
1803 for (arc = blk->succ; arc; arc = arc->succ_next)
1804 total += arc->count;
1805 else if (!blk->num_pred)
1806 for (arc = blk->pred; arc; arc = arc->pred_next)
1807 total += arc->count;
1808 else
1809 continue;
1811 blk->count = total;
1812 blk->count_valid = 1;
1813 blk->chain = valid_blocks;
1814 blk->valid_chain = 1;
1815 valid_blocks = blk;
1817 while ((blk = valid_blocks))
1819 gcov_type total;
1820 arc_t *arc, *inv_arc;
1822 valid_blocks = blk->chain;
1823 blk->valid_chain = 0;
1824 if (blk->num_succ == 1)
1826 block_t *dst;
1828 total = blk->count;
1829 inv_arc = NULL;
1830 for (arc = blk->succ; arc; arc = arc->succ_next)
1832 total -= arc->count;
1833 if (!arc->count_valid)
1834 inv_arc = arc;
1836 dst = inv_arc->dst;
1837 inv_arc->count_valid = 1;
1838 inv_arc->count = total;
1839 blk->num_succ--;
1840 dst->num_pred--;
1841 if (dst->count_valid)
1843 if (dst->num_pred == 1 && !dst->valid_chain)
1845 dst->chain = valid_blocks;
1846 dst->valid_chain = 1;
1847 valid_blocks = dst;
1850 else
1852 if (!dst->num_pred && !dst->invalid_chain)
1854 dst->chain = invalid_blocks;
1855 dst->invalid_chain = 1;
1856 invalid_blocks = dst;
1860 if (blk->num_pred == 1)
1862 block_t *src;
1864 total = blk->count;
1865 inv_arc = NULL;
1866 for (arc = blk->pred; arc; arc = arc->pred_next)
1868 total -= arc->count;
1869 if (!arc->count_valid)
1870 inv_arc = arc;
1872 src = inv_arc->src;
1873 inv_arc->count_valid = 1;
1874 inv_arc->count = total;
1875 blk->num_pred--;
1876 src->num_succ--;
1877 if (src->count_valid)
1879 if (src->num_succ == 1 && !src->valid_chain)
1881 src->chain = valid_blocks;
1882 src->valid_chain = 1;
1883 valid_blocks = src;
1886 else
1888 if (!src->num_succ && !src->invalid_chain)
1890 src->chain = invalid_blocks;
1891 src->invalid_chain = 1;
1892 invalid_blocks = src;
1899 /* If the graph has been correctly solved, every block will have a
1900 valid count. */
1901 for (unsigned i = 0; ix < fn->blocks.size (); i++)
1902 if (!fn->blocks[i].count_valid)
1904 fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
1905 bbg_file_name, fn->name);
1906 break;
1910 /* Mark all the blocks only reachable via an incoming catch. */
1912 static void
1913 find_exception_blocks (function_t *fn)
1915 unsigned ix;
1916 block_t **queue = XALLOCAVEC (block_t *, fn->blocks.size ());
1918 /* First mark all blocks as exceptional. */
1919 for (ix = fn->blocks.size (); ix--;)
1920 fn->blocks[ix].exceptional = 1;
1922 /* Now mark all the blocks reachable via non-fake edges */
1923 queue[0] = &fn->blocks[0];
1924 queue[0]->exceptional = 0;
1925 for (ix = 1; ix;)
1927 block_t *block = queue[--ix];
1928 const arc_t *arc;
1930 for (arc = block->succ; arc; arc = arc->succ_next)
1931 if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
1933 arc->dst->exceptional = 0;
1934 queue[ix++] = arc->dst;
1940 /* Increment totals in COVERAGE according to arc ARC. */
1942 static void
1943 add_branch_counts (coverage_t *coverage, const arc_t *arc)
1945 if (arc->is_call_non_return)
1947 coverage->calls++;
1948 if (arc->src->count)
1949 coverage->calls_executed++;
1951 else if (!arc->is_unconditional)
1953 coverage->branches++;
1954 if (arc->src->count)
1955 coverage->branches_executed++;
1956 if (arc->count)
1957 coverage->branches_taken++;
1961 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
1962 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1963 If DP is zero, no decimal point is printed. Only print 100% when
1964 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1965 format TOP. Return pointer to a static string. */
1967 static char const *
1968 format_gcov (gcov_type top, gcov_type bottom, int dp)
1970 static char buffer[20];
1972 /* Handle invalid values that would result in a misleading value. */
1973 if (bottom != 0 && top > bottom && dp >= 0)
1975 sprintf (buffer, "NAN %%");
1976 return buffer;
1979 if (dp >= 0)
1981 float ratio = bottom ? (float)top / bottom : 0;
1982 int ix;
1983 unsigned limit = 100;
1984 unsigned percent;
1986 for (ix = dp; ix--; )
1987 limit *= 10;
1989 percent = (unsigned) (ratio * limit + (float)0.5);
1990 if (percent <= 0 && top)
1991 percent = 1;
1992 else if (percent >= limit && top != bottom)
1993 percent = limit - 1;
1994 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1995 if (dp)
1997 dp++;
2000 buffer[ix+1] = buffer[ix];
2001 ix--;
2003 while (dp--);
2004 buffer[ix + 1] = '.';
2007 else
2008 sprintf (buffer, "%" PRId64, (int64_t)top);
2010 return buffer;
2013 /* Summary of execution */
2015 static void
2016 executed_summary (unsigned lines, unsigned executed)
2018 if (lines)
2019 fnotice (stdout, "Lines executed:%s of %d\n",
2020 format_gcov (executed, lines, 2), lines);
2021 else
2022 fnotice (stdout, "No executable lines\n");
2025 /* Output summary info for a function or file. */
2027 static void
2028 function_summary (const coverage_t *coverage, const char *title)
2030 fnotice (stdout, "%s '%s'\n", title, coverage->name);
2031 executed_summary (coverage->lines, coverage->lines_executed);
2033 if (flag_branches)
2035 if (coverage->branches)
2037 fnotice (stdout, "Branches executed:%s of %d\n",
2038 format_gcov (coverage->branches_executed,
2039 coverage->branches, 2),
2040 coverage->branches);
2041 fnotice (stdout, "Taken at least once:%s of %d\n",
2042 format_gcov (coverage->branches_taken,
2043 coverage->branches, 2),
2044 coverage->branches);
2046 else
2047 fnotice (stdout, "No branches\n");
2048 if (coverage->calls)
2049 fnotice (stdout, "Calls executed:%s of %d\n",
2050 format_gcov (coverage->calls_executed, coverage->calls, 2),
2051 coverage->calls);
2052 else
2053 fnotice (stdout, "No calls\n");
2057 /* Canonicalize the filename NAME by canonicalizing directory
2058 separators, eliding . components and resolving .. components
2059 appropriately. Always returns a unique string. */
2061 static char *
2062 canonicalize_name (const char *name)
2064 /* The canonical name cannot be longer than the incoming name. */
2065 char *result = XNEWVEC (char, strlen (name) + 1);
2066 const char *base = name, *probe;
2067 char *ptr = result;
2068 char *dd_base;
2069 int slash = 0;
2071 #if HAVE_DOS_BASED_FILE_SYSTEM
2072 if (base[0] && base[1] == ':')
2074 result[0] = base[0];
2075 result[1] = ':';
2076 base += 2;
2077 ptr += 2;
2079 #endif
2080 for (dd_base = ptr; *base; base = probe)
2082 size_t len;
2084 for (probe = base; *probe; probe++)
2085 if (IS_DIR_SEPARATOR (*probe))
2086 break;
2088 len = probe - base;
2089 if (len == 1 && base[0] == '.')
2090 /* Elide a '.' directory */
2092 else if (len == 2 && base[0] == '.' && base[1] == '.')
2094 /* '..', we can only elide it and the previous directory, if
2095 we're not a symlink. */
2096 struct stat ATTRIBUTE_UNUSED buf;
2098 *ptr = 0;
2099 if (dd_base == ptr
2100 #if defined (S_ISLNK)
2101 /* S_ISLNK is not POSIX.1-1996. */
2102 || stat (result, &buf) || S_ISLNK (buf.st_mode)
2103 #endif
2106 /* Cannot elide, or unreadable or a symlink. */
2107 dd_base = ptr + 2 + slash;
2108 goto regular;
2110 while (ptr != dd_base && *ptr != '/')
2111 ptr--;
2112 slash = ptr != result;
2114 else
2116 regular:
2117 /* Regular pathname component. */
2118 if (slash)
2119 *ptr++ = '/';
2120 memcpy (ptr, base, len);
2121 ptr += len;
2122 slash = 1;
2125 for (; IS_DIR_SEPARATOR (*probe); probe++)
2126 continue;
2128 *ptr = 0;
2130 return result;
2133 /* Print hex representation of 16 bytes from SUM and write it to BUFFER. */
2135 static void
2136 md5sum_to_hex (const char *sum, char *buffer)
2138 for (unsigned i = 0; i < 16; i++)
2139 sprintf (buffer + (2 * i), "%02x", (unsigned char)sum[i]);
2142 /* Generate an output file name. INPUT_NAME is the canonicalized main
2143 input file and SRC_NAME is the canonicalized file name.
2144 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
2145 long_output_names we prepend the processed name of the input file
2146 to each output name (except when the current source file is the
2147 input file, so you don't get a double concatenation). The two
2148 components are separated by '##'. With preserve_paths we create a
2149 filename from all path components of the source file, replacing '/'
2150 with '#', and .. with '^', without it we simply take the basename
2151 component. (Remember, the canonicalized name will already have
2152 elided '.' components and converted \\ separators.) */
2154 static char *
2155 make_gcov_file_name (const char *input_name, const char *src_name)
2157 char *ptr;
2158 char *result;
2160 if (flag_long_names && input_name && strcmp (src_name, input_name))
2162 /* Generate the input filename part. */
2163 result = XNEWVEC (char, strlen (input_name) + strlen (src_name) + 10);
2165 ptr = result;
2166 ptr = mangle_name (input_name, ptr);
2167 ptr[0] = ptr[1] = '#';
2168 ptr += 2;
2170 else
2172 result = XNEWVEC (char, strlen (src_name) + 10);
2173 ptr = result;
2176 ptr = mangle_name (src_name, ptr);
2177 strcpy (ptr, ".gcov");
2179 /* When hashing filenames, we shorten them by only using the filename
2180 component and appending a hash of the full (mangled) pathname. */
2181 if (flag_hash_filenames)
2183 md5_ctx ctx;
2184 char md5sum[16];
2185 char md5sum_hex[33];
2187 md5_init_ctx (&ctx);
2188 md5_process_bytes (src_name, strlen (src_name), &ctx);
2189 md5_finish_ctx (&ctx, md5sum);
2190 md5sum_to_hex (md5sum, md5sum_hex);
2191 free (result);
2193 result = XNEWVEC (char, strlen (src_name) + 50);
2194 ptr = result;
2195 ptr = mangle_name (src_name, ptr);
2196 ptr[0] = ptr[1] = '#';
2197 ptr += 2;
2198 memcpy (ptr, md5sum_hex, 32);
2199 ptr += 32;
2200 strcpy (ptr, ".gcov");
2203 return result;
2206 static char *
2207 mangle_name (char const *base, char *ptr)
2209 size_t len;
2211 /* Generate the source filename part. */
2212 if (!flag_preserve_paths)
2214 base = lbasename (base);
2215 len = strlen (base);
2216 memcpy (ptr, base, len);
2217 ptr += len;
2219 else
2221 /* Convert '/' to '#', convert '..' to '^',
2222 convert ':' to '~' on DOS based file system. */
2223 const char *probe;
2225 #if HAVE_DOS_BASED_FILE_SYSTEM
2226 if (base[0] && base[1] == ':')
2228 ptr[0] = base[0];
2229 ptr[1] = '~';
2230 ptr += 2;
2231 base += 2;
2233 #endif
2234 for (; *base; base = probe)
2236 size_t len;
2238 for (probe = base; *probe; probe++)
2239 if (*probe == '/')
2240 break;
2241 len = probe - base;
2242 if (len == 2 && base[0] == '.' && base[1] == '.')
2243 *ptr++ = '^';
2244 else
2246 memcpy (ptr, base, len);
2247 ptr += len;
2249 if (*probe)
2251 *ptr++ = '#';
2252 probe++;
2257 return ptr;
2260 /* Scan through the bb_data for each line in the block, increment
2261 the line number execution count indicated by the execution count of
2262 the appropriate basic block. */
2264 static void
2265 add_line_counts (coverage_t *coverage, function_t *fn)
2267 bool has_any_line = false;
2268 /* Scan each basic block. */
2269 for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
2271 line_t *line = NULL;
2272 block_t *block = &fn->blocks[ix];
2273 if (block->count && ix && ix + 1 != fn->blocks.size ())
2274 fn->blocks_executed++;
2275 for (unsigned i = 0; i < block->locations.size (); i++)
2277 const source_t *src = &sources[block->locations[i].source_file_idx];
2279 vector<unsigned> &lines = block->locations[i].lines;
2280 for (unsigned j = 0; j < lines.size (); j++)
2282 line = &src->lines[lines[j]];
2283 if (coverage)
2285 if (!line->exists)
2286 coverage->lines++;
2287 if (!line->count && block->count)
2288 coverage->lines_executed++;
2290 line->exists = 1;
2291 if (!block->exceptional)
2292 line->unexceptional = 1;
2293 line->count += block->count;
2296 block->cycle.arc = NULL;
2297 block->cycle.ident = ~0U;
2298 has_any_line = true;
2300 if (!ix || ix + 1 == fn->blocks.size ())
2301 /* Entry or exit block */;
2302 else if (line != NULL)
2304 block->chain = line->blocks;
2305 line->blocks = block;
2307 if (flag_branches)
2309 arc_t *arc;
2311 for (arc = block->succ; arc; arc = arc->succ_next)
2313 arc->line_next = line->branches;
2314 line->branches = arc;
2315 if (coverage && !arc->is_unconditional)
2316 add_branch_counts (coverage, arc);
2322 if (!has_any_line)
2323 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
2326 /* Accumulate the line counts of a file. */
2328 static void
2329 accumulate_line_counts (source_t *src)
2331 line_t *line;
2332 function_t *fn, *fn_p, *fn_n;
2333 unsigned ix;
2335 /* Reverse the function order. */
2336 for (fn = src->functions, fn_p = NULL; fn; fn_p = fn, fn = fn_n)
2338 fn_n = fn->next_file_fn;
2339 fn->next_file_fn = fn_p;
2341 src->functions = fn_p;
2343 for (ix = src->num_lines, line = src->lines; ix--; line++)
2345 if (line->blocks)
2347 /* The user expects the line count to be the number of times
2348 a line has been executed. Simply summing the block count
2349 will give an artificially high number. The Right Thing
2350 is to sum the entry counts to the graph of blocks on this
2351 line, then find the elementary cycles of the local graph
2352 and add the transition counts of those cycles. */
2353 block_t *block, *block_p, *block_n;
2354 gcov_type count = 0;
2356 /* Reverse the block information. */
2357 for (block = line->blocks, block_p = NULL; block;
2358 block_p = block, block = block_n)
2360 block_n = block->chain;
2361 block->chain = block_p;
2362 block->cycle.ident = ix;
2364 line->blocks = block_p;
2366 /* Sum the entry arcs. */
2367 for (block = line->blocks; block; block = block->chain)
2369 arc_t *arc;
2371 for (arc = block->pred; arc; arc = arc->pred_next)
2372 if (flag_branches)
2373 add_branch_counts (&src->coverage, arc);
2376 /* Cycle detection. */
2377 for (block = line->blocks; block; block = block->chain)
2379 for (arc_t *arc = block->pred; arc; arc = arc->pred_next)
2380 if (!line->has_block (arc->src))
2381 count += arc->count;
2382 for (arc_t *arc = block->succ; arc; arc = arc->succ_next)
2383 arc->cs_count = arc->count;
2386 /* Now, add the count of loops entirely on this line. */
2387 count += get_cycles_count (*line);
2388 line->count = count;
2391 if (line->exists)
2393 src->coverage.lines++;
2394 if (line->count)
2395 src->coverage.lines_executed++;
2400 /* Output information about ARC number IX. Returns nonzero if
2401 anything is output. */
2403 static int
2404 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
2406 if (arc->is_call_non_return)
2408 if (arc->src->count)
2410 fnotice (gcov_file, "call %2d returned %s\n", ix,
2411 format_gcov (arc->src->count - arc->count,
2412 arc->src->count, -flag_counts));
2414 else
2415 fnotice (gcov_file, "call %2d never executed\n", ix);
2417 else if (!arc->is_unconditional)
2419 if (arc->src->count)
2420 fnotice (gcov_file, "branch %2d taken %s%s", ix,
2421 format_gcov (arc->count, arc->src->count, -flag_counts),
2422 arc->fall_through ? " (fallthrough)"
2423 : arc->is_throw ? " (throw)" : "");
2424 else
2425 fnotice (gcov_file, "branch %2d never executed", ix);
2427 if (flag_verbose)
2428 fnotice (gcov_file, " (BB %d)", arc->dst->id);
2430 fnotice (gcov_file, "\n");
2432 else if (flag_unconditional && !arc->dst->is_call_return)
2434 if (arc->src->count)
2435 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
2436 format_gcov (arc->count, arc->src->count, -flag_counts));
2437 else
2438 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
2440 else
2441 return 0;
2442 return 1;
2445 static const char *
2446 read_line (FILE *file)
2448 static char *string;
2449 static size_t string_len;
2450 size_t pos = 0;
2451 char *ptr;
2453 if (!string_len)
2455 string_len = 200;
2456 string = XNEWVEC (char, string_len);
2459 while ((ptr = fgets (string + pos, string_len - pos, file)))
2461 size_t len = strlen (string + pos);
2463 if (len && string[pos + len - 1] == '\n')
2465 string[pos + len - 1] = 0;
2466 return string;
2468 pos += len;
2469 /* If the file contains NUL characters or an incomplete
2470 last line, which can happen more than once in one run,
2471 we have to avoid doubling the STRING_LEN unnecessarily. */
2472 if (pos > string_len / 2)
2474 string_len *= 2;
2475 string = XRESIZEVEC (char, string, string_len);
2479 return pos ? string : NULL;
2482 /* Pad string S with spaces from left to have total width equal to 9. */
2484 static void
2485 pad_count_string (string &s)
2487 if (s.size () < 9)
2488 s.insert (0, 9 - s.size (), ' ');
2491 /* Print GCOV line beginning to F stream. If EXISTS is set to true, the
2492 line exists in source file. UNEXCEPTIONAL indicated that it's not in
2493 an exceptional statement. The output is printed for LINE_NUM of given
2494 COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
2495 used to indicate non-executed blocks. */
2497 static void
2498 output_line_beginning (FILE *f, bool exists, bool unexceptional,
2499 gcov_type count, unsigned line_num,
2500 const char *exceptional_string,
2501 const char *unexceptional_string)
2503 string s;
2504 if (exists)
2506 if (count > 0)
2508 s = format_gcov (count, 0, -1);
2509 pad_count_string (s);
2511 else
2513 if (flag_use_colors)
2515 s = "0";
2516 pad_count_string (s);
2517 if (unexceptional)
2518 s.insert (0, SGR_SEQ (COLOR_BG_RED
2519 COLOR_SEPARATOR COLOR_FG_WHITE));
2520 else
2521 s.insert (0, SGR_SEQ (COLOR_BG_CYAN
2522 COLOR_SEPARATOR COLOR_FG_WHITE));
2523 s += SGR_RESET;
2525 else
2527 s = unexceptional ? unexceptional_string : exceptional_string;
2528 pad_count_string (s);
2532 else
2534 s = "-";
2535 pad_count_string (s);
2538 fprintf (f, "%s:%5u", s.c_str (), line_num);
2541 /* Read in the source file one line at a time, and output that line to
2542 the gcov file preceded by its execution count and other
2543 information. */
2545 static void
2546 output_lines (FILE *gcov_file, const source_t *src)
2548 #define DEFAULT_LINE_START " -: 0:"
2550 FILE *source_file;
2551 unsigned line_num; /* current line number. */
2552 const line_t *line; /* current line info ptr. */
2553 const char *retval = ""; /* status of source file reading. */
2554 function_t *fn = NULL;
2556 fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
2557 if (!multiple_files)
2559 fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
2560 fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
2561 no_data_file ? "-" : da_file_name);
2562 fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
2564 fprintf (gcov_file, DEFAULT_LINE_START "Programs:%u\n", program_count);
2566 source_file = fopen (src->name, "r");
2567 if (!source_file)
2569 fnotice (stderr, "Cannot open source file %s\n", src->name);
2570 retval = NULL;
2572 else if (src->file_time == 0)
2573 fprintf (gcov_file, DEFAULT_LINE_START "Source is newer than graph\n");
2575 if (flag_branches)
2576 fn = src->functions;
2578 for (line_num = 1, line = &src->lines[line_num];
2579 line_num < src->num_lines; line_num++, line++)
2581 for (; fn && fn->line == line_num; fn = fn->next_file_fn)
2583 arc_t *arc = fn->blocks[EXIT_BLOCK].pred;
2584 gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
2585 gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
2587 for (; arc; arc = arc->pred_next)
2588 if (arc->fake)
2589 return_count -= arc->count;
2591 fprintf (gcov_file, "function %s", flag_demangled_names ?
2592 fn->demangled_name : fn->name);
2593 fprintf (gcov_file, " called %s",
2594 format_gcov (called_count, 0, -1));
2595 fprintf (gcov_file, " returned %s",
2596 format_gcov (return_count, called_count, 0));
2597 fprintf (gcov_file, " blocks executed %s",
2598 format_gcov (fn->blocks_executed, fn->blocks.size () - 2,
2599 0));
2600 fprintf (gcov_file, "\n");
2603 if (retval)
2604 retval = read_line (source_file);
2606 /* For lines which don't exist in the .bb file, print '-' before
2607 the source line. For lines which exist but were never
2608 executed, print '#####' or '=====' before the source line.
2609 Otherwise, print the execution count before the source line.
2610 There are 16 spaces of indentation added before the source
2611 line so that tabs won't be messed up. */
2612 output_line_beginning (gcov_file, line->exists, line->unexceptional,
2613 line->count, line_num,
2614 "=====", "#####");
2615 fprintf (gcov_file, ":%s\n", retval ? retval : "/*EOF*/");
2617 if (flag_all_blocks)
2619 block_t *block;
2620 arc_t *arc;
2621 int ix, jx;
2623 for (ix = jx = 0, block = line->blocks; block;
2624 block = block->chain)
2626 if (!block->is_call_return)
2628 output_line_beginning (gcov_file, line->exists,
2629 block->exceptional,
2630 block->count, line_num,
2631 "%%%%%", "$$$$$");
2632 fprintf (gcov_file, "-block %2d", ix++);
2633 if (flag_verbose)
2634 fprintf (gcov_file, " (BB %u)", block->id);
2635 fprintf (gcov_file, "\n");
2637 if (flag_branches)
2638 for (arc = block->succ; arc; arc = arc->succ_next)
2639 jx += output_branch_count (gcov_file, jx, arc);
2642 else if (flag_branches)
2644 int ix;
2645 arc_t *arc;
2647 for (ix = 0, arc = line->branches; arc; arc = arc->line_next)
2648 ix += output_branch_count (gcov_file, ix, arc);
2652 /* Handle all remaining source lines. There may be lines after the
2653 last line of code. */
2654 if (retval)
2656 for (; (retval = read_line (source_file)); line_num++)
2657 fprintf (gcov_file, "%9s:%5u:%s\n", "-", line_num, retval);
2660 if (source_file)
2661 fclose (source_file);