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