1 /* Gcov.c: prepend line execution counts and branch probabilities to a
3 Copyright (C) 1990-2018 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)
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. */
34 #define INCLUDE_ALGORITHM
35 #define INCLUDE_VECTOR
36 #define INCLUDE_STRING
40 #include "coretypes.h"
43 #include "diagnostic.h"
46 #include "color-macros.h"
58 /* The gcno file is generated by -ftest-coverage option. The gcda file is
59 generated by a program compiled with -fprofile-arcs. Their formats
60 are documented in gcov-io.h. */
62 /* The functions in this file for creating and solution program flow graphs
63 are very similar to functions in the gcc source file profile.c. In
64 some places we make use of the knowledge of how profile.c works to
65 select particular algorithms here. */
67 /* The code validates that the profile information read in corresponds
68 to the code currently being compiled. Rather than checking for
69 identical files, the code below compares a checksum on the CFG
70 (based on the order of basic blocks and the arcs in the CFG). If
71 the CFG checksum in the gcda file match the CFG checksum in the
72 gcno file, the profile data will be used. */
74 /* This is the size of the buffer used to read in source file lines. */
80 /* Describes an arc between two basic blocks. */
84 /* source and destination blocks. */
85 struct block_info
*src
;
86 struct block_info
*dst
;
88 /* transition counts. */
90 /* used in cycle search, so that we do not clobber original counts. */
93 unsigned int count_valid
: 1;
94 unsigned int on_tree
: 1;
95 unsigned int fake
: 1;
96 unsigned int fall_through
: 1;
98 /* Arc to a catch handler. */
99 unsigned int is_throw
: 1;
101 /* Arc is for a function that abnormally returns. */
102 unsigned int is_call_non_return
: 1;
104 /* Arc is for catch/setjmp. */
105 unsigned int is_nonlocal_return
: 1;
107 /* Is an unconditional branch. */
108 unsigned int is_unconditional
: 1;
110 /* Loop making arc. */
111 unsigned int cycle
: 1;
113 /* Links to next arc on src and dst lists. */
114 struct arc_info
*succ_next
;
115 struct arc_info
*pred_next
;
118 /* Describes which locations (lines and files) are associated with
121 struct block_location_info
123 block_location_info (unsigned _source_file_idx
):
124 source_file_idx (_source_file_idx
)
127 unsigned source_file_idx
;
128 vector
<unsigned> lines
;
131 /* Describes a basic block. Contains lists of arcs to successor and
132 predecessor blocks. */
139 /* Chain of exit and entry arcs. */
143 /* Number of unprocessed exit and entry arcs. */
149 /* Block execution count. */
151 unsigned count_valid
: 1;
152 unsigned valid_chain
: 1;
153 unsigned invalid_chain
: 1;
154 unsigned exceptional
: 1;
156 /* Block is a call instrumenting site. */
157 unsigned is_call_site
: 1; /* Does the call. */
158 unsigned is_call_return
: 1; /* Is the return. */
160 /* Block is a landing pad for longjmp or throw. */
161 unsigned is_nonlocal_return
: 1;
163 vector
<block_location_info
> locations
;
167 /* Single line graph cycle workspace. Used for all-blocks
171 } cycle
; /* Used in all-blocks mode, after blocks are linked onto
174 /* Temporary chain for solving graph, and for chaining blocks on one
176 struct block_info
*chain
;
180 block_info::block_info (): succ (NULL
), pred (NULL
), num_succ (0), num_pred (0),
181 id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
182 exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
183 locations (), chain (NULL
)
188 /* Describes a single line of source. Contains a chain of basic blocks
193 /* Default constructor. */
196 /* Return true when NEEDLE is one of basic blocks the line belongs to. */
197 bool has_block (block_info
*needle
);
199 /* Execution count. */
202 /* Branches from blocks that end on this line. */
203 vector
<arc_info
*> branches
;
205 /* blocks which start on this line. Used in all-blocks mode. */
206 vector
<block_info
*> blocks
;
209 unsigned unexceptional
: 1;
210 unsigned has_unexecuted_block
: 1;
213 line_info::line_info (): count (0), branches (), blocks (), exists (false),
214 unexceptional (0), has_unexecuted_block (0)
219 line_info::has_block (block_info
*needle
)
221 return std::find (blocks
.begin (), blocks
.end (), needle
) != blocks
.end ();
224 /* Describes a single function. Contains an array of basic blocks. */
231 /* Return true when line N belongs to the function in source file SRC_IDX.
232 The line must be defined in body of the function, can't be inlined. */
233 bool group_line_p (unsigned n
, unsigned src_idx
);
235 /* Function filter based on function_info::artificial variable. */
238 is_artificial (function_info
*fn
)
240 return fn
->artificial
;
243 /* Name of function. */
245 char *demangled_name
;
247 unsigned lineno_checksum
;
248 unsigned cfg_checksum
;
250 /* The graph contains at least one fake incoming edge. */
251 unsigned has_catch
: 1;
253 /* True when the function is artificial and does not exist
255 unsigned artificial
: 1;
257 /* True when multiple functions start at a line in a source file. */
258 unsigned is_group
: 1;
260 /* Array of basic blocks. Like in GCC, the entry block is
261 at blocks[0] and the exit block is at blocks[1]. */
262 #define ENTRY_BLOCK (0)
263 #define EXIT_BLOCK (1)
264 vector
<block_info
> blocks
;
265 unsigned blocks_executed
;
267 /* Raw arc coverage counts. */
268 vector
<gcov_type
> counts
;
270 /* First line number. */
273 /* First line column. */
274 unsigned start_column
;
276 /* Last line number. */
279 /* Index of source file where the function is defined. */
282 /* Vector of line information. */
283 vector
<line_info
> lines
;
286 struct function_info
*next
;
289 /* Function info comparer that will sort functions according to starting
292 struct function_line_start_cmp
294 inline bool operator() (const function_info
*lhs
,
295 const function_info
*rhs
)
297 return (lhs
->start_line
== rhs
->start_line
298 ? lhs
->start_column
< rhs
->start_column
299 : lhs
->start_line
< rhs
->start_line
);
303 /* Describes coverage of a file or function. */
311 int branches_executed
;
320 /* Describes a file mentioned in the block graph. Contains an array
325 /* Default constructor. */
328 vector
<function_info
*> get_functions_at_location (unsigned line_num
) const;
330 /* Index of the source_info in sources vector. */
333 /* Canonical name of source file. */
337 /* Vector of line information. */
338 vector
<line_info
> lines
;
340 coverage_info coverage
;
342 /* Functions in this source file. These are in ascending line
344 vector
<function_info
*> functions
;
347 source_info::source_info (): index (0), name (NULL
), file_time (),
348 lines (), coverage (), functions ()
352 vector
<function_info
*>
353 source_info::get_functions_at_location (unsigned line_num
) const
355 vector
<function_info
*> r
;
357 for (vector
<function_info
*>::const_iterator it
= functions
.begin ();
358 it
!= functions
.end (); it
++)
360 if ((*it
)->start_line
== line_num
&& (*it
)->src
== index
)
364 std::sort (r
.begin (), r
.end (), function_line_start_cmp ());
376 name_map (char *_name
, unsigned _src
): name (_name
), src (_src
)
380 bool operator== (const name_map
&rhs
) const
382 #if HAVE_DOS_BASED_FILE_SYSTEM
383 return strcasecmp (this->name
, rhs
.name
) == 0;
385 return strcmp (this->name
, rhs
.name
) == 0;
389 bool operator< (const name_map
&rhs
) const
391 #if HAVE_DOS_BASED_FILE_SYSTEM
392 return strcasecmp (this->name
, rhs
.name
) < 0;
394 return strcmp (this->name
, rhs
.name
) < 0;
398 const char *name
; /* Source file name */
399 unsigned src
; /* Source file */
402 /* Vector of all functions. */
403 static vector
<function_info
*> functions
;
405 /* Vector of source files. */
406 static vector
<source_info
> sources
;
408 /* Mapping of file names to sources */
409 static vector
<name_map
> names
;
411 /* This holds data summary information. */
413 static unsigned object_runs
;
414 static unsigned program_count
;
416 static unsigned total_lines
;
417 static unsigned total_executed
;
419 /* Modification time of graph file. */
421 static time_t bbg_file_time
;
423 /* Name of the notes (gcno) output file. The "bbg" prefix is for
424 historical reasons, when the notes file contained only the
425 basic block graph notes. */
427 static char *bbg_file_name
;
429 /* Stamp of the bbg file */
430 static unsigned bbg_stamp
;
432 /* Supports has_unexecuted_blocks functionality. */
433 static unsigned bbg_supports_has_unexecuted_blocks
;
435 /* Working directory in which a TU was compiled. */
436 static const char *bbg_cwd
;
438 /* Name and file pointer of the input file for the count data (gcda). */
440 static char *da_file_name
;
442 /* Data file is missing. */
444 static int no_data_file
;
446 /* If there is several input files, compute and display results after
447 reading all data files. This way if two or more gcda file refer to
448 the same source file (eg inline subprograms in a .h file), the
451 static int multiple_files
= 0;
453 /* Output branch probabilities. */
455 static int flag_branches
= 0;
457 /* Show unconditional branches too. */
458 static int flag_unconditional
= 0;
460 /* Output a gcov file if this is true. This is on by default, and can
461 be turned off by the -n option. */
463 static int flag_gcov_file
= 1;
465 /* Output to stdout instead to a gcov file. */
467 static int flag_use_stdout
= 0;
469 /* Output progress indication if this is true. This is off by default
470 and can be turned on by the -d option. */
472 static int flag_display_progress
= 0;
474 /* Output *.gcov file in intermediate format used by 'lcov'. */
476 static int flag_intermediate_format
= 0;
478 /* Output demangled function names. */
480 static int flag_demangled_names
= 0;
482 /* For included files, make the gcov output file name include the name
483 of the input source file. For example, if x.h is included in a.c,
484 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
486 static int flag_long_names
= 0;
488 /* For situations when a long name can potentially hit filesystem path limit,
489 let's calculate md5sum of the path and append it to a file name. */
491 static int flag_hash_filenames
= 0;
493 /* Print verbose informations. */
495 static int flag_verbose
= 0;
497 /* Print colored output. */
499 static int flag_use_colors
= 0;
501 /* Output count information for every basic block, not merely those
502 that contain line number information. */
504 static int flag_all_blocks
= 0;
506 /* Output human readable numbers. */
508 static int flag_human_readable_numbers
= 0;
510 /* Output summary info for each function. */
512 static int flag_function_summary
= 0;
514 /* Object directory file prefix. This is the directory/file where the
515 graph and data files are looked for, if nonzero. */
517 static char *object_directory
= 0;
519 /* Source directory prefix. This is removed from source pathnames
520 that match, when generating the output file name. */
522 static char *source_prefix
= 0;
523 static size_t source_length
= 0;
525 /* Only show data for sources with relative pathnames. Absolute ones
526 usually indicate a system header file, which although it may
527 contain inline functions, is usually uninteresting. */
528 static int flag_relative_only
= 0;
530 /* Preserve all pathname components. Needed when object files and
531 source files are in subdirectories. '/' is mangled as '#', '.' is
532 elided and '..' mangled to '^'. */
534 static int flag_preserve_paths
= 0;
536 /* Output the number of times a branch was taken as opposed to the percentage
537 of times it was taken. */
539 static int flag_counts
= 0;
541 /* Forward declarations. */
542 static int process_args (int, char **);
543 static void print_usage (int) ATTRIBUTE_NORETURN
;
544 static void print_version (void) ATTRIBUTE_NORETURN
;
545 static void process_file (const char *);
546 static void process_all_functions (void);
547 static void generate_results (const char *);
548 static void create_file_names (const char *);
549 static char *canonicalize_name (const char *);
550 static unsigned find_source (const char *);
551 static void read_graph_file (void);
552 static int read_count_file (void);
553 static void solve_flow_graph (function_info
*);
554 static void find_exception_blocks (function_info
*);
555 static void add_branch_counts (coverage_info
*, const arc_info
*);
556 static void add_line_counts (coverage_info
*, function_info
*);
557 static void executed_summary (unsigned, unsigned);
558 static void function_summary (const coverage_info
*, const char *);
559 static const char *format_gcov (gcov_type
, gcov_type
, int);
560 static void accumulate_line_counts (source_info
*);
561 static void output_gcov_file (const char *, source_info
*);
562 static int output_branch_count (FILE *, int, const arc_info
*);
563 static void output_lines (FILE *, const source_info
*);
564 static char *make_gcov_file_name (const char *, const char *);
565 static char *mangle_name (const char *, char *);
566 static void release_structures (void);
567 extern int main (int, char **);
569 function_info::function_info (): name (NULL
), demangled_name (NULL
),
570 ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
571 artificial (0), is_group (0),
572 blocks (), blocks_executed (0), counts (),
573 start_line (0), start_column (), end_line (0), src (0), lines (), next (NULL
)
577 function_info::~function_info ()
579 for (int i
= blocks
.size () - 1; i
>= 0; i
--)
581 arc_info
*arc
, *arc_n
;
583 for (arc
= blocks
[i
].succ
; arc
; arc
= arc_n
)
585 arc_n
= arc
->succ_next
;
589 if (flag_demangled_names
&& demangled_name
!= name
)
590 free (demangled_name
);
594 bool function_info::group_line_p (unsigned n
, unsigned src_idx
)
596 return is_group
&& src
== src_idx
&& start_line
<= n
&& n
<= end_line
;
600 There are a bajillion algorithms that do this. Boost's function is named
601 hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
602 "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
603 (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
605 The basic algorithm is simple: effectively, we're finding all simple paths
606 in a subgraph (that shrinks every iteration). Duplicates are filtered by
607 "blocking" a path when a node is added to the path (this also prevents non-
608 simple paths)--the node is unblocked only when it participates in a cycle.
611 typedef vector
<arc_info
*> arc_vector_t
;
612 typedef vector
<const block_info
*> block_vector_t
;
614 /* Enum with types of loop in CFG. */
623 /* Loop_type operator that merges two values: A and B. */
625 inline loop_type
& operator |= (loop_type
& a
, loop_type b
)
627 return a
= static_cast<loop_type
> (a
| b
);
630 /* Handle cycle identified by EDGES, where the function finds minimum cs_count
631 and subtract the value from all counts. The subtracted value is added
632 to COUNT. Returns type of loop. */
635 handle_cycle (const arc_vector_t
&edges
, int64_t &count
)
637 /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
639 int64_t cycle_count
= INTTYPE_MAXIMUM (int64_t);
640 for (unsigned i
= 0; i
< edges
.size (); i
++)
642 int64_t ecount
= edges
[i
]->cs_count
;
643 if (cycle_count
> ecount
)
644 cycle_count
= ecount
;
646 count
+= cycle_count
;
647 for (unsigned i
= 0; i
< edges
.size (); i
++)
648 edges
[i
]->cs_count
-= cycle_count
;
650 return cycle_count
< 0 ? NEGATIVE_LOOP
: LOOP
;
653 /* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
654 blocked by U in BLOCK_LISTS. */
657 unblock (const block_info
*u
, block_vector_t
&blocked
,
658 vector
<block_vector_t
> &block_lists
)
660 block_vector_t::iterator it
= find (blocked
.begin (), blocked
.end (), u
);
661 if (it
== blocked
.end ())
664 unsigned index
= it
- blocked
.begin ();
667 block_vector_t
to_unblock (block_lists
[index
]);
669 block_lists
.erase (block_lists
.begin () + index
);
671 for (block_vector_t::iterator it
= to_unblock
.begin ();
672 it
!= to_unblock
.end (); it
++)
673 unblock (*it
, blocked
, block_lists
);
676 /* Find circuit going to block V, PATH is provisional seen cycle.
677 BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
678 blocked by a block. COUNT is accumulated count of the current LINE.
679 Returns what type of loop it contains. */
682 circuit (block_info
*v
, arc_vector_t
&path
, block_info
*start
,
683 block_vector_t
&blocked
, vector
<block_vector_t
> &block_lists
,
684 line_info
&linfo
, int64_t &count
)
686 loop_type result
= NO_LOOP
;
688 /* Add v to the block list. */
689 gcc_assert (find (blocked
.begin (), blocked
.end (), v
) == blocked
.end ());
690 blocked
.push_back (v
);
691 block_lists
.push_back (block_vector_t ());
693 for (arc_info
*arc
= v
->succ
; arc
; arc
= arc
->succ_next
)
695 block_info
*w
= arc
->dst
;
696 if (w
< start
|| !linfo
.has_block (w
))
699 path
.push_back (arc
);
701 /* Cycle has been found. */
702 result
|= handle_cycle (path
, count
);
703 else if (find (blocked
.begin (), blocked
.end (), w
) == blocked
.end ())
704 result
|= circuit (w
, path
, start
, blocked
, block_lists
, linfo
, count
);
709 if (result
!= NO_LOOP
)
710 unblock (v
, blocked
, block_lists
);
712 for (arc_info
*arc
= v
->succ
; arc
; arc
= arc
->succ_next
)
714 block_info
*w
= arc
->dst
;
715 if (w
< start
|| !linfo
.has_block (w
))
719 = find (blocked
.begin (), blocked
.end (), w
) - blocked
.begin ();
720 gcc_assert (index
< blocked
.size ());
721 block_vector_t
&list
= block_lists
[index
];
722 if (find (list
.begin (), list
.end (), v
) == list
.end ())
729 /* Find cycles for a LINFO. If HANDLE_NEGATIVE_CYCLES is set and the line
730 contains a negative loop, then perform the same function once again. */
733 get_cycles_count (line_info
&linfo
, bool handle_negative_cycles
= true)
735 /* Note that this algorithm works even if blocks aren't in sorted order.
736 Each iteration of the circuit detection is completely independent
737 (except for reducing counts, but that shouldn't matter anyways).
738 Therefore, operating on a permuted order (i.e., non-sorted) only
739 has the effect of permuting the output cycles. */
741 loop_type result
= NO_LOOP
;
743 for (vector
<block_info
*>::iterator it
= linfo
.blocks
.begin ();
744 it
!= linfo
.blocks
.end (); it
++)
747 block_vector_t blocked
;
748 vector
<block_vector_t
> block_lists
;
749 result
|= circuit (*it
, path
, *it
, blocked
, block_lists
, linfo
,
753 /* If we have a negative cycle, repeat the find_cycles routine. */
754 if (result
== NEGATIVE_LOOP
&& handle_negative_cycles
)
755 count
+= get_cycles_count (linfo
, false);
761 main (int argc
, char **argv
)
767 p
= argv
[0] + strlen (argv
[0]);
768 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
772 xmalloc_set_program_name (progname
);
774 /* Unlock the stdio streams. */
775 unlock_std_streams ();
779 diagnostic_initialize (global_dc
, 0);
781 /* Handle response files. */
782 expandargv (&argc
, &argv
);
784 argno
= process_args (argc
, argv
);
788 if (argc
- argno
> 1)
793 for (; argno
!= argc
; argno
++)
795 if (flag_display_progress
)
796 printf ("Processing file %d out of %d\n", argno
- first_arg
+ 1,
798 process_file (argv
[argno
]);
800 if (flag_intermediate_format
|| argno
== argc
- 1)
802 process_all_functions ();
803 generate_results (argv
[argno
]);
804 release_structures ();
811 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
812 otherwise the output of --help. */
815 print_usage (int error_p
)
817 FILE *file
= error_p
? stderr
: stdout
;
818 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
820 fnotice (file
, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
821 fnotice (file
, "Print code coverage information.\n\n");
822 fnotice (file
, " -a, --all-blocks Show information for every basic block\n");
823 fnotice (file
, " -b, --branch-probabilities Include branch probabilities in output\n");
824 fnotice (file
, " -c, --branch-counts Output counts of branches taken\n\
825 rather than percentages\n");
826 fnotice (file
, " -d, --display-progress Display progress information\n");
827 fnotice (file
, " -f, --function-summaries Output summaries for each function\n");
828 fnotice (file
, " -h, --help Print this help, then exit\n");
829 fnotice (file
, " -i, --intermediate-format Output .gcov file in intermediate text format\n");
830 fnotice (file
, " -j, --human-readable Output human readable numbers\n");
831 fnotice (file
, " -k, --use-colors Emit colored output\n");
832 fnotice (file
, " -l, --long-file-names Use long output file names for included\n\
834 fnotice (file
, " -m, --demangled-names Output demangled function names\n");
835 fnotice (file
, " -n, --no-output Do not create an output file\n");
836 fnotice (file
, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
837 fnotice (file
, " -p, --preserve-paths Preserve all pathname components\n");
838 fnotice (file
, " -r, --relative-only Only show data for relative sources\n");
839 fnotice (file
, " -s, --source-prefix DIR Source prefix to elide\n");
840 fnotice (file
, " -t, --stdout Output to stdout instead of a file\n");
841 fnotice (file
, " -u, --unconditional-branches Show unconditional branch counts too\n");
842 fnotice (file
, " -v, --version Print version number, then exit\n");
843 fnotice (file
, " -w, --verbose Print verbose informations\n");
844 fnotice (file
, " -x, --hash-filenames Hash long pathnames\n");
845 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
850 /* Print version information and exit. */
855 fnotice (stdout
, "gcov %s%s\n", pkgversion_string
, version_string
);
856 fprintf (stdout
, "Copyright %s 2018 Free Software Foundation, Inc.\n",
859 _("This is free software; see the source for copying conditions.\n"
860 "There is NO warranty; not even for MERCHANTABILITY or \n"
861 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
862 exit (SUCCESS_EXIT_CODE
);
865 static const struct option options
[] =
867 { "help", no_argument
, NULL
, 'h' },
868 { "version", no_argument
, NULL
, 'v' },
869 { "verbose", no_argument
, NULL
, 'w' },
870 { "all-blocks", no_argument
, NULL
, 'a' },
871 { "branch-probabilities", no_argument
, NULL
, 'b' },
872 { "branch-counts", no_argument
, NULL
, 'c' },
873 { "intermediate-format", no_argument
, NULL
, 'i' },
874 { "human-readable", no_argument
, NULL
, 'j' },
875 { "no-output", no_argument
, NULL
, 'n' },
876 { "long-file-names", no_argument
, NULL
, 'l' },
877 { "function-summaries", no_argument
, NULL
, 'f' },
878 { "demangled-names", no_argument
, NULL
, 'm' },
879 { "preserve-paths", no_argument
, NULL
, 'p' },
880 { "relative-only", no_argument
, NULL
, 'r' },
881 { "object-directory", required_argument
, NULL
, 'o' },
882 { "object-file", required_argument
, NULL
, 'o' },
883 { "source-prefix", required_argument
, NULL
, 's' },
884 { "stdout", no_argument
, NULL
, 't' },
885 { "unconditional-branches", no_argument
, NULL
, 'u' },
886 { "display-progress", no_argument
, NULL
, 'd' },
887 { "hash-filenames", no_argument
, NULL
, 'x' },
888 { "use-colors", no_argument
, NULL
, 'k' },
892 /* Process args, return index to first non-arg. */
895 process_args (int argc
, char **argv
)
899 const char *opts
= "abcdfhijklmno:prs:tuvwx";
900 while ((opt
= getopt_long (argc
, argv
, opts
, options
, NULL
)) != -1)
914 flag_function_summary
= 1;
918 /* print_usage will exit. */
923 flag_human_readable_numbers
= 1;
929 flag_demangled_names
= 1;
935 object_directory
= optarg
;
938 source_prefix
= optarg
;
939 source_length
= strlen (source_prefix
);
942 flag_relative_only
= 1;
945 flag_preserve_paths
= 1;
948 flag_unconditional
= 1;
951 flag_intermediate_format
= 1;
955 flag_display_progress
= 1;
958 flag_hash_filenames
= 1;
968 /* print_version will exit. */
971 /* print_usage will exit. */
978 /* Output intermediate LINE sitting on LINE_NUM to output file F. */
981 output_intermediate_line (FILE *f
, line_info
*line
, unsigned line_num
)
986 fprintf (f
, "lcount:%u,%s,%d\n", line_num
,
987 format_gcov (line
->count
, 0, -1),
988 line
->has_unexecuted_block
);
990 vector
<arc_info
*>::const_iterator it
;
992 for (it
= line
->branches
.begin (); it
!= line
->branches
.end ();
995 if (!(*it
)->is_unconditional
&& !(*it
)->is_call_non_return
)
997 const char *branch_type
;
998 /* branch:<line_num>,<branch_coverage_infoype>
999 branch_coverage_infoype
1000 : notexec (Branch not executed)
1001 : taken (Branch executed and taken)
1002 : nottaken (Branch executed, but not taken)
1004 if ((*it
)->src
->count
)
1006 = ((*it
)->count
> 0) ? "taken" : "nottaken";
1008 branch_type
= "notexec";
1009 fprintf (f
, "branch:%d,%s\n", line_num
, branch_type
);
1014 /* Get the name of the gcov file. The return value must be free'd.
1016 It appends the '.gcov' extension to the *basename* of the file.
1017 The resulting file name will be in PWD.
1020 input: foo.da, output: foo.da.gcov
1021 input: a/b/foo.cc, output: foo.cc.gcov */
1024 get_gcov_intermediate_filename (const char *file_name
)
1026 const char *gcov
= ".gcov";
1030 /* Find the 'basename'. */
1031 cptr
= lbasename (file_name
);
1033 result
= XNEWVEC (char, strlen (cptr
) + strlen (gcov
) + 1);
1034 sprintf (result
, "%s%s", cptr
, gcov
);
1039 /* Output the result in intermediate format used by 'lcov'.
1041 The intermediate format contains a single file named 'foo.cc.gcov',
1042 with no source code included.
1044 The default gcov outputs multiple files: 'foo.cc.gcov',
1045 'iostream.gcov', 'ios_base.h.gcov', etc. with source code
1046 included. Instead the intermediate format here outputs only a single
1047 file 'foo.cc.gcov' similar to the above example. */
1050 output_intermediate_file (FILE *gcov_file
, source_info
*src
)
1052 fprintf (gcov_file
, "version:%s\n", version_string
);
1053 fprintf (gcov_file
, "file:%s\n", src
->name
); /* source file name */
1054 fprintf (gcov_file
, "cwd:%s\n", bbg_cwd
);
1056 std::sort (src
->functions
.begin (), src
->functions
.end (),
1057 function_line_start_cmp ());
1058 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
1059 it
!= src
->functions
.end (); it
++)
1061 /* function:<name>,<line_number>,<execution_count> */
1062 fprintf (gcov_file
, "function:%d,%d,%s,%s\n", (*it
)->start_line
,
1063 (*it
)->end_line
, format_gcov ((*it
)->blocks
[0].count
, 0, -1),
1064 flag_demangled_names
? (*it
)->demangled_name
: (*it
)->name
);
1067 for (unsigned line_num
= 1; line_num
<= src
->lines
.size (); line_num
++)
1069 vector
<function_info
*> fns
= src
->get_functions_at_location (line_num
);
1071 /* Print first group functions that begin on the line. */
1072 for (vector
<function_info
*>::iterator it2
= fns
.begin ();
1073 it2
!= fns
.end (); it2
++)
1075 vector
<line_info
> &lines
= (*it2
)->lines
;
1076 for (unsigned i
= 0; i
< lines
.size (); i
++)
1078 line_info
*line
= &lines
[i
];
1079 output_intermediate_line (gcov_file
, line
, line_num
+ i
);
1083 /* Follow with lines associated with the source file. */
1084 output_intermediate_line (gcov_file
, &src
->lines
[line_num
], line_num
);
1088 /* Function start pair. */
1089 struct function_start
1091 unsigned source_file_idx
;
1092 unsigned start_line
;
1095 /* Traits class for function start hash maps below. */
1097 struct function_start_pair_hash
: typed_noop_remove
<function_start
>
1099 typedef function_start value_type
;
1100 typedef function_start compare_type
;
1103 hash (const function_start
&ref
)
1105 inchash::hash
hstate (0);
1106 hstate
.add_int (ref
.source_file_idx
);
1107 hstate
.add_int (ref
.start_line
);
1108 return hstate
.end ();
1112 equal (const function_start
&ref1
, const function_start
&ref2
)
1114 return (ref1
.source_file_idx
== ref2
.source_file_idx
1115 && ref1
.start_line
== ref2
.start_line
);
1119 mark_deleted (function_start
&ref
)
1121 ref
.start_line
= ~1U;
1125 mark_empty (function_start
&ref
)
1127 ref
.start_line
= ~2U;
1131 is_deleted (const function_start
&ref
)
1133 return ref
.start_line
== ~1U;
1137 is_empty (const function_start
&ref
)
1139 return ref
.start_line
== ~2U;
1143 /* Process a single input file. */
1146 process_file (const char *file_name
)
1148 create_file_names (file_name
);
1153 /* Process all functions in all files. */
1156 process_all_functions (void)
1158 hash_map
<function_start_pair_hash
, function_info
*> fn_map
;
1160 /* Identify group functions. */
1161 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1162 it
!= functions
.end (); it
++)
1163 if (!(*it
)->artificial
)
1165 function_start needle
;
1166 needle
.source_file_idx
= (*it
)->src
;
1167 needle
.start_line
= (*it
)->start_line
;
1169 function_info
**slot
= fn_map
.get (needle
);
1172 (*slot
)->is_group
= 1;
1173 (*it
)->is_group
= 1;
1176 fn_map
.put (needle
, *it
);
1179 /* Remove all artificial function. */
1180 functions
.erase (remove_if (functions
.begin (), functions
.end (),
1181 function_info::is_artificial
), functions
.end ());
1183 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1184 it
!= functions
.end (); it
++)
1186 function_info
*fn
= *it
;
1187 unsigned src
= fn
->src
;
1189 if (!fn
->counts
.empty () || no_data_file
)
1191 source_info
*s
= &sources
[src
];
1192 s
->functions
.push_back (fn
);
1194 /* Mark last line in files touched by function. */
1195 for (unsigned block_no
= 0; block_no
!= fn
->blocks
.size ();
1198 block_info
*block
= &fn
->blocks
[block_no
];
1199 for (unsigned i
= 0; i
< block
->locations
.size (); i
++)
1201 /* Sort lines of locations. */
1202 sort (block
->locations
[i
].lines
.begin (),
1203 block
->locations
[i
].lines
.end ());
1205 if (!block
->locations
[i
].lines
.empty ())
1207 s
= &sources
[block
->locations
[i
].source_file_idx
];
1209 = block
->locations
[i
].lines
.back ();
1211 /* Record new lines for the function. */
1212 if (last_line
>= s
->lines
.size ())
1214 s
= &sources
[block
->locations
[i
].source_file_idx
];
1216 = block
->locations
[i
].lines
.back ();
1218 /* Record new lines for the function. */
1219 if (last_line
>= s
->lines
.size ())
1221 /* Record new lines for a source file. */
1222 s
->lines
.resize (last_line
+ 1);
1229 /* Allocate lines for group function, following start_line
1230 and end_line information of the function. */
1232 fn
->lines
.resize (fn
->end_line
- fn
->start_line
+ 1);
1234 solve_flow_graph (fn
);
1236 find_exception_blocks (fn
);
1240 /* The function was not in the executable -- some other
1241 instance must have been selected. */
1247 output_gcov_file (const char *file_name
, source_info
*src
)
1249 char *gcov_file_name
= make_gcov_file_name (file_name
, src
->coverage
.name
);
1251 if (src
->coverage
.lines
)
1253 FILE *gcov_file
= fopen (gcov_file_name
, "w");
1256 fnotice (stdout
, "Creating '%s'\n", gcov_file_name
);
1257 output_lines (gcov_file
, src
);
1258 if (ferror (gcov_file
))
1259 fnotice (stderr
, "Error writing output file '%s'\n",
1264 fnotice (stderr
, "Could not open output file '%s'\n", gcov_file_name
);
1268 unlink (gcov_file_name
);
1269 fnotice (stdout
, "Removing '%s'\n", gcov_file_name
);
1271 free (gcov_file_name
);
1275 generate_results (const char *file_name
)
1277 FILE *gcov_intermediate_file
= NULL
;
1278 char *gcov_intermediate_filename
= NULL
;
1280 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1281 it
!= functions
.end (); it
++)
1283 function_info
*fn
= *it
;
1284 coverage_info coverage
;
1286 memset (&coverage
, 0, sizeof (coverage
));
1287 coverage
.name
= flag_demangled_names
? fn
->demangled_name
: fn
->name
;
1288 add_line_counts (flag_function_summary
? &coverage
: NULL
, fn
);
1289 if (flag_function_summary
)
1291 function_summary (&coverage
, "Function");
1292 fnotice (stdout
, "\n");
1300 needle
.name
= file_name
;
1301 vector
<name_map
>::iterator it
= std::find (names
.begin (), names
.end (),
1303 if (it
!= names
.end ())
1304 file_name
= sources
[it
->src
].coverage
.name
;
1306 file_name
= canonicalize_name (file_name
);
1309 if (flag_gcov_file
&& flag_intermediate_format
&& !flag_use_stdout
)
1311 /* Open the intermediate file. */
1312 gcov_intermediate_filename
= get_gcov_intermediate_filename (file_name
);
1313 gcov_intermediate_file
= fopen (gcov_intermediate_filename
, "w");
1314 if (!gcov_intermediate_file
)
1316 fnotice (stderr
, "Cannot open intermediate output file %s\n",
1317 gcov_intermediate_filename
);
1322 for (vector
<source_info
>::iterator it
= sources
.begin ();
1323 it
!= sources
.end (); it
++)
1325 source_info
*src
= &(*it
);
1326 if (flag_relative_only
)
1328 /* Ignore this source, if it is an absolute path (after
1329 source prefix removal). */
1330 char first
= src
->coverage
.name
[0];
1332 #if HAVE_DOS_BASED_FILE_SYSTEM
1333 if (first
&& src
->coverage
.name
[1] == ':')
1334 first
= src
->coverage
.name
[2];
1336 if (IS_DIR_SEPARATOR (first
))
1340 accumulate_line_counts (src
);
1342 if (!flag_use_stdout
)
1343 function_summary (&src
->coverage
, "File");
1344 total_lines
+= src
->coverage
.lines
;
1345 total_executed
+= src
->coverage
.lines_executed
;
1348 if (flag_intermediate_format
)
1349 /* Output the intermediate format without requiring source
1350 files. This outputs a section to a *single* file. */
1351 output_intermediate_file ((flag_use_stdout
1352 ? stdout
: gcov_intermediate_file
), src
);
1355 if (flag_use_stdout
)
1357 if (src
->coverage
.lines
)
1358 output_lines (stdout
, src
);
1362 output_gcov_file (file_name
, src
);
1363 fnotice (stdout
, "\n");
1369 if (flag_gcov_file
&& flag_intermediate_format
&& !flag_use_stdout
)
1371 /* Now we've finished writing the intermediate file. */
1372 fclose (gcov_intermediate_file
);
1373 XDELETEVEC (gcov_intermediate_filename
);
1377 executed_summary (total_lines
, total_executed
);
1380 /* Release all memory used. */
1383 release_structures (void)
1385 for (vector
<function_info
*>::iterator it
= functions
.begin ();
1386 it
!= functions
.end (); it
++)
1391 functions
.resize (0);
1394 /* Generate the names of the graph and data files. If OBJECT_DIRECTORY
1395 is not specified, these are named from FILE_NAME sans extension. If
1396 OBJECT_DIRECTORY is specified and is a directory, the files are in that
1397 directory, but named from the basename of the FILE_NAME, sans extension.
1398 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
1399 and the data files are named from that. */
1402 create_file_names (const char *file_name
)
1406 int length
= strlen (file_name
);
1409 /* Free previous file names. */
1410 free (bbg_file_name
);
1411 free (da_file_name
);
1412 da_file_name
= bbg_file_name
= NULL
;
1416 if (object_directory
&& object_directory
[0])
1420 length
+= strlen (object_directory
) + 2;
1421 name
= XNEWVEC (char, length
);
1424 base
= !stat (object_directory
, &status
) && S_ISDIR (status
.st_mode
);
1425 strcat (name
, object_directory
);
1426 if (base
&& (!IS_DIR_SEPARATOR (name
[strlen (name
) - 1])))
1431 name
= XNEWVEC (char, length
+ 1);
1432 strcpy (name
, file_name
);
1438 /* Append source file name. */
1439 const char *cptr
= lbasename (file_name
);
1440 strcat (name
, cptr
? cptr
: file_name
);
1443 /* Remove the extension. */
1444 cptr
= strrchr (CONST_CAST (char *, lbasename (name
)), '.');
1448 length
= strlen (name
);
1450 bbg_file_name
= XNEWVEC (char, length
+ strlen (GCOV_NOTE_SUFFIX
) + 1);
1451 strcpy (bbg_file_name
, name
);
1452 strcpy (bbg_file_name
+ length
, GCOV_NOTE_SUFFIX
);
1454 da_file_name
= XNEWVEC (char, length
+ strlen (GCOV_DATA_SUFFIX
) + 1);
1455 strcpy (da_file_name
, name
);
1456 strcpy (da_file_name
+ length
, GCOV_DATA_SUFFIX
);
1462 /* Find or create a source file structure for FILE_NAME. Copies
1463 FILE_NAME on creation */
1466 find_source (const char *file_name
)
1473 file_name
= "<unknown>";
1476 needle
.name
= file_name
;
1478 vector
<name_map
>::iterator it
= std::find (names
.begin (), names
.end (),
1480 if (it
!= names
.end ())
1486 /* Not found, try the canonical name. */
1487 canon
= canonicalize_name (file_name
);
1488 needle
.name
= canon
;
1489 it
= std::find (names
.begin (), names
.end (), needle
);
1490 if (it
== names
.end ())
1492 /* Not found with canonical name, create a new source. */
1495 idx
= sources
.size ();
1496 needle
= name_map (canon
, idx
);
1497 names
.push_back (needle
);
1499 sources
.push_back (source_info ());
1500 src
= &sources
.back ();
1502 src
->coverage
.name
= src
->name
;
1505 #if HAVE_DOS_BASED_FILE_SYSTEM
1506 /* You lose if separators don't match exactly in the
1508 && !strncasecmp (source_prefix
, src
->coverage
.name
, source_length
)
1510 && !strncmp (source_prefix
, src
->coverage
.name
, source_length
)
1512 && IS_DIR_SEPARATOR (src
->coverage
.name
[source_length
]))
1513 src
->coverage
.name
+= source_length
+ 1;
1514 if (!stat (src
->name
, &status
))
1515 src
->file_time
= status
.st_mtime
;
1520 needle
.name
= file_name
;
1521 if (std::find (names
.begin (), names
.end (), needle
) == names
.end ())
1523 /* Append the non-canonical name. */
1524 names
.push_back (name_map (xstrdup (file_name
), idx
));
1527 /* Resort the name map. */
1528 std::sort (names
.begin (), names
.end ());
1531 if (sources
[idx
].file_time
> bbg_file_time
)
1533 static int info_emitted
;
1535 fnotice (stderr
, "%s:source file is newer than notes file '%s'\n",
1536 file_name
, bbg_file_name
);
1540 "(the message is displayed only once per source file)\n");
1543 sources
[idx
].file_time
= 0;
1549 /* Read the notes file. Save functions to FUNCTIONS global vector. */
1552 read_graph_file (void)
1555 unsigned current_tag
= 0;
1558 if (!gcov_open (bbg_file_name
, 1))
1560 fnotice (stderr
, "%s:cannot open notes file\n", bbg_file_name
);
1563 bbg_file_time
= gcov_time ();
1564 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC
))
1566 fnotice (stderr
, "%s:not a gcov notes file\n", bbg_file_name
);
1571 version
= gcov_read_unsigned ();
1572 if (version
!= GCOV_VERSION
)
1576 GCOV_UNSIGNED2STRING (v
, version
);
1577 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1579 fnotice (stderr
, "%s:version '%.4s', prefer '%.4s'\n",
1580 bbg_file_name
, v
, e
);
1582 bbg_stamp
= gcov_read_unsigned ();
1583 bbg_cwd
= xstrdup (gcov_read_string ());
1584 bbg_supports_has_unexecuted_blocks
= gcov_read_unsigned ();
1586 function_info
*fn
= NULL
;
1587 while ((tag
= gcov_read_unsigned ()))
1589 unsigned length
= gcov_read_unsigned ();
1590 gcov_position_t base
= gcov_position ();
1592 if (tag
== GCOV_TAG_FUNCTION
)
1594 char *function_name
;
1596 unsigned lineno_checksum
, cfg_checksum
;
1598 ident
= gcov_read_unsigned ();
1599 lineno_checksum
= gcov_read_unsigned ();
1600 cfg_checksum
= gcov_read_unsigned ();
1601 function_name
= xstrdup (gcov_read_string ());
1602 unsigned artificial
= gcov_read_unsigned ();
1603 unsigned src_idx
= find_source (gcov_read_string ());
1604 unsigned start_line
= gcov_read_unsigned ();
1605 unsigned start_column
= gcov_read_unsigned ();
1606 unsigned end_line
= gcov_read_unsigned ();
1608 fn
= new function_info ();
1609 functions
.push_back (fn
);
1610 fn
->name
= function_name
;
1611 if (flag_demangled_names
)
1613 fn
->demangled_name
= cplus_demangle (fn
->name
, DMGL_PARAMS
);
1614 if (!fn
->demangled_name
)
1615 fn
->demangled_name
= fn
->name
;
1618 fn
->lineno_checksum
= lineno_checksum
;
1619 fn
->cfg_checksum
= cfg_checksum
;
1621 fn
->start_line
= start_line
;
1622 fn
->start_column
= start_column
;
1623 fn
->end_line
= end_line
;
1624 fn
->artificial
= artificial
;
1628 else if (fn
&& tag
== GCOV_TAG_BLOCKS
)
1630 if (!fn
->blocks
.empty ())
1631 fnotice (stderr
, "%s:already seen blocks for '%s'\n",
1632 bbg_file_name
, fn
->name
);
1634 fn
->blocks
.resize (gcov_read_unsigned ());
1636 else if (fn
&& tag
== GCOV_TAG_ARCS
)
1638 unsigned src
= gcov_read_unsigned ();
1639 fn
->blocks
[src
].id
= src
;
1640 unsigned num_dests
= GCOV_TAG_ARCS_NUM (length
);
1641 block_info
*src_blk
= &fn
->blocks
[src
];
1642 unsigned mark_catches
= 0;
1643 struct arc_info
*arc
;
1645 if (src
>= fn
->blocks
.size () || fn
->blocks
[src
].succ
)
1650 unsigned dest
= gcov_read_unsigned ();
1651 unsigned flags
= gcov_read_unsigned ();
1653 if (dest
>= fn
->blocks
.size ())
1655 arc
= XCNEW (arc_info
);
1657 arc
->dst
= &fn
->blocks
[dest
];
1661 arc
->count_valid
= 0;
1662 arc
->on_tree
= !!(flags
& GCOV_ARC_ON_TREE
);
1663 arc
->fake
= !!(flags
& GCOV_ARC_FAKE
);
1664 arc
->fall_through
= !!(flags
& GCOV_ARC_FALLTHROUGH
);
1666 arc
->succ_next
= src_blk
->succ
;
1667 src_blk
->succ
= arc
;
1668 src_blk
->num_succ
++;
1670 arc
->pred_next
= fn
->blocks
[dest
].pred
;
1671 fn
->blocks
[dest
].pred
= arc
;
1672 fn
->blocks
[dest
].num_pred
++;
1678 /* Exceptional exit from this function, the
1679 source block must be a call. */
1680 fn
->blocks
[src
].is_call_site
= 1;
1681 arc
->is_call_non_return
= 1;
1686 /* Non-local return from a callee of this
1687 function. The destination block is a setjmp. */
1688 arc
->is_nonlocal_return
= 1;
1689 fn
->blocks
[dest
].is_nonlocal_return
= 1;
1694 fn
->counts
.push_back (0);
1699 /* We have a fake exit from this block. The other
1700 non-fall through exits must be to catch handlers.
1701 Mark them as catch arcs. */
1703 for (arc
= src_blk
->succ
; arc
; arc
= arc
->succ_next
)
1704 if (!arc
->fake
&& !arc
->fall_through
)
1711 else if (fn
&& tag
== GCOV_TAG_LINES
)
1713 unsigned blockno
= gcov_read_unsigned ();
1714 block_info
*block
= &fn
->blocks
[blockno
];
1716 if (blockno
>= fn
->blocks
.size ())
1721 unsigned lineno
= gcov_read_unsigned ();
1724 block
->locations
.back ().lines
.push_back (lineno
);
1727 const char *file_name
= gcov_read_string ();
1731 block
->locations
.push_back (block_location_info
1732 (find_source (file_name
)));
1736 else if (current_tag
&& !GCOV_TAG_IS_SUBTAG (current_tag
, tag
))
1741 gcov_sync (base
, length
);
1742 if (gcov_is_error ())
1745 fnotice (stderr
, "%s:corrupted\n", bbg_file_name
);
1751 if (functions
.empty ())
1752 fnotice (stderr
, "%s:no functions found\n", bbg_file_name
);
1755 /* Reads profiles from the count file and attach to each
1756 function. Return nonzero if fatal error. */
1759 read_count_file (void)
1764 function_info
*fn
= NULL
;
1767 if (!gcov_open (da_file_name
, 1))
1769 fnotice (stderr
, "%s:cannot open data file, assuming not executed\n",
1774 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
1776 fnotice (stderr
, "%s:not a gcov data file\n", da_file_name
);
1781 version
= gcov_read_unsigned ();
1782 if (version
!= GCOV_VERSION
)
1786 GCOV_UNSIGNED2STRING (v
, version
);
1787 GCOV_UNSIGNED2STRING (e
, GCOV_VERSION
);
1789 fnotice (stderr
, "%s:version '%.4s', prefer version '%.4s'\n",
1790 da_file_name
, v
, e
);
1792 tag
= gcov_read_unsigned ();
1793 if (tag
!= bbg_stamp
)
1795 fnotice (stderr
, "%s:stamp mismatch with notes file\n", da_file_name
);
1799 while ((tag
= gcov_read_unsigned ()))
1801 unsigned length
= gcov_read_unsigned ();
1802 unsigned long base
= gcov_position ();
1804 if (tag
== GCOV_TAG_PROGRAM_SUMMARY
)
1806 struct gcov_summary summary
;
1807 gcov_read_summary (&summary
);
1808 object_runs
+= summary
.runs
;
1811 else if (tag
== GCOV_TAG_FUNCTION
&& !length
)
1813 else if (tag
== GCOV_TAG_FUNCTION
&& length
== GCOV_TAG_FUNCTION_LENGTH
)
1817 /* Try to find the function in the list. To speed up the
1818 search, first start from the last function found. */
1819 ident
= gcov_read_unsigned ();
1822 for (vector
<function_info
*>::reverse_iterator it
1823 = functions
.rbegin (); it
!= functions
.rend (); it
++)
1825 if ((*it
)->ident
== ident
)
1834 else if (gcov_read_unsigned () != fn
->lineno_checksum
1835 || gcov_read_unsigned () != fn
->cfg_checksum
)
1838 fnotice (stderr
, "%s:profile mismatch for '%s'\n",
1839 da_file_name
, fn
->name
);
1843 else if (tag
== GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS
) && fn
)
1845 if (length
!= GCOV_TAG_COUNTER_LENGTH (fn
->counts
.size ()))
1848 for (ix
= 0; ix
!= fn
->counts
.size (); ix
++)
1849 fn
->counts
[ix
] += gcov_read_counter ();
1851 gcov_sync (base
, length
);
1852 if ((error
= gcov_is_error ()))
1856 ? N_("%s:overflowed\n")
1857 : N_("%s:corrupted\n"),
1867 /* Solve the flow graph. Propagate counts from the instrumented arcs
1868 to the blocks and the uninstrumented arcs. */
1871 solve_flow_graph (function_info
*fn
)
1875 gcov_type
*count_ptr
= &fn
->counts
.front ();
1877 block_info
*valid_blocks
= NULL
; /* valid, but unpropagated blocks. */
1878 block_info
*invalid_blocks
= NULL
; /* invalid, but inferable blocks. */
1880 /* The arcs were built in reverse order. Fix that now. */
1881 for (ix
= fn
->blocks
.size (); ix
--;)
1883 arc_info
*arc_p
, *arc_n
;
1885 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].succ
; arc
;
1886 arc_p
= arc
, arc
= arc_n
)
1888 arc_n
= arc
->succ_next
;
1889 arc
->succ_next
= arc_p
;
1891 fn
->blocks
[ix
].succ
= arc_p
;
1893 for (arc_p
= NULL
, arc
= fn
->blocks
[ix
].pred
; arc
;
1894 arc_p
= arc
, arc
= arc_n
)
1896 arc_n
= arc
->pred_next
;
1897 arc
->pred_next
= arc_p
;
1899 fn
->blocks
[ix
].pred
= arc_p
;
1902 if (fn
->blocks
.size () < 2)
1903 fnotice (stderr
, "%s:'%s' lacks entry and/or exit blocks\n",
1904 bbg_file_name
, fn
->name
);
1907 if (fn
->blocks
[ENTRY_BLOCK
].num_pred
)
1908 fnotice (stderr
, "%s:'%s' has arcs to entry block\n",
1909 bbg_file_name
, fn
->name
);
1911 /* We can't deduce the entry block counts from the lack of
1913 fn
->blocks
[ENTRY_BLOCK
].num_pred
= ~(unsigned)0;
1915 if (fn
->blocks
[EXIT_BLOCK
].num_succ
)
1916 fnotice (stderr
, "%s:'%s' has arcs from exit block\n",
1917 bbg_file_name
, fn
->name
);
1919 /* Likewise, we can't deduce exit block counts from the lack
1920 of its successors. */
1921 fn
->blocks
[EXIT_BLOCK
].num_succ
= ~(unsigned)0;
1924 /* Propagate the measured counts, this must be done in the same
1925 order as the code in profile.c */
1926 for (unsigned i
= 0; i
< fn
->blocks
.size (); i
++)
1928 blk
= &fn
->blocks
[i
];
1929 block_info
const *prev_dst
= NULL
;
1930 int out_of_order
= 0;
1931 int non_fake_succ
= 0;
1933 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1941 arc
->count
= *count_ptr
++;
1942 arc
->count_valid
= 1;
1944 arc
->dst
->num_pred
--;
1946 if (prev_dst
&& prev_dst
> arc
->dst
)
1948 prev_dst
= arc
->dst
;
1950 if (non_fake_succ
== 1)
1952 /* If there is only one non-fake exit, it is an
1953 unconditional branch. */
1954 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
1957 arc
->is_unconditional
= 1;
1958 /* If this block is instrumenting a call, it might be
1959 an artificial block. It is not artificial if it has
1960 a non-fallthrough exit, or the destination of this
1961 arc has more than one entry. Mark the destination
1962 block as a return site, if none of those conditions
1964 if (blk
->is_call_site
&& arc
->fall_through
1965 && arc
->dst
->pred
== arc
&& !arc
->pred_next
)
1966 arc
->dst
->is_call_return
= 1;
1970 /* Sort the successor arcs into ascending dst order. profile.c
1971 normally produces arcs in the right order, but sometimes with
1972 one or two out of order. We're not using a particularly
1976 arc_info
*start
= blk
->succ
;
1977 unsigned changes
= 1;
1981 arc_info
*arc
, *arc_p
, *arc_n
;
1984 for (arc_p
= NULL
, arc
= start
; (arc_n
= arc
->succ_next
);)
1986 if (arc
->dst
> arc_n
->dst
)
1990 arc_p
->succ_next
= arc_n
;
1993 arc
->succ_next
= arc_n
->succ_next
;
1994 arc_n
->succ_next
= arc
;
2007 /* Place it on the invalid chain, it will be ignored if that's
2009 blk
->invalid_chain
= 1;
2010 blk
->chain
= invalid_blocks
;
2011 invalid_blocks
= blk
;
2014 while (invalid_blocks
|| valid_blocks
)
2016 while ((blk
= invalid_blocks
))
2018 gcov_type total
= 0;
2019 const arc_info
*arc
;
2021 invalid_blocks
= blk
->chain
;
2022 blk
->invalid_chain
= 0;
2024 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2025 total
+= arc
->count
;
2026 else if (!blk
->num_pred
)
2027 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
2028 total
+= arc
->count
;
2033 blk
->count_valid
= 1;
2034 blk
->chain
= valid_blocks
;
2035 blk
->valid_chain
= 1;
2038 while ((blk
= valid_blocks
))
2041 arc_info
*arc
, *inv_arc
;
2043 valid_blocks
= blk
->chain
;
2044 blk
->valid_chain
= 0;
2045 if (blk
->num_succ
== 1)
2051 for (arc
= blk
->succ
; arc
; arc
= arc
->succ_next
)
2053 total
-= arc
->count
;
2054 if (!arc
->count_valid
)
2058 inv_arc
->count_valid
= 1;
2059 inv_arc
->count
= total
;
2062 if (dst
->count_valid
)
2064 if (dst
->num_pred
== 1 && !dst
->valid_chain
)
2066 dst
->chain
= valid_blocks
;
2067 dst
->valid_chain
= 1;
2073 if (!dst
->num_pred
&& !dst
->invalid_chain
)
2075 dst
->chain
= invalid_blocks
;
2076 dst
->invalid_chain
= 1;
2077 invalid_blocks
= dst
;
2081 if (blk
->num_pred
== 1)
2087 for (arc
= blk
->pred
; arc
; arc
= arc
->pred_next
)
2089 total
-= arc
->count
;
2090 if (!arc
->count_valid
)
2094 inv_arc
->count_valid
= 1;
2095 inv_arc
->count
= total
;
2098 if (src
->count_valid
)
2100 if (src
->num_succ
== 1 && !src
->valid_chain
)
2102 src
->chain
= valid_blocks
;
2103 src
->valid_chain
= 1;
2109 if (!src
->num_succ
&& !src
->invalid_chain
)
2111 src
->chain
= invalid_blocks
;
2112 src
->invalid_chain
= 1;
2113 invalid_blocks
= src
;
2120 /* If the graph has been correctly solved, every block will have a
2122 for (unsigned i
= 0; ix
< fn
->blocks
.size (); i
++)
2123 if (!fn
->blocks
[i
].count_valid
)
2125 fnotice (stderr
, "%s:graph is unsolvable for '%s'\n",
2126 bbg_file_name
, fn
->name
);
2131 /* Mark all the blocks only reachable via an incoming catch. */
2134 find_exception_blocks (function_info
*fn
)
2137 block_info
**queue
= XALLOCAVEC (block_info
*, fn
->blocks
.size ());
2139 /* First mark all blocks as exceptional. */
2140 for (ix
= fn
->blocks
.size (); ix
--;)
2141 fn
->blocks
[ix
].exceptional
= 1;
2143 /* Now mark all the blocks reachable via non-fake edges */
2144 queue
[0] = &fn
->blocks
[0];
2145 queue
[0]->exceptional
= 0;
2148 block_info
*block
= queue
[--ix
];
2149 const arc_info
*arc
;
2151 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2152 if (!arc
->fake
&& !arc
->is_throw
&& arc
->dst
->exceptional
)
2154 arc
->dst
->exceptional
= 0;
2155 queue
[ix
++] = arc
->dst
;
2161 /* Increment totals in COVERAGE according to arc ARC. */
2164 add_branch_counts (coverage_info
*coverage
, const arc_info
*arc
)
2166 if (arc
->is_call_non_return
)
2169 if (arc
->src
->count
)
2170 coverage
->calls_executed
++;
2172 else if (!arc
->is_unconditional
)
2174 coverage
->branches
++;
2175 if (arc
->src
->count
)
2176 coverage
->branches_executed
++;
2178 coverage
->branches_taken
++;
2182 /* Format COUNT, if flag_human_readable_numbers is set, return it human
2186 format_count (gcov_type count
)
2188 static char buffer
[64];
2189 const char *units
= " kMGTPEZY";
2191 if (count
< 1000 || !flag_human_readable_numbers
)
2193 sprintf (buffer
, "%" PRId64
, count
);
2198 gcov_type divisor
= 1;
2199 for (i
= 0; units
[i
+1]; i
++, divisor
*= 1000)
2201 if (count
+ divisor
/ 2 < 1000 * divisor
)
2204 gcov_type r
= (count
+ divisor
/ 2) / divisor
;
2205 sprintf (buffer
, "%" PRId64
"%c", r
, units
[i
]);
2209 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
2210 count. If DECIMAL_PLACES >= 0, format TOP/BOTTOM * 100 to DECIMAL_PLACES.
2211 If DECIMAL_PLACES is zero, no decimal point is printed. Only print 100% when
2212 TOP==BOTTOM and only print 0% when TOP=0. If DECIMAL_PLACES < 0, then simply
2213 format TOP. Return pointer to a static string. */
2216 format_gcov (gcov_type top
, gcov_type bottom
, int decimal_places
)
2218 static char buffer
[20];
2220 if (decimal_places
>= 0)
2222 float ratio
= bottom
? 100.0f
* top
/ bottom
: 0;
2224 /* Round up to 1% if there's a small non-zero value. */
2225 if (ratio
> 0.0f
&& ratio
< 0.5f
&& decimal_places
== 0)
2227 sprintf (buffer
, "%.*f%%", decimal_places
, ratio
);
2230 return format_count (top
);
2235 /* Summary of execution */
2238 executed_summary (unsigned lines
, unsigned executed
)
2241 fnotice (stdout
, "Lines executed:%s of %d\n",
2242 format_gcov (executed
, lines
, 2), lines
);
2244 fnotice (stdout
, "No executable lines\n");
2247 /* Output summary info for a function or file. */
2250 function_summary (const coverage_info
*coverage
, const char *title
)
2252 fnotice (stdout
, "%s '%s'\n", title
, coverage
->name
);
2253 executed_summary (coverage
->lines
, coverage
->lines_executed
);
2257 if (coverage
->branches
)
2259 fnotice (stdout
, "Branches executed:%s of %d\n",
2260 format_gcov (coverage
->branches_executed
,
2261 coverage
->branches
, 2),
2262 coverage
->branches
);
2263 fnotice (stdout
, "Taken at least once:%s of %d\n",
2264 format_gcov (coverage
->branches_taken
,
2265 coverage
->branches
, 2),
2266 coverage
->branches
);
2269 fnotice (stdout
, "No branches\n");
2270 if (coverage
->calls
)
2271 fnotice (stdout
, "Calls executed:%s of %d\n",
2272 format_gcov (coverage
->calls_executed
, coverage
->calls
, 2),
2275 fnotice (stdout
, "No calls\n");
2279 /* Canonicalize the filename NAME by canonicalizing directory
2280 separators, eliding . components and resolving .. components
2281 appropriately. Always returns a unique string. */
2284 canonicalize_name (const char *name
)
2286 /* The canonical name cannot be longer than the incoming name. */
2287 char *result
= XNEWVEC (char, strlen (name
) + 1);
2288 const char *base
= name
, *probe
;
2293 #if HAVE_DOS_BASED_FILE_SYSTEM
2294 if (base
[0] && base
[1] == ':')
2296 result
[0] = base
[0];
2302 for (dd_base
= ptr
; *base
; base
= probe
)
2306 for (probe
= base
; *probe
; probe
++)
2307 if (IS_DIR_SEPARATOR (*probe
))
2311 if (len
== 1 && base
[0] == '.')
2312 /* Elide a '.' directory */
2314 else if (len
== 2 && base
[0] == '.' && base
[1] == '.')
2316 /* '..', we can only elide it and the previous directory, if
2317 we're not a symlink. */
2318 struct stat ATTRIBUTE_UNUSED buf
;
2322 #if defined (S_ISLNK)
2323 /* S_ISLNK is not POSIX.1-1996. */
2324 || stat (result
, &buf
) || S_ISLNK (buf
.st_mode
)
2328 /* Cannot elide, or unreadable or a symlink. */
2329 dd_base
= ptr
+ 2 + slash
;
2332 while (ptr
!= dd_base
&& *ptr
!= '/')
2334 slash
= ptr
!= result
;
2339 /* Regular pathname component. */
2342 memcpy (ptr
, base
, len
);
2347 for (; IS_DIR_SEPARATOR (*probe
); probe
++)
2355 /* Print hex representation of 16 bytes from SUM and write it to BUFFER. */
2358 md5sum_to_hex (const char *sum
, char *buffer
)
2360 for (unsigned i
= 0; i
< 16; i
++)
2361 sprintf (buffer
+ (2 * i
), "%02x", (unsigned char)sum
[i
]);
2364 /* Generate an output file name. INPUT_NAME is the canonicalized main
2365 input file and SRC_NAME is the canonicalized file name.
2366 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
2367 long_output_names we prepend the processed name of the input file
2368 to each output name (except when the current source file is the
2369 input file, so you don't get a double concatenation). The two
2370 components are separated by '##'. With preserve_paths we create a
2371 filename from all path components of the source file, replacing '/'
2372 with '#', and .. with '^', without it we simply take the basename
2373 component. (Remember, the canonicalized name will already have
2374 elided '.' components and converted \\ separators.) */
2377 make_gcov_file_name (const char *input_name
, const char *src_name
)
2382 if (flag_long_names
&& input_name
&& strcmp (src_name
, input_name
))
2384 /* Generate the input filename part. */
2385 result
= XNEWVEC (char, strlen (input_name
) + strlen (src_name
) + 10);
2388 ptr
= mangle_name (input_name
, ptr
);
2389 ptr
[0] = ptr
[1] = '#';
2394 result
= XNEWVEC (char, strlen (src_name
) + 10);
2398 ptr
= mangle_name (src_name
, ptr
);
2399 strcpy (ptr
, ".gcov");
2401 /* When hashing filenames, we shorten them by only using the filename
2402 component and appending a hash of the full (mangled) pathname. */
2403 if (flag_hash_filenames
)
2407 char md5sum_hex
[33];
2409 md5_init_ctx (&ctx
);
2410 md5_process_bytes (src_name
, strlen (src_name
), &ctx
);
2411 md5_finish_ctx (&ctx
, md5sum
);
2412 md5sum_to_hex (md5sum
, md5sum_hex
);
2415 result
= XNEWVEC (char, strlen (src_name
) + 50);
2417 ptr
= mangle_name (src_name
, ptr
);
2418 ptr
[0] = ptr
[1] = '#';
2420 memcpy (ptr
, md5sum_hex
, 32);
2422 strcpy (ptr
, ".gcov");
2429 mangle_name (char const *base
, char *ptr
)
2433 /* Generate the source filename part. */
2434 if (!flag_preserve_paths
)
2436 base
= lbasename (base
);
2437 len
= strlen (base
);
2438 memcpy (ptr
, base
, len
);
2442 ptr
= mangle_path (base
);
2447 /* Scan through the bb_data for each line in the block, increment
2448 the line number execution count indicated by the execution count of
2449 the appropriate basic block. */
2452 add_line_counts (coverage_info
*coverage
, function_info
*fn
)
2454 bool has_any_line
= false;
2455 /* Scan each basic block. */
2456 for (unsigned ix
= 0; ix
!= fn
->blocks
.size (); ix
++)
2458 line_info
*line
= NULL
;
2459 block_info
*block
= &fn
->blocks
[ix
];
2460 if (block
->count
&& ix
&& ix
+ 1 != fn
->blocks
.size ())
2461 fn
->blocks_executed
++;
2462 for (unsigned i
= 0; i
< block
->locations
.size (); i
++)
2464 unsigned src_idx
= block
->locations
[i
].source_file_idx
;
2465 vector
<unsigned> &lines
= block
->locations
[i
].lines
;
2467 block
->cycle
.arc
= NULL
;
2468 block
->cycle
.ident
= ~0U;
2470 for (unsigned j
= 0; j
< lines
.size (); j
++)
2472 unsigned ln
= lines
[j
];
2474 /* Line belongs to a function that is in a group. */
2475 if (fn
->group_line_p (ln
, src_idx
))
2477 gcc_assert (lines
[j
] - fn
->start_line
< fn
->lines
.size ());
2478 line
= &(fn
->lines
[lines
[j
] - fn
->start_line
]);
2480 if (!block
->exceptional
)
2482 line
->unexceptional
= 1;
2483 if (block
->count
== 0)
2484 line
->has_unexecuted_block
= 1;
2486 line
->count
+= block
->count
;
2490 gcc_assert (ln
< sources
[src_idx
].lines
.size ());
2491 line
= &(sources
[src_idx
].lines
[ln
]);
2496 if (!line
->count
&& block
->count
)
2497 coverage
->lines_executed
++;
2500 if (!block
->exceptional
)
2502 line
->unexceptional
= 1;
2503 if (block
->count
== 0)
2504 line
->has_unexecuted_block
= 1;
2506 line
->count
+= block
->count
;
2510 has_any_line
= true;
2512 if (!ix
|| ix
+ 1 == fn
->blocks
.size ())
2513 /* Entry or exit block. */;
2514 else if (line
!= NULL
)
2516 line
->blocks
.push_back (block
);
2522 for (arc
= block
->succ
; arc
; arc
= arc
->succ_next
)
2523 line
->branches
.push_back (arc
);
2530 fnotice (stderr
, "%s:no lines for '%s'\n", bbg_file_name
, fn
->name
);
2533 /* Accumulate info for LINE that belongs to SRC source file. If ADD_COVERAGE
2534 is set to true, update source file summary. */
2536 static void accumulate_line_info (line_info
*line
, source_info
*src
,
2540 for (vector
<arc_info
*>::iterator it
= line
->branches
.begin ();
2541 it
!= line
->branches
.end (); it
++)
2542 add_branch_counts (&src
->coverage
, *it
);
2544 if (!line
->blocks
.empty ())
2546 /* The user expects the line count to be the number of times
2547 a line has been executed. Simply summing the block count
2548 will give an artificially high number. The Right Thing
2549 is to sum the entry counts to the graph of blocks on this
2550 line, then find the elementary cycles of the local graph
2551 and add the transition counts of those cycles. */
2552 gcov_type count
= 0;
2554 /* Cycle detection. */
2555 for (vector
<block_info
*>::iterator it
= line
->blocks
.begin ();
2556 it
!= line
->blocks
.end (); it
++)
2558 for (arc_info
*arc
= (*it
)->pred
; arc
; arc
= arc
->pred_next
)
2559 if (!line
->has_block (arc
->src
))
2560 count
+= arc
->count
;
2561 for (arc_info
*arc
= (*it
)->succ
; arc
; arc
= arc
->succ_next
)
2562 arc
->cs_count
= arc
->count
;
2565 /* Now, add the count of loops entirely on this line. */
2566 count
+= get_cycles_count (*line
);
2567 line
->count
= count
;
2570 if (line
->exists
&& add_coverage
)
2572 src
->coverage
.lines
++;
2574 src
->coverage
.lines_executed
++;
2578 /* Accumulate the line counts of a file. */
2581 accumulate_line_counts (source_info
*src
)
2583 /* First work on group functions. */
2584 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
2585 it
!= src
->functions
.end (); it
++)
2587 function_info
*fn
= *it
;
2589 if (fn
->src
!= src
->index
|| !fn
->is_group
)
2592 for (vector
<line_info
>::iterator it2
= fn
->lines
.begin ();
2593 it2
!= fn
->lines
.end (); it2
++)
2595 line_info
*line
= &(*it2
);
2596 accumulate_line_info (line
, src
, false);
2600 /* Work on global lines that line in source file SRC. */
2601 for (vector
<line_info
>::iterator it
= src
->lines
.begin ();
2602 it
!= src
->lines
.end (); it
++)
2603 accumulate_line_info (&(*it
), src
, true);
2605 /* If not using intermediate mode, sum lines of group functions and
2606 add them to lines that live in a source file. */
2607 if (!flag_intermediate_format
)
2608 for (vector
<function_info
*>::iterator it
= src
->functions
.begin ();
2609 it
!= src
->functions
.end (); it
++)
2611 function_info
*fn
= *it
;
2613 if (fn
->src
!= src
->index
|| !fn
->is_group
)
2616 for (unsigned i
= 0; i
< fn
->lines
.size (); i
++)
2618 line_info
*fn_line
= &fn
->lines
[i
];
2619 if (fn_line
->exists
)
2621 unsigned ln
= fn
->start_line
+ i
;
2622 line_info
*src_line
= &src
->lines
[ln
];
2624 if (!src_line
->exists
)
2625 src
->coverage
.lines
++;
2626 if (!src_line
->count
&& fn_line
->count
)
2627 src
->coverage
.lines_executed
++;
2629 src_line
->count
+= fn_line
->count
;
2630 src_line
->exists
= 1;
2632 if (fn_line
->has_unexecuted_block
)
2633 src_line
->has_unexecuted_block
= 1;
2635 if (fn_line
->unexceptional
)
2636 src_line
->unexceptional
= 1;
2642 /* Output information about ARC number IX. Returns nonzero if
2643 anything is output. */
2646 output_branch_count (FILE *gcov_file
, int ix
, const arc_info
*arc
)
2648 if (arc
->is_call_non_return
)
2650 if (arc
->src
->count
)
2652 fnotice (gcov_file
, "call %2d returned %s\n", ix
,
2653 format_gcov (arc
->src
->count
- arc
->count
,
2654 arc
->src
->count
, -flag_counts
));
2657 fnotice (gcov_file
, "call %2d never executed\n", ix
);
2659 else if (!arc
->is_unconditional
)
2661 if (arc
->src
->count
)
2662 fnotice (gcov_file
, "branch %2d taken %s%s", ix
,
2663 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
),
2664 arc
->fall_through
? " (fallthrough)"
2665 : arc
->is_throw
? " (throw)" : "");
2667 fnotice (gcov_file
, "branch %2d never executed", ix
);
2670 fnotice (gcov_file
, " (BB %d)", arc
->dst
->id
);
2672 fnotice (gcov_file
, "\n");
2674 else if (flag_unconditional
&& !arc
->dst
->is_call_return
)
2676 if (arc
->src
->count
)
2677 fnotice (gcov_file
, "unconditional %2d taken %s\n", ix
,
2678 format_gcov (arc
->count
, arc
->src
->count
, -flag_counts
));
2680 fnotice (gcov_file
, "unconditional %2d never executed\n", ix
);
2688 read_line (FILE *file
)
2690 static char *string
;
2691 static size_t string_len
;
2698 string
= XNEWVEC (char, string_len
);
2701 while ((ptr
= fgets (string
+ pos
, string_len
- pos
, file
)))
2703 size_t len
= strlen (string
+ pos
);
2705 if (len
&& string
[pos
+ len
- 1] == '\n')
2707 string
[pos
+ len
- 1] = 0;
2711 /* If the file contains NUL characters or an incomplete
2712 last line, which can happen more than once in one run,
2713 we have to avoid doubling the STRING_LEN unnecessarily. */
2714 if (pos
> string_len
/ 2)
2717 string
= XRESIZEVEC (char, string
, string_len
);
2721 return pos
? string
: NULL
;
2724 /* Pad string S with spaces from left to have total width equal to 9. */
2727 pad_count_string (string
&s
)
2730 s
.insert (0, 9 - s
.size (), ' ');
2733 /* Print GCOV line beginning to F stream. If EXISTS is set to true, the
2734 line exists in source file. UNEXCEPTIONAL indicated that it's not in
2735 an exceptional statement. The output is printed for LINE_NUM of given
2736 COUNT of executions. EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
2737 used to indicate non-executed blocks. */
2740 output_line_beginning (FILE *f
, bool exists
, bool unexceptional
,
2741 bool has_unexecuted_block
,
2742 gcov_type count
, unsigned line_num
,
2743 const char *exceptional_string
,
2744 const char *unexceptional_string
)
2751 s
= format_gcov (count
, 0, -1);
2752 if (has_unexecuted_block
2753 && bbg_supports_has_unexecuted_blocks
)
2755 if (flag_use_colors
)
2757 pad_count_string (s
);
2758 s
.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
2759 COLOR_SEPARATOR COLOR_FG_WHITE
));
2765 pad_count_string (s
);
2769 if (flag_use_colors
)
2772 pad_count_string (s
);
2774 s
.insert (0, SGR_SEQ (COLOR_BG_RED
2775 COLOR_SEPARATOR COLOR_FG_WHITE
));
2777 s
.insert (0, SGR_SEQ (COLOR_BG_CYAN
2778 COLOR_SEPARATOR COLOR_FG_WHITE
));
2783 s
= unexceptional
? unexceptional_string
: exceptional_string
;
2784 pad_count_string (s
);
2791 pad_count_string (s
);
2794 fprintf (f
, "%s:%5u", s
.c_str (), line_num
);
2798 print_source_line (FILE *f
, const vector
<const char *> &source_lines
,
2801 gcc_assert (line
>= 1);
2802 gcc_assert (line
<= source_lines
.size ());
2804 fprintf (f
, ":%s\n", source_lines
[line
- 1]);
2807 /* Output line details for LINE and print it to F file. LINE lives on
2811 output_line_details (FILE *f
, const line_info
*line
, unsigned line_num
)
2813 if (flag_all_blocks
)
2819 for (vector
<block_info
*>::const_iterator it
= line
->blocks
.begin ();
2820 it
!= line
->blocks
.end (); it
++)
2822 if (!(*it
)->is_call_return
)
2824 output_line_beginning (f
, line
->exists
,
2825 (*it
)->exceptional
, false,
2826 (*it
)->count
, line_num
,
2828 fprintf (f
, "-block %2d", ix
++);
2830 fprintf (f
, " (BB %u)", (*it
)->id
);
2834 for (arc
= (*it
)->succ
; arc
; arc
= arc
->succ_next
)
2835 jx
+= output_branch_count (f
, jx
, arc
);
2838 else if (flag_branches
)
2843 for (vector
<arc_info
*>::const_iterator it
= line
->branches
.begin ();
2844 it
!= line
->branches
.end (); it
++)
2845 ix
+= output_branch_count (f
, ix
, (*it
));
2849 /* Output detail statistics about function FN to file F. */
2852 output_function_details (FILE *f
, const function_info
*fn
)
2857 arc_info
*arc
= fn
->blocks
[EXIT_BLOCK
].pred
;
2858 gcov_type return_count
= fn
->blocks
[EXIT_BLOCK
].count
;
2859 gcov_type called_count
= fn
->blocks
[ENTRY_BLOCK
].count
;
2861 for (; arc
; arc
= arc
->pred_next
)
2863 return_count
-= arc
->count
;
2865 fprintf (f
, "function %s",
2866 flag_demangled_names
? fn
->demangled_name
: fn
->name
);
2867 fprintf (f
, " called %s",
2868 format_gcov (called_count
, 0, -1));
2869 fprintf (f
, " returned %s",
2870 format_gcov (return_count
, called_count
, 0));
2871 fprintf (f
, " blocks executed %s",
2872 format_gcov (fn
->blocks_executed
, fn
->blocks
.size () - 2,
2877 /* Read in the source file one line at a time, and output that line to
2878 the gcov file preceded by its execution count and other
2882 output_lines (FILE *gcov_file
, const source_info
*src
)
2884 #define DEFAULT_LINE_START " -: 0:"
2885 #define FN_SEPARATOR "------------------\n"
2890 fprintf (gcov_file
, DEFAULT_LINE_START
"Source:%s\n", src
->coverage
.name
);
2891 if (!multiple_files
)
2893 fprintf (gcov_file
, DEFAULT_LINE_START
"Graph:%s\n", bbg_file_name
);
2894 fprintf (gcov_file
, DEFAULT_LINE_START
"Data:%s\n",
2895 no_data_file
? "-" : da_file_name
);
2896 fprintf (gcov_file
, DEFAULT_LINE_START
"Runs:%u\n", object_runs
);
2898 fprintf (gcov_file
, DEFAULT_LINE_START
"Programs:%u\n", program_count
);
2900 source_file
= fopen (src
->name
, "r");
2902 fnotice (stderr
, "Cannot open source file %s\n", src
->name
);
2903 else if (src
->file_time
== 0)
2904 fprintf (gcov_file
, DEFAULT_LINE_START
"Source is newer than graph\n");
2906 vector
<const char *> source_lines
;
2908 while ((retval
= read_line (source_file
)) != NULL
)
2909 source_lines
.push_back (xstrdup (retval
));
2911 unsigned line_start_group
= 0;
2912 vector
<function_info
*> fns
;
2914 for (unsigned line_num
= 1; line_num
<= source_lines
.size (); line_num
++)
2916 if (line_num
>= src
->lines
.size ())
2918 fprintf (gcov_file
, "%9s:%5u", "-", line_num
);
2919 print_source_line (gcov_file
, source_lines
, line_num
);
2923 const line_info
*line
= &src
->lines
[line_num
];
2925 if (line_start_group
== 0)
2927 fns
= src
->get_functions_at_location (line_num
);
2928 if (fns
.size () > 1)
2930 /* It's possible to have functions that partially overlap,
2931 thus take the maximum end_line of functions starting
2933 for (unsigned i
= 0; i
< fns
.size (); i
++)
2934 if (fns
[i
]->end_line
> line_start_group
)
2935 line_start_group
= fns
[i
]->end_line
;
2937 else if (fns
.size () == 1)
2939 function_info
*fn
= fns
[0];
2940 output_function_details (gcov_file
, fn
);
2944 /* For lines which don't exist in the .bb file, print '-' before
2945 the source line. For lines which exist but were never
2946 executed, print '#####' or '=====' before the source line.
2947 Otherwise, print the execution count before the source line.
2948 There are 16 spaces of indentation added before the source
2949 line so that tabs won't be messed up. */
2950 output_line_beginning (gcov_file
, line
->exists
, line
->unexceptional
,
2951 line
->has_unexecuted_block
, line
->count
,
2952 line_num
, "=====", "#####");
2954 print_source_line (gcov_file
, source_lines
, line_num
);
2955 output_line_details (gcov_file
, line
, line_num
);
2957 if (line_start_group
== line_num
)
2959 for (vector
<function_info
*>::iterator it
= fns
.begin ();
2960 it
!= fns
.end (); it
++)
2962 function_info
*fn
= *it
;
2963 vector
<line_info
> &lines
= fn
->lines
;
2965 fprintf (gcov_file
, FN_SEPARATOR
);
2968 = flag_demangled_names
? fn
->demangled_name
: fn
->name
;
2970 if (flag_use_colors
)
2972 fn_name
.insert (0, SGR_SEQ (COLOR_FG_CYAN
));
2973 fn_name
+= SGR_RESET
;
2976 fprintf (gcov_file
, "%s:\n", fn_name
.c_str ());
2978 output_function_details (gcov_file
, fn
);
2980 /* Print all lines covered by the function. */
2981 for (unsigned i
= 0; i
< lines
.size (); i
++)
2983 line_info
*line
= &lines
[i
];
2984 unsigned l
= fn
->start_line
+ i
;
2986 /* For lines which don't exist in the .bb file, print '-'
2987 before the source line. For lines which exist but
2988 were never executed, print '#####' or '=====' before
2989 the source line. Otherwise, print the execution count
2990 before the source line.
2991 There are 16 spaces of indentation added before the source
2992 line so that tabs won't be messed up. */
2993 output_line_beginning (gcov_file
, line
->exists
,
2994 line
->unexceptional
,
2995 line
->has_unexecuted_block
,
2997 l
, "=====", "#####");
2999 print_source_line (gcov_file
, source_lines
, l
);
3000 output_line_details (gcov_file
, line
, l
);
3004 fprintf (gcov_file
, FN_SEPARATOR
);
3005 line_start_group
= 0;
3010 fclose (source_file
);