OSDN Git Service

* config/linux.h (ASM_COMMENT_START): Remove from here,
[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, 91, 92, 93, 94, 96, 1997 Free Software Foundation, Inc.
4    Contributed by James E. Wilson of Cygnus Support.
5    Mangled by Bob Manson of Cygnus Support.
6
7 Gcov is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 Gcov is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Gcov; see the file COPYING.  If not, write to
19 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 /* ??? The code in final.c that produces the struct bb assumes that there is
22    no padding between the fields.  This is not necessary true.  The current
23    code can only be trusted if longs and pointers are the same size.  */
24
25 /* ??? No need to print an execution count on every line, could just print
26    it on the first line of each block, and only print it on a subsequent
27    line in the same block if the count changes.  */
28
29 /* ??? Print a list of the ten blocks with the highest execution counts,
30    and list the line numbers corresponding to those blocks.  Also, perhaps
31    list the line numbers with the highest execution counts, only printing
32    the first if there are several which are all listed in the same block.  */
33
34 /* ??? Should have an option to print the number of basic blocks, and the
35    percent of them that are covered.  */
36
37 /* ??? Does not correctly handle the case where two .bb files refer to the
38    same included source file.  For example, if one has a short file containing
39    only inline functions, which is then included in two other files, then
40    there will be two .bb files which refer to the include file, but there
41    is no way to get the total execution counts for the included file, can
42    only get execution counts for one or the other of the including files.  */
43
44 #include "config.h"
45 #include "system.h"
46 #include <sys/stat.h>
47 #include "gansidecl.h"
48
49 #include "gcov-io.h"
50
51 /* The .bb file format consists of several lists of 4-byte integers
52    which are the line numbers of each basic block in the file.  Each
53    list is terminated by a zero.  These lists correspond to the basic
54    blocks in the reconstructed program flow graph.
55
56    A line number of -1 indicates that a source file name (padded to a
57    long boundary) follows.  The padded file name is followed by
58    another -1 to make it easy to scan past file names.  A -2 indicates
59    that a function name (padded to a long boundary) follows; the name
60    is followed by another -2 to make it easy to scan past the function
61    name.
62
63    The .bbg file contains enough info to enable gcov to reconstruct the
64    program flow graph.  The first word is the number of basic blocks,
65    the second word is the number of arcs, followed by the list of arcs
66    (source bb, dest bb pairs), then a -1, then the number of instrumented
67    arcs followed by the instrumented arcs, followed by another -1.  This
68    is repeated for each function.
69
70    The .da file contains the execution count for each instrumented branch.
71
72    The .bb and .bbg files are created by giving GCC the -ftest-coverage option,
73    and the .da files are created when an executable compiled with
74    -fprofile-arcs is run.  */
75
76 /* The functions in this file for creating and solution program flow graphs
77    are very similar to functions in the gcc source file profile.c.  */
78
79 char gcov_version_string[] = "GNU gcov version 1.5\n";
80
81 /* This is the size of the buffer used to read in source file lines.  */
82
83 #define STRING_SIZE 200
84
85 /* One copy of this structure is created for each source file mentioned in the
86    .bb file.  */
87
88 struct sourcefile
89 {
90   char *name;
91   int maxlineno;
92   struct sourcefile *next;
93 };
94
95 /* This points to the head of the sourcefile structure list.  */
96
97 struct sourcefile *sources;
98
99 /* One of these is dynamically created whenever we identify an arc in the
100    function.  */
101
102 struct adj_list {
103   int source;
104   int target;
105   int arc_count;
106   unsigned int count_valid : 1;
107   unsigned int on_tree : 1;
108   unsigned int fake : 1;
109   unsigned int fall_through : 1;
110 #if 0
111   /* Not needed for gcov, but defined in profile.c.  */
112   rtx branch_insn;
113 #endif
114   struct adj_list *pred_next;
115   struct adj_list *succ_next;
116 };
117
118 /* Count the number of basic blocks, and create an array of these structures,
119    one for each bb in the function.  */
120
121 struct bb_info {
122   struct adj_list *succ;
123   struct adj_list *pred;
124   int succ_count;
125   int pred_count;
126   int exec_count;
127   unsigned int count_valid : 1;
128   unsigned int on_tree : 1;
129 #if 0
130   /* Not needed for gcov, but defined in profile.c.  */
131   rtx first_insn;
132 #endif
133 };
134
135 /* When outputting branch probabilities, one of these structures is created
136    for each branch/call.  */
137
138 struct arcdata
139 {
140   int prob;
141   int call_insn;
142   struct arcdata *next;
143 };
144
145 /* Used to save the list of bb_graphs, one per function.  */
146
147 struct bb_info_list {
148   /* Indexed by block number, holds the basic block graph for one function.  */
149   struct bb_info *bb_graph;
150   int num_blocks;
151   struct bb_info_list *next;
152 };
153
154 /* Holds a list of function basic block graphs.  */
155
156 static struct bb_info_list *bb_graph_list = 0;
157
158 /* Name and file pointer of the input file for the basic block graph.  */
159
160 static char *bbg_file_name;
161 static FILE *bbg_file;
162
163 /* Name and file pointer of the input file for the arc count data.  */
164
165 static char *da_file_name;
166 static FILE *da_file;
167
168 /* Name and file pointer of the input file for the basic block line counts.  */
169
170 static char *bb_file_name;
171 static FILE *bb_file;
172
173 /* Holds the entire contents of the bb_file read into memory.  */
174
175 static char *bb_data;
176
177 /* Size of bb_data array in longs.  */
178
179 static long bb_data_size;
180
181 /* Name and file pointer of the output file.  */
182
183 static char *gcov_file_name;
184 static FILE *gcov_file;
185
186 /* Name of the file mentioned on the command line.  */
187
188 static char *input_file_name = 0;
189
190 /* Output branch probabilities if true.  */
191
192 static int output_branch_probs = 0;
193
194 /* Output a gcov file if this is true.  This is on by default, and can
195    be turned off by the -n option.  */
196
197 static int output_gcov_file = 1;
198
199 /* For included files, make the gcov output file name include the name of
200    the input source file.  For example, if x.h is included in a.c, then the
201    output file name is a.c.x.h.gcov instead of x.h.gcov.  This works only
202    when a single source file is specified.  */
203
204 static int output_long_names = 0;
205
206 /* Output summary info for each function.  */
207
208 static int output_function_summary = 0;
209
210 /* Object directory file prefix.  This is the directory where .bb and .bbg
211    files are looked for, if non-zero.  */
212
213 static char *object_directory = 0;
214
215 /* Forward declarations.  */
216 static void process_args PROTO ((int, char **));
217 static void open_files PROTO ((void));
218 static void read_files PROTO ((void));
219 static void scan_for_source_files PROTO ((void));
220 static void output_data PROTO ((void));
221 char * xmalloc ();
222
223 int
224 main (argc, argv)
225      int argc;
226      char **argv;
227 {
228   process_args (argc, argv);
229
230   open_files ();
231
232   read_files ();
233
234   scan_for_source_files ();
235
236   output_data ();
237
238   return 0;
239 }
240
241 char *
242 xmalloc (size)
243      unsigned size;
244 {
245   register char *value = (char *) malloc (size);
246   if (value == 0)
247     {
248       fprintf (stderr, "error: virtual memory exhausted");
249       exit (FATAL_EXIT_CODE);
250     }
251   return value;
252 }
253
254 /* More 'friendly' abort that prints the line and file.
255    config.h can #define abort fancy_abort if you like that sort of thing.  */
256
257 void
258 fancy_abort ()
259 {
260   fprintf (stderr, "Internal gcc abort.\n");
261   exit (FATAL_EXIT_CODE);
262 }
263 \f
264 /* Print a usage message and exit.  */
265
266 static void
267 print_usage ()
268 {
269   fprintf (stderr, "gcov [-b] [-v] [-n] [-l] [-f] [-o OBJDIR] file\n");
270   exit (FATAL_EXIT_CODE);
271 }
272
273 /* Parse the command line.  */
274
275 static void
276 process_args (argc, argv)
277      int argc;
278      char **argv;
279 {
280   int i;
281
282   for (i = 1; i < argc; i++)
283     {
284       if (argv[i][0] == '-')
285         {
286           if (argv[i][1] == 'b')
287             output_branch_probs = 1;
288           else if (argv[i][1] == 'v')
289             fputs (gcov_version_string, stderr);
290           else if (argv[i][1] == 'n')
291             output_gcov_file = 0;
292           else if (argv[i][1] == 'l')
293             output_long_names = 1;
294           else if (argv[i][1] == 'f')
295             output_function_summary = 1;
296           else if (argv[i][1] == 'o' && argv[i][2] == '\0')
297             object_directory = argv[++i];
298           else
299             print_usage ();
300         }
301       else if (! input_file_name)
302         input_file_name = argv[i];
303       else
304         print_usage ();
305     }
306
307   if (! input_file_name)
308     print_usage ();
309 }
310
311
312 /* Find and open the .bb, .da, and .bbg files.  */
313
314 static void
315 open_files ()
316 {
317   int count, objdir_count;
318   char *cptr;
319
320   /* Determine the names of the .bb, .bbg, and .da files.  Strip off the
321      extension, if any, and append the new extensions.  */
322   count = strlen (input_file_name);
323   if (object_directory)
324     objdir_count = strlen (object_directory);
325   else
326     objdir_count = 0;
327
328   da_file_name = xmalloc (count + objdir_count + 4);
329   bb_file_name = xmalloc (count + objdir_count + 4);
330   bbg_file_name = xmalloc (count + objdir_count + 5);
331
332   if (object_directory)
333     {
334       strcpy (da_file_name, object_directory);
335       strcpy (bb_file_name, object_directory);
336       strcpy (bbg_file_name, object_directory);
337
338       if (object_directory[objdir_count - 1] != '/')
339         {
340           strcat (da_file_name, "/");
341           strcat (bb_file_name, "/");
342           strcat (bbg_file_name, "/");
343         }
344
345       cptr = rindex (input_file_name, '/');
346       if (cptr)
347         {
348           strcat (da_file_name, cptr + 1);
349           strcat (bb_file_name, cptr + 1);
350           strcat (bbg_file_name, cptr + 1);
351         }
352       else
353         {
354           strcat (da_file_name, input_file_name);
355           strcat (bb_file_name, input_file_name);
356           strcat (bbg_file_name, input_file_name);
357         }
358     }
359   else
360     {
361       strcpy (da_file_name, input_file_name);
362       strcpy (bb_file_name, input_file_name);
363       strcpy (bbg_file_name, input_file_name);
364     }
365
366   cptr = rindex (bb_file_name, '.');
367   if (cptr)
368     strcpy (cptr, ".bb");
369   else
370     strcat (bb_file_name, ".bb");
371
372   cptr = rindex (da_file_name, '.');
373   if (cptr)
374     strcpy (cptr, ".da");
375   else
376     strcat (da_file_name, ".da");
377
378   cptr = rindex (bbg_file_name, '.');
379   if (cptr)
380     strcpy (cptr, ".bbg");
381   else
382     strcat (bbg_file_name, ".bbg");
383
384   bb_file = fopen (bb_file_name, "r");
385   if (bb_file == NULL)
386     {
387       fprintf (stderr, "Could not open basic block file %s.\n", bb_file_name);
388       exit (FATAL_EXIT_CODE);
389     }
390
391   /* If none of the functions in the file were executed, then there won't
392      be a .da file.  Just assume that all counts are zero in this case.  */
393   da_file = fopen (da_file_name, "r");
394   if (da_file == NULL)
395     {
396       fprintf (stderr, "Could not open data file %s.\n", da_file_name);
397       fprintf (stderr, "Assuming that all execution counts are zero.\n");
398     }
399     
400   bbg_file = fopen (bbg_file_name, "r");
401   if (bbg_file == NULL)
402     {
403       fprintf (stderr, "Could not open program flow graph file %s.\n",
404                bbg_file_name);
405       exit (FATAL_EXIT_CODE);
406     }
407
408   /* Check for empty .bbg file.  This indicates that there is no executable
409      code in this source file.  */
410   /* Set the EOF condition if at the end of file.  */
411   ungetc (getc (bbg_file), bbg_file);
412   if (feof (bbg_file))
413     {
414       fprintf (stderr, "No executable code associated with file %s.\n",
415                input_file_name);
416       exit (FATAL_EXIT_CODE);
417     }
418 }
419 \f
420 /* Initialize a new arc.  */
421
422 static void
423 init_arc (arcptr, source, target, bb_graph)
424      struct adj_list *arcptr;
425      int source, target;
426      struct bb_info *bb_graph;
427 {
428   arcptr->target = target;
429   arcptr->source = source;
430
431   arcptr->arc_count = 0;
432   arcptr->count_valid = 0;
433   arcptr->on_tree = 0;
434   arcptr->fake = 0;
435   arcptr->fall_through = 0;
436
437   arcptr->succ_next = bb_graph[source].succ;
438   bb_graph[source].succ = arcptr;
439   bb_graph[source].succ_count++;
440
441   arcptr->pred_next = bb_graph[target].pred;
442   bb_graph[target].pred = arcptr;
443   bb_graph[target].pred_count++;
444 }
445
446
447 /* Reverse the arcs on a arc list.  */
448
449 static struct adj_list *
450 reverse_arcs (arcptr)
451      struct adj_list *arcptr;
452 {
453   struct adj_list *prev = 0;
454   struct adj_list *next;
455
456   for ( ; arcptr; arcptr = next)
457     {
458       next = arcptr->succ_next;
459       arcptr->succ_next = prev;
460       prev = arcptr;
461     }
462
463   return prev;
464 }
465
466
467 /* Construct the program flow graph from the .bbg file, and read in the data
468    in the .da file.  */
469
470 static void
471 create_program_flow_graph (bptr)
472      struct bb_info_list *bptr;
473 {
474   long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
475   int i;
476   struct adj_list *arcptr;
477   struct bb_info *bb_graph;
478
479   /* Read the number of blocks.  */
480   __read_long (&num_blocks, bbg_file, 4);
481
482   /* Create an array of size bb number of bb_info structs.  Bzero it.  */
483   bb_graph = (struct bb_info *) xmalloc (num_blocks
484                                          * sizeof (struct bb_info));
485   bzero ((char *) bb_graph, sizeof (struct bb_info) * num_blocks);
486
487   bptr->bb_graph = bb_graph;
488   bptr->num_blocks = num_blocks;
489
490   /* Read and create each arc from the .bbg file.  */
491   __read_long (&number_arcs, bbg_file, 4);
492   for (i = 0; i < num_blocks; i++)
493     {
494       int j;
495
496       __read_long (&num_arcs_per_block, bbg_file, 4);
497       for (j = 0; j < num_arcs_per_block; j++)
498         {
499           if (number_arcs-- < 0)
500             abort ();
501
502           src = i;
503           __read_long (&dest, bbg_file, 4);
504
505           arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
506           init_arc (arcptr, src, dest, bb_graph);
507
508           __read_long (&flag_bits, bbg_file, 4);
509           arcptr->on_tree = flag_bits & 0x1;
510           arcptr->fake = !! (flag_bits & 0x2);
511           arcptr->fall_through = !! (flag_bits & 0x4);
512         }
513     }
514
515   if (number_arcs)
516     abort ();
517
518   /* Read and ignore the -1 separating the arc list from the arc list of the
519      next function.  */
520   __read_long (&src, bbg_file, 4);
521   if (src != -1)
522     abort ();
523
524   /* Must reverse the order of all succ arcs, to ensure that they match
525      the order of the data in the .da file.  */
526
527   for (i = 0; i < num_blocks; i++)
528     if (bb_graph[i].succ)
529       bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
530
531   /* For each arc not on the spanning tree, set its execution count from
532      the .da file.  */
533
534   /* The first count in the .da file is the number of times that the function
535      was entered.  This is the exec_count for block zero.  */
536
537   /* This duplicates code in branch_prob in profile.c.  */
538
539   for (i = 0; i < num_blocks; i++)
540     for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
541       if (! arcptr->on_tree)
542         {
543           long tmp_count = 0;;
544           if (da_file && __read_long (&tmp_count, da_file, 8))
545             abort();
546
547           arcptr->arc_count = tmp_count;
548           arcptr->count_valid = 1;
549           bb_graph[i].succ_count--;
550           bb_graph[arcptr->target].pred_count--;
551         }
552 }
553   
554 static void
555 solve_program_flow_graph (bptr)
556      struct bb_info_list *bptr;
557 {
558   int passes, changes, total;
559   int i;
560   struct adj_list *arcptr;
561   struct bb_info *bb_graph;
562   int num_blocks;
563
564   num_blocks = bptr->num_blocks;
565   bb_graph = bptr->bb_graph;
566
567   /* For every block in the file,
568      - if every exit/entrance arc has a known count, then set the block count
569      - if the block count is known, and every exit/entrance arc but one has
570        a known execution count, then set the count of the remaining arc
571
572      As arc counts are set, decrement the succ/pred count, but don't delete
573      the arc, that way we can easily tell when all arcs are known, or only
574      one arc is unknown.  */
575
576   /* The order that the basic blocks are iterated through is important.
577      Since the code that finds spanning trees starts with block 0, low numbered
578      arcs are put on the spanning tree in preference to high numbered arcs.
579      Hence, most instrumented arcs are at the end.  Graph solving works much
580      faster if we propagate numbers from the end to the start.
581
582      This takes an average of slightly more than 3 passes.  */
583
584   changes = 1;
585   passes = 0;
586   while (changes)
587     {
588       passes++;
589       changes = 0;
590
591       for (i = num_blocks - 1; i >= 0; i--)
592         {
593           if (! bb_graph[i].count_valid)
594             {
595               if (bb_graph[i].succ_count == 0)
596                 {
597                   total = 0;
598                   for (arcptr = bb_graph[i].succ; arcptr;
599                        arcptr = arcptr->succ_next)
600                     total += arcptr->arc_count;
601                   bb_graph[i].exec_count = total;
602                   bb_graph[i].count_valid = 1;
603                   changes = 1;
604                 }
605               else if (bb_graph[i].pred_count == 0)
606                 {
607                   total = 0;
608                   for (arcptr = bb_graph[i].pred; arcptr;
609                        arcptr = arcptr->pred_next)
610                     total += arcptr->arc_count;
611                   bb_graph[i].exec_count = total;
612                   bb_graph[i].count_valid = 1;
613                   changes = 1;
614                 }
615             }
616           if (bb_graph[i].count_valid)
617             {
618               if (bb_graph[i].succ_count == 1)
619                 {
620                   total = 0;
621                   /* One of the counts will be invalid, but it is zero,
622                      so adding it in also doesn't hurt.  */
623                   for (arcptr = bb_graph[i].succ; arcptr;
624                        arcptr = arcptr->succ_next)
625                     total += arcptr->arc_count;
626                   /* Calculate count for remaining arc by conservation.  */
627                   total = bb_graph[i].exec_count - total;
628                   /* Search for the invalid arc, and set its count.  */
629                   for (arcptr = bb_graph[i].succ; arcptr;
630                        arcptr = arcptr->succ_next)
631                     if (! arcptr->count_valid)
632                       break;
633                   if (! arcptr)
634                     abort ();
635                   arcptr->count_valid = 1;
636                   arcptr->arc_count = total;
637                   bb_graph[i].succ_count--;
638
639                   bb_graph[arcptr->target].pred_count--;
640                   changes = 1;
641                 }
642               if (bb_graph[i].pred_count == 1)
643                 {
644                   total = 0;
645                   /* One of the counts will be invalid, but it is zero,
646                      so adding it in also doesn't hurt.  */
647                   for (arcptr = bb_graph[i].pred; arcptr;
648                        arcptr = arcptr->pred_next)
649                     total += arcptr->arc_count;
650                   /* Calculate count for remaining arc by conservation.  */
651                   total = bb_graph[i].exec_count - total;
652                   /* Search for the invalid arc, and set its count.  */
653                   for (arcptr = bb_graph[i].pred; arcptr;
654                        arcptr = arcptr->pred_next)
655                     if (! arcptr->count_valid)
656                       break;
657                   if (! arcptr)
658                     abort ();
659                   arcptr->count_valid = 1;
660                   arcptr->arc_count = total;
661                   bb_graph[i].pred_count--;
662
663                   bb_graph[arcptr->source].succ_count--;
664                   changes = 1;
665                 }
666             }
667         }
668     }
669               
670   /* If the graph has been correctly solved, every block will have a
671      succ and pred count of zero.  */
672   for (i = 0; i < num_blocks; i++)
673     if (bb_graph[i].succ_count || bb_graph[i].pred_count)
674       abort ();
675 }
676
677
678 static void
679 read_files ()
680 {
681   struct stat buf;
682   struct bb_info_list *list_end = 0;
683   struct bb_info_list *b_ptr;
684   long total;
685
686   /* Read and ignore the first word of the .da file, which is the count of
687      how many numbers follow.  */
688   if (da_file && __read_long (&total, da_file, 8))
689     abort();
690
691   while (! feof (bbg_file))
692     {
693       b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
694
695       b_ptr->next = 0;
696       if (list_end)
697         list_end->next = b_ptr;
698       else
699         bb_graph_list = b_ptr;
700       list_end = b_ptr;
701
702       /* Read in the data in the .bbg file and reconstruct the program flow
703          graph for one function.  */
704       create_program_flow_graph (b_ptr);
705
706       /* Set the EOF condition if at the end of file.  */
707       ungetc (getc (bbg_file), bbg_file);
708     }
709
710   /* Check to make sure the .da file data is valid.  */
711
712   if (da_file)
713     {
714       if (feof (da_file))
715         fprintf (stderr, ".da file contents exhausted too early\n");
716       /* Should be at end of file now.  */
717       if (__read_long (&total, da_file, 8) == 0)
718         fprintf (stderr, ".da file contents not exhausted\n");
719     }
720
721   /* Calculate all of the basic block execution counts and branch
722      taken probabilities.  */
723
724   for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
725     solve_program_flow_graph (b_ptr);
726
727   /* Read in all of the data from the .bb file.   This info will be accessed
728      sequentially twice.  */
729   stat (bb_file_name, &buf);
730   bb_data_size = buf.st_size / 4;
731
732   bb_data = (char *) xmalloc ((unsigned) buf.st_size);
733   fread (bb_data, sizeof (char), buf.st_size, bb_file);
734   
735   fclose (bb_file);
736   if (da_file)
737     fclose (da_file);
738   fclose (bbg_file);
739 }
740
741
742 /* Scan the data in the .bb file to find all source files referenced,
743    and the largest line number mentioned in each one.  */
744
745 static void
746 scan_for_source_files ()
747 {
748   struct sourcefile *s_ptr = NULL;
749   char *ptr;
750   int count;
751   long line_num;
752
753   /* Search the bb_data to find:
754      1) The number of sources files contained herein, and
755      2) The largest line number for each source file.  */
756
757   ptr = bb_data;
758   sources = 0;
759   for (count = 0; count < bb_data_size; count++)
760     {
761       __fetch_long (&line_num, ptr, 4);
762       ptr += 4;
763       if (line_num == -1)
764         {
765           /* A source file name follows.  Check to see if we already have
766            a sourcefile structure for this file.  */
767           s_ptr = sources;
768           while (s_ptr && strcmp (s_ptr->name, ptr))
769             s_ptr = s_ptr->next;
770
771           if (s_ptr == 0)
772             {
773               /* No sourcefile structure for this file name exists, create
774                  a new one, and append it to the front of the sources list.  */
775               s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
776               s_ptr->name = xmalloc (strlen ((char *) ptr) + 1);
777               strcpy (s_ptr->name, (char *) ptr);
778               s_ptr->maxlineno = 0;
779               s_ptr->next = sources;
780               sources = s_ptr;
781             }
782
783           /* Scan past the file name.  */
784           {
785             long delim;
786             do {
787               count++;
788               __fetch_long (&delim, ptr, 4);
789               ptr += 4;
790             } while (delim != line_num);
791           }
792         }
793       else if (line_num == -2)
794         {
795           long delim;
796
797           /* A function name follows.  Ignore it.  */
798           do {
799             count++;
800             __fetch_long (&delim, ptr, 4);
801             ptr += 4;
802           } while (delim != line_num);
803         }
804       /* There will be a zero before the first file name, in which case s_ptr
805          will still be uninitialized.  So, only try to set the maxlineno
806          field if line_num is non-zero.  */
807       else if (line_num > 0)
808         {
809           if (s_ptr->maxlineno <= line_num)
810             s_ptr->maxlineno = line_num + 1;
811         }
812       else if (line_num < 0)
813         {
814           /* Don't know what this is, but it's garbage. */
815           abort();
816         }
817     }
818 }
819 \f
820 /* For calculating coverage at the function level.  */
821
822 static int function_source_lines;
823 static int function_source_lines_executed;
824 static int function_branches;
825 static int function_branches_executed;
826 static int function_branches_taken;
827 static int function_calls;
828 static int function_calls_executed;
829 static char *function_name;
830
831 /* Calculate the branch taken probabilities for all arcs branches at the
832    end of this block.  */
833
834 static void
835 calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num)
836      struct bb_info_list *current_graph;
837      int block_num;
838      struct arcdata **branch_probs;
839      int last_line_num;
840 {
841   int total;
842   struct adj_list *arcptr;
843   struct arcdata *end_ptr, *a_ptr;
844
845   total = current_graph->bb_graph[block_num].exec_count;
846   for (arcptr = current_graph->bb_graph[block_num].succ; arcptr;
847        arcptr = arcptr->succ_next)
848     {
849       /* Ignore fall through arcs as they aren't really branches.  */
850
851       if (arcptr->fall_through)
852         continue;
853                       
854       a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
855       if (total == 0)
856         a_ptr->prob = -1;
857       else
858         a_ptr->prob = ((arcptr->arc_count * 100) + (total >> 1)) / total;
859       a_ptr->call_insn = arcptr->fake;
860
861       if (output_function_summary)
862         {
863           if (a_ptr->call_insn)
864             {
865               function_calls++;
866               if (a_ptr->prob != -1)
867                 function_calls_executed++;
868             }
869           else
870             {
871               function_branches++;
872               if (a_ptr->prob != -1)
873                 function_branches_executed++;
874               if (a_ptr->prob > 0)
875                 function_branches_taken++;
876             }
877         }
878
879       /* Append the new branch to the end of the list.  */
880       a_ptr->next = 0;
881       if (! branch_probs[last_line_num])
882         branch_probs[last_line_num] = a_ptr;
883       else
884         {
885           end_ptr = branch_probs[last_line_num];
886           while (end_ptr->next != 0)
887             end_ptr = end_ptr->next;
888           end_ptr->next = a_ptr;
889         }
890     }
891 }
892
893 /* Output summary info for a function.  */
894
895 static void
896 function_summary ()
897 {
898   if (function_source_lines)
899     fprintf (stdout, "%6.2f%% of %d source lines executed in function %s\n",
900              (((double) function_source_lines_executed / function_source_lines)
901               * 100), function_source_lines, function_name);
902   else
903     fprintf (stdout, "No executable source lines in function %s\n",
904              function_name);
905
906   if (output_branch_probs)
907     {
908       if (function_branches)
909         {
910           fprintf (stdout, "%6.2f%% of %d branches executed in function %s\n",
911                    (((double) function_branches_executed / function_branches)
912                     * 100), function_branches, function_name);
913           fprintf (stdout,
914                 "%6.2f%% of %d branches taken at least once in function %s\n",
915                    (((double) function_branches_taken / function_branches)
916                     * 100), function_branches, function_name);
917         }
918       else
919         fprintf (stdout, "No branches in function %s\n", function_name);
920       if (function_calls)
921         fprintf (stdout, "%6.2f%% of %d calls executed in function %s\n",
922                  (((double) function_calls_executed / function_calls)
923                   * 100), function_calls, function_name);
924       else
925         fprintf (stdout, "No calls in function %s\n", function_name);
926     }
927 }
928
929 /* Calculate line execution counts, and output the data to a .tcov file.  */
930
931 static void
932 output_data ()
933 {
934   /* When scanning data, this is true only if the data applies to the
935      current source file.  */
936   int this_file;
937   /* An array indexed by line number which indicates how many times that line
938      was executed.  */
939   long *line_counts;
940   /* An array indexed by line number which indicates whether the line was
941      present in the bb file (i.e. whether it had code associate with it).
942      Lines never executed are those which both exist, and have zero execution
943      counts.  */
944   char *line_exists;
945   /* An array indexed by line number, which contains a list of branch
946      probabilities, one for each branch on that line.  */
947   struct arcdata **branch_probs = NULL;
948   struct sourcefile *s_ptr;
949   char *source_file_name;
950   FILE *source_file;
951   struct bb_info_list *current_graph;
952   int count;
953   char *cptr;
954   long block_num;
955   long line_num;
956   long last_line_num = 0;
957   int i;
958   struct arcdata *a_ptr;
959   /* Buffer used for reading in lines from the source file.  */
960   char string[STRING_SIZE];
961   /* For calculating coverage at the file level.  */
962   int total_source_lines;
963   int total_source_lines_executed;
964   int total_branches;
965   int total_branches_executed;
966   int total_branches_taken;
967   int total_calls;
968   int total_calls_executed;
969
970   /* Now, for each source file, allocate an array big enough to hold a count
971      for each line.  Scan through the bb_data, and when the file name matches
972      the current file name, then for each following line number, increment
973      the line number execution count indicated by the execution count of
974      the appropriate basic block.  */
975
976   for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
977     {
978       /* If this is a relative file name, and an object directory has been
979          specified, then make it relative to the object directory name.  */
980       if (*s_ptr->name != '/' && object_directory != 0
981           && *object_directory != '\0')
982         {
983           int objdir_count = strlen (object_directory);
984           source_file_name = xmalloc (objdir_count + strlen (s_ptr->name) + 2);
985           strcpy (source_file_name, object_directory);
986           if (object_directory[objdir_count - 1] != '/')
987             source_file_name[objdir_count++] = '/';
988           strcpy (source_file_name + objdir_count, s_ptr->name);
989         }
990       else
991         source_file_name = s_ptr->name;
992
993       line_counts = (long *) xmalloc (sizeof (long) * s_ptr->maxlineno);
994       bzero ((char *) line_counts, sizeof (long) * s_ptr->maxlineno);
995       line_exists = xmalloc (s_ptr->maxlineno);
996       bzero (line_exists, s_ptr->maxlineno);
997       if (output_branch_probs)
998         {
999           branch_probs = (struct arcdata **) xmalloc (sizeof (struct arcdata **)
1000                                                       * s_ptr->maxlineno);
1001           bzero ((char *) branch_probs, 
1002                  sizeof (struct arcdata **) * s_ptr->maxlineno);
1003         }
1004       
1005       /* There will be a zero at the beginning of the bb info, before the
1006          first list of line numbers, so must initialize block_num to 0.  */
1007       block_num = 0;
1008       this_file = 0;
1009       current_graph = 0;
1010       {
1011         /* Pointer into the bb_data, incremented while scanning the data.  */
1012         char *ptr = bb_data;
1013         for (count = 0; count < bb_data_size; count++)
1014           {
1015             long delim;
1016
1017             __fetch_long (&line_num, ptr, 4);
1018             ptr += 4;
1019             if (line_num == -1)
1020               {
1021                 /* Marks the beginning of a file name.  Check to see whether
1022                    this is the filename we are currently collecting data for.  */
1023
1024                 if (strcmp (s_ptr->name, ptr))
1025                   this_file = 0;
1026                 else
1027                   this_file = 1;
1028               
1029                 /* Scan past the file name.  */
1030                 do {
1031                   count++;
1032                   __fetch_long (&delim, ptr, 4);
1033                   ptr += 4;
1034                 } while (delim != line_num);
1035               }
1036             else if (line_num == -2)
1037               {
1038                 /* Marks the start of a new function.  Advance to the next
1039                    program flow graph.  */
1040
1041                 if (! current_graph)
1042                   current_graph = bb_graph_list;
1043                 else
1044                   {
1045                     if (block_num == current_graph->num_blocks - 1)
1046                       /* Last block falls through to exit.  */
1047                       ;
1048                     else if (block_num == current_graph->num_blocks - 2)
1049                       {
1050                         if (output_branch_probs && this_file)
1051                           calculate_branch_probs (current_graph, block_num,
1052                                                   branch_probs, last_line_num);
1053                       }
1054                     else
1055                       {
1056                         fprintf (stderr,
1057                                  "didn't use all bb entries of graph, function %s\n",
1058                                  function_name);
1059                         fprintf (stderr, "block_num = %ld, num_blocks = %d\n",
1060                                  block_num, current_graph->num_blocks);
1061                       }
1062
1063                     current_graph = current_graph->next;
1064                     block_num = 0;
1065
1066                     if (output_function_summary && this_file)
1067                       function_summary ();
1068                   }
1069
1070                 if (output_function_summary)
1071                   {
1072                     function_source_lines = 0;
1073                     function_source_lines_executed = 0;
1074                     function_branches = 0;
1075                     function_branches_executed = 0;
1076                     function_branches_taken = 0;
1077                     function_calls = 0;
1078                     function_calls_executed = 0;
1079                   }
1080
1081                 /* Save the function name for later use.  */
1082                 function_name = ptr;
1083
1084                 /* Scan past the file name.  */
1085                 do {
1086                   count++;
1087                   __fetch_long (&delim, ptr, 4);
1088                   ptr += 4;
1089                 } while (delim != line_num);
1090               }
1091             else if (line_num == 0)
1092               {
1093                 /* Marks the end of a block.  */
1094
1095                 if (block_num >= current_graph->num_blocks)
1096                   {
1097                     fprintf (stderr, "ERROR: too many basic blocks in .bb file %s\n",
1098                              function_name);
1099                     abort ();
1100                   }
1101                   
1102                 if (output_branch_probs && this_file)
1103                   calculate_branch_probs (current_graph, block_num,
1104                                           branch_probs, last_line_num);
1105
1106                 block_num++;
1107               }
1108             else if (this_file)
1109               {
1110                 if (output_function_summary)
1111                   {
1112                     if (line_exists[line_num] == 0)
1113                       function_source_lines++;
1114                     if (line_counts[line_num] == 0
1115                         && current_graph->bb_graph[block_num].exec_count != 0)
1116                       function_source_lines_executed++;
1117                   }
1118
1119                 /* Accumulate execution data for this line number.  */
1120
1121                 line_counts[line_num]
1122                   += current_graph->bb_graph[block_num].exec_count;
1123                 line_exists[line_num] = 1;
1124                 last_line_num = line_num;
1125               }
1126           }
1127       }
1128
1129       if (output_function_summary && this_file)
1130         function_summary ();
1131
1132       /* Calculate summary test coverage statistics.  */
1133
1134       total_source_lines = 0;
1135       total_source_lines_executed = 0;
1136       total_branches = 0;
1137       total_branches_executed = 0;
1138       total_branches_taken = 0;
1139       total_calls = 0;
1140       total_calls_executed = 0;
1141
1142       for (count = 1; count < s_ptr->maxlineno; count++)
1143         {
1144           if (line_exists[count])
1145             {
1146               total_source_lines++;
1147               if (line_counts[count])
1148                 total_source_lines_executed++;
1149             }
1150           if (output_branch_probs)
1151             {
1152               for (a_ptr = branch_probs[count]; a_ptr; a_ptr = a_ptr->next)
1153                 {
1154                   if (a_ptr->call_insn)
1155                     {
1156                       total_calls++;
1157                       if (a_ptr->prob != -1)
1158                         total_calls_executed++;
1159                     }
1160                   else
1161                     {
1162                       total_branches++;
1163                       if (a_ptr->prob != -1)
1164                         total_branches_executed++;
1165                       if (a_ptr->prob > 0)
1166                         total_branches_taken++;
1167                     }
1168                 }
1169             }
1170         }
1171
1172       if (total_source_lines)
1173         fprintf (stdout,
1174                  "%6.2f%% of %d source lines executed in file %s\n",
1175                  (((double) total_source_lines_executed / total_source_lines)
1176                   * 100), total_source_lines, source_file_name);
1177       else
1178         fprintf (stdout, "No executable source lines in file %s\n",
1179                  source_file_name);
1180
1181       if (output_branch_probs)
1182         {
1183           if (total_branches)
1184             {
1185               fprintf (stdout, "%6.2f%% of %d branches executed in file %s\n",
1186                        (((double) total_branches_executed / total_branches)
1187                         * 100), total_branches, source_file_name);
1188               fprintf (stdout,
1189                     "%6.2f%% of %d branches taken at least once in file %s\n",
1190                        (((double) total_branches_taken / total_branches)
1191                         * 100), total_branches, source_file_name);
1192             }
1193           else
1194             fprintf (stdout, "No branches in file %s\n", source_file_name);
1195           if (total_calls)
1196             fprintf (stdout, "%6.2f%% of %d calls executed in file %s\n",
1197                      (((double) total_calls_executed / total_calls)
1198                       * 100), total_calls, source_file_name);
1199           else
1200             fprintf (stdout, "No calls in file %s\n", source_file_name);
1201         }
1202
1203       if (output_gcov_file)
1204         {
1205           /* Now the statistics are ready.  Read in the source file one line
1206              at a time, and output that line to the gcov file preceded by
1207              its execution count if non zero.  */
1208       
1209           source_file = fopen (source_file_name, "r");
1210           if (source_file == NULL)
1211             {
1212               fprintf (stderr, "Could not open source file %s.\n",
1213                        source_file_name);
1214               free (line_counts);
1215               free (line_exists);
1216               continue;
1217             }
1218
1219           count = strlen (source_file_name);
1220           cptr = rindex (s_ptr->name, '/');
1221           if (cptr)
1222             cptr = cptr + 1;
1223           else
1224             cptr = s_ptr->name;
1225           if (output_long_names && strcmp (cptr, input_file_name))
1226             {
1227               gcov_file_name = xmalloc (count + 7 + strlen (input_file_name));
1228               
1229               cptr = rindex (input_file_name, '/');
1230               if (cptr)
1231                 strcpy (gcov_file_name, cptr + 1);
1232               else
1233                 strcpy (gcov_file_name, input_file_name);
1234
1235               strcat (gcov_file_name, ".");
1236
1237               cptr = rindex (source_file_name, '/');
1238               if (cptr)
1239                 strcat (gcov_file_name, cptr + 1);
1240               else
1241                 strcat (gcov_file_name, source_file_name);
1242             }
1243           else
1244             {
1245               gcov_file_name = xmalloc (count + 6);
1246               cptr = rindex (source_file_name, '/');
1247               if (cptr)
1248                 strcpy (gcov_file_name, cptr + 1);
1249               else
1250                 strcpy (gcov_file_name, source_file_name);
1251             }
1252
1253           /* Don't strip off the ending for compatibility with tcov, since
1254              this results in confusion if there is more than one file with
1255              the same basename, e.g. tmp.c and tmp.h.  */
1256           strcat (gcov_file_name, ".gcov");
1257
1258           gcov_file = fopen (gcov_file_name, "w");
1259
1260           if (gcov_file == NULL)
1261             {
1262               fprintf (stderr, "Could not open output file %s.\n",
1263                        gcov_file_name);
1264               fclose (source_file);
1265               free (line_counts);
1266               free (line_exists);
1267               continue;
1268             }
1269
1270           fprintf (stdout, "Creating %s.\n", gcov_file_name);
1271
1272           for (count = 1; count < s_ptr->maxlineno; count++)
1273             {
1274               char *retval;
1275               int len;
1276
1277               retval = fgets (string, STRING_SIZE, source_file);
1278
1279               /* For lines which don't exist in the .bb file, print nothing
1280                  before the source line.  For lines which exist but were never
1281                  executed, print ###### before the source line.  Otherwise,
1282                  print the execution count before the source line.  */
1283               /* There are 16 spaces of indentation added before the source
1284                  line so that tabs won't be messed up.  */
1285               if (line_exists[count])
1286                 {
1287                   if (line_counts[count])
1288                     fprintf (gcov_file, "%12ld    %s", line_counts[count],
1289                              string);
1290                   else
1291                     fprintf (gcov_file, "      ######    %s", string);
1292                 }
1293               else
1294                 fprintf (gcov_file, "\t\t%s", string);
1295
1296               /* In case the source file line is larger than our buffer, keep
1297                  reading and outputting lines until we get a newline.  */
1298               len = strlen (string);
1299               while ((len == 0 || string[strlen (string) - 1] != '\n')
1300                      && retval != NULL)
1301                 {
1302                   retval = fgets (string, STRING_SIZE, source_file);
1303                   fputs (string, gcov_file);
1304                 }
1305
1306               if (output_branch_probs)
1307                 {
1308                   for (i = 0, a_ptr = branch_probs[count]; a_ptr;
1309                        a_ptr = a_ptr->next, i++)
1310                     {
1311                       if (a_ptr->call_insn)
1312                         {
1313                           if (a_ptr->prob == -1)
1314                             fprintf (gcov_file, "call %d never executed\n", i);
1315                           else
1316                             fprintf (gcov_file,
1317                                      "call %d returns = %d%%\n",
1318                                      i, 100 - a_ptr->prob);
1319                         }
1320                       else
1321                         {
1322                           if (a_ptr->prob == -1)
1323                             fprintf (gcov_file, "branch %d never executed\n",
1324                                      i);
1325                           else
1326                             fprintf (gcov_file, "branch %d taken = %d%%\n", i,
1327                                      a_ptr->prob);
1328                         }
1329                     }
1330                 }
1331
1332               /* Gracefully handle errors while reading the source file.  */
1333               if (retval == NULL)
1334                 {
1335                   fprintf (stderr,
1336                            "Unexpected EOF while reading source file %s.\n",
1337                            source_file_name);
1338                   break;
1339                 }
1340             }
1341
1342           /* Handle all remaining source lines.  There may be lines
1343              after the last line of code.  */
1344
1345           {
1346             char *retval = fgets (string, STRING_SIZE, source_file);
1347             while (retval != NULL)
1348               {
1349                 int len;
1350
1351                 fprintf (gcov_file, "\t\t%s", string);
1352
1353                 /* In case the source file line is larger than our buffer, keep
1354                    reading and outputting lines until we get a newline.  */
1355                 len = strlen (string);
1356                 while ((len == 0 || string[strlen (string) - 1] != '\n')
1357                        && retval != NULL)
1358                   {
1359                     retval = fgets (string, STRING_SIZE, source_file);
1360                     fputs (string, gcov_file);
1361                   }
1362
1363                 retval = fgets (string, STRING_SIZE, source_file);
1364               }
1365           }
1366
1367           fclose (source_file);
1368           fclose (gcov_file);
1369         }
1370
1371       free (line_counts);
1372       free (line_exists);
1373     }
1374 }