alias.c: Fix typos in comments.
[gcc.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 }