OSDN Git Service

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