gcov.c 48.7 KB
Newer Older
Doug Evans committed
1 2
/* Gcov.c: prepend line execution counts and branch probabilities to a
   source file.
3 4
   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
   2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Doug Evans committed
5
   Contributed by James E. Wilson of Cygnus Support.
6
   Mangled by Bob Manson of Cygnus Support.
7
   Mangled further by Nathan Sidwell <nathan@codesourcery.com>
Doug Evans committed
8 9 10 11 12 13 14 15 16 17 18 19 20

Gcov is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

Gcov is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Gcov; see the file COPYING.  If not, write to
Kelley Cook committed
21 22
the Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.  */
Doug Evans committed
23 24 25 26 27 28 29 30 31

/* ??? Print a list of the ten blocks with the highest execution counts,
   and list the line numbers corresponding to those blocks.  Also, perhaps
   list the line numbers with the highest execution counts, only printing
   the first if there are several which are all listed in the same block.  */

/* ??? Should have an option to print the number of basic blocks, and the
   percent of them that are covered.  */

32 33 34 35 36 37 38 39 40 41 42
/* ??? Does not correctly handle the case where two .bb files refer to
   the same included source file.  For example, if one has a short
   file containing only inline functions, which is then included in
   two other files, then there will be two .bb files which refer to
   the include file, but there is no way to get the total execution
   counts for the included file, can only get execution counts for one
   or the other of the including files. this can be fixed by --ratios
   --long-file-names --preserve-paths and perl.  */

/* Need an option to show individual block counts, and show
   probabilities of fall through arcs.  */
Doug Evans committed
43

44
#include "config.h"
45
#include "system.h"
46 47
#include "coretypes.h"
#include "tm.h"
48
#include "intl.h"
49
#include "version.h"
Doug Evans committed
50

51 52
#include <getopt.h>

53
#define IN_GCOV 1
Doug Evans committed
54
#include "gcov-io.h"
55
#include "gcov-io.c"
Doug Evans committed
56

57 58 59
/* The bbg file is generated by -ftest-coverage option. The da file is
   generated by a program compiled with -fprofile-arcs. Their formats
   are documented in gcov-io.h.  */
Doug Evans committed
60 61

/* The functions in this file for creating and solution program flow graphs
62 63 64
   are very similar to functions in the gcc source file profile.c.  In
   some places we make use of the knowledge of how profile.c works to
   select particular algorithms here.  */
Doug Evans committed
65 66 67 68 69

/* This is the size of the buffer used to read in source file lines.  */

#define STRING_SIZE 200

70 71
struct function_info;
struct block_info;
72
struct source_info;
Doug Evans committed
73

74
/* Describes an arc between two basic blocks.  */
Doug Evans committed
75

76 77
typedef struct arc_info
{
78
  /* source and destination blocks.  */
79 80
  struct block_info *src;
  struct block_info *dst;
Doug Evans committed
81

82 83
  /* transition counts.  */
  gcov_type count;
84 85
  /* used in cycle search, so that we do not clobber original counts.  */
  gcov_type cs_count;
Doug Evans committed
86 87 88 89 90 91

  unsigned int count_valid : 1;
  unsigned int on_tree : 1;
  unsigned int fake : 1;
  unsigned int fall_through : 1;

92 93 94 95 96 97 98 99 100
  /* Arc is for a function that abnormally returns.  */
  unsigned int is_call_non_return : 1;

  /* Arc is for catch/setjump.  */
  unsigned int is_nonlocal_return : 1;

  /* Is an unconditional branch.  */
  unsigned int is_unconditional : 1;

101 102 103
  /* Loop making arc.  */
  unsigned int cycle : 1;

104 105
  /* Next branch on line.  */
  struct arc_info *line_next;
106

107 108 109 110
  /* Links to next arc on src and dst lists.  */
  struct arc_info *succ_next;
  struct arc_info *pred_next;
} arc_t;
Doug Evans committed
111

112 113
/* Describes a basic block. Contains lists of arcs to successor and
   predecessor blocks.  */
Doug Evans committed
114

115
typedef struct block_info
Doug Evans committed
116
{
117 118 119 120
  /* Chain of exit and entry arcs.  */
  arc_t *succ;
  arc_t *pred;

121
  /* Number of unprocessed exit and entry arcs.  */
122 123 124
  gcov_type num_succ;
  gcov_type num_pred;

125
  /* Block execution count.  */
126
  gcov_type count;
127
  unsigned flags : 13;
128 129 130 131
  unsigned count_valid : 1;
  unsigned valid_chain : 1;
  unsigned invalid_chain : 1;

132
  /* Block is a call instrumenting site.  */
133 134
  unsigned is_call_site : 1; /* Does the call.  */
  unsigned is_call_return : 1; /* Is the return.  */
135

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
  /* Block is a landing pad for longjmp or throw.  */
  unsigned is_nonlocal_return : 1;

  union
  {
    struct
    {
     /* Array of line numbers and source files. source files are
        introduced by a linenumber of zero, the next 'line number' is
        the number of the source file.  Always starts with a source
        file.  */
      unsigned *encoding;
      unsigned num;
    } line; /* Valid until blocks are linked onto lines */
    struct
    {
152
      /* Single line graph cycle workspace.  Used for all-blocks
153
	 mode.  */
154 155 156
      arc_t *arc;
      unsigned ident;
    } cycle; /* Used in all-blocks mode, after blocks are linked onto
157
	       lines.  */
158 159 160 161
  } u;

  /* Temporary chain for solving graph, and for chaining blocks on one
     line.  */
162
  struct block_info *chain;
163

164
} block_t;
Doug Evans committed
165

166
/* Describes a single function. Contains an array of basic blocks.  */
Doug Evans committed
167

168
typedef struct function_info
Nathan Sidwell committed
169
{
170 171
  /* Name of function.  */
  char *name;
172
  unsigned ident;
173
  unsigned checksum;
Doug Evans committed
174

175 176 177
  /* Array of basic blocks.  */
  block_t *blocks;
  unsigned num_blocks;
178
  unsigned blocks_executed;
179 180 181 182

  /* Raw arc coverage counts.  */
  gcov_type *counts;
  unsigned num_counts;
183 184 185 186 187 188 189

  /* First line number.  */
  unsigned line;
  struct source_info *src;

  /* Next function in same source file.  */
  struct function_info *line_next;
190

191 192 193 194 195 196 197
  /* Next function.  */
  struct function_info *next;
} function_t;

/* Describes coverage of a file or function.  */

typedef struct coverage_info
Nathan Sidwell committed
198 199 200
{
  int lines;
  int lines_executed;
201

Nathan Sidwell committed
202 203 204
  int branches;
  int branches_executed;
  int branches_taken;
205

Nathan Sidwell committed
206 207
  int calls;
  int calls_executed;
208

Nathan Sidwell committed
209
  char *name;
210
} coverage_t;
Nathan Sidwell committed
211

212 213
/* Describes a single line of source. Contains a chain of basic blocks
   with code on it.  */
Doug Evans committed
214

215 216 217
typedef struct line_info
{
  gcov_type count;	   /* execution count */
218 219
  union
  {
220
    arc_t *branches;	   /* branches from blocks that end on this
221
			      line. Used for branch-counts when not
222
			      all-blocks mode.  */
223
    block_t *blocks;       /* blocks which start on this line.  Used
224
			      in all-blocks mode.  */
225
  } u;
226 227
  unsigned exists : 1;
} line_t;
Doug Evans committed
228

229 230
/* Describes a file mentioned in the block graph.  Contains an array
   of line info.  */
231

232 233 234 235 236
typedef struct source_info
{
  /* Name of source file.  */
  char *name;
  unsigned index;
237

238
  /* Array of line information.  */
239 240
  line_t *lines;
  unsigned num_lines;
Doug Evans committed
241

242
  coverage_t coverage;
243 244 245 246

  /* Functions in this source file.  These are in ascending line
     number order.  */
  function_t *functions;
247

248 249 250
  /* Next source file.  */
  struct source_info *next;
} source_t;
Doug Evans committed
251

