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 }
View Code

 

你可能感兴趣的:(GC)