]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gcov.c
* cse.c: Fix formatting.
[thirdparty/gcc.git] / gcc / gcov.c
CommitLineData
10f2b886 1/* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file.
c773fc10 3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
dfe09cce 4 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
10f2b886 5 Contributed by James E. Wilson of Cygnus Support.
99c14947 6 Mangled by Bob Manson of Cygnus Support.
10f2b886 7
8Gcov is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
13Gcov is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with Gcov; see the file COPYING. If not, write to
7f19c2d0 20the Free Software Foundation, 59 Temple Place - Suite 330,
21Boston, MA 02111-1307, USA. */
10f2b886 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
99c14947 46#include "config.h"
1486870d 47#include "system.h"
be2828ce 48#include "intl.h"
f5fff740 49#include "version.h"
ef5ed00c 50#undef abort
10f2b886 51
f5fff740 52#include <getopt.h>
53
63f23608 54typedef HOST_WIDEST_INT gcov_type;
10f2b886 55#include "gcov-io.h"
56
10f2b886 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
10f2b886 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
92struct 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
101struct sourcefile *sources;
102
103/* One of these is dynamically created whenever we identify an arc in the
104 function. */
105
106struct adj_list {
107 int source;
108 int target;
63f23608 109 gcov_type arc_count;
10f2b886 110 unsigned int count_valid : 1;
111 unsigned int on_tree : 1;
112 unsigned int fake : 1;
113 unsigned int fall_through : 1;
114#if 0
115 /* Not needed for gcov, but defined in profile.c. */
116 rtx branch_insn;
117#endif
118 struct adj_list *pred_next;
119 struct adj_list *succ_next;
120};
121
122/* Count the number of basic blocks, and create an array of these structures,
123 one for each bb in the function. */
124
125struct bb_info {
126 struct adj_list *succ;
127 struct adj_list *pred;
63f23608 128 gcov_type succ_count;
129 gcov_type pred_count;
130 gcov_type exec_count;
10f2b886 131 unsigned int count_valid : 1;
132 unsigned int on_tree : 1;
133#if 0
134 /* Not needed for gcov, but defined in profile.c. */
135 rtx first_insn;
136#endif
137};
138
139/* When outputting branch probabilities, one of these structures is created
140 for each branch/call. */
141
142struct arcdata
143{
3f83cb00 144 gcov_type hits;
145 gcov_type total;
10f2b886 146 int call_insn;
147 struct arcdata *next;
148};
149
150/* Used to save the list of bb_graphs, one per function. */
151
152struct bb_info_list {
153 /* Indexed by block number, holds the basic block graph for one function. */
154 struct bb_info *bb_graph;
155 int num_blocks;
156 struct bb_info_list *next;
157};
158
159/* Holds a list of function basic block graphs. */
160
161static struct bb_info_list *bb_graph_list = 0;
162
163/* Name and file pointer of the input file for the basic block graph. */
164
165static char *bbg_file_name;
166static FILE *bbg_file;
167
168/* Name and file pointer of the input file for the arc count data. */
169
170static char *da_file_name;
171static FILE *da_file;
172
173/* Name and file pointer of the input file for the basic block line counts. */
174
175static char *bb_file_name;
176static FILE *bb_file;
177
178/* Holds the entire contents of the bb_file read into memory. */
179
180static char *bb_data;
181
182/* Size of bb_data array in longs. */
183
184static long bb_data_size;
185
186/* Name and file pointer of the output file. */
187
188static char *gcov_file_name;
189static FILE *gcov_file;
190
191/* Name of the file mentioned on the command line. */
192
193static char *input_file_name = 0;
194
195/* Output branch probabilities if true. */
196
197static int output_branch_probs = 0;
198
199/* Output a gcov file if this is true. This is on by default, and can
200 be turned off by the -n option. */
201
202static int output_gcov_file = 1;
203
204/* For included files, make the gcov output file name include the name of
205 the input source file. For example, if x.h is included in a.c, then the
206 output file name is a.c.x.h.gcov instead of x.h.gcov. This works only
207 when a single source file is specified. */
208
209static int output_long_names = 0;
210
211/* Output summary info for each function. */
212
213static int output_function_summary = 0;
214
215/* Object directory file prefix. This is the directory where .bb and .bbg
216 files are looked for, if non-zero. */
217
218static char *object_directory = 0;
219
887f59f0 220/* Output the number of times a branch was taken as opposed to the percentage
221 of times it was taken. Turned on by the -c option */
87e97de6 222
887f59f0 223static int output_branch_counts = 0;
224
10f2b886 225/* Forward declarations. */
621f6678 226static void process_args PARAMS ((int, char **));
227static void open_files PARAMS ((void));
228static void read_files PARAMS ((void));
229static void scan_for_source_files PARAMS ((void));
230static void output_data PARAMS ((void));
f5fff740 231static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
232static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
621f6678 233static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
234static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
235static void create_program_flow_graph PARAMS ((struct bb_info_list *));
236static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
237static void calculate_branch_probs PARAMS ((struct bb_info_list *, int,
238 struct arcdata **, int));
239static void function_summary PARAMS ((void));
240
241extern int main PARAMS ((int, char **));
10f2b886 242
243int
244main (argc, argv)
245 int argc;
246 char **argv;
247{
eb718689 248 gcc_init_libintl ();
be2828ce 249
10f2b886 250 process_args (argc, argv);
251
252 open_files ();
253
254 read_files ();
255
256 scan_for_source_files ();
257
258 output_data ();
259
260 return 0;
261}
262
621f6678 263static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
be2828ce 264static void
621f6678 265fnotice VPARAMS ((FILE *file, const char *msgid, ...))
be2828ce 266{
0903457a 267 VA_OPEN (ap, msgid);
268 VA_FIXEDARG (ap, FILE *, file);
269 VA_FIXEDARG (ap, const char *, msgid);
be2828ce 270
0cc5917f 271 vfprintf (file, _(msgid), ap);
0903457a 272 VA_CLOSE (ap);
be2828ce 273}
274
10f2b886 275/* More 'friendly' abort that prints the line and file.
276 config.h can #define abort fancy_abort if you like that sort of thing. */
621f6678 277extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
10f2b886 278
279void
280fancy_abort ()
281{
155b05dc 282 fnotice (stderr, "Internal gcov abort.\n");
10f2b886 283 exit (FATAL_EXIT_CODE);
284}
285\f
f5fff740 286/* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
287 otherwise the output of --help. */
10f2b886 288
289static void
f5fff740 290print_usage (error_p)
291 int error_p;
10f2b886 292{
f5fff740 293 FILE *file = error_p ? stderr : stdout;
294 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
295 fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
296 fnotice (file, "Print code coverage information.\n\n");
297 fnotice (file, " -h, --help Print this help, then exit\n");
298 fnotice (file, " -v, --version Print version number, then exit\n");
299 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
300 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
301 rather than percentages\n");
302 fnotice (file, " -n, --no-output Do not create an output file\n");
303 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
304 source files\n");
305 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
306 fnotice (file, " -o, --object-directory OBJDIR Search for object files in OBJDIR\n");
307 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
308 GCCBUGURL);
309 exit (status);
310}
311
312/* Print version information and exit. */
313
314static void
315print_version ()
316{
317 fnotice (stdout, "gcov (GCC) %s\n", version_string);
318 fnotice (stdout, "Copyright (C) 2001 Free Software Foundation, Inc.\n");
319 fnotice (stdout,
320 "This is free software; see the source for copying conditions. There is NO\n\
321warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
322 exit (SUCCESS_EXIT_CODE);
10f2b886 323}
324
f5fff740 325static const struct option options[] =
326{
327 { "help", no_argument, NULL, 'h' },
328 { "version", no_argument, NULL, 'v' },
329 { "branch-probabilities", no_argument, NULL, 'b' },
330 { "branch-counts", no_argument, NULL, 'c' },
331 { "no-output", no_argument, NULL, 'n' },
332 { "long-file-names", no_argument, NULL, 'l' },
333 { "function-summaries", no_argument, NULL, 'f' },
334 { "object-directory", required_argument, NULL, 'o' }
335};
336
10f2b886 337/* Parse the command line. */
338
339static void
340process_args (argc, argv)
341 int argc;
342 char **argv;
343{
f5fff740 344 int opt;
10f2b886 345
f5fff740 346 while ((opt = getopt_long (argc, argv, "hvbclnfo:", options, NULL)) != -1)
10f2b886 347 {
f5fff740 348 switch (opt)
10f2b886 349 {
f5fff740 350 case 'h':
351 print_usage (false);
352 /* print_usage will exit. */
353 case 'v':
354 print_version ();
355 /* print_version will exit. */
356 case 'b':
357 output_branch_probs = 1;
358 break;
359 case 'c':
360 output_branch_counts = 1;
361 break;
362 case 'n':
363 output_gcov_file = 0;
364 break;
365 case 'l':
366 output_long_names = 1;
367 break;
368 case 'f':
369 output_function_summary = 1;
370 break;
371 case 'o':
372 object_directory = optarg;
373 break;
374 default:
375 print_usage (true);
376 /* print_usage will exit. */
10f2b886 377 }
10f2b886 378 }
379
f5fff740 380 if (optind != argc - 1)
381 print_usage (true);
382
383 input_file_name = argv[optind];
10f2b886 384}
385
386
387/* Find and open the .bb, .da, and .bbg files. */
388
389static void
390open_files ()
391{
392 int count, objdir_count;
393 char *cptr;
394
395 /* Determine the names of the .bb, .bbg, and .da files. Strip off the
396 extension, if any, and append the new extensions. */
397 count = strlen (input_file_name);
398 if (object_directory)
399 objdir_count = strlen (object_directory);
400 else
401 objdir_count = 0;
402
403 da_file_name = xmalloc (count + objdir_count + 4);
404 bb_file_name = xmalloc (count + objdir_count + 4);
405 bbg_file_name = xmalloc (count + objdir_count + 5);
406
407 if (object_directory)
408 {
409 strcpy (da_file_name, object_directory);
410 strcpy (bb_file_name, object_directory);
411 strcpy (bbg_file_name, object_directory);
412
413 if (object_directory[objdir_count - 1] != '/')
414 {
415 strcat (da_file_name, "/");
416 strcat (bb_file_name, "/");
417 strcat (bbg_file_name, "/");
418 }
419
78dbff7c 420 cptr = strrchr (input_file_name, '/');
10f2b886 421 if (cptr)
422 {
423 strcat (da_file_name, cptr + 1);
424 strcat (bb_file_name, cptr + 1);
425 strcat (bbg_file_name, cptr + 1);
426 }
427 else
428 {
429 strcat (da_file_name, input_file_name);
430 strcat (bb_file_name, input_file_name);
431 strcat (bbg_file_name, input_file_name);
432 }
433 }
434 else
435 {
436 strcpy (da_file_name, input_file_name);
437 strcpy (bb_file_name, input_file_name);
438 strcpy (bbg_file_name, input_file_name);
439 }
440
78dbff7c 441 cptr = strrchr (bb_file_name, '.');
10f2b886 442 if (cptr)
443 strcpy (cptr, ".bb");
444 else
445 strcat (bb_file_name, ".bb");
446
78dbff7c 447 cptr = strrchr (da_file_name, '.');
10f2b886 448 if (cptr)
449 strcpy (cptr, ".da");
450 else
451 strcat (da_file_name, ".da");
452
78dbff7c 453 cptr = strrchr (bbg_file_name, '.');
10f2b886 454 if (cptr)
455 strcpy (cptr, ".bbg");
456 else
457 strcat (bbg_file_name, ".bbg");
458
155b05dc 459 bb_file = fopen (bb_file_name, "rb");
10f2b886 460 if (bb_file == NULL)
461 {
be2828ce 462 fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
d587587a 463 exit (FATAL_EXIT_CODE);
10f2b886 464 }
465
466 /* If none of the functions in the file were executed, then there won't
467 be a .da file. Just assume that all counts are zero in this case. */
155b05dc 468 da_file = fopen (da_file_name, "rb");
10f2b886 469 if (da_file == NULL)
470 {
be2828ce 471 fnotice (stderr, "Could not open data file %s.\n", da_file_name);
472 fnotice (stderr, "Assuming that all execution counts are zero.\n");
10f2b886 473 }
87e97de6 474
155b05dc 475 bbg_file = fopen (bbg_file_name, "rb");
10f2b886 476 if (bbg_file == NULL)
477 {
be2828ce 478 fnotice (stderr, "Could not open program flow graph file %s.\n",
10f2b886 479 bbg_file_name);
d587587a 480 exit (FATAL_EXIT_CODE);
10f2b886 481 }
482
483 /* Check for empty .bbg file. This indicates that there is no executable
484 code in this source file. */
485 /* Set the EOF condition if at the end of file. */
486 ungetc (getc (bbg_file), bbg_file);
487 if (feof (bbg_file))
488 {
be2828ce 489 fnotice (stderr, "No executable code associated with file %s.\n",
10f2b886 490 input_file_name);
d587587a 491 exit (FATAL_EXIT_CODE);
10f2b886 492 }
493}
494\f
495/* Initialize a new arc. */
496
497static void
498init_arc (arcptr, source, target, bb_graph)
499 struct adj_list *arcptr;
500 int source, target;
501 struct bb_info *bb_graph;
502{
503 arcptr->target = target;
504 arcptr->source = source;
505
506 arcptr->arc_count = 0;
507 arcptr->count_valid = 0;
508 arcptr->on_tree = 0;
509 arcptr->fake = 0;
510 arcptr->fall_through = 0;
511
512 arcptr->succ_next = bb_graph[source].succ;
513 bb_graph[source].succ = arcptr;
514 bb_graph[source].succ_count++;
515
516 arcptr->pred_next = bb_graph[target].pred;
517 bb_graph[target].pred = arcptr;
518 bb_graph[target].pred_count++;
519}
520
521
20dd417a 522/* Reverse the arcs on an arc list. */
10f2b886 523
524static struct adj_list *
525reverse_arcs (arcptr)
526 struct adj_list *arcptr;
527{
528 struct adj_list *prev = 0;
529 struct adj_list *next;
530
531 for ( ; arcptr; arcptr = next)
532 {
533 next = arcptr->succ_next;
534 arcptr->succ_next = prev;
535 prev = arcptr;
536 }
537
538 return prev;
539}
540
541
542/* Construct the program flow graph from the .bbg file, and read in the data
543 in the .da file. */
544
545static void
546create_program_flow_graph (bptr)
547 struct bb_info_list *bptr;
548{
549 long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
550 int i;
551 struct adj_list *arcptr;
552 struct bb_info *bb_graph;
553
554 /* Read the number of blocks. */
555 __read_long (&num_blocks, bbg_file, 4);
556
713829e9 557 /* Create an array of size bb number of bb_info structs. */
558 bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
10f2b886 559
560 bptr->bb_graph = bb_graph;
561 bptr->num_blocks = num_blocks;
562
563 /* Read and create each arc from the .bbg file. */
564 __read_long (&number_arcs, bbg_file, 4);
565 for (i = 0; i < num_blocks; i++)
566 {
567 int j;
568
569 __read_long (&num_arcs_per_block, bbg_file, 4);
570 for (j = 0; j < num_arcs_per_block; j++)
571 {
572 if (number_arcs-- < 0)
573 abort ();
574
575 src = i;
576 __read_long (&dest, bbg_file, 4);
577
578 arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
579 init_arc (arcptr, src, dest, bb_graph);
580
581 __read_long (&flag_bits, bbg_file, 4);
582 arcptr->on_tree = flag_bits & 0x1;
583 arcptr->fake = !! (flag_bits & 0x2);
584 arcptr->fall_through = !! (flag_bits & 0x4);
585 }
586 }
587
588 if (number_arcs)
589 abort ();
590
591 /* Read and ignore the -1 separating the arc list from the arc list of the
592 next function. */
593 __read_long (&src, bbg_file, 4);
594 if (src != -1)
595 abort ();
596
597 /* Must reverse the order of all succ arcs, to ensure that they match
598 the order of the data in the .da file. */
599
600 for (i = 0; i < num_blocks; i++)
601 if (bb_graph[i].succ)
602 bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
603
604 /* For each arc not on the spanning tree, set its execution count from
605 the .da file. */
606
607 /* The first count in the .da file is the number of times that the function
608 was entered. This is the exec_count for block zero. */
609
610 /* This duplicates code in branch_prob in profile.c. */
611
612 for (i = 0; i < num_blocks; i++)
613 for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
614 if (! arcptr->on_tree)
615 {
63f23608 616 gcov_type tmp_count = 0;
617 if (da_file && __read_gcov_type (&tmp_count, da_file, 8))
dfe09cce 618 abort ();
10f2b886 619
620 arcptr->arc_count = tmp_count;
621 arcptr->count_valid = 1;
622 bb_graph[i].succ_count--;
623 bb_graph[arcptr->target].pred_count--;
624 }
625}
87e97de6 626
10f2b886 627static void
628solve_program_flow_graph (bptr)
629 struct bb_info_list *bptr;
630{
63f23608 631 int passes, changes;
632 gcov_type total;
10f2b886 633 int i;
634 struct adj_list *arcptr;
635 struct bb_info *bb_graph;
636 int num_blocks;
637
638 num_blocks = bptr->num_blocks;
639 bb_graph = bptr->bb_graph;
640
641 /* For every block in the file,
642 - if every exit/entrance arc has a known count, then set the block count
643 - if the block count is known, and every exit/entrance arc but one has
644 a known execution count, then set the count of the remaining arc
645
646 As arc counts are set, decrement the succ/pred count, but don't delete
647 the arc, that way we can easily tell when all arcs are known, or only
648 one arc is unknown. */
649
650 /* The order that the basic blocks are iterated through is important.
651 Since the code that finds spanning trees starts with block 0, low numbered
652 arcs are put on the spanning tree in preference to high numbered arcs.
653 Hence, most instrumented arcs are at the end. Graph solving works much
654 faster if we propagate numbers from the end to the start.
655
656 This takes an average of slightly more than 3 passes. */
657
658 changes = 1;
659 passes = 0;
660 while (changes)
661 {
662 passes++;
663 changes = 0;
664
665 for (i = num_blocks - 1; i >= 0; i--)
666 {
667 if (! bb_graph[i].count_valid)
668 {
669 if (bb_graph[i].succ_count == 0)
670 {
671 total = 0;
672 for (arcptr = bb_graph[i].succ; arcptr;
673 arcptr = arcptr->succ_next)
674 total += arcptr->arc_count;
675 bb_graph[i].exec_count = total;
676 bb_graph[i].count_valid = 1;
677 changes = 1;
678 }
679 else if (bb_graph[i].pred_count == 0)
680 {
681 total = 0;
682 for (arcptr = bb_graph[i].pred; arcptr;
683 arcptr = arcptr->pred_next)
684 total += arcptr->arc_count;
685 bb_graph[i].exec_count = total;
686 bb_graph[i].count_valid = 1;
687 changes = 1;
688 }
689 }
690 if (bb_graph[i].count_valid)
691 {
692 if (bb_graph[i].succ_count == 1)
693 {
694 total = 0;
695 /* One of the counts will be invalid, but it is zero,
696 so adding it in also doesn't hurt. */
697 for (arcptr = bb_graph[i].succ; arcptr;
698 arcptr = arcptr->succ_next)
699 total += arcptr->arc_count;
700 /* Calculate count for remaining arc by conservation. */
701 total = bb_graph[i].exec_count - total;
702 /* Search for the invalid arc, and set its count. */
703 for (arcptr = bb_graph[i].succ; arcptr;
704 arcptr = arcptr->succ_next)
705 if (! arcptr->count_valid)
706 break;
707 if (! arcptr)
708 abort ();
709 arcptr->count_valid = 1;
710 arcptr->arc_count = total;
711 bb_graph[i].succ_count--;
712
713 bb_graph[arcptr->target].pred_count--;
714 changes = 1;
715 }
716 if (bb_graph[i].pred_count == 1)
717 {
718 total = 0;
719 /* One of the counts will be invalid, but it is zero,
720 so adding it in also doesn't hurt. */
721 for (arcptr = bb_graph[i].pred; arcptr;
722 arcptr = arcptr->pred_next)
723 total += arcptr->arc_count;
724 /* Calculate count for remaining arc by conservation. */
725 total = bb_graph[i].exec_count - total;
726 /* Search for the invalid arc, and set its count. */
727 for (arcptr = bb_graph[i].pred; arcptr;
728 arcptr = arcptr->pred_next)
729 if (! arcptr->count_valid)
730 break;
731 if (! arcptr)
732 abort ();
733 arcptr->count_valid = 1;
734 arcptr->arc_count = total;
735 bb_graph[i].pred_count--;
736
737 bb_graph[arcptr->source].succ_count--;
738 changes = 1;
739 }
740 }
741 }
742 }
87e97de6 743
10f2b886 744 /* If the graph has been correctly solved, every block will have a
745 succ and pred count of zero. */
746 for (i = 0; i < num_blocks; i++)
747 if (bb_graph[i].succ_count || bb_graph[i].pred_count)
748 abort ();
749}
750
751
752static void
753read_files ()
754{
755 struct stat buf;
756 struct bb_info_list *list_end = 0;
757 struct bb_info_list *b_ptr;
99c14947 758 long total;
10f2b886 759
760 /* Read and ignore the first word of the .da file, which is the count of
761 how many numbers follow. */
762 if (da_file && __read_long (&total, da_file, 8))
dfe09cce 763 abort ();
10f2b886 764
765 while (! feof (bbg_file))
766 {
767 b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
768
769 b_ptr->next = 0;
770 if (list_end)
771 list_end->next = b_ptr;
772 else
773 bb_graph_list = b_ptr;
774 list_end = b_ptr;
775
776 /* Read in the data in the .bbg file and reconstruct the program flow
777 graph for one function. */
99c14947 778 create_program_flow_graph (b_ptr);
10f2b886 779
780 /* Set the EOF condition if at the end of file. */
781 ungetc (getc (bbg_file), bbg_file);
782 }
783
784 /* Check to make sure the .da file data is valid. */
785
786 if (da_file)
787 {
788 if (feof (da_file))
be2828ce 789 fnotice (stderr, ".da file contents exhausted too early\n");
10f2b886 790 /* Should be at end of file now. */
791 if (__read_long (&total, da_file, 8) == 0)
be2828ce 792 fnotice (stderr, ".da file contents not exhausted\n");
10f2b886 793 }
794
795 /* Calculate all of the basic block execution counts and branch
796 taken probabilities. */
797
798 for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
799 solve_program_flow_graph (b_ptr);
800
801 /* Read in all of the data from the .bb file. This info will be accessed
802 sequentially twice. */
803 stat (bb_file_name, &buf);
804 bb_data_size = buf.st_size / 4;
805
99c14947 806 bb_data = (char *) xmalloc ((unsigned) buf.st_size);
10f2b886 807 fread (bb_data, sizeof (char), buf.st_size, bb_file);
87e97de6 808
10f2b886 809 fclose (bb_file);
810 if (da_file)
811 fclose (da_file);
812 fclose (bbg_file);
813}
814
815
816/* Scan the data in the .bb file to find all source files referenced,
817 and the largest line number mentioned in each one. */
818
819static void
820scan_for_source_files ()
821{
99c14947 822 struct sourcefile *s_ptr = NULL;
10f2b886 823 char *ptr;
e725f898 824 long count;
10f2b886 825 long line_num;
826
827 /* Search the bb_data to find:
828 1) The number of sources files contained herein, and
829 2) The largest line number for each source file. */
830
831 ptr = bb_data;
832 sources = 0;
833 for (count = 0; count < bb_data_size; count++)
834 {
835 __fetch_long (&line_num, ptr, 4);
836 ptr += 4;
837 if (line_num == -1)
838 {
839 /* A source file name follows. Check to see if we already have
840 a sourcefile structure for this file. */
841 s_ptr = sources;
842 while (s_ptr && strcmp (s_ptr->name, ptr))
843 s_ptr = s_ptr->next;
844
845 if (s_ptr == 0)
846 {
847 /* No sourcefile structure for this file name exists, create
848 a new one, and append it to the front of the sources list. */
849 s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
713829e9 850 s_ptr->name = xstrdup (ptr);
10f2b886 851 s_ptr->maxlineno = 0;
852 s_ptr->next = sources;
853 sources = s_ptr;
854 }
855
856 /* Scan past the file name. */
857 {
858 long delim;
859 do {
860 count++;
861 __fetch_long (&delim, ptr, 4);
862 ptr += 4;
863 } while (delim != line_num);
864 }
865 }
866 else if (line_num == -2)
867 {
868 long delim;
869
870 /* A function name follows. Ignore it. */
871 do {
872 count++;
873 __fetch_long (&delim, ptr, 4);
874 ptr += 4;
875 } while (delim != line_num);
876 }
877 /* There will be a zero before the first file name, in which case s_ptr
878 will still be uninitialized. So, only try to set the maxlineno
879 field if line_num is non-zero. */
880 else if (line_num > 0)
881 {
882 if (s_ptr->maxlineno <= line_num)
883 s_ptr->maxlineno = line_num + 1;
884 }
885 else if (line_num < 0)
886 {
aa40f561 887 /* Don't know what this is, but it's garbage. */
dfe09cce 888 abort ();
10f2b886 889 }
890 }
891}
892\f
893/* For calculating coverage at the function level. */
894
895static int function_source_lines;
896static int function_source_lines_executed;
897static int function_branches;
898static int function_branches_executed;
899static int function_branches_taken;
900static int function_calls;
901static int function_calls_executed;
902static char *function_name;
903
904/* Calculate the branch taken probabilities for all arcs branches at the
905 end of this block. */
906
907static void
908calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num)
909 struct bb_info_list *current_graph;
910 int block_num;
911 struct arcdata **branch_probs;
912 int last_line_num;
913{
e725f898 914 gcov_type total;
10f2b886 915 struct adj_list *arcptr;
916 struct arcdata *end_ptr, *a_ptr;
917
918 total = current_graph->bb_graph[block_num].exec_count;
919 for (arcptr = current_graph->bb_graph[block_num].succ; arcptr;
920 arcptr = arcptr->succ_next)
921 {
922 /* Ignore fall through arcs as they aren't really branches. */
923
924 if (arcptr->fall_through)
925 continue;
87e97de6 926
10f2b886 927 a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
887f59f0 928 a_ptr->total = total;
10f2b886 929 if (total == 0)
887f59f0 930 a_ptr->hits = 0;
10f2b886 931 else
887f59f0 932 a_ptr->hits = arcptr->arc_count;
10f2b886 933 a_ptr->call_insn = arcptr->fake;
934
935 if (output_function_summary)
936 {
937 if (a_ptr->call_insn)
938 {
939 function_calls++;
887f59f0 940 if (a_ptr->total != 0)
10f2b886 941 function_calls_executed++;
942 }
943 else
944 {
945 function_branches++;
887f59f0 946 if (a_ptr->total != 0)
10f2b886 947 function_branches_executed++;
887f59f0 948 if (a_ptr->hits > 0)
10f2b886 949 function_branches_taken++;
950 }
951 }
952
953 /* Append the new branch to the end of the list. */
954 a_ptr->next = 0;
955 if (! branch_probs[last_line_num])
956 branch_probs[last_line_num] = a_ptr;
957 else
958 {
959 end_ptr = branch_probs[last_line_num];
960 while (end_ptr->next != 0)
961 end_ptr = end_ptr->next;
962 end_ptr->next = a_ptr;
963 }
964 }
965}
966
967/* Output summary info for a function. */
968
969static void
970function_summary ()
971{
972 if (function_source_lines)
0cc5917f 973 fnotice (stdout, "%6.2f%% of %d source lines executed in function %s\n",
10f2b886 974 (((double) function_source_lines_executed / function_source_lines)
975 * 100), function_source_lines, function_name);
976 else
be2828ce 977 fnotice (stdout, "No executable source lines in function %s\n",
10f2b886 978 function_name);
979
980 if (output_branch_probs)
981 {
982 if (function_branches)
983 {
0cc5917f 984 fnotice (stdout, "%6.2f%% of %d branches executed in function %s\n",
10f2b886 985 (((double) function_branches_executed / function_branches)
986 * 100), function_branches, function_name);
be2828ce 987 fnotice (stdout,
0cc5917f 988 "%6.2f%% of %d branches taken at least once in function %s\n",
10f2b886 989 (((double) function_branches_taken / function_branches)
990 * 100), function_branches, function_name);
991 }
992 else
be2828ce 993 fnotice (stdout, "No branches in function %s\n", function_name);
10f2b886 994 if (function_calls)
0cc5917f 995 fnotice (stdout, "%6.2f%% of %d calls executed in function %s\n",
10f2b886 996 (((double) function_calls_executed / function_calls)
997 * 100), function_calls, function_name);
998 else
be2828ce 999 fnotice (stdout, "No calls in function %s\n", function_name);
10f2b886 1000 }
1001}
1002
1003/* Calculate line execution counts, and output the data to a .tcov file. */
1004
1005static void
1006output_data ()
1007{
1008 /* When scanning data, this is true only if the data applies to the
1009 current source file. */
1010 int this_file;
1011 /* An array indexed by line number which indicates how many times that line
1012 was executed. */
63f23608 1013 gcov_type *line_counts;
10f2b886 1014 /* An array indexed by line number which indicates whether the line was
1015 present in the bb file (i.e. whether it had code associate with it).
1016 Lines never executed are those which both exist, and have zero execution
1017 counts. */
1018 char *line_exists;
1019 /* An array indexed by line number, which contains a list of branch
1020 probabilities, one for each branch on that line. */
99c14947 1021 struct arcdata **branch_probs = NULL;
10f2b886 1022 struct sourcefile *s_ptr;
1023 char *source_file_name;
1024 FILE *source_file;
1025 struct bb_info_list *current_graph;
e725f898 1026 long count;
10f2b886 1027 char *cptr;
1028 long block_num;
1029 long line_num;
99c14947 1030 long last_line_num = 0;
10f2b886 1031 int i;
1032 struct arcdata *a_ptr;
1033 /* Buffer used for reading in lines from the source file. */
1034 char string[STRING_SIZE];
1035 /* For calculating coverage at the file level. */
1036 int total_source_lines;
1037 int total_source_lines_executed;
1038 int total_branches;
1039 int total_branches_executed;
1040 int total_branches_taken;
1041 int total_calls;
1042 int total_calls_executed;
1043
1044 /* Now, for each source file, allocate an array big enough to hold a count
1045 for each line. Scan through the bb_data, and when the file name matches
1046 the current file name, then for each following line number, increment
1047 the line number execution count indicated by the execution count of
1048 the appropriate basic block. */
1049
1050 for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
1051 {
1052 /* If this is a relative file name, and an object directory has been
1053 specified, then make it relative to the object directory name. */
c026482a 1054 if (! IS_ABSOLUTE_PATHNAME (s_ptr->name)
155b05dc 1055 && object_directory != 0
10f2b886 1056 && *object_directory != '\0')
1057 {
1058 int objdir_count = strlen (object_directory);
1059 source_file_name = xmalloc (objdir_count + strlen (s_ptr->name) + 2);
1060 strcpy (source_file_name, object_directory);
1061 if (object_directory[objdir_count - 1] != '/')
1062 source_file_name[objdir_count++] = '/';
1063 strcpy (source_file_name + objdir_count, s_ptr->name);
1064 }
1065 else
1066 source_file_name = s_ptr->name;
1067
63f23608 1068 line_counts = (gcov_type *) xcalloc (sizeof (gcov_type), s_ptr->maxlineno);
713829e9 1069 line_exists = xcalloc (1, s_ptr->maxlineno);
10f2b886 1070 if (output_branch_probs)
713829e9 1071 branch_probs = (struct arcdata **)
1072 xcalloc (sizeof (struct arcdata *), s_ptr->maxlineno);
87e97de6 1073
10f2b886 1074 /* There will be a zero at the beginning of the bb info, before the
1075 first list of line numbers, so must initialize block_num to 0. */
1076 block_num = 0;
1077 this_file = 0;
1078 current_graph = 0;
1079 {
1080 /* Pointer into the bb_data, incremented while scanning the data. */
1081 char *ptr = bb_data;
1082 for (count = 0; count < bb_data_size; count++)
1083 {
1084 long delim;
1085
1086 __fetch_long (&line_num, ptr, 4);
1087 ptr += 4;
1088 if (line_num == -1)
1089 {
1090 /* Marks the beginning of a file name. Check to see whether
1091 this is the filename we are currently collecting data for. */
1092
1093 if (strcmp (s_ptr->name, ptr))
1094 this_file = 0;
1095 else
1096 this_file = 1;
87e97de6 1097
10f2b886 1098 /* Scan past the file name. */
1099 do {
1100 count++;
1101 __fetch_long (&delim, ptr, 4);
1102 ptr += 4;
1103 } while (delim != line_num);
1104 }
1105 else if (line_num == -2)
1106 {
1107 /* Marks the start of a new function. Advance to the next
1108 program flow graph. */
1109
1110 if (! current_graph)
1111 current_graph = bb_graph_list;
1112 else
1113 {
1114 if (block_num == current_graph->num_blocks - 1)
1115 /* Last block falls through to exit. */
1116 ;
1117 else if (block_num == current_graph->num_blocks - 2)
1118 {
1119 if (output_branch_probs && this_file)
1120 calculate_branch_probs (current_graph, block_num,
1121 branch_probs, last_line_num);
1122 }
1123 else
1124 {
be2828ce 1125 fnotice (stderr,
10f2b886 1126 "didn't use all bb entries of graph, function %s\n",
1127 function_name);
0cc5917f 1128 fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
10f2b886 1129 block_num, current_graph->num_blocks);
1130 }
1131
1132 current_graph = current_graph->next;
1133 block_num = 0;
1134
1135 if (output_function_summary && this_file)
1136 function_summary ();
1137 }
1138
1139 if (output_function_summary)
1140 {
1141 function_source_lines = 0;
1142 function_source_lines_executed = 0;
1143 function_branches = 0;
1144 function_branches_executed = 0;
1145 function_branches_taken = 0;
1146 function_calls = 0;
1147 function_calls_executed = 0;
1148 }
1149
1150 /* Save the function name for later use. */
1151 function_name = ptr;
1152
1153 /* Scan past the file name. */
1154 do {
1155 count++;
1156 __fetch_long (&delim, ptr, 4);
1157 ptr += 4;
1158 } while (delim != line_num);
1159 }
1160 else if (line_num == 0)
1161 {
1162 /* Marks the end of a block. */
1163
1164 if (block_num >= current_graph->num_blocks)
1165 {
be2828ce 1166 fnotice (stderr, "ERROR: too many basic blocks in .bb file %s\n",
10f2b886 1167 function_name);
1168 abort ();
1169 }
87e97de6 1170
10f2b886 1171 if (output_branch_probs && this_file)
1172 calculate_branch_probs (current_graph, block_num,
1173 branch_probs, last_line_num);
1174
1175 block_num++;
1176 }
1177 else if (this_file)
1178 {
1179 if (output_function_summary)
1180 {
1181 if (line_exists[line_num] == 0)
1182 function_source_lines++;
1183 if (line_counts[line_num] == 0
1184 && current_graph->bb_graph[block_num].exec_count != 0)
1185 function_source_lines_executed++;
1186 }
1187
1188 /* Accumulate execution data for this line number. */
1189
1190 line_counts[line_num]
1191 += current_graph->bb_graph[block_num].exec_count;
1192 line_exists[line_num] = 1;
1193 last_line_num = line_num;
1194 }
1195 }
1196 }
1197
1198 if (output_function_summary && this_file)
1199 function_summary ();
1200
1201 /* Calculate summary test coverage statistics. */
1202
1203 total_source_lines = 0;
1204 total_source_lines_executed = 0;
1205 total_branches = 0;
1206 total_branches_executed = 0;
1207 total_branches_taken = 0;
1208 total_calls = 0;
1209 total_calls_executed = 0;
1210
1211 for (count = 1; count < s_ptr->maxlineno; count++)
1212 {
1213 if (line_exists[count])
1214 {
1215 total_source_lines++;
1216 if (line_counts[count])
1217 total_source_lines_executed++;
1218 }
1219 if (output_branch_probs)
1220 {
1221 for (a_ptr = branch_probs[count]; a_ptr; a_ptr = a_ptr->next)
1222 {
1223 if (a_ptr->call_insn)
1224 {
1225 total_calls++;
887f59f0 1226 if (a_ptr->total != 0)
10f2b886 1227 total_calls_executed++;
1228 }
1229 else
1230 {
1231 total_branches++;
887f59f0 1232 if (a_ptr->total != 0)
10f2b886 1233 total_branches_executed++;
887f59f0 1234 if (a_ptr->hits > 0)
10f2b886 1235 total_branches_taken++;
1236 }
1237 }
1238 }
1239 }
1240
1241 if (total_source_lines)
be2828ce 1242 fnotice (stdout,
0cc5917f 1243 "%6.2f%% of %d source lines executed in file %s\n",
10f2b886 1244 (((double) total_source_lines_executed / total_source_lines)
1245 * 100), total_source_lines, source_file_name);
1246 else
be2828ce 1247 fnotice (stdout, "No executable source lines in file %s\n",
10f2b886 1248 source_file_name);
1249
1250 if (output_branch_probs)
1251 {
1252 if (total_branches)
1253 {
0cc5917f 1254 fnotice (stdout, "%6.2f%% of %d branches executed in file %s\n",
10f2b886 1255 (((double) total_branches_executed / total_branches)
1256 * 100), total_branches, source_file_name);
be2828ce 1257 fnotice (stdout,
0cc5917f 1258 "%6.2f%% of %d branches taken at least once in file %s\n",
10f2b886 1259 (((double) total_branches_taken / total_branches)
1260 * 100), total_branches, source_file_name);
1261 }
1262 else
be2828ce 1263 fnotice (stdout, "No branches in file %s\n", source_file_name);
10f2b886 1264 if (total_calls)
0cc5917f 1265 fnotice (stdout, "%6.2f%% of %d calls executed in file %s\n",
10f2b886 1266 (((double) total_calls_executed / total_calls)
1267 * 100), total_calls, source_file_name);
1268 else
be2828ce 1269 fnotice (stdout, "No calls in file %s\n", source_file_name);
10f2b886 1270 }
1271
1272 if (output_gcov_file)
1273 {
1274 /* Now the statistics are ready. Read in the source file one line
99c14947 1275 at a time, and output that line to the gcov file preceded by
10f2b886 1276 its execution count if non zero. */
87e97de6 1277
10f2b886 1278 source_file = fopen (source_file_name, "r");
1279 if (source_file == NULL)
1280 {
be2828ce 1281 fnotice (stderr, "Could not open source file %s.\n",
10f2b886 1282 source_file_name);
1283 free (line_counts);
1284 free (line_exists);
1285 continue;
1286 }
1287
1288 count = strlen (source_file_name);
78dbff7c 1289 cptr = strrchr (s_ptr->name, '/');
10f2b886 1290 if (cptr)
1291 cptr = cptr + 1;
1292 else
1293 cptr = s_ptr->name;
1294 if (output_long_names && strcmp (cptr, input_file_name))
1295 {
1296 gcov_file_name = xmalloc (count + 7 + strlen (input_file_name));
87e97de6 1297
78dbff7c 1298 cptr = strrchr (input_file_name, '/');
10f2b886 1299 if (cptr)
1300 strcpy (gcov_file_name, cptr + 1);
1301 else
1302 strcpy (gcov_file_name, input_file_name);
1303
1304 strcat (gcov_file_name, ".");
1305
78dbff7c 1306 cptr = strrchr (source_file_name, '/');
10f2b886 1307 if (cptr)
1308 strcat (gcov_file_name, cptr + 1);
1309 else
1310 strcat (gcov_file_name, source_file_name);
1311 }
1312 else
1313 {
1314 gcov_file_name = xmalloc (count + 6);
78dbff7c 1315 cptr = strrchr (source_file_name, '/');
10f2b886 1316 if (cptr)
1317 strcpy (gcov_file_name, cptr + 1);
1318 else
1319 strcpy (gcov_file_name, source_file_name);
1320 }
1321
1322 /* Don't strip off the ending for compatibility with tcov, since
1323 this results in confusion if there is more than one file with
1324 the same basename, e.g. tmp.c and tmp.h. */
1325 strcat (gcov_file_name, ".gcov");
1326
1327 gcov_file = fopen (gcov_file_name, "w");
1328
1329 if (gcov_file == NULL)
1330 {
be2828ce 1331 fnotice (stderr, "Could not open output file %s.\n",
10f2b886 1332 gcov_file_name);
1333 fclose (source_file);
1334 free (line_counts);
1335 free (line_exists);
1336 continue;
1337 }
1338
be2828ce 1339 fnotice (stdout, "Creating %s.\n", gcov_file_name);
10f2b886 1340
1341 for (count = 1; count < s_ptr->maxlineno; count++)
1342 {
1343 char *retval;
1344 int len;
1345
1346 retval = fgets (string, STRING_SIZE, source_file);
1347
1348 /* For lines which don't exist in the .bb file, print nothing
1349 before the source line. For lines which exist but were never
1350 executed, print ###### before the source line. Otherwise,
1351 print the execution count before the source line. */
99c14947 1352 /* There are 16 spaces of indentation added before the source
1353 line so that tabs won't be messed up. */
10f2b886 1354 if (line_exists[count])
1355 {
1356 if (line_counts[count])
63f23608 1357 {
1358 char c[20];
1359 sprintf (c, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)line_counts[count]);
1360 fprintf (gcov_file, "%12s %s", c,
1361 string);
1362 }
10f2b886 1363 else
1364 fprintf (gcov_file, " ###### %s", string);
1365 }
1366 else
1367 fprintf (gcov_file, "\t\t%s", string);
1368
1369 /* In case the source file line is larger than our buffer, keep
99c14947 1370 reading and outputting lines until we get a newline. */
10f2b886 1371 len = strlen (string);
0bc644e0 1372 while ((len == 0 || string[strlen (string) - 1] != '\n')
1373 && retval != NULL)
10f2b886 1374 {
1375 retval = fgets (string, STRING_SIZE, source_file);
1376 fputs (string, gcov_file);
1377 }
1378
1379 if (output_branch_probs)
1380 {
1381 for (i = 0, a_ptr = branch_probs[count]; a_ptr;
1382 a_ptr = a_ptr->next, i++)
1383 {
1384 if (a_ptr->call_insn)
1385 {
887f59f0 1386 if (a_ptr->total == 0)
be2828ce 1387 fnotice (gcov_file, "call %d never executed\n", i);
887f59f0 1388 else
1389 {
1390 if (output_branch_counts)
e725f898 1391 {
1392 char c[20];
1393 sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
1394 a_ptr->total - a_ptr->hits);
1395 fnotice (gcov_file,
1396 "call %d returns = %s\n", i, c);
1397 }
887f59f0 1398 else
e725f898 1399 {
1400 char c[20];
1401 sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
1402 100 - ((a_ptr->hits * 100)
1403 + (a_ptr->total >> 1))
1404 / a_ptr->total);
1405 fnotice (gcov_file,
1406 "call %d returns = %s%%\n", i, c);
1407 }
887f59f0 1408 }
10f2b886 1409 }
1410 else
1411 {
887f59f0 1412 if (a_ptr->total == 0)
be2828ce 1413 fnotice (gcov_file, "branch %d never executed\n",
10f2b886 1414 i);
1415 else
887f59f0 1416 {
1417 if (output_branch_counts)
e725f898 1418 {
1419 char c[20];
1420 sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
1421 a_ptr->hits);
1422 fnotice (gcov_file,
1423 "branch %d taken = %s\n", i, c);
1424 }
887f59f0 1425 else
e725f898 1426 {
1427 char c[20];
1428 sprintf (c, HOST_WIDEST_INT_PRINT_DEC,
1429 ((a_ptr->hits * 100)
1430 + (a_ptr->total >> 1))
1431 / a_ptr->total);
887f59f0 1432 fnotice (gcov_file,
e725f898 1433 "branch %d taken = %s%%\n", i, c);
1434 }
887f59f0 1435 }
10f2b886 1436 }
887f59f0 1437 }
1438 }
10f2b886 1439
1440 /* Gracefully handle errors while reading the source file. */
1441 if (retval == NULL)
1442 {
be2828ce 1443 fnotice (stderr,
10f2b886 1444 "Unexpected EOF while reading source file %s.\n",
1445 source_file_name);
1446 break;
1447 }
1448 }
1449
1450 /* Handle all remaining source lines. There may be lines
1451 after the last line of code. */
1452
1453 {
1454 char *retval = fgets (string, STRING_SIZE, source_file);
1455 while (retval != NULL)
1456 {
1457 int len;
1458
1459 fprintf (gcov_file, "\t\t%s", string);
1460
1461 /* In case the source file line is larger than our buffer, keep
99c14947 1462 reading and outputting lines until we get a newline. */
10f2b886 1463 len = strlen (string);
0bc644e0 1464 while ((len == 0 || string[strlen (string) - 1] != '\n')
1465 && retval != NULL)
10f2b886 1466 {
1467 retval = fgets (string, STRING_SIZE, source_file);
1468 fputs (string, gcov_file);
1469 }
1470
1471 retval = fgets (string, STRING_SIZE, source_file);
1472 }
1473 }
1474
1475 fclose (source_file);
1476 fclose (gcov_file);
1477 }
1478
1479 free (line_counts);
1480 free (line_exists);
1481 }
1482}