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