Daily bump.
[official-gcc.git] / gcc / gcov.cc
blobfd4a5cd331ddd4bb2dbd99c40d0494deed172751
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>
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 #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"
51 #include <zlib.h>
52 #include <getopt.h>
54 #include "md5.h"
56 using namespace std;
58 #define IN_GCOV 1
59 #include "gcov-io.h"
60 #include "gcov-io.cc"
62 #define GCOV_JSON_FORMAT_VERSION "2"
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. */
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. */
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. */
80 /* This is the size of the buffer used to read in source file lines. */
82 class function_info;
83 class block_info;
84 class source_info;
85 class condition_info;
87 /* Describes an arc between two basic blocks. */
89 struct arc_info
91 /* source and destination blocks. */
92 class block_info *src;
93 class block_info *dst;
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;
100 unsigned int count_valid : 1;
101 unsigned int on_tree : 1;
102 unsigned int fake : 1;
103 unsigned int fall_through : 1;
105 /* Arc to a catch handler. */
106 unsigned int is_throw : 1;
108 /* Arc is for a function that abnormally returns. */
109 unsigned int is_call_non_return : 1;
111 /* Arc is for catch/setjmp. */
112 unsigned int is_nonlocal_return : 1;
114 /* Is an unconditional branch. */
115 unsigned int is_unconditional : 1;
117 /* Loop making arc. */
118 unsigned int cycle : 1;
120 /* Links to next arc on src and dst lists. */
121 struct arc_info *succ_next;
122 struct arc_info *pred_next;
125 /* Describes which locations (lines and files) are associated with
126 a basic block. */
128 class block_location_info
130 public:
131 block_location_info (unsigned _source_file_idx):
132 source_file_idx (_source_file_idx)
135 unsigned source_file_idx;
136 vector<unsigned> lines;
139 /* Describes a single conditional expression and the (recorded) conditions
140 shown to independently affect the outcome. */
141 class condition_info
143 public:
144 condition_info ();
146 int popcount () const;
148 /* Bitsets storing the independently significant outcomes for true and false,
149 respectively. */
150 gcov_type_unsigned truev;
151 gcov_type_unsigned falsev;
153 /* Number of terms in the expression; if (x) -> 1, if (x && y) -> 2 etc. */
154 unsigned n_terms;
157 condition_info::condition_info (): truev (0), falsev (0), n_terms (0)
161 int condition_info::popcount () const
163 return popcount_hwi (truev) + popcount_hwi (falsev);
166 /* Describes a basic block. Contains lists of arcs to successor and
167 predecessor blocks. */
169 class block_info
171 public:
172 /* Constructor. */
173 block_info ();
175 /* Chain of exit and entry arcs. */
176 arc_info *succ;
177 arc_info *pred;
179 /* Number of unprocessed exit and entry arcs. */
180 gcov_type num_succ;
181 gcov_type num_pred;
183 unsigned id;
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;
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. */
196 /* Block is a landing pad for longjmp or throw. */
197 unsigned is_nonlocal_return : 1;
199 condition_info conditions;
201 vector<block_location_info> locations;
203 struct
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. */
212 /* Temporary chain for solving graph, and for chaining blocks on one
213 line. */
214 class block_info *chain;
218 block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0),
219 id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
220 exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
221 locations (), chain (NULL)
223 cycle.arc = NULL;
226 /* Describes a single line of source. Contains a chain of basic blocks
227 with code on it. */
229 class line_info
231 public:
232 /* Default constructor. */
233 line_info ();
235 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
236 bool has_block (block_info *needle);
238 /* Execution count. */
239 gcov_type count;
241 /* Branches from blocks that end on this line. */
242 vector<arc_info *> branches;
244 /* blocks which start on this line. Used in all-blocks mode. */
245 vector<block_info *> blocks;
247 unsigned exists : 1;
248 unsigned unexceptional : 1;
249 unsigned has_unexecuted_block : 1;
252 line_info::line_info (): count (0), branches (), blocks (), exists (false),
253 unexceptional (0), has_unexecuted_block (0)
257 bool
258 line_info::has_block (block_info *needle)
260 return std::find (blocks.begin (), blocks.end (), needle) != blocks.end ();
263 /* Output demangled function names. */
265 static int flag_demangled_names = 0;
267 /* Describes a single function. Contains an array of basic blocks. */
269 class function_info
271 public:
272 function_info ();
273 ~function_info ();
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);
279 /* Function filter based on function_info::artificial variable. */
281 static inline bool
282 is_artificial (function_info *fn)
284 return fn->artificial;
287 /* Name of function. */
288 char *m_name;
289 char *m_demangled_name;
290 unsigned ident;
291 unsigned lineno_checksum;
292 unsigned cfg_checksum;
294 /* The graph contains at least one fake incoming edge. */
295 unsigned has_catch : 1;
297 /* True when the function is artificial and does not exist
298 in a source file. */
299 unsigned artificial : 1;
301 /* True when multiple functions start at a line in a source file. */
302 unsigned is_group : 1;
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;
311 vector<condition_info*> conditions;
313 /* Raw arc coverage counts. */
314 vector<gcov_type> counts;
316 /* First line number. */
317 unsigned start_line;
319 /* First line column. */
320 unsigned start_column;
322 /* Last line number. */
323 unsigned end_line;
325 /* Last line column. */
326 unsigned end_column;
328 /* Index of source file where the function is defined. */
329 unsigned src;
331 /* Vector of line information (used only for group functions). */
332 vector<line_info> lines;
334 /* Next function. */
335 class function_info *next;
337 /* Get demangled name of a function. The demangled name
338 is converted when it is used for the first time. */
339 char *get_demangled_name ()
341 if (m_demangled_name == NULL)
343 m_demangled_name = cplus_demangle (m_name, DMGL_PARAMS);
344 if (!m_demangled_name)
345 m_demangled_name = m_name;
348 return m_demangled_name;
351 /* Get name of the function based on flag_demangled_names. */
352 char *get_name ()
354 return flag_demangled_names ? get_demangled_name () : m_name;
357 /* Return number of basic blocks (without entry and exit block). */
358 unsigned get_block_count ()
360 return blocks.size () - 2;
364 /* Function info comparer that will sort functions according to starting
365 line. */
367 struct function_line_start_cmp
369 inline bool operator() (const function_info *lhs,
370 const function_info *rhs)
372 return (lhs->start_line == rhs->start_line
373 ? lhs->start_column < rhs->start_column
374 : lhs->start_line < rhs->start_line);
378 /* Describes coverage of a file or function. */
380 struct coverage_info
382 int lines;
383 int lines_executed;
385 int branches;
386 int branches_executed;
387 int branches_taken;
389 int conditions;
390 int conditions_covered;
392 int calls;
393 int calls_executed;
395 char *name;
398 /* Describes a file mentioned in the block graph. Contains an array
399 of line info. */
401 class source_info
403 public:
404 /* Default constructor. */
405 source_info ();
407 vector<function_info *> *get_functions_at_location (unsigned line_num) const;
409 /* Register a new function. */
410 void add_function (function_info *fn);
412 /* Debug the source file. */
413 void debug ();
415 /* Index of the source_info in sources vector. */
416 unsigned index;
418 /* Canonical name of source file. */
419 char *name;
420 time_t file_time;
422 /* Vector of line information. */
423 vector<line_info> lines;
425 coverage_info coverage;
427 /* Maximum line count in the source file. */
428 unsigned int maximum_count;
430 /* Functions in this source file. These are in ascending line
431 number order. */
432 vector<function_info *> functions;
434 /* Line number to functions map. */
435 vector<vector<function_info *> *> line_to_function_map;
438 source_info::source_info (): index (0), name (NULL), file_time (),
439 lines (), coverage (), maximum_count (0), functions ()
443 /* Register a new function. */
444 void
445 source_info::add_function (function_info *fn)
447 functions.push_back (fn);
449 if (fn->start_line >= line_to_function_map.size ())
450 line_to_function_map.resize (fn->start_line + 1);
452 vector<function_info *> **slot = &line_to_function_map[fn->start_line];
453 if (*slot == NULL)
454 *slot = new vector<function_info *> ();
456 (*slot)->push_back (fn);
459 vector<function_info *> *
460 source_info::get_functions_at_location (unsigned line_num) const
462 if (line_num >= line_to_function_map.size ())
463 return NULL;
465 vector<function_info *> *slot = line_to_function_map[line_num];
466 if (slot != NULL)
467 std::sort (slot->begin (), slot->end (), function_line_start_cmp ());
469 return slot;
472 void source_info::debug ()
474 fprintf (stderr, "source_info: %s\n", name);
475 for (vector<function_info *>::iterator it = functions.begin ();
476 it != functions.end (); it++)
478 function_info *fn = *it;
479 fprintf (stderr, " function_info: %s\n", fn->get_name ());
480 for (vector<block_info>::iterator bit = fn->blocks.begin ();
481 bit != fn->blocks.end (); bit++)
483 fprintf (stderr, " block_info id=%d, count=%" PRId64 " \n",
484 bit->id, bit->count);
488 for (unsigned lineno = 1; lineno < lines.size (); ++lineno)
490 line_info &line = lines[lineno];
491 fprintf (stderr, " line_info=%d, count=%" PRId64 "\n", lineno, line.count);
494 fprintf (stderr, "\n");
497 class name_map
499 public:
500 name_map ()
504 name_map (char *_name, unsigned _src): name (_name), src (_src)
508 bool operator== (const name_map &rhs) const
510 #if HAVE_DOS_BASED_FILE_SYSTEM
511 return strcasecmp (this->name, rhs.name) == 0;
512 #else
513 return strcmp (this->name, rhs.name) == 0;
514 #endif
517 bool operator< (const name_map &rhs) const
519 #if HAVE_DOS_BASED_FILE_SYSTEM
520 return strcasecmp (this->name, rhs.name) < 0;
521 #else
522 return strcmp (this->name, rhs.name) < 0;
523 #endif
526 const char *name; /* Source file name */
527 unsigned src; /* Source file */
530 /* Vector of all functions. */
531 static vector<function_info *> functions;
533 /* Function ident to function_info * map. */
534 static map<unsigned, function_info *> ident_to_fn;
536 /* Vector of source files. */
537 static vector<source_info> sources;
539 /* Mapping of file names to sources */
540 static vector<name_map> names;
542 /* Record all processed files in order to warn about
543 a file being read multiple times. */
544 static vector<char *> processed_files;
546 /* This holds data summary information. */
548 static unsigned object_runs;
550 static unsigned total_lines;
551 static unsigned total_executed;
553 /* Modification time of graph file. */
555 static time_t bbg_file_time;
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. */
561 static char *bbg_file_name;
563 /* Stamp of the bbg file */
564 static unsigned bbg_stamp;
566 /* Supports has_unexecuted_blocks functionality. */
567 static unsigned bbg_supports_has_unexecuted_blocks;
569 /* Working directory in which a TU was compiled. */
570 static const char *bbg_cwd;
572 /* Name and file pointer of the input file for the count data (gcda). */
574 static char *da_file_name;
576 /* Data file is missing. */
578 static int no_data_file;
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. */
585 static int multiple_files = 0;
587 /* Output branch probabilities. */
589 static int flag_branches = 0;
591 /* Output conditions (modified condition/decision coverage). */
593 static bool flag_conditions = 0;
595 /* Show unconditional branches too. */
596 static int flag_unconditional = 0;
598 /* Output a gcov file if this is true. This is on by default, and can
599 be turned off by the -n option. */
601 static int flag_gcov_file = 1;
603 /* Output to stdout instead to a gcov file. */
605 static int flag_use_stdout = 0;
607 /* Output progress indication if this is true. This is off by default
608 and can be turned on by the -d option. */
610 static int flag_display_progress = 0;
612 /* Output *.gcov file in JSON intermediate format used by consumers. */
614 static int flag_json_format = 0;
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. */
620 static int flag_long_names = 0;
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. */
625 static int flag_hash_filenames = 0;
627 /* Print verbose informations. */
629 static int flag_verbose = 0;
631 /* Print colored output. */
633 static int flag_use_colors = 0;
635 /* Use perf-like colors to indicate hot lines. */
637 static int flag_use_hotness_colors = 0;
639 /* Output count information for every basic block, not merely those
640 that contain line number information. */
642 static int flag_all_blocks = 0;
644 /* Output human readable numbers. */
646 static int flag_human_readable_numbers = 0;
648 /* Output summary info for each function. */
650 static int flag_function_summary = 0;
652 /* Print debugging dumps. */
654 static int flag_debug = 0;
656 /* Object directory file prefix. This is the directory/file where the
657 graph and data files are looked for, if nonzero. */
659 static char *object_directory = 0;
661 /* Source directory prefix. This is removed from source pathnames
662 that match, when generating the output file name. */
664 static char *source_prefix = 0;
665 static size_t source_length = 0;
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;
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 '^'. */
676 static int flag_preserve_paths = 0;
678 /* Output the number of times a branch was taken as opposed to the percentage
679 of times it was taken. */
681 static int flag_counts = 0;
683 /* Return code of the tool invocation. */
684 static int return_code = 0;
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 **);
717 function_info::function_info (): m_name (NULL), m_demangled_name (NULL),
718 ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
719 artificial (0), is_group (0),
720 blocks (), blocks_executed (0), counts (),
721 start_line (0), start_column (0), end_line (0), end_column (0),
722 src (0), lines (), next (NULL)
726 function_info::~function_info ()
728 for (int i = blocks.size () - 1; i >= 0; i--)
730 arc_info *arc, *arc_n;
732 for (arc = blocks[i].succ; arc; arc = arc_n)
734 arc_n = arc->succ_next;
735 free (arc);
738 if (m_demangled_name != m_name)
739 free (m_demangled_name);
740 free (m_name);
743 bool function_info::group_line_p (unsigned n, unsigned src_idx)
745 return is_group && src == src_idx && start_line <= n && n <= end_line;
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>).
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.
760 typedef vector<arc_info *> arc_vector_t;
761 typedef vector<const block_info *> block_vector_t;
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. */
767 static void
768 handle_cycle (const arc_vector_t &edges, int64_t &count)
770 /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
771 that amount. */
772 int64_t cycle_count = INTTYPE_MAXIMUM (int64_t);
773 for (unsigned i = 0; i < edges.size (); i++)
775 int64_t ecount = edges[i]->cs_count;
776 if (cycle_count > ecount)
777 cycle_count = ecount;
779 count += cycle_count;
780 for (unsigned i = 0; i < edges.size (); i++)
781 edges[i]->cs_count -= cycle_count;
783 gcc_assert (cycle_count > 0);
786 /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
787 blocked by U in BLOCK_LISTS. */
789 static void
790 unblock (const block_info *u, block_vector_t &blocked,
791 vector<block_vector_t > &block_lists)
793 block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u);
794 if (it == blocked.end ())
795 return;
797 unsigned index = it - blocked.begin ();
798 blocked.erase (it);
800 block_vector_t to_unblock (block_lists[index]);
802 block_lists.erase (block_lists.begin () + index);
804 for (block_vector_t::iterator it = to_unblock.begin ();
805 it != to_unblock.end (); it++)
806 unblock (*it, blocked, block_lists);
809 /* Return true when PATH contains a zero cycle arc count. */
811 static bool
812 path_contains_zero_or_negative_cycle_arc (arc_vector_t &path)
814 for (unsigned i = 0; i < path.size (); i++)
815 if (path[i]->cs_count <= 0)
816 return true;
817 return false;
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. */
825 static bool
826 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)
830 bool loop_found = false;
832 /* Add v to the block list. */
833 gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
834 blocked.push_back (v);
835 block_lists.push_back (block_vector_t ());
837 for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
839 block_info *w = arc->dst;
840 if (w < start
841 || arc->cs_count <= 0
842 || !linfo.has_block (w))
843 continue;
845 path.push_back (arc);
846 if (w == start)
848 /* Cycle has been found. */
849 handle_cycle (path, count);
850 loop_found = true;
852 else if (!path_contains_zero_or_negative_cycle_arc (path)
853 && find (blocked.begin (), blocked.end (), w) == blocked.end ())
854 loop_found |= circuit (w, path, start, blocked, block_lists, linfo,
855 count);
857 path.pop_back ();
860 if (loop_found)
861 unblock (v, blocked, block_lists);
862 else
863 for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
865 block_info *w = arc->dst;
866 if (w < start
867 || arc->cs_count <= 0
868 || !linfo.has_block (w))
869 continue;
871 size_t index
872 = find (blocked.begin (), blocked.end (), w) - blocked.begin ();
873 gcc_assert (index < blocked.size ());
874 block_vector_t &list = block_lists[index];
875 if (find (list.begin (), list.end (), v) == list.end ())
876 list.push_back (v);
879 return loop_found;
882 /* Find cycles for a LINFO. */
884 static gcov_type
885 get_cycles_count (line_info &linfo)
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. */
893 gcov_type count = 0;
894 for (vector<block_info *>::iterator it = linfo.blocks.begin ();
895 it != linfo.blocks.end (); it++)
897 arc_vector_t path;
898 block_vector_t blocked;
899 vector<block_vector_t > block_lists;
900 circuit (*it, path, *it, blocked, block_lists, linfo, count);
903 return count;
907 main (int argc, char **argv)
909 int argno;
910 int first_arg;
911 const char *p;
913 p = argv[0] + strlen (argv[0]);
914 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
915 --p;
916 progname = p;
918 xmalloc_set_program_name (progname);
920 /* Unlock the stdio streams. */
921 unlock_std_streams ();
923 gcc_init_libintl ();
925 diagnostic_initialize (global_dc, 0);
927 /* Handle response files. */
928 expandargv (&argc, &argv);
930 argno = process_args (argc, argv);
931 if (optind == argc)
932 print_usage (true);
934 if (argc - argno > 1)
935 multiple_files = 1;
937 first_arg = argno;
939 for (; argno != argc; argno++)
941 if (flag_display_progress)
942 printf ("Processing file %d out of %d\n", argno - first_arg + 1,
943 argc - first_arg);
944 process_file (argv[argno]);
946 if (flag_json_format || argno == argc - 1)
948 process_all_functions ();
949 generate_results (argv[argno]);
950 release_structures ();
954 if (!flag_use_stdout)
955 executed_summary (total_lines, total_executed);
957 return return_code;
960 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
961 otherwise the output of --help. */
963 static void
964 print_usage (int error_p)
966 FILE *file = error_p ? stderr : stdout;
967 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
969 fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
970 fnotice (file, "Print code coverage information.\n\n");
971 fnotice (file, " -a, --all-blocks Show information for every basic block\n");
972 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
973 fnotice (file, " -c, --branch-counts Output counts of branches taken\n\
974 rather than percentages\n");
975 fnotice (file, " -g, --conditions Include modified condition/decision\n\
976 coverage in output\n");
977 fnotice (file, " -d, --display-progress Display progress information\n");
978 fnotice (file, " -D, --debug Display debugging dumps\n");
979 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
980 fnotice (file, " -h, --help Print this help, then exit\n");
981 fnotice (file, " -j, --json-format Output JSON intermediate format\n\
982 into .gcov.json.gz file\n");
983 fnotice (file, " -H, --human-readable Output human readable numbers\n");
984 fnotice (file, " -k, --use-colors Emit colored output\n");
985 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
986 source files\n");
987 fnotice (file, " -m, --demangled-names Output demangled function names\n");
988 fnotice (file, " -n, --no-output Do not create an output file\n");
989 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
990 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
991 fnotice (file, " -q, --use-hotness-colors Emit perf-like colored output for hot lines\n");
992 fnotice (file, " -r, --relative-only Only show data for relative sources\n");
993 fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n");
994 fnotice (file, " -t, --stdout Output to stdout instead of a file\n");
995 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
996 fnotice (file, " -v, --version Print version number, then exit\n");
997 fnotice (file, " -w, --verbose Print verbose informations\n");
998 fnotice (file, " -x, --hash-filenames Hash long pathnames\n");
999 fnotice (file, "\nObsolete options:\n");
1000 fnotice (file, " -i, --json-format Replaced with -j, --json-format\n");
1001 fnotice (file, " -j, --human-readable Replaced with -H, --human-readable\n");
1002 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
1003 bug_report_url);
1004 exit (status);
1007 /* Print version information and exit. */
1009 static void
1010 print_version (void)
1012 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
1013 fnotice (stdout, "JSON format version: %s\n", GCOV_JSON_FORMAT_VERSION);
1014 fprintf (stdout, "Copyright %s 2024 Free Software Foundation, Inc.\n",
1015 _("(C)"));
1016 fnotice (stdout,
1017 _("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 exit (SUCCESS_EXIT_CODE);
1022 static const struct option options[] =
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 }
1052 /* Process args, return index to first non-arg. */
1054 static int
1055 process_args (int argc, char **argv)
1057 int opt;
1059 const char *opts = "abcdDfghHijklmno:pqrs:tuvwx";
1060 while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
1062 switch (opt)
1064 case 'a':
1065 flag_all_blocks = 1;
1066 break;
1067 case 'b':
1068 flag_branches = 1;
1069 break;
1070 case 'c':
1071 flag_counts = 1;
1072 break;
1073 case 'f':
1074 flag_function_summary = 1;
1075 break;
1076 case 'g':
1077 flag_conditions = 1;
1078 break;
1079 case 'h':
1080 print_usage (false);
1081 /* print_usage will exit. */
1082 case 'l':
1083 flag_long_names = 1;
1084 break;
1085 case 'H':
1086 flag_human_readable_numbers = 1;
1087 break;
1088 case 'k':
1089 flag_use_colors = 1;
1090 break;
1091 case 'q':
1092 flag_use_hotness_colors = 1;
1093 break;
1094 case 'm':
1095 flag_demangled_names = 1;
1096 break;
1097 case 'n':
1098 flag_gcov_file = 0;
1099 break;
1100 case 'o':
1101 object_directory = optarg;
1102 break;
1103 case 's':
1104 source_prefix = optarg;
1105 source_length = strlen (source_prefix);
1106 break;
1107 case 'r':
1108 flag_relative_only = 1;
1109 break;
1110 case 'p':
1111 flag_preserve_paths = 1;
1112 break;
1113 case 'u':
1114 flag_unconditional = 1;
1115 break;
1116 case 'i':
1117 case 'j':
1118 flag_json_format = 1;
1119 flag_gcov_file = 1;
1120 break;
1121 case 'd':
1122 flag_display_progress = 1;
1123 break;
1124 case 'x':
1125 flag_hash_filenames = 1;
1126 break;
1127 case 'w':
1128 flag_verbose = 1;
1129 break;
1130 case 't':
1131 flag_use_stdout = 1;
1132 break;
1133 case 'D':
1134 flag_debug = 1;
1135 break;
1136 case 'v':
1137 print_version ();
1138 /* print_version will exit. */
1139 default:
1140 print_usage (true);
1141 /* print_usage will exit. */
1145 return optind;
1148 /* Output intermediate LINE sitting on LINE_NUM to JSON OBJECT.
1149 Add FUNCTION_NAME to the LINE. */
1151 static void
1152 output_intermediate_json_line (json::array *object,
1153 line_info *line, unsigned line_num,
1154 const char *function_name)
1156 if (!line->exists)
1157 return;
1159 json::object *lineo = new json::object ();
1160 lineo->set_integer ("line_number", line_num);
1161 if (function_name != NULL)
1162 lineo->set_string ("function_name", function_name);
1163 lineo->set_integer ("count", line->count);
1164 lineo->set_bool ("unexecuted_block", line->has_unexecuted_block);
1166 json::array *bb_ids = new json::array ();
1167 for (const block_info *block : line->blocks)
1168 bb_ids->append (new json::integer_number (block->id));
1169 lineo->set ("block_ids", bb_ids);
1171 json::array *branches = new json::array ();
1172 lineo->set ("branches", branches);
1174 json::array *calls = new json::array ();
1175 lineo->set ("calls", calls);
1177 vector<arc_info *>::const_iterator it;
1178 if (flag_branches)
1179 for (it = line->branches.begin (); it != line->branches.end ();
1180 it++)
1182 if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
1184 json::object *branch = new json::object ();
1185 branch->set_integer ("count", (*it)->count);
1186 branch->set_bool ("throw", (*it)->is_throw);
1187 branch->set_bool ("fallthrough", (*it)->fall_through);
1188 branch->set_integer ("source_block_id", (*it)->src->id);
1189 branch->set_integer ("destination_block_id", (*it)->dst->id);
1190 branches->append (branch);
1192 else if ((*it)->is_call_non_return)
1194 json::object *call = new json::object ();
1195 gcov_type returns = (*it)->src->count - (*it)->count;
1196 call->set_integer ("source_block_id", (*it)->src->id);
1197 call->set_integer ("destination_block_id", (*it)->dst->id);
1198 call->set_integer ("returned", returns);
1199 calls->append (call);
1203 json::array *conditions = new json::array ();
1204 lineo->set ("conditions", conditions);
1205 if (flag_conditions)
1207 vector<block_info *>::const_iterator it;
1208 for (it = line->blocks.begin (); it != line->blocks.end (); it++)
1210 const condition_info& info = (*it)->conditions;
1211 if (info.n_terms == 0)
1212 continue;
1214 const int count = 2 * info.n_terms;
1215 const int covered = info.popcount ();
1217 json::object *cond = new json::object ();
1218 cond->set ("count", new json::integer_number (count));
1219 cond->set ("covered", new json::integer_number (covered));
1221 json::array *mtrue = new json::array ();
1222 json::array *mfalse = new json::array ();
1223 cond->set ("not_covered_true", mtrue);
1224 cond->set ("not_covered_false", mfalse);
1226 if (count != covered)
1228 for (unsigned i = 0; i < info.n_terms; i++)
1230 gcov_type_unsigned index = 1;
1231 index <<= i;
1232 if (!(index & info.truev))
1233 mtrue->append (new json::integer_number (i));
1234 if (!(index & info.falsev))
1235 mfalse->append (new json::integer_number (i));
1238 conditions->append (cond);
1242 object->append (lineo);
1245 /* Strip filename extension in STR. */
1247 static string
1248 strip_extention (string str)
1250 string::size_type pos = str.rfind ('.');
1251 if (pos != string::npos)
1252 str = str.substr (0, pos);
1254 return str;
1257 /* Calcualte md5sum for INPUT string and return it in hex string format. */
1259 static string
1260 get_md5sum (const char *input)
1262 md5_ctx ctx;
1263 char md5sum[16];
1264 string str;
1266 md5_init_ctx (&ctx);
1267 md5_process_bytes (input, strlen (input), &ctx);
1268 md5_finish_ctx (&ctx, md5sum);
1270 for (unsigned i = 0; i < 16; i++)
1272 char b[3];
1273 sprintf (b, "%02x", (unsigned char)md5sum[i]);
1274 str += b;
1277 return str;
1280 /* Get the name of the gcov file. The return value must be free'd.
1282 It appends the '.gcov' extension to the *basename* of the file.
1283 The resulting file name will be in PWD.
1285 e.g.,
1286 input: foo.da, output: foo.da.gcov
1287 input: a/b/foo.cc, output: foo.cc.gcov */
1289 static string
1290 get_gcov_intermediate_filename (const char *input_file_name)
1292 string base = basename (input_file_name);
1293 string str = strip_extention (base);
1295 if (flag_hash_filenames)
1297 str += "##";
1298 str += get_md5sum (input_file_name);
1300 else if (flag_preserve_paths && base != input_file_name)
1302 str += "##";
1303 str += mangle_path (input_file_name);
1304 str = strip_extention (str);
1307 str += ".gcov.json.gz";
1308 return str.c_str ();
1311 /* Output the result in JSON intermediate format.
1312 Source info SRC is dumped into JSON_FILES which is JSON array. */
1314 static void
1315 output_json_intermediate_file (json::array *json_files, source_info *src)
1317 json::object *root = new json::object ();
1318 json_files->append (root);
1320 root->set_string ("file", src->name);
1322 json::array *functions = new json::array ();
1323 root->set ("functions", functions);
1325 std::sort (src->functions.begin (), src->functions.end (),
1326 function_line_start_cmp ());
1327 for (vector<function_info *>::iterator it = src->functions.begin ();
1328 it != src->functions.end (); it++)
1330 json::object *function = new json::object ();
1331 function->set_string ("name", (*it)->m_name);
1332 function->set_string ("demangled_name", (*it)->get_demangled_name ());
1333 function->set_integer ("start_line", (*it)->start_line);
1334 function->set_integer ("start_column", (*it)->start_column);
1335 function->set_integer ("end_line", (*it)->end_line);
1336 function->set_integer ("end_column", (*it)->end_column);
1337 function->set_integer ("blocks", (*it)->get_block_count ());
1338 function->set_integer ("blocks_executed", (*it)->blocks_executed);
1339 function->set_integer ("execution_count", (*it)->blocks[0].count);
1341 functions->append (function);
1344 json::array *lineso = new json::array ();
1345 root->set ("lines", lineso);
1347 vector<function_info *> last_non_group_fns;
1349 for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
1351 vector<function_info *> *fns = src->get_functions_at_location (line_num);
1353 if (fns != NULL)
1354 /* Print info for all group functions that begin on the line. */
1355 for (vector<function_info *>::iterator it2 = fns->begin ();
1356 it2 != fns->end (); it2++)
1358 if (!(*it2)->is_group)
1359 last_non_group_fns.push_back (*it2);
1361 vector<line_info> &lines = (*it2)->lines;
1362 /* The LINES array is allocated only for group functions. */
1363 for (unsigned i = 0; i < lines.size (); i++)
1365 line_info *line = &lines[i];
1366 output_intermediate_json_line (lineso, line, line_num + i,
1367 (*it2)->m_name);
1371 /* Follow with lines associated with the source file. */
1372 if (line_num < src->lines.size ())
1374 unsigned size = last_non_group_fns.size ();
1375 function_info *last_fn = size > 0 ? last_non_group_fns[size - 1] : NULL;
1376 const char *fname = last_fn ? last_fn->m_name : NULL;
1377 output_intermediate_json_line (lineso, &src->lines[line_num], line_num,
1378 fname);
1380 /* Pop ending function from stack. */
1381 if (last_fn != NULL && last_fn->end_line == line_num)
1382 last_non_group_fns.pop_back ();
1387 /* Function start pair. */
1388 struct function_start
1390 unsigned source_file_idx;
1391 unsigned start_line;
1394 /* Traits class for function start hash maps below. */
1396 struct function_start_pair_hash : typed_noop_remove <function_start>
1398 typedef function_start value_type;
1399 typedef function_start compare_type;
1401 static hashval_t
1402 hash (const function_start &ref)
1404 inchash::hash hstate (0);
1405 hstate.add_int (ref.source_file_idx);
1406 hstate.add_int (ref.start_line);
1407 return hstate.end ();
1410 static bool
1411 equal (const function_start &ref1, const function_start &ref2)
1413 return (ref1.source_file_idx == ref2.source_file_idx
1414 && ref1.start_line == ref2.start_line);
1417 static void
1418 mark_deleted (function_start &ref)
1420 ref.start_line = ~1U;
1423 static const bool empty_zero_p = false;
1425 static void
1426 mark_empty (function_start &ref)
1428 ref.start_line = ~2U;
1431 static bool
1432 is_deleted (const function_start &ref)
1434 return ref.start_line == ~1U;
1437 static bool
1438 is_empty (const function_start &ref)
1440 return ref.start_line == ~2U;
1444 /* Process a single input file. */
1446 static void
1447 process_file (const char *file_name)
1449 create_file_names (file_name);
1451 for (unsigned i = 0; i < processed_files.size (); i++)
1452 if (strcmp (da_file_name, processed_files[i]) == 0)
1454 fnotice (stderr, "'%s' file is already processed\n",
1455 file_name);
1456 return;
1459 processed_files.push_back (xstrdup (da_file_name));
1461 read_graph_file ();
1462 read_count_file ();
1465 /* Process all functions in all files. */
1467 static void
1468 process_all_functions (void)
1470 hash_map<function_start_pair_hash, function_info *> fn_map;
1472 /* Identify group functions. */
1473 for (vector<function_info *>::iterator it = functions.begin ();
1474 it != functions.end (); it++)
1475 if (!(*it)->artificial)
1477 function_start needle;
1478 needle.source_file_idx = (*it)->src;
1479 needle.start_line = (*it)->start_line;
1481 function_info **slot = fn_map.get (needle);
1482 if (slot)
1484 (*slot)->is_group = 1;
1485 (*it)->is_group = 1;
1487 else
1488 fn_map.put (needle, *it);
1491 /* Remove all artificial function. */
1492 functions.erase (remove_if (functions.begin (), functions.end (),
1493 function_info::is_artificial), functions.end ());
1495 for (vector<function_info *>::iterator it = functions.begin ();
1496 it != functions.end (); it++)
1498 function_info *fn = *it;
1499 unsigned src = fn->src;
1501 if (!fn->counts.empty () || no_data_file)
1503 source_info *s = &sources[src];
1504 s->add_function (fn);
1506 /* Mark last line in files touched by function. */
1507 for (unsigned block_no = 0; block_no != fn->blocks.size ();
1508 block_no++)
1510 block_info *block = &fn->blocks[block_no];
1511 for (unsigned i = 0; i < block->locations.size (); i++)
1513 /* Sort lines of locations. */
1514 sort (block->locations[i].lines.begin (),
1515 block->locations[i].lines.end ());
1517 if (!block->locations[i].lines.empty ())
1519 s = &sources[block->locations[i].source_file_idx];
1520 unsigned last_line
1521 = block->locations[i].lines.back ();
1523 /* Record new lines for the function. */
1524 if (last_line >= s->lines.size ())
1526 s = &sources[block->locations[i].source_file_idx];
1527 unsigned last_line
1528 = block->locations[i].lines.back ();
1530 /* Record new lines for the function. */
1531 if (last_line >= s->lines.size ())
1533 /* Record new lines for a source file. */
1534 s->lines.resize (last_line + 1);
1541 /* Allocate lines for group function, following start_line
1542 and end_line information of the function. */
1543 if (fn->is_group)
1544 fn->lines.resize (fn->end_line - fn->start_line + 1);
1546 solve_flow_graph (fn);
1547 if (fn->has_catch)
1548 find_exception_blocks (fn);
1550 else
1552 /* The function was not in the executable -- some other
1553 instance must have been selected. */
1558 static void
1559 output_gcov_file (const char *file_name, source_info *src)
1561 string gcov_file_name_str
1562 = make_gcov_file_name (file_name, src->coverage.name);
1563 const char *gcov_file_name = gcov_file_name_str.c_str ();
1565 if (src->coverage.lines)
1567 FILE *gcov_file = fopen (gcov_file_name, "w");
1568 if (gcov_file)
1570 fnotice (stdout, "Creating '%s'\n", gcov_file_name);
1571 output_lines (gcov_file, src);
1572 if (ferror (gcov_file))
1574 fnotice (stderr, "Error writing output file '%s'\n",
1575 gcov_file_name);
1576 return_code = 6;
1578 fclose (gcov_file);
1580 else
1582 fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
1583 return_code = 6;
1586 else
1588 unlink (gcov_file_name);
1589 fnotice (stdout, "Removing '%s'\n", gcov_file_name);
1593 static void
1594 generate_results (const char *file_name)
1596 string gcov_intermediate_filename;
1598 for (vector<function_info *>::iterator it = functions.begin ();
1599 it != functions.end (); it++)
1601 function_info *fn = *it;
1602 coverage_info coverage;
1604 memset (&coverage, 0, sizeof (coverage));
1605 coverage.name = fn->get_name ();
1606 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
1607 if (flag_function_summary)
1609 function_summary (&coverage);
1610 fnotice (stdout, "\n");
1614 name_map needle;
1615 needle.name = file_name;
1616 vector<name_map>::iterator it
1617 = std::find (names.begin (), names.end (), needle);
1618 if (it != names.end ())
1619 file_name = sources[it->src].coverage.name;
1620 else
1621 file_name = canonicalize_name (file_name);
1623 gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
1625 json::object *root = new json::object ();
1626 root->set_string ("format_version", GCOV_JSON_FORMAT_VERSION);
1627 root->set_string ("gcc_version", version_string);
1629 if (bbg_cwd != NULL)
1630 root->set_string ("current_working_directory", bbg_cwd);
1631 root->set_string ("data_file", file_name);
1633 json::array *json_files = new json::array ();
1634 root->set ("files", json_files);
1636 for (vector<source_info>::iterator it = sources.begin ();
1637 it != sources.end (); it++)
1639 source_info *src = &(*it);
1640 if (flag_relative_only)
1642 /* Ignore this source, if it is an absolute path (after
1643 source prefix removal). */
1644 char first = src->coverage.name[0];
1646 #if HAVE_DOS_BASED_FILE_SYSTEM
1647 if (first && src->coverage.name[1] == ':')
1648 first = src->coverage.name[2];
1649 #endif
1650 if (IS_DIR_SEPARATOR (first))
1651 continue;
1654 accumulate_line_counts (src);
1655 if (flag_debug)
1656 src->debug ();
1658 if (!flag_use_stdout)
1659 file_summary (&src->coverage);
1660 total_lines += src->coverage.lines;
1661 total_executed += src->coverage.lines_executed;
1662 if (flag_gcov_file)
1664 if (flag_json_format)
1666 output_json_intermediate_file (json_files, src);
1667 if (!flag_use_stdout)
1668 fnotice (stdout, "\n");
1670 else
1672 if (flag_use_stdout)
1674 if (src->coverage.lines)
1675 output_lines (stdout, src);
1677 else
1679 output_gcov_file (file_name, src);
1680 fnotice (stdout, "\n");
1686 if (flag_gcov_file && flag_json_format)
1688 if (flag_use_stdout)
1690 root->dump (stdout, false);
1691 printf ("\n");
1693 else
1695 pretty_printer pp;
1696 root->print (&pp, false);
1697 pp_formatted_text (&pp);
1699 fnotice (stdout, "Creating '%s'\n",
1700 gcov_intermediate_filename.c_str ());
1701 gzFile output = gzopen (gcov_intermediate_filename.c_str (), "w");
1702 if (output == NULL)
1704 fnotice (stderr, "Cannot open JSON output file %s\n",
1705 gcov_intermediate_filename.c_str ());
1706 return_code = 6;
1707 return;
1710 if (gzputs (output, pp_formatted_text (&pp)) == EOF
1711 || gzclose (output))
1713 fnotice (stderr, "Error writing JSON output file %s\n",
1714 gcov_intermediate_filename.c_str ());
1715 return_code = 6;
1716 return;
1722 /* Release all memory used. */
1724 static void
1725 release_structures (void)
1727 for (vector<function_info *>::iterator it = functions.begin ();
1728 it != functions.end (); it++)
1729 delete (*it);
1731 sources.resize (0);
1732 names.resize (0);
1733 functions.resize (0);
1734 ident_to_fn.clear ();
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. */
1744 static void
1745 create_file_names (const char *file_name)
1747 char *cptr;
1748 char *name;
1749 int length = strlen (file_name);
1750 int base;
1752 /* Free previous file names. */
1753 free (bbg_file_name);
1754 free (da_file_name);
1755 da_file_name = bbg_file_name = NULL;
1756 bbg_file_time = 0;
1757 bbg_stamp = 0;
1759 if (object_directory && object_directory[0])
1761 struct stat status;
1763 length += strlen (object_directory) + 2;
1764 name = XNEWVEC (char, length);
1765 name[0] = 0;
1767 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
1768 strcat (name, object_directory);
1769 if (base && (!IS_DIR_SEPARATOR (name[strlen (name) - 1])))
1770 strcat (name, "/");
1772 else
1774 name = XNEWVEC (char, length + 1);
1775 strcpy (name, file_name);
1776 base = 0;
1779 if (base)
1781 /* Append source file name. */
1782 const char *cptr = lbasename (file_name);
1783 strcat (name, cptr ? cptr : file_name);
1786 /* Remove the extension. */
1787 cptr = strrchr (CONST_CAST (char *, lbasename (name)), '.');
1788 if (cptr)
1789 *cptr = 0;
1791 length = strlen (name);
1793 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
1794 strcpy (bbg_file_name, name);
1795 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
1797 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
1798 strcpy (da_file_name, name);
1799 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
1801 free (name);
1802 return;
1805 /* Find or create a source file structure for FILE_NAME. Copies
1806 FILE_NAME on creation */
1808 static unsigned
1809 find_source (const char *file_name)
1811 char *canon;
1812 unsigned idx;
1813 struct stat status;
1815 if (!file_name)
1816 file_name = "<unknown>";
1818 name_map needle;
1819 needle.name = file_name;
1821 vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1822 needle);
1823 if (it != names.end ())
1825 idx = it->src;
1826 goto check_date;
1829 /* Not found, try the canonical name. */
1830 canon = canonicalize_name (file_name);
1831 needle.name = canon;
1832 it = std::find (names.begin (), names.end (), needle);
1833 if (it == names.end ())
1835 /* Not found with canonical name, create a new source. */
1836 source_info *src;
1838 idx = sources.size ();
1839 needle = name_map (canon, idx);
1840 names.push_back (needle);
1842 sources.push_back (source_info ());
1843 src = &sources.back ();
1844 src->name = canon;
1845 src->coverage.name = src->name;
1846 src->index = idx;
1847 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 && !strncmp (source_prefix, src->coverage.name, source_length)
1854 #endif
1855 && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
1856 src->coverage.name += source_length + 1;
1857 if (!stat (src->name, &status))
1858 src->file_time = status.st_mtime;
1860 else
1861 idx = it->src;
1863 needle.name = file_name;
1864 if (std::find (names.begin (), names.end (), needle) == names.end ())
1866 /* Append the non-canonical name. */
1867 names.push_back (name_map (xstrdup (file_name), idx));
1870 /* Resort the name map. */
1871 std::sort (names.begin (), names.end ());
1873 check_date:
1874 if (sources[idx].file_time > bbg_file_time)
1876 static int info_emitted;
1878 fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
1879 file_name, bbg_file_name);
1880 if (!info_emitted)
1882 fnotice (stderr,
1883 "(the message is displayed only once per source file)\n");
1884 info_emitted = 1;
1886 sources[idx].file_time = 0;
1889 return idx;
1892 /* Read the notes file. Save functions to FUNCTIONS global vector. */
1894 static void
1895 read_graph_file (void)
1897 unsigned version;
1898 unsigned current_tag = 0;
1899 unsigned tag;
1901 if (!gcov_open (bbg_file_name, 1))
1903 fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1904 return_code = 1;
1905 return;
1907 bbg_file_time = gcov_time ();
1908 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1910 fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
1911 return_code = 2;
1912 gcov_close ();
1913 return;
1916 version = gcov_read_unsigned ();
1917 if (version != GCOV_VERSION)
1919 char v[4], e[4];
1921 GCOV_UNSIGNED2STRING (v, version);
1922 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1924 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1925 bbg_file_name, v, e);
1926 return_code = 3;
1928 bbg_stamp = gcov_read_unsigned ();
1929 /* Read checksum. */
1930 gcov_read_unsigned ();
1931 bbg_cwd = xstrdup (gcov_read_string ());
1932 bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
1934 function_info *fn = NULL;
1935 while ((tag = gcov_read_unsigned ()))
1937 unsigned length = gcov_read_unsigned ();
1938 gcov_position_t base = gcov_position ();
1940 if (tag == GCOV_TAG_FUNCTION)
1942 char *function_name;
1943 unsigned ident;
1944 unsigned lineno_checksum, cfg_checksum;
1946 ident = gcov_read_unsigned ();
1947 lineno_checksum = gcov_read_unsigned ();
1948 cfg_checksum = gcov_read_unsigned ();
1949 function_name = xstrdup (gcov_read_string ());
1950 unsigned artificial = gcov_read_unsigned ();
1951 unsigned src_idx = find_source (gcov_read_string ());
1952 unsigned start_line = gcov_read_unsigned ();
1953 unsigned start_column = gcov_read_unsigned ();
1954 unsigned end_line = gcov_read_unsigned ();
1955 unsigned end_column = gcov_read_unsigned ();
1957 fn = new function_info ();
1958 functions.push_back (fn);
1959 ident_to_fn[ident] = fn;
1961 fn->m_name = function_name;
1962 fn->ident = ident;
1963 fn->lineno_checksum = lineno_checksum;
1964 fn->cfg_checksum = cfg_checksum;
1965 fn->src = src_idx;
1966 fn->start_line = start_line;
1967 fn->start_column = start_column;
1968 fn->end_line = end_line;
1969 fn->end_column = end_column;
1970 fn->artificial = artificial;
1972 current_tag = tag;
1974 else if (fn && tag == GCOV_TAG_BLOCKS)
1976 if (!fn->blocks.empty ())
1977 fnotice (stderr, "%s:already seen blocks for '%s'\n",
1978 bbg_file_name, fn->get_name ());
1979 else
1980 fn->blocks.resize (gcov_read_unsigned ());
1982 else if (fn && tag == GCOV_TAG_ARCS)
1984 unsigned src = gcov_read_unsigned ();
1985 fn->blocks[src].id = src;
1986 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1987 block_info *src_blk = &fn->blocks[src];
1988 unsigned mark_catches = 0;
1989 struct arc_info *arc;
1991 if (src >= fn->blocks.size () || fn->blocks[src].succ)
1992 goto corrupt;
1994 while (num_dests--)
1996 unsigned dest = gcov_read_unsigned ();
1997 unsigned flags = gcov_read_unsigned ();
1999 if (dest >= fn->blocks.size ())
2000 goto corrupt;
2001 arc = XCNEW (arc_info);
2003 arc->dst = &fn->blocks[dest];
2004 /* Set id in order to find EXIT_BLOCK. */
2005 arc->dst->id = dest;
2006 arc->src = src_blk;
2008 arc->count = 0;
2009 arc->count_valid = 0;
2010 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
2011 arc->fake = !!(flags & GCOV_ARC_FAKE);
2012 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
2014 arc->succ_next = src_blk->succ;
2015 src_blk->succ = arc;
2016 src_blk->num_succ++;
2018 arc->pred_next = fn->blocks[dest].pred;
2019 fn->blocks[dest].pred = arc;
2020 fn->blocks[dest].num_pred++;
2022 if (arc->fake)
2024 if (src)
2026 /* Exceptional exit from this function, the
2027 source block must be a call. */
2028 fn->blocks[src].is_call_site = 1;
2029 arc->is_call_non_return = 1;
2030 mark_catches = 1;
2032 else
2034 /* Non-local return from a callee of this
2035 function. The destination block is a setjmp. */
2036 arc->is_nonlocal_return = 1;
2037 fn->blocks[dest].is_nonlocal_return = 1;
2041 if (!arc->on_tree)
2042 fn->counts.push_back (0);
2045 if (mark_catches)
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. */
2051 for (arc = src_blk->succ; arc; arc = arc->succ_next)
2052 if (!arc->fake && !arc->fall_through)
2054 arc->is_throw = 1;
2055 fn->has_catch = 1;
2059 else if (fn && tag == GCOV_TAG_CONDS)
2061 unsigned num_dests = GCOV_TAG_CONDS_NUM (length);
2063 if (!fn->conditions.empty ())
2064 fnotice (stderr, "%s:already seen conditions for '%s'\n",
2065 bbg_file_name, fn->get_name ());
2066 else
2067 fn->conditions.resize (num_dests);
2069 for (unsigned i = 0; i < num_dests; ++i)
2071 unsigned idx = gcov_read_unsigned ();
2073 if (idx >= fn->blocks.size ())
2074 goto corrupt;
2076 condition_info *info = &fn->blocks[idx].conditions;
2077 info->n_terms = gcov_read_unsigned ();
2078 fn->conditions[i] = info;
2081 else if (fn && tag == GCOV_TAG_LINES)
2083 unsigned blockno = gcov_read_unsigned ();
2084 block_info *block = &fn->blocks[blockno];
2086 if (blockno >= fn->blocks.size ())
2087 goto corrupt;
2089 while (true)
2091 unsigned lineno = gcov_read_unsigned ();
2093 if (lineno)
2094 block->locations.back ().lines.push_back (lineno);
2095 else
2097 const char *file_name = gcov_read_string ();
2099 if (!file_name)
2100 break;
2101 block->locations.push_back (block_location_info
2102 (find_source (file_name)));
2106 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
2108 fn = NULL;
2109 current_tag = 0;
2111 gcov_sync (base, length);
2112 if (gcov_is_error ())
2114 corrupt:;
2115 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
2116 return_code = 4;
2117 break;
2120 gcov_close ();
2122 if (functions.empty ())
2123 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
2126 /* Reads profiles from the count file and attach to each
2127 function. Return nonzero if fatal error. */
2129 static int
2130 read_count_file (void)
2132 unsigned ix;
2133 unsigned version;
2134 unsigned tag;
2135 function_info *fn = NULL;
2136 int error = 0;
2137 map<unsigned, function_info *>::iterator it;
2139 if (!gcov_open (da_file_name, 1))
2141 fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
2142 da_file_name);
2143 no_data_file = 1;
2144 return 0;
2146 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
2148 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
2149 return_code = 2;
2150 cleanup:;
2151 gcov_close ();
2152 return 1;
2154 version = gcov_read_unsigned ();
2155 if (version != GCOV_VERSION)
2157 char v[4], e[4];
2159 GCOV_UNSIGNED2STRING (v, version);
2160 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
2162 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
2163 da_file_name, v, e);
2164 return_code = 3;
2166 tag = gcov_read_unsigned ();
2167 if (tag != bbg_stamp)
2169 fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
2170 return_code = 5;
2171 goto cleanup;
2174 /* Read checksum. */
2175 gcov_read_unsigned ();
2177 while ((tag = gcov_read_unsigned ()))
2179 unsigned length = gcov_read_unsigned ();
2180 int read_length = (int)length;
2181 unsigned long base = gcov_position ();
2183 if (tag == GCOV_TAG_OBJECT_SUMMARY)
2185 struct gcov_summary summary;
2186 gcov_read_summary (&summary);
2187 object_runs = summary.runs;
2189 else if (tag == GCOV_TAG_FUNCTION && !length)
2190 ; /* placeholder */
2191 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
2193 unsigned ident;
2194 ident = gcov_read_unsigned ();
2195 fn = NULL;
2196 it = ident_to_fn.find (ident);
2197 if (it != ident_to_fn.end ())
2198 fn = it->second;
2200 if (!fn)
2202 else if (gcov_read_unsigned () != fn->lineno_checksum
2203 || gcov_read_unsigned () != fn->cfg_checksum)
2205 mismatch:;
2206 fnotice (stderr, "%s:profile mismatch for '%s'\n",
2207 da_file_name, fn->get_name ());
2208 goto cleanup;
2211 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_CONDS) && fn)
2213 length = abs (read_length);
2214 if (length != GCOV_TAG_COUNTER_LENGTH (2 * fn->conditions.size ()))
2215 goto mismatch;
2217 if (read_length > 0)
2219 for (ix = 0; ix != fn->conditions.size (); ix++)
2221 fn->conditions[ix]->truev |= gcov_read_counter ();
2222 fn->conditions[ix]->falsev |= gcov_read_counter ();
2226 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
2228 length = abs (read_length);
2229 if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
2230 goto mismatch;
2232 if (read_length > 0)
2233 for (ix = 0; ix != fn->counts.size (); ix++)
2234 fn->counts[ix] += gcov_read_counter ();
2236 if (read_length < 0)
2237 read_length = 0;
2238 gcov_sync (base, read_length);
2239 if ((error = gcov_is_error ()))
2241 fnotice (stderr,
2242 error < 0
2243 ? N_("%s:overflowed\n")
2244 : N_("%s:corrupted\n"),
2245 da_file_name);
2246 return_code = 4;
2247 goto cleanup;
2251 gcov_close ();
2252 return 0;
2255 /* Solve the flow graph. Propagate counts from the instrumented arcs
2256 to the blocks and the uninstrumented arcs. */
2258 static void
2259 solve_flow_graph (function_info *fn)
2261 unsigned ix;
2262 arc_info *arc;
2263 gcov_type *count_ptr = &fn->counts.front ();
2264 block_info *blk;
2265 block_info *valid_blocks = NULL; /* valid, but unpropagated blocks. */
2266 block_info *invalid_blocks = NULL; /* invalid, but inferable blocks. */
2268 /* The arcs were built in reverse order. Fix that now. */
2269 for (ix = fn->blocks.size (); ix--;)
2271 arc_info *arc_p, *arc_n;
2273 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
2274 arc_p = arc, arc = arc_n)
2276 arc_n = arc->succ_next;
2277 arc->succ_next = arc_p;
2279 fn->blocks[ix].succ = arc_p;
2281 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
2282 arc_p = arc, arc = arc_n)
2284 arc_n = arc->pred_next;
2285 arc->pred_next = arc_p;
2287 fn->blocks[ix].pred = arc_p;
2290 if (fn->blocks.size () < 2)
2291 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
2292 bbg_file_name, fn->get_name ());
2293 else
2295 if (fn->blocks[ENTRY_BLOCK].num_pred)
2296 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 fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
2303 if (fn->blocks[EXIT_BLOCK].num_succ)
2304 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 fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
2312 /* Propagate the measured counts, this must be done in the same
2313 order as the code in profile.cc */
2314 for (unsigned i = 0; i < fn->blocks.size (); i++)
2316 blk = &fn->blocks[i];
2317 block_info const *prev_dst = NULL;
2318 int out_of_order = 0;
2319 int non_fake_succ = 0;
2321 for (arc = blk->succ; arc; arc = arc->succ_next)
2323 if (!arc->fake)
2324 non_fake_succ++;
2326 if (!arc->on_tree)
2328 if (count_ptr)
2329 arc->count = *count_ptr++;
2330 arc->count_valid = 1;
2331 blk->num_succ--;
2332 arc->dst->num_pred--;
2334 if (prev_dst && prev_dst > arc->dst)
2335 out_of_order = 1;
2336 prev_dst = arc->dst;
2338 if (non_fake_succ == 1)
2340 /* If there is only one non-fake exit, it is an
2341 unconditional branch. */
2342 for (arc = blk->succ; arc; arc = arc->succ_next)
2343 if (!arc->fake)
2345 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 if (blk->is_call_site && arc->fall_through
2353 && arc->dst->pred == arc && !arc->pred_next)
2354 arc->dst->is_call_return = 1;
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 if (out_of_order)
2364 arc_info *start = blk->succ;
2365 unsigned changes = 1;
2367 while (changes)
2369 arc_info *arc, *arc_p, *arc_n;
2371 changes = 0;
2372 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
2374 if (arc->dst > arc_n->dst)
2376 changes = 1;
2377 if (arc_p)
2378 arc_p->succ_next = arc_n;
2379 else
2380 start = arc_n;
2381 arc->succ_next = arc_n->succ_next;
2382 arc_n->succ_next = arc;
2383 arc_p = arc_n;
2385 else
2387 arc_p = arc;
2388 arc = arc_n;
2392 blk->succ = start;
2395 /* Place it on the invalid chain, it will be ignored if that's
2396 wrong. */
2397 blk->invalid_chain = 1;
2398 blk->chain = invalid_blocks;
2399 invalid_blocks = blk;
2402 while (invalid_blocks || valid_blocks)
2404 while ((blk = invalid_blocks))
2406 gcov_type total = 0;
2407 const arc_info *arc;
2409 invalid_blocks = blk->chain;
2410 blk->invalid_chain = 0;
2411 if (!blk->num_succ)
2412 for (arc = blk->succ; arc; arc = arc->succ_next)
2413 total += arc->count;
2414 else if (!blk->num_pred)
2415 for (arc = blk->pred; arc; arc = arc->pred_next)
2416 total += arc->count;
2417 else
2418 continue;
2420 blk->count = total;
2421 blk->count_valid = 1;
2422 blk->chain = valid_blocks;
2423 blk->valid_chain = 1;
2424 valid_blocks = blk;
2426 while ((blk = valid_blocks))
2428 gcov_type total;
2429 arc_info *arc, *inv_arc;
2431 valid_blocks = blk->chain;
2432 blk->valid_chain = 0;
2433 if (blk->num_succ == 1)
2435 block_info *dst;
2437 total = blk->count;
2438 inv_arc = NULL;
2439 for (arc = blk->succ; arc; arc = arc->succ_next)
2441 total -= arc->count;
2442 if (!arc->count_valid)
2443 inv_arc = arc;
2445 dst = inv_arc->dst;
2446 inv_arc->count_valid = 1;
2447 inv_arc->count = total;
2448 blk->num_succ--;
2449 dst->num_pred--;
2450 if (dst->count_valid)
2452 if (dst->num_pred == 1 && !dst->valid_chain)
2454 dst->chain = valid_blocks;
2455 dst->valid_chain = 1;
2456 valid_blocks = dst;
2459 else
2461 if (!dst->num_pred && !dst->invalid_chain)
2463 dst->chain = invalid_blocks;
2464 dst->invalid_chain = 1;
2465 invalid_blocks = dst;
2469 if (blk->num_pred == 1)
2471 block_info *src;
2473 total = blk->count;
2474 inv_arc = NULL;
2475 for (arc = blk->pred; arc; arc = arc->pred_next)
2477 total -= arc->count;
2478 if (!arc->count_valid)
2479 inv_arc = arc;
2481 src = inv_arc->src;
2482 inv_arc->count_valid = 1;
2483 inv_arc->count = total;
2484 blk->num_pred--;
2485 src->num_succ--;
2486 if (src->count_valid)
2488 if (src->num_succ == 1 && !src->valid_chain)
2490 src->chain = valid_blocks;
2491 src->valid_chain = 1;
2492 valid_blocks = src;
2495 else
2497 if (!src->num_succ && !src->invalid_chain)
2499 src->chain = invalid_blocks;
2500 src->invalid_chain = 1;
2501 invalid_blocks = src;
2508 /* If the graph has been correctly solved, every block will have a
2509 valid count. */
2510 for (unsigned i = 0; ix < fn->blocks.size (); i++)
2511 if (!fn->blocks[i].count_valid)
2513 fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
2514 bbg_file_name, fn->get_name ());
2515 break;
2519 /* Mark all the blocks only reachable via an incoming catch. */
2521 static void
2522 find_exception_blocks (function_info *fn)
2524 unsigned ix;
2525 block_info **queue = XALLOCAVEC (block_info *, fn->blocks.size ());
2527 /* First mark all blocks as exceptional. */
2528 for (ix = fn->blocks.size (); ix--;)
2529 fn->blocks[ix].exceptional = 1;
2531 /* Now mark all the blocks reachable via non-fake edges */
2532 queue[0] = &fn->blocks[0];
2533 queue[0]->exceptional = 0;
2534 for (ix = 1; ix;)
2536 block_info *block = queue[--ix];
2537 const arc_info *arc;
2539 for (arc = block->succ; arc; arc = arc->succ_next)
2540 if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
2542 arc->dst->exceptional = 0;
2543 queue[ix++] = arc->dst;
2549 /* Increment totals in COVERAGE according to arc ARC. */
2551 static void
2552 add_branch_counts (coverage_info *coverage, const arc_info *arc)
2554 if (arc->is_call_non_return)
2556 coverage->calls++;
2557 if (arc->src->count)
2558 coverage->calls_executed++;
2560 else if (!arc->is_unconditional)
2562 coverage->branches++;
2563 if (arc->src->count)
2564 coverage->branches_executed++;
2565 if (arc->count)
2566 coverage->branches_taken++;
2570 /* Increment totals in COVERAGE according to to block BLOCK. */
2572 static void
2573 add_condition_counts (coverage_info *coverage, const block_info *block)
2575 coverage->conditions += 2 * block->conditions.n_terms;
2576 coverage->conditions_covered += block->conditions.popcount ();
2579 /* Format COUNT, if flag_human_readable_numbers is set, return it human
2580 readable format. */
2582 static char const *
2583 format_count (gcov_type count)
2585 static char buffer[64];
2586 const char *units = " kMGTPEZY";
2588 if (count < 1000 || !flag_human_readable_numbers)
2590 sprintf (buffer, "%" PRId64, count);
2591 return buffer;
2594 unsigned i;
2595 gcov_type divisor = 1;
2596 for (i = 0; units[i+1]; i++, divisor *= 1000)
2598 if (count + divisor / 2 < 1000 * divisor)
2599 break;
2601 float r = 1.0f * count / divisor;
2602 sprintf (buffer, "%.1f%c", r, units[i]);
2603 return buffer;
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. */
2612 static char const *
2613 format_gcov (gcov_type top, gcov_type bottom, int decimal_places)
2615 static char buffer[20];
2617 if (decimal_places >= 0)
2619 float ratio = bottom ? 100.0f * top / bottom: 0;
2621 /* Round up to 1% if there's a small non-zero value. */
2622 if (ratio > 0.0f && ratio < 0.5f && decimal_places == 0)
2623 ratio = 1.0f;
2624 sprintf (buffer, "%.*f%%", decimal_places, ratio);
2626 else
2627 return format_count (top);
2629 return buffer;
2632 /* Summary of execution */
2634 static void
2635 executed_summary (unsigned lines, unsigned executed)
2637 if (lines)
2638 fnotice (stdout, "Lines executed:%s of %d\n",
2639 format_gcov (executed, lines, 2), lines);
2640 else
2641 fnotice (stdout, "No executable lines\n");
2644 /* Output summary info for a function. */
2646 static void
2647 function_summary (const coverage_info *coverage)
2649 fnotice (stdout, "%s '%s'\n", "Function", coverage->name);
2650 executed_summary (coverage->lines, coverage->lines_executed);
2653 /* Output summary info for a file. */
2655 static void
2656 file_summary (const coverage_info *coverage)
2658 fnotice (stdout, "%s '%s'\n", "File", coverage->name);
2659 executed_summary (coverage->lines, coverage->lines_executed);
2661 if (flag_branches)
2663 if (coverage->branches)
2665 fnotice (stdout, "Branches executed:%s of %d\n",
2666 format_gcov (coverage->branches_executed,
2667 coverage->branches, 2),
2668 coverage->branches);
2669 fnotice (stdout, "Taken at least once:%s of %d\n",
2670 format_gcov (coverage->branches_taken,
2671 coverage->branches, 2),
2672 coverage->branches);
2674 else
2675 fnotice (stdout, "No branches\n");
2676 if (coverage->calls)
2677 fnotice (stdout, "Calls executed:%s of %d\n",
2678 format_gcov (coverage->calls_executed, coverage->calls, 2),
2679 coverage->calls);
2680 else
2681 fnotice (stdout, "No calls\n");
2685 if (flag_conditions)
2687 if (coverage->conditions)
2688 fnotice (stdout, "Condition outcomes covered:%s of %d\n",
2689 format_gcov (coverage->conditions_covered,
2690 coverage->conditions, 2),
2691 coverage->conditions);
2692 else
2693 fnotice (stdout, "No conditions\n");
2697 /* Canonicalize the filename NAME by canonicalizing directory
2698 separators, eliding . components and resolving .. components
2699 appropriately. Always returns a unique string. */
2701 static char *
2702 canonicalize_name (const char *name)
2704 /* The canonical name cannot be longer than the incoming name. */
2705 char *result = XNEWVEC (char, strlen (name) + 1);
2706 const char *base = name, *probe;
2707 char *ptr = result;
2708 char *dd_base;
2709 int slash = 0;
2711 #if HAVE_DOS_BASED_FILE_SYSTEM
2712 if (base[0] && base[1] == ':')
2714 result[0] = base[0];
2715 result[1] = ':';
2716 base += 2;
2717 ptr += 2;
2719 #endif
2720 for (dd_base = ptr; *base; base = probe)
2722 size_t len;
2724 for (probe = base; *probe; probe++)
2725 if (IS_DIR_SEPARATOR (*probe))
2726 break;
2728 len = probe - base;
2729 if (len == 1 && base[0] == '.')
2730 /* Elide a '.' directory */
2732 else if (len == 2 && base[0] == '.' && base[1] == '.')
2734 /* '..', we can only elide it and the previous directory, if
2735 we're not a symlink. */
2736 struct stat ATTRIBUTE_UNUSED buf;
2738 *ptr = 0;
2739 if (dd_base == ptr
2740 #if defined (S_ISLNK)
2741 /* S_ISLNK is not POSIX.1-1996. */
2742 || stat (result, &buf) || S_ISLNK (buf.st_mode)
2743 #endif
2746 /* Cannot elide, or unreadable or a symlink. */
2747 dd_base = ptr + 2 + slash;
2748 goto regular;
2750 while (ptr != dd_base && *ptr != '/')
2751 ptr--;
2752 slash = ptr != result;
2754 else
2756 regular:
2757 /* Regular pathname component. */
2758 if (slash)
2759 *ptr++ = '/';
2760 memcpy (ptr, base, len);
2761 ptr += len;
2762 slash = 1;
2765 for (; IS_DIR_SEPARATOR (*probe); probe++)
2766 continue;
2768 *ptr = 0;
2770 return result;
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.) */
2785 static string
2786 make_gcov_file_name (const char *input_name, const char *src_name)
2788 string str;
2790 /* When hashing filenames, we shorten them by only using the filename
2791 component and appending a hash of the full (mangled) pathname. */
2792 if (flag_hash_filenames)
2793 str = (string (mangle_name (src_name)) + "##"
2794 + get_md5sum (src_name) + ".gcov");
2795 else
2797 if (flag_long_names && input_name && strcmp (src_name, input_name) != 0)
2799 str += mangle_name (input_name);
2800 str += "##";
2803 str += mangle_name (src_name);
2804 str += ".gcov";
2807 return str;
2810 /* Mangle BASE name, copy it at the beginning of PTR buffer and
2811 return address of the \0 character of the buffer. */
2813 static char *
2814 mangle_name (char const *base)
2816 /* Generate the source filename part. */
2817 if (!flag_preserve_paths)
2818 return xstrdup (lbasename (base));
2819 else
2820 return mangle_path (base);
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. */
2827 static void
2828 add_line_counts (coverage_info *coverage, function_info *fn)
2830 bool has_any_line = false;
2831 /* Scan each basic block. */
2832 for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
2834 line_info *line = NULL;
2835 block_info *block = &fn->blocks[ix];
2836 if (block->count && ix && ix + 1 != fn->blocks.size ())
2837 fn->blocks_executed++;
2838 for (unsigned i = 0; i < block->locations.size (); i++)
2840 unsigned src_idx = block->locations[i].source_file_idx;
2841 vector<unsigned> &lines = block->locations[i].lines;
2843 block->cycle.arc = NULL;
2844 block->cycle.ident = ~0U;
2846 for (unsigned j = 0; j < lines.size (); j++)
2848 unsigned ln = lines[j];
2850 /* Line belongs to a function that is in a group. */
2851 if (fn->group_line_p (ln, src_idx))
2853 gcc_assert (lines[j] - fn->start_line < fn->lines.size ());
2854 line = &(fn->lines[lines[j] - fn->start_line]);
2855 if (coverage)
2857 if (!line->exists)
2858 coverage->lines++;
2859 if (!line->count && block->count)
2860 coverage->lines_executed++;
2862 line->exists = 1;
2863 if (!block->exceptional)
2865 line->unexceptional = 1;
2866 if (block->count == 0)
2867 line->has_unexecuted_block = 1;
2869 line->count += block->count;
2871 else
2873 gcc_assert (ln < sources[src_idx].lines.size ());
2874 line = &(sources[src_idx].lines[ln]);
2875 if (coverage)
2877 if (!line->exists)
2878 coverage->lines++;
2879 if (!line->count && block->count)
2880 coverage->lines_executed++;
2882 line->exists = 1;
2883 if (!block->exceptional)
2885 line->unexceptional = 1;
2886 if (block->count == 0)
2887 line->has_unexecuted_block = 1;
2889 line->count += block->count;
2893 has_any_line = true;
2895 if (!ix || ix + 1 == fn->blocks.size ())
2896 /* Entry or exit block. */;
2897 else if (line != NULL)
2899 line->blocks.push_back (block);
2901 if (flag_branches)
2903 arc_info *arc;
2905 for (arc = block->succ; arc; arc = arc->succ_next)
2906 line->branches.push_back (arc);
2912 if (!has_any_line)
2913 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name,
2914 fn->get_name ());
2917 /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE
2918 is set to true, update source file summary. */
2920 static void accumulate_line_info (line_info *line, source_info *src,
2921 bool add_coverage)
2923 if (add_coverage)
2924 for (vector<arc_info *>::iterator it = line->branches.begin ();
2925 it != line->branches.end (); it++)
2926 add_branch_counts (&src->coverage, *it);
2928 if (add_coverage)
2929 for (vector<block_info *>::iterator it = line->blocks.begin ();
2930 it != line->blocks.end (); it++)
2931 add_condition_counts (&src->coverage, *it);
2934 if (!line->blocks.empty ())
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;
2944 /* Cycle detection. */
2945 for (vector<block_info *>::iterator it = line->blocks.begin ();
2946 it != line->blocks.end (); it++)
2948 for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next)
2949 if (!line->has_block (arc->src))
2950 count += arc->count;
2951 for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next)
2952 arc->cs_count = arc->count;
2955 /* Now, add the count of loops entirely on this line. */
2956 count += get_cycles_count (*line);
2957 line->count = count;
2959 if (line->count > src->maximum_count)
2960 src->maximum_count = line->count;
2963 if (line->exists && add_coverage)
2965 src->coverage.lines++;
2966 if (line->count)
2967 src->coverage.lines_executed++;
2971 /* Accumulate the line counts of a file. */
2973 static void
2974 accumulate_line_counts (source_info *src)
2976 /* First work on group functions. */
2977 for (vector<function_info *>::iterator it = src->functions.begin ();
2978 it != src->functions.end (); it++)
2980 function_info *fn = *it;
2982 if (fn->src != src->index || !fn->is_group)
2983 continue;
2985 for (vector<line_info>::iterator it2 = fn->lines.begin ();
2986 it2 != fn->lines.end (); it2++)
2988 line_info *line = &(*it2);
2989 accumulate_line_info (line, src, true);
2993 /* Work on global lines that line in source file SRC. */
2994 for (vector<line_info>::iterator it = src->lines.begin ();
2995 it != src->lines.end (); it++)
2996 accumulate_line_info (&(*it), src, true);
2998 /* If not using intermediate mode, sum lines of group functions and
2999 add them to lines that live in a source file. */
3000 if (!flag_json_format)
3001 for (vector<function_info *>::iterator it = src->functions.begin ();
3002 it != src->functions.end (); it++)
3004 function_info *fn = *it;
3006 if (fn->src != src->index || !fn->is_group)
3007 continue;
3009 for (unsigned i = 0; i < fn->lines.size (); i++)
3011 line_info *fn_line = &fn->lines[i];
3012 if (fn_line->exists)
3014 unsigned ln = fn->start_line + i;
3015 line_info *src_line = &src->lines[ln];
3017 if (!src_line->exists)
3018 src->coverage.lines++;
3019 if (!src_line->count && fn_line->count)
3020 src->coverage.lines_executed++;
3022 src_line->count += fn_line->count;
3023 src_line->exists = 1;
3025 if (fn_line->has_unexecuted_block)
3026 src_line->has_unexecuted_block = 1;
3028 if (fn_line->unexceptional)
3029 src_line->unexceptional = 1;
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. */
3039 static void
3040 output_conditions (FILE *gcov_file, const block_info *binfo)
3042 const condition_info& info = binfo->conditions;
3043 if (info.n_terms == 0)
3044 return;
3046 const int expected = 2 * info.n_terms;
3047 const int got = info.popcount ();
3049 fnotice (gcov_file, "condition outcomes covered %d/%d\n", got, expected);
3050 if (expected == got)
3051 return;
3053 for (unsigned i = 0; i < info.n_terms; i++)
3055 gcov_type_unsigned index = 1;
3056 index <<= i;
3057 if ((index & info.truev & info.falsev))
3058 continue;
3060 const char *t = (index & info.truev) ? "" : "true";
3061 const char *f = (index & info.falsev) ? "" : " false";
3062 fnotice (gcov_file, "condition %2u not covered (%s%s)\n", i, t, f + !t[0]);
3066 /* Output information about ARC number IX. Returns nonzero if
3067 anything is output. */
3069 static int
3070 output_branch_count (FILE *gcov_file, int ix, const arc_info *arc)
3072 if (arc->is_call_non_return)
3074 if (arc->src->count)
3076 fnotice (gcov_file, "call %2d returned %s\n", ix,
3077 format_gcov (arc->src->count - arc->count,
3078 arc->src->count, -flag_counts));
3080 else
3081 fnotice (gcov_file, "call %2d never executed\n", ix);
3083 else if (!arc->is_unconditional)
3085 if (arc->src->count)
3086 fnotice (gcov_file, "branch %2d taken %s%s", ix,
3087 format_gcov (arc->count, arc->src->count, -flag_counts),
3088 arc->fall_through ? " (fallthrough)"
3089 : arc->is_throw ? " (throw)" : "");
3090 else
3091 fnotice (gcov_file, "branch %2d never executed%s", ix,
3092 (arc->fall_through ? " (fallthrough)"
3093 : arc->is_throw ? " (throw)" : ""));
3095 if (flag_verbose)
3096 fnotice (gcov_file, " (BB %d)", arc->dst->id);
3098 fnotice (gcov_file, "\n");
3100 else if (flag_unconditional && !arc->dst->is_call_return)
3102 if (arc->src->count)
3103 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
3104 format_gcov (arc->count, arc->src->count, -flag_counts));
3105 else
3106 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
3108 else
3109 return 0;
3110 return 1;
3113 static const char *
3114 read_line (FILE *file)
3116 static char *string;
3117 static size_t string_len;
3118 size_t pos = 0;
3120 if (!string_len)
3122 string_len = 200;
3123 string = XNEWVEC (char, string_len);
3126 while (fgets (string + pos, string_len - pos, file))
3128 size_t len = strlen (string + pos);
3130 if (len && string[pos + len - 1] == '\n')
3132 string[pos + len - 1] = 0;
3133 return string;
3135 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 if (pos > string_len / 2)
3141 string_len *= 2;
3142 string = XRESIZEVEC (char, string, string_len);
3146 return pos ? string : NULL;
3149 /* Pad string S with spaces from left to have total width equal to 9. */
3151 static void
3152 pad_count_string (string &s)
3154 if (s.size () < 9)
3155 s.insert (0, 9 - s.size (), ' ');
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. */
3164 static void
3165 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)
3172 string s;
3173 if (exists)
3175 if (count > 0)
3177 s = format_gcov (count, 0, -1);
3178 if (has_unexecuted_block
3179 && bbg_supports_has_unexecuted_blocks)
3181 if (flag_use_colors)
3183 pad_count_string (s);
3184 s.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
3185 COLOR_SEPARATOR COLOR_FG_WHITE));
3186 s += SGR_RESET;
3188 else
3189 s += "*";
3191 pad_count_string (s);
3193 else
3195 if (flag_use_colors)
3197 s = "0";
3198 pad_count_string (s);
3199 if (unexceptional)
3200 s.insert (0, SGR_SEQ (COLOR_BG_RED
3201 COLOR_SEPARATOR COLOR_FG_WHITE));
3202 else
3203 s.insert (0, SGR_SEQ (COLOR_BG_CYAN
3204 COLOR_SEPARATOR COLOR_FG_WHITE));
3205 s += SGR_RESET;
3207 else
3209 s = unexceptional ? unexceptional_string : exceptional_string;
3210 pad_count_string (s);
3214 else
3216 s = "-";
3217 pad_count_string (s);
3220 /* Format line number in output. */
3221 char buffer[16];
3222 sprintf (buffer, "%5u", line_num);
3223 string linestr (buffer);
3225 if (flag_use_hotness_colors && maximum_count)
3227 if (count * 2 > maximum_count) /* > 50%. */
3228 linestr.insert (0, SGR_SEQ (COLOR_BG_RED));
3229 else if (count * 5 > maximum_count) /* > 20%. */
3230 linestr.insert (0, SGR_SEQ (COLOR_BG_YELLOW));
3231 else if (count * 10 > maximum_count) /* > 10%. */
3232 linestr.insert (0, SGR_SEQ (COLOR_BG_GREEN));
3233 linestr += SGR_RESET;
3236 fprintf (f, "%s:%s", s.c_str (), linestr.c_str ());
3239 static void
3240 print_source_line (FILE *f, const vector<const char *> &source_lines,
3241 unsigned line)
3243 gcc_assert (line >= 1);
3244 gcc_assert (line <= source_lines.size ());
3246 fprintf (f, ":%s\n", source_lines[line - 1]);
3249 /* Output line details for LINE and print it to F file. LINE lives on
3250 LINE_NUM. */
3252 static void
3253 output_line_details (FILE *f, const line_info *line, unsigned line_num)
3255 if (flag_all_blocks)
3257 arc_info *arc;
3258 int jx = 0;
3259 for (vector<block_info *>::const_iterator it = line->blocks.begin ();
3260 it != line->blocks.end (); it++)
3262 if (!(*it)->is_call_return)
3264 output_line_beginning (f, line->exists,
3265 (*it)->exceptional, false,
3266 (*it)->count, line_num,
3267 "%%%%%", "$$$$$", 0);
3268 fprintf (f, "-block %d", (*it)->id);
3269 if (flag_verbose)
3270 fprintf (f, " (BB %u)", (*it)->id);
3271 fprintf (f, "\n");
3273 if (flag_branches)
3274 for (arc = (*it)->succ; arc; arc = arc->succ_next)
3275 jx += output_branch_count (f, jx, arc);
3277 if (flag_conditions)
3278 output_conditions (f, *it);
3281 else
3283 if (flag_branches)
3285 int ix;
3287 ix = 0;
3288 for (vector<arc_info *>::const_iterator it = line->branches.begin ();
3289 it != line->branches.end (); it++)
3290 ix += output_branch_count (f, ix, (*it));
3293 if (flag_conditions)
3295 for (vector<block_info *>::const_iterator it = line->blocks.begin ();
3296 it != line->blocks.end (); it++)
3297 output_conditions (f, *it);
3302 /* Output detail statistics about function FN to file F. */
3304 static void
3305 output_function_details (FILE *f, function_info *fn)
3307 if (!flag_branches)
3308 return;
3310 arc_info *arc = fn->blocks[EXIT_BLOCK].pred;
3311 gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
3312 gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
3314 for (; arc; arc = arc->pred_next)
3315 if (arc->fake)
3316 return_count -= arc->count;
3318 fprintf (f, "function %s", fn->get_name ());
3319 fprintf (f, " called %s",
3320 format_gcov (called_count, 0, -1));
3321 fprintf (f, " returned %s",
3322 format_gcov (return_count, called_count, 0));
3323 fprintf (f, " blocks executed %s",
3324 format_gcov (fn->blocks_executed, fn->get_block_count (), 0));
3325 fprintf (f, "\n");
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. */
3332 static void
3333 output_lines (FILE *gcov_file, const source_info *src)
3335 #define DEFAULT_LINE_START " -: 0:"
3336 #define FN_SEPARATOR "------------------\n"
3338 FILE *source_file;
3339 const char *retval;
3341 /* Print colorization legend. */
3342 if (flag_use_colors)
3343 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");
3351 if (flag_use_hotness_colors)
3352 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");
3358 fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
3359 if (!multiple_files)
3361 fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
3362 fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
3363 no_data_file ? "-" : da_file_name);
3364 fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
3367 source_file = fopen (src->name, "r");
3368 if (!source_file)
3369 fnotice (stderr, "Cannot open source file %s\n", src->name);
3370 else if (src->file_time == 0)
3371 fprintf (gcov_file, DEFAULT_LINE_START "Source is newer than graph\n");
3373 vector<const char *> source_lines;
3374 if (source_file)
3375 while ((retval = read_line (source_file)) != NULL)
3376 source_lines.push_back (xstrdup (retval));
3378 unsigned line_start_group = 0;
3379 vector<function_info *> *fns;
3381 for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
3383 if (line_num >= src->lines.size ())
3385 fprintf (gcov_file, "%9s:%5u", "-", line_num);
3386 print_source_line (gcov_file, source_lines, line_num);
3387 continue;
3390 const line_info *line = &src->lines[line_num];
3392 if (line_start_group == 0)
3394 fns = src->get_functions_at_location (line_num);
3395 if (fns != NULL && fns->size () > 1)
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 for (unsigned i = 0; i < fns->size (); i++)
3401 if ((*fns)[i]->end_line > line_start_group)
3402 line_start_group = (*fns)[i]->end_line;
3404 else if (fns != NULL && fns->size () == 1)
3406 function_info *fn = (*fns)[0];
3407 output_function_details (gcov_file, fn);
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 output_line_beginning (gcov_file, line->exists, line->unexceptional,
3418 line->has_unexecuted_block, line->count,
3419 line_num, "=====", "#####", src->maximum_count);
3421 print_source_line (gcov_file, source_lines, line_num);
3422 output_line_details (gcov_file, line, line_num);
3424 if (line_start_group == line_num)
3426 for (vector<function_info *>::iterator it = fns->begin ();
3427 it != fns->end (); it++)
3429 function_info *fn = *it;
3430 vector<line_info> &lines = fn->lines;
3432 fprintf (gcov_file, FN_SEPARATOR);
3434 string fn_name = fn->get_name ();
3435 if (flag_use_colors)
3437 fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN));
3438 fn_name += SGR_RESET;
3441 fprintf (gcov_file, "%s:\n", fn_name.c_str ());
3443 output_function_details (gcov_file, fn);
3445 /* Print all lines covered by the function. */
3446 for (unsigned i = 0; i < lines.size (); i++)
3448 line_info *line = &lines[i];
3449 unsigned l = fn->start_line + i;
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 output_line_beginning (gcov_file, line->exists,
3459 line->unexceptional,
3460 line->has_unexecuted_block,
3461 line->count,
3462 l, "=====", "#####",
3463 src->maximum_count);
3465 print_source_line (gcov_file, source_lines, l);
3466 output_line_details (gcov_file, line, l);
3470 fprintf (gcov_file, FN_SEPARATOR);
3471 line_start_group = 0;
3475 if (source_file)
3476 fclose (source_file);