1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2    source file.
3    Copyright (C) 1990-2016 Free Software Foundation, Inc.
4    Contributed by James E. Wilson of Cygnus Support.
5    Mangled by Bob Manson of Cygnus Support.
6    Mangled further by Nathan Sidwell <nathan@codesourcery.com>
7 
8 Gcov is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
12 
13 Gcov is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Gcov; see the file COPYING3.  If not see
20 <http://www.gnu.org/licenses/>.  */
21 
22 /* ??? Print a list of the ten blocks with the highest execution counts,
23    and list the line numbers corresponding to those blocks.  Also, perhaps
24    list the line numbers with the highest execution counts, only printing
25    the first if there are several which are all listed in the same block.  */
26 
27 /* ??? Should have an option to print the number of basic blocks, and the
28    percent of them that are covered.  */
29 
30 /* Need an option to show individual block counts, and show
31    probabilities of fall through arcs.  */
32 
33 #include "config.h"
34 #include "system.h"
35 #include "coretypes.h"
36 #include "tm.h"
37 #include "intl.h"
38 #include "diagnostic.h"
39 #include "version.h"
40 #include "demangle.h"
41 
42 #include <getopt.h>
43 
44 #define IN_GCOV 1
45 #include "gcov-io.h"
46 #include "gcov-io.c"
47 
48 /* The gcno file is generated by -ftest-coverage option. The gcda file is
49    generated by a program compiled with -fprofile-arcs. Their formats
50    are documented in gcov-io.h.  */
51 
52 /* The functions in this file for creating and solution program flow graphs
53    are very similar to functions in the gcc source file profile.c.  In
54    some places we make use of the knowledge of how profile.c works to
55    select particular algorithms here.  */
56 
57 /* The code validates that the profile information read in corresponds
58    to the code currently being compiled.  Rather than checking for
59    identical files, the code below compares a checksum on the CFG
60    (based on the order of basic blocks and the arcs in the CFG).  If
61    the CFG checksum in the gcda file match the CFG checksum in the
62    gcno file, the profile data will be used.  */
63 
64 /* This is the size of the buffer used to read in source file lines.  */
65 
66 struct function_info;
67 struct block_info;
68 struct source_info;
69 
70 /* Describes an arc between two basic blocks.  */
71 
72 typedef struct arc_info
73 {
74   /* source and destination blocks.  */
75   struct block_info *src;
76   struct block_info *dst;
77 
78   /* transition counts.  */
79   gcov_type count;
80   /* used in cycle search, so that we do not clobber original counts.  */
81   gcov_type cs_count;
82 
83   unsigned int count_valid : 1;
84   unsigned int on_tree : 1;
85   unsigned int fake : 1;
86   unsigned int fall_through : 1;
87 
88   /* Arc to a catch handler.  */
89   unsigned int is_throw : 1;
90 
91   /* Arc is for a function that abnormally returns.  */
92   unsigned int is_call_non_return : 1;
93 
94   /* Arc is for catch/setjmp.  */
95   unsigned int is_nonlocal_return : 1;
96 
97   /* Is an unconditional branch.  */
98   unsigned int is_unconditional : 1;
99 
100   /* Loop making arc.  */
101   unsigned int cycle : 1;
102 
103   /* Next branch on line.  */
104   struct arc_info *line_next;
105 
106   /* Links to next arc on src and dst lists.  */
107   struct arc_info *succ_next;
108   struct arc_info *pred_next;
109 } arc_t;
110 
111 /* Describes a basic block. Contains lists of arcs to successor and
112    predecessor blocks.  */
113 
114 typedef struct block_info
115 {
116   /* Chain of exit and entry arcs.  */
117   arc_t *succ;
118   arc_t *pred;
119 
120   /* Number of unprocessed exit and entry arcs.  */
121   gcov_type num_succ;
122   gcov_type num_pred;
123 
124   /* Block execution count.  */
125   gcov_type count;
126   unsigned flags : 12;
127   unsigned count_valid : 1;
128   unsigned valid_chain : 1;
129   unsigned invalid_chain : 1;
130   unsigned exceptional : 1;
131 
132   /* Block is a call instrumenting site.  */
133   unsigned is_call_site : 1; /* Does the call.  */
134   unsigned is_call_return : 1; /* Is the return.  */
135 
136   /* Block is a landing pad for longjmp or throw.  */
137   unsigned is_nonlocal_return : 1;
138 
139   union
140   {
141     struct
142     {
143      /* Array of line numbers and source files. source files are
144         introduced by a linenumber of zero, the next 'line number' is
145         the number of the source file.  Always starts with a source
146         file.  */
147       unsigned *encoding;
148       unsigned num;
149     } line; /* Valid until blocks are linked onto lines */
150     struct
151     {
152       /* Single line graph cycle workspace.  Used for all-blocks
153 	 mode.  */
154       arc_t *arc;
155       unsigned ident;
156     } cycle; /* Used in all-blocks mode, after blocks are linked onto
157 	       lines.  */
158   } u;
159 
160   /* Temporary chain for solving graph, and for chaining blocks on one
161      line.  */
162   struct block_info *chain;
163 
164 } block_t;
165 
166 /* Describes a single function. Contains an array of basic blocks.  */
167 
168 typedef struct function_info
169 {
170   /* Name of function.  */
171   char *name;
172   char *demangled_name;
173   unsigned ident;
174   unsigned lineno_checksum;
175   unsigned cfg_checksum;
176 
177   /* The graph contains at least one fake incoming edge.  */
178   unsigned has_catch : 1;
179 
180   /* Array of basic blocks.  Like in GCC, the entry block is
181      at blocks[0] and the exit block is at blocks[1].  */
182 #define ENTRY_BLOCK (0)
183 #define EXIT_BLOCK (1)
184   block_t *blocks;
185   unsigned num_blocks;
186   unsigned blocks_executed;
187 
188   /* Raw arc coverage counts.  */
189   gcov_type *counts;
190   unsigned num_counts;
191 
192   /* First line number & file.  */
193   unsigned line;
194   unsigned src;
195 
196   /* Next function in same source file.  */
197   struct function_info *line_next;
198 
199   /* Next function.  */
200   struct function_info *next;
201 } function_t;
202 
203 /* Describes coverage of a file or function.  */
204 
205 typedef struct coverage_info
206 {
207   int lines;
208   int lines_executed;
209 
210   int branches;
211   int branches_executed;
212   int branches_taken;
213 
214   int calls;
215   int calls_executed;
216 
217   char *name;
218 } coverage_t;
219 
220 /* Describes a single line of source. Contains a chain of basic blocks
221    with code on it.  */
222 
223 typedef struct line_info
224 {
225   gcov_type count;	   /* execution count */
226   union
227   {
228     arc_t *branches;	   /* branches from blocks that end on this
229 			      line. Used for branch-counts when not
230 			      all-blocks mode.  */
231     block_t *blocks;       /* blocks which start on this line.  Used
232 			      in all-blocks mode.  */
233   } u;
234   unsigned exists : 1;
235   unsigned unexceptional : 1;
236 } line_t;
237 
238 /* Describes a file mentioned in the block graph.  Contains an array
239    of line info.  */
240 
241 typedef struct source_info
242 {
243   /* Canonical name of source file.  */
244   char *name;
245   time_t file_time;
246 
247   /* Array of line information.  */
248   line_t *lines;
249   unsigned num_lines;
250 
251   coverage_t coverage;
252 
253   /* Functions in this source file.  These are in ascending line
254      number order.  */
255   function_t *functions;
256 } source_t;
257 
258 typedef struct name_map
259 {
260   char *name;  /* Source file name */
261   unsigned src;  /* Source file */
262 } name_map_t;
263 
264 /* Holds a list of function basic block graphs.  */
265 
266 static function_t *functions;
267 static function_t **fn_end = &functions;
268 
269 static source_t *sources;   /* Array of source files  */
270 static unsigned n_sources;  /* Number of sources */
271 static unsigned a_sources;  /* Allocated sources */
272 
273 static name_map_t *names;   /* Mapping of file names to sources */
274 static unsigned n_names;    /* Number of names */
275 static unsigned a_names;    /* Allocated names */
276 
277 /* This holds data summary information.  */
278 
279 static unsigned object_runs;
280 static unsigned program_count;
281 
282 static unsigned total_lines;
283 static unsigned total_executed;
284 
285 /* Modification time of graph file.  */
286 
287 static time_t bbg_file_time;
288 
289 /* Name of the notes (gcno) output file.  The "bbg" prefix is for
290    historical reasons, when the notes file contained only the
291    basic block graph notes.  */
292 
293 static char *bbg_file_name;
294 
295 /* Stamp of the bbg file */
296 static unsigned bbg_stamp;
297 
298 /* Name and file pointer of the input file for the count data (gcda).  */
299 
300 static char *da_file_name;
301 
302 /* Data file is missing.  */
303 
304 static int no_data_file;
305 
306 /* If there is several input files, compute and display results after
307    reading all data files.  This way if two or more gcda file refer to
308    the same source file (eg inline subprograms in a .h file), the
309    counts are added.  */
310 
311 static int multiple_files = 0;
312 
313 /* Output branch probabilities.  */
314 
315 static int flag_branches = 0;
316 
317 /* Show unconditional branches too.  */
318 static int flag_unconditional = 0;
319 
320 /* Output a gcov file if this is true.  This is on by default, and can
321    be turned off by the -n option.  */
322 
323 static int flag_gcov_file = 1;
324 
325 /* Output progress indication if this is true.  This is off by default
326    and can be turned on by the -d option.  */
327 
328 static int flag_display_progress = 0;
329 
330 /* Output *.gcov file in intermediate format used by 'lcov'.  */
331 
332 static int flag_intermediate_format = 0;
333 
334 /* Output demangled function names.  */
335 
336 static int flag_demangled_names = 0;
337 
338 /* For included files, make the gcov output file name include the name
339    of the input source file.  For example, if x.h is included in a.c,
340    then the output file name is a.c##x.h.gcov instead of x.h.gcov.  */
341 
342 static int flag_long_names = 0;
343 
344 /* Output count information for every basic block, not merely those
345    that contain line number information.  */
346 
347 static int flag_all_blocks = 0;
348 
349 /* Output summary info for each function.  */
350 
351 static int flag_function_summary = 0;
352 
353 /* Object directory file prefix.  This is the directory/file where the
354    graph and data files are looked for, if nonzero.  */
355 
356 static char *object_directory = 0;
357 
358 /* Source directory prefix.  This is removed from source pathnames
359    that match, when generating the output file name.  */
360 
361 static char *source_prefix = 0;
362 static size_t source_length = 0;
363 
364 /* Only show data for sources with relative pathnames.  Absolute ones
365    usually indicate a system header file, which although it may
366    contain inline functions, is usually uninteresting.  */
367 static int flag_relative_only = 0;
368 
369 /* Preserve all pathname components. Needed when object files and
370    source files are in subdirectories. '/' is mangled as '#', '.' is
371    elided and '..' mangled to '^'.  */
372 
373 static int flag_preserve_paths = 0;
374 
375 /* Output the number of times a branch was taken as opposed to the percentage
376    of times it was taken.  */
377 
378 static int flag_counts = 0;
379 
380 /* Forward declarations.  */
381 static int process_args (int, char **);
382 static void print_usage (int) ATTRIBUTE_NORETURN;
383 static void print_version (void) ATTRIBUTE_NORETURN;
384 static void process_file (const char *);
385 static void generate_results (const char *);
386 static void create_file_names (const char *);
387 static int name_search (const void *, const void *);
388 static int name_sort (const void *, const void *);
389 static char *canonicalize_name (const char *);
390 static unsigned find_source (const char *);
391 static function_t *read_graph_file (void);
392 static int read_count_file (function_t *);
393 static void solve_flow_graph (function_t *);
394 static void find_exception_blocks (function_t *);
395 static void add_branch_counts (coverage_t *, const arc_t *);
396 static void add_line_counts (coverage_t *, function_t *);
397 static void executed_summary (unsigned, unsigned);
398 static void function_summary (const coverage_t *, const char *);
399 static const char *format_gcov (gcov_type, gcov_type, int);
400 static void accumulate_line_counts (source_t *);
401 static void output_gcov_file (const char *, source_t *);
402 static int output_branch_count (FILE *, int, const arc_t *);
403 static void output_lines (FILE *, const source_t *);
404 static char *make_gcov_file_name (const char *, const char *);
405 static char *mangle_name (const char *, char *);
406 static void release_structures (void);
407 static void release_function (function_t *);
408 extern int main (int, char **);
409 
410 int
main(int argc,char ** argv)411 main (int argc, char **argv)
412 {
413   int argno;
414   int first_arg;
415   const char *p;
416 
417   p = argv[0] + strlen (argv[0]);
418   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
419     --p;
420   progname = p;
421 
422   xmalloc_set_program_name (progname);
423 
424   /* Unlock the stdio streams.  */
425   unlock_std_streams ();
426 
427   gcc_init_libintl ();
428 
429   diagnostic_initialize (global_dc, 0);
430 
431   /* Handle response files.  */
432   expandargv (&argc, &argv);
433 
434   a_names = 10;
435   names = XNEWVEC (name_map_t, a_names);
436   a_sources = 10;
437   sources = XNEWVEC (source_t, a_sources);
438 
439   argno = process_args (argc, argv);
440   if (optind == argc)
441     print_usage (true);
442 
443   if (argc - argno > 1)
444     multiple_files = 1;
445 
446   first_arg = argno;
447 
448   for (; argno != argc; argno++)
449     {
450       if (flag_display_progress)
451         printf ("Processing file %d out of %d\n",
452 		argno - first_arg + 1, argc - first_arg);
453       process_file (argv[argno]);
454     }
455 
456   generate_results (multiple_files ? NULL : argv[argc - 1]);
457 
458   release_structures ();
459 
460   return 0;
461 }
462 
463 /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
464    otherwise the output of --help.  */
465 
466 static void
print_usage(int error_p)467 print_usage (int error_p)
468 {
469   FILE *file = error_p ? stderr : stdout;
470   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
471 
472   fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
473   fnotice (file, "Print code coverage information.\n\n");
474   fnotice (file, "  -a, --all-blocks                Show information for every basic block\n");
475   fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output\n");
476   fnotice (file, "  -c, --branch-counts             Output counts of branches taken\n\
477                                     rather than percentages\n");
478   fnotice (file, "  -d, --display-progress          Display progress information\n");
479   fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
480   fnotice (file, "  -h, --help                      Print this help, then exit\n");
481   fnotice (file, "  -i, --intermediate-format       Output .gcov file in intermediate text format\n");
482   fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
483                                     source files\n");
484   fnotice (file, "  -m, --demangled-names           Output demangled function names\n");
485   fnotice (file, "  -n, --no-output                 Do not create an output file\n");
486   fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
487   fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
488   fnotice (file, "  -r, --relative-only             Only show data for relative sources\n");
489   fnotice (file, "  -s, --source-prefix DIR         Source prefix to elide\n");
490   fnotice (file, "  -u, --unconditional-branches    Show unconditional branch counts too\n");
491   fnotice (file, "  -v, --version                   Print version number, then exit\n");
492   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
493 	   bug_report_url);
494   exit (status);
495 }
496 
497 /* Print version information and exit.  */
498 
499 static void
print_version(void)500 print_version (void)
501 {
502   fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
503   fprintf (stdout, "Copyright %s 2017 Free Software Foundation, Inc.\n",
504 	   _("(C)"));
505   fnotice (stdout,
506 	   _("This is free software; see the source for copying conditions.\n"
507 	     "There is NO warranty; not even for MERCHANTABILITY or \n"
508 	     "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
509   exit (SUCCESS_EXIT_CODE);
510 }
511 
512 static const struct option options[] =
513 {
514   { "help",                 no_argument,       NULL, 'h' },
515   { "version",              no_argument,       NULL, 'v' },
516   { "all-blocks",           no_argument,       NULL, 'a' },
517   { "branch-probabilities", no_argument,       NULL, 'b' },
518   { "branch-counts",        no_argument,       NULL, 'c' },
519   { "intermediate-format",  no_argument,       NULL, 'i' },
520   { "no-output",            no_argument,       NULL, 'n' },
521   { "long-file-names",      no_argument,       NULL, 'l' },
522   { "function-summaries",   no_argument,       NULL, 'f' },
523   { "demangled-names",      no_argument,       NULL, 'm' },
524   { "preserve-paths",       no_argument,       NULL, 'p' },
525   { "relative-only",        no_argument,       NULL, 'r' },
526   { "object-directory",     required_argument, NULL, 'o' },
527   { "object-file",          required_argument, NULL, 'o' },
528   { "source-prefix",        required_argument, NULL, 's' },
529   { "unconditional-branches", no_argument,     NULL, 'u' },
530   { "display-progress",     no_argument,       NULL, 'd' },
531   { 0, 0, 0, 0 }
532 };
533 
534 /* Process args, return index to first non-arg.  */
535 
536 static int
process_args(int argc,char ** argv)537 process_args (int argc, char **argv)
538 {
539   int opt;
540 
541   while ((opt = getopt_long (argc, argv, "abcdfhilmno:s:pruv", options, NULL)) !=
542          -1)
543     {
544       switch (opt)
545 	{
546 	case 'a':
547 	  flag_all_blocks = 1;
548 	  break;
549 	case 'b':
550 	  flag_branches = 1;
551 	  break;
552 	case 'c':
553 	  flag_counts = 1;
554 	  break;
555 	case 'f':
556 	  flag_function_summary = 1;
557 	  break;
558 	case 'h':
559 	  print_usage (false);
560 	  /* print_usage will exit.  */
561 	case 'l':
562 	  flag_long_names = 1;
563 	  break;
564 	case 'm':
565 	  flag_demangled_names = 1;
566 	  break;
567 	case 'n':
568 	  flag_gcov_file = 0;
569 	  break;
570 	case 'o':
571 	  object_directory = optarg;
572 	  break;
573 	case 's':
574 	  source_prefix = optarg;
575 	  source_length = strlen (source_prefix);
576 	  break;
577 	case 'r':
578 	  flag_relative_only = 1;
579 	  break;
580 	case 'p':
581 	  flag_preserve_paths = 1;
582 	  break;
583 	case 'u':
584 	  flag_unconditional = 1;
585 	  break;
586 	case 'i':
587           flag_intermediate_format = 1;
588           flag_gcov_file = 1;
589           break;
590         case 'd':
591           flag_display_progress = 1;
592           break;
593 	case 'v':
594 	  print_version ();
595 	  /* print_version will exit.  */
596 	default:
597 	  print_usage (true);
598 	  /* print_usage will exit.  */
599 	}
600     }
601 
602   return optind;
603 }
604 
605 /* Output the result in intermediate format used by 'lcov'.
606 
607 The intermediate format contains a single file named 'foo.cc.gcov',
608 with no source code included. A sample output is
609 
610 file:foo.cc
611 function:5,1,_Z3foov
612 function:13,1,main
613 function:19,1,_GLOBAL__sub_I__Z3foov
614 function:19,1,_Z41__static_initialization_and_destruction_0ii
615 lcount:5,1
616 lcount:7,9
617 lcount:9,8
618 lcount:11,1
619 file:/.../iostream
620 lcount:74,1
621 file:/.../basic_ios.h
622 file:/.../ostream
623 file:/.../ios_base.h
624 function:157,0,_ZStorSt12_Ios_IostateS_
625 lcount:157,0
626 file:/.../char_traits.h
627 function:258,0,_ZNSt11char_traitsIcE6lengthEPKc
628 lcount:258,0
629 ...
630 
631 The default gcov outputs multiple files: 'foo.cc.gcov',
632 'iostream.gcov', 'ios_base.h.gcov', etc. with source code
633 included. Instead the intermediate format here outputs only a single
634 file 'foo.cc.gcov' similar to the above example. */
635 
636 static void
output_intermediate_file(FILE * gcov_file,source_t * src)637 output_intermediate_file (FILE *gcov_file, source_t *src)
638 {
639   unsigned line_num;    /* current line number.  */
640   const line_t *line;   /* current line info ptr.  */
641   function_t *fn;       /* current function info ptr. */
642 
643   fprintf (gcov_file, "file:%s\n", src->name);    /* source file name */
644 
645   for (fn = src->functions; fn; fn = fn->line_next)
646     {
647       /* function:<name>,<line_number>,<execution_count> */
648       fprintf (gcov_file, "function:%d,%s,%s\n", fn->line,
649                format_gcov (fn->blocks[0].count, 0, -1),
650                flag_demangled_names ? fn->demangled_name : fn->name);
651     }
652 
653   for (line_num = 1, line = &src->lines[line_num];
654        line_num < src->num_lines;
655        line_num++, line++)
656     {
657       arc_t *arc;
658       if (line->exists)
659         fprintf (gcov_file, "lcount:%u,%s\n", line_num,
660                  format_gcov (line->count, 0, -1));
661       if (flag_branches)
662         for (arc = line->u.branches; arc; arc = arc->line_next)
663           {
664             if (!arc->is_unconditional && !arc->is_call_non_return)
665               {
666                 const char *branch_type;
667                 /* branch:<line_num>,<branch_coverage_type>
668                    branch_coverage_type
669                      : notexec (Branch not executed)
670                      : taken (Branch executed and taken)
671                      : nottaken (Branch executed, but not taken)
672                 */
673                 if (arc->src->count)
674                   branch_type = (arc->count > 0) ? "taken" : "nottaken";
675                 else
676                   branch_type = "notexec";
677                 fprintf (gcov_file, "branch:%d,%s\n", line_num, branch_type);
678               }
679           }
680     }
681 }
682 
683 
684 /* Process a single input file.  */
685 
686 static void
process_file(const char * file_name)687 process_file (const char *file_name)
688 {
689   function_t *fns;
690 
691   create_file_names (file_name);
692   fns = read_graph_file ();
693   if (!fns)
694     return;
695 
696   read_count_file (fns);
697   while (fns)
698     {
699       function_t *fn = fns;
700 
701       fns = fn->next;
702       fn->next = NULL;
703       if (fn->counts || no_data_file)
704 	{
705 	  unsigned src = fn->src;
706 	  unsigned line = fn->line;
707 	  unsigned block_no;
708 	  function_t *probe, **prev;
709 
710 	  /* Now insert it into the source file's list of
711 	     functions. Normally functions will be encountered in
712 	     ascending order, so a simple scan is quick.  Note we're
713 	     building this list in reverse order.  */
714 	  for (prev = &sources[src].functions;
715 	       (probe = *prev); prev = &probe->line_next)
716 	    if (probe->line <= line)
717 	      break;
718 	  fn->line_next = probe;
719 	  *prev = fn;
720 
721 	  /* Mark last line in files touched by function.  */
722 	  for (block_no = 0; block_no != fn->num_blocks; block_no++)
723 	    {
724 	      unsigned *enc = fn->blocks[block_no].u.line.encoding;
725 	      unsigned num = fn->blocks[block_no].u.line.num;
726 
727 	      for (; num--; enc++)
728 		if (!*enc)
729 		  {
730 		    if (enc[1] != src)
731 		      {
732 			if (line >= sources[src].num_lines)
733 			  sources[src].num_lines = line + 1;
734 			line = 0;
735 			src = enc[1];
736 		      }
737 		    enc++;
738 		    num--;
739 		  }
740 		else if (*enc > line)
741 		  line = *enc;
742 	    }
743 	  if (line >= sources[src].num_lines)
744 	    sources[src].num_lines = line + 1;
745 
746 	  solve_flow_graph (fn);
747 	  if (fn->has_catch)
748 	    find_exception_blocks (fn);
749 	  *fn_end = fn;
750 	  fn_end = &fn->next;
751 	}
752       else
753 	/* The function was not in the executable -- some other
754 	   instance must have been selected.  */
755 	release_function (fn);
756     }
757 }
758 
759 static void
output_gcov_file(const char * file_name,source_t * src)760 output_gcov_file (const char *file_name, source_t *src)
761 {
762   char *gcov_file_name = make_gcov_file_name (file_name, src->coverage.name);
763 
764   if (src->coverage.lines)
765     {
766       FILE *gcov_file = fopen (gcov_file_name, "w");
767       if (gcov_file)
768         {
769           fnotice (stdout, "Creating '%s'\n", gcov_file_name);
770 
771 	  if (flag_intermediate_format)
772 	    output_intermediate_file (gcov_file, src);
773 	  else
774 	    output_lines (gcov_file, src);
775           if (ferror (gcov_file))
776             fnotice (stderr, "Error writing output file '%s'\n", gcov_file_name);
777           fclose (gcov_file);
778         }
779       else
780         fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
781     }
782   else
783     {
784       unlink (gcov_file_name);
785       fnotice (stdout, "Removing '%s'\n", gcov_file_name);
786     }
787   free (gcov_file_name);
788 }
789 
790 static void
generate_results(const char * file_name)791 generate_results (const char *file_name)
792 {
793   unsigned ix;
794   source_t *src;
795   function_t *fn;
796 
797   for (ix = n_sources, src = sources; ix--; src++)
798     if (src->num_lines)
799       src->lines = XCNEWVEC (line_t, src->num_lines);
800 
801   for (fn = functions; fn; fn = fn->next)
802     {
803       coverage_t coverage;
804 
805       memset (&coverage, 0, sizeof (coverage));
806       coverage.name = flag_demangled_names ? fn->demangled_name : fn->name;
807       add_line_counts (flag_function_summary ? &coverage : NULL, fn);
808       if (flag_function_summary)
809 	{
810 	  function_summary (&coverage, "Function");
811 	  fnotice (stdout, "\n");
812 	}
813     }
814 
815   if (file_name)
816     {
817       name_map_t *name_map = (name_map_t *)bsearch
818 	(file_name, names, n_names, sizeof (*names), name_search);
819       if (name_map)
820 	file_name = sources[name_map->src].coverage.name;
821       else
822 	file_name = canonicalize_name (file_name);
823     }
824 
825   for (ix = n_sources, src = sources; ix--; src++)
826     {
827       if (flag_relative_only)
828 	{
829 	  /* Ignore this source, if it is an absolute path (after
830 	     source prefix removal).  */
831 	  char first = src->coverage.name[0];
832 
833 #if HAVE_DOS_BASED_FILE_SYSTEM
834 	  if (first && src->coverage.name[1] == ':')
835 	    first = src->coverage.name[2];
836 #endif
837 	  if (IS_DIR_SEPARATOR (first))
838 	    continue;
839 	}
840 
841       accumulate_line_counts (src);
842       function_summary (&src->coverage, "File");
843       total_lines += src->coverage.lines;
844       total_executed += src->coverage.lines_executed;
845       if (flag_gcov_file)
846 	{
847 	  output_gcov_file (file_name, src);
848           fnotice (stdout, "\n");
849         }
850     }
851 
852   if (!file_name)
853     executed_summary (total_lines, total_executed);
854 }
855 
856 /* Release a function structure */
857 
858 static void
release_function(function_t * fn)859 release_function (function_t *fn)
860 {
861   unsigned ix;
862   block_t *block;
863 
864   for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
865     {
866       arc_t *arc, *arc_n;
867 
868       for (arc = block->succ; arc; arc = arc_n)
869 	{
870 	  arc_n = arc->succ_next;
871 	  free (arc);
872 	}
873     }
874   free (fn->blocks);
875   free (fn->counts);
876   if (flag_demangled_names && fn->demangled_name != fn->name)
877     free (fn->demangled_name);
878   free (fn->name);
879 }
880 
881 /* Release all memory used.  */
882 
883 static void
release_structures(void)884 release_structures (void)
885 {
886   unsigned ix;
887   function_t *fn;
888 
889   for (ix = n_sources; ix--;)
890     free (sources[ix].lines);
891   free (sources);
892 
893   for (ix = n_names; ix--;)
894     free (names[ix].name);
895   free (names);
896 
897   while ((fn = functions))
898     {
899       functions = fn->next;
900       release_function (fn);
901     }
902 }
903 
904 /* Generate the names of the graph and data files.  If OBJECT_DIRECTORY
905    is not specified, these are named from FILE_NAME sans extension.  If
906    OBJECT_DIRECTORY is specified and is a directory, the files are in that
907    directory, but named from the basename of the FILE_NAME, sans extension.
908    Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
909    and the data files are named from that.  */
910 
911 static void
create_file_names(const char * file_name)912 create_file_names (const char *file_name)
913 {
914   char *cptr;
915   char *name;
916   int length = strlen (file_name);
917   int base;
918 
919   /* Free previous file names.  */
920   free (bbg_file_name);
921   free (da_file_name);
922   da_file_name = bbg_file_name = NULL;
923   bbg_file_time = 0;
924   bbg_stamp = 0;
925 
926   if (object_directory && object_directory[0])
927     {
928       struct stat status;
929 
930       length += strlen (object_directory) + 2;
931       name = XNEWVEC (char, length);
932       name[0] = 0;
933 
934       base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
935       strcat (name, object_directory);
936       if (base && (! IS_DIR_SEPARATOR (name[strlen (name) - 1])))
937 	strcat (name, "/");
938     }
939   else
940     {
941       name = XNEWVEC (char, length + 1);
942       strcpy (name, file_name);
943       base = 0;
944     }
945 
946   if (base)
947     {
948       /* Append source file name.  */
949       const char *cptr = lbasename (file_name);
950       strcat (name, cptr ? cptr : file_name);
951     }
952 
953   /* Remove the extension.  */
954   cptr = strrchr (CONST_CAST (char *, lbasename (name)), '.');
955   if (cptr)
956     *cptr = 0;
957 
958   length = strlen (name);
959 
960   bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
961   strcpy (bbg_file_name, name);
962   strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
963 
964   da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
965   strcpy (da_file_name, name);
966   strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
967 
968   free (name);
969   return;
970 }
971 
972 /* A is a string and B is a pointer to name_map_t.  Compare for file
973    name orderability.  */
974 
975 static int
name_search(const void * a_,const void * b_)976 name_search (const void *a_, const void *b_)
977 {
978   const char *a = (const char *)a_;
979   const name_map_t *b = (const name_map_t *)b_;
980 
981 #if HAVE_DOS_BASED_FILE_SYSTEM
982   return strcasecmp (a, b->name);
983 #else
984   return strcmp (a, b->name);
985 #endif
986 }
987 
988 /* A and B are a pointer to name_map_t.  Compare for file name
989    orderability.  */
990 
991 static int
name_sort(const void * a_,const void * b_)992 name_sort (const void *a_, const void *b_)
993 {
994   const name_map_t *a = (const name_map_t *)a_;
995   return name_search (a->name, b_);
996 }
997 
998 /* Find or create a source file structure for FILE_NAME. Copies
999    FILE_NAME on creation */
1000 
1001 static unsigned
find_source(const char * file_name)1002 find_source (const char *file_name)
1003 {
1004   name_map_t *name_map;
1005   char *canon;
1006   unsigned idx;
1007   struct stat status;
1008 
1009   if (!file_name)
1010     file_name = "<unknown>";
1011   name_map = (name_map_t *)bsearch
1012     (file_name, names, n_names, sizeof (*names), name_search);
1013   if (name_map)
1014     {
1015       idx = name_map->src;
1016       goto check_date;
1017     }
1018 
1019   if (n_names + 2 > a_names)
1020     {
1021       /* Extend the name map array -- we'll be inserting one or two
1022 	 entries.  */
1023       a_names *= 2;
1024       name_map = XNEWVEC (name_map_t, a_names);
1025       memcpy (name_map, names, n_names * sizeof (*names));
1026       free (names);
1027       names = name_map;
1028     }
1029 
1030   /* Not found, try the canonical name. */
1031   canon = canonicalize_name (file_name);
1032   name_map = (name_map_t *)bsearch
1033     (canon, names, n_names, sizeof (*names), name_search);
1034   if (!name_map)
1035     {
1036       /* Not found with canonical name, create a new source.  */
1037       source_t *src;
1038 
1039       if (n_sources == a_sources)
1040 	{
1041 	  a_sources *= 2;
1042 	  src = XNEWVEC (source_t, a_sources);
1043 	  memcpy (src, sources, n_sources * sizeof (*sources));
1044 	  free (sources);
1045 	  sources = src;
1046 	}
1047 
1048       idx = n_sources;
1049 
1050       name_map = &names[n_names++];
1051       name_map->name = canon;
1052       name_map->src = idx;
1053 
1054       src = &sources[n_sources++];
1055       memset (src, 0, sizeof (*src));
1056       src->name = canon;
1057       src->coverage.name = src->name;
1058       if (source_length
1059 #if HAVE_DOS_BASED_FILE_SYSTEM
1060 	  /* You lose if separators don't match exactly in the
1061 	     prefix.  */
1062 	  && !strncasecmp (source_prefix, src->coverage.name, source_length)
1063 #else
1064 	  && !strncmp (source_prefix, src->coverage.name, source_length)
1065 #endif
1066 	  && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
1067 	src->coverage.name += source_length + 1;
1068       if (!stat (src->name, &status))
1069 	src->file_time = status.st_mtime;
1070     }
1071   else
1072     idx = name_map->src;
1073 
1074   if (name_search (file_name, name_map))
1075     {
1076       /* Append the non-canonical name.  */
1077       name_map = &names[n_names++];
1078       name_map->name = xstrdup (file_name);
1079       name_map->src = idx;
1080     }
1081 
1082   /* Resort the name map.  */
1083   qsort (names, n_names, sizeof (*names), name_sort);
1084 
1085  check_date:
1086   if (sources[idx].file_time > bbg_file_time)
1087     {
1088       static int info_emitted;
1089 
1090       fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
1091 	       file_name, bbg_file_name);
1092       if (!info_emitted)
1093 	{
1094 	  fnotice (stderr,
1095 		   "(the message is displayed only once per source file)\n");
1096 	  info_emitted = 1;
1097 	}
1098       sources[idx].file_time = 0;
1099     }
1100 
1101   return idx;
1102 }
1103 
1104 /* Read the notes file.  Return list of functions read -- in reverse order.  */
1105 
1106 static function_t *
read_graph_file(void)1107 read_graph_file (void)
1108 {
1109   unsigned version;
1110   unsigned current_tag = 0;
1111   function_t *fn = NULL;
1112   function_t *fns = NULL;
1113   function_t **fns_end = &fns;
1114   unsigned src_idx = 0;
1115   unsigned ix;
1116   unsigned tag;
1117 
1118   if (!gcov_open (bbg_file_name, 1))
1119     {
1120       fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1121       return fns;
1122     }
1123   bbg_file_time = gcov_time ();
1124   if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1125     {
1126       fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
1127       gcov_close ();
1128       return fns;
1129     }
1130 
1131   version = gcov_read_unsigned ();
1132   if (version != GCOV_VERSION)
1133     {
1134       char v[4], e[4];
1135 
1136       GCOV_UNSIGNED2STRING (v, version);
1137       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1138 
1139       fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1140 	       bbg_file_name, v, e);
1141     }
1142   bbg_stamp = gcov_read_unsigned ();
1143 
1144   while ((tag = gcov_read_unsigned ()))
1145     {
1146       unsigned length = gcov_read_unsigned ();
1147       gcov_position_t base = gcov_position ();
1148 
1149       if (tag == GCOV_TAG_FUNCTION)
1150 	{
1151 	  char *function_name;
1152 	  unsigned ident, lineno;
1153 	  unsigned lineno_checksum, cfg_checksum;
1154 
1155 	  ident = gcov_read_unsigned ();
1156 	  lineno_checksum = gcov_read_unsigned ();
1157 	  cfg_checksum = gcov_read_unsigned ();
1158 	  function_name = xstrdup (gcov_read_string ());
1159 	  src_idx = find_source (gcov_read_string ());
1160 	  lineno = gcov_read_unsigned ();
1161 
1162 	  fn = XCNEW (function_t);
1163 	  fn->name = function_name;
1164           if (flag_demangled_names)
1165             {
1166               fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS);
1167               if (!fn->demangled_name)
1168                 fn->demangled_name = fn->name;
1169             }
1170 	  fn->ident = ident;
1171 	  fn->lineno_checksum = lineno_checksum;
1172 	  fn->cfg_checksum = cfg_checksum;
1173 	  fn->src = src_idx;
1174 	  fn->line = lineno;
1175 
1176 	  fn->line_next = NULL;
1177 	  fn->next = NULL;
1178 	  *fns_end = fn;
1179 	  fns_end = &fn->next;
1180 	  current_tag = tag;
1181 	}
1182       else if (fn && tag == GCOV_TAG_BLOCKS)
1183 	{
1184 	  if (fn->blocks)
1185 	    fnotice (stderr, "%s:already seen blocks for '%s'\n",
1186 		     bbg_file_name, fn->name);
1187 	  else
1188 	    {
1189 	      unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
1190 	      fn->num_blocks = num_blocks;
1191 
1192 	      fn->blocks = XCNEWVEC (block_t, fn->num_blocks);
1193 	      for (ix = 0; ix != num_blocks; ix++)
1194 		fn->blocks[ix].flags = gcov_read_unsigned ();
1195 	    }
1196 	}
1197       else if (fn && tag == GCOV_TAG_ARCS)
1198 	{
1199 	  unsigned src = gcov_read_unsigned ();
1200 	  unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1201 	  block_t *src_blk = &fn->blocks[src];
1202 	  unsigned mark_catches = 0;
1203 	  struct arc_info *arc;
1204 
1205 	  if (src >= fn->num_blocks || fn->blocks[src].succ)
1206 	    goto corrupt;
1207 
1208 	  while (num_dests--)
1209 	    {
1210 	      unsigned dest = gcov_read_unsigned ();
1211 	      unsigned flags = gcov_read_unsigned ();
1212 
1213 	      if (dest >= fn->num_blocks)
1214 		goto corrupt;
1215 	      arc = XCNEW (arc_t);
1216 
1217 	      arc->dst = &fn->blocks[dest];
1218 	      arc->src = src_blk;
1219 
1220 	      arc->count = 0;
1221 	      arc->count_valid = 0;
1222 	      arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
1223 	      arc->fake = !!(flags & GCOV_ARC_FAKE);
1224 	      arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
1225 
1226 	      arc->succ_next = src_blk->succ;
1227 	      src_blk->succ = arc;
1228 	      src_blk->num_succ++;
1229 
1230 	      arc->pred_next = fn->blocks[dest].pred;
1231 	      fn->blocks[dest].pred = arc;
1232 	      fn->blocks[dest].num_pred++;
1233 
1234 	      if (arc->fake)
1235 		{
1236 		  if (src)
1237 		    {
1238 		      /* Exceptional exit from this function, the
1239 			 source block must be a call.  */
1240 		      fn->blocks[src].is_call_site = 1;
1241 		      arc->is_call_non_return = 1;
1242 		      mark_catches = 1;
1243 		    }
1244 		  else
1245 		    {
1246 		      /* Non-local return from a callee of this
1247 		         function. The destination block is a setjmp.  */
1248 		      arc->is_nonlocal_return = 1;
1249 		      fn->blocks[dest].is_nonlocal_return = 1;
1250 		    }
1251 		}
1252 
1253 	      if (!arc->on_tree)
1254 		fn->num_counts++;
1255 	    }
1256 
1257 	  if (mark_catches)
1258 	    {
1259 	      /* We have a fake exit from this block.  The other
1260 		 non-fall through exits must be to catch handlers.
1261 		 Mark them as catch arcs.  */
1262 
1263 	      for (arc = src_blk->succ; arc; arc = arc->succ_next)
1264 		if (!arc->fake && !arc->fall_through)
1265 		  {
1266 		    arc->is_throw = 1;
1267 		    fn->has_catch = 1;
1268 		  }
1269 	    }
1270 	}
1271       else if (fn && tag == GCOV_TAG_LINES)
1272 	{
1273 	  unsigned blockno = gcov_read_unsigned ();
1274 	  unsigned *line_nos = XCNEWVEC (unsigned, length - 1);
1275 
1276 	  if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
1277 	    goto corrupt;
1278 
1279 	  for (ix = 0; ;  )
1280 	    {
1281 	      unsigned lineno = gcov_read_unsigned ();
1282 
1283 	      if (lineno)
1284 		{
1285 		  if (!ix)
1286 		    {
1287 		      line_nos[ix++] = 0;
1288 		      line_nos[ix++] = src_idx;
1289 		    }
1290 		  line_nos[ix++] = lineno;
1291 		}
1292 	      else
1293 		{
1294 		  const char *file_name = gcov_read_string ();
1295 
1296 		  if (!file_name)
1297 		    break;
1298 		  src_idx = find_source (file_name);
1299 		  line_nos[ix++] = 0;
1300 		  line_nos[ix++] = src_idx;
1301 		}
1302 	    }
1303 
1304 	  fn->blocks[blockno].u.line.encoding = line_nos;
1305 	  fn->blocks[blockno].u.line.num = ix;
1306 	}
1307       else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
1308 	{
1309 	  fn = NULL;
1310 	  current_tag = 0;
1311 	}
1312       gcov_sync (base, length);
1313       if (gcov_is_error ())
1314 	{
1315 	corrupt:;
1316 	  fnotice (stderr, "%s:corrupted\n", bbg_file_name);
1317 	  break;
1318 	}
1319     }
1320   gcov_close ();
1321 
1322   if (!fns)
1323     fnotice (stderr, "%s:no functions found\n", bbg_file_name);
1324 
1325   return fns;
1326 }
1327 
1328 /* Reads profiles from the count file and attach to each
1329    function. Return nonzero if fatal error.  */
1330 
1331 static int
read_count_file(function_t * fns)1332 read_count_file (function_t *fns)
1333 {
1334   unsigned ix;
1335   unsigned version;
1336   unsigned tag;
1337   function_t *fn = NULL;
1338   int error = 0;
1339 
1340   if (!gcov_open (da_file_name, 1))
1341     {
1342       fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
1343 	       da_file_name);
1344       no_data_file = 1;
1345       return 0;
1346     }
1347   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
1348     {
1349       fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
1350     cleanup:;
1351       gcov_close ();
1352       return 1;
1353     }
1354   version = gcov_read_unsigned ();
1355   if (version != GCOV_VERSION)
1356     {
1357       char v[4], e[4];
1358 
1359       GCOV_UNSIGNED2STRING (v, version);
1360       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1361 
1362       fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
1363 	       da_file_name, v, e);
1364     }
1365   tag = gcov_read_unsigned ();
1366   if (tag != bbg_stamp)
1367     {
1368       fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
1369       goto cleanup;
1370     }
1371 
1372   while ((tag = gcov_read_unsigned ()))
1373     {
1374       unsigned length = gcov_read_unsigned ();
1375       unsigned long base = gcov_position ();
1376 
1377       if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1378 	{
1379 	  struct gcov_summary summary;
1380 	  gcov_read_summary (&summary);
1381 	  object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs;
1382 	  program_count++;
1383 	}
1384       else if (tag == GCOV_TAG_FUNCTION && !length)
1385 	; /* placeholder  */
1386       else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
1387 	{
1388 	  unsigned ident;
1389 	  struct function_info *fn_n;
1390 
1391 	  /* Try to find the function in the list.  To speed up the
1392 	     search, first start from the last function found.  */
1393 	  ident = gcov_read_unsigned ();
1394 	  fn_n = fns;
1395 	  for (fn = fn ? fn->next : NULL; ; fn = fn->next)
1396 	    {
1397 	      if (fn)
1398 		;
1399 	      else if ((fn = fn_n))
1400 		fn_n = NULL;
1401 	      else
1402 		{
1403 		  fnotice (stderr, "%s:unknown function '%u'\n",
1404 			   da_file_name, ident);
1405 		  break;
1406 		}
1407 	      if (fn->ident == ident)
1408 		break;
1409 	    }
1410 
1411 	  if (!fn)
1412 	    ;
1413 	  else if (gcov_read_unsigned () != fn->lineno_checksum
1414 		   || gcov_read_unsigned () != fn->cfg_checksum)
1415 	    {
1416 	    mismatch:;
1417 	      fnotice (stderr, "%s:profile mismatch for '%s'\n",
1418 		       da_file_name, fn->name);
1419 	      goto cleanup;
1420 	    }
1421 	}
1422       else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1423 	{
1424 	  if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
1425 	    goto mismatch;
1426 
1427 	  if (!fn->counts)
1428 	    fn->counts = XCNEWVEC (gcov_type, fn->num_counts);
1429 
1430 	  for (ix = 0; ix != fn->num_counts; ix++)
1431 	    fn->counts[ix] += gcov_read_counter ();
1432 	}
1433       gcov_sync (base, length);
1434       if ((error = gcov_is_error ()))
1435 	{
1436 	  fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1437 		   da_file_name);
1438 	  goto cleanup;
1439 	}
1440     }
1441 
1442   gcov_close ();
1443   return 0;
1444 }
1445 
1446 /* Solve the flow graph. Propagate counts from the instrumented arcs
1447    to the blocks and the uninstrumented arcs.  */
1448 
1449 static void
solve_flow_graph(function_t * fn)1450 solve_flow_graph (function_t *fn)
1451 {
1452   unsigned ix;
1453   arc_t *arc;
1454   gcov_type *count_ptr = fn->counts;
1455   block_t *blk;
1456   block_t *valid_blocks = NULL;    /* valid, but unpropagated blocks.  */
1457   block_t *invalid_blocks = NULL;  /* invalid, but inferable blocks.  */
1458 
1459   /* The arcs were built in reverse order.  Fix that now.  */
1460   for (ix = fn->num_blocks; ix--;)
1461     {
1462       arc_t *arc_p, *arc_n;
1463 
1464       for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
1465 	   arc_p = arc, arc = arc_n)
1466 	{
1467 	  arc_n = arc->succ_next;
1468 	  arc->succ_next = arc_p;
1469 	}
1470       fn->blocks[ix].succ = arc_p;
1471 
1472       for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
1473 	   arc_p = arc, arc = arc_n)
1474 	{
1475 	  arc_n = arc->pred_next;
1476 	  arc->pred_next = arc_p;
1477 	}
1478       fn->blocks[ix].pred = arc_p;
1479     }
1480 
1481   if (fn->num_blocks < 2)
1482     fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
1483 	     bbg_file_name, fn->name);
1484   else
1485     {
1486       if (fn->blocks[ENTRY_BLOCK].num_pred)
1487 	fnotice (stderr, "%s:'%s' has arcs to entry block\n",
1488 		 bbg_file_name, fn->name);
1489       else
1490 	/* We can't deduce the entry block counts from the lack of
1491 	   predecessors.  */
1492 	fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
1493 
1494       if (fn->blocks[EXIT_BLOCK].num_succ)
1495 	fnotice (stderr, "%s:'%s' has arcs from exit block\n",
1496 		 bbg_file_name, fn->name);
1497       else
1498 	/* Likewise, we can't deduce exit block counts from the lack
1499 	   of its successors.  */
1500 	fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
1501     }
1502 
1503   /* Propagate the measured counts, this must be done in the same
1504      order as the code in profile.c  */
1505   for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
1506     {
1507       block_t const *prev_dst = NULL;
1508       int out_of_order = 0;
1509       int non_fake_succ = 0;
1510 
1511       for (arc = blk->succ; arc; arc = arc->succ_next)
1512 	{
1513 	  if (!arc->fake)
1514 	    non_fake_succ++;
1515 
1516 	  if (!arc->on_tree)
1517 	    {
1518 	      if (count_ptr)
1519 		arc->count = *count_ptr++;
1520 	      arc->count_valid = 1;
1521 	      blk->num_succ--;
1522 	      arc->dst->num_pred--;
1523 	    }
1524 	  if (prev_dst && prev_dst > arc->dst)
1525 	    out_of_order = 1;
1526 	  prev_dst = arc->dst;
1527 	}
1528       if (non_fake_succ == 1)
1529 	{
1530 	  /* If there is only one non-fake exit, it is an
1531 	     unconditional branch.  */
1532 	  for (arc = blk->succ; arc; arc = arc->succ_next)
1533 	    if (!arc->fake)
1534 	      {
1535 		arc->is_unconditional = 1;
1536 		/* If this block is instrumenting a call, it might be
1537 		   an artificial block. It is not artificial if it has
1538 		   a non-fallthrough exit, or the destination of this
1539 		   arc has more than one entry.  Mark the destination
1540 		   block as a return site, if none of those conditions
1541 		   hold.  */
1542 		if (blk->is_call_site && arc->fall_through
1543 		    && arc->dst->pred == arc && !arc->pred_next)
1544 		  arc->dst->is_call_return = 1;
1545 	      }
1546 	}
1547 
1548       /* Sort the successor arcs into ascending dst order. profile.c
1549 	 normally produces arcs in the right order, but sometimes with
1550 	 one or two out of order.  We're not using a particularly
1551 	 smart sort.  */
1552       if (out_of_order)
1553 	{
1554 	  arc_t *start = blk->succ;
1555 	  unsigned changes = 1;
1556 
1557 	  while (changes)
1558 	    {
1559 	      arc_t *arc, *arc_p, *arc_n;
1560 
1561 	      changes = 0;
1562 	      for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1563 		{
1564 		  if (arc->dst > arc_n->dst)
1565 		    {
1566 		      changes = 1;
1567 		      if (arc_p)
1568 			arc_p->succ_next = arc_n;
1569 		      else
1570 			start = arc_n;
1571 		      arc->succ_next = arc_n->succ_next;
1572 		      arc_n->succ_next = arc;
1573 		      arc_p = arc_n;
1574 		    }
1575 		  else
1576 		    {
1577 		      arc_p = arc;
1578 		      arc = arc_n;
1579 		    }
1580 		}
1581 	    }
1582 	  blk->succ = start;
1583 	}
1584 
1585       /* Place it on the invalid chain, it will be ignored if that's
1586 	 wrong.  */
1587       blk->invalid_chain = 1;
1588       blk->chain = invalid_blocks;
1589       invalid_blocks = blk;
1590     }
1591 
1592   while (invalid_blocks || valid_blocks)
1593     {
1594       while ((blk = invalid_blocks))
1595 	{
1596 	  gcov_type total = 0;
1597 	  const arc_t *arc;
1598 
1599 	  invalid_blocks = blk->chain;
1600 	  blk->invalid_chain = 0;
1601 	  if (!blk->num_succ)
1602 	    for (arc = blk->succ; arc; arc = arc->succ_next)
1603 	      total += arc->count;
1604 	  else if (!blk->num_pred)
1605 	    for (arc = blk->pred; arc; arc = arc->pred_next)
1606 	      total += arc->count;
1607 	  else
1608 	    continue;
1609 
1610 	  blk->count = total;
1611 	  blk->count_valid = 1;
1612 	  blk->chain = valid_blocks;
1613 	  blk->valid_chain = 1;
1614 	  valid_blocks = blk;
1615 	}
1616       while ((blk = valid_blocks))
1617 	{
1618 	  gcov_type total;
1619 	  arc_t *arc, *inv_arc;
1620 
1621 	  valid_blocks = blk->chain;
1622 	  blk->valid_chain = 0;
1623 	  if (blk->num_succ == 1)
1624 	    {
1625 	      block_t *dst;
1626 
1627 	      total = blk->count;
1628 	      inv_arc = NULL;
1629 	      for (arc = blk->succ; arc; arc = arc->succ_next)
1630 		{
1631 		  total -= arc->count;
1632 		  if (!arc->count_valid)
1633 		    inv_arc = arc;
1634 		}
1635 	      dst = inv_arc->dst;
1636 	      inv_arc->count_valid = 1;
1637 	      inv_arc->count = total;
1638 	      blk->num_succ--;
1639 	      dst->num_pred--;
1640 	      if (dst->count_valid)
1641 		{
1642 		  if (dst->num_pred == 1 && !dst->valid_chain)
1643 		    {
1644 		      dst->chain = valid_blocks;
1645 		      dst->valid_chain = 1;
1646 		      valid_blocks = dst;
1647 		    }
1648 		}
1649 	      else
1650 		{
1651 		  if (!dst->num_pred && !dst->invalid_chain)
1652 		    {
1653 		      dst->chain = invalid_blocks;
1654 		      dst->invalid_chain = 1;
1655 		      invalid_blocks = dst;
1656 		    }
1657 		}
1658 	    }
1659 	  if (blk->num_pred == 1)
1660 	    {
1661 	      block_t *src;
1662 
1663 	      total = blk->count;
1664 	      inv_arc = NULL;
1665 	      for (arc = blk->pred; arc; arc = arc->pred_next)
1666 		{
1667 		  total -= arc->count;
1668 		  if (!arc->count_valid)
1669 		    inv_arc = arc;
1670 		}
1671 	      src = inv_arc->src;
1672 	      inv_arc->count_valid = 1;
1673 	      inv_arc->count = total;
1674 	      blk->num_pred--;
1675 	      src->num_succ--;
1676 	      if (src->count_valid)
1677 		{
1678 		  if (src->num_succ == 1 && !src->valid_chain)
1679 		    {
1680 		      src->chain = valid_blocks;
1681 		      src->valid_chain = 1;
1682 		      valid_blocks = src;
1683 		    }
1684 		}
1685 	      else
1686 		{
1687 		  if (!src->num_succ && !src->invalid_chain)
1688 		    {
1689 		      src->chain = invalid_blocks;
1690 		      src->invalid_chain = 1;
1691 		      invalid_blocks = src;
1692 		    }
1693 		}
1694 	    }
1695 	}
1696     }
1697 
1698   /* If the graph has been correctly solved, every block will have a
1699      valid count.  */
1700   for (ix = 0; ix < fn->num_blocks; ix++)
1701     if (!fn->blocks[ix].count_valid)
1702       {
1703 	fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
1704 		 bbg_file_name, fn->name);
1705 	break;
1706       }
1707 }
1708 
1709 /* Mark all the blocks only reachable via an incoming catch.  */
1710 
1711 static void
find_exception_blocks(function_t * fn)1712 find_exception_blocks (function_t *fn)
1713 {
1714   unsigned ix;
1715   block_t **queue = XALLOCAVEC (block_t *, fn->num_blocks);
1716 
1717   /* First mark all blocks as exceptional.  */
1718   for (ix = fn->num_blocks; ix--;)
1719     fn->blocks[ix].exceptional = 1;
1720 
1721   /* Now mark all the blocks reachable via non-fake edges */
1722   queue[0] = fn->blocks;
1723   queue[0]->exceptional = 0;
1724   for (ix = 1; ix;)
1725     {
1726       block_t *block = queue[--ix];
1727       const arc_t *arc;
1728 
1729       for (arc = block->succ; arc; arc = arc->succ_next)
1730 	if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
1731 	  {
1732 	    arc->dst->exceptional = 0;
1733 	    queue[ix++] = arc->dst;
1734 	  }
1735     }
1736 }
1737 
1738 
1739 /* Increment totals in COVERAGE according to arc ARC.  */
1740 
1741 static void
add_branch_counts(coverage_t * coverage,const arc_t * arc)1742 add_branch_counts (coverage_t *coverage, const arc_t *arc)
1743 {
1744   if (arc->is_call_non_return)
1745     {
1746       coverage->calls++;
1747       if (arc->src->count)
1748 	coverage->calls_executed++;
1749     }
1750   else if (!arc->is_unconditional)
1751     {
1752       coverage->branches++;
1753       if (arc->src->count)
1754 	coverage->branches_executed++;
1755       if (arc->count)
1756 	coverage->branches_taken++;
1757     }
1758 }
1759 
1760 /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
1761    count.  If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1762    If DP is zero, no decimal point is printed. Only print 100% when
1763    TOP==BOTTOM and only print 0% when TOP=0.  If dp < 0, then simply
1764    format TOP.  Return pointer to a static string.  */
1765 
1766 static char const *
format_gcov(gcov_type top,gcov_type bottom,int dp)1767 format_gcov (gcov_type top, gcov_type bottom, int dp)
1768 {
1769   static char buffer[20];
1770 
1771   /* Handle invalid values that would result in a misleading value.  */
1772   if (bottom != 0 && top > bottom && dp >= 0)
1773     {
1774       sprintf (buffer, "NAN %%");
1775       return buffer;
1776     }
1777 
1778   if (dp >= 0)
1779     {
1780       float ratio = bottom ? (float)top / bottom : 0;
1781       int ix;
1782       unsigned limit = 100;
1783       unsigned percent;
1784 
1785       for (ix = dp; ix--; )
1786 	limit *= 10;
1787 
1788       percent = (unsigned) (ratio * limit + (float)0.5);
1789       if (percent <= 0 && top)
1790 	percent = 1;
1791       else if (percent >= limit && top != bottom)
1792 	percent = limit - 1;
1793       ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1794       if (dp)
1795 	{
1796 	  dp++;
1797 	  do
1798 	    {
1799 	      buffer[ix+1] = buffer[ix];
1800 	      ix--;
1801 	    }
1802 	  while (dp--);
1803 	  buffer[ix + 1] = '.';
1804 	}
1805     }
1806   else
1807     sprintf (buffer, "%" PRId64, (int64_t)top);
1808 
1809   return buffer;
1810 }
1811 
1812 /* Summary of execution */
1813 
1814 static void
executed_summary(unsigned lines,unsigned executed)1815 executed_summary (unsigned lines, unsigned executed)
1816 {
1817   if (lines)
1818     fnotice (stdout, "Lines executed:%s of %d\n",
1819 	     format_gcov (executed, lines, 2), lines);
1820   else
1821     fnotice (stdout, "No executable lines\n");
1822 }
1823 
1824 /* Output summary info for a function or file.  */
1825 
1826 static void
function_summary(const coverage_t * coverage,const char * title)1827 function_summary (const coverage_t *coverage, const char *title)
1828 {
1829   fnotice (stdout, "%s '%s'\n", title, coverage->name);
1830   executed_summary (coverage->lines, coverage->lines_executed);
1831 
1832   if (flag_branches)
1833     {
1834       if (coverage->branches)
1835 	{
1836 	  fnotice (stdout, "Branches executed:%s of %d\n",
1837 		   format_gcov (coverage->branches_executed,
1838 				coverage->branches, 2),
1839 		   coverage->branches);
1840 	  fnotice (stdout, "Taken at least once:%s of %d\n",
1841 		   format_gcov (coverage->branches_taken,
1842 				coverage->branches, 2),
1843 		   coverage->branches);
1844 	}
1845       else
1846 	fnotice (stdout, "No branches\n");
1847       if (coverage->calls)
1848 	fnotice (stdout, "Calls executed:%s of %d\n",
1849 		 format_gcov (coverage->calls_executed, coverage->calls, 2),
1850 		 coverage->calls);
1851       else
1852 	fnotice (stdout, "No calls\n");
1853     }
1854 }
1855 
1856 /* Canonicalize the filename NAME by canonicalizing directory
1857    separators, eliding . components and resolving .. components
1858    appropriately.  Always returns a unique string.  */
1859 
1860 static char *
canonicalize_name(const char * name)1861 canonicalize_name (const char *name)
1862 {
1863   /* The canonical name cannot be longer than the incoming name.  */
1864   char *result = XNEWVEC (char, strlen (name) + 1);
1865   const char *base = name, *probe;
1866   char *ptr = result;
1867   char *dd_base;
1868   int slash = 0;
1869 
1870 #if HAVE_DOS_BASED_FILE_SYSTEM
1871   if (base[0] && base[1] == ':')
1872     {
1873       result[0] = base[0];
1874       result[1] = ':';
1875       base += 2;
1876       ptr += 2;
1877     }
1878 #endif
1879   for (dd_base = ptr; *base; base = probe)
1880     {
1881       size_t len;
1882 
1883       for (probe = base; *probe; probe++)
1884 	if (IS_DIR_SEPARATOR (*probe))
1885 	  break;
1886 
1887       len = probe - base;
1888       if (len == 1 && base[0] == '.')
1889 	/* Elide a '.' directory */
1890 	;
1891       else if (len == 2 && base[0] == '.' && base[1] == '.')
1892 	{
1893 	  /* '..', we can only elide it and the previous directory, if
1894 	     we're not a symlink.  */
1895 	  struct stat ATTRIBUTE_UNUSED buf;
1896 
1897 	  *ptr = 0;
1898 	  if (dd_base == ptr
1899 #if defined (S_ISLNK)
1900 	      /* S_ISLNK is not POSIX.1-1996.  */
1901 	      || stat (result, &buf) || S_ISLNK (buf.st_mode)
1902 #endif
1903 	      )
1904 	    {
1905 	      /* Cannot elide, or unreadable or a symlink.  */
1906 	      dd_base = ptr + 2 + slash;
1907 	      goto regular;
1908 	    }
1909 	  while (ptr != dd_base && *ptr != '/')
1910 	    ptr--;
1911 	  slash = ptr != result;
1912 	}
1913       else
1914 	{
1915 	regular:
1916 	  /* Regular pathname component.  */
1917 	  if (slash)
1918 	    *ptr++ = '/';
1919 	  memcpy (ptr, base, len);
1920 	  ptr += len;
1921 	  slash = 1;
1922 	}
1923 
1924       for (; IS_DIR_SEPARATOR (*probe); probe++)
1925 	continue;
1926     }
1927   *ptr = 0;
1928 
1929   return result;
1930 }
1931 
1932 /* Generate an output file name. INPUT_NAME is the canonicalized main
1933    input file and SRC_NAME is the canonicalized file name.
1934    LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation.  With
1935    long_output_names we prepend the processed name of the input file
1936    to each output name (except when the current source file is the
1937    input file, so you don't get a double concatenation). The two
1938    components are separated by '##'.  With preserve_paths we create a
1939    filename from all path components of the source file, replacing '/'
1940    with '#', and .. with '^', without it we simply take the basename
1941    component.  (Remember, the canonicalized name will already have
1942    elided '.' components and converted \\ separators.)  */
1943 
1944 static char *
make_gcov_file_name(const char * input_name,const char * src_name)1945 make_gcov_file_name (const char *input_name, const char *src_name)
1946 {
1947   char *ptr;
1948   char *result;
1949 
1950   if (flag_long_names && input_name && strcmp (src_name, input_name))
1951     {
1952       /* Generate the input filename part.  */
1953       result = XNEWVEC (char, strlen (input_name) + strlen (src_name) + 10);
1954 
1955       ptr = result;
1956       ptr = mangle_name (input_name, ptr);
1957       ptr[0] = ptr[1] = '#';
1958       ptr += 2;
1959     }
1960   else
1961     {
1962       result = XNEWVEC (char, strlen (src_name) + 10);
1963       ptr = result;
1964     }
1965 
1966   ptr = mangle_name (src_name, ptr);
1967   strcpy (ptr, ".gcov");
1968 
1969   return result;
1970 }
1971 
1972 static char *
mangle_name(char const * base,char * ptr)1973 mangle_name (char const *base, char *ptr)
1974 {
1975   size_t len;
1976 
1977   /* Generate the source filename part.  */
1978   if (!flag_preserve_paths)
1979     {
1980       base = lbasename (base);
1981       len = strlen (base);
1982       memcpy (ptr, base, len);
1983       ptr += len;
1984     }
1985   else
1986     {
1987       /* Convert '/' to '#', convert '..' to '^',
1988 	 convert ':' to '~' on DOS based file system.  */
1989       const char *probe;
1990 
1991 #if HAVE_DOS_BASED_FILE_SYSTEM
1992       if (base[0] && base[1] == ':')
1993 	{
1994 	  ptr[0] = base[0];
1995 	  ptr[1] = '~';
1996 	  ptr += 2;
1997 	  base += 2;
1998 	}
1999 #endif
2000       for (; *base; base = probe)
2001 	{
2002 	  size_t len;
2003 
2004 	  for (probe = base; *probe; probe++)
2005 	    if (*probe == '/')
2006 	      break;
2007 	  len = probe - base;
2008 	  if (len == 2 && base[0] == '.' && base[1] == '.')
2009 	    *ptr++ = '^';
2010 	  else
2011 	    {
2012 	      memcpy (ptr, base, len);
2013 	      ptr += len;
2014 	    }
2015 	  if (*probe)
2016 	    {
2017 	      *ptr++ = '#';
2018 	      probe++;
2019 	    }
2020 	}
2021     }
2022 
2023   return ptr;
2024 }
2025 
2026 /* Scan through the bb_data for each line in the block, increment
2027    the line number execution count indicated by the execution count of
2028    the appropriate basic block.  */
2029 
2030 static void
add_line_counts(coverage_t * coverage,function_t * fn)2031 add_line_counts (coverage_t *coverage, function_t *fn)
2032 {
2033   unsigned ix;
2034   line_t *line = NULL; /* This is propagated from one iteration to the
2035 			  next.  */
2036 
2037   /* Scan each basic block.  */
2038   for (ix = 0; ix != fn->num_blocks; ix++)
2039     {
2040       block_t *block = &fn->blocks[ix];
2041       unsigned *encoding;
2042       const source_t *src = NULL;
2043       unsigned jx;
2044 
2045       if (block->count && ix && ix + 1 != fn->num_blocks)
2046 	fn->blocks_executed++;
2047       for (jx = 0, encoding = block->u.line.encoding;
2048 	   jx != block->u.line.num; jx++, encoding++)
2049 	if (!*encoding)
2050 	  {
2051 	    src = &sources[*++encoding];
2052 	    jx++;
2053 	  }
2054 	else
2055 	  {
2056 	    line = &src->lines[*encoding];
2057 
2058 	    if (coverage)
2059 	      {
2060 		if (!line->exists)
2061 		  coverage->lines++;
2062 		if (!line->count && block->count)
2063 		  coverage->lines_executed++;
2064 	      }
2065 	    line->exists = 1;
2066 	    if (!block->exceptional)
2067 	      line->unexceptional = 1;
2068 	    line->count += block->count;
2069 	  }
2070       free (block->u.line.encoding);
2071       block->u.cycle.arc = NULL;
2072       block->u.cycle.ident = ~0U;
2073 
2074       if (!ix || ix + 1 == fn->num_blocks)
2075 	/* Entry or exit block */;
2076       else if (flag_all_blocks)
2077 	{
2078 	  line_t *block_line = line;
2079 
2080 	  if (!block_line)
2081 	    block_line = &sources[fn->src].lines[fn->line];
2082 
2083 	  block->chain = block_line->u.blocks;
2084 	  block_line->u.blocks = block;
2085 	}
2086       else if (flag_branches)
2087 	{
2088 	  arc_t *arc;
2089 
2090 	  for (arc = block->succ; arc; arc = arc->succ_next)
2091 	    {
2092 	      arc->line_next = line->u.branches;
2093 	      line->u.branches = arc;
2094 	      if (coverage && !arc->is_unconditional)
2095 		add_branch_counts (coverage, arc);
2096 	    }
2097 	}
2098     }
2099   if (!line)
2100     fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
2101 }
2102 
2103 /* Accumulate the line counts of a file.  */
2104 
2105 static void
accumulate_line_counts(source_t * src)2106 accumulate_line_counts (source_t *src)
2107 {
2108   line_t *line;
2109   function_t *fn, *fn_p, *fn_n;
2110   unsigned ix;
2111 
2112   /* Reverse the function order.  */
2113   for (fn = src->functions, fn_p = NULL; fn;
2114        fn_p = fn, fn = fn_n)
2115     {
2116       fn_n = fn->line_next;
2117       fn->line_next = fn_p;
2118     }
2119   src->functions = fn_p;
2120 
2121   for (ix = src->num_lines, line = src->lines; ix--; line++)
2122     {
2123       if (!flag_all_blocks)
2124 	{
2125 	  arc_t *arc, *arc_p, *arc_n;
2126 
2127 	  /* Total and reverse the branch information.  */
2128 	  for (arc = line->u.branches, arc_p = NULL; arc;
2129 	       arc_p = arc, arc = arc_n)
2130 	    {
2131 	      arc_n = arc->line_next;
2132 	      arc->line_next = arc_p;
2133 
2134 	      add_branch_counts (&src->coverage, arc);
2135 	    }
2136 	  line->u.branches = arc_p;
2137 	}
2138       else if (line->u.blocks)
2139 	{
2140 	  /* The user expects the line count to be the number of times
2141 	     a line has been executed. Simply summing the block count
2142 	     will give an artificially high number.  The Right Thing
2143 	     is to sum the entry counts to the graph of blocks on this
2144 	     line, then find the elementary cycles of the local graph
2145 	     and add the transition counts of those cycles.  */
2146 	  block_t *block, *block_p, *block_n;
2147 	  gcov_type count = 0;
2148 
2149 	  /* Reverse the block information.  */
2150 	  for (block = line->u.blocks, block_p = NULL; block;
2151 	       block_p = block, block = block_n)
2152 	    {
2153 	      block_n = block->chain;
2154 	      block->chain = block_p;
2155 	      block->u.cycle.ident = ix;
2156 	    }
2157 	  line->u.blocks = block_p;
2158 
2159 	  /* Sum the entry arcs.  */
2160 	  for (block = line->u.blocks; block; block = block->chain)
2161 	    {
2162 	      arc_t *arc;
2163 
2164 	      for (arc = block->pred; arc; arc = arc->pred_next)
2165 		{
2166 		  if (arc->src->u.cycle.ident != ix)
2167 		    count += arc->count;
2168 		  if (flag_branches)
2169 		    add_branch_counts (&src->coverage, arc);
2170 		}
2171 
2172 	      /* Initialize the cs_count.  */
2173 	      for (arc = block->succ; arc; arc = arc->succ_next)
2174 		arc->cs_count = arc->count;
2175 	    }
2176 
2177 	  /* Find the loops. This uses the algorithm described in
2178 	     Tiernan 'An Efficient Search Algorithm to Find the
2179 	     Elementary Circuits of a Graph', CACM Dec 1970. We hold
2180 	     the P array by having each block point to the arc that
2181 	     connects to the previous block. The H array is implicitly
2182 	     held because of the arc ordering, and the block's
2183 	     previous arc pointer.
2184 
2185 	     Although the algorithm is O(N^3) for highly connected
2186 	     graphs, at worst we'll have O(N^2), as most blocks have
2187 	     only one or two exits. Most graphs will be small.
2188 
2189 	     For each loop we find, locate the arc with the smallest
2190 	     transition count, and add that to the cumulative
2191 	     count.  Decrease flow over the cycle and remove the arc
2192 	     from consideration.  */
2193 	  for (block = line->u.blocks; block; block = block->chain)
2194 	    {
2195 	      block_t *head = block;
2196 	      arc_t *arc;
2197 
2198 	    next_vertex:;
2199 	      arc = head->succ;
2200 	    current_vertex:;
2201 	      while (arc)
2202 		{
2203 		  block_t *dst = arc->dst;
2204 		  if (/* Already used that arc.  */
2205 		      arc->cycle
2206 		      /* Not to same graph, or before first vertex.  */
2207 		      || dst->u.cycle.ident != ix
2208 		      /* Already in path.  */
2209 		      || dst->u.cycle.arc)
2210 		    {
2211 		      arc = arc->succ_next;
2212 		      continue;
2213 		    }
2214 
2215 		  if (dst == block)
2216 		    {
2217 		      /* Found a closing arc.  */
2218 		      gcov_type cycle_count = arc->cs_count;
2219 		      arc_t *cycle_arc = arc;
2220 		      arc_t *probe_arc;
2221 
2222 		      /* Locate the smallest arc count of the loop.  */
2223 		      for (dst = head; (probe_arc = dst->u.cycle.arc);
2224 			   dst = probe_arc->src)
2225 			if (cycle_count > probe_arc->cs_count)
2226 			  {
2227 			    cycle_count = probe_arc->cs_count;
2228 			    cycle_arc = probe_arc;
2229 			  }
2230 
2231 		      count += cycle_count;
2232 		      cycle_arc->cycle = 1;
2233 
2234 		      /* Remove the flow from the cycle.  */
2235 		      arc->cs_count -= cycle_count;
2236 		      for (dst = head; (probe_arc = dst->u.cycle.arc);
2237 			   dst = probe_arc->src)
2238 			probe_arc->cs_count -= cycle_count;
2239 
2240 		      /* Unwind to the cyclic arc.  */
2241 		      while (head != cycle_arc->src)
2242 			{
2243 			  arc = head->u.cycle.arc;
2244 			  head->u.cycle.arc = NULL;
2245 			  head = arc->src;
2246 			}
2247 		      /* Move on.  */
2248 		      arc = arc->succ_next;
2249 		      continue;
2250 		    }
2251 
2252 		  /* Add new block to chain.  */
2253 		  dst->u.cycle.arc = arc;
2254 		  head = dst;
2255 		  goto next_vertex;
2256 		}
2257 	      /* We could not add another vertex to the path. Remove
2258 		 the last vertex from the list.  */
2259 	      arc = head->u.cycle.arc;
2260 	      if (arc)
2261 		{
2262 		  /* It was not the first vertex. Move onto next arc.  */
2263 		  head->u.cycle.arc = NULL;
2264 		  head = arc->src;
2265 		  arc = arc->succ_next;
2266 		  goto current_vertex;
2267 		}
2268 	      /* Mark this block as unusable.  */
2269 	      block->u.cycle.ident = ~0U;
2270 	    }
2271 
2272 	  line->count = count;
2273 	}
2274 
2275       if (line->exists)
2276 	{
2277 	  src->coverage.lines++;
2278 	  if (line->count)
2279 	    src->coverage.lines_executed++;
2280 	}
2281     }
2282 }
2283 
2284 /* Output information about ARC number IX.  Returns nonzero if
2285    anything is output.  */
2286 
2287 static int
output_branch_count(FILE * gcov_file,int ix,const arc_t * arc)2288 output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
2289 {
2290   if (arc->is_call_non_return)
2291     {
2292       if (arc->src->count)
2293 	{
2294 	  fnotice (gcov_file, "call   %2d returned %s\n", ix,
2295 		   format_gcov (arc->src->count - arc->count,
2296 				arc->src->count, -flag_counts));
2297 	}
2298       else
2299 	fnotice (gcov_file, "call   %2d never executed\n", ix);
2300     }
2301   else if (!arc->is_unconditional)
2302     {
2303       if (arc->src->count)
2304 	fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
2305 		 format_gcov (arc->count, arc->src->count, -flag_counts),
2306 		 arc->fall_through ? " (fallthrough)"
2307 		 : arc->is_throw ? " (throw)" : "");
2308       else
2309 	fnotice (gcov_file, "branch %2d never executed\n", ix);
2310     }
2311   else if (flag_unconditional && !arc->dst->is_call_return)
2312     {
2313       if (arc->src->count)
2314 	fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
2315 		 format_gcov (arc->count, arc->src->count, -flag_counts));
2316       else
2317 	fnotice (gcov_file, "unconditional %2d never executed\n", ix);
2318     }
2319   else
2320     return 0;
2321   return 1;
2322 
2323 }
2324 
2325 static const char *
read_line(FILE * file)2326 read_line (FILE *file)
2327 {
2328   static char *string;
2329   static size_t string_len;
2330   size_t pos = 0;
2331   char *ptr;
2332 
2333   if (!string_len)
2334     {
2335       string_len = 200;
2336       string = XNEWVEC (char, string_len);
2337     }
2338 
2339   while ((ptr = fgets (string + pos, string_len - pos, file)))
2340     {
2341       size_t len = strlen (string + pos);
2342 
2343       if (string[pos + len - 1] == '\n')
2344 	{
2345 	  string[pos + len - 1] = 0;
2346 	  return string;
2347 	}
2348       pos += len;
2349       string = XRESIZEVEC (char, string, string_len * 2);
2350       string_len *= 2;
2351     }
2352 
2353   return pos ? string : NULL;
2354 }
2355 
2356 /* Read in the source file one line at a time, and output that line to
2357    the gcov file preceded by its execution count and other
2358    information.  */
2359 
2360 static void
output_lines(FILE * gcov_file,const source_t * src)2361 output_lines (FILE *gcov_file, const source_t *src)
2362 {
2363   FILE *source_file;
2364   unsigned line_num;	/* current line number.  */
2365   const line_t *line;           /* current line info ptr.  */
2366   const char *retval = "";	/* status of source file reading.  */
2367   function_t *fn = NULL;
2368 
2369   fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->coverage.name);
2370   if (!multiple_files)
2371     {
2372       fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
2373       fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
2374 	       no_data_file ? "-" : da_file_name);
2375       fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, object_runs);
2376     }
2377   fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
2378 
2379   source_file = fopen (src->name, "r");
2380   if (!source_file)
2381     {
2382       fnotice (stderr, "Cannot open source file %s\n", src->name);
2383       retval = NULL;
2384     }
2385   else if (src->file_time == 0)
2386     fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0);
2387 
2388   if (flag_branches)
2389     fn = src->functions;
2390 
2391   for (line_num = 1, line = &src->lines[line_num];
2392        line_num < src->num_lines; line_num++, line++)
2393     {
2394       for (; fn && fn->line == line_num; fn = fn->line_next)
2395 	{
2396 	  arc_t *arc = fn->blocks[EXIT_BLOCK].pred;
2397 	  gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
2398 	  gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
2399 
2400 	  for (; arc; arc = arc->pred_next)
2401 	    if (arc->fake)
2402 	      return_count -= arc->count;
2403 
2404 	  fprintf (gcov_file, "function %s", flag_demangled_names ?
2405                    fn->demangled_name : fn->name);
2406 	  fprintf (gcov_file, " called %s",
2407 		   format_gcov (called_count, 0, -1));
2408 	  fprintf (gcov_file, " returned %s",
2409 		   format_gcov (return_count, called_count, 0));
2410 	  fprintf (gcov_file, " blocks executed %s",
2411 		   format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
2412 	  fprintf (gcov_file, "\n");
2413 	}
2414 
2415       if (retval)
2416 	retval = read_line (source_file);
2417 
2418       /* For lines which don't exist in the .bb file, print '-' before
2419 	 the source line.  For lines which exist but were never
2420 	 executed, print '#####' or '=====' before the source line.
2421 	 Otherwise, print the execution count before the source line.
2422 	 There are 16 spaces of indentation added before the source
2423 	 line so that tabs won't be messed up.  */
2424       fprintf (gcov_file, "%9s:%5u:%s\n",
2425 	       !line->exists ? "-" : line->count
2426 	       ? format_gcov (line->count, 0, -1)
2427 	       : line->unexceptional ? "#####" : "=====", line_num,
2428 	       retval ? retval : "/*EOF*/");
2429 
2430       if (flag_all_blocks)
2431 	{
2432 	  block_t *block;
2433 	  arc_t *arc;
2434 	  int ix, jx;
2435 
2436 	  for (ix = jx = 0, block = line->u.blocks; block;
2437 	       block = block->chain)
2438 	    {
2439 	      if (!block->is_call_return)
2440 		fprintf (gcov_file, "%9s:%5u-block %2d\n",
2441 			 !line->exists ? "-" : block->count
2442 			 ? format_gcov (block->count, 0, -1)
2443 			 : block->exceptional ? "%%%%%" : "$$$$$",
2444 			 line_num, ix++);
2445 	      if (flag_branches)
2446 		for (arc = block->succ; arc; arc = arc->succ_next)
2447 		  jx += output_branch_count (gcov_file, jx, arc);
2448 	    }
2449 	}
2450       else if (flag_branches)
2451 	{
2452 	  int ix;
2453 	  arc_t *arc;
2454 
2455 	  for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
2456 	    ix += output_branch_count (gcov_file, ix, arc);
2457 	}
2458     }
2459 
2460   /* Handle all remaining source lines.  There may be lines after the
2461      last line of code.  */
2462   if (retval)
2463     {
2464       for (; (retval = read_line (source_file)); line_num++)
2465 	fprintf (gcov_file, "%9s:%5u:%s\n", "-", line_num, retval);
2466     }
2467 
2468   if (source_file)
2469     fclose (source_file);
2470 }
2471