Index: ChangeLog
[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, 2002 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 #include "version.h"
50 #undef abort
51
52 #include <getopt.h>
53
54 typedef HOST_WIDEST_INT gcov_type;
55 #include "gcov-io.h"
56
57 /* The .bb file format consists of several lists of 4-byte integers
58 which are the line numbers of each basic block in the file. Each
59 list is terminated by a zero. These lists correspond to the basic
60 blocks in the reconstructed program flow graph.
61
62 A line number of -1 indicates that a source file name (padded to a
63 long boundary) follows. The padded file name is followed by
64 another -1 to make it easy to scan past file names. A -2 indicates
65 that a function name (padded to a long boundary) follows; the name
66 is followed by another -2 to make it easy to scan past the function
67 name.
68
69 The .bbg file contains enough info to enable gcov to reconstruct the
70 program flow graph. The first word is the number of basic blocks,
71 the second word is the number of arcs, followed by the list of arcs
72 (source bb, dest bb pairs), then a -1, then the number of instrumented
73 arcs followed by the instrumented arcs, followed by another -1. This
74 is repeated for each function.
75
76 The .da file contains the execution count for each instrumented branch.
77
78 The .bb and .bbg files are created by giving GCC the -ftest-coverage option,
79 and the .da files are created when an executable compiled with
80 -fprofile-arcs is run. */
81
82 /* The functions in this file for creating and solution program flow graphs
83 are very similar to functions in the gcc source file profile.c. */
84
85 /* This is the size of the buffer used to read in source file lines. */
86
87 #define STRING_SIZE 200
88
89 /* One copy of this structure is created for each source file mentioned in the
90 .bb file. */
91
92 struct sourcefile
93 {
94 char *name;
95 int maxlineno;
96 struct sourcefile *next;
97 };
98
99 /* This points to the head of the sourcefile structure list. */
100
101 struct sourcefile *sources;
102
103 /* One of these is dynamically created whenever we identify an arc in the
104 function. */
105
106 struct adj_list
107 {
108 int source;
109 int target;
110 gcov_type arc_count;
111 unsigned int count_valid : 1;
112 unsigned int on_tree : 1;
113 unsigned int fake : 1;
114 unsigned int fall_through : 1;
115 #if 0
116 /* Not needed for gcov, but defined in profile.c. */
117 rtx branch_insn;
118 #endif
119 struct adj_list *pred_next;
120 struct adj_list *succ_next;
121 };
122
123 /* Count the number of basic blocks, and create an array of these structures,
124 one for each bb in the function. */
125
126 struct bb_info
127 {
128 struct adj_list *succ;
129 struct adj_list *pred;
130 gcov_type succ_count;
131 gcov_type pred_count;
132 gcov_type exec_count;
133 unsigned int count_valid : 1;
134 unsigned int on_tree : 1;
135 #if 0
136 /* Not needed for gcov, but defined in profile.c. */
137 rtx first_insn;
138 #endif
139 };
140
141 /* When outputting branch probabilities, one of these structures is created
142 for each branch/call. */
143
144 struct arcdata
145 {
146 gcov_type hits;
147 gcov_type total;
148 int call_insn;
149 struct arcdata *next;
150 };
151
152 /* Used to save the list of bb_graphs, one per function. */
153
154 struct bb_info_list
155 {
156 /* Indexed by block number, holds the basic block graph for one function. */
157 struct bb_info *bb_graph;
158 int num_blocks;
159 struct bb_info_list *next;
160 };
161
162 /* Used to hold information about each line. */
163 struct line_info
164 {
165 gcov_type count; /* execution count */
166 struct arcdata *branches; /* list of branch probabilities for line. */
167 unsigned exists : 1; /* has code associated with it. */
168 };
169
170 struct coverage
171 {
172 int lines;
173 int lines_executed;
174
175 int branches;
176 int branches_executed;
177 int branches_taken;
178
179 int calls;
180 int calls_executed;
181
182 char *name;
183 };
184
185 /* Holds a list of function basic block graphs. */
186
187 static struct bb_info_list *bb_graph_list = 0;
188
189 /* Modification time of data files. */
190
191 static time_t bb_file_time;
192
193 /* Name and file pointer of the input file for the basic block graph. */
194
195 static char *bbg_file_name;
196 static FILE *bbg_file;
197
198 /* Name and file pointer of the input file for the arc count data. */
199
200 static char *da_file_name;
201 static FILE *da_file;
202
203 /* Name and file pointer of the input file for the basic block line counts. */
204
205 static char *bb_file_name;
206 static FILE *bb_file;
207
208 /* Holds the entire contents of the bb_file read into memory. */
209
210 static char *bb_data;
211
212 /* Size of bb_data array in longs. */
213
214 static long bb_data_size;
215
216 /* Name of the file mentioned on the command line. */
217
218 static char *input_file_name = 0;
219
220 /* Output branch probabilities if true. */
221
222 static int output_branch_probs = 0;
223
224 /* Output a gcov file if this is true. This is on by default, and can
225 be turned off by the -n option. */
226
227 static int output_gcov_file = 1;
228
229 /* For included files, make the gcov output file name include the name of
230 the input source file. For example, if x.h is included in a.c, then the
231 output file name is a.c.x.h.gcov instead of x.h.gcov. This works only
232 when a single source file is specified. */
233
234 static int output_long_names = 0;
235
236 /* Output summary info for each function. */
237
238 static int output_function_summary = 0;
239
240 /* Object directory file prefix. This is the directory/file
241 where .bb and .bbg files are looked for, if nonzero. */
242
243 static char *object_directory = 0;
244
245 /* Preserve all pathname components. Needed when object files and
246 source files are in subdirectories. */
247 static int preserve_paths = 0;
248
249 /* Output the number of times a branch was taken as opposed to the percentage
250 of times it was taken. Turned on by the -c option */
251
252 static int output_branch_counts = 0;
253
254 /* Forward declarations. */
255 static void process_args PARAMS ((int, char **));
256 static void open_files PARAMS ((void));
257 static void read_files PARAMS ((void));
258 static void scan_for_source_files PARAMS ((void));
259 static void output_data PARAMS ((struct sourcefile *));
260 static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
261 static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
262 static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
263 static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
264 static gcov_type *read_profile PARAMS ((char *, long, int));
265 static void create_program_flow_graph PARAMS ((struct bb_info_list *));
266 static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
267 static void accumulate_branch_counts PARAMS ((struct coverage *,
268 struct arcdata *));
269 static void calculate_branch_probs PARAMS ((struct bb_info *,
270 struct line_info *,
271 struct coverage *));
272 static void function_summary PARAMS ((struct coverage *, const char *));
273 static void init_line_info PARAMS ((struct line_info *,
274 struct coverage *, long));
275 static void output_line_info PARAMS ((FILE *, const struct line_info *,
276 const struct coverage *, long));
277 static char *make_gcov_file_name PARAMS ((char *));
278 static const char *format_hwint PARAMS ((HOST_WIDEST_INT, HOST_WIDEST_INT,
279 int));
280
281 extern int main PARAMS ((int, char **));
282
283 int
284 main (argc, argv)
285 int argc;
286 char **argv;
287 {
288 struct sourcefile *s_ptr;
289
290 gcc_init_libintl ();
291
292 process_args (argc, argv);
293
294 open_files ();
295
296 read_files ();
297
298 scan_for_source_files ();
299
300 for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
301 output_data (s_ptr);
302
303 return 0;
304 }
305
306 static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
307 static void
308 fnotice VPARAMS ((FILE *file, const char *msgid, ...))
309 {
310 VA_OPEN (ap, msgid);
311 VA_FIXEDARG (ap, FILE *, file);
312 VA_FIXEDARG (ap, const char *, msgid);
313
314 vfprintf (file, _(msgid), ap);
315 VA_CLOSE (ap);
316 }
317
318 /* More 'friendly' abort that prints the line and file.
319 config.h can #define abort fancy_abort if you like that sort of thing. */
320 extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
321
322 void
323 fancy_abort ()
324 {
325 fnotice (stderr, "Internal gcov abort.\n");
326 exit (FATAL_EXIT_CODE);
327 }
328 \f
329 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
330 otherwise the output of --help. */
331
332 static void
333 print_usage (error_p)
334 int error_p;
335 {
336 FILE *file = error_p ? stderr : stdout;
337 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
338 fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
339 fnotice (file, "Print code coverage information.\n\n");
340 fnotice (file, " -h, --help Print this help, then exit\n");
341 fnotice (file, " -v, --version Print version number, then exit\n");
342 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
343 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
344 rather than percentages\n");
345 fnotice (file, " -n, --no-output Do not create an output file\n");
346 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
347 source files\n");
348 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
349 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
350 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
351 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
352 bug_report_url);
353 exit (status);
354 }
355
356 /* Print version information and exit. */
357
358 static void
359 print_version ()
360 {
361 fnotice (stdout, "gcov (GCC) %s\n", version_string);
362 fnotice (stdout, "Copyright (C) 2001 Free Software Foundation, Inc.\n");
363 fnotice (stdout,
364 "This is free software; see the source for copying conditions. There is NO\n\
365 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
366 exit (SUCCESS_EXIT_CODE);
367 }
368
369 static const struct option options[] =
370 {
371 { "help", no_argument, NULL, 'h' },
372 { "version", no_argument, NULL, 'v' },
373 { "branch-probabilities", no_argument, NULL, 'b' },
374 { "branch-counts", no_argument, NULL, 'c' },
375 { "no-output", no_argument, NULL, 'n' },
376 { "long-file-names", no_argument, NULL, 'l' },
377 { "function-summaries", no_argument, NULL, 'f' },
378 { "preserve-paths", no_argument, NULL, 'p' },
379 { "object-directory", required_argument, NULL, 'o' },
380 { "object-file", required_argument, NULL, 'o' },
381 };
382
383 /* Parse the command line. */
384
385 static void
386 process_args (argc, argv)
387 int argc;
388 char **argv;
389 {
390 int opt;
391
392 while ((opt = getopt_long (argc, argv, "hvbclnfo:p", options, NULL)) != -1)
393 {
394 switch (opt)
395 {
396 case 'h':
397 print_usage (false);
398 /* print_usage will exit. */
399 case 'v':
400 print_version ();
401 /* print_version will exit. */
402 case 'b':
403 output_branch_probs = 1;
404 break;
405 case 'c':
406 output_branch_counts = 1;
407 break;
408 case 'n':
409 output_gcov_file = 0;
410 break;
411 case 'l':
412 output_long_names = 1;
413 break;
414 case 'f':
415 output_function_summary = 1;
416 break;
417 case 'o':
418 object_directory = optarg;
419 break;
420 case 'p':
421 preserve_paths = 1;
422 break;
423 default:
424 print_usage (true);
425 /* print_usage will exit. */
426 }
427 }
428
429 if (optind != argc - 1)
430 print_usage (true);
431
432 input_file_name = argv[optind];
433 }
434
435
436 /* Find and open the .bb, .da, and .bbg files. If OBJECT_DIRECTORY is
437 not specified, these are looked for in the current directory, and
438 named from the basename of the input_file_name sans extension. If
439 OBJECT_DIRECTORY is specified and is a directory, the files are in
440 that directory, but named from the basename of the input_file_name,
441 sans extension. Otherwise OBJECT_DIRECTORY is taken to be the name
442 of the object *file*, and the data files are named from that. */
443
444 static void
445 open_files ()
446 {
447 char *cptr;
448 char *name;
449 int length = strlen (input_file_name);
450 int base;
451
452 if (object_directory && object_directory[0])
453 {
454 struct stat status;
455
456 length += strlen (object_directory) + 2;
457 name = xmalloc (length);
458 name[0] = 0;
459
460 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
461 strcat (name, object_directory);
462 if (base && name[strlen (name) - 1] != '/')
463 strcat (name, "/");
464 }
465 else
466 {
467 name = xmalloc (length + 1);
468 name[0] = 0;
469 base = 1;
470 }
471
472 if (base)
473 {
474 /* Append source file name */
475 cptr = strrchr (input_file_name, '/');
476 cptr = cptr ? cptr + 1 : input_file_name;
477
478 strcat (name, cptr);
479 }
480 /* Remove the extension. */
481 cptr = strrchr (name, '.');
482 if (cptr)
483 *cptr = 0;
484
485 length = strlen (name);
486 da_file_name = xmalloc (length + 4);
487 bb_file_name = xmalloc (length + 4);
488 bbg_file_name = xmalloc (length + 5);
489
490 strcpy (da_file_name, name);
491 strcpy (bb_file_name, name);
492 strcpy (bbg_file_name, name);
493 strcpy (da_file_name + length, ".da");
494 strcpy (bb_file_name + length, ".bb");
495 strcpy (bbg_file_name + length, ".bbg");
496
497 bb_file = fopen (bb_file_name, "rb");
498 if (bb_file == NULL)
499 {
500 fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
501 exit (FATAL_EXIT_CODE);
502 }
503
504 bbg_file = fopen (bbg_file_name, "rb");
505 if (bbg_file == NULL)
506 {
507 fnotice (stderr, "Could not open program flow graph file %s.\n",
508 bbg_file_name);
509 exit (FATAL_EXIT_CODE);
510 }
511
512 {
513 struct stat status;
514
515 if (!fstat (fileno (bb_file), &status))
516 bb_file_time = status.st_mtime;
517 }
518
519 /* If none of the functions in the file were executed, then there won't
520 be a .da file. Just assume that all counts are zero in this case. */
521 da_file = fopen (da_file_name, "rb");
522 if (da_file == NULL)
523 {
524 fnotice (stderr, "Could not open data file %s.\n", da_file_name);
525 fnotice (stderr, "Assuming that all execution counts are zero.\n");
526 }
527
528 /* Check for empty .bbg file. This indicates that there is no executable
529 code in this source file. */
530 /* Set the EOF condition if at the end of file. */
531 ungetc (getc (bbg_file), bbg_file);
532 if (feof (bbg_file))
533 {
534 fnotice (stderr, "No executable code associated with file %s.\n",
535 input_file_name);
536 exit (FATAL_EXIT_CODE);
537 }
538 }
539 \f
540 /* Initialize a new arc. */
541
542 static void
543 init_arc (arcptr, source, target, bb_graph)
544 struct adj_list *arcptr;
545 int source, target;
546 struct bb_info *bb_graph;
547 {
548 arcptr->target = target;
549 arcptr->source = source;
550
551 arcptr->arc_count = 0;
552 arcptr->count_valid = 0;
553 arcptr->on_tree = 0;
554 arcptr->fake = 0;
555 arcptr->fall_through = 0;
556
557 arcptr->succ_next = bb_graph[source].succ;
558 bb_graph[source].succ = arcptr;
559 bb_graph[source].succ_count++;
560
561 arcptr->pred_next = bb_graph[target].pred;
562 bb_graph[target].pred = arcptr;
563 bb_graph[target].pred_count++;
564 }
565
566 /* Reverse the arcs on an arc list. */
567
568 static struct adj_list *
569 reverse_arcs (arcptr)
570 struct adj_list *arcptr;
571 {
572 struct adj_list *prev = 0;
573 struct adj_list *next;
574
575 for ( ; arcptr; arcptr = next)
576 {
577 next = arcptr->succ_next;
578 arcptr->succ_next = prev;
579 prev = arcptr;
580 }
581
582 return prev;
583 }
584
585 /* Reads profiles from the .da file and compute a hybrid profile. */
586
587 static gcov_type *
588 read_profile (function_name, cfg_checksum, instr_arcs)
589 char *function_name;
590 long cfg_checksum;
591 int instr_arcs;
592 {
593 int i;
594 int okay = 1;
595 gcov_type *profile;
596 char *function_name_buffer;
597 int function_name_buffer_len;
598
599 profile = xmalloc (sizeof (gcov_type) * instr_arcs);
600 function_name_buffer_len = strlen (function_name) + 1;
601 function_name_buffer = xmalloc (function_name_buffer_len + 1);
602
603 for (i = 0; i < instr_arcs; i++)
604 profile[i] = 0;
605
606 if (!da_file)
607 return profile;
608
609 rewind (da_file);
610 while (1)
611 {
612 long magic, extra_bytes;
613 long func_count;
614 int i;
615
616 if (__read_long (&magic, da_file, 4) != 0)
617 break;
618
619 if (magic != -123)
620 {
621 okay = 0;
622 break;
623 }
624
625 if (__read_long (&func_count, da_file, 4) != 0)
626 {
627 okay = 0;
628 break;
629 }
630
631 if (__read_long (&extra_bytes, da_file, 4) != 0)
632 {
633 okay = 0;
634 break;
635 }
636
637 /* skip extra data emited by __bb_exit_func. */
638 fseek (da_file, extra_bytes, SEEK_CUR);
639
640 for (i = 0; i < func_count; i++)
641 {
642 long arc_count;
643 long chksum;
644 int j;
645
646 if (__read_gcov_string
647 (function_name_buffer, function_name_buffer_len, da_file,
648 -1) != 0)
649 {
650 okay = 0;
651 break;
652 }
653
654 if (__read_long (&chksum, da_file, 4) != 0)
655 {
656 okay = 0;
657 break;
658 }
659
660 if (__read_long (&arc_count, da_file, 4) != 0)
661 {
662 okay = 0;
663 break;
664 }
665
666 if (strcmp (function_name_buffer, function_name) != 0
667 || arc_count != instr_arcs || chksum != cfg_checksum)
668 {
669 /* skip */
670 if (fseek (da_file, arc_count * 8, SEEK_CUR) < 0)
671 {
672 okay = 0;
673 break;
674 }
675 }
676 else
677 {
678 gcov_type tmp;
679
680 for (j = 0; j < arc_count; j++)
681 if (__read_gcov_type (&tmp, da_file, 8) != 0)
682 {
683 okay = 0;
684 break;
685 }
686 else
687 {
688 profile[j] += tmp;
689 }
690 }
691 }
692
693 if (!okay)
694 break;
695
696 }
697
698 free (function_name_buffer);
699
700 if (!okay)
701 {
702 fprintf (stderr, ".da file corrupted!\n");
703 free (profile);
704 abort ();
705 }
706
707 return profile;
708 }
709
710 /* Construct the program flow graph from the .bbg file, and read in the data
711 in the .da file. */
712
713 static void
714 create_program_flow_graph (bptr)
715 struct bb_info_list *bptr;
716 {
717 long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
718 int i;
719 struct adj_list *arcptr;
720 struct bb_info *bb_graph;
721 long cfg_checksum;
722 long instr_arcs = 0;
723 gcov_type *profile;
724 int profile_pos = 0;
725 char *function_name;
726 long function_name_len, tmp;
727
728 /* Read function name. */
729 __read_long (&tmp, bbg_file, 4); /* ignore -1. */
730 __read_long (&function_name_len, bbg_file, 4);
731 function_name = xmalloc (function_name_len + 1);
732 fread (function_name, 1, function_name_len + 1, bbg_file);
733
734 /* Skip padding. */
735 tmp = (function_name_len + 1) % 4;
736
737 if (tmp)
738 fseek (bbg_file, 4 - tmp, SEEK_CUR);
739
740 __read_long (&tmp, bbg_file, 4); /* ignore -1. */
741
742 /* Read the cfg checksum. */
743 __read_long (&cfg_checksum, bbg_file, 4);
744
745 /* Read the number of blocks. */
746 __read_long (&num_blocks, bbg_file, 4);
747
748 /* Create an array of size bb number of bb_info structs. */
749 bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
750
751 bptr->bb_graph = bb_graph;
752 bptr->num_blocks = num_blocks;
753
754 /* Read and create each arc from the .bbg file. */
755 __read_long (&number_arcs, bbg_file, 4);
756 for (i = 0; i < num_blocks; i++)
757 {
758 int j;
759
760 __read_long (&num_arcs_per_block, bbg_file, 4);
761 for (j = 0; j < num_arcs_per_block; j++)
762 {
763 if (number_arcs-- < 0)
764 abort ();
765
766 src = i;
767 __read_long (&dest, bbg_file, 4);
768
769 arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
770 init_arc (arcptr, src, dest, bb_graph);
771
772 __read_long (&flag_bits, bbg_file, 4);
773 if (flag_bits & 0x1)
774 arcptr->on_tree++;
775 else
776 instr_arcs++;
777 arcptr->fake = !! (flag_bits & 0x2);
778 arcptr->fall_through = !! (flag_bits & 0x4);
779 }
780 }
781
782 if (number_arcs)
783 abort ();
784
785 /* Read and ignore the -1 separating the arc list from the arc list of the
786 next function. */
787 __read_long (&src, bbg_file, 4);
788 if (src != -1)
789 abort ();
790
791 /* Must reverse the order of all succ arcs, to ensure that they match
792 the order of the data in the .da file. */
793
794 for (i = 0; i < num_blocks; i++)
795 if (bb_graph[i].succ)
796 bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
797
798 /* Read profile from the .da file. */
799
800 profile = read_profile (function_name, cfg_checksum, instr_arcs);
801
802 /* For each arc not on the spanning tree, set its execution count from
803 the .da file. */
804
805 /* The first count in the .da file is the number of times that the function
806 was entered. This is the exec_count for block zero. */
807
808 /* This duplicates code in branch_prob in profile.c. */
809
810 for (i = 0; i < num_blocks; i++)
811 for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
812 if (! arcptr->on_tree)
813 {
814 arcptr->arc_count = profile[profile_pos++];
815 arcptr->count_valid = 1;
816 bb_graph[i].succ_count--;
817 bb_graph[arcptr->target].pred_count--;
818 }
819 free (profile);
820 free (function_name);
821 }
822
823 static void
824 solve_program_flow_graph (bptr)
825 struct bb_info_list *bptr;
826 {
827 int passes, changes;
828 gcov_type total;
829 int i;
830 struct adj_list *arcptr;
831 struct bb_info *bb_graph;
832 int num_blocks;
833
834 num_blocks = bptr->num_blocks;
835 bb_graph = bptr->bb_graph;
836
837 /* For every block in the file,
838 - if every exit/entrance arc has a known count, then set the block count
839 - if the block count is known, and every exit/entrance arc but one has
840 a known execution count, then set the count of the remaining arc
841
842 As arc counts are set, decrement the succ/pred count, but don't delete
843 the arc, that way we can easily tell when all arcs are known, or only
844 one arc is unknown. */
845
846 /* The order that the basic blocks are iterated through is important.
847 Since the code that finds spanning trees starts with block 0, low numbered
848 arcs are put on the spanning tree in preference to high numbered arcs.
849 Hence, most instrumented arcs are at the end. Graph solving works much
850 faster if we propagate numbers from the end to the start.
851
852 This takes an average of slightly more than 3 passes. */
853
854 changes = 1;
855 passes = 0;
856 while (changes)
857 {
858 passes++;
859 changes = 0;
860
861 for (i = num_blocks - 1; i >= 0; i--)
862 {
863 if (! bb_graph[i].count_valid)
864 {
865 if (bb_graph[i].succ_count == 0)
866 {
867 total = 0;
868 for (arcptr = bb_graph[i].succ; arcptr;
869 arcptr = arcptr->succ_next)
870 total += arcptr->arc_count;
871 bb_graph[i].exec_count = total;
872 bb_graph[i].count_valid = 1;
873 changes = 1;
874 }
875 else if (bb_graph[i].pred_count == 0)
876 {
877 total = 0;
878 for (arcptr = bb_graph[i].pred; arcptr;
879 arcptr = arcptr->pred_next)
880 total += arcptr->arc_count;
881 bb_graph[i].exec_count = total;
882 bb_graph[i].count_valid = 1;
883 changes = 1;
884 }
885 }
886 if (bb_graph[i].count_valid)
887 {
888 if (bb_graph[i].succ_count == 1)
889 {
890 total = 0;
891 /* One of the counts will be invalid, but it is zero,
892 so adding it in also doesn't hurt. */
893 for (arcptr = bb_graph[i].succ; arcptr;
894 arcptr = arcptr->succ_next)
895 total += arcptr->arc_count;
896 /* Calculate count for remaining arc by conservation. */
897 total = bb_graph[i].exec_count - total;
898 /* Search for the invalid arc, and set its count. */
899 for (arcptr = bb_graph[i].succ; arcptr;
900 arcptr = arcptr->succ_next)
901 if (! arcptr->count_valid)
902 break;
903 if (! arcptr)
904 abort ();
905 arcptr->count_valid = 1;
906 arcptr->arc_count = total;
907 bb_graph[i].succ_count--;
908
909 bb_graph[arcptr->target].pred_count--;
910 changes = 1;
911 }
912 if (bb_graph[i].pred_count == 1)
913 {
914 total = 0;
915 /* One of the counts will be invalid, but it is zero,
916 so adding it in also doesn't hurt. */
917 for (arcptr = bb_graph[i].pred; arcptr;
918 arcptr = arcptr->pred_next)
919 total += arcptr->arc_count;
920 /* Calculate count for remaining arc by conservation. */
921 total = bb_graph[i].exec_count - total;
922 /* Search for the invalid arc, and set its count. */
923 for (arcptr = bb_graph[i].pred; arcptr;
924 arcptr = arcptr->pred_next)
925 if (! arcptr->count_valid)
926 break;
927 if (! arcptr)
928 abort ();
929 arcptr->count_valid = 1;
930 arcptr->arc_count = total;
931 bb_graph[i].pred_count--;
932
933 bb_graph[arcptr->source].succ_count--;
934 changes = 1;
935 }
936 }
937 }
938 }
939
940 /* If the graph has been correctly solved, every block will have a
941 succ and pred count of zero. */
942 for (i = 0; i < num_blocks; i++)
943 if (bb_graph[i].succ_count || bb_graph[i].pred_count)
944 abort ();
945 }
946
947
948 static void
949 read_files ()
950 {
951 struct stat buf;
952 struct bb_info_list *list_end = 0;
953 struct bb_info_list *b_ptr;
954
955 while (! feof (bbg_file))
956 {
957 b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
958
959 b_ptr->next = 0;
960 if (list_end)
961 list_end->next = b_ptr;
962 else
963 bb_graph_list = b_ptr;
964 list_end = b_ptr;
965
966 /* Read in the data in the .bbg file and reconstruct the program flow
967 graph for one function. */
968 create_program_flow_graph (b_ptr);
969
970 /* Set the EOF condition if at the end of file. */
971 ungetc (getc (bbg_file), bbg_file);
972 }
973
974 /* Calculate all of the basic block execution counts and branch
975 taken probabilities. */
976
977 for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
978 solve_program_flow_graph (b_ptr);
979
980 /* Read in all of the data from the .bb file. This info will be accessed
981 sequentially twice. */
982 stat (bb_file_name, &buf);
983 bb_data_size = buf.st_size / 4;
984
985 bb_data = (char *) xmalloc ((unsigned) buf.st_size);
986 fread (bb_data, sizeof (char), buf.st_size, bb_file);
987
988 fclose (bb_file);
989 if (da_file)
990 fclose (da_file);
991 fclose (bbg_file);
992 }
993
994
995 /* Scan the data in the .bb file to find all source files referenced,
996 and the largest line number mentioned in each one. */
997
998 static void
999 scan_for_source_files ()
1000 {
1001 struct sourcefile *s_ptr = NULL;
1002 char *ptr;
1003 long count;
1004 long line_num;
1005
1006 /* Search the bb_data to find:
1007 1) The number of sources files contained herein, and
1008 2) The largest line number for each source file. */
1009
1010 ptr = bb_data;
1011 sources = 0;
1012 for (count = 0; count < bb_data_size; count++)
1013 {
1014 __fetch_long (&line_num, ptr, 4);
1015 ptr += 4;
1016 if (line_num == -1)
1017 {
1018 /* A source file name follows. Check to see if we already have
1019 a sourcefile structure for this file. */
1020 s_ptr = sources;
1021 while (s_ptr && strcmp (s_ptr->name, ptr))
1022 s_ptr = s_ptr->next;
1023
1024 if (s_ptr == 0)
1025 {
1026 /* No sourcefile structure for this file name exists, create
1027 a new one, and append it to the front of the sources list. */
1028 s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
1029 s_ptr->name = xstrdup (ptr);
1030 s_ptr->maxlineno = 0;
1031 s_ptr->next = sources;
1032 sources = s_ptr;
1033 }
1034
1035 /* Scan past the file name. */
1036 {
1037 long delim;
1038 do {
1039 count++;
1040 __fetch_long (&delim, ptr, 4);
1041 ptr += 4;
1042 } while (delim != line_num);
1043 }
1044 }
1045 else if (line_num == -2)
1046 {
1047 long delim;
1048
1049 /* A function name follows. Ignore it. */
1050 do {
1051 count++;
1052 __fetch_long (&delim, ptr, 4);
1053 ptr += 4;
1054 } while (delim != line_num);
1055 }
1056 /* There will be a zero before the first file name, in which case s_ptr
1057 will still be uninitialized. So, only try to set the maxlineno
1058 field if line_num is nonzero. */
1059 else if (line_num > 0)
1060 {
1061 if (s_ptr->maxlineno <= line_num)
1062 s_ptr->maxlineno = line_num + 1;
1063 }
1064 else if (line_num < 0)
1065 {
1066 /* Don't know what this is, but it's garbage. */
1067 abort ();
1068 }
1069 }
1070 }
1071 \f
1072
1073 /* Increment totals in FUNCTION according to arc A_PTR. */
1074
1075 static void
1076 accumulate_branch_counts (function, a_ptr)
1077 struct coverage *function;
1078 struct arcdata *a_ptr;
1079 {
1080 if (a_ptr->call_insn)
1081 {
1082 function->calls++;
1083 if (a_ptr->total)
1084 function->calls_executed++;
1085 }
1086 else
1087 {
1088 function->branches++;
1089 if (a_ptr->total)
1090 function->branches_executed++;
1091 if (a_ptr->hits)
1092 function->branches_taken++;
1093 }
1094 }
1095
1096 /* Calculate the branch taken probabilities for all arcs branches at the
1097 end of this block. */
1098
1099 static void
1100 calculate_branch_probs (block_ptr, line_info, function)
1101 struct bb_info *block_ptr;
1102 struct line_info *line_info;
1103 struct coverage *function;
1104 {
1105 gcov_type total;
1106 struct adj_list *arcptr;
1107
1108 total = block_ptr->exec_count;
1109 for (arcptr = block_ptr->succ; arcptr; arcptr = arcptr->succ_next)
1110 {
1111 struct arcdata *a_ptr;
1112
1113 /* Ignore fall through arcs as they aren't really branches. */
1114 if (arcptr->fall_through)
1115 continue;
1116
1117 a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
1118 a_ptr->total = total;
1119 a_ptr->hits = total ? arcptr->arc_count : 0;
1120 a_ptr->call_insn = arcptr->fake;
1121
1122 if (function)
1123 accumulate_branch_counts (function, a_ptr);
1124 /* Prepend the new branch to the list. */
1125 a_ptr->next = line_info->branches;
1126 line_info->branches = a_ptr;
1127 }
1128 }
1129
1130 /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1131 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1132 If DP is zero, no decimal point is printed. Only print 100% when
1133 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1134 format TOP. Return pointer to a static string. */
1135
1136 static char const *
1137 format_hwint (top, bottom, dp)
1138 HOST_WIDEST_INT top, bottom;
1139 int dp;
1140 {
1141 static char buffer[20];
1142
1143 if (dp >= 0)
1144 {
1145 float ratio = bottom ? (float)top / bottom : 0;
1146 int ix;
1147 unsigned limit = 100;
1148 unsigned percent;
1149
1150 for (ix = dp; ix--; )
1151 limit *= 10;
1152
1153 percent = (unsigned) (ratio * limit + (float)0.5);
1154 if (percent <= 0 && top)
1155 percent = 1;
1156 else if (percent >= limit && top != bottom)
1157 percent = limit - 1;
1158 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1159 if (dp)
1160 {
1161 dp++;
1162 do
1163 {
1164 buffer[ix+1] = buffer[ix];
1165 ix--;
1166 }
1167 while (dp--);
1168 buffer[ix + 1] = '.';
1169 }
1170 }
1171 else
1172 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, top);
1173
1174 return buffer;
1175 }
1176
1177
1178 /* Output summary info for a function. */
1179
1180 static void
1181 function_summary (function, title)
1182 struct coverage *function;
1183 const char *title;
1184 {
1185 if (function->lines)
1186 fnotice (stdout, "%s of %d lines executed in %s %s\n",
1187 format_hwint (function->lines_executed,
1188 function->lines, 2),
1189 function->lines, title, function->name);
1190 else
1191 fnotice (stdout, "No executable lines in %s %s\n",
1192 title, function->name);
1193
1194 if (output_branch_probs)
1195 {
1196 if (function->branches)
1197 {
1198 fnotice (stdout, "%s of %d branches executed in %s %s\n",
1199 format_hwint (function->branches_executed,
1200 function->branches, 2),
1201 function->branches, title, function->name);
1202 fnotice (stdout,
1203 "%s of %d branches taken at least once in %s %s\n",
1204 format_hwint (function->branches_taken,
1205 function->branches, 2),
1206 function->branches, title, function->name);
1207 }
1208 else
1209 fnotice (stdout, "No branches in %s %s\n", title, function->name);
1210 if (function->calls)
1211 fnotice (stdout, "%s of %d calls executed in %s %s\n",
1212 format_hwint (function->calls_executed,
1213 function->calls, 2),
1214 function->calls, title, function->name);
1215 else
1216 fnotice (stdout, "No calls in %s %s\n", title, function->name);
1217 }
1218 }
1219
1220 /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1221 affect name generation. With preserve_paths we create a filename
1222 from all path components of the source file, replacing '/' with
1223 '#', without it we simply take the basename component. With
1224 long_output_names we prepend the processed name of the input file
1225 to each output name (except when the current source file is the
1226 input file, so you don't get a double concatenation). The two
1227 components are separated by '##'. Also '.' filename components are
1228 removed and '..' components are renamed to '^'. */
1229
1230 static char *
1231 make_gcov_file_name (src_name)
1232 char *src_name;
1233 {
1234 char *cptr;
1235 char *name = xmalloc (strlen (src_name) + strlen (input_file_name) + 10);
1236
1237 name[0] = 0;
1238 if (output_long_names && strcmp (src_name, input_file_name))
1239 {
1240 /* Generate the input filename part. */
1241 cptr = preserve_paths ? NULL : strrchr (input_file_name, '/');
1242 cptr = cptr ? cptr + 1 : input_file_name;
1243 strcat (name, cptr);
1244 strcat (name, "##");
1245 }
1246
1247 /* Generate the source filename part. */
1248 cptr = preserve_paths ? NULL : strrchr (src_name, '/');
1249 cptr = cptr ? cptr + 1 : src_name;
1250 strcat (name, cptr);
1251
1252 if (preserve_paths)
1253 {
1254 /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1255 char *prev;
1256
1257 for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
1258 {
1259 unsigned shift = 0;
1260
1261 if (prev + 1 == cptr && prev[0] == '.')
1262 {
1263 /* Remove '.' */
1264 shift = 2;
1265 }
1266 else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
1267 {
1268 /* Convert '..' */
1269 shift = 1;
1270 prev[1] = '^';
1271 }
1272 else
1273 *cptr++ = '#';
1274 if (shift)
1275 {
1276 cptr = prev;
1277 do
1278 prev[0] = prev[shift];
1279 while (*prev++);
1280 }
1281 }
1282 }
1283
1284 /* Don't strip off the ending for compatibility with tcov, since
1285 this results in confusion if there is more than one file with the
1286 same basename, e.g. tmp.c and tmp.h. */
1287 strcat (name, ".gcov");
1288 return name;
1289 }
1290
1291 /* Scan through the bb_data, and when the file name matches the
1292 source file name, then for each following line number, increment
1293 the line number execution count indicated by the execution count of
1294 the appropriate basic block. */
1295
1296 static void
1297 init_line_info (line_info, total, maxlineno)
1298 struct line_info *line_info;
1299 struct coverage *total;
1300 long maxlineno;
1301 {
1302 long block_num = 0; /* current block number */
1303 struct bb_info *block_ptr = NULL; /* current block ptr */
1304 struct coverage function;
1305 struct coverage *func_ptr = NULL;
1306 struct bb_info_list *current_graph = NULL; /* Graph for current function. */
1307 int is_this_file = 0; /* We're scanning a block from the desired file. */
1308 char *ptr = bb_data;
1309 long count;
1310 long line_num;
1311 struct line_info *line_ptr = 0; /* line info ptr. */
1312
1313 memset (&function, 0, sizeof (function));
1314 if (output_function_summary)
1315 func_ptr = &function;
1316
1317 for (count = 0; count < bb_data_size; count++)
1318 {
1319 __fetch_long (&line_num, ptr, 4);
1320 ptr += 4;
1321 if (line_num < 0)
1322 {
1323 long delim;
1324
1325 if (line_num == -1)
1326 {
1327 /* Marks the beginning of a file name. Check to see
1328 whether this is the filename we are currently
1329 collecting data for. */
1330 is_this_file = !strcmp (total->name, ptr);
1331 }
1332 else if (line_num == -2)
1333 {
1334 /* Marks the start of a new function. Advance to the
1335 next program flow graph. */
1336 if (!current_graph)
1337 current_graph = bb_graph_list;
1338 else
1339 {
1340 if (block_num == current_graph->num_blocks - 1)
1341 /* Last block falls through to exit. */
1342 ;
1343 else if (block_num == current_graph->num_blocks - 2)
1344 {
1345 if (output_branch_probs && is_this_file)
1346 calculate_branch_probs (block_ptr, line_ptr, func_ptr);
1347 }
1348 else
1349 {
1350 fnotice (stderr,
1351 "didn't use all bb entries of graph, function %s\n",
1352 function.name);
1353 fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
1354 block_num, current_graph->num_blocks);
1355 }
1356 if (func_ptr && is_this_file)
1357 function_summary (func_ptr, "function");
1358 current_graph = current_graph->next;
1359 }
1360 block_num = 0;
1361 block_ptr = current_graph->bb_graph;
1362 memset (&function, 0, sizeof (function));
1363 function.name = ptr;
1364 }
1365 else
1366 {
1367 fnotice (stderr, "ERROR: unexpected line number %ld\n", line_num);
1368 abort ();
1369 }
1370
1371 /* Scan past the string. */
1372 for (delim = 0; delim != line_num; count++)
1373 {
1374 __fetch_long (&delim, ptr, 4);
1375 ptr += 4;
1376 }
1377 }
1378 else if (!line_num)
1379 {
1380 /* Marks the end of a block. */
1381 if (block_num >= current_graph->num_blocks)
1382 {
1383 fnotice (stderr, "ERROR: too many basic blocks in function %s\n",
1384 function.name);
1385 abort ();
1386 }
1387
1388 if (output_branch_probs && is_this_file)
1389 calculate_branch_probs (block_ptr, line_ptr, func_ptr);
1390
1391 block_num++;
1392 block_ptr++;
1393 }
1394 else if (is_this_file)
1395 {
1396 if (line_num >= maxlineno)
1397 {
1398 fnotice (stderr, "ERROR: out of range line number in function %s\n",
1399 function.name);
1400 abort ();
1401 }
1402
1403 line_ptr = &line_info[line_num];
1404 if (func_ptr)
1405 {
1406 if (!line_ptr->exists)
1407 func_ptr->lines++;
1408 if (!line_ptr->count && block_ptr->exec_count)
1409 func_ptr->lines_executed++;
1410 }
1411
1412 /* Accumulate execution data for this line number. */
1413 line_ptr->count += block_ptr->exec_count;
1414 line_ptr->exists = 1;
1415 }
1416 }
1417
1418 if (func_ptr && is_this_file)
1419 function_summary (func_ptr, "function");
1420
1421 /* Calculate summary test coverage statistics. */
1422 for (line_num = 1, line_ptr = &line_info[line_num];
1423 line_num < maxlineno; line_num++, line_ptr++)
1424 {
1425 struct arcdata *a_ptr, *prev, *next;
1426
1427 if (line_ptr->exists)
1428 {
1429 total->lines++;
1430 if (line_ptr->count)
1431 total->lines_executed++;
1432 }
1433
1434 /* Total and reverse the branch information. */
1435 for (a_ptr = line_ptr->branches, prev = NULL; a_ptr; a_ptr = next)
1436 {
1437 next = a_ptr->next;
1438 a_ptr->next = prev;
1439 prev = a_ptr;
1440
1441 accumulate_branch_counts (total, a_ptr);
1442 }
1443 line_ptr->branches = prev;
1444 }
1445 }
1446
1447 /* Read in the source file one line at a time, and output that line to
1448 the gcov file preceded by its execution count and other
1449 information. */
1450
1451 static void
1452 output_line_info (gcov_file, line_info, total, maxlineno)
1453 FILE *gcov_file;
1454 const struct line_info *line_info;
1455 const struct coverage *total;
1456 long maxlineno;
1457 {
1458 FILE *source_file;
1459 long line_num; /* current line number */
1460 const struct line_info *line_ptr; /* current line info ptr. */
1461 char string[STRING_SIZE]; /* line buffer. */
1462 char const *retval = ""; /* status of source file reading. */
1463
1464 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, total->name);
1465 fprintf (gcov_file, "%9s:%5d:Object:%s\n", "-", 0, bb_file_name);
1466
1467 source_file = fopen (total->name, "r");
1468 if (!source_file)
1469 {
1470 fnotice (stderr, "Could not open source file %s.\n", total->name);
1471 retval = NULL;
1472 }
1473 else
1474 {
1475 struct stat status;
1476
1477 if (!fstat (fileno (source_file), &status)
1478 && status.st_mtime > bb_file_time)
1479 {
1480 fnotice (stderr, "Warning: source file %s is newer than %s\n",
1481 total->name, bb_file_name);
1482 fprintf (gcov_file, "%9s:%5d:Source is newer than compiler output\n",
1483 "-", 0);
1484 }
1485 }
1486
1487 for (line_num = 1, line_ptr = &line_info[line_num];
1488 line_num < maxlineno; line_num++, line_ptr++)
1489 {
1490 /* For lines which don't exist in the .bb file, print '-' before
1491 the source line. For lines which exist but were never
1492 executed, print '#####' before the source line. Otherwise,
1493 print the execution count before the source line. There are
1494 16 spaces of indentation added before the source line so that
1495 tabs won't be messed up. */
1496 fprintf (gcov_file, "%9s:%5ld:",
1497 !line_ptr->exists ? "-"
1498 : !line_ptr->count ? "#####"
1499 : format_hwint (line_ptr->count, 0, -1), line_num);
1500
1501 if (retval)
1502 {
1503 /* Copy source line. */
1504 do
1505 {
1506 retval = fgets (string, STRING_SIZE, source_file);
1507 if (!retval)
1508 {
1509 fnotice (stderr,
1510 "Unexpected EOF while reading source file %s.\n",
1511 total->name);
1512 break;
1513 }
1514 fputs (retval, gcov_file);
1515 }
1516 while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1517 }
1518 if (!retval)
1519 fputs ("??\n", gcov_file);
1520
1521 if (output_branch_probs)
1522 {
1523 int i;
1524 struct arcdata *a_ptr;
1525
1526 for (i = 0, a_ptr = line_ptr->branches; a_ptr;
1527 a_ptr = a_ptr->next, i++)
1528 {
1529 if (a_ptr->call_insn)
1530 {
1531 if (a_ptr->total == 0)
1532 fnotice (gcov_file, "call %2d never executed\n", i);
1533 else
1534 fnotice
1535 (gcov_file, "call %2d returns %s\n", i,
1536 format_hwint (a_ptr->total - a_ptr->hits,
1537 a_ptr->total,
1538 -output_branch_counts));
1539 }
1540 else
1541 {
1542 if (a_ptr->total == 0)
1543 fnotice (gcov_file, "branch %2d never executed\n", i);
1544 else
1545 fnotice
1546 (gcov_file, "branch %2d taken %s\n", i,
1547 format_hwint (a_ptr->hits, a_ptr->total,
1548 -output_branch_counts));
1549 }
1550 }
1551 }
1552 }
1553
1554 /* Handle all remaining source lines. There may be lines after the
1555 last line of code. */
1556 if (retval)
1557 {
1558 for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
1559 {
1560 fprintf (gcov_file, "%9s:%5ld:%s", "-", line_num, retval);
1561
1562 while (!retval[0] || retval[strlen (retval) - 1] != '\n')
1563 {
1564 retval = fgets (string, STRING_SIZE, source_file);
1565 if (!retval)
1566 break;
1567 fputs (retval, gcov_file);
1568 }
1569 }
1570 }
1571
1572 if (source_file)
1573 fclose (source_file);
1574 }
1575
1576 /* Calculate line execution counts, and output a .gcov file for source
1577 file S_PTR. Allocate an array big enough to hold a count for each
1578 line. Scan through the bb_data, and when the file name matches the
1579 current file name, then for each following line number, increment
1580 the line number execution count indicated by the execution count of
1581 the appropriate basic block. */
1582
1583 static void
1584 output_data (s_ptr)
1585 struct sourcefile *s_ptr;
1586 {
1587 struct line_info *line_info /* line info data */
1588 = (struct line_info *) xcalloc (s_ptr->maxlineno,
1589 sizeof (struct line_info));
1590 long line_num;
1591 struct coverage total;
1592
1593 memset (&total, 0, sizeof (total));
1594 total.name = s_ptr->name;
1595
1596 init_line_info (line_info, &total, s_ptr->maxlineno);
1597 function_summary (&total, "file");
1598
1599 if (output_gcov_file)
1600 {
1601 /* Now the statistics are ready. Read in the source file one
1602 line at a time, and output that line to the gcov file
1603 preceded by its execution information. */
1604
1605 char *gcov_file_name = make_gcov_file_name (total.name);
1606 FILE *gcov_file = fopen (gcov_file_name, "w");
1607
1608 if (gcov_file)
1609 {
1610 fnotice (stdout, "Creating %s.\n", gcov_file_name);
1611 output_line_info (gcov_file, line_info, &total, s_ptr->maxlineno);
1612 if (ferror (gcov_file))
1613 fnotice (stderr, "Error writing output file %s.\n",
1614 gcov_file_name);
1615 fclose (gcov_file);
1616 }
1617 else
1618 fnotice (stderr, "Could not open output file %s.\n", gcov_file_name);
1619 free (gcov_file_name);
1620 }
1621
1622 /* Free data. */
1623 for (line_num = 1; line_num != s_ptr->maxlineno; line_num++)
1624 {
1625 struct arcdata *branch, *next;
1626
1627 for (branch = line_info[line_num].branches; branch; branch = next)
1628 {
1629 next = branch->next;
1630 free (branch);
1631 }
1632 }
1633 free (line_info);
1634 }