xref: /openbsd-src/gnu/usr.bin/gcc/gcc/gcov.c (revision c87b03e512fc05ed6e0222f6fb0ae86264b1d05b)
1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2    source file.
3    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
4    1999, 2000, 2001, 2002 Free Software Foundation, Inc.
5    Contributed by James E. Wilson of Cygnus Support.
6    Mangled by Bob Manson of Cygnus Support.
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 2, 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 COPYING.  If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22 
23 /* ??? The code in final.c that produces the struct bb assumes that there is
24    no padding between the fields.  This is not necessary true.  The current
25    code can only be trusted if longs and pointers are the same size.  */
26 
27 /* ??? No need to print an execution count on every line, could just print
28    it on the first line of each block, and only print it on a subsequent
29    line in the same block if the count changes.  */
30 
31 /* ??? Print a list of the ten blocks with the highest execution counts,
32    and list the line numbers corresponding to those blocks.  Also, perhaps
33    list the line numbers with the highest execution counts, only printing
34    the first if there are several which are all listed in the same block.  */
35 
36 /* ??? Should have an option to print the number of basic blocks, and the
37    percent of them that are covered.  */
38 
39 /* ??? Does not correctly handle the case where two .bb files refer to the
40    same included source file.  For example, if one has a short file containing
41    only inline functions, which is then included in two other files, then
42    there will be two .bb files which refer to the include file, but there
43    is no way to get the total execution counts for the included file, can
44    only get execution counts for one or the other of the including files.  */
45 
46 #include "config.h"
47 #include "system.h"
48 #include "intl.h"
49 #include "version.h"
50 #undef abort
51 
52 #include <getopt.h>
53 
54 typedef HOST_WIDEST_INT gcov_type;
55 #include "gcov-io.h"
56 
57 /* The .bb file format consists of several lists of 4-byte integers
58    which are the line numbers of each basic block in the file.  Each
59    list is terminated by a zero.  These lists correspond to the basic
60    blocks in the reconstructed program flow graph.
61 
62    A line number of -1 indicates that a source file name (padded to a
63    long boundary) follows.  The padded file name is followed by
64    another -1 to make it easy to scan past file names.  A -2 indicates
65    that a function name (padded to a long boundary) follows; the name
66    is followed by another -2 to make it easy to scan past the function
67    name.
68 
69    The .bbg file contains enough info to enable gcov to reconstruct the
70    program flow graph.  The first word is the number of basic blocks,
71    the second word is the number of arcs, followed by the list of arcs
72    (source bb, dest bb pairs), then a -1, then the number of instrumented
73    arcs followed by the instrumented arcs, followed by another -1.  This
74    is repeated for each function.
75 
76    The .da file contains the execution count for each instrumented branch.
77 
78    The .bb and .bbg files are created by giving GCC the -ftest-coverage option,
79    and the .da files are created when an executable compiled with
80    -fprofile-arcs is run.  */
81 
82 /* The functions in this file for creating and solution program flow graphs
83    are very similar to functions in the gcc source file profile.c.  */
84 
85 /* This is the size of the buffer used to read in source file lines.  */
86 
87 #define STRING_SIZE 200
88 
89 /* One copy of this structure is created for each source file mentioned in the
90    .bb file.  */
91 
92 struct sourcefile
93 {
94   char *name;
95   int maxlineno;
96   struct sourcefile *next;
97 };
98 
99 /* This points to the head of the sourcefile structure list.  */
100 
101 struct sourcefile *sources;
102 
103 /* One of these is dynamically created whenever we identify an arc in the
104    function.  */
105 
106 struct adj_list
107 {
108   int source;
109   int target;
110   gcov_type arc_count;
111   unsigned int count_valid : 1;
112   unsigned int on_tree : 1;
113   unsigned int fake : 1;
114   unsigned int fall_through : 1;
115 #if 0
116   /* Not needed for gcov, but defined in profile.c.  */
117   rtx branch_insn;
118 #endif
119   struct adj_list *pred_next;
120   struct adj_list *succ_next;
121 };
122 
123 /* Count the number of basic blocks, and create an array of these structures,
124    one for each bb in the function.  */
125 
126 struct bb_info
127 {
128   struct adj_list *succ;
129   struct adj_list *pred;
130   gcov_type succ_count;
131   gcov_type pred_count;
132   gcov_type exec_count;
133   unsigned int count_valid : 1;
134   unsigned int on_tree : 1;
135 #if 0
136   /* Not needed for gcov, but defined in profile.c.  */
137   rtx first_insn;
138 #endif
139 };
140 
141 /* When outputting branch probabilities, one of these structures is created
142    for each branch/call.  */
143 
144 struct arcdata
145 {
146   gcov_type hits;
147   gcov_type total;
148   int call_insn;
149   struct arcdata *next;
150 };
151 
152 /* Used to save the list of bb_graphs, one per function.  */
153 
154 struct bb_info_list
155 {
156   /* Indexed by block number, holds the basic block graph for one function.  */
157   struct bb_info *bb_graph;
158   int num_blocks;
159   struct bb_info_list *next;
160 };
161 
162 /* Used to hold information about each line.  */
163 struct line_info
164 {
165   gcov_type count;	      /* execution count */
166   struct arcdata *branches;   /* list of branch probabilities for line.  */
167   unsigned exists : 1;	      /* has code associated with it.  */
168 };
169 
170 struct coverage
171 {
172   int lines;
173   int lines_executed;
174 
175   int branches;
176   int branches_executed;
177   int branches_taken;
178 
179   int calls;
180   int calls_executed;
181 
182   char *name;
183 };
184 
185 /* Holds a list of function basic block graphs.  */
186 
187 static struct bb_info_list *bb_graph_list = 0;
188 
189 /* Modification time of data files.  */
190 
191 static time_t bb_file_time;
192 
193 /* Name and file pointer of the input file for the basic block graph.  */
194 
195 static char *bbg_file_name;
196 static FILE *bbg_file;
197 
198 /* Name and file pointer of the input file for the arc count data.  */
199 
200 static char *da_file_name;
201 static FILE *da_file;
202 
203 /* Name and file pointer of the input file for the basic block line counts.  */
204 
205 static char *bb_file_name;
206 static FILE *bb_file;
207 
208 /* Holds the entire contents of the bb_file read into memory.  */
209 
210 static char *bb_data;
211 
212 /* Size of bb_data array in longs.  */
213 
214 static long bb_data_size;
215 
216 /* Name of the file mentioned on the command line.  */
217 
218 static char *input_file_name = 0;
219 
220 /* Output branch probabilities if true.  */
221 
222 static int output_branch_probs = 0;
223 
224 /* Output a gcov file if this is true.  This is on by default, and can
225    be turned off by the -n option.  */
226 
227 static int output_gcov_file = 1;
228 
229 /* For included files, make the gcov output file name include the name of
230    the input source file.  For example, if x.h is included in a.c, then the
231    output file name is a.c.x.h.gcov instead of x.h.gcov.  This works only
232    when a single source file is specified.  */
233 
234 static int output_long_names = 0;
235 
236 /* Output summary info for each function.  */
237 
238 static int output_function_summary = 0;
239 
240 /* Object directory file prefix.  This is the directory/file
241    where .bb and .bbg files are looked for, if nonzero.  */
242 
243 static char *object_directory = 0;
244 
245 /* Preserve all pathname components. Needed when object files and
246    source files are in subdirectories.  */
247 static int preserve_paths = 0;
248 
249 /* Output the number of times a branch was taken as opposed to the percentage
250    of times it was taken.  Turned on by the -c option */
251 
252 static int output_branch_counts = 0;
253 
254 /* Forward declarations.  */
255 static void process_args PARAMS ((int, char **));
256 static void open_files PARAMS ((void));
257 static void read_files PARAMS ((void));
258 static void scan_for_source_files PARAMS ((void));
259 static void output_data PARAMS ((struct sourcefile *));
260 static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
261 static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
262 static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
263 static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
264 static gcov_type *read_profile PARAMS ((char *, long, int));
265 static void create_program_flow_graph PARAMS ((struct bb_info_list *));
266 static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
267 static void accumulate_branch_counts PARAMS ((struct coverage *,
268 					      struct arcdata *));
269 static void calculate_branch_probs PARAMS ((struct bb_info *,
270 					    struct line_info *,
271 					    struct coverage *));
272 static void function_summary PARAMS ((struct coverage *, const char *));
273 static void init_line_info PARAMS ((struct line_info *,
274 				    struct coverage *, long));
275 static void output_line_info PARAMS ((FILE *, const struct line_info *,
276 				      const struct coverage *, long));
277 static char *make_gcov_file_name PARAMS ((char *));
278 static const char *format_hwint PARAMS ((HOST_WIDEST_INT, HOST_WIDEST_INT,
279 					 int));
280 
281 extern int main PARAMS ((int, char **));
282 
283 int
main(argc,argv)284 main (argc, argv)
285      int argc;
286      char **argv;
287 {
288   struct sourcefile *s_ptr;
289 
290   gcc_init_libintl ();
291 
292   process_args (argc, argv);
293 
294   open_files ();
295 
296   read_files ();
297 
298   scan_for_source_files ();
299 
300   for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
301     output_data (s_ptr);
302 
303   return 0;
304 }
305 
306 static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
307 static void
fnotice(FILE * file,const char * msgid,...)308 fnotice VPARAMS ((FILE *file, const char *msgid, ...))
309 {
310   VA_OPEN (ap, msgid);
311   VA_FIXEDARG (ap, FILE *, file);
312   VA_FIXEDARG (ap, const char *, msgid);
313 
314   vfprintf (file, _(msgid), ap);
315   VA_CLOSE (ap);
316 }
317 
318 /* More 'friendly' abort that prints the line and file.
319    config.h can #define abort fancy_abort if you like that sort of thing.  */
320 extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
321 
322 void
fancy_abort()323 fancy_abort ()
324 {
325   fnotice (stderr, "Internal gcov abort.\n");
326   exit (FATAL_EXIT_CODE);
327 }
328 
329 /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
330    otherwise the output of --help.  */
331 
332 static void
print_usage(error_p)333 print_usage (error_p)
334      int error_p;
335 {
336   FILE *file = error_p ? stderr : stdout;
337   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
338   fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
339   fnotice (file, "Print code coverage information.\n\n");
340   fnotice (file, "  -h, --help                      Print this help, then exit\n");
341   fnotice (file, "  -v, --version                   Print version number, then exit\n");
342   fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output\n");
343   fnotice (file, "  -c, --branch-counts             Given counts of branches taken\n\
344                                     rather than percentages\n");
345   fnotice (file, "  -n, --no-output                 Do not create an output file\n");
346   fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
347                                     source files\n");
348   fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
349   fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
350   fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
351   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
352 	   bug_report_url);
353   exit (status);
354 }
355 
356 /* Print version information and exit.  */
357 
358 static void
print_version()359 print_version ()
360 {
361   fnotice (stdout, "gcov (GCC) %s\n", version_string);
362   fnotice (stdout, "Copyright (C) 2001 Free Software Foundation, Inc.\n");
363   fnotice (stdout,
364 	   "This is free software; see the source for copying conditions.  There is NO\n\
365 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
366   exit (SUCCESS_EXIT_CODE);
367 }
368 
369 static const struct option options[] =
370 {
371   { "help",                 no_argument,       NULL, 'h' },
372   { "version",              no_argument,       NULL, 'v' },
373   { "branch-probabilities", no_argument,       NULL, 'b' },
374   { "branch-counts",        no_argument,       NULL, 'c' },
375   { "no-output",            no_argument,       NULL, 'n' },
376   { "long-file-names",      no_argument,       NULL, 'l' },
377   { "function-summaries",   no_argument,       NULL, 'f' },
378   { "preserve-paths",       no_argument,       NULL, 'p' },
379   { "object-directory",     required_argument, NULL, 'o' },
380   { "object-file",          required_argument, NULL, 'o' },
381 };
382 
383 /* Parse the command line.  */
384 
385 static void
process_args(argc,argv)386 process_args (argc, argv)
387      int argc;
388      char **argv;
389 {
390   int opt;
391 
392   while ((opt = getopt_long (argc, argv, "hvbclnfo:p", options, NULL)) != -1)
393     {
394       switch (opt)
395 	{
396 	case 'h':
397 	  print_usage (false);
398 	  /* print_usage will exit.  */
399 	case 'v':
400 	  print_version ();
401 	  /* print_version will exit.  */
402 	case 'b':
403 	  output_branch_probs = 1;
404 	  break;
405 	case 'c':
406 	  output_branch_counts = 1;
407 	  break;
408 	case 'n':
409 	  output_gcov_file = 0;
410 	  break;
411 	case 'l':
412 	  output_long_names = 1;
413 	  break;
414 	case 'f':
415 	  output_function_summary = 1;
416 	  break;
417 	case 'o':
418 	  object_directory = optarg;
419 	  break;
420 	case 'p':
421 	  preserve_paths = 1;
422 	  break;
423 	default:
424 	  print_usage (true);
425 	  /* print_usage will exit.  */
426 	}
427     }
428 
429   if (optind != argc - 1)
430     print_usage (true);
431 
432   input_file_name = argv[optind];
433 }
434 
435 
436 /* Find and open the .bb, .da, and .bbg files. If OBJECT_DIRECTORY is
437    not specified, these are looked for in the current directory, and
438    named from the basename of the input_file_name sans extension. If
439    OBJECT_DIRECTORY is specified and is a directory, the files are in
440    that directory, but named from the basename of the input_file_name,
441    sans extension. Otherwise OBJECT_DIRECTORY is taken to be the name
442    of the object *file*, and the data files are named from that.  */
443 
444 static void
open_files()445 open_files ()
446 {
447   char *cptr;
448   char *name;
449   int length = strlen (input_file_name);
450   int base;
451 
452   if (object_directory && object_directory[0])
453     {
454       struct stat status;
455 
456       length += strlen (object_directory) + 2;
457       name = xmalloc (length);
458       name[0] = 0;
459 
460       base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
461       strcat (name, object_directory);
462       if (base && name[strlen (name) - 1] != '/')
463 	strcat (name, "/");
464     }
465   else
466     {
467       name = xmalloc (length + 1);
468       name[0] = 0;
469       base = 1;
470     }
471 
472   if (base)
473     {
474       /* Append source file name */
475       cptr = strrchr (input_file_name, '/');
476       cptr = cptr ? cptr + 1 : input_file_name;
477 
478       strcat (name, cptr);
479     }
480   /* Remove the extension.  */
481   cptr = strrchr (name, '.');
482   if (cptr)
483     *cptr = 0;
484 
485   length = strlen (name);
486   da_file_name = xmalloc (length + 4);
487   bb_file_name = xmalloc (length + 4);
488   bbg_file_name = xmalloc (length + 5);
489 
490   strcpy (da_file_name, name);
491   strcpy (bb_file_name, name);
492   strcpy (bbg_file_name, name);
493   strcpy (da_file_name + length, ".da");
494   strcpy (bb_file_name + length, ".bb");
495   strcpy (bbg_file_name + length, ".bbg");
496 
497   bb_file = fopen (bb_file_name, "rb");
498   if (bb_file == NULL)
499     {
500       fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
501       exit (FATAL_EXIT_CODE);
502     }
503 
504   bbg_file = fopen (bbg_file_name, "rb");
505   if (bbg_file == NULL)
506     {
507       fnotice (stderr, "Could not open program flow graph file %s.\n",
508 	       bbg_file_name);
509       exit (FATAL_EXIT_CODE);
510     }
511 
512   {
513     struct stat status;
514 
515     if (!fstat (fileno (bb_file), &status))
516       bb_file_time = status.st_mtime;
517   }
518 
519   /* If none of the functions in the file were executed, then there won't
520      be a .da file.  Just assume that all counts are zero in this case.  */
521   da_file = fopen (da_file_name, "rb");
522   if (da_file == NULL)
523     {
524       fnotice (stderr, "Could not open data file %s.\n", da_file_name);
525       fnotice (stderr, "Assuming that all execution counts are zero.\n");
526     }
527 
528   /* Check for empty .bbg file.  This indicates that there is no executable
529      code in this source file.  */
530   /* Set the EOF condition if at the end of file.  */
531   ungetc (getc (bbg_file), bbg_file);
532   if (feof (bbg_file))
533     {
534       fnotice (stderr, "No executable code associated with file %s.\n",
535 	       input_file_name);
536       exit (FATAL_EXIT_CODE);
537     }
538 }
539 
540 /* Initialize a new arc.  */
541 
542 static void
init_arc(arcptr,source,target,bb_graph)543 init_arc (arcptr, source, target, bb_graph)
544      struct adj_list *arcptr;
545      int source, target;
546      struct bb_info *bb_graph;
547 {
548   arcptr->target = target;
549   arcptr->source = source;
550 
551   arcptr->arc_count = 0;
552   arcptr->count_valid = 0;
553   arcptr->on_tree = 0;
554   arcptr->fake = 0;
555   arcptr->fall_through = 0;
556 
557   arcptr->succ_next = bb_graph[source].succ;
558   bb_graph[source].succ = arcptr;
559   bb_graph[source].succ_count++;
560 
561   arcptr->pred_next = bb_graph[target].pred;
562   bb_graph[target].pred = arcptr;
563   bb_graph[target].pred_count++;
564 }
565 
566 /* Reverse the arcs on an arc list.  */
567 
568 static struct adj_list *
reverse_arcs(arcptr)569 reverse_arcs (arcptr)
570      struct adj_list *arcptr;
571 {
572   struct adj_list *prev = 0;
573   struct adj_list *next;
574 
575   for ( ; arcptr; arcptr = next)
576     {
577       next = arcptr->succ_next;
578       arcptr->succ_next = prev;
579       prev = arcptr;
580     }
581 
582   return prev;
583 }
584 
585 /* Reads profiles from the .da file and compute a hybrid profile.  */
586 
587 static gcov_type *
read_profile(function_name,cfg_checksum,instr_arcs)588 read_profile (function_name, cfg_checksum, instr_arcs)
589      char *function_name;
590      long cfg_checksum;
591      int instr_arcs;
592 {
593   int i;
594   int okay = 1;
595   gcov_type *profile;
596   char *function_name_buffer;
597   int function_name_buffer_len;
598 
599   profile = xmalloc (sizeof (gcov_type) * instr_arcs);
600   function_name_buffer_len = strlen (function_name) + 1;
601   function_name_buffer = xmalloc (function_name_buffer_len + 1);
602 
603   for (i = 0; i < instr_arcs; i++)
604     profile[i] = 0;
605 
606   if (!da_file)
607     return profile;
608 
609   rewind (da_file);
610   while (1)
611     {
612       long magic, extra_bytes;
613       long func_count;
614       int i;
615 
616       if (__read_long (&magic, da_file, 4) != 0)
617 	break;
618 
619       if (magic != -123)
620 	{
621 	  okay = 0;
622 	  break;
623 	}
624 
625       if (__read_long (&func_count, da_file, 4) != 0)
626 	{
627 	  okay = 0;
628 	  break;
629 	}
630 
631       if (__read_long (&extra_bytes, da_file, 4) != 0)
632 	{
633 	  okay = 0;
634 	  break;
635 	}
636 
637       /* skip extra data emited by __bb_exit_func.  */
638       fseek (da_file, extra_bytes, SEEK_CUR);
639 
640       for (i = 0; i < func_count; i++)
641 	{
642 	  long arc_count;
643 	  long chksum;
644 	  int j;
645 
646 	  if (__read_gcov_string
647 	      (function_name_buffer, function_name_buffer_len, da_file,
648 	       -1) != 0)
649 	    {
650 	      okay = 0;
651 	      break;
652 	    }
653 
654 	  if (__read_long (&chksum, da_file, 4) != 0)
655 	    {
656 	      okay = 0;
657 	      break;
658 	    }
659 
660 	  if (__read_long (&arc_count, da_file, 4) != 0)
661 	    {
662 	      okay = 0;
663 	      break;
664 	    }
665 
666 	  if (strcmp (function_name_buffer, function_name) != 0
667 	      || arc_count != instr_arcs || chksum != cfg_checksum)
668 	    {
669 	      /* skip */
670 	      if (fseek (da_file, arc_count * 8, SEEK_CUR) < 0)
671 		{
672 		  okay = 0;
673 		  break;
674 		}
675 	    }
676 	  else
677 	    {
678 	      gcov_type tmp;
679 
680 	      for (j = 0; j < arc_count; j++)
681 		if (__read_gcov_type (&tmp, da_file, 8) != 0)
682 		  {
683 		    okay = 0;
684 		    break;
685 		  }
686 		else
687 		  {
688 		    profile[j] += tmp;
689 		  }
690 	    }
691 	}
692 
693       if (!okay)
694 	break;
695 
696     }
697 
698   free (function_name_buffer);
699 
700   if (!okay)
701     {
702       fprintf (stderr, ".da file corrupted!\n");
703       free (profile);
704       abort ();
705     }
706 
707   return profile;
708 }
709 
710 /* Construct the program flow graph from the .bbg file, and read in the data
711    in the .da file.  */
712 
713 static void
create_program_flow_graph(bptr)714 create_program_flow_graph (bptr)
715      struct bb_info_list *bptr;
716 {
717   long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
718   int i;
719   struct adj_list *arcptr;
720   struct bb_info *bb_graph;
721   long cfg_checksum;
722   long instr_arcs = 0;
723   gcov_type *profile;
724   int profile_pos = 0;
725   char *function_name;
726   long function_name_len, tmp;
727 
728   /* Read function name.  */
729   __read_long (&tmp, bbg_file, 4);   /* ignore -1.  */
730   __read_long (&function_name_len, bbg_file, 4);
731   function_name = xmalloc (function_name_len + 1);
732   fread (function_name, 1, function_name_len + 1, bbg_file);
733 
734   /* Skip padding.  */
735   tmp = (function_name_len + 1) % 4;
736 
737   if (tmp)
738     fseek (bbg_file, 4 - tmp, SEEK_CUR);
739 
740   __read_long (&tmp, bbg_file, 4);   /* ignore -1.  */
741 
742   /* Read the cfg checksum.  */
743   __read_long (&cfg_checksum, bbg_file, 4);
744 
745   /* Read the number of blocks.  */
746   __read_long (&num_blocks, bbg_file, 4);
747 
748   /* Create an array of size bb number of bb_info structs.  */
749   bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
750 
751   bptr->bb_graph = bb_graph;
752   bptr->num_blocks = num_blocks;
753 
754   /* Read and create each arc from the .bbg file.  */
755   __read_long (&number_arcs, bbg_file, 4);
756   for (i = 0; i < num_blocks; i++)
757     {
758       int j;
759 
760       __read_long (&num_arcs_per_block, bbg_file, 4);
761       for (j = 0; j < num_arcs_per_block; j++)
762 	{
763 	  if (number_arcs-- < 0)
764 	    abort ();
765 
766 	  src = i;
767 	  __read_long (&dest, bbg_file, 4);
768 
769 	  arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
770 	  init_arc (arcptr, src, dest, bb_graph);
771 
772 	  __read_long (&flag_bits, bbg_file, 4);
773 	  if (flag_bits & 0x1)
774 	    arcptr->on_tree++;
775 	  else
776 	    instr_arcs++;
777 	  arcptr->fake = !! (flag_bits & 0x2);
778 	  arcptr->fall_through = !! (flag_bits & 0x4);
779 	}
780     }
781 
782   if (number_arcs)
783     abort ();
784 
785   /* Read and ignore the -1 separating the arc list from the arc list of the
786      next function.  */
787   __read_long (&src, bbg_file, 4);
788   if (src != -1)
789     abort ();
790 
791   /* Must reverse the order of all succ arcs, to ensure that they match
792      the order of the data in the .da file.  */
793 
794   for (i = 0; i < num_blocks; i++)
795     if (bb_graph[i].succ)
796       bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
797 
798   /* Read profile from the .da file.  */
799 
800   profile = read_profile (function_name, cfg_checksum, instr_arcs);
801 
802   /* For each arc not on the spanning tree, set its execution count from
803      the .da file.  */
804 
805   /* The first count in the .da file is the number of times that the function
806      was entered.  This is the exec_count for block zero.  */
807 
808   /* This duplicates code in branch_prob in profile.c.  */
809 
810   for (i = 0; i < num_blocks; i++)
811     for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
812       if (! arcptr->on_tree)
813 	{
814 	  arcptr->arc_count = profile[profile_pos++];
815 	  arcptr->count_valid = 1;
816 	  bb_graph[i].succ_count--;
817 	  bb_graph[arcptr->target].pred_count--;
818 	}
819   free (profile);
820   free (function_name);
821 }
822 
823 static void
solve_program_flow_graph(bptr)824 solve_program_flow_graph (bptr)
825      struct bb_info_list *bptr;
826 {
827   int passes, changes;
828   gcov_type total;
829   int i;
830   struct adj_list *arcptr;
831   struct bb_info *bb_graph;
832   int num_blocks;
833 
834   num_blocks = bptr->num_blocks;
835   bb_graph = bptr->bb_graph;
836 
837   /* For every block in the file,
838      - if every exit/entrance arc has a known count, then set the block count
839      - if the block count is known, and every exit/entrance arc but one has
840        a known execution count, then set the count of the remaining arc
841 
842      As arc counts are set, decrement the succ/pred count, but don't delete
843      the arc, that way we can easily tell when all arcs are known, or only
844      one arc is unknown.  */
845 
846   /* The order that the basic blocks are iterated through is important.
847      Since the code that finds spanning trees starts with block 0, low numbered
848      arcs are put on the spanning tree in preference to high numbered arcs.
849      Hence, most instrumented arcs are at the end.  Graph solving works much
850      faster if we propagate numbers from the end to the start.
851 
852      This takes an average of slightly more than 3 passes.  */
853 
854   changes = 1;
855   passes = 0;
856   while (changes)
857     {
858       passes++;
859       changes = 0;
860 
861       for (i = num_blocks - 1; i >= 0; i--)
862 	{
863 	  if (! bb_graph[i].count_valid)
864 	    {
865 	      if (bb_graph[i].succ_count == 0)
866 		{
867 		  total = 0;
868 		  for (arcptr = bb_graph[i].succ; arcptr;
869 		       arcptr = arcptr->succ_next)
870 		    total += arcptr->arc_count;
871 		  bb_graph[i].exec_count = total;
872 		  bb_graph[i].count_valid = 1;
873 		  changes = 1;
874 		}
875 	      else if (bb_graph[i].pred_count == 0)
876 		{
877 		  total = 0;
878 		  for (arcptr = bb_graph[i].pred; arcptr;
879 		       arcptr = arcptr->pred_next)
880 		    total += arcptr->arc_count;
881 		  bb_graph[i].exec_count = total;
882 		  bb_graph[i].count_valid = 1;
883 		  changes = 1;
884 		}
885 	    }
886 	  if (bb_graph[i].count_valid)
887 	    {
888 	      if (bb_graph[i].succ_count == 1)
889 		{
890 		  total = 0;
891 		  /* One of the counts will be invalid, but it is zero,
892 		     so adding it in also doesn't hurt.  */
893 		  for (arcptr = bb_graph[i].succ; arcptr;
894 		       arcptr = arcptr->succ_next)
895 		    total += arcptr->arc_count;
896 		  /* Calculate count for remaining arc by conservation.  */
897 		  total = bb_graph[i].exec_count - total;
898 		  /* Search for the invalid arc, and set its count.  */
899 		  for (arcptr = bb_graph[i].succ; arcptr;
900 		       arcptr = arcptr->succ_next)
901 		    if (! arcptr->count_valid)
902 		      break;
903 		  if (! arcptr)
904 		    abort ();
905 		  arcptr->count_valid = 1;
906 		  arcptr->arc_count = total;
907 		  bb_graph[i].succ_count--;
908 
909 		  bb_graph[arcptr->target].pred_count--;
910 		  changes = 1;
911 		}
912 	      if (bb_graph[i].pred_count == 1)
913 		{
914 		  total = 0;
915 		  /* One of the counts will be invalid, but it is zero,
916 		     so adding it in also doesn't hurt.  */
917 		  for (arcptr = bb_graph[i].pred; arcptr;
918 		       arcptr = arcptr->pred_next)
919 		    total += arcptr->arc_count;
920 		  /* Calculate count for remaining arc by conservation.  */
921 		  total = bb_graph[i].exec_count - total;
922 		  /* Search for the invalid arc, and set its count.  */
923 		  for (arcptr = bb_graph[i].pred; arcptr;
924 		       arcptr = arcptr->pred_next)
925 		    if (! arcptr->count_valid)
926 		      break;
927 		  if (! arcptr)
928 		    abort ();
929 		  arcptr->count_valid = 1;
930 		  arcptr->arc_count = total;
931 		  bb_graph[i].pred_count--;
932 
933 		  bb_graph[arcptr->source].succ_count--;
934 		  changes = 1;
935 		}
936 	    }
937 	}
938     }
939 
940   /* If the graph has been correctly solved, every block will have a
941      succ and pred count of zero.  */
942   for (i = 0; i < num_blocks; i++)
943     if (bb_graph[i].succ_count || bb_graph[i].pred_count)
944       abort ();
945 }
946 
947 
948 static void
read_files()949 read_files ()
950 {
951   struct stat buf;
952   struct bb_info_list *list_end = 0;
953   struct bb_info_list *b_ptr;
954 
955   while (! feof (bbg_file))
956     {
957       b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
958 
959       b_ptr->next = 0;
960       if (list_end)
961 	list_end->next = b_ptr;
962       else
963 	bb_graph_list = b_ptr;
964       list_end = b_ptr;
965 
966       /* Read in the data in the .bbg file and reconstruct the program flow
967 	 graph for one function.  */
968       create_program_flow_graph (b_ptr);
969 
970       /* Set the EOF condition if at the end of file.  */
971       ungetc (getc (bbg_file), bbg_file);
972     }
973 
974   /* Calculate all of the basic block execution counts and branch
975      taken probabilities.  */
976 
977   for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
978     solve_program_flow_graph (b_ptr);
979 
980   /* Read in all of the data from the .bb file.   This info will be accessed
981      sequentially twice.  */
982   stat (bb_file_name, &buf);
983   bb_data_size = buf.st_size / 4;
984 
985   bb_data = (char *) xmalloc ((unsigned) buf.st_size);
986   fread (bb_data, sizeof (char), buf.st_size, bb_file);
987 
988   fclose (bb_file);
989   if (da_file)
990     fclose (da_file);
991   fclose (bbg_file);
992 }
993 
994 
995 /* Scan the data in the .bb file to find all source files referenced,
996    and the largest line number mentioned in each one.  */
997 
998 static void
scan_for_source_files()999 scan_for_source_files ()
1000 {
1001   struct sourcefile *s_ptr = NULL;
1002   char *ptr;
1003   long count;
1004   long line_num;
1005 
1006   /* Search the bb_data to find:
1007      1) The number of sources files contained herein, and
1008      2) The largest line number for each source file.  */
1009 
1010   ptr = bb_data;
1011   sources = 0;
1012   for (count = 0; count < bb_data_size; count++)
1013     {
1014       __fetch_long (&line_num, ptr, 4);
1015       ptr += 4;
1016       if (line_num == -1)
1017 	{
1018 	  /* A source file name follows.  Check to see if we already have
1019 	   a sourcefile structure for this file.  */
1020 	  s_ptr = sources;
1021 	  while (s_ptr && strcmp (s_ptr->name, ptr))
1022 	    s_ptr = s_ptr->next;
1023 
1024 	  if (s_ptr == 0)
1025 	    {
1026 	      /* No sourcefile structure for this file name exists, create
1027 		 a new one, and append it to the front of the sources list.  */
1028 	      s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
1029 	      s_ptr->name = xstrdup (ptr);
1030 	      s_ptr->maxlineno = 0;
1031 	      s_ptr->next = sources;
1032 	      sources = s_ptr;
1033 	    }
1034 
1035 	  /* Scan past the file name.  */
1036 	  {
1037 	    long delim;
1038 	    do {
1039 	      count++;
1040 	      __fetch_long (&delim, ptr, 4);
1041 	      ptr += 4;
1042 	    } while (delim != line_num);
1043 	  }
1044 	}
1045       else if (line_num == -2)
1046 	{
1047 	  long delim;
1048 
1049 	  /* A function name follows.  Ignore it.  */
1050 	  do {
1051 	    count++;
1052 	    __fetch_long (&delim, ptr, 4);
1053 	    ptr += 4;
1054 	  } while (delim != line_num);
1055 	}
1056       /* There will be a zero before the first file name, in which case s_ptr
1057 	 will still be uninitialized.  So, only try to set the maxlineno
1058 	 field if line_num is nonzero.  */
1059       else if (line_num > 0)
1060 	{
1061 	  if (s_ptr->maxlineno <= line_num)
1062 	    s_ptr->maxlineno = line_num + 1;
1063 	}
1064       else if (line_num < 0)
1065 	{
1066 	  /* Don't know what this is, but it's garbage.  */
1067 	  abort ();
1068 	}
1069     }
1070 }
1071 
1072 
1073 /* Increment totals in FUNCTION according to arc A_PTR.  */
1074 
1075 static void
accumulate_branch_counts(function,a_ptr)1076 accumulate_branch_counts (function, a_ptr)
1077      struct coverage *function;
1078      struct arcdata *a_ptr;
1079 {
1080   if (a_ptr->call_insn)
1081     {
1082       function->calls++;
1083       if (a_ptr->total)
1084 	function->calls_executed++;
1085     }
1086   else
1087     {
1088       function->branches++;
1089       if (a_ptr->total)
1090 	function->branches_executed++;
1091       if (a_ptr->hits)
1092 	function->branches_taken++;
1093     }
1094 }
1095 
1096 /* Calculate the branch taken probabilities for all arcs branches at the
1097    end of this block.  */
1098 
1099 static void
calculate_branch_probs(block_ptr,line_info,function)1100 calculate_branch_probs (block_ptr, line_info, function)
1101      struct bb_info *block_ptr;
1102      struct line_info *line_info;
1103      struct coverage *function;
1104 {
1105   gcov_type total;
1106   struct adj_list *arcptr;
1107 
1108   total = block_ptr->exec_count;
1109   for (arcptr = block_ptr->succ; arcptr; arcptr = arcptr->succ_next)
1110     {
1111       struct arcdata *a_ptr;
1112 
1113       /* Ignore fall through arcs as they aren't really branches.  */
1114       if (arcptr->fall_through)
1115 	continue;
1116 
1117       a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
1118       a_ptr->total = total;
1119       a_ptr->hits = total ? arcptr->arc_count : 0;
1120       a_ptr->call_insn = arcptr->fake;
1121 
1122       if (function)
1123 	accumulate_branch_counts (function, a_ptr);
1124       /* Prepend the new branch to the list.  */
1125       a_ptr->next = line_info->branches;
1126       line_info->branches = a_ptr;
1127     }
1128 }
1129 
1130 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1131    count.  If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1132    If DP is zero, no decimal point is printed. Only print 100% when
1133    TOP==BOTTOM and only print 0% when TOP=0.  If dp < 0, then simply
1134    format TOP.  Return pointer to a static string.  */
1135 
1136 static char const *
format_hwint(top,bottom,dp)1137 format_hwint (top, bottom, dp)
1138      HOST_WIDEST_INT top, bottom;
1139      int dp;
1140 {
1141   static char buffer[20];
1142 
1143   if (dp >= 0)
1144     {
1145       float ratio = bottom ? (float)top / bottom : 0;
1146       int ix;
1147       unsigned limit = 100;
1148       unsigned percent;
1149 
1150       for (ix = dp; ix--; )
1151 	limit *= 10;
1152 
1153       percent = (unsigned) (ratio * limit + (float)0.5);
1154       if (percent <= 0 && top)
1155 	percent = 1;
1156       else if (percent >= limit && top != bottom)
1157 	percent = limit - 1;
1158       ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1159       if (dp)
1160 	{
1161 	  dp++;
1162 	  do
1163 	    {
1164 	      buffer[ix+1] = buffer[ix];
1165 	      ix--;
1166 	    }
1167 	  while (dp--);
1168 	  buffer[ix + 1] = '.';
1169 	}
1170     }
1171   else
1172     sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, top);
1173 
1174   return buffer;
1175 }
1176 
1177 
1178 /* Output summary info for a function.  */
1179 
1180 static void
function_summary(function,title)1181 function_summary (function, title)
1182      struct coverage *function;
1183      const char *title;
1184 {
1185   if (function->lines)
1186     fnotice (stdout, "%s of %d lines executed in %s %s\n",
1187 	     format_hwint (function->lines_executed,
1188 			   function->lines, 2),
1189 	     function->lines, title, function->name);
1190   else
1191     fnotice (stdout, "No executable lines in %s %s\n",
1192 	     title, function->name);
1193 
1194   if (output_branch_probs)
1195     {
1196       if (function->branches)
1197 	{
1198 	  fnotice (stdout, "%s of %d branches executed in %s %s\n",
1199 		   format_hwint (function->branches_executed,
1200 				 function->branches, 2),
1201 		   function->branches, title, function->name);
1202 	  fnotice (stdout,
1203 		"%s of %d branches taken at least once in %s %s\n",
1204 		   format_hwint (function->branches_taken,
1205 				 function->branches, 2),
1206 		   function->branches, title, function->name);
1207 	}
1208       else
1209 	fnotice (stdout, "No branches in %s %s\n", title, function->name);
1210       if (function->calls)
1211 	fnotice (stdout, "%s of %d calls executed in %s %s\n",
1212 		 format_hwint (function->calls_executed,
1213 			       function->calls, 2),
1214 		 function->calls, title, function->name);
1215       else
1216 	fnotice (stdout, "No calls in %s %s\n", title, function->name);
1217     }
1218 }
1219 
1220 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1221    affect name generation. With preserve_paths we create a filename
1222    from all path components of the source file, replacing '/' with
1223    '#', without it we simply take the basename component. With
1224    long_output_names we prepend the processed name of the input file
1225    to each output name (except when the current source file is the
1226    input file, so you don't get a double concatenation). The two
1227    components are separated by '##'. Also '.' filename components are
1228    removed and '..'  components are renamed to '^'.  */
1229 
1230 static char *
make_gcov_file_name(src_name)1231 make_gcov_file_name (src_name)
1232      char *src_name;
1233 {
1234   char *cptr;
1235   char *name = xmalloc (strlen (src_name) + strlen (input_file_name) + 10);
1236 
1237   name[0] = 0;
1238   if (output_long_names && strcmp (src_name, input_file_name))
1239     {
1240       /* Generate the input filename part.  */
1241       cptr = preserve_paths ? NULL : strrchr (input_file_name, '/');
1242       cptr = cptr ? cptr + 1 : input_file_name;
1243       strcat (name, cptr);
1244       strcat (name, "##");
1245     }
1246 
1247   /* Generate the source filename part.  */
1248   cptr = preserve_paths ? NULL : strrchr (src_name, '/');
1249   cptr = cptr ? cptr + 1 : src_name;
1250   strcat (name, cptr);
1251 
1252   if (preserve_paths)
1253     {
1254       /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1255       char *prev;
1256 
1257       for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
1258  	{
1259  	  unsigned shift = 0;
1260 
1261  	  if (prev + 1 == cptr && prev[0] == '.')
1262  	    {
1263  	      /* Remove '.' */
1264  	      shift = 2;
1265  	    }
1266  	  else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
1267  	    {
1268  	      /* Convert '..' */
1269  	      shift = 1;
1270  	      prev[1] = '^';
1271  	    }
1272  	  else
1273  	    *cptr++ = '#';
1274  	  if (shift)
1275  	    {
1276  	      cptr = prev;
1277  	      do
1278  		prev[0] = prev[shift];
1279 	      while (*prev++);
1280  	    }
1281  	}
1282     }
1283 
1284   /* Don't strip off the ending for compatibility with tcov, since
1285      this results in confusion if there is more than one file with the
1286      same basename, e.g. tmp.c and tmp.h.  */
1287   strcat (name, ".gcov");
1288   return name;
1289 }
1290 
1291 /* Scan through the bb_data, and when the file name matches the
1292    source file name, then for each following line number, increment
1293    the line number execution count indicated by the execution count of
1294    the appropriate basic block.  */
1295 
1296 static void
init_line_info(line_info,total,maxlineno)1297 init_line_info (line_info, total, maxlineno)
1298      struct line_info *line_info;
1299      struct coverage *total;
1300      long maxlineno;
1301 {
1302   long block_num = 0;		/* current block number */
1303   struct bb_info *block_ptr = NULL;	/* current block ptr */
1304   struct coverage function;
1305   struct coverage *func_ptr = NULL;
1306   struct bb_info_list *current_graph = NULL; /* Graph for current function.  */
1307   int is_this_file = 0;	/* We're scanning a block from the desired file.  */
1308   char *ptr = bb_data;
1309   long count;
1310   long line_num;
1311   struct line_info *line_ptr = 0; /* line info ptr.  */
1312 
1313   memset (&function, 0, sizeof (function));
1314   if (output_function_summary)
1315     func_ptr = &function;
1316 
1317   for (count = 0; count < bb_data_size; count++)
1318     {
1319       __fetch_long (&line_num, ptr, 4);
1320       ptr += 4;
1321       if (line_num < 0)
1322 	{
1323 	  long delim;
1324 
1325 	  if (line_num == -1)
1326 	    {
1327 	      /* Marks the beginning of a file name.  Check to see
1328 	     	 whether this is the filename we are currently
1329 	     	 collecting data for.  */
1330 	      is_this_file = !strcmp (total->name, ptr);
1331 	    }
1332 	  else if (line_num == -2)
1333 	    {
1334 	      /* Marks the start of a new function.  Advance to the
1335 	     	 next program flow graph.  */
1336 	      if (!current_graph)
1337 		current_graph = bb_graph_list;
1338 	      else
1339 		{
1340 		  if (block_num == current_graph->num_blocks - 1)
1341 		    /* Last block falls through to exit.  */
1342 		    ;
1343 		  else if (block_num == current_graph->num_blocks - 2)
1344 		    {
1345 		      if (output_branch_probs && is_this_file)
1346 			calculate_branch_probs (block_ptr, line_ptr, func_ptr);
1347 		    }
1348 		  else
1349 		    {
1350 		      fnotice (stderr,
1351 			       "didn't use all bb entries of graph, function %s\n",
1352 			       function.name);
1353 		      fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
1354 			       block_num, current_graph->num_blocks);
1355 		    }
1356 		  if (func_ptr && is_this_file)
1357 		    function_summary (func_ptr, "function");
1358 		  current_graph = current_graph->next;
1359 		}
1360 	      block_num = 0;
1361 	      block_ptr = current_graph->bb_graph;
1362 	      memset (&function, 0, sizeof (function));
1363 	      function.name = ptr;
1364 	    }
1365 	  else
1366 	    {
1367 	      fnotice (stderr, "ERROR: unexpected line number %ld\n", line_num);
1368 	      abort ();
1369 	    }
1370 
1371 	  /* Scan past the string.  */
1372 	  for (delim = 0; delim != line_num; count++)
1373 	    {
1374 	      __fetch_long (&delim, ptr, 4);
1375 	      ptr += 4;
1376 	    }
1377 	}
1378       else if (!line_num)
1379 	{
1380 	  /* Marks the end of a block.  */
1381 	  if (block_num >= current_graph->num_blocks)
1382 	    {
1383 	      fnotice (stderr, "ERROR: too many basic blocks in function %s\n",
1384 		       function.name);
1385 	      abort ();
1386 	    }
1387 
1388 	  if (output_branch_probs && is_this_file)
1389 	    calculate_branch_probs (block_ptr, line_ptr, func_ptr);
1390 
1391 	  block_num++;
1392 	  block_ptr++;
1393 	}
1394       else if (is_this_file)
1395 	{
1396 	  if (line_num >= maxlineno)
1397 	    {
1398 	      fnotice (stderr, "ERROR: out of range line number in function %s\n",
1399 		       function.name);
1400 	      abort ();
1401 	    }
1402 
1403 	  line_ptr = &line_info[line_num];
1404 	  if (func_ptr)
1405 	    {
1406 	      if (!line_ptr->exists)
1407 		func_ptr->lines++;
1408 	      if (!line_ptr->count && block_ptr->exec_count)
1409 		func_ptr->lines_executed++;
1410 	    }
1411 
1412 	  /* Accumulate execution data for this line number.  */
1413 	  line_ptr->count += block_ptr->exec_count;
1414 	  line_ptr->exists = 1;
1415 	}
1416     }
1417 
1418   if (func_ptr && is_this_file)
1419     function_summary (func_ptr, "function");
1420 
1421   /* Calculate summary test coverage statistics.  */
1422   for (line_num = 1, line_ptr = &line_info[line_num];
1423        line_num < maxlineno; line_num++, line_ptr++)
1424     {
1425       struct arcdata *a_ptr, *prev, *next;
1426 
1427       if (line_ptr->exists)
1428 	{
1429 	  total->lines++;
1430 	  if (line_ptr->count)
1431 	    total->lines_executed++;
1432 	}
1433 
1434       /* Total and reverse the branch information.  */
1435       for (a_ptr = line_ptr->branches, prev = NULL; a_ptr; a_ptr = next)
1436 	{
1437 	  next = a_ptr->next;
1438 	  a_ptr->next = prev;
1439 	  prev = a_ptr;
1440 
1441 	  accumulate_branch_counts (total, a_ptr);
1442 	}
1443       line_ptr->branches = prev;
1444     }
1445 }
1446 
1447 /* Read in the source file one line at a time, and output that line to
1448    the gcov file preceded by its execution count and other
1449    information.  */
1450 
1451 static void
output_line_info(gcov_file,line_info,total,maxlineno)1452 output_line_info (gcov_file, line_info, total, maxlineno)
1453      FILE *gcov_file;
1454      const struct line_info *line_info;
1455      const struct coverage *total;
1456      long maxlineno;
1457 {
1458   FILE *source_file;
1459   long line_num;                    /* current line number */
1460   const struct line_info *line_ptr; /* current line info ptr.  */
1461   char string[STRING_SIZE];         /* line buffer.  */
1462   char const *retval = "";	    /* status of source file reading.  */
1463 
1464   fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, total->name);
1465   fprintf (gcov_file, "%9s:%5d:Object:%s\n", "-", 0, bb_file_name);
1466 
1467   source_file = fopen (total->name, "r");
1468   if (!source_file)
1469     {
1470       fnotice (stderr, "Could not open source file %s.\n", total->name);
1471       retval = NULL;
1472     }
1473   else
1474     {
1475       struct stat status;
1476 
1477       if (!fstat (fileno (source_file), &status)
1478 	  && status.st_mtime > bb_file_time)
1479 	{
1480 	  fnotice (stderr, "Warning: source file %s is newer than %s\n",
1481 		   total->name, bb_file_name);
1482 	  fprintf (gcov_file, "%9s:%5d:Source is newer than compiler output\n",
1483 		   "-", 0);
1484 	}
1485     }
1486 
1487   for (line_num = 1, line_ptr = &line_info[line_num];
1488        line_num < maxlineno; line_num++, line_ptr++)
1489     {
1490       /* For lines which don't exist in the .bb file, print '-' before
1491  	 the source line.  For lines which exist but were never
1492  	 executed, print '#####' before the source line.  Otherwise,
1493  	 print the execution count before the source line.  There are
1494  	 16 spaces of indentation added before the source line so that
1495  	 tabs won't be messed up.  */
1496       fprintf (gcov_file, "%9s:%5ld:",
1497 	       !line_ptr->exists ? "-"
1498 	       : !line_ptr->count ? "#####"
1499 	       : format_hwint (line_ptr->count, 0, -1), line_num);
1500 
1501       if (retval)
1502 	{
1503 	  /* Copy source line.  */
1504 	  do
1505 	    {
1506 	      retval = fgets (string, STRING_SIZE, source_file);
1507 	      if (!retval)
1508 		{
1509 		  fnotice (stderr,
1510 			   "Unexpected EOF while reading source file %s.\n",
1511 			   total->name);
1512 		  break;
1513 		}
1514 	      fputs (retval, gcov_file);
1515 	    }
1516 	  while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1517 	}
1518       if (!retval)
1519 	fputs ("??\n", gcov_file);
1520 
1521       if (output_branch_probs)
1522 	{
1523 	  int i;
1524 	  struct arcdata *a_ptr;
1525 
1526 	  for (i = 0, a_ptr = line_ptr->branches; a_ptr;
1527 	       a_ptr = a_ptr->next, i++)
1528 	    {
1529 	      if (a_ptr->call_insn)
1530 		{
1531 		  if (a_ptr->total == 0)
1532 		    fnotice (gcov_file, "call   %2d never executed\n", i);
1533 		  else
1534 		    fnotice
1535 		      (gcov_file, "call   %2d returns %s\n", i,
1536 		       format_hwint (a_ptr->total - a_ptr->hits,
1537 				     a_ptr->total,
1538 				     -output_branch_counts));
1539 		}
1540 	      else
1541 		{
1542 		  if (a_ptr->total == 0)
1543 		    fnotice (gcov_file, "branch %2d never executed\n", i);
1544 		  else
1545 		    fnotice
1546 		      (gcov_file, "branch %2d taken %s\n", i,
1547 		       format_hwint (a_ptr->hits, a_ptr->total,
1548 				     -output_branch_counts));
1549 		}
1550 	    }
1551 	}
1552     }
1553 
1554   /* Handle all remaining source lines.  There may be lines after the
1555      last line of code.  */
1556   if (retval)
1557     {
1558       for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
1559 	{
1560 	  fprintf (gcov_file, "%9s:%5ld:%s", "-", line_num, retval);
1561 
1562 	  while (!retval[0] || retval[strlen (retval) - 1] != '\n')
1563 	    {
1564 	      retval = fgets (string, STRING_SIZE, source_file);
1565 	      if (!retval)
1566 		break;
1567 	      fputs (retval, gcov_file);
1568 	    }
1569 	}
1570     }
1571 
1572   if (source_file)
1573     fclose (source_file);
1574 }
1575 
1576 /* Calculate line execution counts, and output a .gcov file for source
1577    file S_PTR. Allocate an array big enough to hold a count for each
1578    line.  Scan through the bb_data, and when the file name matches the
1579    current file name, then for each following line number, increment
1580    the line number execution count indicated by the execution count of
1581    the appropriate basic block.  */
1582 
1583 static void
output_data(s_ptr)1584 output_data (s_ptr)
1585 	     struct sourcefile *s_ptr;
1586 {
1587   struct line_info *line_info	/* line info data */
1588     = (struct line_info *) xcalloc (s_ptr->maxlineno,
1589 				    sizeof (struct line_info));
1590   long line_num;
1591   struct coverage total;
1592 
1593   memset (&total, 0, sizeof (total));
1594   total.name = s_ptr->name;
1595 
1596   init_line_info (line_info, &total, s_ptr->maxlineno);
1597   function_summary (&total, "file");
1598 
1599   if (output_gcov_file)
1600     {
1601       /* Now the statistics are ready.  Read in the source file one
1602 	 line at a time, and output that line to the gcov file
1603 	 preceded by its execution information.  */
1604 
1605       char *gcov_file_name = make_gcov_file_name (total.name);
1606       FILE *gcov_file = fopen (gcov_file_name, "w");
1607 
1608       if (gcov_file)
1609 	{
1610 	  fnotice (stdout, "Creating %s.\n", gcov_file_name);
1611 	  output_line_info (gcov_file, line_info, &total, s_ptr->maxlineno);
1612 	  if (ferror (gcov_file))
1613 	    fnotice (stderr, "Error writing output file %s.\n",
1614 		     gcov_file_name);
1615 	  fclose (gcov_file);
1616 	}
1617       else
1618 	fnotice (stderr, "Could not open output file %s.\n", gcov_file_name);
1619       free (gcov_file_name);
1620     }
1621 
1622   /* Free data.  */
1623   for (line_num = 1; line_num != s_ptr->maxlineno; line_num++)
1624     {
1625       struct arcdata *branch, *next;
1626 
1627       for (branch = line_info[line_num].branches; branch; branch = next)
1628 	{
1629 	  next = branch->next;
1630 	  free (branch);
1631 	}
1632     }
1633   free (line_info);
1634 }
1635