252
/* Holds a list of function basic block graphs.  */
Doug Evans committed
253

254
static function_t *functions;
Doug Evans committed
255

256
/* This points to the head of the sourcefile structure list.  */
Doug Evans committed
257

258
static source_t *sources;
Doug Evans committed
259

260 261 262 263 264
/* This holds data summary information.  */

static struct gcov_summary object_summary;
static unsigned program_count;

265
/* Modification time of graph file.  */
Doug Evans committed
266

267
static time_t bbg_file_time;
Doug Evans committed
268

269
/* Name and file pointer of the input file for the basic block graph.  */
Doug Evans committed
270

271
static char *bbg_file_name;
Doug Evans committed
272

273 274 275
/* Stamp of the bbg file */
static unsigned bbg_stamp;

276
/* Name and file pointer of the input file for the arc count data.  */
Doug Evans committed
277

278
static char *da_file_name;
Doug Evans committed
279

280 281 282 283
/* Data file is missing.  */

static int no_data_file;

284
/* Output branch probabilities.  */
Doug Evans committed
285

286
static int flag_branches = 0;
Doug Evans committed
287

288
/* Show unconditional branches too.  */
289 290
static int flag_unconditional = 0;

Doug Evans committed
291 292 293
/* Output a gcov file if this is true.  This is on by default, and can
   be turned off by the -n option.  */

294
static int flag_gcov_file = 1;
Doug Evans committed
295

296 297 298
/* For included files, make the gcov output file name include the name
   of the input source file.  For example, if x.h is included in a.c,
   then the output file name is a.c##x.h.gcov instead of x.h.gcov.  */
Doug Evans committed
299

300
static int flag_long_names = 0;
Doug Evans committed
301

302 303 304 305 306
/* Output count information for every basic block, not merely those
   that contain line number information.  */

static int flag_all_blocks = 0;

Doug Evans committed
307 308
/* Output summary info for each function.  */

309
static int flag_function_summary = 0;
Doug Evans committed
310

311 312
/* Object directory file prefix.  This is the directory/file where the
   graph and data files are looked for, if nonzero.  */
Doug Evans committed
313 314 315

static char *object_directory = 0;

316
/* Preserve all pathname components. Needed when object files and
317 318 319 320
   source files are in subdirectories. '/' is mangled as '#', '.' is
   elided and '..' mangled to '^'.  */

static int flag_preserve_paths = 0;
321

322
/* Output the number of times a branch was taken as opposed to the percentage
323
   of times it was taken.  */
324

325
static int flag_counts = 0;
326

Doug Evans committed
327
/* Forward declarations.  */
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2;
static int process_args (int, char **);
static void print_usage (int) ATTRIBUTE_NORETURN;
static void print_version (void) ATTRIBUTE_NORETURN;
static void process_file (const char *);
static void create_file_names (const char *);
static source_t *find_source (const char *);
static int read_graph_file (void);
static int read_count_file (void);
static void solve_flow_graph (function_t *);
static void add_branch_counts (coverage_t *, const arc_t *);
static void add_line_counts (coverage_t *, function_t *);
static void function_summary (const coverage_t *, const char *);
static const char *format_gcov (gcov_type, gcov_type, int);
static void accumulate_line_counts (source_t *);
static int output_branch_count (FILE *, int, const arc_t *);
static void output_lines (FILE *, const source_t *);
static char *make_gcov_file_name (const char *, const char *);
static void release_structures (void);
extern int main (int, char **);
Doug Evans committed
348 349

int
350
main (int argc, char **argv)
Doug Evans committed
351
{
352
  int argno;
353

354
  /* Unlock the stdio streams.  */
355
  unlock_std_streams ();
356

357
  gcc_init_libintl ();
358

359 360 361
  argno = process_args (argc, argv);
  if (optind == argc)
    print_usage (true);
Doug Evans committed
362

363 364 365
  for (; argno != argc; argno++)
    {
      release_structures ();
366

367 368
      process_file (argv[argno]);
    }
369

Doug Evans committed
370 371 372
  return 0;
}

373
static void
374
fnotice (FILE *file, const char *cmsgid, ...)
375
{
376
  va_list ap;
377

378 379
  va_start (ap, cmsgid);
  vfprintf (file, _(cmsgid), ap);
380
  va_end (ap);
381
}
Doug Evans committed
382

383 384
/* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
   otherwise the output of --help.  */
Doug Evans committed
385 386

static void
387
print_usage (int error_p)
Doug Evans committed
388
{
389 390
  FILE *file = error_p ? stderr : stdout;
  int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
391

392 393 394 395
  fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
  fnotice (file, "Print code coverage information.\n\n");
  fnotice (file, "  -h, --help                      Print this help, then exit\n");
  fnotice (file, "  -v, --version                   Print version number, then exit\n");
396
  fnotice (file, "  -a, --all-blocks                Show information for every basic block\n");
397 398 399 400 401 402 403
  fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output\n");
  fnotice (file, "  -c, --branch-counts             Given counts of branches taken\n\
                                    rather than percentages\n");
  fnotice (file, "  -n, --no-output                 Do not create an output file\n");
  fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
                                    source files\n");
  fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
404 405
  fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
  fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
406
  fnotice (file, "  -u, --unconditional-branches    Show unconditional branch counts too\n");
407
  fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
408
	   bug_report_url);
409 410 411 412 413 414
  exit (status);
}

/* Print version information and exit.  */

