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