OSDN Git Service

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