static void
415
print_version (void)
416
{
417
  fnotice (stdout, "gcov (GCC) %s\n", version_string);
418
  fprintf (stdout, "Copyright %s 2006 Free Software Foundation, Inc.\n",
419
	   _("(C)"));
420
  fnotice (stdout,
421 422 423
	   _("This is free software; see the source for copying conditions.\n"
	     "There is NO warranty; not even for MERCHANTABILITY or \n"
	     "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
424
  exit (SUCCESS_EXIT_CODE);
Doug Evans committed
425 426
}

427 428 429 430
static const struct option options[] =
{
  { "help",                 no_argument,       NULL, 'h' },
  { "version",              no_argument,       NULL, 'v' },
431
  { "all-blocks",           no_argument,       NULL, 'a' },
432 433 434 435 436
  { "branch-probabilities", no_argument,       NULL, 'b' },
  { "branch-counts",        no_argument,       NULL, 'c' },
  { "no-output",            no_argument,       NULL, 'n' },
  { "long-file-names",      no_argument,       NULL, 'l' },
  { "function-summaries",   no_argument,       NULL, 'f' },
437 438 439
  { "preserve-paths",       no_argument,       NULL, 'p' },
  { "object-directory",     required_argument, NULL, 'o' },
  { "object-file",          required_argument, NULL, 'o' },
440
  { "unconditional-branches", no_argument,     NULL, 'u' },
441
  { 0, 0, 0, 0 }
442 443
};

444
/* Process args, return index to first non-arg.  */
Doug Evans committed
445

446
static int
447
process_args (int argc, char **argv)
Doug Evans committed
448
{
449
  int opt;
Doug Evans committed
450

451
  while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1)
Doug Evans committed
452
    {
453
      switch (opt)
Doug Evans committed
454
	{
455 456 457
	case 'a':
	  flag_all_blocks = 1;
	  break;
458
	case 'b':
459
	  flag_branches = 1;
460 461
	  break;
	case 'c':
462
	  flag_counts = 1;
463
	  break;
464 465
	case 'f':
	  flag_function_summary = 1;
466
	  break;
467 468 469
	case 'h':
	  print_usage (false);
	  /* print_usage will exit.  */
470
	case 'l':
471
	  flag_long_names = 1;
472
	  break;
473 474
	case 'n':
	  flag_gcov_file = 0;
475 476 477 478
	  break;
	case 'o':
	  object_directory = optarg;
	  break;
479
	case 'p':
480
	  flag_preserve_paths = 1;
481
	  break;
482 483 484 485 486 487
	case 'u':
	  flag_unconditional = 1;
	  break;
	case 'v':
	  print_version ();
	  /* print_version will exit.  */
488 489 490
	default:
	  print_usage (true);
	  /* print_usage will exit.  */
Doug Evans committed
491 492 493
	}
    }

494 495 496 497
  return optind;
}

/* Process a single source file.  */
498

499
static void
500
process_file (const char *file_name)
501 502 503
{
  source_t *src;
  function_t *fn;
504

505 506 507
  create_file_names (file_name);
  if (read_graph_file ())
    return;
508

509 510 511 512 513
  if (!functions)
    {
      fnotice (stderr, "%s:no functions found\n", bbg_file_name);
      return;
    }
514

515 516
  if (read_count_file ())
    return;
517

518 519 520
  for (fn = functions; fn; fn = fn->next)
    solve_flow_graph (fn);
  for (src = sources; src; src = src->next)
521
    src->lines = XCNEWVEC (line_t, src->num_lines);
522 523 524
  for (fn = functions; fn; fn = fn->next)
    {
      coverage_t coverage;
525

526 527 528 529 530 531 532 533 534
      memset (&coverage, 0, sizeof (coverage));
      coverage.name = fn->name;
      add_line_counts (flag_function_summary ? &coverage : NULL, fn);
      if (flag_function_summary)
	{
	  function_summary (&coverage, "Function");
	  fnotice (stdout, "\n");
	}
    }
535

536 537 538 539 540 541 542 543
  for (src = sources; src; src = src->next)
    {
      accumulate_line_counts (src);
      function_summary (&src->coverage, "File");
      if (flag_gcov_file)
	{
	  char *gcov_file_name = make_gcov_file_name (file_name, src->name);
	  FILE *gcov_file = fopen (gcov_file_name, "w");
544

545 546
	  if (gcov_file)
	    {
547
	      fnotice (stdout, "%s:creating '%s'\n",
548 549 550
		       src->name, gcov_file_name);
	      output_lines (gcov_file, src);
	      if (ferror (gcov_file))
551
		    fnotice (stderr, "%s:error writing output file '%s'\n",
552 553 554 555
			     src->name, gcov_file_name);
	      fclose (gcov_file);
	    }
	  else
556
	    fnotice (stderr, "%s:could not open output file '%s'\n",
557 558 559 560 561
		     src->name, gcov_file_name);
	  free (gcov_file_name);
	}
      fnotice (stdout, "\n");
    }
Doug Evans committed
562 563
}

564
/* Release all memory used.  */
Doug Evans committed
565

566
static void
567
release_structures (void)
568 569 570
{
  function_t *fn;
  source_t *src;
571

572 573 574 575
  free (bbg_file_name);
  free (da_file_name);
  da_file_name = bbg_file_name = NULL;
  bbg_file_time = 0;
576
  bbg_stamp = 0;
577

578 579 580 581 582 583 584
  while ((src = sources))
    {
      sources = src->next;

      free (src->name);
      free (src->lines);
    }
585

586 587 588 589
  while ((fn = functions))
    {
      unsigned ix;
      block_t *block;
590

591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
      functions = fn->next;
      for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
	{
	  arc_t *arc, *arc_n;

	  for (arc = block->succ; arc; arc = arc_n)
	    {
	      arc_n = arc->succ_next;
	      free (arc);
	    }
	}
      free (fn->blocks);
      free (fn->counts);
    }
}

/* Generate the names of the graph and data files. If OBJECT_DIRECTORY
   is not specified, these are looked for in the current directory,
   and named from the basename of the FILE_NAME sans extension. If
610
   OBJECT_DIRECTORY is specified and is a directory, the files are in
611 612 613
   that directory, but named from the basename of the FILE_NAME, sans
   extension. Otherwise OBJECT_DIRECTORY is taken to be the name of
   the object *file*, and the data files are named from that.  */
Doug Evans committed
614 615

static void
616
create_file_names (const char *file_name)
Doug Evans committed
617 618
{
  char *cptr;
619
  char *name;
620
  int length = strlen (file_name);
621
  int base;
622

623
  if (object_directory && object_directory[0])
Doug Evans committed
624
    {
625 626 627
      struct stat status;

      length += strlen (object_directory) + 2;
628
      name = XNEWVEC (char, length);
629
      name[0] = 0;
630

631 632 633 634
      base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
      strcat (name, object_directory);
      if (base && name[strlen (name) - 1] != '/')
	strcat (name, "/");
Doug Evans committed
635 636 637
    }
  else
    {
638
      name = XNEWVEC (char, length + 1);
639 640
      name[0] = 0;
      base = 1;
Doug Evans committed
641
    }
642

643 644
  if (base)
    {
645
      /* Append source file name.  */
646 647
      cptr = strrchr (file_name, '/');
      strcat (name, cptr ? cptr + 1 : file_name);
648
    }
649

650
  /* Remove the extension.  */
651
  cptr = strrchr (name, '.');
Doug Evans committed
652
  if (cptr)
653
    *cptr = 0;
654

655
  length = strlen (name);
656
  
657
  bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
658
  strcpy (bbg_file_name, name);
659
  strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
660

661
  da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
662 663
  strcpy (da_file_name, name);
  strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
664

665
  free (name);
666
  return;
Doug Evans committed
667 668
}

669 670
/* Find or create a source file structure for FILE_NAME. Copies
   FILE_NAME on creation */
671 672

static source_t *
673
find_source (const char *file_name)
674 675
{
  source_t *src;
676 677 678

  if (!file_name)
    file_name = "<unknown>";
679

680 681
  for (src = sources; src; src = src->next)
    if (!strcmp (file_name, src->name))
682
      return src;
683

684
  src = XCNEW (source_t);
685 686 687 688 689 690
  src->name = xstrdup (file_name);
  src->coverage.name = src->name;
  src->index = sources ? sources->index + 1 : 1;
  src->next = sources;
  sources = src;

691 692 693
  return src;
}

694
/* Read the graph file. Return nonzero on fatal error.  */
Doug Evans committed
695

696
static int
697
read_graph_file (void)
Doug Evans committed
698
{
699
  unsigned version;
700 701 702 703
  unsigned current_tag = 0;
  struct function_info *fn = NULL;
  source_t *src = NULL;
  unsigned ix;
704
  unsigned tag;
705

706
  if (!gcov_open (bbg_file_name, 1))
Doug Evans committed
707
    {
708 709
      fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
      return 1;
Doug Evans committed
710
    }
711
  bbg_file_time = gcov_time ();
712
  if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
713
    {
714
      fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
715
      gcov_close ();
716 717
      return 1;
    }
718

719 720
  version = gcov_read_unsigned ();
  if (version != GCOV_VERSION)
721 722
    {
      char v[4], e[4];
723

724 725 726
      GCOV_UNSIGNED2STRING (v, version);
      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);

727
      fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
728 729
	       bbg_file_name, v, e);
    }
730 731
  bbg_stamp = gcov_read_unsigned ();

732
  while ((tag = gcov_read_unsigned ()))
