1 /* Gcov.c: prepend line execution counts and branch probabilities to a
3 Copyright (C) 1990, 91-94, 96, 97, 98, 1999 Free Software Foundation, Inc.
4 Contributed by James E. Wilson of Cygnus Support.
5 Mangled by Bob Manson of Cygnus Support.
7 Gcov is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 Gcov is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Gcov; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 /* ??? The code in final.c that produces the struct bb assumes that there is
23 no padding between the fields. This is not necessary true. The current
24 code can only be trusted if longs and pointers are the same size. */
26 /* ??? No need to print an execution count on every line, could just print
27 it on the first line of each block, and only print it on a subsequent
28 line in the same block if the count changes. */
30 /* ??? Print a list of the ten blocks with the highest execution counts,
31 and list the line numbers corresponding to those blocks. Also, perhaps
32 list the line numbers with the highest execution counts, only printing
33 the first if there are several which are all listed in the same block. */
35 /* ??? Should have an option to print the number of basic blocks, and the
36 percent of them that are covered. */
38 /* ??? Does not correctly handle the case where two .bb files refer to the
39 same included source file. For example, if one has a short file containing
40 only inline functions, which is then included in two other files, then
41 there will be two .bb files which refer to the include file, but there
42 is no way to get the total execution counts for the included file, can
43 only get execution counts for one or the other of the including files. */
52 /* The .bb file format consists of several lists of 4-byte integers
53 which are the line numbers of each basic block in the file. Each
54 list is terminated by a zero. These lists correspond to the basic
55 blocks in the reconstructed program flow graph.
57 A line number of -1 indicates that a source file name (padded to a
58 long boundary) follows. The padded file name is followed by
59 another -1 to make it easy to scan past file names. A -2 indicates
60 that a function name (padded to a long boundary) follows; the name
61 is followed by another -2 to make it easy to scan past the function
64 The .bbg file contains enough info to enable gcov to reconstruct the
65 program flow graph. The first word is the number of basic blocks,
66 the second word is the number of arcs, followed by the list of arcs
67 (source bb, dest bb pairs), then a -1, then the number of instrumented
68 arcs followed by the instrumented arcs, followed by another -1. This
69 is repeated for each function.
71 The .da file contains the execution count for each instrumented branch.
73 The .bb and .bbg files are created by giving GCC the -ftest-coverage option,
74 and the .da files are created when an executable compiled with
75 -fprofile-arcs is run. */
77 /* The functions in this file for creating and solution program flow graphs
78 are very similar to functions in the gcc source file profile.c. */
80 char gcov_version_string[] = "GNU gcov version 1.5\n";
82 /* This is the size of the buffer used to read in source file lines. */
84 #define STRING_SIZE 200
86 /* One copy of this structure is created for each source file mentioned in the
93 struct sourcefile *next;
96 /* This points to the head of the sourcefile structure list. */
98 struct sourcefile *sources;
100 /* One of these is dynamically created whenever we identify an arc in the
107 unsigned int count_valid : 1;
108 unsigned int on_tree : 1;
109 unsigned int fake : 1;
110 unsigned int fall_through : 1;
112 /* Not needed for gcov, but defined in profile.c. */
115 struct adj_list *pred_next;
116 struct adj_list *succ_next;
119 /* Count the number of basic blocks, and create an array of these structures,
120 one for each bb in the function. */
123 struct adj_list *succ;
124 struct adj_list *pred;
128 unsigned int count_valid : 1;
129 unsigned int on_tree : 1;
131 /* Not needed for gcov, but defined in profile.c. */
136 /* When outputting branch probabilities, one of these structures is created
137 for each branch/call. */
143 struct arcdata *next;
146 /* Used to save the list of bb_graphs, one per function. */
148 struct bb_info_list {
149 /* Indexed by block number, holds the basic block graph for one function. */
150 struct bb_info *bb_graph;
152 struct bb_info_list *next;
155 /* Holds a list of function basic block graphs. */
157 static struct bb_info_list *bb_graph_list = 0;
159 /* Name and file pointer of the input file for the basic block graph. */
161 static char *bbg_file_name;
162 static FILE *bbg_file;
164 /* Name and file pointer of the input file for the arc count data. */
166 static char *da_file_name;
167 static FILE *da_file;
169 /* Name and file pointer of the input file for the basic block line counts. */
171 static char *bb_file_name;
172 static FILE *bb_file;
174 /* Holds the entire contents of the bb_file read into memory. */
176 static char *bb_data;
178 /* Size of bb_data array in longs. */
180 static long bb_data_size;
182 /* Name and file pointer of the output file. */
184 static char *gcov_file_name;
185 static FILE *gcov_file;
187 /* Name of the file mentioned on the command line. */
189 static char *input_file_name = 0;
191 /* Output branch probabilities if true. */
193 static int output_branch_probs = 0;
195 /* Output a gcov file if this is true. This is on by default, and can
196 be turned off by the -n option. */
198 static int output_gcov_file = 1;
200 /* For included files, make the gcov output file name include the name of
201 the input source file. For example, if x.h is included in a.c, then the
202 output file name is a.c.x.h.gcov instead of x.h.gcov. This works only
203 when a single source file is specified. */
205 static int output_long_names = 0;
207 /* Output summary info for each function. */
209 static int output_function_summary = 0;
211 /* Object directory file prefix. This is the directory where .bb and .bbg
212 files are looked for, if non-zero. */
214 static char *object_directory = 0;
216 /* Forward declarations. */
217 static void process_args PROTO ((int, char **));
218 static void open_files PROTO ((void));
219 static void read_files PROTO ((void));
220 static void scan_for_source_files PROTO ((void));
221 static void output_data PROTO ((void));
222 static void print_usage PROTO ((void)) ATTRIBUTE_NORETURN;
229 #ifdef HAVE_LC_MESSAGES
230 setlocale (LC_MESSAGES, "");
232 (void) bindtextdomain (PACKAGE, localedir);
233 (void) textdomain (PACKAGE);
235 process_args (argc, argv);
241 scan_for_source_files ();
248 static void fnotice PVPROTO ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
250 fnotice VPROTO ((FILE *file, const char *msgid, ...))
252 #ifndef ANSI_PROTOTYPES
258 VA_START (ap, msgid);
260 #ifndef ANSI_PROTOTYPES
261 file = va_arg (ap, FILE *);
262 msgid = va_arg (ap, const char *);
265 vfprintf (file, _(msgid), ap);
274 register PTR value = (PTR) malloc (size);
277 fnotice (stderr, "error: virtual memory exhausted");
278 exit (FATAL_EXIT_CODE);
283 /* More 'friendly' abort that prints the line and file.
284 config.h can #define abort fancy_abort if you like that sort of thing. */
289 fnotice (stderr, "Internal gcc abort.\n");
290 exit (FATAL_EXIT_CODE);
293 /* Print a usage message and exit. */
298 fnotice (stderr, "gcov [-b] [-v] [-n] [-l] [-f] [-o OBJDIR] file\n");
299 exit (FATAL_EXIT_CODE);
302 /* Parse the command line. */
305 process_args (argc, argv)
311 for (i = 1; i < argc; i++)
313 if (argv[i][0] == '-')
315 if (argv[i][1] == 'b')
316 output_branch_probs = 1;
317 else if (argv[i][1] == 'v')
318 fputs (gcov_version_string, stderr);
319 else if (argv[i][1] == 'n')
320 output_gcov_file = 0;
321 else if (argv[i][1] == 'l')
322 output_long_names = 1;
323 else if (argv[i][1] == 'f')
324 output_function_summary = 1;
325 else if (argv[i][1] == 'o' && argv[i][2] == '\0')
326 object_directory = argv[++i];
330 else if (! input_file_name)
331 input_file_name = argv[i];
336 if (! input_file_name)
341 /* Find and open the .bb, .da, and .bbg files. */
346 int count, objdir_count;
349 /* Determine the names of the .bb, .bbg, and .da files. Strip off the
350 extension, if any, and append the new extensions. */
351 count = strlen (input_file_name);
352 if (object_directory)
353 objdir_count = strlen (object_directory);
357 da_file_name = xmalloc (count + objdir_count + 4);
358 bb_file_name = xmalloc (count + objdir_count + 4);
359 bbg_file_name = xmalloc (count + objdir_count + 5);
361 if (object_directory)
363 strcpy (da_file_name, object_directory);
364 strcpy (bb_file_name, object_directory);
365 strcpy (bbg_file_name, object_directory);
367 if (object_directory[objdir_count - 1] != '/')
369 strcat (da_file_name, "/");
370 strcat (bb_file_name, "/");
371 strcat (bbg_file_name, "/");
374 cptr = rindex (input_file_name, '/');
377 strcat (da_file_name, cptr + 1);
378 strcat (bb_file_name, cptr + 1);
379 strcat (bbg_file_name, cptr + 1);
383 strcat (da_file_name, input_file_name);
384 strcat (bb_file_name, input_file_name);
385 strcat (bbg_file_name, input_file_name);
390 strcpy (da_file_name, input_file_name);
391 strcpy (bb_file_name, input_file_name);
392 strcpy (bbg_file_name, input_file_name);
395 cptr = rindex (bb_file_name, '.');
397 strcpy (cptr, ".bb");
399 strcat (bb_file_name, ".bb");
401 cptr = rindex (da_file_name, '.');
403 strcpy (cptr, ".da");
405 strcat (da_file_name, ".da");
407 cptr = rindex (bbg_file_name, '.');
409 strcpy (cptr, ".bbg");
411 strcat (bbg_file_name, ".bbg");
413 bb_file = fopen (bb_file_name, "r");
416 fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
417 exit (FATAL_EXIT_CODE);
420 /* If none of the functions in the file were executed, then there won't
421 be a .da file. Just assume that all counts are zero in this case. */
422 da_file = fopen (da_file_name, "r");
425 fnotice (stderr, "Could not open data file %s.\n", da_file_name);
426 fnotice (stderr, "Assuming that all execution counts are zero.\n");
429 bbg_file = fopen (bbg_file_name, "r");
430 if (bbg_file == NULL)
432 fnotice (stderr, "Could not open program flow graph file %s.\n",
434 exit (FATAL_EXIT_CODE);
437 /* Check for empty .bbg file. This indicates that there is no executable
438 code in this source file. */
439 /* Set the EOF condition if at the end of file. */
440 ungetc (getc (bbg_file), bbg_file);
443 fnotice (stderr, "No executable code associated with file %s.\n",
445 exit (FATAL_EXIT_CODE);
449 /* Initialize a new arc. */
452 init_arc (arcptr, source, target, bb_graph)
453 struct adj_list *arcptr;
455 struct bb_info *bb_graph;
457 arcptr->target = target;
458 arcptr->source = source;
460 arcptr->arc_count = 0;
461 arcptr->count_valid = 0;
464 arcptr->fall_through = 0;
466 arcptr->succ_next = bb_graph[source].succ;
467 bb_graph[source].succ = arcptr;
468 bb_graph[source].succ_count++;
470 arcptr->pred_next = bb_graph[target].pred;
471 bb_graph[target].pred = arcptr;
472 bb_graph[target].pred_count++;
476 /* Reverse the arcs on a arc list. */
478 static struct adj_list *
479 reverse_arcs (arcptr)
480 struct adj_list *arcptr;
482 struct adj_list *prev = 0;
483 struct adj_list *next;
485 for ( ; arcptr; arcptr = next)
487 next = arcptr->succ_next;
488 arcptr->succ_next = prev;
496 /* Construct the program flow graph from the .bbg file, and read in the data
500 create_program_flow_graph (bptr)
501 struct bb_info_list *bptr;
503 long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
505 struct adj_list *arcptr;
506 struct bb_info *bb_graph;
508 /* Read the number of blocks. */
509 __read_long (&num_blocks, bbg_file, 4);
511 /* Create an array of size bb number of bb_info structs. Bzero it. */
512 bb_graph = (struct bb_info *) xmalloc (num_blocks
513 * sizeof (struct bb_info));
514 bzero ((char *) bb_graph, sizeof (struct bb_info) * num_blocks);
516 bptr->bb_graph = bb_graph;
517 bptr->num_blocks = num_blocks;
519 /* Read and create each arc from the .bbg file. */
520 __read_long (&number_arcs, bbg_file, 4);
521 for (i = 0; i < num_blocks; i++)
525 __read_long (&num_arcs_per_block, bbg_file, 4);
526 for (j = 0; j < num_arcs_per_block; j++)
528 if (number_arcs-- < 0)
532 __read_long (&dest, bbg_file, 4);
534 arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
535 init_arc (arcptr, src, dest, bb_graph);
537 __read_long (&flag_bits, bbg_file, 4);
538 arcptr->on_tree = flag_bits & 0x1;
539 arcptr->fake = !! (flag_bits & 0x2);
540 arcptr->fall_through = !! (flag_bits & 0x4);
547 /* Read and ignore the -1 separating the arc list from the arc list of the
549 __read_long (&src, bbg_file, 4);
553 /* Must reverse the order of all succ arcs, to ensure that they match
554 the order of the data in the .da file. */
556 for (i = 0; i < num_blocks; i++)
557 if (bb_graph[i].succ)
558 bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
560 /* For each arc not on the spanning tree, set its execution count from
563 /* The first count in the .da file is the number of times that the function
564 was entered. This is the exec_count for block zero. */
566 /* This duplicates code in branch_prob in profile.c. */
568 for (i = 0; i < num_blocks; i++)
569 for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
570 if (! arcptr->on_tree)
573 if (da_file && __read_long (&tmp_count, da_file, 8))
576 arcptr->arc_count = tmp_count;
577 arcptr->count_valid = 1;
578 bb_graph[i].succ_count--;
579 bb_graph[arcptr->target].pred_count--;
584 solve_program_flow_graph (bptr)
585 struct bb_info_list *bptr;
587 int passes, changes, total;
589 struct adj_list *arcptr;
590 struct bb_info *bb_graph;
593 num_blocks = bptr->num_blocks;
594 bb_graph = bptr->bb_graph;
596 /* For every block in the file,
597 - if every exit/entrance arc has a known count, then set the block count
598 - if the block count is known, and every exit/entrance arc but one has
599 a known execution count, then set the count of the remaining arc
601 As arc counts are set, decrement the succ/pred count, but don't delete
602 the arc, that way we can easily tell when all arcs are known, or only
603 one arc is unknown. */
605 /* The order that the basic blocks are iterated through is important.
606 Since the code that finds spanning trees starts with block 0, low numbered
607 arcs are put on the spanning tree in preference to high numbered arcs.
608 Hence, most instrumented arcs are at the end. Graph solving works much
609 faster if we propagate numbers from the end to the start.
611 This takes an average of slightly more than 3 passes. */
620 for (i = num_blocks - 1; i >= 0; i--)
622 if (! bb_graph[i].count_valid)
624 if (bb_graph[i].succ_count == 0)
627 for (arcptr = bb_graph[i].succ; arcptr;
628 arcptr = arcptr->succ_next)
629 total += arcptr->arc_count;
630 bb_graph[i].exec_count = total;
631 bb_graph[i].count_valid = 1;
634 else if (bb_graph[i].pred_count == 0)
637 for (arcptr = bb_graph[i].pred; arcptr;
638 arcptr = arcptr->pred_next)
639 total += arcptr->arc_count;
640 bb_graph[i].exec_count = total;
641 bb_graph[i].count_valid = 1;
645 if (bb_graph[i].count_valid)
647 if (bb_graph[i].succ_count == 1)
650 /* One of the counts will be invalid, but it is zero,
651 so adding it in also doesn't hurt. */
652 for (arcptr = bb_graph[i].succ; arcptr;
653 arcptr = arcptr->succ_next)
654 total += arcptr->arc_count;
655 /* Calculate count for remaining arc by conservation. */
656 total = bb_graph[i].exec_count - total;
657 /* Search for the invalid arc, and set its count. */
658 for (arcptr = bb_graph[i].succ; arcptr;
659 arcptr = arcptr->succ_next)
660 if (! arcptr->count_valid)
664 arcptr->count_valid = 1;
665 arcptr->arc_count = total;
666 bb_graph[i].succ_count--;
668 bb_graph[arcptr->target].pred_count--;
671 if (bb_graph[i].pred_count == 1)
674 /* One of the counts will be invalid, but it is zero,
675 so adding it in also doesn't hurt. */
676 for (arcptr = bb_graph[i].pred; arcptr;
677 arcptr = arcptr->pred_next)
678 total += arcptr->arc_count;
679 /* Calculate count for remaining arc by conservation. */
680 total = bb_graph[i].exec_count - total;
681 /* Search for the invalid arc, and set its count. */
682 for (arcptr = bb_graph[i].pred; arcptr;
683 arcptr = arcptr->pred_next)
684 if (! arcptr->count_valid)
688 arcptr->count_valid = 1;
689 arcptr->arc_count = total;
690 bb_graph[i].pred_count--;
692 bb_graph[arcptr->source].succ_count--;
699 /* If the graph has been correctly solved, every block will have a
700 succ and pred count of zero. */
701 for (i = 0; i < num_blocks; i++)
702 if (bb_graph[i].succ_count || bb_graph[i].pred_count)
711 struct bb_info_list *list_end = 0;
712 struct bb_info_list *b_ptr;
715 /* Read and ignore the first word of the .da file, which is the count of
716 how many numbers follow. */
717 if (da_file && __read_long (&total, da_file, 8))
720 while (! feof (bbg_file))
722 b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
726 list_end->next = b_ptr;
728 bb_graph_list = b_ptr;
731 /* Read in the data in the .bbg file and reconstruct the program flow
732 graph for one function. */
733 create_program_flow_graph (b_ptr);
735 /* Set the EOF condition if at the end of file. */
736 ungetc (getc (bbg_file), bbg_file);
739 /* Check to make sure the .da file data is valid. */
744 fnotice (stderr, ".da file contents exhausted too early\n");
745 /* Should be at end of file now. */
746 if (__read_long (&total, da_file, 8) == 0)
747 fnotice (stderr, ".da file contents not exhausted\n");
750 /* Calculate all of the basic block execution counts and branch
751 taken probabilities. */
753 for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
754 solve_program_flow_graph (b_ptr);
756 /* Read in all of the data from the .bb file. This info will be accessed
757 sequentially twice. */
758 stat (bb_file_name, &buf);
759 bb_data_size = buf.st_size / 4;
761 bb_data = (char *) xmalloc ((unsigned) buf.st_size);
762 fread (bb_data, sizeof (char), buf.st_size, bb_file);
771 /* Scan the data in the .bb file to find all source files referenced,
772 and the largest line number mentioned in each one. */
775 scan_for_source_files ()
777 struct sourcefile *s_ptr = NULL;
782 /* Search the bb_data to find:
783 1) The number of sources files contained herein, and
784 2) The largest line number for each source file. */
788 for (count = 0; count < bb_data_size; count++)
790 __fetch_long (&line_num, ptr, 4);
794 /* A source file name follows. Check to see if we already have
795 a sourcefile structure for this file. */
797 while (s_ptr && strcmp (s_ptr->name, ptr))
802 /* No sourcefile structure for this file name exists, create
803 a new one, and append it to the front of the sources list. */
804 s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
805 s_ptr->name = xmalloc (strlen ((char *) ptr) + 1);
806 strcpy (s_ptr->name, (char *) ptr);
807 s_ptr->maxlineno = 0;
808 s_ptr->next = sources;
812 /* Scan past the file name. */
817 __fetch_long (&delim, ptr, 4);
819 } while (delim != line_num);
822 else if (line_num == -2)
826 /* A function name follows. Ignore it. */
829 __fetch_long (&delim, ptr, 4);
831 } while (delim != line_num);
833 /* There will be a zero before the first file name, in which case s_ptr
834 will still be uninitialized. So, only try to set the maxlineno
835 field if line_num is non-zero. */
836 else if (line_num > 0)
838 if (s_ptr->maxlineno <= line_num)
839 s_ptr->maxlineno = line_num + 1;
841 else if (line_num < 0)
843 /* Don't know what this is, but it's garbage. */
849 /* For calculating coverage at the function level. */
851 static int function_source_lines;
852 static int function_source_lines_executed;
853 static int function_branches;
854 static int function_branches_executed;
855 static int function_branches_taken;
856 static int function_calls;
857 static int function_calls_executed;
858 static char *function_name;
860 /* Calculate the branch taken probabilities for all arcs branches at the
861 end of this block. */
864 calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num)
865 struct bb_info_list *current_graph;
867 struct arcdata **branch_probs;
871 struct adj_list *arcptr;
872 struct arcdata *end_ptr, *a_ptr;
874 total = current_graph->bb_graph[block_num].exec_count;
875 for (arcptr = current_graph->bb_graph[block_num].succ; arcptr;
876 arcptr = arcptr->succ_next)
878 /* Ignore fall through arcs as they aren't really branches. */
880 if (arcptr->fall_through)
883 a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
887 a_ptr->prob = ((arcptr->arc_count * 100) + (total >> 1)) / total;
888 a_ptr->call_insn = arcptr->fake;
890 if (output_function_summary)
892 if (a_ptr->call_insn)
895 if (a_ptr->prob != -1)
896 function_calls_executed++;
901 if (a_ptr->prob != -1)
902 function_branches_executed++;
904 function_branches_taken++;
908 /* Append the new branch to the end of the list. */
910 if (! branch_probs[last_line_num])
911 branch_probs[last_line_num] = a_ptr;
914 end_ptr = branch_probs[last_line_num];
915 while (end_ptr->next != 0)
916 end_ptr = end_ptr->next;
917 end_ptr->next = a_ptr;
922 /* Output summary info for a function. */
927 if (function_source_lines)
928 fnotice (stdout, "%6.2f%% of %d source lines executed in function %s\n",
929 (((double) function_source_lines_executed / function_source_lines)
930 * 100), function_source_lines, function_name);
932 fnotice (stdout, "No executable source lines in function %s\n",
935 if (output_branch_probs)
937 if (function_branches)
939 fnotice (stdout, "%6.2f%% of %d branches executed in function %s\n",
940 (((double) function_branches_executed / function_branches)
941 * 100), function_branches, function_name);
943 "%6.2f%% of %d branches taken at least once in function %s\n",
944 (((double) function_branches_taken / function_branches)
945 * 100), function_branches, function_name);
948 fnotice (stdout, "No branches in function %s\n", function_name);
950 fnotice (stdout, "%6.2f%% of %d calls executed in function %s\n",
951 (((double) function_calls_executed / function_calls)
952 * 100), function_calls, function_name);
954 fnotice (stdout, "No calls in function %s\n", function_name);
958 /* Calculate line execution counts, and output the data to a .tcov file. */
963 /* When scanning data, this is true only if the data applies to the
964 current source file. */
966 /* An array indexed by line number which indicates how many times that line
969 /* An array indexed by line number which indicates whether the line was
970 present in the bb file (i.e. whether it had code associate with it).
971 Lines never executed are those which both exist, and have zero execution
974 /* An array indexed by line number, which contains a list of branch
975 probabilities, one for each branch on that line. */
976 struct arcdata **branch_probs = NULL;
977 struct sourcefile *s_ptr;
978 char *source_file_name;
980 struct bb_info_list *current_graph;
985 long last_line_num = 0;
987 struct arcdata *a_ptr;
988 /* Buffer used for reading in lines from the source file. */
989 char string[STRING_SIZE];
990 /* For calculating coverage at the file level. */
991 int total_source_lines;
992 int total_source_lines_executed;
994 int total_branches_executed;
995 int total_branches_taken;
997 int total_calls_executed;
999 /* Now, for each source file, allocate an array big enough to hold a count
1000 for each line. Scan through the bb_data, and when the file name matches
1001 the current file name, then for each following line number, increment
1002 the line number execution count indicated by the execution count of
1003 the appropriate basic block. */
1005 for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
1007 /* If this is a relative file name, and an object directory has been
1008 specified, then make it relative to the object directory name. */
1009 if (*s_ptr->name != '/' && object_directory != 0
1010 && *object_directory != '\0')
1012 int objdir_count = strlen (object_directory);
1013 source_file_name = xmalloc (objdir_count + strlen (s_ptr->name) + 2);
1014 strcpy (source_file_name, object_directory);
1015 if (object_directory[objdir_count - 1] != '/')
1016 source_file_name[objdir_count++] = '/';
1017 strcpy (source_file_name + objdir_count, s_ptr->name);
1020 source_file_name = s_ptr->name;
1022 line_counts = (long *) xmalloc (sizeof (long) * s_ptr->maxlineno);
1023 bzero ((char *) line_counts, sizeof (long) * s_ptr->maxlineno);
1024 line_exists = xmalloc (s_ptr->maxlineno);
1025 bzero (line_exists, s_ptr->maxlineno);
1026 if (output_branch_probs)
1028 branch_probs = (struct arcdata **) xmalloc (sizeof (struct arcdata *)
1029 * s_ptr->maxlineno);
1030 bzero ((char *) branch_probs,
1031 sizeof (struct arcdata *) * s_ptr->maxlineno);
1034 /* There will be a zero at the beginning of the bb info, before the
1035 first list of line numbers, so must initialize block_num to 0. */
1040 /* Pointer into the bb_data, incremented while scanning the data. */
1041 char *ptr = bb_data;
1042 for (count = 0; count < bb_data_size; count++)
1046 __fetch_long (&line_num, ptr, 4);
1050 /* Marks the beginning of a file name. Check to see whether
1051 this is the filename we are currently collecting data for. */
1053 if (strcmp (s_ptr->name, ptr))
1058 /* Scan past the file name. */
1061 __fetch_long (&delim, ptr, 4);
1063 } while (delim != line_num);
1065 else if (line_num == -2)
1067 /* Marks the start of a new function. Advance to the next
1068 program flow graph. */
1070 if (! current_graph)
1071 current_graph = bb_graph_list;
1074 if (block_num == current_graph->num_blocks - 1)
1075 /* Last block falls through to exit. */
1077 else if (block_num == current_graph->num_blocks - 2)
1079 if (output_branch_probs && this_file)
1080 calculate_branch_probs (current_graph, block_num,
1081 branch_probs, last_line_num);
1086 "didn't use all bb entries of graph, function %s\n",
1088 fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
1089 block_num, current_graph->num_blocks);
1092 current_graph = current_graph->next;
1095 if (output_function_summary && this_file)
1096 function_summary ();
1099 if (output_function_summary)
1101 function_source_lines = 0;
1102 function_source_lines_executed = 0;
1103 function_branches = 0;
1104 function_branches_executed = 0;
1105 function_branches_taken = 0;
1107 function_calls_executed = 0;
1110 /* Save the function name for later use. */
1111 function_name = ptr;
1113 /* Scan past the file name. */
1116 __fetch_long (&delim, ptr, 4);
1118 } while (delim != line_num);
1120 else if (line_num == 0)
1122 /* Marks the end of a block. */
1124 if (block_num >= current_graph->num_blocks)
1126 fnotice (stderr, "ERROR: too many basic blocks in .bb file %s\n",
1131 if (output_branch_probs && this_file)
1132 calculate_branch_probs (current_graph, block_num,
1133 branch_probs, last_line_num);
1139 if (output_function_summary)
1141 if (line_exists[line_num] == 0)
1142 function_source_lines++;
1143 if (line_counts[line_num] == 0
1144 && current_graph->bb_graph[block_num].exec_count != 0)
1145 function_source_lines_executed++;
1148 /* Accumulate execution data for this line number. */
1150 line_counts[line_num]
1151 += current_graph->bb_graph[block_num].exec_count;
1152 line_exists[line_num] = 1;
1153 last_line_num = line_num;
1158 if (output_function_summary && this_file)
1159 function_summary ();
1161 /* Calculate summary test coverage statistics. */
1163 total_source_lines = 0;
1164 total_source_lines_executed = 0;
1166 total_branches_executed = 0;
1167 total_branches_taken = 0;
1169 total_calls_executed = 0;
1171 for (count = 1; count < s_ptr->maxlineno; count++)
1173 if (line_exists[count])
1175 total_source_lines++;
1176 if (line_counts[count])
1177 total_source_lines_executed++;
1179 if (output_branch_probs)
1181 for (a_ptr = branch_probs[count]; a_ptr; a_ptr = a_ptr->next)
1183 if (a_ptr->call_insn)
1186 if (a_ptr->prob != -1)
1187 total_calls_executed++;
1192 if (a_ptr->prob != -1)
1193 total_branches_executed++;
1194 if (a_ptr->prob > 0)
1195 total_branches_taken++;
1201 if (total_source_lines)
1203 "%6.2f%% of %d source lines executed in file %s\n",
1204 (((double) total_source_lines_executed / total_source_lines)
1205 * 100), total_source_lines, source_file_name);
1207 fnotice (stdout, "No executable source lines in file %s\n",
1210 if (output_branch_probs)
1214 fnotice (stdout, "%6.2f%% of %d branches executed in file %s\n",
1215 (((double) total_branches_executed / total_branches)
1216 * 100), total_branches, source_file_name);
1218 "%6.2f%% of %d branches taken at least once in file %s\n",
1219 (((double) total_branches_taken / total_branches)
1220 * 100), total_branches, source_file_name);
1223 fnotice (stdout, "No branches in file %s\n", source_file_name);
1225 fnotice (stdout, "%6.2f%% of %d calls executed in file %s\n",
1226 (((double) total_calls_executed / total_calls)
1227 * 100), total_calls, source_file_name);
1229 fnotice (stdout, "No calls in file %s\n", source_file_name);
1232 if (output_gcov_file)
1234 /* Now the statistics are ready. Read in the source file one line
1235 at a time, and output that line to the gcov file preceded by
1236 its execution count if non zero. */
1238 source_file = fopen (source_file_name, "r");
1239 if (source_file == NULL)
1241 fnotice (stderr, "Could not open source file %s.\n",
1248 count = strlen (source_file_name);
1249 cptr = rindex (s_ptr->name, '/');
1254 if (output_long_names && strcmp (cptr, input_file_name))
1256 gcov_file_name = xmalloc (count + 7 + strlen (input_file_name));
1258 cptr = rindex (input_file_name, '/');
1260 strcpy (gcov_file_name, cptr + 1);
1262 strcpy (gcov_file_name, input_file_name);
1264 strcat (gcov_file_name, ".");
1266 cptr = rindex (source_file_name, '/');
1268 strcat (gcov_file_name, cptr + 1);
1270 strcat (gcov_file_name, source_file_name);
1274 gcov_file_name = xmalloc (count + 6);
1275 cptr = rindex (source_file_name, '/');
1277 strcpy (gcov_file_name, cptr + 1);
1279 strcpy (gcov_file_name, source_file_name);
1282 /* Don't strip off the ending for compatibility with tcov, since
1283 this results in confusion if there is more than one file with
1284 the same basename, e.g. tmp.c and tmp.h. */
1285 strcat (gcov_file_name, ".gcov");
1287 gcov_file = fopen (gcov_file_name, "w");
1289 if (gcov_file == NULL)
1291 fnotice (stderr, "Could not open output file %s.\n",
1293 fclose (source_file);
1299 fnotice (stdout, "Creating %s.\n", gcov_file_name);
1301 for (count = 1; count < s_ptr->maxlineno; count++)
1306 retval = fgets (string, STRING_SIZE, source_file);
1308 /* For lines which don't exist in the .bb file, print nothing
1309 before the source line. For lines which exist but were never
1310 executed, print ###### before the source line. Otherwise,
1311 print the execution count before the source line. */
1312 /* There are 16 spaces of indentation added before the source
1313 line so that tabs won't be messed up. */
1314 if (line_exists[count])
1316 if (line_counts[count])
1317 fprintf (gcov_file, "%12ld %s", line_counts[count],
1320 fprintf (gcov_file, " ###### %s", string);
1323 fprintf (gcov_file, "\t\t%s", string);
1325 /* In case the source file line is larger than our buffer, keep
1326 reading and outputting lines until we get a newline. */
1327 len = strlen (string);
1328 while ((len == 0 || string[strlen (string) - 1] != '\n')
1331 retval = fgets (string, STRING_SIZE, source_file);
1332 fputs (string, gcov_file);
1335 if (output_branch_probs)
1337 for (i = 0, a_ptr = branch_probs[count]; a_ptr;
1338 a_ptr = a_ptr->next, i++)
1340 if (a_ptr->call_insn)
1342 if (a_ptr->prob == -1)
1343 fnotice (gcov_file, "call %d never executed\n", i);
1346 "call %d returns = %d%%\n",
1347 i, 100 - a_ptr->prob);
1351 if (a_ptr->prob == -1)
1352 fnotice (gcov_file, "branch %d never executed\n",
1355 fnotice (gcov_file, "branch %d taken = %d%%\n", i,
1361 /* Gracefully handle errors while reading the source file. */
1365 "Unexpected EOF while reading source file %s.\n",
1371 /* Handle all remaining source lines. There may be lines
1372 after the last line of code. */
1375 char *retval = fgets (string, STRING_SIZE, source_file);
1376 while (retval != NULL)
1380 fprintf (gcov_file, "\t\t%s", string);
1382 /* In case the source file line is larger than our buffer, keep
1383 reading and outputting lines until we get a newline. */
1384 len = strlen (string);
1385 while ((len == 0 || string[strlen (string) - 1] != '\n')
1388 retval = fgets (string, STRING_SIZE, source_file);
1389 fputs (string, gcov_file);
1392 retval = fgets (string, STRING_SIZE, source_file);
1396 fclose (source_file);