]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gcov.c
backport: As described in http://gcc.gnu.org/ml/gcc/2012-08/msg00015.html...
[thirdparty/gcc.git] / gcc / gcov.c
CommitLineData
86144b75
DE
1/* Gcov.c: prepend line execution counts and branch probabilities to a
2 source file.
a6d6c2c0 3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
66f1b195 4 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
0e5997c0 5 Free Software Foundation, Inc.
86144b75 6 Contributed by James E. Wilson of Cygnus Support.
1d300e19 7 Mangled by Bob Manson of Cygnus Support.
4977bab6 8 Mangled further by Nathan Sidwell <nathan@codesourcery.com>
86144b75
DE
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
9dcd6f09 12the Free Software Foundation; either version 3, or (at your option)
86144b75
DE
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
9dcd6f09
NC
21along with Gcov; see the file COPYING3. If not see
22<http://www.gnu.org/licenses/>. */
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/* Need an option to show individual block counts, and show
33 probabilities of fall through arcs. */
86144b75 34
1d300e19 35#include "config.h"
b04cd507 36#include "system.h"
4977bab6
ZW
37#include "coretypes.h"
38#include "tm.h"
ab87f8c8 39#include "intl.h"
2691e6d7 40#include "diagnostic.h"
5735c3ea 41#include "version.h"
86144b75 42
5735c3ea
JM
43#include <getopt.h>
44
546d2adb 45#define IN_GCOV 1
86144b75 46#include "gcov-io.h"
d79f9ec9 47#include "gcov-io.c"
86144b75 48
1a9075e2 49/* The gcno file is generated by -ftest-coverage option. The gcda file is
4977bab6
ZW
50 generated by a program compiled with -fprofile-arcs. Their formats
51 are documented in gcov-io.h. */
86144b75
DE
52
53/* The functions in this file for creating and solution program flow graphs
4977bab6
ZW
54 are very similar to functions in the gcc source file profile.c. In
55 some places we make use of the knowledge of how profile.c works to
56 select particular algorithms here. */
86144b75 57
10adac51
XDL
58/* The code validates that the profile information read in corresponds
59 to the code currently being compiled. Rather than checking for
9696c529 60 identical files, the code below compares a checksum on the CFG
10adac51 61 (based on the order of basic blocks and the arcs in the CFG). If
9696c529
SB
62 the CFG checksum in the gcda file match the CFG checksum in the
63 gcno file, the profile data will be used. */
10adac51 64
86144b75
DE
65/* This is the size of the buffer used to read in source file lines. */
66
4977bab6
ZW
67struct function_info;
68struct block_info;
27283c73 69struct source_info;
86144b75 70
4977bab6 71/* Describes an arc between two basic blocks. */
86144b75 72
4977bab6
ZW
73typedef struct arc_info
74{
32dd366d 75 /* source and destination blocks. */
4977bab6
ZW
76 struct block_info *src;
77 struct block_info *dst;
86144b75 78
4977bab6
ZW
79 /* transition counts. */
80 gcov_type count;
3d7ca167
ZD
81 /* used in cycle search, so that we do not clobber original counts. */
82 gcov_type cs_count;
86144b75 83
86144b75
DE
84 unsigned int count_valid : 1;
85 unsigned int on_tree : 1;
86 unsigned int fake : 1;
87 unsigned int fall_through : 1;
86144b75 88
8919c0d9
NS
89 /* Arc to a catch handler. */
90 unsigned int is_throw : 1;
91
27283c73
NS
92 /* Arc is for a function that abnormally returns. */
93 unsigned int is_call_non_return : 1;
94
fa10beec 95 /* Arc is for catch/setjmp. */
27283c73
NS
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;
8919c0d9 127 unsigned flags : 12;
4977bab6
ZW
128 unsigned count_valid : 1;
129 unsigned valid_chain : 1;
130 unsigned invalid_chain : 1;
8919c0d9 131 unsigned exceptional : 1;
4977bab6 132
27283c73 133 /* Block is a call instrumenting site. */
10b7602f
NS
134 unsigned is_call_site : 1; /* Does the call. */
135 unsigned is_call_return : 1; /* Is the return. */
4977bab6 136
27283c73
NS
137 /* Block is a landing pad for longjmp or throw. */
138 unsigned is_nonlocal_return : 1;
139
140 union
141 {
142 struct
143 {
144 /* Array of line numbers and source files. source files are
145 introduced by a linenumber of zero, the next 'line number' is
146 the number of the source file. Always starts with a source
147 file. */
148 unsigned *encoding;
149 unsigned num;
150 } line; /* Valid until blocks are linked onto lines */
151 struct
152 {
10b7602f 153 /* Single line graph cycle workspace. Used for all-blocks
71c0e7fc 154 mode. */
10b7602f
NS
155 arc_t *arc;
156 unsigned ident;
157 } cycle; /* Used in all-blocks mode, after blocks are linked onto
71c0e7fc 158 lines. */
27283c73
NS
159 } u;
160
161 /* Temporary chain for solving graph, and for chaining blocks on one
162 line. */
4977bab6 163 struct block_info *chain;
f55ade6e 164
4977bab6 165} block_t;
86144b75 166
4977bab6 167/* Describes a single function. Contains an array of basic blocks. */
86144b75 168
4977bab6 169typedef struct function_info
8b219a76 170{
4977bab6
ZW
171 /* Name of function. */
172 char *name;
796621e8 173 unsigned ident;
10adac51
XDL
174 unsigned lineno_checksum;
175 unsigned cfg_checksum;
86144b75 176
8919c0d9
NS
177 /* The graph contains at least one fake incoming edge. */
178 unsigned has_catch : 1;
179
9696c529
SB
180 /* Array of basic blocks. Like in GCC, the entry block is
181 at blocks[0] and the exit block is at blocks[1]. */
182#define ENTRY_BLOCK (0)
183#define EXIT_BLOCK (1)
4977bab6
ZW
184 block_t *blocks;
185 unsigned num_blocks;
27283c73 186 unsigned blocks_executed;
4977bab6
ZW
187
188 /* Raw arc coverage counts. */
189 gcov_type *counts;
190 unsigned num_counts;
27283c73 191
1ce1b792 192 /* First line number & file. */
27283c73 193 unsigned line;
1ce1b792 194 unsigned src;
27283c73
NS
195
196 /* Next function in same source file. */
197 struct function_info *line_next;
f55ade6e 198
4977bab6
ZW
199 /* Next function. */
200 struct function_info *next;
201} function_t;
202
203/* Describes coverage of a file or function. */
204
205typedef struct coverage_info
8b219a76
NS
206{
207 int lines;
208 int lines_executed;
f55ade6e 209
8b219a76
NS
210 int branches;
211 int branches_executed;
212 int branches_taken;
f55ade6e 213
8b219a76
NS
214 int calls;
215 int calls_executed;
f55ade6e 216
8b219a76 217 char *name;
4977bab6 218} coverage_t;
8b219a76 219
4977bab6
ZW
220/* Describes a single line of source. Contains a chain of basic blocks
221 with code on it. */
86144b75 222
4977bab6
ZW
223typedef struct line_info
224{
225 gcov_type count; /* execution count */
27283c73
NS
226 union
227 {
f55ade6e 228 arc_t *branches; /* branches from blocks that end on this
27283c73 229 line. Used for branch-counts when not
71c0e7fc 230 all-blocks mode. */
27283c73 231 block_t *blocks; /* blocks which start on this line. Used
71c0e7fc 232 in all-blocks mode. */
27283c73 233 } u;
4977bab6 234 unsigned exists : 1;
8919c0d9 235 unsigned unexceptional : 1;
4977bab6 236} line_t;
86144b75 237
4977bab6
ZW
238/* Describes a file mentioned in the block graph. Contains an array
239 of line info. */
37b8715b 240
4977bab6
ZW
241typedef struct source_info
242{
eeabee0a 243 /* Canonical name of source file. */
4977bab6 244 char *name;
1a9075e2 245 time_t file_time;
37b8715b 246
32dd366d 247 /* Array of line information. */
4977bab6
ZW
248 line_t *lines;
249 unsigned num_lines;
86144b75 250
4977bab6 251 coverage_t coverage;
27283c73
NS
252
253 /* Functions in this source file. These are in ascending line
254 number order. */
255 function_t *functions;
4977bab6 256} source_t;
86144b75 257
eeabee0a
NS
258typedef struct name_map
259{
260 char *name; /* Source file name */
261 unsigned src; /* Source file */
262} name_map_t;
263
4977bab6 264/* Holds a list of function basic block graphs. */
86144b75 265
4977bab6 266static function_t *functions;
1ce1b792 267static function_t **fn_end = &functions;
86144b75 268
1ce1b792
NS
269static source_t *sources; /* Array of source files */
270static unsigned n_sources; /* Number of sources */
271static unsigned a_sources; /* Allocated sources */
1a9075e2 272
eeabee0a
NS
273static name_map_t *names; /* Mapping of file names to sources */
274static unsigned n_names; /* Number of names */
275static unsigned a_names; /* Allocated names */
276
27283c73
NS
277/* This holds data summary information. */
278
5366b186 279static unsigned object_runs;
27283c73
NS
280static unsigned program_count;
281
bdbdc4e1
NS
282static unsigned total_lines;
283static unsigned total_executed;
284
32dd366d 285/* Modification time of graph file. */
86144b75 286
4977bab6 287static time_t bbg_file_time;
86144b75 288
efbb59b2
SB
289/* Name of the notes (gcno) output file. The "bbg" prefix is for
290 historical reasons, when the notes file contained only the
291 basic block graph notes. */
86144b75 292
4977bab6 293static char *bbg_file_name;
86144b75 294
dd486eb2
NS
295/* Stamp of the bbg file */
296static unsigned bbg_stamp;
297
efbb59b2 298/* Name and file pointer of the input file for the count data (gcda). */
86144b75 299
4977bab6 300static char *da_file_name;
86144b75 301
80b3502b
NS
302/* Data file is missing. */
303
304static int no_data_file;
305
1a9075e2
TG
306/* If there is several input files, compute and display results after
307 reading all data files. This way if two or more gcda file refer to
308 the same source file (eg inline subprograms in a .h file), the
309 counts are added. */
310
311static int multiple_files = 0;
312
4977bab6 313/* Output branch probabilities. */
86144b75 314
4977bab6 315static int flag_branches = 0;
86144b75 316
f55ade6e 317/* Show unconditional branches too. */
27283c73
NS
318static int flag_unconditional = 0;
319
86144b75
DE
320/* Output a gcov file if this is true. This is on by default, and can
321 be turned off by the -n option. */
322
4977bab6 323static int flag_gcov_file = 1;
86144b75 324
acdb4da7
NS
325/* Output progress indication if this is true. This is off by default
326 and can be turned on by the -d option. */
327
328static int flag_display_progress = 0;
329
4977bab6
ZW
330/* For included files, make the gcov output file name include the name
331 of the input source file. For example, if x.h is included in a.c,
332 then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
86144b75 333
4977bab6 334static int flag_long_names = 0;
86144b75 335
27283c73
NS
336/* Output count information for every basic block, not merely those
337 that contain line number information. */
338
339static int flag_all_blocks = 0;
340
86144b75
DE
341/* Output summary info for each function. */
342
4977bab6 343static int flag_function_summary = 0;
86144b75 344
4977bab6
ZW
345/* Object directory file prefix. This is the directory/file where the
346 graph and data files are looked for, if nonzero. */
86144b75
DE
347
348static char *object_directory = 0;
349
1bec9caa
NS
350/* Source directory prefix. This is removed from source pathnames
351 that match, when generating the output file name. */
352
353static char *source_prefix = 0;
354static size_t source_length = 0;
355
356/* Only show data for sources with relative pathnames. Absolute ones
357 usually indicate a system header file, which although it may
358 contain inline functions, is usually uninteresting. */
359static int flag_relative_only = 0;
360
37b8715b 361/* Preserve all pathname components. Needed when object files and
4977bab6
ZW
362 source files are in subdirectories. '/' is mangled as '#', '.' is
363 elided and '..' mangled to '^'. */
364
365static int flag_preserve_paths = 0;
37b8715b 366
8bfa6fc5 367/* Output the number of times a branch was taken as opposed to the percentage
32dd366d 368 of times it was taken. */
23190837 369
4977bab6 370static int flag_counts = 0;
8bfa6fc5 371
86144b75 372/* Forward declarations. */
f55ade6e
AJ
373static int process_args (int, char **);
374static void print_usage (int) ATTRIBUTE_NORETURN;
375static void print_version (void) ATTRIBUTE_NORETURN;
376static void process_file (const char *);
1a9075e2 377static void generate_results (const char *);
f55ade6e 378static void create_file_names (const char *);
eeabee0a
NS
379static int name_search (const void *, const void *);
380static int name_sort (const void *, const void *);
381static char *canonicalize_name (const char *);
1ce1b792
NS
382static unsigned find_source (const char *);
383static function_t *read_graph_file (void);
384static int read_count_file (function_t *);
f55ade6e 385static void solve_flow_graph (function_t *);
8919c0d9 386static void find_exception_blocks (function_t *);
f55ade6e
AJ
387static void add_branch_counts (coverage_t *, const arc_t *);
388static void add_line_counts (coverage_t *, function_t *);
bdbdc4e1 389static void executed_summary (unsigned, unsigned);
f55ade6e
AJ
390static void function_summary (const coverage_t *, const char *);
391static const char *format_gcov (gcov_type, gcov_type, int);
392static void accumulate_line_counts (source_t *);
393static int output_branch_count (FILE *, int, const arc_t *);
394static void output_lines (FILE *, const source_t *);
395static char *make_gcov_file_name (const char *, const char *);
eeabee0a 396static char *mangle_name (const char *, char *);
f55ade6e 397static void release_structures (void);
5366b186 398static void release_function (function_t *);
f55ade6e 399extern int main (int, char **);
86144b75
DE
400
401int
f55ade6e 402main (int argc, char **argv)
86144b75 403{
4977bab6 404 int argno;
acdb4da7 405 int first_arg;
2691e6d7
JM
406 const char *p;
407
408 p = argv[0] + strlen (argv[0]);
409 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
410 --p;
411 progname = p;
412
413 xmalloc_set_program_name (progname);
f55ade6e 414
98a3dad4 415 /* Unlock the stdio streams. */
2653bb0c 416 unlock_std_streams ();
98a3dad4 417
191bf464 418 gcc_init_libintl ();
ab87f8c8 419
2691e6d7
JM
420 diagnostic_initialize (global_dc, 0);
421
e3536b82
TG
422 /* Handle response files. */
423 expandargv (&argc, &argv);
424
84ec53b6
NS
425 a_names = 10;
426 names = XNEWVEC (name_map_t, a_names);
427 a_sources = 10;
428 sources = XNEWVEC (source_t, a_sources);
429
4977bab6
ZW
430 argno = process_args (argc, argv);
431 if (optind == argc)
432 print_usage (true);
86144b75 433
1a9075e2
TG
434 if (argc - argno > 1)
435 multiple_files = 1;
436
acdb4da7
NS
437 first_arg = argno;
438
4977bab6 439 for (; argno != argc; argno++)
acdb4da7
NS
440 {
441 if (flag_display_progress)
442 printf("Processing file %d out of %d\n",
443 argno - first_arg + 1, argc - first_arg);
444 process_file (argv[argno]);
445 }
f55ade6e 446
1a9075e2
TG
447 generate_results (multiple_files ? NULL : argv[argc - 1]);
448
449 release_structures ();
f55ade6e 450
86144b75
DE
451 return 0;
452}
86144b75 453\f
5735c3ea
JM
454/* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
455 otherwise the output of --help. */
86144b75
DE
456
457static void
f55ade6e 458print_usage (int error_p)
86144b75 459{
5735c3ea
JM
460 FILE *file = error_p ? stderr : stdout;
461 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
f55ade6e 462
eeabee0a 463 fnotice (file, "Usage: gcov [OPTION]... SOURCE|OBJ...\n\n");
5735c3ea
JM
464 fnotice (file, "Print code coverage information.\n\n");
465 fnotice (file, " -h, --help Print this help, then exit\n");
466 fnotice (file, " -v, --version Print version number, then exit\n");
27283c73 467 fnotice (file, " -a, --all-blocks Show information for every basic block\n");
5735c3ea
JM
468 fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
469 fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
470 rather than percentages\n");
471 fnotice (file, " -n, --no-output Do not create an output file\n");
472 fnotice (file, " -l, --long-file-names Use long output file names for included\n\
473 source files\n");
474 fnotice (file, " -f, --function-summaries Output summaries for each function\n");
37b8715b 475 fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
1bec9caa
NS
476 fnotice (file, " -s, --source-prefix DIR Source prefix to elide\n");
477 fnotice (file, " -r, --relative-only Only show data for relative sources\n");
37b8715b 478 fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
27283c73 479 fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
acdb4da7 480 fnotice (file, " -d, --display-progress Display progress information\n");
5735c3ea 481 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
a976603e 482 bug_report_url);
5735c3ea
JM
483 exit (status);
484}
485
486/* Print version information and exit. */
487
488static void
f55ade6e 489print_version (void)
5735c3ea 490{
2f41c1d6 491 fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
66f1b195 492 fprintf (stdout, "Copyright %s 2012 Free Software Foundation, Inc.\n",
9f76f909 493 _("(C)"));
5735c3ea 494 fnotice (stdout,
9f76f909
KH
495 _("This is free software; see the source for copying conditions.\n"
496 "There is NO warranty; not even for MERCHANTABILITY or \n"
497 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
5735c3ea 498 exit (SUCCESS_EXIT_CODE);
86144b75
DE
499}
500
5735c3ea
JM
501static const struct option options[] =
502{
503 { "help", no_argument, NULL, 'h' },
504 { "version", no_argument, NULL, 'v' },
27283c73 505 { "all-blocks", no_argument, NULL, 'a' },
5735c3ea
JM
506 { "branch-probabilities", no_argument, NULL, 'b' },
507 { "branch-counts", no_argument, NULL, 'c' },
508 { "no-output", no_argument, NULL, 'n' },
509 { "long-file-names", no_argument, NULL, 'l' },
510 { "function-summaries", no_argument, NULL, 'f' },
37b8715b 511 { "preserve-paths", no_argument, NULL, 'p' },
1bec9caa 512 { "relative-only", no_argument, NULL, 'r' },
37b8715b
NS
513 { "object-directory", required_argument, NULL, 'o' },
514 { "object-file", required_argument, NULL, 'o' },
1bec9caa 515 { "source-prefix", required_argument, NULL, 's' },
27283c73 516 { "unconditional-branches", no_argument, NULL, 'u' },
acdb4da7 517 { "display-progress", no_argument, NULL, 'd' },
d90f9882 518 { 0, 0, 0, 0 }
5735c3ea
JM
519};
520
4977bab6 521/* Process args, return index to first non-arg. */
86144b75 522
4977bab6 523static int
f55ade6e 524process_args (int argc, char **argv)
86144b75 525{
5735c3ea 526 int opt;
86144b75 527
1bec9caa 528 while ((opt = getopt_long (argc, argv, "abcdfhlno:s:pruv", options, NULL)) != -1)
86144b75 529 {
5735c3ea 530 switch (opt)
86144b75 531 {
27283c73
NS
532 case 'a':
533 flag_all_blocks = 1;
534 break;
5735c3ea 535 case 'b':
4977bab6 536 flag_branches = 1;
5735c3ea
JM
537 break;
538 case 'c':
4977bab6 539 flag_counts = 1;
5735c3ea 540 break;
27283c73
NS
541 case 'f':
542 flag_function_summary = 1;
5735c3ea 543 break;
27283c73
NS
544 case 'h':
545 print_usage (false);
546 /* print_usage will exit. */
5735c3ea 547 case 'l':
4977bab6 548 flag_long_names = 1;
5735c3ea 549 break;
27283c73
NS
550 case 'n':
551 flag_gcov_file = 0;
5735c3ea
JM
552 break;
553 case 'o':
554 object_directory = optarg;
555 break;
1bec9caa
NS
556 case 's':
557 source_prefix = optarg;
558 source_length = strlen (source_prefix);
559 break;
560 case 'r':
561 flag_relative_only = 1;
562 break;
37b8715b 563 case 'p':
4977bab6 564 flag_preserve_paths = 1;
37b8715b 565 break;
27283c73
NS
566 case 'u':
567 flag_unconditional = 1;
568 break;
acdb4da7
NS
569 case 'd':
570 flag_display_progress = 1;
571 break;
27283c73
NS
572 case 'v':
573 print_version ();
574 /* print_version will exit. */
5735c3ea
JM
575 default:
576 print_usage (true);
577 /* print_usage will exit. */
86144b75 578 }
86144b75
DE
579 }
580
4977bab6
ZW
581 return optind;
582}
583
eeabee0a 584/* Process a single input file. */
5735c3ea 585
4977bab6 586static void
f55ade6e 587process_file (const char *file_name)
4977bab6 588{
1ce1b792 589 function_t *fns;
f55ade6e 590
4977bab6 591 create_file_names (file_name);
1ce1b792
NS
592 fns = read_graph_file ();
593 if (!fns)
4977bab6 594 return;
1ce1b792
NS
595
596 read_count_file (fns);
597 while (fns)
4977bab6 598 {
1ce1b792 599 function_t *fn = fns;
f55ade6e 600
1ce1b792
NS
601 fns = fn->next;
602 fn->next = NULL;
5366b186
NS
603 if (fn->counts)
604 {
1ce1b792
NS
605 unsigned src = fn->src;
606 unsigned line = fn->line;
607 unsigned block_no;
608 function_t *probe, **prev;
609
610 /* Now insert it into the source file's list of
611 functions. Normally functions will be encountered in
612 ascending order, so a simple scan is quick. Note we're
613 building this list in reverse order. */
614 for (prev = &sources[src].functions;
615 (probe = *prev); prev = &probe->line_next)
616 if (probe->line <= line)
617 break;
618 fn->line_next = probe;
619 *prev = fn;
620
621 /* Mark last line in files touched by function. */
622 for (block_no = 0; block_no != fn->num_blocks; block_no++)
623 {
624 unsigned *enc = fn->blocks[block_no].u.line.encoding;
625 unsigned num = fn->blocks[block_no].u.line.num;
626
627 for (; num--; enc++)
628 if (!*enc)
629 {
630 if (enc[1] != src)
631 {
632 if (line >= sources[src].num_lines)
633 sources[src].num_lines = line + 1;
634 line = 0;
635 src = enc[1];
636 }
637 enc++;
638 num--;
639 }
640 else if (*enc > line)
641 line = *enc;
642 }
643 if (line >= sources[src].num_lines)
644 sources[src].num_lines = line + 1;
645
5366b186 646 solve_flow_graph (fn);
8919c0d9
NS
647 if (fn->has_catch)
648 find_exception_blocks (fn);
1ce1b792
NS
649 *fn_end = fn;
650 fn_end = &fn->next;
5366b186
NS
651 }
652 else
1ce1b792
NS
653 /* The function was not in the executable -- some other
654 instance must have been selected. */
655 release_function (fn);
5366b186 656 }
1a9075e2
TG
657}
658
659static void
660generate_results (const char *file_name)
661{
1ce1b792 662 unsigned ix;
1a9075e2
TG
663 source_t *src;
664 function_t *fn;
665
1ce1b792
NS
666 for (ix = n_sources, src = sources; ix--; src++)
667 if (src->num_lines)
668 src->lines = XCNEWVEC (line_t, src->num_lines);
669
4977bab6
ZW
670 for (fn = functions; fn; fn = fn->next)
671 {
672 coverage_t coverage;
f55ade6e 673
4977bab6
ZW
674 memset (&coverage, 0, sizeof (coverage));
675 coverage.name = fn->name;
676 add_line_counts (flag_function_summary ? &coverage : NULL, fn);
677 if (flag_function_summary)
678 {
679 function_summary (&coverage, "Function");
680 fnotice (stdout, "\n");
681 }
682 }
f55ade6e 683
eeabee0a
NS
684 if (file_name)
685 {
686 name_map_t *name_map = (name_map_t *)bsearch
687 (file_name, names, n_names, sizeof (*names), name_search);
688 if (name_map)
1bec9caa 689 file_name = sources[name_map->src].coverage.name;
eeabee0a
NS
690 else
691 file_name = canonicalize_name (file_name);
692 }
693
1ce1b792 694 for (ix = n_sources, src = sources; ix--; src++)
4977bab6 695 {
1bec9caa
NS
696 if (flag_relative_only)
697 {
698 /* Ignore this source, if it is an absolute path (after
699 source prefix removal). */
700 char first = src->coverage.name[0];
701
702#if HAVE_DOS_BASED_FILE_SYSTEM
703 if (first && src->coverage.name[1] == ':')
fe860eb5 704 first = src->coverage.name[2];
1bec9caa 705#endif
fe860eb5
KT
706 if (IS_DIR_SEPARATOR (first))
707 continue;
1bec9caa
NS
708 }
709
4977bab6
ZW
710 accumulate_line_counts (src);
711 function_summary (&src->coverage, "File");
bdbdc4e1
NS
712 total_lines += src->coverage.lines;
713 total_executed += src->coverage.lines_executed;
8f961b22 714 if (flag_gcov_file)
4977bab6 715 {
1bec9caa
NS
716 char *gcov_file_name
717 = make_gcov_file_name (file_name, src->coverage.name);
f55ade6e 718
8f961b22 719 if (src->coverage.lines)
4977bab6 720 {
8f961b22
NS
721 FILE *gcov_file = fopen (gcov_file_name, "w");
722
723 if (gcov_file)
724 {
725 fnotice (stdout, "Creating '%s'\n", gcov_file_name);
726 output_lines (gcov_file, src);
727 if (ferror (gcov_file))
1bec9caa
NS
728 fnotice (stderr, "Error writing output file '%s'\n",
729 gcov_file_name);
8f961b22
NS
730 fclose (gcov_file);
731 }
732 else
733 fnotice (stderr, "Could not open output file '%s'\n",
734 gcov_file_name);
4977bab6
ZW
735 }
736 else
8f961b22
NS
737 {
738 unlink (gcov_file_name);
739 fnotice (stdout, "Removing '%s'\n", gcov_file_name);
740 }
4977bab6
ZW
741 free (gcov_file_name);
742 }
743 fnotice (stdout, "\n");
744 }
bdbdc4e1
NS
745
746 if (!file_name)
747 executed_summary (total_lines, total_executed);
86144b75
DE
748}
749
5366b186
NS
750/* Release a function structure */
751
752static void
753release_function (function_t *fn)
754{
755 unsigned ix;
756 block_t *block;
757
758 for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
759 {
760 arc_t *arc, *arc_n;
761
762 for (arc = block->succ; arc; arc = arc_n)
763 {
764 arc_n = arc->succ_next;
765 free (arc);
766 }
767 }
768 free (fn->blocks);
769 free (fn->counts);
770}
771
4977bab6 772/* Release all memory used. */
86144b75 773
4977bab6 774static void
f55ade6e 775release_structures (void)
4977bab6 776{
1ce1b792 777 unsigned ix;
4977bab6 778 function_t *fn;
f55ade6e 779
1ce1b792 780 for (ix = n_sources; ix--;)
eeabee0a
NS
781 free (sources[ix].lines);
782 free (sources);
783
784 for (ix = n_names; ix--;)
785 free (names[ix].name);
786 free (names);
f55ade6e 787
4977bab6
ZW
788 while ((fn = functions))
789 {
4977bab6 790 functions = fn->next;
5366b186 791 release_function (fn);
4977bab6
ZW
792 }
793}
794
15882fe9
TG
795/* Generate the names of the graph and data files. If OBJECT_DIRECTORY
796 is not specified, these are named from FILE_NAME sans extension. If
797 OBJECT_DIRECTORY is specified and is a directory, the files are in that
798 directory, but named from the basename of the FILE_NAME, sans extension.
799 Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
800 and the data files are named from that. */
86144b75
DE
801
802static void
f55ade6e 803create_file_names (const char *file_name)
86144b75 804{
86144b75 805 char *cptr;
37b8715b 806 char *name;
4977bab6 807 int length = strlen (file_name);
37b8715b 808 int base;
f55ade6e 809
1a9075e2 810 /* Free previous file names. */
04695783
JM
811 free (bbg_file_name);
812 free (da_file_name);
1a9075e2
TG
813 da_file_name = bbg_file_name = NULL;
814 bbg_file_time = 0;
815 bbg_stamp = 0;
816
37b8715b 817 if (object_directory && object_directory[0])
86144b75 818 {
37b8715b
NS
819 struct stat status;
820
821 length += strlen (object_directory) + 2;
5ed6ace5 822 name = XNEWVEC (char, length);
37b8715b 823 name[0] = 0;
f55ade6e 824
37b8715b
NS
825 base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
826 strcat (name, object_directory);
2f07423c 827 if (base && (! IS_DIR_SEPARATOR (name[strlen (name) - 1])))
37b8715b 828 strcat (name, "/");
86144b75
DE
829 }
830 else
831 {
5ed6ace5 832 name = XNEWVEC (char, length + 1);
15882fe9
TG
833 strcpy (name, file_name);
834 base = 0;
86144b75 835 }
f55ade6e 836
37b8715b
NS
837 if (base)
838 {
f9da5064 839 /* Append source file name. */
2f07423c
PO
840 const char *cptr = lbasename (file_name);
841 strcat (name, cptr ? cptr : file_name);
37b8715b 842 }
f55ade6e 843
4b7e68e7 844 /* Remove the extension. */
37b8715b 845 cptr = strrchr (name, '.');
86144b75 846 if (cptr)
37b8715b 847 *cptr = 0;
f55ade6e 848
37b8715b 849 length = strlen (name);
b8698a0f 850
5ed6ace5 851 bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
4977bab6 852 strcpy (bbg_file_name, name);
160e2e4f 853 strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
37b8715b 854
5ed6ace5 855 da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
4977bab6
ZW
856 strcpy (da_file_name, name);
857 strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
f55ade6e 858
a14df7da 859 free (name);
4977bab6 860 return;
86144b75 861}
86144b75 862
eeabee0a
NS
863/* A is a string and B is a pointer to name_map_t. Compare for file
864 name orderability. */
865
866static int
867name_search (const void *a_, const void *b_)
868{
869 const char *a = (const char *)a_;
870 const name_map_t *b = (const name_map_t *)b_;
871
872#if HAVE_DOS_BASED_FILE_SYSTEM
873 return strcasecmp (a, b->name);
874#else
875 return strcmp (a, b->name);
876#endif
877}
878
879/* A and B are a pointer to name_map_t. Compare for file name
880 orderability. */
881
882static int
883name_sort (const void *a_, const void *b_)
884{
885 const name_map_t *a = (const name_map_t *)a_;
886 return name_search (a->name, b_);
887}
888
94de45d9
NS
889/* Find or create a source file structure for FILE_NAME. Copies
890 FILE_NAME on creation */
27283c73 891
1ce1b792 892static unsigned
f55ade6e 893find_source (const char *file_name)
27283c73 894{
eeabee0a
NS
895 name_map_t *name_map;
896 char *canon;
897 unsigned idx;
1a9075e2 898 struct stat status;
94de45d9
NS
899
900 if (!file_name)
901 file_name = "<unknown>";
eeabee0a
NS
902 name_map = (name_map_t *)bsearch
903 (file_name, names, n_names, sizeof (*names), name_search);
904 if (name_map)
905 {
906 idx = name_map->src;
907 goto check_date;
908 }
f55ade6e 909
eeabee0a 910 if (n_names + 2 > a_names)
1a9075e2 911 {
eeabee0a
NS
912 /* Extend the name map array -- we'll be inserting one or two
913 entries. */
eeabee0a
NS
914 a_names *= 2;
915 name_map = XNEWVEC (name_map_t, a_names);
916 memcpy (name_map, names, n_names * sizeof (*names));
917 free (names);
918 names = name_map;
919 }
920
921 /* Not found, try the canonical name. */
922 canon = canonicalize_name (file_name);
923 name_map = (name_map_t *)bsearch
924 (canon, names, n_names, sizeof (*names), name_search);
925 if (!name_map)
926 {
927 /* Not found with canonical name, create a new source. */
928 source_t *src;
929
1ce1b792
NS
930 if (n_sources == a_sources)
931 {
1ce1b792
NS
932 a_sources *= 2;
933 src = XNEWVEC (source_t, a_sources);
934 memcpy (src, sources, n_sources * sizeof (*sources));
935 free (sources);
936 sources = src;
937 }
eeabee0a
NS
938
939 idx = n_sources;
940
941 name_map = &names[n_names++];
942 name_map->name = canon;
943 name_map->src = idx;
944
945 src = &sources[n_sources++];
946 memset (src, 0, sizeof (*src));
947 src->name = canon;
1a9075e2 948 src->coverage.name = src->name;
1bec9caa
NS
949 if (source_length
950#if HAVE_DOS_BASED_FILE_SYSTEM
951 /* You lose if separators don't match exactly in the
952 prefix. */
953 && !strncasecmp (source_prefix, src->coverage.name, source_length)
954#else
955 && !strncmp (source_prefix, src->coverage.name, source_length)
956#endif
957 && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
958 src->coverage.name += source_length + 1;
eeabee0a 959 if (!stat (src->name, &status))
1a9075e2
TG
960 src->file_time = status.st_mtime;
961 }
eeabee0a
NS
962 else
963 idx = name_map->src;
964
965 if (name_search (file_name, name_map))
966 {
967 /* Append the non-canonical name. */
968 name_map = &names[n_names++];
969 name_map->name = xstrdup (file_name);
970 name_map->src = idx;
971 }
1a9075e2 972
eeabee0a
NS
973 /* Resort the name map. */
974 qsort (names, n_names, sizeof (*names), name_sort);
975
976 check_date:
977 if (sources[idx].file_time > bbg_file_time)
1a9075e2
TG
978 {
979 static int info_emitted;
980
efbb59b2 981 fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
eeabee0a 982 file_name, bbg_file_name);
1a9075e2
TG
983 if (!info_emitted)
984 {
985 fnotice (stderr,
986 "(the message is only displayed one per source file)\n");
987 info_emitted = 1;
988 }
eeabee0a 989 sources[idx].file_time = 0;
1a9075e2 990 }
94de45d9 991
eeabee0a 992 return idx;
27283c73
NS
993}
994
efbb59b2 995/* Read the notes file. Return list of functions read -- in reverse order. */
86144b75 996
1ce1b792 997static function_t *
f55ade6e 998read_graph_file (void)
86144b75 999{
94de45d9 1000 unsigned version;
4977bab6 1001 unsigned current_tag = 0;
1ce1b792
NS
1002 function_t *fn = NULL;
1003 function_t *fns = NULL;
1004 function_t **fns_end = &fns;
1005 unsigned src_idx = 0;
4977bab6 1006 unsigned ix;
7d63a2fa 1007 unsigned tag;
f55ade6e 1008
546d2adb 1009 if (!gcov_open (bbg_file_name, 1))
86144b75 1010 {
efbb59b2 1011 fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1ce1b792 1012 return fns;
86144b75 1013 }
546d2adb 1014 bbg_file_time = gcov_time ();
160e2e4f 1015 if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
b7c9bf28 1016 {
efbb59b2 1017 fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
546d2adb 1018 gcov_close ();
1ce1b792 1019 return fns;
4977bab6 1020 }
b7c9bf28 1021
94de45d9
NS
1022 version = gcov_read_unsigned ();
1023 if (version != GCOV_VERSION)
4977bab6
ZW
1024 {
1025 char v[4], e[4];
f55ade6e 1026
330d2e2a
NS
1027 GCOV_UNSIGNED2STRING (v, version);
1028 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1029
9e637a26 1030 fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
4977bab6
ZW
1031 bbg_file_name, v, e);
1032 }
dd486eb2
NS
1033 bbg_stamp = gcov_read_unsigned ();
1034
7d63a2fa 1035 while ((tag = gcov_read_unsigned ()))
4977bab6 1036 {
94de45d9 1037 unsigned length = gcov_read_unsigned ();
7d63a2fa 1038 gcov_position_t base = gcov_position ();
796621e8 1039
4977bab6 1040 if (tag == GCOV_TAG_FUNCTION)
b7c9bf28 1041 {
94de45d9 1042 char *function_name;
10adac51
XDL
1043 unsigned ident, lineno;
1044 unsigned lineno_checksum, cfg_checksum;
4977bab6 1045
796621e8 1046 ident = gcov_read_unsigned ();
10adac51
XDL
1047 lineno_checksum = gcov_read_unsigned ();
1048 cfg_checksum = gcov_read_unsigned ();
796621e8 1049 function_name = xstrdup (gcov_read_string ());
1ce1b792 1050 src_idx = find_source (gcov_read_string ());
94de45d9 1051 lineno = gcov_read_unsigned ();
f55ade6e 1052
5ed6ace5 1053 fn = XCNEW (function_t);
4977bab6 1054 fn->name = function_name;
796621e8 1055 fn->ident = ident;
10adac51
XDL
1056 fn->lineno_checksum = lineno_checksum;
1057 fn->cfg_checksum = cfg_checksum;
1ce1b792 1058 fn->src = src_idx;
27283c73 1059 fn->line = lineno;
4977bab6 1060
1ce1b792
NS
1061 fn->line_next = NULL;
1062 fn->next = NULL;
1063 *fns_end = fn;
1064 fns_end = &fn->next;
4977bab6 1065 current_tag = tag;
b7c9bf28 1066 }
4977bab6 1067 else if (fn && tag == GCOV_TAG_BLOCKS)
b7c9bf28 1068 {
4977bab6 1069 if (fn->blocks)
9e637a26 1070 fnotice (stderr, "%s:already seen blocks for '%s'\n",
4977bab6
ZW
1071 bbg_file_name, fn->name);
1072 else
b7c9bf28 1073 {
330d2e2a 1074 unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
27283c73 1075 fn->num_blocks = num_blocks;
f55ade6e 1076
5ed6ace5 1077 fn->blocks = XCNEWVEC (block_t, fn->num_blocks);
27283c73 1078 for (ix = 0; ix != num_blocks; ix++)
94de45d9 1079 fn->blocks[ix].flags = gcov_read_unsigned ();
b7c9bf28 1080 }
4977bab6
ZW
1081 }
1082 else if (fn && tag == GCOV_TAG_ARCS)
1083 {
94de45d9 1084 unsigned src = gcov_read_unsigned ();
330d2e2a 1085 unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
8919c0d9
NS
1086 block_t *src_blk = &fn->blocks[src];
1087 unsigned mark_catches = 0;
1088 struct arc_info *arc;
4977bab6 1089
94de45d9 1090 if (src >= fn->num_blocks || fn->blocks[src].succ)
4977bab6 1091 goto corrupt;
f55ade6e 1092
4977bab6 1093 while (num_dests--)
b7c9bf28 1094 {
94de45d9
NS
1095 unsigned dest = gcov_read_unsigned ();
1096 unsigned flags = gcov_read_unsigned ();
f55ade6e 1097
94de45d9 1098 if (dest >= fn->num_blocks)
4977bab6 1099 goto corrupt;
5ed6ace5 1100 arc = XCNEW (arc_t);
f55ade6e 1101
4977bab6 1102 arc->dst = &fn->blocks[dest];
8919c0d9 1103 arc->src = src_blk;
f55ade6e 1104
4977bab6
ZW
1105 arc->count = 0;
1106 arc->count_valid = 0;
1107 arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
1108 arc->fake = !!(flags & GCOV_ARC_FAKE);
1109 arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
f55ade6e 1110
8919c0d9
NS
1111 arc->succ_next = src_blk->succ;
1112 src_blk->succ = arc;
1113 src_blk->num_succ++;
f55ade6e 1114
4977bab6
ZW
1115 arc->pred_next = fn->blocks[dest].pred;
1116 fn->blocks[dest].pred = arc;
1117 fn->blocks[dest].num_pred++;
1118
27283c73
NS
1119 if (arc->fake)
1120 {
1121 if (src)
1122 {
1123 /* Exceptional exit from this function, the
1124 source block must be a call. */
1125 fn->blocks[src].is_call_site = 1;
1126 arc->is_call_non_return = 1;
8919c0d9 1127 mark_catches = 1;
27283c73
NS
1128 }
1129 else
1130 {
1131 /* Non-local return from a callee of this
8919c0d9 1132 function. The destination block is a setjmp. */
27283c73
NS
1133 arc->is_nonlocal_return = 1;
1134 fn->blocks[dest].is_nonlocal_return = 1;
1135 }
1136 }
f55ade6e 1137
4977bab6
ZW
1138 if (!arc->on_tree)
1139 fn->num_counts++;
b7c9bf28 1140 }
8919c0d9
NS
1141
1142 if (mark_catches)
1143 {
1144 /* We have a fake exit from this block. The other
1145 non-fall through exits must be to catch handlers.
1146 Mark them as catch arcs. */
1147
1148 for (arc = src_blk->succ; arc; arc = arc->succ_next)
1149 if (!arc->fake && !arc->fall_through)
1150 {
1151 arc->is_throw = 1;
1152 fn->has_catch = 1;
1153 }
1154 }
4977bab6
ZW
1155 }
1156 else if (fn && tag == GCOV_TAG_LINES)
1157 {
94de45d9 1158 unsigned blockno = gcov_read_unsigned ();
5ed6ace5 1159 unsigned *line_nos = XCNEWVEC (unsigned, length - 1);
4977bab6 1160
94de45d9 1161 if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
4977bab6 1162 goto corrupt;
f55ade6e 1163
4977bab6 1164 for (ix = 0; ; )
b7c9bf28 1165 {
94de45d9 1166 unsigned lineno = gcov_read_unsigned ();
f55ade6e 1167
4977bab6 1168 if (lineno)
b7c9bf28 1169 {
4977bab6
ZW
1170 if (!ix)
1171 {
1172 line_nos[ix++] = 0;
1ce1b792 1173 line_nos[ix++] = src_idx;
4977bab6
ZW
1174 }
1175 line_nos[ix++] = lineno;
b7c9bf28 1176 }
4977bab6
ZW
1177 else
1178 {
94de45d9 1179 const char *file_name = gcov_read_string ();
f55ade6e 1180
4977bab6 1181 if (!file_name)
b7c9bf28 1182 break;
1ce1b792 1183 src_idx = find_source (file_name);
4977bab6 1184 line_nos[ix++] = 0;
1ce1b792 1185 line_nos[ix++] = src_idx;
4977bab6 1186 }
b7c9bf28 1187 }
f55ade6e 1188
27283c73
NS
1189 fn->blocks[blockno].u.line.encoding = line_nos;
1190 fn->blocks[blockno].u.line.num = ix;
4977bab6
ZW
1191 }
1192 else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
1193 {
1194 fn = NULL;
1195 current_tag = 0;
1196 }
474f141e 1197 gcov_sync (base, length);
94de45d9 1198 if (gcov_is_error ())
00cf2913
NS
1199 {
1200 corrupt:;
1201 fnotice (stderr, "%s:corrupted\n", bbg_file_name);
1ce1b792 1202 break;
00cf2913 1203 }
b7c9bf28 1204 }
546d2adb 1205 gcov_close ();
f55ade6e 1206
1ce1b792
NS
1207 if (!fns)
1208 fnotice (stderr, "%s:no functions found\n", bbg_file_name);
b7c9bf28 1209
1ce1b792 1210 return fns;
b7c9bf28 1211}
86144b75 1212
4977bab6 1213/* Reads profiles from the count file and attach to each
272d0bee 1214 function. Return nonzero if fatal error. */
86144b75 1215
4977bab6 1216static int
1ce1b792 1217read_count_file (function_t *fns)
86144b75 1218{
4977bab6 1219 unsigned ix;
94de45d9 1220 unsigned version;
7d63a2fa 1221 unsigned tag;
4977bab6 1222 function_t *fn = NULL;
7d63a2fa 1223 int error = 0;
4977bab6 1224
546d2adb 1225 if (!gcov_open (da_file_name, 1))
86144b75 1226 {
80b3502b
NS
1227 fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
1228 da_file_name);
1229 no_data_file = 1;
1230 return 0;
4977bab6 1231 }
160e2e4f 1232 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
4977bab6
ZW
1233 {
1234 fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
1235 cleanup:;
546d2adb 1236 gcov_close ();
4977bab6
ZW
1237 return 1;
1238 }
94de45d9
NS
1239 version = gcov_read_unsigned ();
1240 if (version != GCOV_VERSION)
4977bab6 1241 {
330d2e2a
NS
1242 char v[4], e[4];
1243
1244 GCOV_UNSIGNED2STRING (v, version);
1245 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
b8698a0f 1246
9e637a26 1247 fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
330d2e2a 1248 da_file_name, v, e);
86144b75 1249 }
dd486eb2
NS
1250 tag = gcov_read_unsigned ();
1251 if (tag != bbg_stamp)
1252 {
efbb59b2 1253 fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
dd486eb2
NS
1254 goto cleanup;
1255 }
f55ade6e 1256
7d63a2fa 1257 while ((tag = gcov_read_unsigned ()))
4977bab6 1258 {
94de45d9
NS
1259 unsigned length = gcov_read_unsigned ();
1260 unsigned long base = gcov_position ();
94de45d9 1261
5366b186 1262 if (tag == GCOV_TAG_PROGRAM_SUMMARY)
86144b75 1263 {
5366b186
NS
1264 struct gcov_summary summary;
1265 gcov_read_summary (&summary);
1266 object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs;
1267 program_count++;
1268 }
1269 else if (tag == GCOV_TAG_FUNCTION && !length)
1270 ; /* placeholder */
1271 else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
1272 {
1273 unsigned ident;
1274 struct function_info *fn_n;
4977bab6 1275
5366b186
NS
1276 /* Try to find the function in the list. To speed up the
1277 search, first start from the last function found. */
1278 ident = gcov_read_unsigned ();
1ce1b792 1279 fn_n = fns;
5366b186
NS
1280 for (fn = fn ? fn->next : NULL; ; fn = fn->next)
1281 {
1282 if (fn)
1283 ;
1284 else if ((fn = fn_n))
1285 fn_n = NULL;
1286 else
1287 {
1288 fnotice (stderr, "%s:unknown function '%u'\n",
1289 da_file_name, ident);
4977bab6 1290 break;
5366b186
NS
1291 }
1292 if (fn->ident == ident)
1293 break;
1294 }
4977bab6
ZW
1295
1296 if (!fn)
1297 ;
10adac51
XDL
1298 else if (gcov_read_unsigned () != fn->lineno_checksum
1299 || gcov_read_unsigned () != fn->cfg_checksum)
86144b75 1300 {
4977bab6 1301 mismatch:;
9e637a26 1302 fnotice (stderr, "%s:profile mismatch for '%s'\n",
94de45d9 1303 da_file_name, fn->name);
4977bab6
ZW
1304 goto cleanup;
1305 }
1306 }
cdb23767 1307 else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
4977bab6 1308 {
330d2e2a 1309 if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
4977bab6 1310 goto mismatch;
f55ade6e 1311
4977bab6 1312 if (!fn->counts)
5ed6ace5 1313 fn->counts = XCNEWVEC (gcov_type, fn->num_counts);
f55ade6e 1314
4977bab6 1315 for (ix = 0; ix != fn->num_counts; ix++)
94de45d9
NS
1316 fn->counts[ix] += gcov_read_counter ();
1317 }
474f141e 1318 gcov_sync (base, length);
94de45d9 1319 if ((error = gcov_is_error ()))
00cf2913
NS
1320 {
1321 fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1322 da_file_name);
1323 goto cleanup;
1324 }
7d63a2fa 1325 }
f55ade6e 1326
546d2adb 1327 gcov_close ();
4977bab6 1328 return 0;
86144b75
DE
1329}
1330
4977bab6
ZW
1331/* Solve the flow graph. Propagate counts from the instrumented arcs
1332 to the blocks and the uninstrumented arcs. */
86144b75
DE
1333
1334static void
f55ade6e 1335solve_flow_graph (function_t *fn)
86144b75 1336{
4977bab6
ZW
1337 unsigned ix;
1338 arc_t *arc;
1339 gcov_type *count_ptr = fn->counts;
27283c73 1340 block_t *blk;
32dd366d
KH
1341 block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */
1342 block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
f55ade6e 1343
1ce1b792
NS
1344 /* The arcs were built in reverse order. Fix that now. */
1345 for (ix = fn->num_blocks; ix--;)
1346 {
1347 arc_t *arc_p, *arc_n;
1348
1349 for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
1350 arc_p = arc, arc = arc_n)
1351 {
1352 arc_n = arc->succ_next;
1353 arc->succ_next = arc_p;
1354 }
1355 fn->blocks[ix].succ = arc_p;
1356
1357 for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
1358 arc_p = arc, arc = arc_n)
1359 {
1360 arc_n = arc->pred_next;
1361 arc->pred_next = arc_p;
1362 }
1363 fn->blocks[ix].pred = arc_p;
1364 }
1365
4977bab6 1366 if (fn->num_blocks < 2)
9e637a26 1367 fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
4977bab6
ZW
1368 bbg_file_name, fn->name);
1369 else
86144b75 1370 {
9696c529 1371 if (fn->blocks[ENTRY_BLOCK].num_pred)
9e637a26 1372 fnotice (stderr, "%s:'%s' has arcs to entry block\n",
4977bab6 1373 bbg_file_name, fn->name);
86144b75 1374 else
4977bab6
ZW
1375 /* We can't deduce the entry block counts from the lack of
1376 predecessors. */
9696c529 1377 fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
f55ade6e 1378
9696c529 1379 if (fn->blocks[EXIT_BLOCK].num_succ)
9e637a26 1380 fnotice (stderr, "%s:'%s' has arcs from exit block\n",
4977bab6
ZW
1381 bbg_file_name, fn->name);
1382 else
1383 /* Likewise, we can't deduce exit block counts from the lack
1384 of its successors. */
9696c529 1385 fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
86144b75
DE
1386 }
1387
4977bab6
ZW
1388 /* Propagate the measured counts, this must be done in the same
1389 order as the code in profile.c */
27283c73 1390 for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
86144b75 1391 {
4977bab6
ZW
1392 block_t const *prev_dst = NULL;
1393 int out_of_order = 0;
27283c73 1394 int non_fake_succ = 0;
f55ade6e 1395
27283c73 1396 for (arc = blk->succ; arc; arc = arc->succ_next)
86144b75 1397 {
27283c73
NS
1398 if (!arc->fake)
1399 non_fake_succ++;
f55ade6e 1400
4977bab6 1401 if (!arc->on_tree)
86144b75 1402 {
4977bab6
ZW
1403 if (count_ptr)
1404 arc->count = *count_ptr++;
1405 arc->count_valid = 1;
27283c73 1406 blk->num_succ--;
4977bab6 1407 arc->dst->num_pred--;
86144b75 1408 }
4977bab6
ZW
1409 if (prev_dst && prev_dst > arc->dst)
1410 out_of_order = 1;
1411 prev_dst = arc->dst;
86144b75 1412 }
27283c73
NS
1413 if (non_fake_succ == 1)
1414 {
1415 /* If there is only one non-fake exit, it is an
1416 unconditional branch. */
1417 for (arc = blk->succ; arc; arc = arc->succ_next)
1418 if (!arc->fake)
1419 {
1420 arc->is_unconditional = 1;
1421 /* If this block is instrumenting a call, it might be
e0bb17a8 1422 an artificial block. It is not artificial if it has
10b7602f
NS
1423 a non-fallthrough exit, or the destination of this
1424 arc has more than one entry. Mark the destination
1425 block as a return site, if none of those conditions
1426 hold. */
1427 if (blk->is_call_site && arc->fall_through
1428 && arc->dst->pred == arc && !arc->pred_next)
1429 arc->dst->is_call_return = 1;
27283c73
NS
1430 }
1431 }
f55ade6e 1432
4977bab6
ZW
1433 /* Sort the successor arcs into ascending dst order. profile.c
1434 normally produces arcs in the right order, but sometimes with
1435 one or two out of order. We're not using a particularly
32dd366d 1436 smart sort. */
4977bab6 1437 if (out_of_order)
86144b75 1438 {
27283c73 1439 arc_t *start = blk->succ;
4977bab6 1440 unsigned changes = 1;
f55ade6e 1441
4977bab6
ZW
1442 while (changes)
1443 {
1444 arc_t *arc, *arc_p, *arc_n;
f55ade6e 1445
4977bab6
ZW
1446 changes = 0;
1447 for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1448 {
1449 if (arc->dst > arc_n->dst)
1450 {
1451 changes = 1;
1452 if (arc_p)
1453 arc_p->succ_next = arc_n;
1454 else
1455 start = arc_n;
1456 arc->succ_next = arc_n->succ_next;
1457 arc_n->succ_next = arc;
1458 arc_p = arc_n;
1459 }
1460 else
1461 {
1462 arc_p = arc;
1463 arc = arc_n;
1464 }
1465 }
1466 }
27283c73 1467 blk->succ = start;
86144b75 1468 }
f55ade6e 1469
4977bab6
ZW
1470 /* Place it on the invalid chain, it will be ignored if that's
1471 wrong. */
27283c73
NS
1472 blk->invalid_chain = 1;
1473 blk->chain = invalid_blocks;
1474 invalid_blocks = blk;
4977bab6
ZW
1475 }
1476
1477 while (invalid_blocks || valid_blocks)
1478 {
4977bab6 1479 while ((blk = invalid_blocks))
86144b75 1480 {
4977bab6
ZW
1481 gcov_type total = 0;
1482 const arc_t *arc;
f55ade6e 1483
4977bab6
ZW
1484 invalid_blocks = blk->chain;
1485 blk->invalid_chain = 0;
1486 if (!blk->num_succ)
1487 for (arc = blk->succ; arc; arc = arc->succ_next)
1488 total += arc->count;
1489 else if (!blk->num_pred)
1490 for (arc = blk->pred; arc; arc = arc->pred_next)
1491 total += arc->count;
1492 else
1493 continue;
f55ade6e 1494
4977bab6
ZW
1495 blk->count = total;
1496 blk->count_valid = 1;
1497 blk->chain = valid_blocks;
1498 blk->valid_chain = 1;
1499 valid_blocks = blk;
86144b75 1500 }
4977bab6 1501 while ((blk = valid_blocks))
86144b75 1502 {
4977bab6
ZW
1503 gcov_type total;
1504 arc_t *arc, *inv_arc;
1505
1506 valid_blocks = blk->chain;
1507 blk->valid_chain = 0;
1508 if (blk->num_succ == 1)
1509 {
1510 block_t *dst;
f55ade6e 1511
4977bab6
ZW
1512 total = blk->count;
1513 inv_arc = NULL;
1514 for (arc = blk->succ; arc; arc = arc->succ_next)
1515 {
1516 total -= arc->count;
1517 if (!arc->count_valid)
1518 inv_arc = arc;
1519 }
1520 dst = inv_arc->dst;
1521 inv_arc->count_valid = 1;
1522 inv_arc->count = total;
1523 blk->num_succ--;
1524 dst->num_pred--;
1525 if (dst->count_valid)
1526 {
1527 if (dst->num_pred == 1 && !dst->valid_chain)
1528 {
1529 dst->chain = valid_blocks;
1530 dst->valid_chain = 1;
1531 valid_blocks = dst;
1532 }
1533 }
1534 else
1535 {
1536 if (!dst->num_pred && !dst->invalid_chain)
1537 {
1538 dst->chain = invalid_blocks;
1539 dst->invalid_chain = 1;
1540 invalid_blocks = dst;
1541 }
1542 }
1543 }
1544 if (blk->num_pred == 1)
1545 {
1546 block_t *src;
f55ade6e 1547
4977bab6
ZW
1548 total = blk->count;
1549 inv_arc = NULL;
1550 for (arc = blk->pred; arc; arc = arc->pred_next)
1551 {
1552 total -= arc->count;
1553 if (!arc->count_valid)
1554 inv_arc = arc;
1555 }
1556 src = inv_arc->src;
1557 inv_arc->count_valid = 1;
1558 inv_arc->count = total;
1559 blk->num_pred--;
1560 src->num_succ--;
1561 if (src->count_valid)
1562 {
1563 if (src->num_succ == 1 && !src->valid_chain)
1564 {
1565 src->chain = valid_blocks;
1566 src->valid_chain = 1;
1567 valid_blocks = src;
1568 }
1569 }
1570 else
1571 {
1572 if (!src->num_succ && !src->invalid_chain)
1573 {
1574 src->chain = invalid_blocks;
1575 src->invalid_chain = 1;
1576 invalid_blocks = src;
1577 }
1578 }
1579 }
86144b75
DE
1580 }
1581 }
f55ade6e 1582
4977bab6
ZW
1583 /* If the graph has been correctly solved, every block will have a
1584 valid count. */
1585 for (ix = 0; ix < fn->num_blocks; ix++)
1586 if (!fn->blocks[ix].count_valid)
1587 {
9e637a26 1588 fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
4977bab6
ZW
1589 bbg_file_name, fn->name);
1590 break;
1591 }
86144b75 1592}
4977bab6 1593
8919c0d9
NS
1594/* Mark all the blocks only reachable via an incoming catch. */
1595
1596static void
1597find_exception_blocks (function_t *fn)
1598{
1599 unsigned ix;
1600 block_t **queue = XALLOCAVEC (block_t *, fn->num_blocks);
1601
1602 /* First mark all blocks as exceptional. */
1603 for (ix = fn->num_blocks; ix--;)
1604 fn->blocks[ix].exceptional = 1;
1605
1606 /* Now mark all the blocks reachable via non-fake edges */
1607 queue[0] = fn->blocks;
1608 queue[0]->exceptional = 0;
1609 for (ix = 1; ix;)
1610 {
1611 block_t *block = queue[--ix];
1612 const arc_t *arc;
1613
1614 for (arc = block->succ; arc; arc = arc->succ_next)
1615 if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
1616 {
1617 arc->dst->exceptional = 0;
1618 queue[ix++] = arc->dst;
1619 }
1620 }
1621}
86144b75 1622\f
86144b75 1623
4977bab6 1624/* Increment totals in COVERAGE according to arc ARC. */
8b219a76
NS
1625
1626static void
f55ade6e 1627add_branch_counts (coverage_t *coverage, const arc_t *arc)
8b219a76 1628{
27283c73 1629 if (arc->is_call_non_return)
8b219a76 1630 {
4977bab6
ZW
1631 coverage->calls++;
1632 if (arc->src->count)
1633 coverage->calls_executed++;
8b219a76 1634 }
27283c73 1635 else if (!arc->is_unconditional)
8b219a76 1636 {
4977bab6
ZW
1637 coverage->branches++;
1638 if (arc->src->count)
1639 coverage->branches_executed++;
1640 if (arc->count)
1641 coverage->branches_taken++;
86144b75
DE
1642 }
1643}
1644
9696c529 1645/* Format a GCOV_TYPE integer as either a percent ratio, or absolute
37b8715b
NS
1646 count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1647 If DP is zero, no decimal point is printed. Only print 100% when
1648 TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1649 format TOP. Return pointer to a static string. */
1650
1651static char const *
f55ade6e 1652format_gcov (gcov_type top, gcov_type bottom, int dp)
37b8715b
NS
1653{
1654 static char buffer[20];
f55ade6e 1655
37b8715b
NS
1656 if (dp >= 0)
1657 {
1658 float ratio = bottom ? (float)top / bottom : 0;
1659 int ix;
1660 unsigned limit = 100;
1661 unsigned percent;
f55ade6e 1662
37b8715b
NS
1663 for (ix = dp; ix--; )
1664 limit *= 10;
f55ade6e 1665
d19202ba
NS
1666 percent = (unsigned) (ratio * limit + (float)0.5);
1667 if (percent <= 0 && top)
37b8715b 1668 percent = 1;
d19202ba 1669 else if (percent >= limit && top != bottom)
37b8715b
NS
1670 percent = limit - 1;
1671 ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1672 if (dp)
1673 {
1674 dp++;
1675 do
1676 {
1677 buffer[ix+1] = buffer[ix];
1678 ix--;
1679 }
1680 while (dp--);
1681 buffer[ix + 1] = '.';
1682 }
1683 }
1684 else
4977bab6 1685 sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
f55ade6e 1686
37b8715b
NS
1687 return buffer;
1688}
1689
bdbdc4e1 1690/* Summary of execution */
86144b75
DE
1691
1692static void
bdbdc4e1 1693executed_summary (unsigned lines, unsigned executed)
86144b75 1694{
bdbdc4e1 1695 if (lines)
4977bab6 1696 fnotice (stdout, "Lines executed:%s of %d\n",
bdbdc4e1 1697 format_gcov (executed, lines, 2), lines);
86144b75 1698 else
1457ebf9 1699 fnotice (stdout, "No executable lines\n");
bdbdc4e1
NS
1700}
1701
1702/* Output summary info for a function or file. */
1703
1704static void
1705function_summary (const coverage_t *coverage, const char *title)
1706{
1707 fnotice (stdout, "%s '%s'\n", title, coverage->name);
1708 executed_summary (coverage->lines, coverage->lines_executed);
86144b75 1709
4977bab6 1710 if (flag_branches)
86144b75 1711 {
4977bab6 1712 if (coverage->branches)
86144b75 1713 {
4977bab6
ZW
1714 fnotice (stdout, "Branches executed:%s of %d\n",
1715 format_gcov (coverage->branches_executed,
1716 coverage->branches, 2),
1717 coverage->branches);
1718 fnotice (stdout, "Taken at least once:%s of %d\n",
1719 format_gcov (coverage->branches_taken,
1720 coverage->branches, 2),
1721 coverage->branches);
86144b75
DE
1722 }
1723 else
4977bab6
ZW
1724 fnotice (stdout, "No branches\n");
1725 if (coverage->calls)
1726 fnotice (stdout, "Calls executed:%s of %d\n",
1727 format_gcov (coverage->calls_executed, coverage->calls, 2),
1728 coverage->calls);
86144b75 1729 else
4977bab6 1730 fnotice (stdout, "No calls\n");
8b219a76
NS
1731 }
1732}
1733
eeabee0a
NS
1734/* Canonicalize the filename NAME by canonicalizing directory
1735 separators, eliding . components and resolving .. components
1736 appropriately. Always returns a unique string. */
1737
1738static char *
1739canonicalize_name (const char *name)
1740{
1741 /* The canonical name cannot be longer than the incoming name. */
1742 char *result = XNEWVEC (char, strlen (name) + 1);
1743 const char *base = name, *probe;
1744 char *ptr = result;
1745 char *dd_base;
1746 int slash = 0;
1747
1748#if HAVE_DOS_BASED_FILE_SYSTEM
1749 if (base[0] && base[1] == ':')
1750 {
1751 result[0] = base[0];
1752 result[1] = ':';
1753 base += 2;
1754 ptr += 2;
1755 }
1756#endif
1757 for (dd_base = ptr; *base; base = probe)
1758 {
1759 size_t len;
1760
1761 for (probe = base; *probe; probe++)
1762 if (IS_DIR_SEPARATOR (*probe))
1763 break;
1764
1765 len = probe - base;
1766 if (len == 1 && base[0] == '.')
1767 /* Elide a '.' directory */
1768 ;
1769 else if (len == 2 && base[0] == '.' && base[1] == '.')
1770 {
1771 /* '..', we can only elide it and the previous directory, if
1772 we're not a symlink. */
8c121ccb
NS
1773 struct stat ATTRIBUTE_UNUSED buf;
1774
eeabee0a 1775 *ptr = 0;
8c121ccb
NS
1776 if (dd_base == ptr
1777#if defined (S_ISLNK)
1778 /* S_ISLNK is not POSIX.1-1996. */
1779 || stat (result, &buf) || S_ISLNK (buf.st_mode)
1780#endif
1781 )
eeabee0a
NS
1782 {
1783 /* Cannot elide, or unreadable or a symlink. */
1784 dd_base = ptr + 2 + slash;
1785 goto regular;
1786 }
1787 while (ptr != dd_base && *ptr != '/')
1788 ptr--;
1789 slash = ptr != result;
1790 }
1791 else
1792 {
1793 regular:
1794 /* Regular pathname component. */
1795 if (slash)
1796 *ptr++ = '/';
1797 memcpy (ptr, base, len);
1798 ptr += len;
1799 slash = 1;
1800 }
1801
1802 for (; IS_DIR_SEPARATOR (*probe); probe++)
1803 continue;
1804 }
1805 *ptr = 0;
1806
1807 return result;
1808}
1809
1810/* Generate an output file name. INPUT_NAME is the canonicalized main
1811 input file and SRC_NAME is the canonicalized file name.
1812 LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation. With
8b219a76
NS
1813 long_output_names we prepend the processed name of the input file
1814 to each output name (except when the current source file is the
1815 input file, so you don't get a double concatenation). The two
eeabee0a
NS
1816 components are separated by '##'. With preserve_paths we create a
1817 filename from all path components of the source file, replacing '/'
1818 with '#', and .. with '^', without it we simply take the basename
1819 component. (Remember, the canonicalized name will already have
1820 elided '.' components and converted \\ separators.) */
8b219a76
NS
1821
1822static char *
f55ade6e 1823make_gcov_file_name (const char *input_name, const char *src_name)
8b219a76 1824{
eeabee0a
NS
1825 char *ptr;
1826 char *result;
f55ade6e 1827
1a9075e2 1828 if (flag_long_names && input_name && strcmp (src_name, input_name))
8b219a76
NS
1829 {
1830 /* Generate the input filename part. */
eeabee0a
NS
1831 result = XNEWVEC (char, strlen (input_name) + strlen (src_name) + 10);
1832
1833 ptr = result;
1834 ptr = mangle_name (input_name, ptr);
1835 ptr[0] = ptr[1] = '#';
1836 ptr += 2;
8b219a76 1837 }
1a9075e2
TG
1838 else
1839 {
eeabee0a
NS
1840 result = XNEWVEC (char, strlen (src_name) + 10);
1841 ptr = result;
1a9075e2 1842 }
f55ade6e 1843
eeabee0a
NS
1844 ptr = mangle_name (src_name, ptr);
1845 strcpy (ptr, ".gcov");
1846
1847 return result;
1848}
f55ade6e 1849
eeabee0a
NS
1850static char *
1851mangle_name (char const *base, char *ptr)
1852{
1853 size_t len;
1854
1855 /* Generate the source filename part. */
1856 if (!flag_preserve_paths)
1857 {
1858 base = lbasename (base);
1859 len = strlen (base);
1860 memcpy (ptr, base, len);
1861 ptr += len;
1862 }
1863 else
8b219a76 1864 {
eeabee0a 1865 /* Convert '/' to '#', convert '..' to '^',
2f07423c 1866 convert ':' to '~' on DOS based file system. */
eeabee0a 1867 const char *probe;
f55ade6e 1868
eeabee0a
NS
1869#if HAVE_DOS_BASED_FILE_SYSTEM
1870 if (base[0] && base[1] == ':')
2f07423c 1871 {
eeabee0a
NS
1872 ptr[0] = base[0];
1873 ptr[1] = '~';
1874 ptr += 2;
1875 base += 2;
1876 }
2f07423c 1877#endif
eeabee0a
NS
1878 for (; *base; base = probe)
1879 {
1880 size_t len;
1881
1882 for (probe = base; *probe; probe++)
1883 if (*probe == '/')
1884 break;
1885 len = probe - base;
1886 if (len == 2 && base[0] == '.' && base[1] == '.')
1887 *ptr++ = '^';
1888 else
2f07423c 1889 {
eeabee0a
NS
1890 memcpy (ptr, base, len);
1891 ptr += len;
2f07423c 1892 }
eeabee0a 1893 if (*probe)
ba78087b 1894 {
eeabee0a
NS
1895 *ptr++ = '#';
1896 probe++;
ba78087b 1897 }
f55ade6e 1898 }
86144b75 1899 }
eeabee0a
NS
1900
1901 return ptr;
86144b75
DE
1902}
1903
4977bab6 1904/* Scan through the bb_data for each line in the block, increment
8b219a76
NS
1905 the line number execution count indicated by the execution count of
1906 the appropriate basic block. */
86144b75
DE
1907
1908static void
f55ade6e 1909add_line_counts (coverage_t *coverage, function_t *fn)
86144b75 1910{
4977bab6 1911 unsigned ix;
beb235f8 1912 line_t *line = NULL; /* This is propagated from one iteration to the
4977bab6
ZW
1913 next. */
1914
32dd366d 1915 /* Scan each basic block. */
4977bab6 1916 for (ix = 0; ix != fn->num_blocks; ix++)
86144b75 1917 {
27283c73 1918 block_t *block = &fn->blocks[ix];
4977bab6
ZW
1919 unsigned *encoding;
1920 const source_t *src = NULL;
1921 unsigned jx;
1922
27283c73
NS
1923 if (block->count && ix && ix + 1 != fn->num_blocks)
1924 fn->blocks_executed++;
1925 for (jx = 0, encoding = block->u.line.encoding;
1926 jx != block->u.line.num; jx++, encoding++)
4977bab6
ZW
1927 if (!*encoding)
1928 {
1ce1b792 1929 src = &sources[*++encoding];
4977bab6
ZW
1930 jx++;
1931 }
1932 else
1933 {
1934 line = &src->lines[*encoding];
1935
1936 if (coverage)
1937 {
1938 if (!line->exists)
1939 coverage->lines++;
27283c73 1940 if (!line->count && block->count)
4977bab6
ZW
1941 coverage->lines_executed++;
1942 }
1943 line->exists = 1;
8919c0d9
NS
1944 if (!block->exceptional)
1945 line->unexceptional = 1;
4977bab6
ZW
1946 line->count += block->count;
1947 }
27283c73 1948 free (block->u.line.encoding);
10b7602f
NS
1949 block->u.cycle.arc = NULL;
1950 block->u.cycle.ident = ~0U;
f55ade6e 1951
27283c73
NS
1952 if (!ix || ix + 1 == fn->num_blocks)
1953 /* Entry or exit block */;
1954 else if (flag_all_blocks)
86144b75 1955 {
1ce1b792
NS
1956 line_t *block_line = line;
1957
1958 if (!block_line)
1959 block_line = &sources[fn->src].lines[fn->line];
f55ade6e 1960
10b7602f
NS
1961 block->chain = block_line->u.blocks;
1962 block_line->u.blocks = block;
27283c73
NS
1963 }
1964 else if (flag_branches)
1965 {
1966 arc_t *arc;
1967
4977bab6 1968 for (arc = block->succ; arc; arc = arc->succ_next)
86144b75 1969 {
27283c73
NS
1970 arc->line_next = line->u.branches;
1971 line->u.branches = arc;
1972 if (coverage && !arc->is_unconditional)
4977bab6 1973 add_branch_counts (coverage, arc);
86144b75 1974 }
8b219a76
NS
1975 }
1976 }
4977bab6 1977 if (!line)
9e637a26 1978 fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
4977bab6
ZW
1979}
1980
32dd366d 1981/* Accumulate the line counts of a file. */
4977bab6
ZW
1982
1983static void
f55ade6e 1984accumulate_line_counts (source_t *src)
4977bab6
ZW
1985{
1986 line_t *line;
27283c73 1987 function_t *fn, *fn_p, *fn_n;
4977bab6 1988 unsigned ix;
27283c73
NS
1989
1990 /* Reverse the function order. */
1991 for (fn = src->functions, fn_p = NULL; fn;
1992 fn_p = fn, fn = fn_n)
1993 {
1994 fn_n = fn->line_next;
1995 fn->line_next = fn_p;
1996 }
1997 src->functions = fn_p;
f55ade6e 1998
4977bab6 1999 for (ix = src->num_lines, line = src->lines; ix--; line++)
8b219a76 2000 {
27283c73 2001 if (!flag_all_blocks)
8b219a76 2002 {
27283c73 2003 arc_t *arc, *arc_p, *arc_n;
f55ade6e 2004
27283c73
NS
2005 /* Total and reverse the branch information. */
2006 for (arc = line->u.branches, arc_p = NULL; arc;
2007 arc_p = arc, arc = arc_n)
2008 {
2009 arc_n = arc->line_next;
2010 arc->line_next = arc_p;
f55ade6e 2011
27283c73
NS
2012 add_branch_counts (&src->coverage, arc);
2013 }
2014 line->u.branches = arc_p;
8b219a76 2015 }
27283c73
NS
2016 else if (line->u.blocks)
2017 {
2018 /* The user expects the line count to be the number of times
2019 a line has been executed. Simply summing the block count
2020 will give an artificially high number. The Right Thing
10b7602f
NS
2021 is to sum the entry counts to the graph of blocks on this
2022 line, then find the elementary cycles of the local graph
2023 and add the transition counts of those cycles. */
27283c73 2024 block_t *block, *block_p, *block_n;
27283c73 2025 gcov_type count = 0;
f55ade6e 2026
f9da5064 2027 /* Reverse the block information. */
27283c73
NS
2028 for (block = line->u.blocks, block_p = NULL; block;
2029 block_p = block, block = block_n)
2030 {
2031 block_n = block->chain;
2032 block->chain = block_p;
10b7602f 2033 block->u.cycle.ident = ix;
27283c73
NS
2034 }
2035 line->u.blocks = block_p;
f55ade6e 2036
10b7602f
NS
2037 /* Sum the entry arcs. */
2038 for (block = line->u.blocks; block; block = block->chain)
2039 {
2040 arc_t *arc;
86144b75 2041
10b7602f
NS
2042 for (arc = block->pred; arc; arc = arc->pred_next)
2043 {
2044 if (arc->src->u.cycle.ident != ix)
2045 count += arc->count;
2046 if (flag_branches)
2047 add_branch_counts (&src->coverage, arc);
2048 }
3d7ca167
ZD
2049
2050 /* Initialize the cs_count. */
2051 for (arc = block->succ; arc; arc = arc->succ_next)
2052 arc->cs_count = arc->count;
10b7602f
NS
2053 }
2054
2055 /* Find the loops. This uses the algorithm described in
2056 Tiernan 'An Efficient Search Algorithm to Find the
2057 Elementary Circuits of a Graph', CACM Dec 1970. We hold
2058 the P array by having each block point to the arc that
2059 connects to the previous block. The H array is implicitly
2060 held because of the arc ordering, and the block's
2061 previous arc pointer.
2062
2063 Although the algorithm is O(N^3) for highly connected
2064 graphs, at worst we'll have O(N^2), as most blocks have
2065 only one or two exits. Most graphs will be small.
2066
2067 For each loop we find, locate the arc with the smallest
2068 transition count, and add that to the cumulative
3d7ca167
ZD
2069 count. Decrease flow over the cycle and remove the arc
2070 from consideration. */
10b7602f 2071 for (block = line->u.blocks; block; block = block->chain)
27283c73 2072 {
10b7602f
NS
2073 block_t *head = block;
2074 arc_t *arc;
f55ade6e 2075
10b7602f
NS
2076 next_vertex:;
2077 arc = head->succ;
2078 current_vertex:;
2079 while (arc)
27283c73 2080 {
10b7602f
NS
2081 block_t *dst = arc->dst;
2082 if (/* Already used that arc. */
2083 arc->cycle
2084 /* Not to same graph, or before first vertex. */
2085 || dst->u.cycle.ident != ix
2086 /* Already in path. */
2087 || dst->u.cycle.arc)
2088 {
2089 arc = arc->succ_next;
2090 continue;
2091 }
f55ade6e 2092
10b7602f 2093 if (dst == block)
27283c73 2094 {
10b7602f 2095 /* Found a closing arc. */
3d7ca167 2096 gcov_type cycle_count = arc->cs_count;
10b7602f
NS
2097 arc_t *cycle_arc = arc;
2098 arc_t *probe_arc;
f55ade6e 2099
71c0e7fc 2100 /* Locate the smallest arc count of the loop. */
10b7602f
NS
2101 for (dst = head; (probe_arc = dst->u.cycle.arc);
2102 dst = probe_arc->src)
3d7ca167 2103 if (cycle_count > probe_arc->cs_count)
10b7602f 2104 {
3d7ca167 2105 cycle_count = probe_arc->cs_count;
10b7602f
NS
2106 cycle_arc = probe_arc;
2107 }
f55ade6e 2108
10b7602f
NS
2109 count += cycle_count;
2110 cycle_arc->cycle = 1;
3d7ca167
ZD
2111
2112 /* Remove the flow from the cycle. */
2113 arc->cs_count -= cycle_count;
2114 for (dst = head; (probe_arc = dst->u.cycle.arc);
2115 dst = probe_arc->src)
2116 probe_arc->cs_count -= cycle_count;
2117
10b7602f
NS
2118 /* Unwind to the cyclic arc. */
2119 while (head != cycle_arc->src)
27283c73 2120 {
10b7602f 2121 arc = head->u.cycle.arc;
3d7ca167 2122 head->u.cycle.arc = NULL;
10b7602f 2123 head = arc->src;
27283c73 2124 }
10b7602f
NS
2125 /* Move on. */
2126 arc = arc->succ_next;
2127 continue;
27283c73 2128 }
f55ade6e 2129
10b7602f
NS
2130 /* Add new block to chain. */
2131 dst->u.cycle.arc = arc;
2132 head = dst;
2133 goto next_vertex;
27283c73 2134 }
10b7602f
NS
2135 /* We could not add another vertex to the path. Remove
2136 the last vertex from the list. */
2137 arc = head->u.cycle.arc;
2138 if (arc)
27283c73 2139 {
71c0e7fc 2140 /* It was not the first vertex. Move onto next arc. */
10b7602f
NS
2141 head->u.cycle.arc = NULL;
2142 head = arc->src;
2143 arc = arc->succ_next;
2144 goto current_vertex;
27283c73 2145 }
10b7602f
NS
2146 /* Mark this block as unusable. */
2147 block->u.cycle.ident = ~0U;
27283c73 2148 }
10b7602f 2149
27283c73
NS
2150 line->count = count;
2151 }
f55ade6e 2152
4977bab6 2153 if (line->exists)
8b219a76 2154 {
4977bab6
ZW
2155 src->coverage.lines++;
2156 if (line->count)
2157 src->coverage.lines_executed++;
8b219a76 2158 }
8b219a76
NS
2159 }
2160}
86144b75 2161
61ada8ae 2162/* Output information about ARC number IX. Returns nonzero if
27283c73
NS
2163 anything is output. */
2164
2165static int
f55ade6e 2166output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
27283c73 2167{
27283c73
NS
2168 if (arc->is_call_non_return)
2169 {
2170 if (arc->src->count)
2171 {
2172 fnotice (gcov_file, "call %2d returned %s\n", ix,
2173 format_gcov (arc->src->count - arc->count,
2174 arc->src->count, -flag_counts));
2175 }
2176 else
2177 fnotice (gcov_file, "call %2d never executed\n", ix);
2178 }
2179 else if (!arc->is_unconditional)
2180 {
2181 if (arc->src->count)
2182 fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
2183 format_gcov (arc->count, arc->src->count, -flag_counts),
8919c0d9
NS
2184 arc->fall_through ? " (fallthrough)"
2185 : arc->is_throw ? " (throw)" : "");
27283c73
NS
2186 else
2187 fnotice (gcov_file, "branch %2d never executed\n", ix);
2188 }
10b7602f 2189 else if (flag_unconditional && !arc->dst->is_call_return)
27283c73
NS
2190 {
2191 if (arc->src->count)
2192 fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
2193 format_gcov (arc->count, arc->src->count, -flag_counts));
2194 else
2195 fnotice (gcov_file, "unconditional %2d never executed\n", ix);
2196 }
2197 else
2198 return 0;
2199 return 1;
f55ade6e 2200
27283c73
NS
2201}
2202
8f961b22
NS
2203static const char *
2204read_line (FILE *file)
2205{
2206 static char *string;
2207 static size_t string_len;
2208 size_t pos = 0;
2209 char *ptr;
2210
2211 if (!string_len)
2212 {
2213 string_len = 200;
2214 string = XNEWVEC (char, string_len);
2215 }
2216
2217 while ((ptr = fgets (string + pos, string_len - pos, file)))
2218 {
2219 size_t len = strlen (string + pos);
2220
2221 if (string[pos + len - 1] == '\n')
2222 {
2223 string[pos + len - 1] = 0;
2224 return string;
2225 }
2226 pos += len;
92b05e72
JJ
2227 string = XRESIZEVEC (char, string, string_len * 2);
2228 string_len *= 2;
8f961b22
NS
2229 }
2230
2231 return pos ? string : NULL;
2232}
2233
8b219a76
NS
2234/* Read in the source file one line at a time, and output that line to
2235 the gcov file preceded by its execution count and other
2236 information. */
86144b75 2237
8b219a76 2238static void
f55ade6e 2239output_lines (FILE *gcov_file, const source_t *src)
8b219a76
NS
2240{
2241 FILE *source_file;
f55ade6e 2242 unsigned line_num; /* current line number. */
4977bab6 2243 const line_t *line; /* current line info ptr. */
8f961b22 2244 const char *retval = ""; /* status of source file reading. */
f5d39c3d 2245 function_t *fn = NULL;
4977bab6 2246
1bec9caa 2247 fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->coverage.name);
1a9075e2
TG
2248 if (!multiple_files)
2249 {
2250 fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
2251 fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
2252 no_data_file ? "-" : da_file_name);
5366b186 2253 fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, object_runs);
1a9075e2 2254 }
27283c73 2255 fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
f55ade6e 2256
4977bab6 2257 source_file = fopen (src->name, "r");
8b219a76
NS
2258 if (!source_file)
2259 {
1bec9caa 2260 fnotice (stderr, "Cannot open source file %s\n", src->name);
8b219a76
NS
2261 retval = NULL;
2262 }
1a9075e2
TG
2263 else if (src->file_time == 0)
2264 fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0);
8b219a76 2265
f5d39c3d
NS
2266 if (flag_branches)
2267 fn = src->functions;
2268
4977bab6
ZW
2269 for (line_num = 1, line = &src->lines[line_num];
2270 line_num < src->num_lines; line_num++, line++)
8b219a76 2271 {
27283c73
NS
2272 for (; fn && fn->line == line_num; fn = fn->line_next)
2273 {
9696c529
SB
2274 arc_t *arc = fn->blocks[EXIT_BLOCK].pred;
2275 gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
2276 gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
b8698a0f 2277
27283c73
NS
2278 for (; arc; arc = arc->pred_next)
2279 if (arc->fake)
2280 return_count -= arc->count;
b8698a0f 2281
27283c73
NS
2282 fprintf (gcov_file, "function %s", fn->name);
2283 fprintf (gcov_file, " called %s",
9696c529 2284 format_gcov (called_count, 0, -1));
27283c73 2285 fprintf (gcov_file, " returned %s",
9696c529 2286 format_gcov (return_count, called_count, 0));
27283c73
NS
2287 fprintf (gcov_file, " blocks executed %s",
2288 format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
2289 fprintf (gcov_file, "\n");
2290 }
f55ade6e 2291
8f961b22
NS
2292 if (retval)
2293 retval = read_line (source_file);
2294
8b219a76 2295 /* For lines which don't exist in the .bb file, print '-' before
f55ade6e 2296 the source line. For lines which exist but were never
8f961b22
NS
2297 executed, print '#####' or '=====' before the source line.
2298 Otherwise, print the execution count before the source line.
2299 There are 16 spaces of indentation added before the source
2300 line so that tabs won't be messed up. */
2301 fprintf (gcov_file, "%9s:%5u:%s\n",
8919c0d9
NS
2302 !line->exists ? "-" : line->count
2303 ? format_gcov (line->count, 0, -1)
8f961b22
NS
2304 : line->unexceptional ? "#####" : "=====", line_num,
2305 retval ? retval : "/*EOF*/");
27283c73
NS
2306
2307 if (flag_all_blocks)
8b219a76 2308 {
27283c73 2309 block_t *block;
10b7602f 2310 arc_t *arc;
27283c73 2311 int ix, jx;
f55ade6e 2312
27283c73
NS
2313 for (ix = jx = 0, block = line->u.blocks; block;
2314 block = block->chain)
37b8715b 2315 {
10b7602f 2316 if (!block->is_call_return)
27283c73 2317 fprintf (gcov_file, "%9s:%5u-block %2d\n",
8919c0d9
NS
2318 !line->exists ? "-" : block->count
2319 ? format_gcov (block->count, 0, -1)
2320 : block->exceptional ? "%%%%%" : "$$$$$",
10b7602f 2321 line_num, ix++);
27283c73
NS
2322 if (flag_branches)
2323 for (arc = block->succ; arc; arc = arc->succ_next)
2324 jx += output_branch_count (gcov_file, jx, arc);
86144b75 2325 }
8b219a76 2326 }
27283c73
NS
2327 else if (flag_branches)
2328 {
2329 int ix;
2330 arc_t *arc;
f55ade6e 2331
27283c73
NS
2332 for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
2333 ix += output_branch_count (gcov_file, ix, arc);
2334 }
8b219a76 2335 }
f55ade6e 2336
8b219a76
NS
2337 /* Handle all remaining source lines. There may be lines after the
2338 last line of code. */
2339 if (retval)
2340 {
8f961b22
NS
2341 for (; (retval = read_line (source_file)); line_num++)
2342 fprintf (gcov_file, "%9s:%5u:%s\n", "-", line_num, retval);
8b219a76 2343 }
f55ade6e 2344
8b219a76
NS
2345 if (source_file)
2346 fclose (source_file);
2347}