OSDN Git Service

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