* java/lang/natString.cc (rehash): Don't bother with memset;
[official-gcc.git] / gcc / gcov.c
blob457c4adec97621409289718ae13a7cf73ef68ef3
1 /* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file.
3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
4 1999, 2000 Free Software Foundation, Inc.
5 Contributed by James E. Wilson of Cygnus Support.
6 Mangled by Bob Manson of Cygnus Support.
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.
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.
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. */
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. */
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. */
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. */
36 /* ??? Should have an option to print the number of basic blocks, and the
37 percent of them that are covered. */
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. */
46 #include "config.h"
47 #include "system.h"
48 #include "intl.h"
49 #undef abort
51 #include "gcov-io.h"
53 /* The .bb file format consists of several lists of 4-byte integers
54 which are the line numbers of each basic block in the file. Each
55 list is terminated by a zero. These lists correspond to the basic
56 blocks in the reconstructed program flow graph.
58 A line number of -1 indicates that a source file name (padded to a
59 long boundary) follows. The padded file name is followed by
60 another -1 to make it easy to scan past file names. A -2 indicates
61 that a function name (padded to a long boundary) follows; the name
62 is followed by another -2 to make it easy to scan past the function
63 name.
65 The .bbg file contains enough info to enable gcov to reconstruct the
66 program flow graph. The first word is the number of basic blocks,
67 the second word is the number of arcs, followed by the list of arcs
68 (source bb, dest bb pairs), then a -1, then the number of instrumented
69 arcs followed by the instrumented arcs, followed by another -1. This
70 is repeated for each function.
72 The .da file contains the execution count for each instrumented branch.
74 The .bb and .bbg files are created by giving GCC the -ftest-coverage option,
75 and the .da files are created when an executable compiled with
76 -fprofile-arcs is run. */
78 /* The functions in this file for creating and solution program flow graphs
79 are very similar to functions in the gcc source file profile.c. */
81 char gcov_version_string[] = "GNU gcov version 1.5\n";
83 /* This is the size of the buffer used to read in source file lines. */
85 #define STRING_SIZE 200
87 /* One copy of this structure is created for each source file mentioned in the
88 .bb file. */
90 struct sourcefile
92 char *name;
93 int maxlineno;
94 struct sourcefile *next;
97 /* This points to the head of the sourcefile structure list. */
99 struct sourcefile *sources;
101 /* One of these is dynamically created whenever we identify an arc in the
102 function. */
104 struct adj_list {
105 int source;
106 int target;
107 int arc_count;
108 unsigned int count_valid : 1;
109 unsigned int on_tree : 1;
110 unsigned int fake : 1;
111 unsigned int fall_through : 1;
112 #if 0
113 /* Not needed for gcov, but defined in profile.c. */
114 rtx branch_insn;
115 #endif
116 struct adj_list *pred_next;
117 struct adj_list *succ_next;
120 /* Count the number of basic blocks, and create an array of these structures,
121 one for each bb in the function. */
123 struct bb_info {
124 struct adj_list *succ;
125 struct adj_list *pred;
126 int succ_count;
127 int pred_count;
128 int exec_count;
129 unsigned int count_valid : 1;
130 unsigned int on_tree : 1;
131 #if 0
132 /* Not needed for gcov, but defined in profile.c. */
133 rtx first_insn;
134 #endif
137 /* When outputting branch probabilities, one of these structures is created
138 for each branch/call. */
140 struct arcdata
142 int hits;
143 int total;
144 int call_insn;
145 struct arcdata *next;
148 /* Used to save the list of bb_graphs, one per function. */
150 struct bb_info_list {
151 /* Indexed by block number, holds the basic block graph for one function. */
152 struct bb_info *bb_graph;
153 int num_blocks;
154 struct bb_info_list *next;
157 /* Holds a list of function basic block graphs. */
159 static struct bb_info_list *bb_graph_list = 0;
161 /* Name and file pointer of the input file for the basic block graph. */
163 static char *bbg_file_name;
164 static FILE *bbg_file;
166 /* Name and file pointer of the input file for the arc count data. */
168 static char *da_file_name;
169 static FILE *da_file;
171 /* Name and file pointer of the input file for the basic block line counts. */
173 static char *bb_file_name;
174 static FILE *bb_file;
176 /* Holds the entire contents of the bb_file read into memory. */
178 static char *bb_data;
180 /* Size of bb_data array in longs. */
182 static long bb_data_size;
184 /* Name and file pointer of the output file. */
186 static char *gcov_file_name;
187 static FILE *gcov_file;
189 /* Name of the file mentioned on the command line. */
191 static char *input_file_name = 0;
193 /* Output branch probabilities if true. */
195 static int output_branch_probs = 0;
197 /* Output a gcov file if this is true. This is on by default, and can
198 be turned off by the -n option. */
200 static int output_gcov_file = 1;
202 /* For included files, make the gcov output file name include the name of
203 the input source file. For example, if x.h is included in a.c, then the
204 output file name is a.c.x.h.gcov instead of x.h.gcov. This works only
205 when a single source file is specified. */
207 static int output_long_names = 0;
209 /* Output summary info for each function. */
211 static int output_function_summary = 0;
213 /* Object directory file prefix. This is the directory where .bb and .bbg
214 files are looked for, if non-zero. */
216 static char *object_directory = 0;
218 /* Output the number of times a branch was taken as opposed to the percentage
219 of times it was taken. Turned on by the -c option */
221 static int output_branch_counts = 0;
223 /* Forward declarations. */
224 static void process_args PARAMS ((int, char **));
225 static void open_files PARAMS ((void));
226 static void read_files PARAMS ((void));
227 static void scan_for_source_files PARAMS ((void));
228 static void output_data PARAMS ((void));
229 static void print_usage PARAMS ((void)) ATTRIBUTE_NORETURN;
230 static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
231 static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
232 static void create_program_flow_graph PARAMS ((struct bb_info_list *));
233 static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
234 static void calculate_branch_probs PARAMS ((struct bb_info_list *, int,
235 struct arcdata **, int));
236 static void function_summary PARAMS ((void));
238 extern int main PARAMS ((int, char **));
241 main (argc, argv)
242 int argc;
243 char **argv;
245 /* LC_CTYPE determines the character set used by the terminal so it has be set
246 to output messages correctly. */
248 #ifdef HAVE_LC_MESSAGES
249 setlocale (LC_CTYPE, "");
250 setlocale (LC_MESSAGES, "");
251 #else
252 setlocale (LC_ALL, "");
253 #endif
255 (void) bindtextdomain (PACKAGE, localedir);
256 (void) textdomain (PACKAGE);
258 process_args (argc, argv);
260 open_files ();
262 read_files ();
264 scan_for_source_files ();
266 output_data ();
268 return 0;
271 static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
272 static void
273 fnotice VPARAMS ((FILE *file, const char *msgid, ...))
275 #ifndef ANSI_PROTOTYPES
276 FILE *file;
277 const char *msgid;
278 #endif
279 va_list ap;
281 VA_START (ap, msgid);
283 #ifndef ANSI_PROTOTYPES
284 file = va_arg (ap, FILE *);
285 msgid = va_arg (ap, const char *);
286 #endif
288 vfprintf (file, _(msgid), ap);
289 va_end (ap);
292 /* More 'friendly' abort that prints the line and file.
293 config.h can #define abort fancy_abort if you like that sort of thing. */
294 extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
296 void
297 fancy_abort ()
299 fnotice (stderr, "Internal gcov abort.\n");
300 exit (FATAL_EXIT_CODE);
303 /* Print a usage message and exit. */
305 static void
306 print_usage ()
308 fnotice (stderr, "gcov [-b] [-v] [-n] [-l] [-f] [-o OBJDIR] file\n");
309 exit (FATAL_EXIT_CODE);
312 /* Parse the command line. */
314 static void
315 process_args (argc, argv)
316 int argc;
317 char **argv;
319 int i;
321 for (i = 1; i < argc; i++)
323 if (argv[i][0] == '-')
325 if (argv[i][1] == 'b')
326 output_branch_probs = 1;
327 else if (argv[i][1] == 'c')
328 output_branch_counts = 1;
329 else if (argv[i][1] == 'v')
330 fputs (gcov_version_string, stderr);
331 else if (argv[i][1] == 'n')
332 output_gcov_file = 0;
333 else if (argv[i][1] == 'l')
334 output_long_names = 1;
335 else if (argv[i][1] == 'f')
336 output_function_summary = 1;
337 else if (argv[i][1] == 'o' && argv[i][2] == '\0')
338 object_directory = argv[++i];
339 else
340 print_usage ();
342 else if (! input_file_name)
343 input_file_name = argv[i];
344 else
345 print_usage ();
348 if (! input_file_name)
349 print_usage ();
353 /* Find and open the .bb, .da, and .bbg files. */
355 static void
356 open_files ()
358 int count, objdir_count;
359 char *cptr;
361 /* Determine the names of the .bb, .bbg, and .da files. Strip off the
362 extension, if any, and append the new extensions. */
363 count = strlen (input_file_name);
364 if (object_directory)
365 objdir_count = strlen (object_directory);
366 else
367 objdir_count = 0;
369 da_file_name = xmalloc (count + objdir_count + 4);
370 bb_file_name = xmalloc (count + objdir_count + 4);
371 bbg_file_name = xmalloc (count + objdir_count + 5);
373 if (object_directory)
375 strcpy (da_file_name, object_directory);
376 strcpy (bb_file_name, object_directory);
377 strcpy (bbg_file_name, object_directory);
379 if (object_directory[objdir_count - 1] != '/')
381 strcat (da_file_name, "/");
382 strcat (bb_file_name, "/");
383 strcat (bbg_file_name, "/");
386 cptr = strrchr (input_file_name, '/');
387 if (cptr)
389 strcat (da_file_name, cptr + 1);
390 strcat (bb_file_name, cptr + 1);
391 strcat (bbg_file_name, cptr + 1);
393 else
395 strcat (da_file_name, input_file_name);
396 strcat (bb_file_name, input_file_name);
397 strcat (bbg_file_name, input_file_name);
400 else
402 strcpy (da_file_name, input_file_name);
403 strcpy (bb_file_name, input_file_name);
404 strcpy (bbg_file_name, input_file_name);
407 cptr = strrchr (bb_file_name, '.');
408 if (cptr)
409 strcpy (cptr, ".bb");
410 else
411 strcat (bb_file_name, ".bb");
413 cptr = strrchr (da_file_name, '.');
414 if (cptr)
415 strcpy (cptr, ".da");
416 else
417 strcat (da_file_name, ".da");
419 cptr = strrchr (bbg_file_name, '.');
420 if (cptr)
421 strcpy (cptr, ".bbg");
422 else
423 strcat (bbg_file_name, ".bbg");
425 bb_file = fopen (bb_file_name, "rb");
426 if (bb_file == NULL)
428 fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
429 exit (FATAL_EXIT_CODE);
432 /* If none of the functions in the file were executed, then there won't
433 be a .da file. Just assume that all counts are zero in this case. */
434 da_file = fopen (da_file_name, "rb");
435 if (da_file == NULL)
437 fnotice (stderr, "Could not open data file %s.\n", da_file_name);
438 fnotice (stderr, "Assuming that all execution counts are zero.\n");
441 bbg_file = fopen (bbg_file_name, "rb");
442 if (bbg_file == NULL)
444 fnotice (stderr, "Could not open program flow graph file %s.\n",
445 bbg_file_name);
446 exit (FATAL_EXIT_CODE);
449 /* Check for empty .bbg file. This indicates that there is no executable
450 code in this source file. */
451 /* Set the EOF condition if at the end of file. */
452 ungetc (getc (bbg_file), bbg_file);
453 if (feof (bbg_file))
455 fnotice (stderr, "No executable code associated with file %s.\n",
456 input_file_name);
457 exit (FATAL_EXIT_CODE);
461 /* Initialize a new arc. */
463 static void
464 init_arc (arcptr, source, target, bb_graph)
465 struct adj_list *arcptr;
466 int source, target;
467 struct bb_info *bb_graph;
469 arcptr->target = target;
470 arcptr->source = source;
472 arcptr->arc_count = 0;
473 arcptr->count_valid = 0;
474 arcptr->on_tree = 0;
475 arcptr->fake = 0;
476 arcptr->fall_through = 0;
478 arcptr->succ_next = bb_graph[source].succ;
479 bb_graph[source].succ = arcptr;
480 bb_graph[source].succ_count++;
482 arcptr->pred_next = bb_graph[target].pred;
483 bb_graph[target].pred = arcptr;
484 bb_graph[target].pred_count++;
488 /* Reverse the arcs on a arc list. */
490 static struct adj_list *
491 reverse_arcs (arcptr)
492 struct adj_list *arcptr;
494 struct adj_list *prev = 0;
495 struct adj_list *next;
497 for ( ; arcptr; arcptr = next)
499 next = arcptr->succ_next;
500 arcptr->succ_next = prev;
501 prev = arcptr;
504 return prev;
508 /* Construct the program flow graph from the .bbg file, and read in the data
509 in the .da file. */
511 static void
512 create_program_flow_graph (bptr)
513 struct bb_info_list *bptr;
515 long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
516 int i;
517 struct adj_list *arcptr;
518 struct bb_info *bb_graph;
520 /* Read the number of blocks. */
521 __read_long (&num_blocks, bbg_file, 4);
523 /* Create an array of size bb number of bb_info structs. */
524 bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
526 bptr->bb_graph = bb_graph;
527 bptr->num_blocks = num_blocks;
529 /* Read and create each arc from the .bbg file. */
530 __read_long (&number_arcs, bbg_file, 4);
531 for (i = 0; i < num_blocks; i++)
533 int j;
535 __read_long (&num_arcs_per_block, bbg_file, 4);
536 for (j = 0; j < num_arcs_per_block; j++)
538 if (number_arcs-- < 0)
539 abort ();
541 src = i;
542 __read_long (&dest, bbg_file, 4);
544 arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
545 init_arc (arcptr, src, dest, bb_graph);
547 __read_long (&flag_bits, bbg_file, 4);
548 arcptr->on_tree = flag_bits & 0x1;
549 arcptr->fake = !! (flag_bits & 0x2);
550 arcptr->fall_through = !! (flag_bits & 0x4);
554 if (number_arcs)
555 abort ();
557 /* Read and ignore the -1 separating the arc list from the arc list of the
558 next function. */
559 __read_long (&src, bbg_file, 4);
560 if (src != -1)
561 abort ();
563 /* Must reverse the order of all succ arcs, to ensure that they match
564 the order of the data in the .da file. */
566 for (i = 0; i < num_blocks; i++)
567 if (bb_graph[i].succ)
568 bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
570 /* For each arc not on the spanning tree, set its execution count from
571 the .da file. */
573 /* The first count in the .da file is the number of times that the function
574 was entered. This is the exec_count for block zero. */
576 /* This duplicates code in branch_prob in profile.c. */
578 for (i = 0; i < num_blocks; i++)
579 for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
580 if (! arcptr->on_tree)
582 long tmp_count = 0;
583 if (da_file && __read_long (&tmp_count, da_file, 8))
584 abort();
586 arcptr->arc_count = tmp_count;
587 arcptr->count_valid = 1;
588 bb_graph[i].succ_count--;
589 bb_graph[arcptr->target].pred_count--;
593 static void
594 solve_program_flow_graph (bptr)
595 struct bb_info_list *bptr;
597 int passes, changes, total;
598 int i;
599 struct adj_list *arcptr;
600 struct bb_info *bb_graph;
601 int num_blocks;
603 num_blocks = bptr->num_blocks;
604 bb_graph = bptr->bb_graph;
606 /* For every block in the file,
607 - if every exit/entrance arc has a known count, then set the block count
608 - if the block count is known, and every exit/entrance arc but one has
609 a known execution count, then set the count of the remaining arc
611 As arc counts are set, decrement the succ/pred count, but don't delete
612 the arc, that way we can easily tell when all arcs are known, or only
613 one arc is unknown. */
615 /* The order that the basic blocks are iterated through is important.
616 Since the code that finds spanning trees starts with block 0, low numbered
617 arcs are put on the spanning tree in preference to high numbered arcs.
618 Hence, most instrumented arcs are at the end. Graph solving works much
619 faster if we propagate numbers from the end to the start.
621 This takes an average of slightly more than 3 passes. */
623 changes = 1;
624 passes = 0;
625 while (changes)
627 passes++;
628 changes = 0;
630 for (i = num_blocks - 1; i >= 0; i--)
632 if (! bb_graph[i].count_valid)
634 if (bb_graph[i].succ_count == 0)
636 total = 0;
637 for (arcptr = bb_graph[i].succ; arcptr;
638 arcptr = arcptr->succ_next)
639 total += arcptr->arc_count;
640 bb_graph[i].exec_count = total;
641 bb_graph[i].count_valid = 1;
642 changes = 1;
644 else if (bb_graph[i].pred_count == 0)
646 total = 0;
647 for (arcptr = bb_graph[i].pred; arcptr;
648 arcptr = arcptr->pred_next)
649 total += arcptr->arc_count;
650 bb_graph[i].exec_count = total;
651 bb_graph[i].count_valid = 1;
652 changes = 1;
655 if (bb_graph[i].count_valid)
657 if (bb_graph[i].succ_count == 1)
659 total = 0;
660 /* One of the counts will be invalid, but it is zero,
661 so adding it in also doesn't hurt. */
662 for (arcptr = bb_graph[i].succ; arcptr;
663 arcptr = arcptr->succ_next)
664 total += arcptr->arc_count;
665 /* Calculate count for remaining arc by conservation. */
666 total = bb_graph[i].exec_count - total;
667 /* Search for the invalid arc, and set its count. */
668 for (arcptr = bb_graph[i].succ; arcptr;
669 arcptr = arcptr->succ_next)
670 if (! arcptr->count_valid)
671 break;
672 if (! arcptr)
673 abort ();
674 arcptr->count_valid = 1;
675 arcptr->arc_count = total;
676 bb_graph[i].succ_count--;
678 bb_graph[arcptr->target].pred_count--;
679 changes = 1;
681 if (bb_graph[i].pred_count == 1)
683 total = 0;
684 /* One of the counts will be invalid, but it is zero,
685 so adding it in also doesn't hurt. */
686 for (arcptr = bb_graph[i].pred; arcptr;
687 arcptr = arcptr->pred_next)
688 total += arcptr->arc_count;
689 /* Calculate count for remaining arc by conservation. */
690 total = bb_graph[i].exec_count - total;
691 /* Search for the invalid arc, and set its count. */
692 for (arcptr = bb_graph[i].pred; arcptr;
693 arcptr = arcptr->pred_next)
694 if (! arcptr->count_valid)
695 break;
696 if (! arcptr)
697 abort ();
698 arcptr->count_valid = 1;
699 arcptr->arc_count = total;
700 bb_graph[i].pred_count--;
702 bb_graph[arcptr->source].succ_count--;
703 changes = 1;
709 /* If the graph has been correctly solved, every block will have a
710 succ and pred count of zero. */
711 for (i = 0; i < num_blocks; i++)
712 if (bb_graph[i].succ_count || bb_graph[i].pred_count)
713 abort ();
717 static void
718 read_files ()
720 struct stat buf;
721 struct bb_info_list *list_end = 0;
722 struct bb_info_list *b_ptr;
723 long total;
725 /* Read and ignore the first word of the .da file, which is the count of
726 how many numbers follow. */
727 if (da_file && __read_long (&total, da_file, 8))
728 abort();
730 while (! feof (bbg_file))
732 b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
734 b_ptr->next = 0;
735 if (list_end)
736 list_end->next = b_ptr;
737 else
738 bb_graph_list = b_ptr;
739 list_end = b_ptr;
741 /* Read in the data in the .bbg file and reconstruct the program flow
742 graph for one function. */
743 create_program_flow_graph (b_ptr);
745 /* Set the EOF condition if at the end of file. */
746 ungetc (getc (bbg_file), bbg_file);
749 /* Check to make sure the .da file data is valid. */
751 if (da_file)
753 if (feof (da_file))
754 fnotice (stderr, ".da file contents exhausted too early\n");
755 /* Should be at end of file now. */
756 if (__read_long (&total, da_file, 8) == 0)
757 fnotice (stderr, ".da file contents not exhausted\n");
760 /* Calculate all of the basic block execution counts and branch
761 taken probabilities. */
763 for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
764 solve_program_flow_graph (b_ptr);
766 /* Read in all of the data from the .bb file. This info will be accessed
767 sequentially twice. */
768 stat (bb_file_name, &buf);
769 bb_data_size = buf.st_size / 4;
771 bb_data = (char *) xmalloc ((unsigned) buf.st_size);
772 fread (bb_data, sizeof (char), buf.st_size, bb_file);
774 fclose (bb_file);
775 if (da_file)
776 fclose (da_file);
777 fclose (bbg_file);
781 /* Scan the data in the .bb file to find all source files referenced,
782 and the largest line number mentioned in each one. */
784 static void
785 scan_for_source_files ()
787 struct sourcefile *s_ptr = NULL;
788 char *ptr;
789 int count;
790 long line_num;
792 /* Search the bb_data to find:
793 1) The number of sources files contained herein, and
794 2) The largest line number for each source file. */
796 ptr = bb_data;
797 sources = 0;
798 for (count = 0; count < bb_data_size; count++)
800 __fetch_long (&line_num, ptr, 4);
801 ptr += 4;
802 if (line_num == -1)
804 /* A source file name follows. Check to see if we already have
805 a sourcefile structure for this file. */
806 s_ptr = sources;
807 while (s_ptr && strcmp (s_ptr->name, ptr))
808 s_ptr = s_ptr->next;
810 if (s_ptr == 0)
812 /* No sourcefile structure for this file name exists, create
813 a new one, and append it to the front of the sources list. */
814 s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
815 s_ptr->name = xstrdup (ptr);
816 s_ptr->maxlineno = 0;
817 s_ptr->next = sources;
818 sources = s_ptr;
821 /* Scan past the file name. */
823 long delim;
824 do {
825 count++;
826 __fetch_long (&delim, ptr, 4);
827 ptr += 4;
828 } while (delim != line_num);
831 else if (line_num == -2)
833 long delim;
835 /* A function name follows. Ignore it. */
836 do {
837 count++;
838 __fetch_long (&delim, ptr, 4);
839 ptr += 4;
840 } while (delim != line_num);
842 /* There will be a zero before the first file name, in which case s_ptr
843 will still be uninitialized. So, only try to set the maxlineno
844 field if line_num is non-zero. */
845 else if (line_num > 0)
847 if (s_ptr->maxlineno <= line_num)
848 s_ptr->maxlineno = line_num + 1;
850 else if (line_num < 0)
852 /* Don't know what this is, but it's garbage. */
853 abort();
858 /* For calculating coverage at the function level. */
860 static int function_source_lines;
861 static int function_source_lines_executed;
862 static int function_branches;
863 static int function_branches_executed;
864 static int function_branches_taken;
865 static int function_calls;
866 static int function_calls_executed;
867 static char *function_name;
869 /* Calculate the branch taken probabilities for all arcs branches at the
870 end of this block. */
872 static void
873 calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num)
874 struct bb_info_list *current_graph;
875 int block_num;
876 struct arcdata **branch_probs;
877 int last_line_num;
879 int total;
880 struct adj_list *arcptr;
881 struct arcdata *end_ptr, *a_ptr;
883 total = current_graph->bb_graph[block_num].exec_count;
884 for (arcptr = current_graph->bb_graph[block_num].succ; arcptr;
885 arcptr = arcptr->succ_next)
887 /* Ignore fall through arcs as they aren't really branches. */
889 if (arcptr->fall_through)
890 continue;
892 a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
893 a_ptr->total = total;
894 if (total == 0)
895 a_ptr->hits = 0;
896 else
897 a_ptr->hits = arcptr->arc_count;
898 a_ptr->call_insn = arcptr->fake;
900 if (output_function_summary)
902 if (a_ptr->call_insn)
904 function_calls++;
905 if (a_ptr->total != 0)
906 function_calls_executed++;
908 else
910 function_branches++;
911 if (a_ptr->total != 0)
912 function_branches_executed++;
913 if (a_ptr->hits > 0)
914 function_branches_taken++;
918 /* Append the new branch to the end of the list. */
919 a_ptr->next = 0;
920 if (! branch_probs[last_line_num])
921 branch_probs[last_line_num] = a_ptr;
922 else
924 end_ptr = branch_probs[last_line_num];
925 while (end_ptr->next != 0)
926 end_ptr = end_ptr->next;
927 end_ptr->next = a_ptr;
932 /* Output summary info for a function. */
934 static void
935 function_summary ()
937 if (function_source_lines)
938 fnotice (stdout, "%6.2f%% of %d source lines executed in function %s\n",
939 (((double) function_source_lines_executed / function_source_lines)
940 * 100), function_source_lines, function_name);
941 else
942 fnotice (stdout, "No executable source lines in function %s\n",
943 function_name);
945 if (output_branch_probs)
947 if (function_branches)
949 fnotice (stdout, "%6.2f%% of %d branches executed in function %s\n",
950 (((double) function_branches_executed / function_branches)
951 * 100), function_branches, function_name);
952 fnotice (stdout,
953 "%6.2f%% of %d branches taken at least once in function %s\n",
954 (((double) function_branches_taken / function_branches)
955 * 100), function_branches, function_name);
957 else
958 fnotice (stdout, "No branches in function %s\n", function_name);
959 if (function_calls)
960 fnotice (stdout, "%6.2f%% of %d calls executed in function %s\n",
961 (((double) function_calls_executed / function_calls)
962 * 100), function_calls, function_name);
963 else
964 fnotice (stdout, "No calls in function %s\n", function_name);
968 /* Calculate line execution counts, and output the data to a .tcov file. */
970 static void
971 output_data ()
973 /* When scanning data, this is true only if the data applies to the
974 current source file. */
975 int this_file;
976 /* An array indexed by line number which indicates how many times that line
977 was executed. */
978 long *line_counts;
979 /* An array indexed by line number which indicates whether the line was
980 present in the bb file (i.e. whether it had code associate with it).
981 Lines never executed are those which both exist, and have zero execution
982 counts. */
983 char *line_exists;
984 /* An array indexed by line number, which contains a list of branch
985 probabilities, one for each branch on that line. */
986 struct arcdata **branch_probs = NULL;
987 struct sourcefile *s_ptr;
988 char *source_file_name;
989 FILE *source_file;
990 struct bb_info_list *current_graph;
991 int count;
992 char *cptr;
993 long block_num;
994 long line_num;
995 long last_line_num = 0;
996 int i;
997 struct arcdata *a_ptr;
998 /* Buffer used for reading in lines from the source file. */
999 char string[STRING_SIZE];
1000 /* For calculating coverage at the file level. */
1001 int total_source_lines;
1002 int total_source_lines_executed;
1003 int total_branches;
1004 int total_branches_executed;
1005 int total_branches_taken;
1006 int total_calls;
1007 int total_calls_executed;
1009 /* Now, for each source file, allocate an array big enough to hold a count
1010 for each line. Scan through the bb_data, and when the file name matches
1011 the current file name, then for each following line number, increment
1012 the line number execution count indicated by the execution count of
1013 the appropriate basic block. */
1015 for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
1017 /* If this is a relative file name, and an object directory has been
1018 specified, then make it relative to the object directory name. */
1019 if (! (*s_ptr->name == '/' || *s_ptr->name == DIR_SEPARATOR
1020 /* Check for disk name on MS-DOS-based systems. */
1021 || (DIR_SEPARATOR == '\\'
1022 && s_ptr->name[1] == ':'
1023 && (s_ptr->name[2] == DIR_SEPARATOR
1024 || s_ptr->name[2] == '/')))
1025 && object_directory != 0
1026 && *object_directory != '\0')
1028 int objdir_count = strlen (object_directory);
1029 source_file_name = xmalloc (objdir_count + strlen (s_ptr->name) + 2);
1030 strcpy (source_file_name, object_directory);
1031 if (object_directory[objdir_count - 1] != '/')
1032 source_file_name[objdir_count++] = '/';
1033 strcpy (source_file_name + objdir_count, s_ptr->name);
1035 else
1036 source_file_name = s_ptr->name;
1038 line_counts = (long *) xcalloc (sizeof (long), s_ptr->maxlineno);
1039 line_exists = xcalloc (1, s_ptr->maxlineno);
1040 if (output_branch_probs)
1041 branch_probs = (struct arcdata **)
1042 xcalloc (sizeof (struct arcdata *), s_ptr->maxlineno);
1044 /* There will be a zero at the beginning of the bb info, before the
1045 first list of line numbers, so must initialize block_num to 0. */
1046 block_num = 0;
1047 this_file = 0;
1048 current_graph = 0;
1050 /* Pointer into the bb_data, incremented while scanning the data. */
1051 char *ptr = bb_data;
1052 for (count = 0; count < bb_data_size; count++)
1054 long delim;
1056 __fetch_long (&line_num, ptr, 4);
1057 ptr += 4;
1058 if (line_num == -1)
1060 /* Marks the beginning of a file name. Check to see whether
1061 this is the filename we are currently collecting data for. */
1063 if (strcmp (s_ptr->name, ptr))
1064 this_file = 0;
1065 else
1066 this_file = 1;
1068 /* Scan past the file name. */
1069 do {
1070 count++;
1071 __fetch_long (&delim, ptr, 4);
1072 ptr += 4;
1073 } while (delim != line_num);
1075 else if (line_num == -2)
1077 /* Marks the start of a new function. Advance to the next
1078 program flow graph. */
1080 if (! current_graph)
1081 current_graph = bb_graph_list;
1082 else
1084 if (block_num == current_graph->num_blocks - 1)
1085 /* Last block falls through to exit. */
1087 else if (block_num == current_graph->num_blocks - 2)
1089 if (output_branch_probs && this_file)
1090 calculate_branch_probs (current_graph, block_num,
1091 branch_probs, last_line_num);
1093 else
1095 fnotice (stderr,
1096 "didn't use all bb entries of graph, function %s\n",
1097 function_name);
1098 fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
1099 block_num, current_graph->num_blocks);
1102 current_graph = current_graph->next;
1103 block_num = 0;
1105 if (output_function_summary && this_file)
1106 function_summary ();
1109 if (output_function_summary)
1111 function_source_lines = 0;
1112 function_source_lines_executed = 0;
1113 function_branches = 0;
1114 function_branches_executed = 0;
1115 function_branches_taken = 0;
1116 function_calls = 0;
1117 function_calls_executed = 0;
1120 /* Save the function name for later use. */
1121 function_name = ptr;
1123 /* Scan past the file name. */
1124 do {
1125 count++;
1126 __fetch_long (&delim, ptr, 4);
1127 ptr += 4;
1128 } while (delim != line_num);
1130 else if (line_num == 0)
1132 /* Marks the end of a block. */
1134 if (block_num >= current_graph->num_blocks)
1136 fnotice (stderr, "ERROR: too many basic blocks in .bb file %s\n",
1137 function_name);
1138 abort ();
1141 if (output_branch_probs && this_file)
1142 calculate_branch_probs (current_graph, block_num,
1143 branch_probs, last_line_num);
1145 block_num++;
1147 else if (this_file)
1149 if (output_function_summary)
1151 if (line_exists[line_num] == 0)
1152 function_source_lines++;
1153 if (line_counts[line_num] == 0
1154 && current_graph->bb_graph[block_num].exec_count != 0)
1155 function_source_lines_executed++;
1158 /* Accumulate execution data for this line number. */
1160 line_counts[line_num]
1161 += current_graph->bb_graph[block_num].exec_count;
1162 line_exists[line_num] = 1;
1163 last_line_num = line_num;
1168 if (output_function_summary && this_file)
1169 function_summary ();
1171 /* Calculate summary test coverage statistics. */
1173 total_source_lines = 0;
1174 total_source_lines_executed = 0;
1175 total_branches = 0;
1176 total_branches_executed = 0;
1177 total_branches_taken = 0;
1178 total_calls = 0;
1179 total_calls_executed = 0;
1181 for (count = 1; count < s_ptr->maxlineno; count++)
1183 if (line_exists[count])
1185 total_source_lines++;
1186 if (line_counts[count])
1187 total_source_lines_executed++;
1189 if (output_branch_probs)
1191 for (a_ptr = branch_probs[count]; a_ptr; a_ptr = a_ptr->next)
1193 if (a_ptr->call_insn)
1195 total_calls++;
1196 if (a_ptr->total != 0)
1197 total_calls_executed++;
1199 else
1201 total_branches++;
1202 if (a_ptr->total != 0)
1203 total_branches_executed++;
1204 if (a_ptr->hits > 0)
1205 total_branches_taken++;
1211 if (total_source_lines)
1212 fnotice (stdout,
1213 "%6.2f%% of %d source lines executed in file %s\n",
1214 (((double) total_source_lines_executed / total_source_lines)
1215 * 100), total_source_lines, source_file_name);
1216 else
1217 fnotice (stdout, "No executable source lines in file %s\n",
1218 source_file_name);
1220 if (output_branch_probs)
1222 if (total_branches)
1224 fnotice (stdout, "%6.2f%% of %d branches executed in file %s\n",
1225 (((double) total_branches_executed / total_branches)
1226 * 100), total_branches, source_file_name);
1227 fnotice (stdout,
1228 "%6.2f%% of %d branches taken at least once in file %s\n",
1229 (((double) total_branches_taken / total_branches)
1230 * 100), total_branches, source_file_name);
1232 else
1233 fnotice (stdout, "No branches in file %s\n", source_file_name);
1234 if (total_calls)
1235 fnotice (stdout, "%6.2f%% of %d calls executed in file %s\n",
1236 (((double) total_calls_executed / total_calls)
1237 * 100), total_calls, source_file_name);
1238 else
1239 fnotice (stdout, "No calls in file %s\n", source_file_name);
1242 if (output_gcov_file)
1244 /* Now the statistics are ready. Read in the source file one line
1245 at a time, and output that line to the gcov file preceded by
1246 its execution count if non zero. */
1248 source_file = fopen (source_file_name, "r");
1249 if (source_file == NULL)
1251 fnotice (stderr, "Could not open source file %s.\n",
1252 source_file_name);
1253 free (line_counts);
1254 free (line_exists);
1255 continue;
1258 count = strlen (source_file_name);
1259 cptr = strrchr (s_ptr->name, '/');
1260 if (cptr)
1261 cptr = cptr + 1;
1262 else
1263 cptr = s_ptr->name;
1264 if (output_long_names && strcmp (cptr, input_file_name))
1266 gcov_file_name = xmalloc (count + 7 + strlen (input_file_name));
1268 cptr = strrchr (input_file_name, '/');
1269 if (cptr)
1270 strcpy (gcov_file_name, cptr + 1);
1271 else
1272 strcpy (gcov_file_name, input_file_name);
1274 strcat (gcov_file_name, ".");
1276 cptr = strrchr (source_file_name, '/');
1277 if (cptr)
1278 strcat (gcov_file_name, cptr + 1);
1279 else
1280 strcat (gcov_file_name, source_file_name);
1282 else
1284 gcov_file_name = xmalloc (count + 6);
1285 cptr = strrchr (source_file_name, '/');
1286 if (cptr)
1287 strcpy (gcov_file_name, cptr + 1);
1288 else
1289 strcpy (gcov_file_name, source_file_name);
1292 /* Don't strip off the ending for compatibility with tcov, since
1293 this results in confusion if there is more than one file with
1294 the same basename, e.g. tmp.c and tmp.h. */
1295 strcat (gcov_file_name, ".gcov");
1297 gcov_file = fopen (gcov_file_name, "w");
1299 if (gcov_file == NULL)
1301 fnotice (stderr, "Could not open output file %s.\n",
1302 gcov_file_name);
1303 fclose (source_file);
1304 free (line_counts);
1305 free (line_exists);
1306 continue;
1309 fnotice (stdout, "Creating %s.\n", gcov_file_name);
1311 for (count = 1; count < s_ptr->maxlineno; count++)
1313 char *retval;
1314 int len;
1316 retval = fgets (string, STRING_SIZE, source_file);
1318 /* For lines which don't exist in the .bb file, print nothing
1319 before the source line. For lines which exist but were never
1320 executed, print ###### before the source line. Otherwise,
1321 print the execution count before the source line. */
1322 /* There are 16 spaces of indentation added before the source
1323 line so that tabs won't be messed up. */
1324 if (line_exists[count])
1326 if (line_counts[count])
1327 fprintf (gcov_file, "%12ld %s", line_counts[count],
1328 string);
1329 else
1330 fprintf (gcov_file, " ###### %s", string);
1332 else
1333 fprintf (gcov_file, "\t\t%s", string);
1335 /* In case the source file line is larger than our buffer, keep
1336 reading and outputting lines until we get a newline. */
1337 len = strlen (string);
1338 while ((len == 0 || string[strlen (string) - 1] != '\n')
1339 && retval != NULL)
1341 retval = fgets (string, STRING_SIZE, source_file);
1342 fputs (string, gcov_file);
1345 if (output_branch_probs)
1347 for (i = 0, a_ptr = branch_probs[count]; a_ptr;
1348 a_ptr = a_ptr->next, i++)
1350 if (a_ptr->call_insn)
1352 if (a_ptr->total == 0)
1353 fnotice (gcov_file, "call %d never executed\n", i);
1354 else
1356 if (output_branch_counts)
1357 fnotice (gcov_file,
1358 "call %d returns = %d\n",
1359 i, a_ptr->total - a_ptr->hits);
1360 else
1361 fnotice (gcov_file,
1362 "call %d returns = %d%%\n",
1363 i, 100 - ((a_ptr->hits * 100) +
1364 (a_ptr->total >> 1))/a_ptr->total);
1367 else
1369 if (a_ptr->total == 0)
1370 fnotice (gcov_file, "branch %d never executed\n",
1372 else
1374 if (output_branch_counts)
1375 fnotice (gcov_file,
1376 "branch %d taken = %d\n",
1377 i, a_ptr->hits);
1378 else
1379 fnotice (gcov_file,
1380 "branch %d taken = %d%%\n", i,
1381 ((a_ptr->hits * 100) +
1382 (a_ptr->total >> 1))/
1383 a_ptr->total);
1390 /* Gracefully handle errors while reading the source file. */
1391 if (retval == NULL)
1393 fnotice (stderr,
1394 "Unexpected EOF while reading source file %s.\n",
1395 source_file_name);
1396 break;
1400 /* Handle all remaining source lines. There may be lines
1401 after the last line of code. */
1404 char *retval = fgets (string, STRING_SIZE, source_file);
1405 while (retval != NULL)
1407 int len;
1409 fprintf (gcov_file, "\t\t%s", string);
1411 /* In case the source file line is larger than our buffer, keep
1412 reading and outputting lines until we get a newline. */
1413 len = strlen (string);
1414 while ((len == 0 || string[strlen (string) - 1] != '\n')
1415 && retval != NULL)
1417 retval = fgets (string, STRING_SIZE, source_file);
1418 fputs (string, gcov_file);
1421 retval = fgets (string, STRING_SIZE, source_file);
1425 fclose (source_file);
1426 fclose (gcov_file);
1429 free (line_counts);
1430 free (line_exists);