OSDN Git Service

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