]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gcov.c
c-decl.c: Fix comment formatting.
[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,
f55ade6e 4 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
86144b75 5 Contributed by James E. Wilson of Cygnus Support.
1d300e19 6 Mangled by Bob Manson of Cygnus Support.
4977bab6 7 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
86144b75
DE
8
9Gcov is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2, or (at your option)
12any later version.
13
14Gcov is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with Gcov; see the file COPYING. If not, write to
5f38fdda
JL
21the Free Software Foundation, 59 Temple Place - Suite 330,
22Boston, MA 02111-1307, USA. */
86144b75 23
86144b75
DE
24/* ??? Print a list of the ten blocks with the highest execution counts,
25 and list the line numbers corresponding to those blocks. Also, perhaps
26 list the line numbers with the highest execution counts, only printing
27 the first if there are several which are all listed in the same block. */
28
29/* ??? Should have an option to print the number of basic blocks, and the
30 percent of them that are covered. */
31
4977bab6
ZW
32/* ??? Does not correctly handle the case where two .bb files refer to
33 the same included source file. For example, if one has a short
34 file containing only inline functions, which is then included in
35 two other files, then there will be two .bb files which refer to
36 the include file, but there is no way to get the total execution
37 counts for the included file, can only get execution counts for one
38 or the other of the including files. this can be fixed by --ratios
39 --long-file-names --preserve-paths and perl. */
40
41/* Need an option to show individual block counts, and show
42 probabilities of fall through arcs. */
86144b75 43
1d300e19 44#include "config.h"
b04cd507 45#include "system.h"
4977bab6
ZW
46#include "coretypes.h"
47#include "tm.h"
ab87f8c8 48#include "intl.h"
5735c3ea 49#include "version.h"
2a611d21 50#undef abort
86144b75 51
5735c3ea
JM
52#include <getopt.h>
53
546d2adb 54#define IN_GCOV 1
86144b75 55#include "gcov-io.h"
d79f9ec9 56#include "gcov-io.c"
86144b75 57
4977bab6
ZW
58/* The bbg file is generated by -ftest-coverage option. The da file is
59 generated by a program compiled with -fprofile-arcs. Their formats
60 are documented in gcov-io.h. */
86144b75
DE
61
62/* The functions in this file for creating and solution program flow graphs
4977bab6
ZW
63 are very similar to functions in the gcc source file profile.c. In
64 some places we make use of the knowledge of how profile.c works to
65 select particular algorithms here. */
86144b75 66
86144b75
DE
67/* This is the size of the buffer used to read in source file lines. */
68
69#define STRING_SIZE 200
70
4977bab6
ZW
71struct function_info;
72struct block_info;
27283c73 73struct source_info;
86144b75 74
4977bab6 75/* Describes an arc between two basic blocks. */
86144b75 76
4977bab6
ZW
77typedef struct arc_info
78{
32dd366d 79 /* source and destination blocks. */
4977bab6
ZW
80 struct block_info *src;
81 struct block_info *dst;
86144b75 82
4977bab6
ZW
83 /* transition counts. */
84 gcov_type count;
86144b75 85
86144b75
DE
86 unsigned int count_valid : 1;
87 unsigned int on_tree : 1;
88 unsigned int fake : 1;
89 unsigned int fall_through : 1;
86144b75 90
27283c73
NS
91 /* Arc is for a function that abnormally returns. */
92 unsigned int is_call_non_return : 1;
93
94 /* Arc is for catch/setjump. */
95 unsigned int is_nonlocal_return : 1;
96
97 /* Is an unconditional branch. */
98 unsigned int is_unconditional : 1;
99
10b7602f
NS
100 /* Loop making arc. */
101 unsigned int cycle : 1;
102
4977bab6
ZW
103 /* Next branch on line. */
104 struct arc_info *line_next;
f55ade6e 105
4977bab6
ZW
106 /* Links to next arc on src and dst lists. */
107 struct arc_info *succ_next;
108 struct arc_info *pred_next;
109} arc_t;
86144b75 110
4977bab6
ZW
111/* Describes a basic block. Contains lists of arcs to successor and
112 predecessor blocks. */
86144b75 113
4977bab6 114typedef struct block_info
86144b75 115{
4977bab6
ZW
116 /* Chain of exit and entry arcs. */
117 arc_t *succ;
118 arc_t *pred;
119
32dd366d 120 /* Number of unprocessed exit and entry arcs. */
4977bab6
ZW
121 gcov_type num_succ;
122 gcov_type num_pred;
123
32dd366d 124 /* Block execution count. */
4977bab6 125 gcov_type count;
27283c73 126 unsigned flags : 13;
4977bab6
ZW
127 unsigned count_valid : 1;
128 unsigned valid_chain : 1;
129 unsigned invalid_chain : 1;
130
27283c73 131 /* Block is a call instrumenting site. */
10b7602f
NS
132 unsigned is_call_site : 1; /* Does the call. */
133 unsigned is_call_return : 1; /* Is the return. */
4977bab6 134
27283c73
NS
135 /* Block is a landing pad for longjmp or throw. */
136 unsigned is_nonlocal_return : 1;
137
138 union
139 {
140 struct
141 {
142 /* Array of line numbers and source files. source files are
143 introduced by a linenumber of zero, the next 'line number' is
144 the number of the source file. Always starts with a source
145 file. */
146 unsigned *encoding;
147 unsigned num;
148 } line; /* Valid until blocks are linked onto lines */
149 struct
150 {
10b7602f 151 /* Single line graph cycle workspace. Used for all-blocks
71c0e7fc 152 mode. */
10b7602f
NS
153 arc_t *arc;
154 unsigned ident;
155 } cycle; /* Used in all-blocks mode, after blocks are linked onto
71c0e7fc 156 lines. */
27283c73
NS
157 } u;
158
159 /* Temporary chain for solving graph, and for chaining blocks on one
160 line. */
4977bab6 161 struct block_info *chain;
f55ade6e 162
4977bab6 163} block_t;
86144b75 164
4977bab6 165/* Describes a single function. Contains an array of basic blocks. */
86144b75 166
4977bab6 167typedef struct function_info
8b219a76 168{
4977bab6
ZW
169 /* Name of function. */
170 char *name;
796621e8 171 unsigned ident;
4977bab6 172 unsigned checksum;
86144b75 173
4977bab6
ZW
174 /* Array of basic blocks. */
175 block_t *blocks;
176 unsigned num_blocks;
27283c73 177 unsigned blocks_executed;
4977bab6
ZW
178
179 /* Raw arc coverage counts. */
180 gcov_type *counts;
181 unsigned num_counts;
27283c73
NS
182
183 /* First line number. */
184 unsigned line;
185 struct source_info *src;
186
187 /* Next function in same source file. */
188 struct function_info *line_next;
f55ade6e 189
4977bab6
ZW
190 /* Next function. */
191 struct function_info *next;
192} function_t;
193
194/* Describes coverage of a file or function. */
195
196typedef struct coverage_info
8b219a76
NS
197{
198 int lines;
199 int lines_executed;
f55ade6e 200
8b219a76
NS
201 int branches;
202 int branches_executed;
203 int branches_taken;
f55ade6e 204
8b219a76
NS
205 int calls;
206 int calls_executed;
f55ade6e 207
8b219a76 208 char *name;
4977bab6 209} coverage_t;
8b219a76 210
4977bab6
ZW
211/* Describes a single line of source. Contains a chain of basic blocks
212 with code on it. */
86144b75 213
4977bab6
ZW
214typedef struct line_info
215{
216 gcov_type count; /* execution count */
27283c73
NS
217 union
218 {
f55ade6e 219 arc_t *branches; /* branches from blocks that end on this
27283c73 220 line. Used for branch-counts when not
71c0e7fc 221 all-blocks mode. */
27283c73 222 block_t *blocks; /* blocks which start on this line. Used
71c0e7fc 223 in all-blocks mode. */
27283c73 224 } u;
4977bab6
ZW
225 unsigned exists : 1;
226} line_t;
86144b75 227
4977bab6
ZW
228/* Describes a file mentioned in the block graph. Contains an array
229 of line info. */
37b8715b 230
4977bab6
ZW
231typedef struct source_info
232{
233 /* Name of source file. */
234 char *name;
235 unsigned index;
37b8715b 236
32dd366d 237 /* Array of line information. */
4977bab6
ZW
238 line_t *lines;
239 unsigned num_lines;
86144b75 240
4977bab6 241 coverage_t coverage;
27283c73
NS
242
243 /* Functions in this source file. These are in ascending line
244 number order. */
245 function_t *functions;
f55ade6e 246
4977bab6
ZW
247 /* Next source file. */
248 struct source_info *next;
249} source_t;
86144b75 250
4977bab6 251/* Holds a list of function basic block graphs. */
86144b75 252
4977bab6 253static function_t *functions;
86144b75 254
4977bab6 255/* This points to the head of the sourcefile structure list. */
86144b75 256
4977bab6 257static source_t *sources;
86144b75 258
27283c73
NS
259/* This holds data summary information. */
260
261static struct gcov_summary object_summary;
262static unsigned program_count;
263
32dd366d 264/* Modification time of graph file. */
86144b75 265
4977bab6 266static time_t bbg_file_time;
86144b75 267
4977bab6 268/* Name and file pointer of the input file for the basic block graph. */
86144b75 269
4977bab6 270static char *bbg_file_name;
86144b75 271
dd486eb2
NS
272/* Stamp of the bbg file */
273static unsigned bbg_stamp;
274
4977bab6 275/* Name and file pointer of the input file for the arc count data. */
86144b75 276
4977bab6 277static char *da_file_name;
86144b75 278
4977bab6 279/* Output branch probabilities. */
86144b75 280
4977bab6 281static int flag_branches = 0;
86144b75 282
f55ade6e 283/* Show unconditional branches too. */
27283c73
NS
284static int flag_unconditional = 0;
285
86144b75
DE
286/* Output a gcov file if this is true. This is on by default, and can
287 be turned off by the -n option. */
288
4977bab6 289static int flag_gcov_file = 1;
86144b75 290
4977bab6
ZW
291/* For included files, make the gcov output file name include the name
292 of the input source file. For example, if x.h is included in a.c,
293 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
86144b75 294
4977bab6 295static int flag_long_names = 0;
86144b75 296
27283c73
NS
297/* Output count information for every basic block, not merely those
298 that contain line number information. */
299
300static int flag_all_blocks = 0;
301
86144b75
DE
302/* Output summary info for each function. */
303
4977bab6 304static int flag_function_summary = 0;
86144b75 305
4977bab6
ZW
306/* Object directory file prefix. This is the directory/file where the
307 graph and data files are looked for, if nonzero. */
86144b75
DE
308
309static char *object_directory = 0;
310
37b8715b 311/* Preserve all pathname components. Needed when object files and
4977bab6
ZW
312 source files are in subdirectories. '/' is mangled as '#', '.' is
313 elided and '..' mangled to '^'. */
314
315static int flag_preserve_paths = 0;
37b8715b 316
8bfa6fc5 317/* Output the number of times a branch was taken as opposed to the percentage
32dd366d 318 of times it was taken. */
23190837 319
4977bab6 320static int flag_counts = 0;
8bfa6fc5 321
86144b75 322/* Forward declarations. */
f55ade6e
AJ
323static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2;
324static int process_args (int, char **);
325static void print_usage (int) ATTRIBUTE_NORETURN;
326static void print_version (void) ATTRIBUTE_NORETURN;
327static void process_file (const char *);
328static void create_file_names (const char *);
329static source_t *find_source (const char *);
330static int read_graph_file (void);
331static int read_count_file (void);
332static void solve_flow_graph (function_t *);
333static void add_branch_counts (coverage_t *, const arc_t *);
334static void add_line_counts (coverage_t *, function_t *);
335static void function_summary (const coverage_t *, const char *);
336static const char *format_gcov (gcov_type, gcov_type, int);
337static void accumulate_line_counts (source_t *);
338static int output_branch_count (FILE *, int, const arc_t *);
339static void output_lines (FILE *, const source_t *);
340static char *make_gcov_file_name (const char *, const char *);
341static void release_structures (void);
342extern int main (int, char **);
86144b75
DE
343
344int
f55ade6e 345main (int argc, char **argv)
86144b75 346{
4977bab6 347 int argno;
f55ade6e 348
191bf464 349 gcc_init_libintl ();
ab87f8c8 350
4977bab6
ZW
351 argno = process_args (argc, argv);
352 if (optind == argc)
353 print_usage (true);
86144b75 354
4977bab6
ZW
355 for (; argno != argc; argno++)
356 {
357 release_structures ();
f55ade6e 358
4977bab6
ZW
359 process_file (argv[argno]);
360 }
f55ade6e 361
86144b75
DE
362 return 0;
363}
364
ab87f8c8 365static void
e34d07f2 366fnotice (FILE *file, const char *msgid, ...)
ab87f8c8 367{
e34d07f2 368 va_list ap;
f55ade6e 369
e34d07f2 370 va_start (ap, msgid);
644f3d7e 371 vfprintf (file, _(msgid), ap);
e34d07f2 372 va_end (ap);
ab87f8c8
JL
373}
374
86144b75
DE
375/* More 'friendly' abort that prints the line and file.
376 config.h can #define abort fancy_abort if you like that sort of thing. */
f55ade6e 377extern void fancy_abort (void) ATTRIBUTE_NORETURN;
86144b75
DE
378
379void
f55ade6e 380fancy_abort (void)
86144b75 381{
14a774a9 382 fnotice (stderr, "Internal gcov abort.\n");
86144b75
DE
383 exit (FATAL_EXIT_CODE);
384}
385\f
5735c3ea
JM
386/* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
387 otherwise the output of --help. */
86144b75
DE
388
389static void
f55ade6e 390print_usage (int error_p)
86144b75 391{
5735c3ea
JM
392 FILE *file = error_p ? stderr : stdout;
393 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
f55ade6e 394
5735c3ea
JM
395 fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
396 fnotice (file, "Print code coverage information.\n\n");
397 fnotice (file, " -h, --help Print this help, then exit\n");
398 fnotice (file, " -v, --version Print version number, then exit\n");
27283c73 399 fnotice (file, " -a, --all-blocks Show information for every basic block\n");
5735c3ea
JM
400 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
401 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
402 rather than percentages\n");
403 fnotice (file, " -n, --no-output Do not create an output file\n");
404 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
405 source files\n");
406 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
37b8715b
NS
407 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
408 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
27283c73 409 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
5735c3ea 410 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
a976603e 411 bug_report_url);
5735c3ea
JM
412 exit (status);
413}
414
415/* Print version information and exit. */
416
417static void
f55ade6e 418print_version (void)
5735c3ea 419{
330d2e2a
NS
420 fnotice (stdout, "gcov (GCC) %s\n", version_string);
421 fnotice (stdout, "Copyright (C) 2003 Free Software Foundation, Inc.\n");
5735c3ea 422 fnotice (stdout,
330d2e2a
NS
423 "This is free software; see the source for copying conditions.\n"
424 "There is NO warranty; not even for MERCHANTABILITY or \n"
425 "FITNESS FOR A PARTICULAR PURPOSE.\n\n");
5735c3ea 426 exit (SUCCESS_EXIT_CODE);
86144b75
DE
427}
428
5735c3ea
JM
429static const struct option options[] =
430{
431 { "help", no_argument, NULL, 'h' },
432 { "version", no_argument, NULL, 'v' },
27283c73 433 { "all-blocks", no_argument, NULL, 'a' },
5735c3ea
JM
434 { "branch-probabilities", no_argument, NULL, 'b' },
435 { "branch-counts", no_argument, NULL, 'c' },
436 { "no-output", no_argument, NULL, 'n' },
437 { "long-file-names", no_argument, NULL, 'l' },
438 { "function-summaries", no_argument, NULL, 'f' },
37b8715b
NS
439 { "preserve-paths", no_argument, NULL, 'p' },
440 { "object-directory", required_argument, NULL, 'o' },
441 { "object-file", required_argument, NULL, 'o' },
27283c73 442 { "unconditional-branches", no_argument, NULL, 'u' },
d90f9882 443 { 0, 0, 0, 0 }
5735c3ea
JM
444};
445
4977bab6 446/* Process args, return index to first non-arg. */
86144b75 447
4977bab6 448static int
f55ade6e 449process_args (int argc, char **argv)
86144b75 450{
5735c3ea 451 int opt;
86144b75 452
27283c73 453 while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1)
86144b75 454 {
5735c3ea 455 switch (opt)
86144b75 456 {
27283c73
NS
457 case 'a':
458 flag_all_blocks = 1;
459 break;
5735c3ea 460 case 'b':
4977bab6 461 flag_branches = 1;
5735c3ea
JM
462 break;
463 case 'c':
4977bab6 464 flag_counts = 1;
5735c3ea 465 break;
27283c73
NS
466 case 'f':
467 flag_function_summary = 1;
5735c3ea 468 break;
27283c73
NS
469 case 'h':
470 print_usage (false);
471 /* print_usage will exit. */
5735c3ea 472 case 'l':
4977bab6 473 flag_long_names = 1;
5735c3ea 474 break;
27283c73
NS
475 case 'n':
476 flag_gcov_file = 0;
5735c3ea
JM
477 break;
478 case 'o':
479 object_directory = optarg;
480 break;
37b8715b 481 case 'p':
4977bab6 482 flag_preserve_paths = 1;
37b8715b 483 break;
27283c73
NS
484 case 'u':
485 flag_unconditional = 1;
486 break;
487 case 'v':
488 print_version ();
489 /* print_version will exit. */
5735c3ea
JM
490 default:
491 print_usage (true);
492 /* print_usage will exit. */
86144b75 493 }
86144b75
DE
494 }
495
4977bab6
ZW
496 return optind;
497}
498
499/* Process a single source file. */
5735c3ea 500
4977bab6 501static void
f55ade6e 502process_file (const char *file_name)
4977bab6
ZW
503{
504 source_t *src;
505 function_t *fn;
f55ade6e 506
4977bab6
ZW
507 create_file_names (file_name);
508 if (read_graph_file ())
509 return;
f55ade6e 510
4977bab6
ZW
511 if (!functions)
512 {
513 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
514 return;
515 }
f55ade6e 516
4977bab6
ZW
517 if (read_count_file ())
518 return;
f55ade6e 519
4977bab6
ZW
520 for (fn = functions; fn; fn = fn->next)
521 solve_flow_graph (fn);
522 for (src = sources; src; src = src->next)
703ad42b 523 src->lines = xcalloc (src->num_lines, sizeof (line_t));
4977bab6
ZW
524 for (fn = functions; fn; fn = fn->next)
525 {
526 coverage_t coverage;
f55ade6e 527
4977bab6
ZW
528 memset (&coverage, 0, sizeof (coverage));
529 coverage.name = fn->name;
530 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
531 if (flag_function_summary)
532 {
533 function_summary (&coverage, "Function");
534 fnotice (stdout, "\n");
535 }
536 }
f55ade6e 537
4977bab6
ZW
538 for (src = sources; src; src = src->next)
539 {
540 accumulate_line_counts (src);
541 function_summary (&src->coverage, "File");
542 if (flag_gcov_file)
543 {
544 char *gcov_file_name = make_gcov_file_name (file_name, src->name);
545 FILE *gcov_file = fopen (gcov_file_name, "w");
f55ade6e 546
4977bab6
ZW
547 if (gcov_file)
548 {
549 fnotice (stdout, "%s:creating `%s'\n",
550 src->name, gcov_file_name);
551 output_lines (gcov_file, src);
552 if (ferror (gcov_file))
553 fnotice (stderr, "%s:error writing output file `%s'\n",
554 src->name, gcov_file_name);
555 fclose (gcov_file);
556 }
557 else
558 fnotice (stderr, "%s:could not open output file `%s'\n",
559 src->name, gcov_file_name);
560 free (gcov_file_name);
561 }
562 fnotice (stdout, "\n");
563 }
86144b75
DE
564}
565
4977bab6 566/* Release all memory used. */
86144b75 567
4977bab6 568static void
f55ade6e 569release_structures (void)
4977bab6
ZW
570{
571 function_t *fn;
572 source_t *src;
f55ade6e 573
4977bab6
ZW
574 free (bbg_file_name);
575 free (da_file_name);
576 da_file_name = bbg_file_name = NULL;
577 bbg_file_time = 0;
dd486eb2 578 bbg_stamp = 0;
f55ade6e 579
4977bab6
ZW
580 while ((src = sources))
581 {
582 sources = src->next;
583
584 free (src->name);
585 free (src->lines);
586 }
f55ade6e 587
4977bab6
ZW
588 while ((fn = functions))
589 {
590 unsigned ix;
591 block_t *block;
f55ade6e 592
4977bab6
ZW
593 functions = fn->next;
594 for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
595 {
596 arc_t *arc, *arc_n;
597
598 for (arc = block->succ; arc; arc = arc_n)
599 {
600 arc_n = arc->succ_next;
601 free (arc);
602 }
4977bab6
ZW
603 }
604 free (fn->blocks);
605 free (fn->counts);
606 }
607}
608
609/* Generate the names of the graph and data files. If OBJECT_DIRECTORY
610 is not specified, these are looked for in the current directory,
611 and named from the basename of the FILE_NAME sans extension. If
37b8715b 612 OBJECT_DIRECTORY is specified and is a directory, the files are in
4977bab6
ZW
613 that directory, but named from the basename of the FILE_NAME, sans
614 extension. Otherwise OBJECT_DIRECTORY is taken to be the name of
615 the object *file*, and the data files are named from that. */
86144b75
DE
616
617static void
f55ade6e 618create_file_names (const char *file_name)
86144b75 619{
86144b75 620 char *cptr;
37b8715b 621 char *name;
4977bab6 622 int length = strlen (file_name);
37b8715b 623 int base;
f55ade6e 624
37b8715b 625 if (object_directory && object_directory[0])
86144b75 626 {
37b8715b
NS
627 struct stat status;
628
629 length += strlen (object_directory) + 2;
630 name = xmalloc (length);
631 name[0] = 0;
f55ade6e 632
37b8715b
NS
633 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
634 strcat (name, object_directory);
635 if (base && name[strlen (name) - 1] != '/')
636 strcat (name, "/");
86144b75
DE
637 }
638 else
639 {
37b8715b
NS
640 name = xmalloc (length + 1);
641 name[0] = 0;
642 base = 1;
86144b75 643 }
f55ade6e 644
37b8715b
NS
645 if (base)
646 {
f9da5064 647 /* Append source file name. */
4977bab6
ZW
648 cptr = strrchr (file_name, '/');
649 strcat (name, cptr ? cptr + 1 : file_name);
37b8715b 650 }
f55ade6e 651
4b7e68e7 652 /* Remove the extension. */
37b8715b 653 cptr = strrchr (name, '.');
86144b75 654 if (cptr)
37b8715b 655 *cptr = 0;
f55ade6e 656
37b8715b 657 length = strlen (name);
160e2e4f
NS
658
659 bbg_file_name = xmalloc (length + strlen (GCOV_NOTE_SUFFIX) + 1);
4977bab6 660 strcpy (bbg_file_name, name);
160e2e4f 661 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
37b8715b 662
4977bab6
ZW
663 da_file_name = xmalloc (length + strlen (GCOV_DATA_SUFFIX) + 1);
664 strcpy (da_file_name, name);
665 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
f55ade6e 666
4977bab6 667 return;
86144b75 668}
86144b75 669
94de45d9
NS
670/* Find or create a source file structure for FILE_NAME. Copies
671 FILE_NAME on creation */
27283c73
NS
672
673static source_t *
f55ade6e 674find_source (const char *file_name)
27283c73 675{
27283c73 676 source_t *src;
94de45d9
NS
677
678 if (!file_name)
679 file_name = "<unknown>";
f55ade6e 680
27283c73
NS
681 for (src = sources; src; src = src->next)
682 if (!strcmp (file_name, src->name))
94de45d9 683 return src;
f55ade6e 684
703ad42b 685 src = xcalloc (1, sizeof (source_t));
94de45d9
NS
686 src->name = xstrdup (file_name);
687 src->coverage.name = src->name;
688 src->index = sources ? sources->index + 1 : 1;
689 src->next = sources;
690 sources = src;
691
27283c73
NS
692 return src;
693}
694
272d0bee 695/* Read the graph file. Return nonzero on fatal error. */
86144b75 696
4977bab6 697static int
f55ade6e 698read_graph_file (void)
86144b75 699{
94de45d9 700 unsigned version;
4977bab6 701 unsigned current_tag = 0;
4977bab6
ZW
702 struct function_info *fn = NULL;
703 source_t *src = NULL;
704 unsigned ix;
7d63a2fa 705 unsigned tag;
f55ade6e 706
546d2adb 707 if (!gcov_open (bbg_file_name, 1))
86144b75 708 {
4977bab6
ZW
709 fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
710 return 1;
86144b75 711 }
546d2adb 712 bbg_file_time = gcov_time ();
160e2e4f 713 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
b7c9bf28 714 {
4977bab6 715 fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
546d2adb 716 gcov_close ();
4977bab6
ZW
717 return 1;
718 }
b7c9bf28 719
94de45d9
NS
720 version = gcov_read_unsigned ();
721 if (version != GCOV_VERSION)
4977bab6
ZW
722 {
723 char v[4], e[4];
f55ade6e 724
330d2e2a
NS
725 GCOV_UNSIGNED2STRING (v, version);
726 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
727
4977bab6
ZW
728 fnotice (stderr, "%s:version `%.4s', prefer `%.4s'\n",
729 bbg_file_name, v, e);
730 }
dd486eb2
NS
731 bbg_stamp = gcov_read_unsigned ();
732
7d63a2fa 733 while ((tag = gcov_read_unsigned ()))
4977bab6 734 {
94de45d9 735 unsigned length = gcov_read_unsigned ();
7d63a2fa 736 gcov_position_t base = gcov_position ();
796621e8 737
4977bab6 738 if (tag == GCOV_TAG_FUNCTION)
b7c9bf28 739 {
94de45d9 740 char *function_name;
796621e8 741 unsigned ident, checksum, lineno;
27283c73
NS
742 source_t *src;
743 function_t *probe, *prev;
4977bab6 744
796621e8 745 ident = gcov_read_unsigned ();
94de45d9 746 checksum = gcov_read_unsigned ();
796621e8 747 function_name = xstrdup (gcov_read_string ());
94de45d9
NS
748 src = find_source (gcov_read_string ());
749 lineno = gcov_read_unsigned ();
f55ade6e 750
703ad42b 751 fn = xcalloc (1, sizeof (function_t));
4977bab6 752 fn->name = function_name;
796621e8 753 fn->ident = ident;
4977bab6 754 fn->checksum = checksum;
27283c73
NS
755 fn->src = src;
756 fn->line = lineno;
4977bab6
ZW
757
758 fn->next = functions;
759 functions = fn;
760 current_tag = tag;
f55ade6e 761
27283c73
NS
762 if (lineno >= src->num_lines)
763 src->num_lines = lineno + 1;
764 /* Now insert it into the source file's list of
765 functions. Normally functions will be encountered in
766 ascending order, so a simple scan is quick. */
767 for (probe = src->functions, prev = NULL;
768 probe && probe->line > lineno;
769 prev = probe, probe = probe->line_next)
770 continue;
771 fn->line_next = probe;
772 if (prev)
773 prev->line_next = fn;
774 else
775 src->functions = fn;
b7c9bf28 776 }
4977bab6 777 else if (fn && tag == GCOV_TAG_BLOCKS)
b7c9bf28 778 {
4977bab6
ZW
779 if (fn->blocks)
780 fnotice (stderr, "%s:already seen blocks for `%s'\n",
781 bbg_file_name, fn->name);
782 else
b7c9bf28 783 {
330d2e2a 784 unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
27283c73 785 fn->num_blocks = num_blocks;
f55ade6e 786
703ad42b 787 fn->blocks = xcalloc (fn->num_blocks, sizeof (block_t));
27283c73 788 for (ix = 0; ix != num_blocks; ix++)
94de45d9 789 fn->blocks[ix].flags = gcov_read_unsigned ();
b7c9bf28 790 }
4977bab6
ZW
791 }
792 else if (fn && tag == GCOV_TAG_ARCS)
793 {
94de45d9 794 unsigned src = gcov_read_unsigned ();
330d2e2a 795 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
4977bab6 796
94de45d9 797 if (src >= fn->num_blocks || fn->blocks[src].succ)
4977bab6 798 goto corrupt;
f55ade6e 799
4977bab6 800 while (num_dests--)
b7c9bf28 801 {
4977bab6 802 struct arc_info *arc;
94de45d9
NS
803 unsigned dest = gcov_read_unsigned ();
804 unsigned flags = gcov_read_unsigned ();
f55ade6e 805
94de45d9 806 if (dest >= fn->num_blocks)
4977bab6 807 goto corrupt;
703ad42b 808 arc = xcalloc (1, sizeof (arc_t));
f55ade6e 809
4977bab6
ZW
810 arc->dst = &fn->blocks[dest];
811 arc->src = &fn->blocks[src];
f55ade6e 812
4977bab6
ZW
813 arc->count = 0;
814 arc->count_valid = 0;
815 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
816 arc->fake = !!(flags & GCOV_ARC_FAKE);
817 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
f55ade6e 818
4977bab6
ZW
819 arc->succ_next = fn->blocks[src].succ;
820 fn->blocks[src].succ = arc;
821 fn->blocks[src].num_succ++;
f55ade6e 822
4977bab6
ZW
823 arc->pred_next = fn->blocks[dest].pred;
824 fn->blocks[dest].pred = arc;
825 fn->blocks[dest].num_pred++;
826
27283c73
NS
827 if (arc->fake)
828 {
829 if (src)
830 {
831 /* Exceptional exit from this function, the
832 source block must be a call. */
833 fn->blocks[src].is_call_site = 1;
834 arc->is_call_non_return = 1;
835 }
836 else
837 {
838 /* Non-local return from a callee of this
f55ade6e
AJ
839 function. The destination block is a catch or
840 setjmp. */
27283c73
NS
841 arc->is_nonlocal_return = 1;
842 fn->blocks[dest].is_nonlocal_return = 1;
843 }
844 }
f55ade6e 845
4977bab6
ZW
846 if (!arc->on_tree)
847 fn->num_counts++;
b7c9bf28 848 }
4977bab6
ZW
849 }
850 else if (fn && tag == GCOV_TAG_LINES)
851 {
94de45d9 852 unsigned blockno = gcov_read_unsigned ();
703ad42b 853 unsigned *line_nos = xcalloc (length - 1, sizeof (unsigned));
4977bab6 854
94de45d9 855 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
4977bab6 856 goto corrupt;
f55ade6e 857
4977bab6 858 for (ix = 0; ; )
b7c9bf28 859 {
94de45d9 860 unsigned lineno = gcov_read_unsigned ();
f55ade6e 861
4977bab6 862 if (lineno)
b7c9bf28 863 {
4977bab6
ZW
864 if (!ix)
865 {
866 line_nos[ix++] = 0;
867 line_nos[ix++] = src->index;
868 }
869 line_nos[ix++] = lineno;
870 if (lineno >= src->num_lines)
871 src->num_lines = lineno + 1;
b7c9bf28 872 }
4977bab6
ZW
873 else
874 {
94de45d9 875 const char *file_name = gcov_read_string ();
f55ade6e 876
4977bab6 877 if (!file_name)
b7c9bf28 878 break;
27283c73 879 src = find_source (file_name);
f55ade6e 880
4977bab6
ZW
881 line_nos[ix++] = 0;
882 line_nos[ix++] = src->index;
883 }
b7c9bf28 884 }
f55ade6e 885
27283c73
NS
886 fn->blocks[blockno].u.line.encoding = line_nos;
887 fn->blocks[blockno].u.line.num = ix;
4977bab6
ZW
888 }
889 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
890 {
891 fn = NULL;
892 current_tag = 0;
893 }
474f141e 894 gcov_sync (base, length);
94de45d9 895 if (gcov_is_error ())
7d63a2fa
NS
896 break;
897 }
898 if (!gcov_is_eof ())
899 {
900 corrupt:;
901 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
902 gcov_close ();
903 return 1;
b7c9bf28 904 }
546d2adb 905 gcov_close ();
f55ade6e 906
4977bab6 907 /* We built everything backwards, so nreverse them all */
f55ade6e 908
4977bab6
ZW
909 /* Reverse sources. Not strictly necessary, but we'll then process
910 them in the 'expected' order. */
911 {
912 source_t *src, *src_p, *src_n;
913
914 for (src_p = NULL, src = sources; src; src_p = src, src = src_n)
915 {
916 src_n = src->next;
917 src->next = src_p;
918 }
919 sources = src_p;
920 }
b7c9bf28 921
4977bab6
ZW
922 /* Reverse functions. */
923 {
924 function_t *fn, *fn_p, *fn_n;
b7c9bf28 925
4977bab6
ZW
926 for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn_n)
927 {
928 unsigned ix;
f55ade6e 929
4977bab6
ZW
930 fn_n = fn->next;
931 fn->next = fn_p;
b7c9bf28 932
f9da5064 933 /* Reverse the arcs. */
4977bab6
ZW
934 for (ix = fn->num_blocks; ix--;)
935 {
936 arc_t *arc, *arc_p, *arc_n;
f55ade6e 937
4977bab6
ZW
938 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
939 arc_p = arc, arc = arc_n)
940 {
941 arc_n = arc->succ_next;
942 arc->succ_next = arc_p;
943 }
944 fn->blocks[ix].succ = arc_p;
945
946 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
947 arc_p = arc, arc = arc_n)
948 {
949 arc_n = arc->pred_next;
950 arc->pred_next = arc_p;
951 }
952 fn->blocks[ix].pred = arc_p;
953 }
954 }
955 functions = fn_p;
956 }
957 return 0;
b7c9bf28 958}
86144b75 959
4977bab6 960/* Reads profiles from the count file and attach to each
272d0bee 961 function. Return nonzero if fatal error. */
86144b75 962
4977bab6 963static int
f55ade6e 964read_count_file (void)
86144b75 965{
4977bab6 966 unsigned ix;
94de45d9 967 unsigned version;
7d63a2fa 968 unsigned tag;
4977bab6 969 function_t *fn = NULL;
7d63a2fa 970 int error = 0;
4977bab6 971
546d2adb 972 if (!gcov_open (da_file_name, 1))
86144b75 973 {
4977bab6
ZW
974 fnotice (stderr, "%s:cannot open data file\n", da_file_name);
975 return 1;
976 }
160e2e4f 977 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
4977bab6
ZW
978 {
979 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
980 cleanup:;
546d2adb 981 gcov_close ();
4977bab6
ZW
982 return 1;
983 }
94de45d9
NS
984 version = gcov_read_unsigned ();
985 if (version != GCOV_VERSION)
4977bab6 986 {
330d2e2a
NS
987 char v[4], e[4];
988
989 GCOV_UNSIGNED2STRING (v, version);
990 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
160e2e4f 991
4977bab6 992 fnotice (stderr, "%s:version `%.4s', prefer version `%.4s'\n",
330d2e2a 993 da_file_name, v, e);
86144b75 994 }
dd486eb2
NS
995 tag = gcov_read_unsigned ();
996 if (tag != bbg_stamp)
997 {
998 fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
999 goto cleanup;
1000 }
f55ade6e 1001
7d63a2fa 1002 while ((tag = gcov_read_unsigned ()))
4977bab6 1003 {
94de45d9
NS
1004 unsigned length = gcov_read_unsigned ();
1005 unsigned long base = gcov_position ();
94de45d9 1006
27283c73 1007 if (tag == GCOV_TAG_OBJECT_SUMMARY)
94de45d9 1008 gcov_read_summary (&object_summary);
cdb23767 1009 else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
94de45d9 1010 program_count++;
27283c73 1011 else if (tag == GCOV_TAG_FUNCTION)
86144b75 1012 {
796621e8 1013 unsigned ident = gcov_read_unsigned ();
4977bab6 1014 struct function_info *fn_n = functions;
4977bab6
ZW
1015
1016 for (fn = fn ? fn->next : NULL; ; fn = fn->next)
86144b75 1017 {
4977bab6
ZW
1018 if (fn)
1019 ;
1020 else if ((fn = fn_n))
1021 fn_n = NULL;
1022 else
86144b75 1023 {
796621e8
NS
1024 fnotice (stderr, "%s:unknown function `%u'\n",
1025 da_file_name, ident);
4977bab6 1026 break;
86144b75 1027 }
796621e8 1028 if (fn->ident == ident)
4977bab6 1029 break;
86144b75 1030 }
4977bab6
ZW
1031
1032 if (!fn)
1033 ;
94de45d9 1034 else if (gcov_read_unsigned () != fn->checksum)
86144b75 1035 {
4977bab6
ZW
1036 mismatch:;
1037 fnotice (stderr, "%s:profile mismatch for `%s'\n",
94de45d9 1038 da_file_name, fn->name);
4977bab6
ZW
1039 goto cleanup;
1040 }
1041 }
cdb23767 1042 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
4977bab6 1043 {
330d2e2a 1044 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
4977bab6 1045 goto mismatch;
f55ade6e 1046
4977bab6 1047 if (!fn->counts)
703ad42b 1048 fn->counts = xcalloc (fn->num_counts, sizeof (gcov_type));
f55ade6e 1049
4977bab6 1050 for (ix = 0; ix != fn->num_counts; ix++)
94de45d9
NS
1051 fn->counts[ix] += gcov_read_counter ();
1052 }
474f141e 1053 gcov_sync (base, length);
94de45d9 1054 if ((error = gcov_is_error ()))
7d63a2fa 1055 break;
86144b75 1056 }
23190837 1057
7d63a2fa
NS
1058 if (!gcov_is_eof ())
1059 {
1060 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1061 da_file_name);
1062 goto cleanup;
1063 }
f55ade6e 1064
546d2adb 1065 gcov_close ();
4977bab6 1066 return 0;
86144b75
DE
1067}
1068
4977bab6
ZW
1069/* Solve the flow graph. Propagate counts from the instrumented arcs
1070 to the blocks and the uninstrumented arcs. */
86144b75
DE
1071
1072static void
f55ade6e 1073solve_flow_graph (function_t *fn)
86144b75 1074{
4977bab6
ZW
1075 unsigned ix;
1076 arc_t *arc;
1077 gcov_type *count_ptr = fn->counts;
27283c73 1078 block_t *blk;
32dd366d
KH
1079 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */
1080 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
f55ade6e 1081
4977bab6
ZW
1082 if (fn->num_blocks < 2)
1083 fnotice (stderr, "%s:`%s' lacks entry and/or exit blocks\n",
1084 bbg_file_name, fn->name);
1085 else
86144b75 1086 {
4977bab6
ZW
1087 if (fn->blocks[0].num_pred)
1088 fnotice (stderr, "%s:`%s' has arcs to entry block\n",
1089 bbg_file_name, fn->name);
86144b75 1090 else
4977bab6
ZW
1091 /* We can't deduce the entry block counts from the lack of
1092 predecessors. */
1093 fn->blocks[0].num_pred = ~(unsigned)0;
f55ade6e 1094
4977bab6
ZW
1095 if (fn->blocks[fn->num_blocks - 1].num_succ)
1096 fnotice (stderr, "%s:`%s' has arcs from exit block\n",
1097 bbg_file_name, fn->name);
1098 else
1099 /* Likewise, we can't deduce exit block counts from the lack
1100 of its successors. */
1101 fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0;
86144b75
DE
1102 }
1103
4977bab6
ZW
1104 /* Propagate the measured counts, this must be done in the same
1105 order as the code in profile.c */
27283c73 1106 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
86144b75 1107 {
4977bab6
ZW
1108 block_t const *prev_dst = NULL;
1109 int out_of_order = 0;
27283c73 1110 int non_fake_succ = 0;
f55ade6e 1111
27283c73 1112 for (arc = blk->succ; arc; arc = arc->succ_next)
86144b75 1113 {
27283c73
NS
1114 if (!arc->fake)
1115 non_fake_succ++;
f55ade6e 1116
4977bab6 1117 if (!arc->on_tree)
86144b75 1118 {
4977bab6
ZW
1119 if (count_ptr)
1120 arc->count = *count_ptr++;
1121 arc->count_valid = 1;
27283c73 1122 blk->num_succ--;
4977bab6 1123 arc->dst->num_pred--;
86144b75 1124 }
4977bab6
ZW
1125 if (prev_dst && prev_dst > arc->dst)
1126 out_of_order = 1;
1127 prev_dst = arc->dst;
86144b75 1128 }
27283c73
NS
1129 if (non_fake_succ == 1)
1130 {
1131 /* If there is only one non-fake exit, it is an
1132 unconditional branch. */
1133 for (arc = blk->succ; arc; arc = arc->succ_next)
1134 if (!arc->fake)
1135 {
1136 arc->is_unconditional = 1;
1137 /* If this block is instrumenting a call, it might be
e0bb17a8 1138 an artificial block. It is not artificial if it has
10b7602f
NS
1139 a non-fallthrough exit, or the destination of this
1140 arc has more than one entry. Mark the destination
1141 block as a return site, if none of those conditions
1142 hold. */
1143 if (blk->is_call_site && arc->fall_through
1144 && arc->dst->pred == arc && !arc->pred_next)
1145 arc->dst->is_call_return = 1;
27283c73
NS
1146 }
1147 }
f55ade6e 1148
4977bab6
ZW
1149 /* Sort the successor arcs into ascending dst order. profile.c
1150 normally produces arcs in the right order, but sometimes with
1151 one or two out of order. We're not using a particularly
32dd366d 1152 smart sort. */
4977bab6 1153 if (out_of_order)
86144b75 1154 {
27283c73 1155 arc_t *start = blk->succ;
4977bab6 1156 unsigned changes = 1;
f55ade6e 1157
4977bab6
ZW
1158 while (changes)
1159 {
1160 arc_t *arc, *arc_p, *arc_n;
f55ade6e 1161
4977bab6
ZW
1162 changes = 0;
1163 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1164 {
1165 if (arc->dst > arc_n->dst)
1166 {
1167 changes = 1;
1168 if (arc_p)
1169 arc_p->succ_next = arc_n;
1170 else
1171 start = arc_n;
1172 arc->succ_next = arc_n->succ_next;
1173 arc_n->succ_next = arc;
1174 arc_p = arc_n;
1175 }
1176 else
1177 {
1178 arc_p = arc;
1179 arc = arc_n;
1180 }
1181 }
1182 }
27283c73 1183 blk->succ = start;
86144b75 1184 }
f55ade6e 1185
4977bab6
ZW
1186 /* Place it on the invalid chain, it will be ignored if that's
1187 wrong. */
27283c73
NS
1188 blk->invalid_chain = 1;
1189 blk->chain = invalid_blocks;
1190 invalid_blocks = blk;
4977bab6
ZW
1191 }
1192
1193 while (invalid_blocks || valid_blocks)
1194 {
4977bab6 1195 while ((blk = invalid_blocks))
86144b75 1196 {
4977bab6
ZW
1197 gcov_type total = 0;
1198 const arc_t *arc;
f55ade6e 1199
4977bab6
ZW
1200 invalid_blocks = blk->chain;
1201 blk->invalid_chain = 0;
1202 if (!blk->num_succ)
1203 for (arc = blk->succ; arc; arc = arc->succ_next)
1204 total += arc->count;
1205 else if (!blk->num_pred)
1206 for (arc = blk->pred; arc; arc = arc->pred_next)
1207 total += arc->count;
1208 else
1209 continue;
f55ade6e 1210
4977bab6
ZW
1211 blk->count = total;
1212 blk->count_valid = 1;
1213 blk->chain = valid_blocks;
1214 blk->valid_chain = 1;
1215 valid_blocks = blk;
86144b75 1216 }
4977bab6 1217 while ((blk = valid_blocks))
86144b75 1218 {
4977bab6
ZW
1219 gcov_type total;
1220 arc_t *arc, *inv_arc;
1221
1222 valid_blocks = blk->chain;
1223 blk->valid_chain = 0;
1224 if (blk->num_succ == 1)
1225 {
1226 block_t *dst;
f55ade6e 1227
4977bab6
ZW
1228 total = blk->count;
1229 inv_arc = NULL;
1230 for (arc = blk->succ; arc; arc = arc->succ_next)
1231 {
1232 total -= arc->count;
1233 if (!arc->count_valid)
1234 inv_arc = arc;
1235 }
1236 dst = inv_arc->dst;
1237 inv_arc->count_valid = 1;
1238 inv_arc->count = total;
1239 blk->num_succ--;
1240 dst->num_pred--;
1241 if (dst->count_valid)
1242 {
1243 if (dst->num_pred == 1 && !dst->valid_chain)
1244 {
1245 dst->chain = valid_blocks;
1246 dst->valid_chain = 1;
1247 valid_blocks = dst;
1248 }
1249 }
1250 else
1251 {
1252 if (!dst->num_pred && !dst->invalid_chain)
1253 {
1254 dst->chain = invalid_blocks;
1255 dst->invalid_chain = 1;
1256 invalid_blocks = dst;
1257 }
1258 }
1259 }
1260 if (blk->num_pred == 1)
1261 {
1262 block_t *src;
f55ade6e 1263
4977bab6
ZW
1264 total = blk->count;
1265 inv_arc = NULL;
1266 for (arc = blk->pred; arc; arc = arc->pred_next)
1267 {
1268 total -= arc->count;
1269 if (!arc->count_valid)
1270 inv_arc = arc;
1271 }
1272 src = inv_arc->src;
1273 inv_arc->count_valid = 1;
1274 inv_arc->count = total;
1275 blk->num_pred--;
1276 src->num_succ--;
1277 if (src->count_valid)
1278 {
1279 if (src->num_succ == 1 && !src->valid_chain)
1280 {
1281 src->chain = valid_blocks;
1282 src->valid_chain = 1;
1283 valid_blocks = src;
1284 }
1285 }
1286 else
1287 {
1288 if (!src->num_succ && !src->invalid_chain)
1289 {
1290 src->chain = invalid_blocks;
1291 src->invalid_chain = 1;
1292 invalid_blocks = src;
1293 }
1294 }
1295 }
86144b75
DE
1296 }
1297 }
f55ade6e 1298
4977bab6
ZW
1299 /* If the graph has been correctly solved, every block will have a
1300 valid count. */
1301 for (ix = 0; ix < fn->num_blocks; ix++)
1302 if (!fn->blocks[ix].count_valid)
1303 {
1304 fnotice (stderr, "%s:graph is unsolvable for `%s'\n",
1305 bbg_file_name, fn->name);
1306 break;
1307 }
86144b75 1308}
4977bab6 1309
86144b75 1310\f
86144b75 1311
4977bab6 1312/* Increment totals in COVERAGE according to arc ARC. */
8b219a76
NS
1313
1314static void
f55ade6e 1315add_branch_counts (coverage_t *coverage, const arc_t *arc)
8b219a76 1316{
27283c73 1317 if (arc->is_call_non_return)
8b219a76 1318 {
4977bab6
ZW
1319 coverage->calls++;
1320 if (arc->src->count)
1321 coverage->calls_executed++;
8b219a76 1322 }
27283c73 1323 else if (!arc->is_unconditional)
8b219a76 1324 {
4977bab6
ZW
1325 coverage->branches++;
1326 if (arc->src->count)
1327 coverage->branches_executed++;
1328 if (arc->count)
1329 coverage->branches_taken++;
86144b75
DE
1330 }
1331}
1332
37b8715b
NS
1333/* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1334 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1335 If DP is zero, no decimal point is printed. Only print 100% when
1336 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1337 format TOP. Return pointer to a static string. */
1338
1339static char const *
f55ade6e 1340format_gcov (gcov_type top, gcov_type bottom, int dp)
37b8715b
NS
1341{
1342 static char buffer[20];
f55ade6e 1343
37b8715b
NS
1344 if (dp >= 0)
1345 {
1346 float ratio = bottom ? (float)top / bottom : 0;
1347 int ix;
1348 unsigned limit = 100;
1349 unsigned percent;
f55ade6e 1350
37b8715b
NS
1351 for (ix = dp; ix--; )
1352 limit *= 10;
f55ade6e 1353
d19202ba
NS
1354 percent = (unsigned) (ratio * limit + (float)0.5);
1355 if (percent <= 0 && top)
37b8715b 1356 percent = 1;
d19202ba 1357 else if (percent >= limit && top != bottom)
37b8715b
NS
1358 percent = limit - 1;
1359 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1360 if (dp)
1361 {
1362 dp++;
1363 do
1364 {
1365 buffer[ix+1] = buffer[ix];
1366 ix--;
1367 }
1368 while (dp--);
1369 buffer[ix + 1] = '.';
1370 }
1371 }
1372 else
4977bab6 1373 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
f55ade6e 1374
37b8715b
NS
1375 return buffer;
1376}
1377
1378
86144b75
DE
1379/* Output summary info for a function. */
1380
1381static void
f55ade6e 1382function_summary (const coverage_t *coverage, const char *title)
86144b75 1383{
4977bab6
ZW
1384 fnotice (stdout, "%s `%s'\n", title, coverage->name);
1385
1386 if (coverage->lines)
1387 fnotice (stdout, "Lines executed:%s of %d\n",
1388 format_gcov (coverage->lines_executed, coverage->lines, 2),
1389 coverage->lines);
86144b75 1390 else
4977bab6 1391 fnotice (stdout, "No executable lines");
86144b75 1392
4977bab6 1393 if (flag_branches)
86144b75 1394 {
4977bab6 1395 if (coverage->branches)
86144b75 1396 {
4977bab6
ZW
1397 fnotice (stdout, "Branches executed:%s of %d\n",
1398 format_gcov (coverage->branches_executed,
1399 coverage->branches, 2),
1400 coverage->branches);
1401 fnotice (stdout, "Taken at least once:%s of %d\n",
1402 format_gcov (coverage->branches_taken,
1403 coverage->branches, 2),
1404 coverage->branches);
86144b75
DE
1405 }
1406 else
4977bab6
ZW
1407 fnotice (stdout, "No branches\n");
1408 if (coverage->calls)
1409 fnotice (stdout, "Calls executed:%s of %d\n",
1410 format_gcov (coverage->calls_executed, coverage->calls, 2),
1411 coverage->calls);
86144b75 1412 else
4977bab6 1413 fnotice (stdout, "No calls\n");
8b219a76
NS
1414 }
1415}
1416
1417/* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1418 affect name generation. With preserve_paths we create a filename
1419 from all path components of the source file, replacing '/' with
1420 '#', without it we simply take the basename component. With
1421 long_output_names we prepend the processed name of the input file
1422 to each output name (except when the current source file is the
1423 input file, so you don't get a double concatenation). The two
1424 components are separated by '##'. Also '.' filename components are
4b7e68e7 1425 removed and '..' components are renamed to '^'. */
8b219a76
NS
1426
1427static char *
f55ade6e 1428make_gcov_file_name (const char *input_name, const char *src_name)
8b219a76
NS
1429{
1430 char *cptr;
4977bab6 1431 char *name = xmalloc (strlen (src_name) + strlen (input_name) + 10);
f55ade6e 1432
8b219a76 1433 name[0] = 0;
4977bab6 1434 if (flag_long_names && strcmp (src_name, input_name))
8b219a76
NS
1435 {
1436 /* Generate the input filename part. */
4977bab6
ZW
1437 cptr = flag_preserve_paths ? NULL : strrchr (input_name, '/');
1438 strcat (name, cptr ? cptr + 1 : input_name);
8b219a76
NS
1439 strcat (name, "##");
1440 }
f55ade6e 1441
4b7e68e7 1442 /* Generate the source filename part. */
4977bab6
ZW
1443 cptr = flag_preserve_paths ? NULL : strrchr (src_name, '/');
1444 strcat (name, cptr ? cptr + 1 : src_name);
f55ade6e 1445
4977bab6 1446 if (flag_preserve_paths)
8b219a76
NS
1447 {
1448 /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1449 char *prev;
f55ade6e 1450
8b219a76 1451 for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
f55ade6e
AJ
1452 {
1453 unsigned shift = 0;
1454
1455 if (prev + 1 == cptr && prev[0] == '.')
1456 {
1457 /* Remove '.' */
1458 shift = 2;
1459 }
1460 else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
1461 {
1462 /* Convert '..' */
1463 shift = 1;
1464 prev[1] = '^';
1465 }
1466 else
1467 *cptr++ = '#';
1468 if (shift)
1469 {
1470 cptr = prev;
1471 do
1472 prev[0] = prev[shift];
8b219a76 1473 while (*prev++);
f55ade6e
AJ
1474 }
1475 }
86144b75 1476 }
f55ade6e 1477
8b219a76
NS
1478 strcat (name, ".gcov");
1479 return name;
86144b75
DE
1480}
1481
4977bab6 1482/* Scan through the bb_data for each line in the block, increment
8b219a76
NS
1483 the line number execution count indicated by the execution count of
1484 the appropriate basic block. */
86144b75
DE
1485
1486static void
f55ade6e 1487add_line_counts (coverage_t *coverage, function_t *fn)
86144b75 1488{
4977bab6 1489 unsigned ix;
beb235f8 1490 line_t *line = NULL; /* This is propagated from one iteration to the
4977bab6
ZW
1491 next. */
1492
32dd366d 1493 /* Scan each basic block. */
4977bab6 1494 for (ix = 0; ix != fn->num_blocks; ix++)
86144b75 1495 {
27283c73 1496 block_t *block = &fn->blocks[ix];
4977bab6
ZW
1497 unsigned *encoding;
1498 const source_t *src = NULL;
1499 unsigned jx;
1500
27283c73
NS
1501 if (block->count && ix && ix + 1 != fn->num_blocks)
1502 fn->blocks_executed++;
1503 for (jx = 0, encoding = block->u.line.encoding;
1504 jx != block->u.line.num; jx++, encoding++)
4977bab6
ZW
1505 if (!*encoding)
1506 {
1507 unsigned src_n = *++encoding;
86144b75 1508
4977bab6
ZW
1509 for (src = sources; src->index != src_n; src = src->next)
1510 continue;
1511 jx++;
1512 }
1513 else
1514 {
1515 line = &src->lines[*encoding];
1516
1517 if (coverage)
1518 {
1519 if (!line->exists)
1520 coverage->lines++;
27283c73 1521 if (!line->count && block->count)
4977bab6
ZW
1522 coverage->lines_executed++;
1523 }
1524 line->exists = 1;
1525 line->count += block->count;
1526 }
27283c73 1527 free (block->u.line.encoding);
10b7602f
NS
1528 block->u.cycle.arc = NULL;
1529 block->u.cycle.ident = ~0U;
f55ade6e 1530
27283c73
NS
1531 if (!ix || ix + 1 == fn->num_blocks)
1532 /* Entry or exit block */;
1533 else if (flag_all_blocks)
86144b75 1534 {
10b7602f 1535 line_t *block_line = line ? line : &fn->src->lines[fn->line];
f55ade6e 1536
10b7602f
NS
1537 block->chain = block_line->u.blocks;
1538 block_line->u.blocks = block;
27283c73
NS
1539 }
1540 else if (flag_branches)
1541 {
1542 arc_t *arc;
1543
4977bab6 1544 for (arc = block->succ; arc; arc = arc->succ_next)
86144b75 1545 {
27283c73
NS
1546 arc->line_next = line->u.branches;
1547 line->u.branches = arc;
1548 if (coverage && !arc->is_unconditional)
4977bab6 1549 add_branch_counts (coverage, arc);
86144b75 1550 }
8b219a76
NS
1551 }
1552 }
4977bab6
ZW
1553 if (!line)
1554 fnotice (stderr, "%s:no lines for `%s'\n", bbg_file_name, fn->name);
1555}
1556
32dd366d 1557/* Accumulate the line counts of a file. */
4977bab6
ZW
1558
1559static void
f55ade6e 1560accumulate_line_counts (source_t *src)
4977bab6
ZW
1561{
1562 line_t *line;
27283c73 1563 function_t *fn, *fn_p, *fn_n;
4977bab6 1564 unsigned ix;
27283c73
NS
1565
1566 /* Reverse the function order. */
1567 for (fn = src->functions, fn_p = NULL; fn;
1568 fn_p = fn, fn = fn_n)
1569 {
1570 fn_n = fn->line_next;
1571 fn->line_next = fn_p;
1572 }
1573 src->functions = fn_p;
f55ade6e 1574
4977bab6 1575 for (ix = src->num_lines, line = src->lines; ix--; line++)
8b219a76 1576 {
27283c73 1577 if (!flag_all_blocks)
8b219a76 1578 {
27283c73 1579 arc_t *arc, *arc_p, *arc_n;
f55ade6e 1580
27283c73
NS
1581 /* Total and reverse the branch information. */
1582 for (arc = line->u.branches, arc_p = NULL; arc;
1583 arc_p = arc, arc = arc_n)
1584 {
1585 arc_n = arc->line_next;
1586 arc->line_next = arc_p;
f55ade6e 1587
27283c73
NS
1588 add_branch_counts (&src->coverage, arc);
1589 }
1590 line->u.branches = arc_p;
8b219a76 1591 }
27283c73
NS
1592 else if (line->u.blocks)
1593 {
1594 /* The user expects the line count to be the number of times
1595 a line has been executed. Simply summing the block count
1596 will give an artificially high number. The Right Thing
10b7602f
NS
1597 is to sum the entry counts to the graph of blocks on this
1598 line, then find the elementary cycles of the local graph
1599 and add the transition counts of those cycles. */
27283c73 1600 block_t *block, *block_p, *block_n;
27283c73 1601 gcov_type count = 0;
f55ade6e 1602
f9da5064 1603 /* Reverse the block information. */
27283c73
NS
1604 for (block = line->u.blocks, block_p = NULL; block;
1605 block_p = block, block = block_n)
1606 {
1607 block_n = block->chain;
1608 block->chain = block_p;
10b7602f 1609 block->u.cycle.ident = ix;
27283c73
NS
1610 }
1611 line->u.blocks = block_p;
f55ade6e 1612
10b7602f
NS
1613 /* Sum the entry arcs. */
1614 for (block = line->u.blocks; block; block = block->chain)
1615 {
1616 arc_t *arc;
86144b75 1617
10b7602f
NS
1618 for (arc = block->pred; arc; arc = arc->pred_next)
1619 {
1620 if (arc->src->u.cycle.ident != ix)
1621 count += arc->count;
1622 if (flag_branches)
1623 add_branch_counts (&src->coverage, arc);
1624 }
1625 }
1626
1627 /* Find the loops. This uses the algorithm described in
1628 Tiernan 'An Efficient Search Algorithm to Find the
1629 Elementary Circuits of a Graph', CACM Dec 1970. We hold
1630 the P array by having each block point to the arc that
1631 connects to the previous block. The H array is implicitly
1632 held because of the arc ordering, and the block's
1633 previous arc pointer.
1634
1635 Although the algorithm is O(N^3) for highly connected
1636 graphs, at worst we'll have O(N^2), as most blocks have
1637 only one or two exits. Most graphs will be small.
1638
1639 For each loop we find, locate the arc with the smallest
1640 transition count, and add that to the cumulative
1641 count. Remove the arc from consideration. */
1642 for (block = line->u.blocks; block; block = block->chain)
27283c73 1643 {
10b7602f
NS
1644 block_t *head = block;
1645 arc_t *arc;
f55ade6e 1646
10b7602f
NS
1647 next_vertex:;
1648 arc = head->succ;
1649 current_vertex:;
1650 while (arc)
27283c73 1651 {
10b7602f
NS
1652 block_t *dst = arc->dst;
1653 if (/* Already used that arc. */
1654 arc->cycle
1655 /* Not to same graph, or before first vertex. */
1656 || dst->u.cycle.ident != ix
1657 /* Already in path. */
1658 || dst->u.cycle.arc)
1659 {
1660 arc = arc->succ_next;
1661 continue;
1662 }
f55ade6e 1663
10b7602f 1664 if (dst == block)
27283c73 1665 {
10b7602f
NS
1666 /* Found a closing arc. */
1667 gcov_type cycle_count = arc->count;
1668 arc_t *cycle_arc = arc;
1669 arc_t *probe_arc;
f55ade6e 1670
71c0e7fc 1671 /* Locate the smallest arc count of the loop. */
10b7602f
NS
1672 for (dst = head; (probe_arc = dst->u.cycle.arc);
1673 dst = probe_arc->src)
1674 if (cycle_count > probe_arc->count)
1675 {
1676 cycle_count = probe_arc->count;
1677 cycle_arc = probe_arc;
1678 }
f55ade6e 1679
10b7602f
NS
1680 count += cycle_count;
1681 cycle_arc->cycle = 1;
1682 /* Unwind to the cyclic arc. */
1683 while (head != cycle_arc->src)
27283c73 1684 {
10b7602f
NS
1685 arc = head->u.cycle.arc;
1686 head = arc->src;
27283c73 1687 }
10b7602f
NS
1688 /* Move on. */
1689 arc = arc->succ_next;
1690 continue;
27283c73 1691 }
f55ade6e 1692
10b7602f
NS
1693 /* Add new block to chain. */
1694 dst->u.cycle.arc = arc;
1695 head = dst;
1696 goto next_vertex;
27283c73 1697 }
10b7602f
NS
1698 /* We could not add another vertex to the path. Remove
1699 the last vertex from the list. */
1700 arc = head->u.cycle.arc;
1701 if (arc)
27283c73 1702 {
71c0e7fc 1703 /* It was not the first vertex. Move onto next arc. */
10b7602f
NS
1704 head->u.cycle.arc = NULL;
1705 head = arc->src;
1706 arc = arc->succ_next;
1707 goto current_vertex;
27283c73 1708 }
10b7602f
NS
1709 /* Mark this block as unusable. */
1710 block->u.cycle.ident = ~0U;
27283c73 1711 }
10b7602f 1712
27283c73
NS
1713 line->count = count;
1714 }
f55ade6e 1715
4977bab6 1716 if (line->exists)
8b219a76 1717 {
4977bab6
ZW
1718 src->coverage.lines++;
1719 if (line->count)
1720 src->coverage.lines_executed++;
8b219a76 1721 }
8b219a76
NS
1722 }
1723}
86144b75 1724
6356f892 1725/* Ouput information about ARC number IX. Returns nonzero if
27283c73
NS
1726 anything is output. */
1727
1728static int
f55ade6e 1729output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
27283c73 1730{
f55ade6e 1731
27283c73
NS
1732 if (arc->is_call_non_return)
1733 {
1734 if (arc->src->count)
1735 {
1736 fnotice (gcov_file, "call %2d returned %s\n", ix,
1737 format_gcov (arc->src->count - arc->count,
1738 arc->src->count, -flag_counts));
1739 }
1740 else
1741 fnotice (gcov_file, "call %2d never executed\n", ix);
1742 }
1743 else if (!arc->is_unconditional)
1744 {
1745 if (arc->src->count)
1746 fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
1747 format_gcov (arc->count, arc->src->count, -flag_counts),
1748 arc->fall_through ? " (fallthrough)" : "");
1749 else
1750 fnotice (gcov_file, "branch %2d never executed\n", ix);
1751 }
10b7602f 1752 else if (flag_unconditional && !arc->dst->is_call_return)
27283c73
NS
1753 {
1754 if (arc->src->count)
1755 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
1756 format_gcov (arc->count, arc->src->count, -flag_counts));
1757 else
1758 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
1759 }
1760 else
1761 return 0;
1762 return 1;
f55ade6e 1763
27283c73
NS
1764}
1765
8b219a76
NS
1766/* Read in the source file one line at a time, and output that line to
1767 the gcov file preceded by its execution count and other
1768 information. */
86144b75 1769
8b219a76 1770static void
f55ade6e 1771output_lines (FILE *gcov_file, const source_t *src)
8b219a76
NS
1772{
1773 FILE *source_file;
f55ade6e 1774 unsigned line_num; /* current line number. */
4977bab6
ZW
1775 const line_t *line; /* current line info ptr. */
1776 char string[STRING_SIZE]; /* line buffer. */
1777 char const *retval = ""; /* status of source file reading. */
27283c73 1778 function_t *fn = src->functions;
4977bab6
ZW
1779
1780 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
1781 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
1782 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, da_file_name);
cdb23767
NS
1783 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
1784 object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
27283c73 1785 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
f55ade6e 1786
4977bab6 1787 source_file = fopen (src->name, "r");
8b219a76
NS
1788 if (!source_file)
1789 {
4977bab6 1790 fnotice (stderr, "%s:cannot open source file\n", src->name);
8b219a76
NS
1791 retval = NULL;
1792 }
1793 else
1794 {
1795 struct stat status;
f55ade6e 1796
8b219a76 1797 if (!fstat (fileno (source_file), &status)
4977bab6 1798 && status.st_mtime > bbg_file_time)
8b219a76 1799 {
4977bab6
ZW
1800 fnotice (stderr, "%s:source file is newer than graph file `%s'\n",
1801 src->name, bbg_file_name);
1802 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n",
8b219a76
NS
1803 "-", 0);
1804 }
1805 }
1806
4977bab6
ZW
1807 for (line_num = 1, line = &src->lines[line_num];
1808 line_num < src->num_lines; line_num++, line++)
8b219a76 1809 {
27283c73
NS
1810 for (; fn && fn->line == line_num; fn = fn->line_next)
1811 {
1812 arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
1813 gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
1814
1815 for (; arc; arc = arc->pred_next)
1816 if (arc->fake)
1817 return_count -= arc->count;
f55ade6e 1818
27283c73
NS
1819 fprintf (gcov_file, "function %s", fn->name);
1820 fprintf (gcov_file, " called %s",
1821 format_gcov (fn->blocks[0].count, 0, -1));
1822 fprintf (gcov_file, " returned %s",
1823 format_gcov (return_count, fn->blocks[0].count, 0));
1824 fprintf (gcov_file, " blocks executed %s",
1825 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
1826 fprintf (gcov_file, "\n");
1827 }
f55ade6e 1828
8b219a76 1829 /* For lines which don't exist in the .bb file, print '-' before
f55ade6e
AJ
1830 the source line. For lines which exist but were never
1831 executed, print '#####' before the source line. Otherwise,
1832 print the execution count before the source line. There are
1833 16 spaces of indentation added before the source line so that
1834 tabs won't be messed up. */
4977bab6
ZW
1835 fprintf (gcov_file, "%9s:%5u:",
1836 !line->exists ? "-" : !line->count ? "#####"
1837 : format_gcov (line->count, 0, -1), line_num);
f55ade6e 1838
8b219a76
NS
1839 if (retval)
1840 {
1841 /* Copy source line. */
1842 do
1843 {
1844 retval = fgets (string, STRING_SIZE, source_file);
1845 if (!retval)
299f79b5 1846 break;
8b219a76 1847 fputs (retval, gcov_file);
37b8715b 1848 }
8b219a76
NS
1849 while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1850 }
1851 if (!retval)
299f79b5 1852 fputs ("/*EOF*/\n", gcov_file);
27283c73
NS
1853
1854 if (flag_all_blocks)
8b219a76 1855 {
27283c73 1856 block_t *block;
10b7602f 1857 arc_t *arc;
27283c73 1858 int ix, jx;
f55ade6e 1859
27283c73
NS
1860 for (ix = jx = 0, block = line->u.blocks; block;
1861 block = block->chain)
37b8715b 1862 {
10b7602f 1863 if (!block->is_call_return)
27283c73
NS
1864 fprintf (gcov_file, "%9s:%5u-block %2d\n",
1865 !line->exists ? "-" : !block->count ? "$$$$$"
10b7602f
NS
1866 : format_gcov (block->count, 0, -1),
1867 line_num, ix++);
27283c73
NS
1868 if (flag_branches)
1869 for (arc = block->succ; arc; arc = arc->succ_next)
1870 jx += output_branch_count (gcov_file, jx, arc);
86144b75 1871 }
8b219a76 1872 }
27283c73
NS
1873 else if (flag_branches)
1874 {
1875 int ix;
1876 arc_t *arc;
f55ade6e 1877
27283c73
NS
1878 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
1879 ix += output_branch_count (gcov_file, ix, arc);
1880 }
8b219a76 1881 }
f55ade6e 1882
8b219a76
NS
1883 /* Handle all remaining source lines. There may be lines after the
1884 last line of code. */
1885 if (retval)
1886 {
1887 for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
1888 {
4977bab6 1889 fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval);
f55ade6e 1890
8b219a76 1891 while (!retval[0] || retval[strlen (retval) - 1] != '\n')
37b8715b 1892 {
8b219a76
NS
1893 retval = fgets (string, STRING_SIZE, source_file);
1894 if (!retval)
1895 break;
1896 fputs (retval, gcov_file);
37b8715b 1897 }
8b219a76
NS
1898 }
1899 }
f55ade6e 1900
8b219a76
NS
1901 if (source_file)
1902 fclose (source_file);
1903}