733
    {
734
      unsigned length = gcov_read_unsigned ();
735
      gcov_position_t base = gcov_position ();
736

737
      if (tag == GCOV_TAG_FUNCTION)
738
	{
739
	  char *function_name;
740
	  unsigned ident, checksum, lineno;
741 742
	  source_t *src;
	  function_t *probe, *prev;
743

744
	  ident = gcov_read_unsigned ();
745
	  checksum = gcov_read_unsigned ();
746
	  function_name = xstrdup (gcov_read_string ());
747 748
	  src = find_source (gcov_read_string ());
	  lineno = gcov_read_unsigned ();
749

750
	  fn = XCNEW (function_t);
751
	  fn->name = function_name;
752
	  fn->ident = ident;
753
	  fn->checksum = checksum;
754 755
	  fn->src = src;
	  fn->line = lineno;
756 757 758 759

	  fn->next = functions;
	  functions = fn;
	  current_tag = tag;
760

761 762 763 764 765 766 767 768 769 770 771 772 773 774
	  if (lineno >= src->num_lines)
	    src->num_lines = lineno + 1;
	  /* Now insert it into the source file's list of
	     functions. Normally functions will be encountered in
	     ascending order, so a simple scan is quick.  */
	  for (probe = src->functions, prev = NULL;
	       probe && probe->line > lineno;
	       prev = probe, probe = probe->line_next)
	    continue;
	  fn->line_next = probe;
	  if (prev)
	    prev->line_next = fn;
	  else
	    src->functions = fn;
775
	}
776
      else if (fn && tag == GCOV_TAG_BLOCKS)
777
	{
778
	  if (fn->blocks)
779
	    fnotice (stderr, "%s:already seen blocks for '%s'\n",
780 781
		     bbg_file_name, fn->name);
	  else
782
	    {
783
	      unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
784
	      fn->num_blocks = num_blocks;
785

786
	      fn->blocks = XCNEWVEC (block_t, fn->num_blocks);
787
	      for (ix = 0; ix != num_blocks; ix++)
788
		fn->blocks[ix].flags = gcov_read_unsigned ();
789
	    }
790 791 792
	}
      else if (fn && tag == GCOV_TAG_ARCS)
	{
793
	  unsigned src = gcov_read_unsigned ();
794
	  unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
795

796
	  if (src >= fn->num_blocks || fn->blocks[src].succ)
797
	    goto corrupt;
798

799
	  while (num_dests--)
800
	    {
801
	      struct arc_info *arc;
802 803
	      unsigned dest = gcov_read_unsigned ();
	      unsigned flags = gcov_read_unsigned ();
804

805
	      if (dest >= fn->num_blocks)
806
		goto corrupt;
807
	      arc = XCNEW (arc_t);
808

809 810
	      arc->dst = &fn->blocks[dest];
	      arc->src = &fn->blocks[src];
811

812 813 814 815 816
	      arc->count = 0;
	      arc->count_valid = 0;
	      arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
	      arc->fake = !!(flags & GCOV_ARC_FAKE);
	      arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
817

818 819 820
	      arc->succ_next = fn->blocks[src].succ;
	      fn->blocks[src].succ = arc;
	      fn->blocks[src].num_succ++;
821

822 823 824 825
	      arc->pred_next = fn->blocks[dest].pred;
	      fn->blocks[dest].pred = arc;
	      fn->blocks[dest].num_pred++;

826 827 828 829 830 831 832 833 834 835 836 837
	      if (arc->fake)
		{
		  if (src)
		    {
		      /* Exceptional exit from this function, the
			 source block must be a call.  */
		      fn->blocks[src].is_call_site = 1;
		      arc->is_call_non_return = 1;
		    }
		  else
		    {
		      /* Non-local return from a callee of this
838 839
		         function. The destination block is a catch or
		         setjmp.  */
840 841 842 843
		      arc->is_nonlocal_return = 1;
		      fn->blocks[dest].is_nonlocal_return = 1;
		    }
		}
844

845 846
	      if (!arc->on_tree)
		fn->num_counts++;
847
	    }
848 849 850
	}
      else if (fn && tag == GCOV_TAG_LINES)
	{
851
	  unsigned blockno = gcov_read_unsigned ();
852
	  unsigned *line_nos = XCNEWVEC (unsigned, length - 1);
853

854
	  if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
855
	    goto corrupt;
856

857
	  for (ix = 0; ;  )
858
	    {
859
	      unsigned lineno = gcov_read_unsigned ();
860

861
	      if (lineno)
862
		{
863 864 865 866 867 868 869 870
		  if (!ix)
		    {
		      line_nos[ix++] = 0;
		      line_nos[ix++] = src->index;
		    }
		  line_nos[ix++] = lineno;
		  if (lineno >= src->num_lines)
		    src->num_lines = lineno + 1;
871
		}
872 873
	      else
		{
874
		  const char *file_name = gcov_read_string ();
875

876
		  if (!file_name)
877
		    break;
878
		  src = find_source (file_name);
879

880 881 882
		  line_nos[ix++] = 0;
		  line_nos[ix++] = src->index;
		}
883
	    }
884

885 886
	  fn->blocks[blockno].u.line.encoding = line_nos;
	  fn->blocks[blockno].u.line.num = ix;
887 888 889 890 891 892
	}
      else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
	{
	  fn = NULL;
	  current_tag = 0;
	}
893
      gcov_sync (base, length);
894
      if (gcov_is_error ())
895 896 897 898 899 900
	{
	corrupt:;
	  fnotice (stderr, "%s:corrupted\n", bbg_file_name);
	  gcov_close ();
	  return 1;
	}
901
    }
902
  gcov_close ();
903

904
  /* We built everything backwards, so nreverse them all.  */
905

906 907 908 909 910 911 912 913 914 915 916 917
  /* Reverse sources. Not strictly necessary, but we'll then process
     them in the 'expected' order.  */
  {
    source_t *src, *src_p, *src_n;

    for (src_p = NULL, src = sources; src; src_p = src, src = src_n)
      {
	src_n = src->next;
	src->next = src_p;
      }
    sources =  src_p;
  }
918

919 920 921
  /* Reverse functions.  */
  {
    function_t *fn, *fn_p, *fn_n;
922

923 924 925
    for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn_n)
      {
	unsigned ix;
926

927 928
	fn_n = fn->next;
	fn->next = fn_p;
929

930
	/* Reverse the arcs.  */
931 932 933
	for (ix = fn->num_blocks; ix--;)
	  {
	    arc_t *arc, *arc_p, *arc_n;
934

935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954
	    for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
		 arc_p = arc, arc = arc_n)
	      {
		arc_n = arc->succ_next;
		arc->succ_next = arc_p;
	      }
	    fn->blocks[ix].succ = arc_p;

	    for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
		 arc_p = arc, arc = arc_n)
	      {
		arc_n = arc->pred_next;
		arc->pred_next = arc_p;
	      }
	    fn->blocks[ix].pred = arc_p;
	  }
      }
    functions = fn_p;
  }
  return 0;
955
}
Doug Evans committed
956

957
/* Reads profiles from the count file and attach to each
958
   function. Return nonzero if fatal error.  */
Doug Evans committed
959

960
static int
961
read_count_file (void)
Doug Evans committed
962
{
963
  unsigned ix;
964
  unsigned version;
965
  unsigned tag;
966
  function_t *fn = NULL;
967
  int error = 0;
968

969
  if (!gcov_open (da_file_name, 1))
Doug Evans committed
970
    {
971 972 973 974
      fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
	       da_file_name);
      no_data_file = 1;
      return 0;
975
    }
976
  if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
977 978 979
    {
      fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
    cleanup:;
980
      gcov_close ();
981 982
      return 1;
    }
983 984
  version = gcov_read_unsigned ();
  if (version != GCOV_VERSION)
985
    {
986 987 988 989
      char v[4], e[4];

      GCOV_UNSIGNED2STRING (v, version);
      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
990
      
991
      fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
992
	       da_file_name, v, e);
Doug Evans committed
993
    }
994 995 996 997 998 999
  tag = gcov_read_unsigned ();
  if (tag != bbg_stamp)
    {
      fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
      goto cleanup;
    }
1000

1001
  while ((tag = gcov_read_unsigned ()))
