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