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 <nathan@codesourcery.com>
   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 }
View Code

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值