gcov源码,供学习使用。

摘自http://www.opensource.apple.com/source/gcc/gcc-5484/gcc/gcov.c

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

时间: 2024-10-29 10:59:03

gcov源码,供学习使用。的相关文章

跟大家聊聊我们为什么要学习源码?学习源码对我们有用吗?(源码感悟)

1 前言 由于现在微服务很流行,越来越多企业采用了SpringCloud微服务架构,而SpringBoot则是快速构建微服务项目的利器.于是源码笔记以此为切入点,将SpringBoot作为我们源码分析的第一个开源项目,之后还会对更多开源项目进行源码分析.要进行源码分析,笔者结合自身经历来跟大家聊聊我们为什么要学习源码这个话题,大家一起探讨学习. 我们程序员在开发代码时每天都在使用别人写好的框架,无论你是在使用Spring生态的Spring核心,SpringMVC,SpringBoot和Sprin

从源码中学习设计模式系列——单例模式序/反序列化以及反射攻击的问题(二)

一.前言 这篇文章是学习单例模式的第二篇,之前的文章一下子就给出来看起来很高大上的实现方法,但是这种模式还是存在漏洞的,具体有什么问题,大家可以停顿一会儿,思考一下.好了,不卖关子了,下面我们来看看每种单例模式存在的问题以及解决办法. 二.每种Singleton 模式的演进 模式一 public class LazySingleton { private static LazySingleton lazySingleton = null; private LazySingleton() { }

Java小白集合源码的学习系列:Vector

目录 Vector源码学习 Vector继承体系 Vector核心源码 基本属性 构造器 扩容机制 Enumeration 概述 源码描述 具体操作 Vector总结 Vector源码学习 前文传送门: Java小白集合源码的学习系列:LinkedList Java小白集合源码的学习系列:ArrayList Vector是JDK1.0中的集合,是集合中的老大哥,其中大部分的方法都被synchronized关键字所修饰,与ArrayList和LinkedList不同,它是线程安全的(关于线程安全,

我们一起学习WCF 第一篇初识WCF(附源码供对照学习)

前言:去年由于工作需要我学习了wcf的相关知识,初期对wcf的作用以及为何用怎么样都是一知半解,也许现在也不是非常的清晰.但是通过项目对wcf的运用在脑海里面也算有了初步的模型.今天我就把我从开始wcf所遇到的困难以及解决方案一点点记下来,可能还有很多不足之处那我们一起共同学习.在学习之前我们有必要初步的看下百度百科对wcf的解释,让我们心中有这一个概念,然后建立项目,然后再次看概念,然后在去更深层的建立项目,然后再去理解这样反复的去做我相信可以做好wcf.那么下面我就会从初识wcf,wcf消息

Android开发者学习必备:10个优质的源码供大家学习

最近看了一些开发的东西,汇总了一些源码.希望可以给大家有些帮助! 1.Android 源码解析—PagerSlidingTabStrippagerSlidingTabStrip 实现联动效果的原理是,它引用了 ViewPager 的OnPageChangeListener. 但是 viewpager 注册的 listener 不是自身的OnPageChangeListener,而是 pagerSlidingTabStrip 内部类PageListener. 通过PageListener实现对对

java集合 源码解析 学习手册

学习路线: http://www.cnblogs.com/skywang12345/ 总结 1 总体框架 2 Collection架构 3 ArrayList详细介绍(源码解析)和使用示例 4 fail-fast总结(通过ArrayList来说明fail-fast的原理.解决办法) 5 LinkedList详细介绍(源码解析)和使用示例 6 Vector详细介绍(源码解析)和使用示例 7 Stack详细介绍(源码解析)和使用示例 8 List总结(LinkedList, ArrayList等使用

国内主流源码类学习网站

转   留着到时候看看 哪些可以用 1.365源码之家 (http://www.365code.com) 365源码之家始建于2004年9月,是一个专门针对各大小网站提供技术及资源服务的网站,我们所 拥有的服务包括源码下载,书籍下载,技术文章 ,网站运营.管理资料,业内最新动态等栏目,提供 全方便从学技术. 2.积木网 (http://www.gimoo.net/) 学习编程技术从积木网(gimoo.net)开始,积木网建站与2006年,提供PHP.asp.net.js.jquery.ruby.

jquery 源码结构学习

最近想要了解一下jquery 库是怎样实现的,源码结构如何.通过查看资料知道了,jquery源码整体结构如下所示,平时用到的例如$.ajax()形式的方法主要是通过jq.extend({})中定义的方法属性得到的,形如$("div").css()方法是通过jq.fn.extend({})拓展得到. (function(window,undefined){ var jq = function(selector,content){ return new jq.fn.init(selecto

Java小白集合源码的学习系列:ArrayList

目录 ArrayList源码学习 ArrayList的继承体系 ArrayList核心源码 ArrayList扩容机制 最后的总结 ArrayList源码学习 本文基于JDK1.8版本,对集合中的巨头ArrayList做一定的源码学习,将会参考大量资料,在文章后面都将会给出参考文章链接,本文用以巩固学习知识. ArrayList的继承体系 ArrayList继承了AbstracList这个抽象类,还实现了List接口,提供了添加.删除.修改.遍历等功能.至于其他接口,以后再做总结. ArrayL

【NopCommerce源码架构学习-二】单例模式实现代码分析

单例模式是是常用经典十几种设计模式中最简单的..NET中单例模式的实现也有很多种方式.下面我来介绍一下NopCommerce中单例模式实现. 我之前的文章就分析了一下nop中EngineContext的实现.EngineContext是把一个Web请求用Nop的EngineContext引擎上下文封装.里面提供了一个IEngine的单例对象的访问方式. 下面就是EngineContext的源码: 一.EngineContext 1 using System.Configuration; 2 3