1002
    {
1003 1004 1005
      unsigned length = gcov_read_unsigned ();
      unsigned long base = gcov_position ();

1006
      if (tag == GCOV_TAG_OBJECT_SUMMARY)
1007
	gcov_read_summary (&object_summary);
1008
      else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1009
	program_count++;
1010
      else if (tag == GCOV_TAG_FUNCTION)
Doug Evans committed
1011
	{
1012
	  unsigned ident = gcov_read_unsigned ();
1013 1014 1015
	  struct function_info *fn_n = functions;

	  for (fn = fn ? fn->next : NULL; ; fn = fn->next)
Doug Evans committed
1016
	    {
1017 1018 1019 1020 1021
	      if (fn)
		;
	      else if ((fn = fn_n))
		fn_n = NULL;
	      else
Doug Evans committed
1022
		{
1023
		  fnotice (stderr, "%s:unknown function '%u'\n",
1024
			   da_file_name, ident);
1025
		  break;
Doug Evans committed
1026
		}
1027
	      if (fn->ident == ident)
1028
		break;
Doug Evans committed
1029
	    }
1030 1031 1032

	  if (!fn)
	    ;
1033
	  else if (gcov_read_unsigned () != fn->checksum)
Doug Evans committed
1034
	    {
1035
	    mismatch:;
1036
	      fnotice (stderr, "%s:profile mismatch for '%s'\n",
1037
		       da_file_name, fn->name);
1038 1039 1040
	      goto cleanup;
	    }
	}
1041
      else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1042
	{
1043
	  if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
1044
	    goto mismatch;
1045

1046
	  if (!fn->counts)
1047
	    fn->counts = XCNEWVEC (gcov_type, fn->num_counts);
1048

1049
	  for (ix = 0; ix != fn->num_counts; ix++)
1050 1051
	    fn->counts[ix] += gcov_read_counter ();
	}
1052
      gcov_sync (base, length);
1053
      if ((error = gcov_is_error ()))
1054 1055 1056 1057 1058
	{
	  fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
		   da_file_name);
	  goto cleanup;
	}
1059
    }
1060

1061
  gcov_close ();
1062
  return 0;
Doug Evans committed
1063 1064
}

1065 1066
/* Solve the flow graph. Propagate counts from the instrumented arcs
   to the blocks and the uninstrumented arcs.  */
Doug Evans committed
1067 1068

static void
1069
solve_flow_graph (function_t *fn)
Doug Evans committed
1070
{
1071 1072 1073
  unsigned ix;
  arc_t *arc;
  gcov_type *count_ptr = fn->counts;
1074
  block_t *blk;
1075 1076
  block_t *valid_blocks = NULL;    /* valid, but unpropagated blocks.  */
  block_t *invalid_blocks = NULL;  /* invalid, but inferable blocks.  */
1077

1078
  if (fn->num_blocks < 2)
1079
    fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
1080 1081
	     bbg_file_name, fn->name);
  else
Doug Evans committed
1082
    {
1083
      if (fn->blocks[0].num_pred)
1084
	fnotice (stderr, "%s:'%s' has arcs to entry block\n",
1085
		 bbg_file_name, fn->name);
Doug Evans committed
1086
      else
1087 1088 1089
	/* We can't deduce the entry block counts from the lack of
	   predecessors.  */
	fn->blocks[0].num_pred = ~(unsigned)0;
1090

1091
      if (fn->blocks[fn->num_blocks - 1].num_succ)
1092
	fnotice (stderr, "%s:'%s' has arcs from exit block\n",
1093 1094 1095 1096 1097
		 bbg_file_name, fn->name);
      else
	/* Likewise, we can't deduce exit block counts from the lack
	   of its successors.  */
	fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0;
Doug Evans committed
1098 1099
    }

1100 1101
  /* Propagate the measured counts, this must be done in the same
     order as the code in profile.c  */
1102
  for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
Doug Evans committed
1103
    {
1104 1105
      block_t const *prev_dst = NULL;
      int out_of_order = 0;
1106
      int non_fake_succ = 0;
1107

1108
      for (arc = blk->succ; arc; arc = arc->succ_next)
Doug Evans committed
1109
	{
1110 1111
	  if (!arc->fake)
	    non_fake_succ++;
1112

1113
	  if (!arc->on_tree)
Doug Evans committed
1114
	    {
1115 1116 1117
	      if (count_ptr)
		arc->count = *count_ptr++;
	      arc->count_valid = 1;
1118
	      blk->num_succ--;
1119
	      arc->dst->num_pred--;
Doug Evans committed
1120
	    }
1121 1122 1123
	  if (prev_dst && prev_dst > arc->dst)
	    out_of_order = 1;
	  prev_dst = arc->dst;
Doug Evans committed
1124
	}
1125 1126 1127 1128 1129 1130 1131 1132 1133
      if (non_fake_succ == 1)
	{
	  /* If there is only one non-fake exit, it is an
	     unconditional branch.  */
	  for (arc = blk->succ; arc; arc = arc->succ_next)
	    if (!arc->fake)
	      {
		arc->is_unconditional = 1;
		/* If this block is instrumenting a call, it might be
1134
		   an artificial block. It is not artificial if it has
1135 1136 1137 1138 1139 1140 1141
		   a non-fallthrough exit, or the destination of this
		   arc has more than one entry.  Mark the destination
		   block as a return site, if none of those conditions
		   hold.  */
		if (blk->is_call_site && arc->fall_through
		    && arc->dst->pred == arc && !arc->pred_next)
		  arc->dst->is_call_return = 1;
1142 1143
	      }
	}
1144

1145 1146 1147
      /* Sort the successor arcs into ascending dst order. profile.c
	 normally produces arcs in the right order, but sometimes with
	 one or two out of order.  We're not using a particularly
1148
	 smart sort.  */
1149
      if (out_of_order)
Doug Evans committed
1150
	{
1151
	  arc_t *start = blk->succ;
1152
	  unsigned changes = 1;
1153

1154 1155 1156
	  while (changes)
	    {
	      arc_t *arc, *arc_p, *arc_n;
1157

1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
	      changes = 0;
	      for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
		{
		  if (arc->dst > arc_n->dst)
		    {
		      changes = 1;
		      if (arc_p)
			arc_p->succ_next = arc_n;
		      else
			start = arc_n;
		      arc->succ_next = arc_n->succ_next;
		      arc_n->succ_next = arc;
		      arc_p = arc_n;
		    }
		  else
		    {
		      arc_p = arc;
		      arc = arc_n;
		    }
		}
	    }
1179
	  blk->succ = start;
Doug Evans committed
1180
	}
1181

1182 1183
      /* Place it on the invalid chain, it will be ignored if that's
	 wrong.  */
1184 1185 1186
      blk->invalid_chain = 1;
      blk->chain = invalid_blocks;
      invalid_blocks = blk;
1187 1188 1189 1190 1191
    }

  while (invalid_blocks || valid_blocks)
    {
      while ((blk = invalid_blocks))
Doug Evans committed
1192
	{
1193 1194
	  gcov_type total = 0;
	  const arc_t *arc;
1195

1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
	  invalid_blocks = blk->chain;
	  blk->invalid_chain = 0;
	  if (!blk->num_succ)
	    for (arc = blk->succ; arc; arc = arc->succ_next)
	      total += arc->count;
	  else if (!blk->num_pred)
	    for (arc = blk->pred; arc; arc = arc->pred_next)
	      total += arc->count;
	  else
	    continue;
1206

1207 1208 1209 1210 1211
	  blk->count = total;
	  blk->count_valid = 1;
	  blk->chain = valid_blocks;
	  blk->valid_chain = 1;
	  valid_blocks = blk;
Doug Evans committed
1212
	}
1213
      while ((blk = valid_blocks))
Doug Evans committed
1214
	{
1215 1216 1217 1218 1219 1220 1221 1222
	  gcov_type total;
	  arc_t *arc, *inv_arc;

	  valid_blocks = blk->chain;
	  blk->valid_chain = 0;
	  if (blk->num_succ == 1)
	    {
	      block_t *dst;
1223

1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
	      total = blk->count;
	      inv_arc = NULL;
	      for (arc = blk->succ; arc; arc = arc->succ_next)
		{
		  total -= arc->count;
		  if (!arc->count_valid)
		    inv_arc = arc;
		}
	      dst = inv_arc->dst;
	      inv_arc->count_valid = 1;
	      inv_arc->count = total;
	      blk->num_succ--;
	      dst->num_pred--;
	      if (dst->count_valid)
		{
		  if (dst->num_pred == 1 && !dst->valid_chain)
		    {
		      dst->chain = valid_blocks;
		      dst->valid_chain = 1;
		      valid_blocks = dst;
		    }
		}
	      else
		{
		  if (!dst->num_pred && !dst->invalid_chain)
		    {
		      dst->chain = invalid_blocks;
		      dst->invalid_chain = 1;
		      invalid_blocks = dst;
		    }
		}
	    }
	  if (blk->num_pred == 1)
	    {
	      block_t *src;
1259

1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291
	      total = blk->count;
	      inv_arc = NULL;
	      for (arc = blk->pred; arc; arc = arc->pred_next)
		{
		  total -= arc->count;
		  if (!arc->count_valid)
		    inv_arc = arc;
		}
	      src = inv_arc->src;
	      inv_arc->count_valid = 1;
	      inv_arc->count = total;
	      blk->num_pred--;
	      src->num_succ--;
	      if (src->count_valid)
		{
		  if (src->num_succ == 1 && !src->valid_chain)
		    {
		      src->chain = valid_blocks;
		      src->valid_chain = 1;
		      valid_blocks = src;
		    }
		}
	      else
		{
		  if (!src->num_succ && !src->invalid_chain)
		    {
		      src->chain = invalid_blocks;
		      src->invalid_chain = 1;
		      invalid_blocks = src;
		    }
		}
	    }
Doug Evans committed
1292 1293
	}
    }
