OSDN Git Service

* emit-rtl.c: Use VA_OPEN/VA_CLOSE/VA_FIXEDARG throughout.
[pf3gnuchains/gcc-fork.git] / gcc / gcov.c
1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2    source file.
3    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
4    1999, 2000, 2001 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 typedef HOST_WIDEST_INT gcov_type;
52 #include "gcov-io.h"
53
54 /* The .bb file format consists of several lists of 4-byte integers
55    which are the line numbers of each basic block in the file.  Each
56    list is terminated by a zero.  These lists correspond to the basic
57    blocks in the reconstructed program flow graph.
58
59    A line number of -1 indicates that a source file name (padded to a
60    long boundary) follows.  The padded file name is followed by
61    another -1 to make it easy to scan past file names.  A -2 indicates
62    that a function name (padded to a long boundary) follows; the name
63    is followed by another -2 to make it easy to scan past the function
64    name.
65
66    The .bbg file contains enough info to enable gcov to reconstruct the
67    program flow graph.  The first word is the number of basic blocks,
68    the second word is the number of arcs, followed by the list of arcs
69    (source bb, dest bb pairs), then a -1, then the number of instrumented
70    arcs followed by the instrumented arcs, followed by another -1.  This
71    is repeated for each function.
72
73    The .da file contains the execution count for each instrumented branch.
74
75    The .bb and .bbg files are created by giving GCC the -ftest-coverage option,
76    and the .da files are created when an executable compiled with
77    -fprofile-arcs is run.  */
78
79 /* The functions in this file for creating and solution program flow graphs
80    are very similar to functions in the gcc source file profile.c.  */
81
82 char gcov_version_string[] = "GNU gcov version 1.5\n";
83
84 /* This is the size of the buffer used to read in source file lines.  */
85
86 #define STRING_SIZE 200
87
88 /* One copy of this structure is created for each source file mentioned in the
89    .bb file.  */
90
91 struct sourcefile
92 {
93   char *name;
94   int maxlineno;
95   struct sourcefile *next;
96 };
97
98 /* This points to the head of the sourcefile structure list.  */
99
100 struct sourcefile *sources;
101
102 /* One of these is dynamically created whenever we identify an arc in the
103    function.  */
104
105 struct adj_list {
106   int source;
107   int target;
108   gcov_type arc_count;
109   unsigned int count_valid : 1;
110   unsigned int on_tree : 1;
111   unsigned int fake : 1;
112   unsigned int fall_through : 1;
113 #if 0
114   /* Not needed for gcov, but defined in profile.c.  */
115   rtx branch_insn;
116 #endif
117   struct adj_list *pred_next;
118   struct adj_list *succ_next;
119 };
120
121 /* Count the number of basic blocks, and create an array of these structures,
122    one for each bb in the function.  */
123
124 struct bb_info {
125   struct adj_list *succ;
126   struct adj_list *pred;
127   gcov_type succ_count;
128   gcov_type pred_count;
129   gcov_type exec_count;
130   unsigned int count_valid : 1;
131   unsigned int on_tree : 1;
132 #if 0
133   /* Not needed for gcov, but defined in profile.c.  */
134   rtx first_insn;
135 #endif
136 };
137
138 /* When outputting branch probabilities, one of these structures is created
139    for each branch/call.  */
140
141 struct arcdata
142 {
143   gcov_type hits;
144   gcov_type total;
145   int call_insn;
146   struct arcdata *next;
147 };
148
149 /* Used to save the list of bb_graphs, one per function.  */
150
151 struct bb_info_list {
152   /* Indexed by block number, holds the basic block graph for one function.  */
153   struct bb_info *bb_graph;
154   int num_blocks;
155   struct bb_info_list *next;
156 };
157
158 /* Holds a list of function basic block graphs.  */
159
160 static struct bb_info_list *bb_graph_list = 0;
161
162 /* Name and file pointer of the input file for the basic block graph.  */
163
164 static char *bbg_file_name;
165 static FILE *bbg_file;
166
167 /* Name and file pointer of the input file for the arc count data.  */
168
169 static char *da_file_name;
170 static FILE *da_file;
171
172 /* Name and file pointer of the input file for the basic block line counts.  */
173
174 static char *bb_file_name;
175 static FILE *bb_file;
176
177 /* Holds the entire contents of the bb_file read into memory.  */
178
179 static char *bb_data;
180
181 /* Size of bb_data array in longs.  */
182
183 static long bb_data_size;
184
185 /* Name and file pointer of the output file.  */
186
187 static char *gcov_file_name;
188 static FILE *gcov_file;
189
190 /* Name of the file mentioned on the command line.  */
191
192 static char *input_file_name = 0;
193
194 /* Output branch probabilities if true.  */
195
196 static int output_branch_probs = 0;
197
198 /* Output a gcov file if this is true.  This is on by default, and can
199    be turned off by the -n option.  */
200
201 static int output_gcov_file = 1;
202
203 /* For included files, make the gcov output file name include the name of
204    the input source file.  For example, if x.h is included in a.c, then the
205    output file name is a.c.x.h.gcov instead of x.h.gcov.  This works only
206    when a single source file is specified.  */
207
208 static int output_long_names = 0;
209
210 /* Output summary info for each function.  */
211
212 static int output_function_summary = 0;
213
214 /* Object directory file prefix.  This is the directory where .bb and .bbg
215    files are looked for, if non-zero.  */
216
217 static char *object_directory = 0;
218
219 /* Output the number of times a branch was taken as opposed to the percentage
220    of times it was taken.  Turned on by the -c option */
221
222 static int output_branch_counts = 0;
223
224 /* Forward declarations.  */
225 static void process_args PARAMS ((int, char **));
226 static void open_files PARAMS ((void));
227 static void read_files PARAMS ((void));
228 static void scan_for_source_files PARAMS ((void));
229 static void output_data PARAMS ((void));
230 static void print_usage PARAMS ((void)) ATTRIBUTE_NORETURN;
231 static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
232 static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
233 static void create_program_flow_graph PARAMS ((struct bb_info_list *));
234 static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
235 static void calculate_branch_probs PARAMS ((struct bb_info_list *, int,
236                                             struct arcdata **, int));
237 static void function_summary PARAMS ((void));
238
239 extern int main PARAMS ((int, char **));
240
241 int
242 main (argc, argv)
243      int argc;
244      char **argv;
245 {
246 /* LC_CTYPE determines the character set used by the terminal so it has be set
247    to output messages correctly.  */
248
249 #ifdef HAVE_LC_MESSAGES
250   setlocale (LC_CTYPE, "");
251   setlocale (LC_MESSAGES, "");
252 #else
253   setlocale (LC_ALL, "");
254 #endif
255
256   (void) bindtextdomain (PACKAGE, localedir);
257   (void) textdomain (PACKAGE);
258
259   process_args (argc, argv);
260
261   open_files ();
262
263   read_files ();
264
265   scan_for_source_files ();
266
267   output_data ();
268
269   return 0;
270 }
271
272 static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
273 static void
274 fnotice VPARAMS ((FILE *file, const char *msgid, ...))
275 {
276   VA_OPEN (ap, msgid);
277   VA_FIXEDARG (ap, FILE *, file);
278   VA_FIXEDARG (ap, const char *, msgid);
279
280   vfprintf (file, _(msgid), ap);
281   VA_CLOSE (ap);
282 }
283
284 /* More 'friendly' abort that prints the line and file.
285    config.h can #define abort fancy_abort if you like that sort of thing.  */
286 extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
287
288 void
289 fancy_abort ()
290 {
291   fnotice (stderr, "Internal gcov abort.\n");
292   exit (FATAL_EXIT_CODE);
293 }
294 \f
295 /* Print a usage message and exit.  */
296
297 static void
298 print_usage ()
299 {
300   fnotice (stderr, "gcov [-b] [-v] [-n] [-l] [-f] [-o OBJDIR] file\n");
301   exit (FATAL_EXIT_CODE);
302 }
303
304 /* Parse the command line.  */
305
306 static void
307 process_args (argc, argv)
308      int argc;
309      char **argv;
310 {
311   int i;
312
313   for (i = 1; i < argc; i++)
314     {
315       if (argv[i][0] == '-')
316         {
317           if (argv[i][1] == 'b')
318             output_branch_probs = 1;
319           else if (argv[i][1] == 'c')
320             output_branch_counts = 1;
321           else if (argv[i][1] == 'v')
322             fputs (gcov_version_string, stderr);
323           else if (argv[i][1] == 'n')
324             output_gcov_file = 0;
325           else if (argv[i][1] == 'l')
326             output_long_names = 1;
327           else if (argv[i][1] == 'f')
328             output_function_summary = 1;
329           else if (argv[i][1] == 'o' && argv[i][2] == '\0')
330             object_directory = argv[++i];
331           else
332             print_usage ();
333         }
334       else if (! input_file_name)
335         input_file_name = argv[i];
336       else
337         print_usage ();
338     }
339
340   if (! input_file_name)
341     print_usage ();
342 }
343
344
345 /* Find and open the .bb, .da, and .bbg files.  */
346
347 static void
348 open_files ()
349 {
350   int count, objdir_count;
351   char *cptr;
352
353   /* Determine the names of the .bb, .bbg, and .da files.  Strip off the
354      extension, if any, and append the new extensions.  */
355   count = strlen (input_file_name);
356   if (object_directory)
357     objdir_count = strlen (object_directory);
358   else
359     objdir_count = 0;
360
361   da_file_name = xmalloc (count + objdir_count + 4);
362   bb_file_name = xmalloc (count + objdir_count + 4);
363   bbg_file_name = xmalloc (count + objdir_count + 5);
364
365   if (object_directory)
366     {
367       strcpy (da_file_name, object_directory);
368       strcpy (bb_file_name, object_directory);
369       strcpy (bbg_file_name, object_directory);
370
371       if (object_directory[objdir_count - 1] != '/')
372         {
373           strcat (da_file_name, "/");
374           strcat (bb_file_name, "/");
375           strcat (bbg_file_name, "/");
376         }
377
378       cptr = strrchr (input_file_name, '/');
379       if (cptr)
380         {
381           strcat (da_file_name, cptr + 1);
382           strcat (bb_file_name, cptr + 1);
383           strcat (bbg_file_name, cptr + 1);
384         }
385       else
386         {
387           strcat (da_file_name, input_file_name);
388           strcat (bb_file_name, input_file_name);
389           strcat (bbg_file_name, input_file_name);
390         }
391     }
392   else
393     {
394       strcpy (da_file_name, input_file_name);
395       strcpy (bb_file_name, input_file_name);
396       strcpy (bbg_file_name, input_file_name);
397     }
398
399   cptr = strrchr (bb_file_name, '.');
400   if (cptr)
401     strcpy (cptr, ".bb");
402   else
403     strcat (bb_file_name, ".bb");
404
405   cptr = strrchr (da_file_name, '.');
406   if (cptr)
407     strcpy (cptr, ".da");
408   else
409     strcat (da_file_name, ".da");
410
411   cptr = strrchr (bbg_file_name, '.');
412   if (cptr)
413     strcpy (cptr, ".bbg");
414   else
415     strcat (bbg_file_name, ".bbg");
416
417   bb_file = fopen (bb_file_name, "rb");
418   if (bb_file == NULL)
419     {
420       fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
421       exit (FATAL_EXIT_CODE);
422     }
423
424   /* If none of the functions in the file were executed, then there won't
425      be a .da file.  Just assume that all counts are zero in this case.  */
426   da_file = fopen (da_file_name, "rb");
427   if (da_file == NULL)
428     {
429       fnotice (stderr, "Could not open data file %s.\n", da_file_name);
430       fnotice (stderr, "Assuming that all execution counts are zero.\n");
431     }
432
433   bbg_file = fopen (bbg_file_name, "rb");
434   if (bbg_file == NULL)
435     {
436       fnotice (stderr, "Could not open program flow graph file %s.\n",
437                bbg_file_name);
438       exit (FATAL_EXIT_CODE);
439     }
440
441   /* Check for empty .bbg file.  This indicates that there is no executable
442      code in this source file.  */
443   /* Set the EOF condition if at the end of file.  */
444   ungetc (getc (bbg_file), bbg_file);
445   if (feof (bbg_file))
446     {
447       fnotice (stderr, "No executable code associated with file %s.\n",
448                input_file_name);
449       exit (FATAL_EXIT_CODE);
450     }
451 }
452 \f
453 /* Initialize a new arc.  */
454
455 static void
456 init_arc (arcptr, source, target, bb_graph)
457      struct adj_list *arcptr;
458      int source, target;
459      struct bb_info *bb_graph;
460 {
461   arcptr->target = target;
462   arcptr->source = source;
463
464   arcptr->arc_count = 0;
465   arcptr->count_valid = 0;
466   arcptr->on_tree = 0;
467   arcptr->fake = 0;
468   arcptr->fall_through = 0;
469
470   arcptr->succ_next = bb_graph[source].succ;
471   bb_graph[source].succ = arcptr;
472   bb_graph[source].succ_count++;
473
474   arcptr->pred_next = bb_graph[target].pred;
475   bb_graph[target].pred = arcptr;
476   bb_graph[target].pred_count++;
477 }
478
479
480 /* Reverse the arcs on a arc list.  */
481
482 static struct adj_list *
483 reverse_arcs (arcptr)
484      struct adj_list *arcptr;
485 {
486   struct adj_list *prev = 0;
487   struct adj_list *next;
488
489   for ( ; arcptr; arcptr = next)
490     {
491       next = arcptr->succ_next;
492       arcptr->succ_next = prev;
493       prev = arcptr;
494     }
495
496   return prev;
497 }
498
499
500 /* Construct the program flow graph from the .bbg file, and read in the data
501    in the .da file.  */
502
503 static void
504 create_program_flow_graph (bptr)
505      struct bb_info_list *bptr;
506 {
507   long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
508   int i;
509   struct adj_list *arcptr;
510   struct bb_info *bb_graph;
511
512   /* Read the number of blocks.  */
513   __read_long (&num_blocks, bbg_file, 4);
514
515   /* Create an array of size bb number of bb_info structs.  */
516   bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
517
518   bptr->bb_graph = bb_graph;
519   bptr->num_blocks = num_blocks;
520
521   /* Read and create each arc from the .bbg file.  */
522   __read_long (&number_arcs, bbg_file, 4);
523   for (i = 0; i < num_blocks; i++)
524     {
525       int j;
526
527       __read_long (&num_arcs_per_block, bbg_file, 4);
528       for (j = 0; j < num_arcs_per_block; j++)
529         {
530           if (number_arcs-- < 0)
531             abort ();
532
533           src = i;
534           __read_long (&dest, bbg_file, 4);
535
536           arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
537           init_arc (arcptr, src, dest, bb_graph);
538
539           __read_long (&flag_bits, bbg_file, 4);
540           arcptr->on_tree = flag_bits & 0x1;
541           arcptr->fake = !! (flag_bits & 0x2);
542           arcptr->fall_through = !! (flag_bits & 0x4);
543         }
544     }
545
546   if (number_arcs)
547     abort ();
548
549   /* Read and ignore the -1 separating the arc list from the arc list of the
550      next function.  */
551   __read_long (&src, bbg_file, 4);
552   if (src != -1)
553     abort ();
554
555   /* Must reverse the order of all succ arcs, to ensure that they match
556      the order of the data in the .da file.  */
557
558   for (i = 0; i < num_blocks; i++)
559     if (bb_graph[i].succ)
560       bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
561
562   /* For each arc not on the spanning tree, set its execution count from
563      the .da file.  */
564
565   /* The first count in the .da file is the number of times that the function
566      was entered.  This is the exec_count for block zero.  */
567
568   /* This duplicates code in branch_prob in profile.c.  */
569
570   for (i = 0; i < num_blocks; i++)
571     for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
572       if (! arcptr->on_tree)
573         {
574           gcov_type tmp_count = 0;
575           if (da_file && __read_gcov_type (&tmp_count, da_file, 8))
576             abort();
577
578           arcptr->arc_count = tmp_count;
579           arcptr->count_valid = 1;
580           bb_graph[i].succ_count--;
581           bb_graph[arcptr->target].pred_count--;
582         }
583 }
584
585 static void
586 solve_program_flow_graph (bptr)
587      struct bb_info_list *bptr;
588 {
589   int passes, changes;
590   gcov_type 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   long 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   gcov_type 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   gcov_type *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   long 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 = (gcov_type *) xcalloc (sizeof (gcov_type), 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 = strrchr (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 = strrchr (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 = strrchr (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 = strrchr (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                     {
1321                       char c[20];
1322                       sprintf (c, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)line_counts[count]);
1323                       fprintf (gcov_file, "%12s    %s", c,
1324                                string);
1325                     }
1326                   else
1327                     fprintf (gcov_file, "      ######    %s", string);
1328                 }
1329               else
1330                 fprintf (gcov_file, "\t\t%s", string);
1331
1332               /* In case the source file line is larger than our buffer, keep
1333                  reading and outputting lines until we get a newline.  */
1334               len = strlen (string);
1335               while ((len == 0 || string[strlen (string) - 1] != '\n')
1336                      && retval != NULL)
1337                 {
1338                   retval = fgets (string, STRING_SIZE, source_file);
1339                   fputs (string, gcov_file);
1340                 }
1341
1342               if (output_branch_probs)
1343                 {
1344                   for (i = 0, a_ptr = branch_probs[count]; a_ptr;
1345                        a_ptr = a_ptr->next, i++)
1346                     {
1347                       if (a_ptr->call_insn)
1348                         {
1349                           if (a_ptr->total == 0)
1350                             fnotice (gcov_file, "call %d never executed\n", i);
1351                             else
1352                               {
1353                                 if (output_branch_counts)
1354                                   {
1355                                     char c[20];
1356                                     sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
1357                                              a_ptr->total - a_ptr->hits);
1358                                     fnotice (gcov_file,
1359                                              "call %d returns = %s\n", i, c);
1360                                   }
1361                                 else
1362                                   {
1363                                     char c[20];
1364                                     sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
1365                                              100 - ((a_ptr->hits * 100)
1366                                                     + (a_ptr->total >> 1))
1367                                              / a_ptr->total);
1368                                     fnotice (gcov_file,
1369                                              "call %d returns = %s%%\n", i, c);
1370                                   }
1371                               }
1372                         }
1373                       else
1374                         {
1375                           if (a_ptr->total == 0)
1376                             fnotice (gcov_file, "branch %d never executed\n",
1377                                      i);
1378                           else
1379                             {
1380                               if (output_branch_counts)
1381                                 {
1382                                   char c[20];
1383                                   sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
1384                                            a_ptr->hits);
1385                                   fnotice (gcov_file,
1386                                            "branch %d taken = %s\n", i, c);
1387                                 }
1388                               else
1389                                 {
1390                                   char c[20];
1391                                   sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
1392                                            ((a_ptr->hits * 100)
1393                                             + (a_ptr->total >> 1))
1394                                            / a_ptr->total);
1395                                 fnotice (gcov_file,
1396                                          "branch %d taken = %s%%\n", i, c);
1397                                 }
1398                             }
1399                         }
1400                    }
1401               }
1402
1403               /* Gracefully handle errors while reading the source file.  */
1404               if (retval == NULL)
1405                 {
1406                   fnotice (stderr,
1407                            "Unexpected EOF while reading source file %s.\n",
1408                            source_file_name);
1409                   break;
1410                 }
1411             }
1412
1413           /* Handle all remaining source lines.  There may be lines
1414              after the last line of code.  */
1415
1416           {
1417             char *retval = fgets (string, STRING_SIZE, source_file);
1418             while (retval != NULL)
1419               {
1420                 int len;
1421
1422                 fprintf (gcov_file, "\t\t%s", string);
1423
1424                 /* In case the source file line is larger than our buffer, keep
1425                    reading and outputting lines until we get a newline.  */
1426                 len = strlen (string);
1427                 while ((len == 0 || string[strlen (string) - 1] != '\n')
1428                        && retval != NULL)
1429                   {
1430                     retval = fgets (string, STRING_SIZE, source_file);
1431                     fputs (string, gcov_file);
1432                   }
1433
1434                 retval = fgets (string, STRING_SIZE, source_file);
1435               }
1436           }
1437
1438           fclose (source_file);
1439           fclose (gcov_file);
1440         }
1441
1442       free (line_counts);
1443       free (line_exists);
1444     }
1445 }