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