1294

1295 1296 1297 1298 1299
  /* If the graph has been correctly solved, every block will have a
     valid count.  */
  for (ix = 0; ix < fn->num_blocks; ix++)
    if (!fn->blocks[ix].count_valid)
      {
1300
	fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
1301 1302 1303
		 bbg_file_name, fn->name);
	break;
      }
Doug Evans committed
1304
}
1305

Doug Evans committed
1306 1307


1308
/* Increment totals in COVERAGE according to arc ARC.  */
Nathan Sidwell committed
1309 1310

static void
1311
add_branch_counts (coverage_t *coverage, const arc_t *arc)
Nathan Sidwell committed
1312
{
1313
  if (arc->is_call_non_return)
Nathan Sidwell committed
1314
    {
1315 1316 1317
      coverage->calls++;
      if (arc->src->count)
	coverage->calls_executed++;
Nathan Sidwell committed
1318
    }
1319
  else if (!arc->is_unconditional)
Nathan Sidwell committed
1320
    {
1321 1322 1323 1324 1325
      coverage->branches++;
      if (arc->src->count)
	coverage->branches_executed++;
      if (arc->count)
	coverage->branches_taken++;
Doug Evans committed
1326 1327 1328
    }
}

1329 1330 1331 1332 1333 1334 1335
/* Format a HOST_WIDE_INT as either a percent ratio, or absolute
   count.  If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
   If DP is zero, no decimal point is printed. Only print 100% when
   TOP==BOTTOM and only print 0% when TOP=0.  If dp < 0, then simply
   format TOP.  Return pointer to a static string.  */

static char const *
1336
format_gcov (gcov_type top, gcov_type bottom, int dp)
1337 1338
{
  static char buffer[20];
1339

1340 1341 1342 1343 1344 1345
  if (dp >= 0)
    {
      float ratio = bottom ? (float)top / bottom : 0;
      int ix;
      unsigned limit = 100;
      unsigned percent;
1346

1347 1348
      for (ix = dp; ix--; )
	limit *= 10;
1349

1350 1351
      percent = (unsigned) (ratio * limit + (float)0.5);
      if (percent <= 0 && top)
1352
	percent = 1;
1353
      else if (percent >= limit && top != bottom)
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368
	percent = limit - 1;
      ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
      if (dp)
	{
	  dp++;
	  do
	    {
	      buffer[ix+1] = buffer[ix];
	      ix--;
	    }
	  while (dp--);
	  buffer[ix + 1] = '.';
	}
    }
  else
1369
    sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
1370

1371 1372 1373 1374
  return buffer;
}


Doug Evans committed
1375 1376 1377
/* Output summary info for a function.  */

static void
1378
function_summary (const coverage_t *coverage, const char *title)
Doug Evans committed
1379
{
1380
  fnotice (stdout, "%s '%s'\n", title, coverage->name);
1381 1382 1383 1384 1385

  if (coverage->lines)
    fnotice (stdout, "Lines executed:%s of %d\n",
	     format_gcov (coverage->lines_executed, coverage->lines, 2),
	     coverage->lines);
Doug Evans committed
1386
  else
1387
    fnotice (stdout, "No executable lines\n");
Doug Evans committed
1388

1389
  if (flag_branches)
Doug Evans committed
1390
    {
1391
      if (coverage->branches)
Doug Evans committed
1392
	{
1393 1394 1395 1396 1397 1398 1399 1400
	  fnotice (stdout, "Branches executed:%s of %d\n",
		   format_gcov (coverage->branches_executed,
				coverage->branches, 2),
		   coverage->branches);
	  fnotice (stdout, "Taken at least once:%s of %d\n",
		   format_gcov (coverage->branches_taken,
				coverage->branches, 2),
		   coverage->branches);
Doug Evans committed
1401 1402
	}
      else
1403 1404 1405 1406 1407
	fnotice (stdout, "No branches\n");
      if (coverage->calls)
	fnotice (stdout, "Calls executed:%s of %d\n",
		 format_gcov (coverage->calls_executed, coverage->calls, 2),
		 coverage->calls);
Doug Evans committed
1408
      else
1409
	fnotice (stdout, "No calls\n");
Nathan Sidwell committed
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
    }
}

/* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
   affect name generation. With preserve_paths we create a filename
   from all path components of the source file, replacing '/' with
   '#', without it we simply take the basename component. With
   long_output_names we prepend the processed name of the input file
   to each output name (except when the current source file is the
   input file, so you don't get a double concatenation). The two
   components are separated by '##'. Also '.' filename components are
1421
   removed and '..'  components are renamed to '^'.  */
Nathan Sidwell committed
1422 1423

static char *
1424
make_gcov_file_name (const char *input_name, const char *src_name)
Nathan Sidwell committed
1425 1426
{
  char *cptr;
1427
  char *name = XNEWVEC (char, strlen (src_name) + strlen (input_name) + 10);
1428

Nathan Sidwell committed
1429
  name[0] = 0;
1430
  if (flag_long_names && strcmp (src_name, input_name))
Nathan Sidwell committed
1431 1432
    {
      /* Generate the input filename part.  */
1433 1434
      cptr = flag_preserve_paths ? NULL : strrchr (input_name, '/');
      strcat (name, cptr ? cptr + 1 : input_name);
Nathan Sidwell committed
1435 1436
      strcat (name, "##");
    }
1437

1438
  /* Generate the source filename part.  */
1439 1440
  cptr = flag_preserve_paths ? NULL : strrchr (src_name, '/');
  strcat (name, cptr ? cptr + 1 : src_name);
1441

1442
  if (flag_preserve_paths)
Nathan Sidwell committed
1443 1444 1445
    {
      /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
      char *prev;
1446

Nathan Sidwell committed
1447
      for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
	{
	  unsigned shift = 0;

	  if (prev + 1 == cptr && prev[0] == '.')
	    {
	      /* Remove '.' */
	      shift = 2;
	    }
	  else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
	    {
	      /* Convert '..' */
	      shift = 1;
	      prev[1] = '^';
	    }
	  else
	    *cptr++ = '#';
	  if (shift)
	    {
	      cptr = prev;
	      do
		prev[0] = prev[shift];
Nathan Sidwell committed
1469
	      while (*prev++);
1470 1471
	    }
	}
Doug Evans committed
1472
    }
1473

Nathan Sidwell committed
1474 1475
  strcat (name, ".gcov");
  return name;
Doug Evans committed
1476 1477
}

1478
/* Scan through the bb_data for each line in the block, increment
Nathan Sidwell committed
1479 1480
   the line number execution count indicated by the execution count of
   the appropriate basic block.  */
Doug Evans committed
1481 1482

