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