zoukankan      html  css  js  c++  java
  • 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
    
    ");
     389   fnotice (file, "Print code coverage information.
    
    ");
     390   fnotice (file, "  -h, --help                      Print this help, then exit
    ");
     391   fnotice (file, "  -v, --version                   Print version number, then exit
    ");
     392   fnotice (file, "  -a, --all-blocks                Show information for every basic block
    ");
     393   fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output
    ");
     394   fnotice (file, "  -c, --branch-counts             Given counts of branches taken
    
     395                                     rather than percentages
    ");
     396   fnotice (file, "  -n, --no-output                 Do not create an output file
    ");
     397   fnotice (file, "  -l, --long-file-names           Use long output file names for included
    
     398                                     source files
    ");
     399   fnotice (file, "  -f, --function-summaries        Output summaries for each function
    ");
     400   fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE
    ");
     401   fnotice (file, "  -p, --preserve-paths            Preserve all pathname components
    ");
     402   fnotice (file, "  -u, --unconditional-branches    Show unconditional branch counts too
    ");
     403   fnotice (file, "
    For bug reporting instructions, please see:
    %s.
    ",
     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
    ", version_string);
     414   fprintf (stdout, "Copyright %s 2004 Free Software Foundation, Inc.
    ",
     415        _("(C)"));
     416   fnotice (stdout,
     417        _("This is free software; see the source for copying conditions.
    "
     418          "There is NO warranty; not even for MERCHANTABILITY or 
    "
     419          "FITNESS FOR A PARTICULAR PURPOSE.
    
    "));
     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
    ", 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, "
    ");
     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'
    ",
     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'
    ",
     548                  src->name, gcov_file_name);
     549           fclose (gcov_file);
     550         }
     551       else
     552         fnotice (stderr, "%s:could not open output file '%s'
    ",
     553              src->name, gcov_file_name);
     554       free (gcov_file_name);
     555     }
     556       fnotice (stdout, "
    ");
     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
    ", 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
    ", 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'
    ",
     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'
    ",
     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
    ", 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
    ", 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
    ", 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'
    ",
     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
    ", 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'
    ",
    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'
    ",
    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
    " : "%s:corrupted
    ",
    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
    ",
    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
    ",
    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
    ",
    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'
    ",
    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'
    ", title, coverage->name);
    1374 
    1375   if (coverage->lines)
    1376     fnotice (stdout, "Lines executed:%s of %d
    ",
    1377          format_gcov (coverage->lines_executed, coverage->lines, 2),
    1378          coverage->lines);
    1379   else
    1380     fnotice (stdout, "No executable lines
    ");
    1381 
    1382   if (flag_branches)
    1383     {
    1384       if (coverage->branches)
    1385     {
    1386       fnotice (stdout, "Branches executed:%s of %d
    ",
    1387            format_gcov (coverage->branches_executed,
    1388                 coverage->branches, 2),
    1389            coverage->branches);
    1390       fnotice (stdout, "Taken at least once:%s of %d
    ",
    1391            format_gcov (coverage->branches_taken,
    1392                 coverage->branches, 2),
    1393            coverage->branches);
    1394     }
    1395       else
    1396     fnotice (stdout, "No branches
    ");
    1397       if (coverage->calls)
    1398     fnotice (stdout, "Calls executed:%s of %d
    ",
    1399          format_gcov (coverage->calls_executed, coverage->calls, 2),
    1400          coverage->calls);
    1401       else
    1402     fnotice (stdout, "No calls
    ");
    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'
    ", 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
    ", 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
    ", ix);
    1744     }
    1745   else if (!arc->is_unconditional)
    1746     {
    1747       if (arc->src->count)
    1748     fnotice (gcov_file, "branch %2d taken %s%s
    ", 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
    ", 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
    ", ix,
    1758          format_gcov (arc->count, arc->src->count, -flag_counts));
    1759       else
    1760     fnotice (gcov_file, "unconditional %2d never executed
    ", 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
    ", "-", 0, src->name);
    1783   fprintf (gcov_file, "%9s:%5d:Graph:%s
    ", "-", 0, bbg_file_name);
    1784   fprintf (gcov_file, "%9s:%5d:Data:%s
    ", "-", 0, da_file_name);
    1785   fprintf (gcov_file, "%9s:%5d:Runs:%u
    ", "-", 0,
    1786        object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
    1787   fprintf (gcov_file, "%9s:%5d:Programs:%u
    ", "-", 0, program_count);
    1788 
    1789   source_file = fopen (src->name, "r");
    1790   if (!source_file)
    1791     {
    1792       fnotice (stderr, "%s:cannot open source file
    ", 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'
    ",
    1803            src->name, bbg_file_name);
    1804       fprintf (gcov_file, "%9s:%5d:Source is newer than graph
    ",
    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, "
    ");
    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] != '
    ');
    1855     }
    1856       if (!retval)
    1857     fputs ("/*EOF*/
    ", 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
    ",
    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] != '
    ')
    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
  • 相关阅读:
    PHP自学2——将用户提交表单存储到外部普通文件中
    PHP自学1——简单表单提交
    自学php的几个例子(包含AMP(Apache、MySQL、PHP)环境搭建链接)
    自学SQL语言的例子(使用MySQL实现)
    自学XML DOM的几个例子
    学习DTD和Schema的几个例子
    自学Xpath的几个例子
    自学XSL的几个例子
    java数据库连接池的介绍与定义一个简单的连接池
    Jquery Ajax 复杂json对象提交到WebService
  • 原文地址:https://www.cnblogs.com/kernel0815/p/4349879.html
Copyright © 2011-2022 走看看