static void
1483
add_line_counts (coverage_t *coverage, function_t *fn)
Doug Evans committed
1484
{
1485
  unsigned ix;
1486
  line_t *line = NULL; /* This is propagated from one iteration to the
1487 1488
			  next.  */

1489
  /* Scan each basic block.  */
1490
  for (ix = 0; ix != fn->num_blocks; ix++)
Doug Evans committed
1491
    {
1492
      block_t *block = &fn->blocks[ix];
1493 1494 1495 1496
      unsigned *encoding;
      const source_t *src = NULL;
      unsigned jx;

1497 1498 1499 1500
      if (block->count && ix && ix + 1 != fn->num_blocks)
	fn->blocks_executed++;
      for (jx = 0, encoding = block->u.line.encoding;
	   jx != block->u.line.num; jx++, encoding++)
1501 1502 1503
	if (!*encoding)
	  {
	    unsigned src_n = *++encoding;
Doug Evans committed
1504

1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516
	    for (src = sources; src->index != src_n; src = src->next)
	      continue;
	    jx++;
	  }
	else
	  {
	    line = &src->lines[*encoding];

	    if (coverage)
	      {
		if (!line->exists)
		  coverage->lines++;
1517
		if (!line->count && block->count)
1518 1519 1520 1521 1522
		  coverage->lines_executed++;
	      }
	    line->exists = 1;
	    line->count += block->count;
	  }
1523
      free (block->u.line.encoding);
1524 1525
      block->u.cycle.arc = NULL;
      block->u.cycle.ident = ~0U;
1526

1527 1528 1529
      if (!ix || ix + 1 == fn->num_blocks)
	/* Entry or exit block */;
      else if (flag_all_blocks)
Doug Evans committed
1530
	{
1531
	  line_t *block_line = line ? line : &fn->src->lines[fn->line];
1532

1533 1534
	  block->chain = block_line->u.blocks;
	  block_line->u.blocks = block;
1535 1536 1537 1538 1539
	}
      else if (flag_branches)
	{
	  arc_t *arc;

1540
	  for (arc = block->succ; arc; arc = arc->succ_next)
Doug Evans committed
1541
	    {
1542 1543 1544
	      arc->line_next = line->u.branches;
	      line->u.branches = arc;
	      if (coverage && !arc->is_unconditional)
1545
		add_branch_counts (coverage, arc);
Doug Evans committed
1546
	    }
Nathan Sidwell committed
1547 1548
	}
    }
1549
  if (!line)
1550
    fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
1551 1552
}

1553
/* Accumulate the line counts of a file.  */
1554 1555

static void
1556
accumulate_line_counts (source_t *src)
1557 1558
{
  line_t *line;
1559
  function_t *fn, *fn_p, *fn_n;
1560
  unsigned ix;
1561 1562 1563 1564 1565 1566 1567 1568 1569

  /* Reverse the function order.  */
  for (fn = src->functions, fn_p = NULL; fn;
       fn_p = fn, fn = fn_n)
    {
      fn_n = fn->line_next;
      fn->line_next = fn_p;
    }
  src->functions = fn_p;
1570

1571
  for (ix = src->num_lines, line = src->lines; ix--; line++)
Nathan Sidwell committed
1572
    {
1573
      if (!flag_all_blocks)
Nathan Sidwell committed
1574
	{
1575
	  arc_t *arc, *arc_p, *arc_n;
1576

1577 1578 1579 1580 1581 1582
	  /* Total and reverse the branch information.  */
	  for (arc = line->u.branches, arc_p = NULL; arc;
	       arc_p = arc, arc = arc_n)
	    {
	      arc_n = arc->line_next;
	      arc->line_next = arc_p;
1583

1584 1585 1586
	      add_branch_counts (&src->coverage, arc);
	    }
	  line->u.branches = arc_p;
Nathan Sidwell committed
1587
	}
1588 1589 1590 1591 1592
      else if (line->u.blocks)
	{
	  /* The user expects the line count to be the number of times
	     a line has been executed. Simply summing the block count
	     will give an artificially high number.  The Right Thing
1593 1594 1595
	     is to sum the entry counts to the graph of blocks on this
	     line, then find the elementary cycles of the local graph
	     and add the transition counts of those cycles.  */
1596 1597
	  block_t *block, *block_p, *block_n;
	  gcov_type count = 0;
1598

1599
	  /* Reverse the block information.  */
1600 1601 1602 1603 1604
	  for (block = line->u.blocks, block_p = NULL; block;
	       block_p = block, block = block_n)
	    {
	      block_n = block->chain;
	      block->chain = block_p;
1605
	      block->u.cycle.ident = ix;
1606 1607
	    }
	  line->u.blocks = block_p;
1608

1609 1610 1611 1612
	  /* Sum the entry arcs.  */
	  for (block = line->u.blocks; block; block = block->chain)
	    {
	      arc_t *arc;
Doug Evans committed
1613

1614 1615 1616 1617 1618 1619 1620
	      for (arc = block->pred; arc; arc = arc->pred_next)
		{
		  if (arc->src->u.cycle.ident != ix)
		    count += arc->count;
		  if (flag_branches)
		    add_branch_counts (&src->coverage, arc);
		}
1621 1622 1623 1624

	      /* Initialize the cs_count.  */
	      for (arc = block->succ; arc; arc = arc->succ_next)
		arc->cs_count = arc->count;
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
	    }

	  /* Find the loops. This uses the algorithm described in
	     Tiernan 'An Efficient Search Algorithm to Find the
	     Elementary Circuits of a Graph', CACM Dec 1970. We hold
	     the P array by having each block point to the arc that
	     connects to the previous block. The H array is implicitly
	     held because of the arc ordering, and the block's
	     previous arc pointer.

	     Although the algorithm is O(N^3) for highly connected
	     graphs, at worst we'll have O(N^2), as most blocks have
	     only one or two exits. Most graphs will be small.

	     For each loop we find, locate the arc with the smallest
	     transition count, and add that to the cumulative
1641 1642
	     count.  Decrease flow over the cycle and remove the arc
	     from consideration.  */
1643
	  for (block = line->u.blocks; block; block = block->chain)
1644
	    {
1645 1646
	      block_t *head = block;
	      arc_t *arc;
1647

1648 1649 1650 1651
	    next_vertex:;
	      arc = head->succ;
	    current_vertex:;
	      while (arc)
1652
		{
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663
		  block_t *dst = arc->dst;
		  if (/* Already used that arc.  */
		      arc->cycle
		      /* Not to same graph, or before first vertex.  */
		      || dst->u.cycle.ident != ix
		      /* Already in path.  */
		      || dst->u.cycle.arc)
		    {
		      arc = arc->succ_next;
		      continue;
		    }
1664

1665
		  if (dst == block)
1666
		    {
1667
		      /* Found a closing arc.  */
1668
		      gcov_type cycle_count = arc->cs_count;
1669 1670
		      arc_t *cycle_arc = arc;
		      arc_t *probe_arc;
1671

1672
		      /* Locate the smallest arc count of the loop.  */
1673 1674
		      for (dst = head; (probe_arc = dst->u.cycle.arc);
			   dst = probe_arc->src)
1675
			if (cycle_count > probe_arc->cs_count)
1676
			  {
1677
			    cycle_count = probe_arc->cs_count;
1678 1679
			    cycle_arc = probe_arc;
			  }
1680

1681 1682
		      count += cycle_count;
		      cycle_arc->cycle = 1;
1683 1684 1685 1686 1687 1688 1689

		      /* Remove the flow from the cycle.  */
		      arc->cs_count -= cycle_count;
		      for (dst = head; (probe_arc = dst->u.cycle.arc);
			   dst = probe_arc->src)
			probe_arc->cs_count -= cycle_count;

1690 1691
		      /* Unwind to the cyclic arc.  */
		      while (head != cycle_arc->src)
1692
			{
1693
			  arc = head->u.cycle.arc;
1694
			  head->u.cycle.arc = NULL;
1695
			  head = arc->src;
1696
			}
1697 1698 1699
		      /* Move on.  */
		      arc = arc->succ_next;
		      continue;
1700
		    }
1701

1702 1703 1704 1705
		  /* Add new block to chain.  */
		  dst->u.cycle.arc = arc;
		  head = dst;
		  goto next_vertex;
1706
		}
1707 1708 1709 1710
	      /* We could not add another vertex to the path. Remove
		 the last vertex from the list.  */
	      arc = head->u.cycle.arc;
	      if (arc)
1711
		{
1712
		  /* It was not the first vertex. Move onto next arc.  */
1713 1714 1715 1716
		  head->u.cycle.arc = NULL;
		  head = arc->src;
		  arc = arc->succ_next;
		  goto current_vertex;
1717
		}
1718 1719
	      /* Mark this block as unusable.  */
	      block->u.cycle.ident = ~0U;
1720
	    }
1721

1722 1723
	  line->count = count;
	}
1724

1725
      if (line->exists)
Nathan Sidwell committed
1726
	{
1727 1728 1729
	  src->coverage.lines++;
	  if (line->count)
	    src->coverage.lines_executed++;
Nathan Sidwell committed
1730 1731 1732
	}
    }
}
Doug Evans committed
1733

