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