1734
/* Output information about ARC number IX.  Returns nonzero if
1735 1736 1737
   anything is output.  */

static int
1738
output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
1739
{
1740

1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760
  if (arc->is_call_non_return)
    {
      if (arc->src->count)
	{
	  fnotice (gcov_file, "call   %2d returned %s\n", ix,
		   format_gcov (arc->src->count - arc->count,
				arc->src->count, -flag_counts));
	}
      else
	fnotice (gcov_file, "call   %2d never executed\n", ix);
    }
  else if (!arc->is_unconditional)
    {
      if (arc->src->count)
	fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
		 format_gcov (arc->count, arc->src->count, -flag_counts),
		 arc->fall_through ? " (fallthrough)" : "");
      else
	fnotice (gcov_file, "branch %2d never executed\n", ix);
    }
1761
  else if (flag_unconditional && !arc->dst->is_call_return)
1762 1763 1764 1765 1766 1767 1768 1769 1770 1771
    {
      if (arc->src->count)
	fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
		 format_gcov (arc->count, arc->src->count, -flag_counts));
      else
	fnotice (gcov_file, "unconditional %2d never executed\n", ix);
    }
  else
    return 0;
  return 1;
1772

1773 1774
}

Nathan Sidwell committed
1775 1776 1777
/* Read in the source file one line at a time, and output that line to
   the gcov file preceded by its execution count and other
   information.  */
Doug Evans committed
1778

Nathan Sidwell committed
1779
static void
1780
output_lines (FILE *gcov_file, const source_t *src)
Nathan Sidwell committed
1781 1782
{
  FILE *source_file;
1783
  unsigned line_num;	/* current line number.  */
1784 1785 1786
  const line_t *line;           /* current line info ptr.  */
  char string[STRING_SIZE];     /* line buffer.  */
  char const *retval = "";	/* status of source file reading.  */
1787
  function_t *fn = NULL;
1788 1789 1790

  fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
  fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
1791 1792
  fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
	   no_data_file ? "-" : da_file_name);
1793 1794
  fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
	   object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
1795
  fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
1796

1797
  source_file = fopen (src->name, "r");
Nathan Sidwell committed
1798 1799
  if (!source_file)
    {
1800
      fnotice (stderr, "%s:cannot open source file\n", src->name);
Nathan Sidwell committed
1801 1802 1803 1804 1805
      retval = NULL;
    }
  else
    {
      struct stat status;
1806

Nathan Sidwell committed
1807
      if (!fstat (fileno (source_file), &status)
1808
	  && status.st_mtime > bbg_file_time)
Nathan Sidwell committed
1809
	{
1810
	  fnotice (stderr, "%s:source file is newer than graph file '%s'\n",
1811 1812
		   src->name, bbg_file_name);
	  fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n",
Nathan Sidwell committed
1813 1814 1815 1816
		   "-", 0);
	}
    }

1817 1818 1819
  if (flag_branches)
    fn = src->functions;

1820 1821
  for (line_num = 1, line = &src->lines[line_num];
       line_num < src->num_lines; line_num++, line++)
Nathan Sidwell committed
1822
    {
1823 1824 1825 1826
      for (; fn && fn->line == line_num; fn = fn->line_next)
	{
	  arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
	  gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
1827
	  
1828 1829 1830
	  for (; arc; arc = arc->pred_next)
	    if (arc->fake)
	      return_count -= arc->count;
1831
	  
1832 1833 1834 1835 1836 1837 1838 1839 1840
	  fprintf (gcov_file, "function %s", fn->name);
	  fprintf (gcov_file, " called %s",
		   format_gcov (fn->blocks[0].count, 0, -1));
	  fprintf (gcov_file, " returned %s",
		   format_gcov (return_count, fn->blocks[0].count, 0));
	  fprintf (gcov_file, " blocks executed %s",
		   format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
	  fprintf (gcov_file, "\n");
	}
1841

Nathan Sidwell committed
1842
      /* For lines which don't exist in the .bb file, print '-' before
1843 1844 1845 1846 1847
	 the source line.  For lines which exist but were never
	 executed, print '#####' before the source line.  Otherwise,
	 print the execution count before the source line.  There are
	 16 spaces of indentation added before the source line so that
	 tabs won't be messed up.  */
1848 1849 1850
      fprintf (gcov_file, "%9s:%5u:",
	       !line->exists ? "-" : !line->count ? "#####"
	       : format_gcov (line->count, 0, -1), line_num);
1851

Nathan Sidwell committed
1852 1853 1854 1855 1856 1857 1858
      if (retval)
	{
	  /* Copy source line.  */
	  do
	    {
	      retval = fgets (string, STRING_SIZE, source_file);
	      if (!retval)
1859
		break;
Nathan Sidwell committed
1860
	      fputs (retval, gcov_file);
1861
	    }
Nathan Sidwell committed
1862 1863 1864
	  while (!retval[0] || retval[strlen (retval) - 1] != '\n');
	}
      if (!retval)
1865
	fputs ("/*EOF*/\n", gcov_file);
1866 1867

      if (flag_all_blocks)
Nathan Sidwell committed
1868
	{
1869
	  block_t *block;
1870
	  arc_t *arc;
1871
	  int ix, jx;
1872

1873 1874
	  for (ix = jx = 0, block = line->u.blocks; block;
	       block = block->chain)
1875
	    {
1876
	      if (!block->is_call_return)
1877 1878
		fprintf (gcov_file, "%9s:%5u-block %2d\n",
			 !line->exists ? "-" : !block->count ? "$$$$$"
1879 1880
			 : format_gcov (block->count, 0, -1),
			 line_num, ix++);
1881 1882 1883
	      if (flag_branches)
		for (arc = block->succ; arc; arc = arc->succ_next)
		  jx += output_branch_count (gcov_file, jx, arc);
Doug Evans committed
1884
	    }
Nathan Sidwell committed
1885
	}
1886 1887 1888 1889
      else if (flag_branches)
	{
	  int ix;
	  arc_t *arc;
1890

1891 1892 1893
	  for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
	    ix += output_branch_count (gcov_file, ix, arc);
	}
Nathan Sidwell committed
1894
    }
1895

Nathan Sidwell committed
1896 1897 1898 1899 1900 1901
  /* Handle all remaining source lines.  There may be lines after the
     last line of code.  */
  if (retval)
    {
      for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
	{
1902
	  fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval);
1903

Nathan Sidwell committed
1904
	  while (!retval[0] || retval[strlen (retval) - 1] != '\n')
1905
	    {
Nathan Sidwell committed
1906 1907 1908 1909
	      retval = fgets (string, STRING_SIZE, source_file);
	      if (!retval)
		break;
	      fputs (retval, gcov_file);
1910
	    }
Nathan Sidwell committed
1911 1912
	}
    }
1913

Nathan Sidwell committed
1914 1915 1916
  if (source_file)
    fclose (source_file);
}