LCOV - code coverage report
Current view: top level - gcc - gcov.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 78.8 % 1992 1569
Test Date: 2026-08-22 16:33:35 Functions: 93.8 % 81 76
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Gcov.c: prepend line execution counts and branch probabilities to a
       2              :    source file.
       3              :    Copyright (C) 1990-2026 Free Software Foundation, Inc.
       4              :    Contributed by James E. Wilson of Cygnus Support.
       5              :    Mangled by Bob Manson of Cygnus Support.
       6              :    Mangled further by Nathan Sidwell <nathan@codesourcery.com>
       7              : 
       8              : Gcov is free software; you can redistribute it and/or modify
       9              : it under the terms of the GNU General Public License as published by
      10              : the Free Software Foundation; either version 3, or (at your option)
      11              : any later version.
      12              : 
      13              : Gcov is distributed in the hope that it will be useful,
      14              : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16              : GNU General Public License for more details.
      17              : 
      18              : You should have received a copy of the GNU General Public License
      19              : along with Gcov; see the file COPYING3.  If not see
      20              : <http://www.gnu.org/licenses/>.  */
      21              : 
      22              : /* ??? Print a list of the ten blocks with the highest execution counts,
      23              :    and list the line numbers corresponding to those blocks.  Also, perhaps
      24              :    list the line numbers with the highest execution counts, only printing
      25              :    the first if there are several which are all listed in the same block.  */
      26              : 
      27              : /* ??? Should have an option to print the number of basic blocks, and the
      28              :    percent of them that are covered.  */
      29              : 
      30              : /* Need an option to show individual block counts, and show
      31              :    probabilities of fall through arcs.  */
      32              : 
      33              : #include "config.h"
      34              : #define INCLUDE_ALGORITHM
      35              : #define INCLUDE_VECTOR
      36              : #define INCLUDE_STRING
      37              : #define INCLUDE_MAP
      38              : #define INCLUDE_SET
      39              : #include "system.h"
      40              : #include "coretypes.h"
      41              : #include "tm.h"
      42              : #include "intl.h"
      43              : #include "diagnostic.h"
      44              : #include "version.h"
      45              : #include "demangle.h"
      46              : #include "color-macros.h"
      47              : #include "pretty-print.h"
      48              : #include "json.h"
      49              : #include "hwint.h"
      50              : #include "xregex.h"
      51              : #include "graphds.h"
      52              : 
      53              : #include <zlib.h>
      54              : #include <getopt.h>
      55              : 
      56              : #include "md5.h"
      57              : 
      58              : using namespace std;
      59              : 
      60              : #define IN_GCOV 1
      61              : #include "gcov-io.h"
      62              : #include "gcov-io.cc"
      63              : 
      64              : #define GCOV_JSON_FORMAT_VERSION "2"
      65              : 
      66              : /* The gcno file is generated by -ftest-coverage option. The gcda file is
      67              :    generated by a program compiled with -fprofile-arcs. Their formats
      68              :    are documented in gcov-io.h.  */
      69              : 
      70              : /* The functions in this file for creating and solution program flow graphs
      71              :    are very similar to functions in the gcc source file profile.cc.  In
      72              :    some places we make use of the knowledge of how profile.cc works to
      73              :    select particular algorithms here.  */
      74              : 
      75              : /* The code validates that the profile information read in corresponds
      76              :    to the code currently being compiled.  Rather than checking for
      77              :    identical files, the code below compares a checksum on the CFG
      78              :    (based on the order of basic blocks and the arcs in the CFG).  If
      79              :    the CFG checksum in the gcda file match the CFG checksum in the
      80              :    gcno file, the profile data will be used.  */
      81              : 
      82              : /* This is the size of the buffer used to read in source file lines.  */
      83              : 
      84              : class function_info;
      85              : class block_info;
      86              : class source_info;
      87              : class condition_info;
      88              : class path_info;
      89              : 
      90              : /* Describes an arc between two basic blocks.  */
      91              : 
      92              : struct arc_info
      93              : {
      94              :   /* source and destination blocks.  */
      95              :   class block_info *src;
      96              :   class block_info *dst;
      97              : 
      98              :   /* transition counts.  */
      99              :   gcov_type count;
     100              :   /* used in cycle search, so that we do not clobber original counts.  */
     101              :   gcov_type cs_count;
     102              : 
     103              :   unsigned int count_valid : 1;
     104              :   unsigned int on_tree : 1;
     105              :   unsigned int fake : 1;
     106              :   unsigned int fall_through : 1;
     107              : 
     108              :   /* Arc to a catch handler.  */
     109              :   unsigned int is_throw : 1;
     110              : 
     111              :   /* Arc is for a function that abnormally returns.  */
     112              :   unsigned int is_call_non_return : 1;
     113              : 
     114              :   /* Arc is for catch/setjmp.  */
     115              :   unsigned int is_nonlocal_return : 1;
     116              : 
     117              :   /* Is an unconditional branch.  */
     118              :   unsigned int is_unconditional : 1;
     119              : 
     120              :   /* Loop making arc.  */
     121              :   unsigned int cycle : 1;
     122              : 
     123              :   /* Is a true arc.  */
     124              :   unsigned int true_value : 1;
     125              : 
     126              :   /* Is a false arc.  */
     127              :   unsigned int false_value : 1;
     128              : 
     129              :   /* Is suppressed arc by #pragma GCC suppress_coverage.  */
     130              :   unsigned int suppressed : 1;
     131              : 
     132              :   /* Links to next arc on src and dst lists.  */
     133              :   struct arc_info *succ_next;
     134              :   struct arc_info *pred_next;
     135              : };
     136              : 
     137              : /* Describes (prime) path coverage.  */
     138              : class path_info
     139              : {
     140              : public:
     141         1450 :   path_info () : paths (), covered () {}
     142              : 
     143              :   /* The prime paths of a function.  The paths will be
     144              :      lexicographically ordered and identified by their index.  */
     145              :   vector<vector<unsigned>> paths;
     146              : 
     147              :   /* The covered paths.  This is really a large bitset partitioned
     148              :      into buckets of gcov_type_unsigned, and bit n is set if the nth
     149              :      path is covered.  */
     150              :   vector<gcov_type_unsigned> covered;
     151              : 
     152              :   /* The prime paths after #pragma GCC suppress_coverage has been taken into
     153              :      account.  This is empty unless something is suppressed, in which case it
     154              :      should be smaller than PATHS.  The paths are lexicographically sorted.  */
     155              :   vector<vector<unsigned>> residual_paths;
     156              : 
     157              :   /* The covered paths after #pragma GCC suppress_coverage has been taken into
     158              :      account.  Like with COVERED, the bit N is set if the Nth path in
     159              :      RESIDUAL_PATHS is covered.  */
     160              :   vector<gcov_type_unsigned> residual_covered;
     161              : 
     162              :   /* The size (in bits) of each bucket.  */
     163              :   static const size_t
     164              :   bucketsize = sizeof (gcov_type_unsigned) * BITS_PER_UNIT;
     165              : 
     166              :   /* Helper for getting the right path set.  */
     167         3367 :   const vector<vector<unsigned>>& get_paths () const
     168         3360 :   { return !suppressed_p () ? paths : residual_paths; }
     169              : 
     170              :   /* Get the number of paths, accounting for suppressed blocks.  */
     171         2758 :   size_t path_count () const
     172         2751 :   { return get_paths ().size (); }
     173              : 
     174              :   /* Get the number of suppressed paths.  This is 0 unless there is a #pragma
     175              :      GCC suppress_coverage somewhere.  */
     176         1379 :   size_t suppressed_count () const
     177         1379 :   { return paths.size () - path_count (); }
     178              : 
     179              :   /* Check if any paths suppressed by #pragma GCC suppress_coverage.  */
     180         7233 :   bool suppressed_p () const
     181         1379 :   { return !residual_paths.empty (); }
     182              : 
     183              :   /* Count the covered paths, accounting for #pragma GCC suppress_coverage.  */
     184         1647 :   unsigned covered_paths () const
     185              :   {
     186         1647 :     unsigned cnt = 0;
     187         2225 :     for (gcov_type_unsigned v : (!suppressed_p () ? covered : residual_covered))
     188          578 :       cnt += popcount_hwi (v);
     189         1647 :     return cnt;
     190              :   }
     191              : 
     192              :   /* Check if the nth path is covered.  */
     193         1944 :   bool covered_p (size_t n) const
     194              :   {
     195         1944 :     if (covered.empty ())
     196              :       return false;
     197              : 
     198         1944 :     const auto& cov = !suppressed_p () ? covered : residual_covered;
     199         1944 :     const size_t bucket = n / bucketsize;
     200         1944 :     const uint64_t bit = n % bucketsize;
     201         1944 :     return cov[bucket] & (gcov_type_unsigned (1) << bit);
     202              :   }
     203              : 
     204              :   void suppress_blocks (const vector<bool>& suppressed);
     205              : };
     206              : 
     207              : /* Describes which locations (lines and files) are associated with
     208              :    a basic block.  */
     209              : 
     210        18755 : class block_location_info
     211              : {
     212              : public:
     213         9454 :   block_location_info (unsigned _source_file_idx):
     214         9454 :     source_file_idx (_source_file_idx)
     215              :   {}
     216              : 
     217              :   unsigned source_file_idx;
     218              :   vector<unsigned> lines;
     219              : };
     220              : 
     221              : /* Describes a single conditional expression and the (recorded) conditions
     222              :    shown to independently affect the outcome.  */
     223              : class condition_info
     224              : {
     225              : public:
     226              :   condition_info ();
     227              : 
     228              :   int popcount () const;
     229              : 
     230              :   /* Bitsets storing the independently significant outcomes for true and false,
     231              :      respectively.  */
     232              :   gcov_type_unsigned truev;
     233              :   gcov_type_unsigned falsev;
     234              : 
     235              :   /* Number of terms in the expression; if (x) -> 1, if (x && y) -> 2 etc.  */
     236              :   unsigned n_terms;
     237              : };
     238              : 
     239        12816 : condition_info::condition_info (): truev (0), falsev (0), n_terms (0)
     240              : {
     241        12816 : }
     242              : 
     243         7546 : int condition_info::popcount () const
     244              : {
     245         7546 :     return popcount_hwi (truev) + popcount_hwi (falsev);
     246              : }
     247              : 
     248              : /* Describes a basic block. Contains lists of arcs to successor and
     249              :    predecessor blocks.  */
     250              : 
     251        12411 : class block_info
     252              : {
     253              : public:
     254              :   /* Constructor.  */
     255              :   block_info ();
     256              : 
     257              :   /* Chain of exit and entry arcs.  */
     258              :   arc_info *succ;
     259              :   arc_info *pred;
     260              : 
     261              :   /* Number of unprocessed exit and entry arcs.  */
     262              :   gcov_type num_succ;
     263              :   gcov_type num_pred;
     264              : 
     265              :   unsigned id;
     266              : 
     267              :   /* Block execution count.  */
     268              :   gcov_type count;
     269              :   unsigned count_valid : 1;
     270              :   unsigned valid_chain : 1;
     271              :   unsigned invalid_chain : 1;
     272              :   unsigned exceptional : 1;
     273              : 
     274              :   /* Block is a call instrumenting site.  */
     275              :   unsigned is_call_site : 1; /* Does the call.  */
     276              :   unsigned is_call_return : 1; /* Is the return.  */
     277              : 
     278              :   /* Block is a landing pad for longjmp or throw.  */
     279              :   unsigned is_nonlocal_return : 1;
     280              : 
     281              :   /* Block is suppressed by #pragma GCC suppress_coverage.  */
     282              :   unsigned suppressed : 1;
     283              : 
     284              :   condition_info conditions;
     285              : 
     286              :   vector<block_location_info> locations;
     287              : 
     288              :   struct
     289              :   {
     290              :     /* Single line graph cycle workspace.  Used for all-blocks
     291              :        mode.  */
     292              :     arc_info *arc;
     293              :     unsigned ident;
     294              :   } cycle; /* Used in all-blocks mode, after blocks are linked onto
     295              :              lines.  */
     296              : 
     297              :   /* Temporary chain for solving graph, and for chaining blocks on one
     298              :      line.  */
     299              :   class block_info *chain;
     300              : 
     301              : };
     302              : 
     303        12816 : block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0),
     304        12816 :   id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
     305        12816 :   exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
     306        12816 :   suppressed (0), locations (), chain (NULL)
     307              : {
     308        12816 :   cycle.arc = NULL;
     309        12816 : }
     310              : 
     311              : /* Describes a single line of source.  Contains a chain of basic blocks
     312              :    with code on it.  */
     313              : 
     314        99623 : class line_info
     315              : {
     316              : public:
     317              :   /* Default constructor.  */
     318              :   line_info ();
     319              : 
     320              :   /* Return true when NEEDLE is one of basic blocks the line belongs to.  */
     321              :   bool has_block (block_info *needle);
     322              : 
     323              :   /* Execution count.  */
     324              :   gcov_type count;
     325              : 
     326              :   /* Branches from blocks that end on this line.  */
     327              :   vector<arc_info *> branches;
     328              : 
     329              :   /* blocks which start on this line.  Used in all-blocks mode.  */
     330              :   vector<block_info *> blocks;
     331              : 
     332              :   unsigned exists : 1;
     333              :   unsigned unexceptional : 1;
     334              :   unsigned has_unexecuted_block : 1;
     335              :   /* Suppressed by #pragma GCC suppress_coverage.  */
     336              :   unsigned suppressed : 1;
     337              : };
     338              : 
     339        53999 : line_info::line_info (): count (0), branches (), blocks (), exists (false),
     340        53999 :   unexceptional (0), has_unexecuted_block (0), suppressed (0)
     341              : {
     342        53999 : }
     343              : 
     344              : bool
     345        22253 : line_info::has_block (block_info *needle)
     346              : {
     347        22253 :   return std::find (blocks.begin (), blocks.end (), needle) != blocks.end ();
     348              : }
     349              : 
     350              : /* Output demangled function names.  */
     351              : 
     352              : static int flag_demangled_names = 0;
     353              : 
     354              : /* Describes a single function. Contains an array of basic blocks.  */
     355              : 
     356              : class function_info
     357              : {
     358              : public:
     359              :   function_info ();
     360              :   ~function_info ();
     361              : 
     362              :   /* Return true when line N belongs to the function in source file SRC_IDX.
     363              :      The line must be defined in body of the function, can't be inlined.  */
     364              :   bool group_line_p (unsigned n, unsigned src_idx);
     365              : 
     366              :   /* Function filter based on function_info::artificial variable.  */
     367              : 
     368              :   static inline bool
     369         1408 :   is_artificial (function_info *fn)
     370              :   {
     371         1408 :     return fn->artificial;
     372              :   }
     373              : 
     374              :   /* Name of function.  */
     375              :   char *m_name;
     376              :   char *m_demangled_name;
     377              :   unsigned ident;
     378              :   unsigned lineno_checksum;
     379              :   unsigned cfg_checksum;
     380              : 
     381              :   /* The graph contains at least one fake incoming edge.  */
     382              :   unsigned has_catch : 1;
     383              : 
     384              :   /* True when the function is artificial and does not exist
     385              :      in a source file.  */
     386              :   unsigned artificial : 1;
     387              : 
     388              :   /* True when multiple functions start at a line in a source file.  */
     389              :   unsigned is_group : 1;
     390              : 
     391              :   /* Array of basic blocks.  Like in GCC, the entry block is
     392              :      at blocks[0] and the exit block is at blocks[1].  */
     393              : #define ENTRY_BLOCK (0)
     394              : #define EXIT_BLOCK (1)
     395              :   vector<block_info> blocks;
     396              :   unsigned blocks_executed;
     397              : 
     398              :   vector<condition_info*> conditions;
     399              : 
     400              :   /* Path coverage information.  */
     401              :   path_info paths;
     402              : 
     403              :   /* Raw arc coverage counts.  */
     404              :   vector<gcov_type> counts;
     405              : 
     406              :   /* First line number.  */
     407              :   unsigned start_line;
     408              : 
     409              :   /* First line column.  */
     410              :   unsigned start_column;
     411              : 
     412              :   /* Last line number.  */
     413              :   unsigned end_line;
     414              : 
     415              :   /* Last line column.  */
     416              :   unsigned end_column;
     417              : 
     418              :   /* Index of source file where the function is defined.  */
     419              :   unsigned src;
     420              : 
     421              :   /* Vector of line information (used only for group functions).  */
     422              :   vector<line_info> lines;
     423              : 
     424              :   /* Next function.  */
     425              :   class function_info *next;
     426              : 
     427              :   /* Blocks suppressed by #pragma GCC suppress_coverage.  If any block is
     428              :      suppressed this is non-empty, and the Nth bit is true if N is suppressed.
     429              :      If suppressed_blocks[0] is true, the whole function is suppressed.  */
     430              :   vector<bool> suppressed_blocks;
     431              : 
     432              :   /*  Get demangled name of a function.  The demangled name
     433              :       is converted when it is used for the first time.  */
     434           21 :   char *get_demangled_name ()
     435              :   {
     436           21 :     if (m_demangled_name == NULL)
     437              :       {
     438           21 :         m_demangled_name = cplus_demangle (m_name, DMGL_PARAMS);
     439           21 :         if (!m_demangled_name)
     440            5 :           m_demangled_name = m_name;
     441              :       }
     442              : 
     443           21 :     return m_demangled_name;
     444              :   }
     445              : 
     446              :   /* Get name of the function based on flag_demangled_names.  */
     447         1692 :   char *get_name ()
     448              :   {
     449         1692 :     return flag_demangled_names ? get_demangled_name () : m_name;
     450              :   }
     451              : 
     452              :   /* Return number of basic blocks (without entry and exit block).  */
     453          170 :   unsigned get_block_count ()
     454              :   {
     455          340 :     return blocks.size () - 2;
     456              :   }
     457              : 
     458        11715 :   bool suppressed_p () const
     459              :   {
     460        13966 :     return !suppressed_blocks.empty () && suppressed_blocks.front ();
     461              :   }
     462              : };
     463              : 
     464              : /* Function info comparer that will sort functions according to starting
     465              :    line.  */
     466              : 
     467              : struct function_line_start_cmp
     468              : {
     469          212 :   inline bool operator() (const function_info *lhs,
     470              :                           const function_info *rhs)
     471              :     {
     472          212 :       return (lhs->start_line == rhs->start_line
     473          212 :               ? lhs->start_column < rhs->start_column
     474          212 :               : lhs->start_line < rhs->start_line);
     475              :     }
     476              : };
     477              : 
     478              : /* Describes coverage of a file or function.  */
     479              : 
     480              : struct coverage_info
     481              : {
     482              :   int function_suppressed;
     483              : 
     484              :   int lines;
     485              :   int lines_executed;
     486              :   int lines_suppressed;
     487              : 
     488              :   int branches;
     489              :   int branches_executed;
     490              :   int branches_taken;
     491              :   int branches_suppressed;
     492              : 
     493              :   int conditions;
     494              :   int conditions_covered;
     495              :   int conditions_suppressed;
     496              : 
     497              :   int calls;
     498              :   int calls_executed;
     499              :   int calls_suppressed;
     500              : 
     501              :   char *name;
     502              : 
     503              :   unsigned paths;
     504              :   unsigned paths_covered;
     505              :   unsigned paths_suppressed;
     506              : };
     507              : 
     508              : /* Describes a file mentioned in the block graph.  Contains an array
     509              :    of line info.  */
     510              : 
     511              : class source_info
     512              : {
     513              : public:
     514              :   /* Default constructor.  */
     515              :   source_info ();
     516              : 
     517              :   vector<function_info *> *get_functions_at_location (unsigned line_num) const;
     518              : 
     519              :   /* Register a new function.  */
     520              :   void add_function (function_info *fn);
     521              : 
     522              :   /* Debug the source file.  */
     523              :   void debug ();
     524              : 
     525              :   /* Index of the source_info in sources vector.  */
     526              :   unsigned index;
     527              : 
     528              :   /* Canonical name of source file.  */
     529              :   char *name;
     530              :   time_t file_time;
     531              : 
     532              :   /* Vector of line information.  */
     533              :   vector<line_info> lines;
     534              : 
     535              :   coverage_info coverage;
     536              : 
     537              :   /* Maximum line count in the source file.  */
     538              :   unsigned int maximum_count;
     539              : 
     540              :   /* Functions in this source file.  These are in ascending line
     541              :      number order.  */
     542              :   vector<function_info *> functions;
     543              : 
     544              :   /* Line number to functions map.  */
     545              :   vector<vector<function_info *> *> line_to_function_map;
     546              : };
     547              : 
     548          238 : source_info::source_info (): index (0), name (NULL), file_time (),
     549          238 :   lines (), coverage (), maximum_count (0), functions ()
     550              : {
     551          238 : }
     552              : 
     553              : /* Register a new function.  */
     554              : void
     555         1363 : source_info::add_function (function_info *fn)
     556              : {
     557         1363 :   functions.push_back (fn);
     558              : 
     559         1363 :   if (fn->start_line >= line_to_function_map.size ())
     560          269 :     line_to_function_map.resize (fn->start_line + 1);
     561              : 
     562         1363 :   vector<function_info *> **slot = &line_to_function_map[fn->start_line];
     563         1363 :   if (*slot == NULL)
     564         1256 :     *slot = new vector<function_info *> ();
     565              : 
     566         1363 :   (*slot)->push_back (fn);
     567         1363 : }
     568              : 
     569              : vector<function_info *> *
     570        51578 : source_info::get_functions_at_location (unsigned line_num) const
     571              : {
     572        51578 :   if (line_num >= line_to_function_map.size ())
     573              :     return NULL;
     574              : 
     575        39394 :   vector<function_info *> *slot = line_to_function_map[line_num];
     576        39394 :   if (slot != NULL)
     577         1243 :     std::sort (slot->begin (), slot->end (), function_line_start_cmp ());
     578              : 
     579              :   return slot;
     580              : }
     581              : 
     582            0 : void source_info::debug ()
     583              : {
     584            0 :   fprintf (stderr, "source_info: %s\n", name);
     585            0 :   for (vector<function_info *>::iterator it = functions.begin ();
     586            0 :        it != functions.end (); it++)
     587              :     {
     588            0 :       function_info *fn = *it;
     589            0 :       fprintf (stderr, "  function_info: %s\n", fn->get_name ());
     590            0 :       for (vector<block_info>::iterator bit = fn->blocks.begin ();
     591            0 :            bit != fn->blocks.end (); bit++)
     592              :         {
     593            0 :           fprintf (stderr, "    block_info id=%d, count=%" PRId64 " \n",
     594            0 :                    bit->id, bit->count);
     595              :         }
     596              :     }
     597              : 
     598            0 :   for (unsigned lineno = 1; lineno < lines.size (); ++lineno)
     599              :     {
     600            0 :       line_info &line = lines[lineno];
     601            0 :       fprintf (stderr, "  line_info=%d, count=%" PRId64 "\n", lineno, line.count);
     602              :     }
     603              : 
     604            0 :   fprintf (stderr, "\n");
     605            0 : }
     606              : 
     607              : class name_map
     608              : {
     609              : public:
     610            0 :   name_map ()
     611              :   {
     612              :   }
     613              : 
     614          239 :   name_map (char *_name, unsigned _src): name (_name), src (_src)
     615              :   {
     616              :   }
     617              : 
     618        19310 :   bool operator== (const name_map &rhs) const
     619              :   {
     620              : #if HAVE_DOS_BASED_FILE_SYSTEM
     621              :     return strcasecmp (this->name, rhs.name) == 0;
     622              : #else
     623        19310 :     return strcmp (this->name, rhs.name) == 0;
     624              : #endif
     625              :   }
     626              : 
     627         1071 :   bool operator< (const name_map &rhs) const
     628              :   {
     629              : #if HAVE_DOS_BASED_FILE_SYSTEM
     630              :     return strcasecmp (this->name, rhs.name) < 0;
     631              : #else
     632         1069 :     return strcmp (this->name, rhs.name) < 0;
     633              : #endif
     634              :   }
     635              : 
     636              :   const char *name;  /* Source file name */
     637              :   unsigned src;  /* Source file */
     638              : };
     639              : 
     640              : /* Vector of all functions.  */
     641              : static vector<function_info *> functions;
     642              : 
     643              : /* Function ident to function_info * map.  */
     644              : static map<unsigned, function_info *> ident_to_fn;
     645              : 
     646              : /* Vector of source files.  */
     647              : static vector<source_info> sources;
     648              : 
     649              : /* Mapping of file names to sources */
     650              : static vector<name_map> names;
     651              : 
     652              : /* Record all processed files in order to warn about
     653              :    a file being read multiple times.  */
     654              : static vector<char *> processed_files;
     655              : 
     656              : /* The contents of a source file.  The nth SOURCE_LINES entry is the
     657              :    contents of the nth SOURCES, or empty if it has not or could not be
     658              :    read.  */
     659              : static vector<vector<const char *>*> source_lines;
     660              : 
     661              : /* This holds data summary information.  */
     662              : 
     663              : static unsigned object_runs;
     664              : 
     665              : static unsigned total_lines;
     666              : static unsigned total_executed;
     667              : static unsigned total_suppressed;
     668              : 
     669              : /* Modification time of graph file.  */
     670              : 
     671              : static time_t bbg_file_time;
     672              : 
     673              : /* Name of the notes (gcno) output file.  The "bbg" prefix is for
     674              :    historical reasons, when the notes file contained only the
     675              :    basic block graph notes.  */
     676              : 
     677              : static char *bbg_file_name;
     678              : 
     679              : /* Stamp of the bbg file */
     680              : static unsigned bbg_stamp;
     681              : 
     682              : /* Supports has_unexecuted_blocks functionality.  */
     683              : static unsigned bbg_supports_has_unexecuted_blocks;
     684              : 
     685              : /* Working directory in which a TU was compiled.  */
     686              : static const char *bbg_cwd;
     687              : 
     688              : /* Name and file pointer of the input file for the count data (gcda).  */
     689              : 
     690              : static char *da_file_name;
     691              : 
     692              : /* Data file is missing.  */
     693              : 
     694              : static int no_data_file;
     695              : 
     696              : /* If there is several input files, compute and display results after
     697              :    reading all data files.  This way if two or more gcda file refer to
     698              :    the same source file (eg inline subprograms in a .h file), the
     699              :    counts are added.  */
     700              : 
     701              : static int multiple_files = 0;
     702              : 
     703              : /* Output branch probabilities.  */
     704              : 
     705              : static int flag_branches = 0;
     706              : 
     707              : /* Output conditions (modified condition/decision coverage).  */
     708              : 
     709              : static bool flag_conditions = 0;
     710              : 
     711              : /* Show unconditional branches too.  */
     712              : static int flag_unconditional = 0;
     713              : 
     714              : /* Output path coverage.  */
     715              : static bool flag_prime_paths = false;
     716              : 
     717              : /* Output path coverage - lines mode.  */
     718              : static bool flag_prime_paths_lines_covered = false;
     719              : static bool flag_prime_paths_lines_uncovered = false;
     720              : 
     721              : /* Output path coverage - source mode.  */
     722              : static bool flag_prime_paths_source_covered  = false;
     723              : static bool flag_prime_paths_source_uncovered  = false;
     724              : 
     725              : /* Output a gcov file if this is true.  This is on by default, and can
     726              :    be turned off by the -n option.  */
     727              : 
     728              : static int flag_gcov_file = 1;
     729              : 
     730              : /* Output to stdout instead to a gcov file.  */
     731              : 
     732              : static int flag_use_stdout = 0;
     733              : 
     734              : /* Output progress indication if this is true.  This is off by default
     735              :    and can be turned on by the -d option.  */
     736              : 
     737              : static int flag_display_progress = 0;
     738              : 
     739              : /* Output *.gcov file in JSON intermediate format used by consumers.  */
     740              : 
     741              : static int flag_json_format = 0;
     742              : 
     743              : /* For included files, make the gcov output file name include the name
     744              :    of the input source file.  For example, if x.h is included in a.c,
     745              :    then the output file name is a.c##x.h.gcov instead of x.h.gcov.  */
     746              : 
     747              : static int flag_long_names = 0;
     748              : 
     749              : /* For situations when a long name can potentially hit filesystem path limit,
     750              :    let's calculate md5sum of the path and append it to a file name.  */
     751              : 
     752              : static int flag_hash_filenames = 0;
     753              : 
     754              : /* Print verbose information.  */
     755              : 
     756              : static int flag_verbose = 0;
     757              : 
     758              : /* Print colored output.  */
     759              : 
     760              : static int flag_use_colors = 0;
     761              : 
     762              : /* Use perf-like colors to indicate hot lines.  */
     763              : 
     764              : static int flag_use_hotness_colors = 0;
     765              : 
     766              : /* Output count information for every basic block, not merely those
     767              :    that contain line number information.  */
     768              : 
     769              : static int flag_all_blocks = 0;
     770              : 
     771              : /* Output human readable numbers.  */
     772              : 
     773              : static int flag_human_readable_numbers = 0;
     774              : 
     775              : /* Output summary info for each function.  */
     776              : 
     777              : static int flag_function_summary = 0;
     778              : 
     779              : /* Print debugging dumps.  */
     780              : 
     781              : static int flag_debug = 0;
     782              : 
     783              : /* Object directory file prefix.  This is the directory/file where the
     784              :    graph and data files are looked for, if nonzero.  */
     785              : 
     786              : static char *object_directory = 0;
     787              : 
     788              : /* Source directory prefix.  This is removed from source pathnames
     789              :    that match, when generating the output file name.  */
     790              : 
     791              : static char *source_prefix = 0;
     792              : static size_t source_length = 0;
     793              : 
     794              : /* Only show data for sources with relative pathnames.  Absolute ones
     795              :    usually indicate a system header file, which although it may
     796              :    contain inline functions, is usually uninteresting.  */
     797              : static int flag_relative_only = 0;
     798              : 
     799              : /* Preserve all pathname components. Needed when object files and
     800              :    source files are in subdirectories. '/' is mangled as '#', '.' is
     801              :    elided and '..' mangled to '^'.  */
     802              : 
     803              : static int flag_preserve_paths = 0;
     804              : 
     805              : /* Output the number of times a branch was taken as opposed to the percentage
     806              :    of times it was taken.  */
     807              : 
     808              : static int flag_counts = 0;
     809              : 
     810              : /* Return code of the tool invocation.  */
     811              : static int return_code = 0;
     812              : 
     813              : /* "Keep policy" when adding functions to the global function table.  This will
     814              :    be set to false when --include is used, otherwise every function should be
     815              :    added to the table.  Used for --include/exclude.  */
     816              : static bool default_keep = true;
     817              : 
     818              : /* Include/exclude filters function based on matching the (de)mangled name.
     819              :    The default is to match the mangled name.  Note that flag_demangled_names
     820              :    does not affect this.  */
     821              : static bool flag_filter_on_demangled = false;
     822              : 
     823              : /* A 'function filter', a filter and action for determining if a function
     824              :    should be included in the output or not.  Used for --include/--exclude
     825              :    filtering.  */
     826              : struct fnfilter
     827              : {
     828              :   /* The (extended) compiled regex for this filter.  */
     829              :   regex_t regex;
     830              : 
     831              :   /* The action when this filter (regex) matches - if true, the function should
     832              :      be kept, otherwise discarded.  */
     833              :   bool keep;
     834              : 
     835              :   /* Compile the regex EXPR, or exit if pattern is malformed.  */
     836           15 :   void compile (const char *expr)
     837              :   {
     838           15 :     int err = regcomp (&regex, expr, REG_NOSUB | REG_EXTENDED);
     839           15 :     if (err)
     840              :       {
     841            0 :         size_t len = regerror (err, &regex, nullptr, 0);
     842            0 :         char *msg = XNEWVEC (char, len);
     843            0 :         regerror (err, &regex, msg, len);
     844            0 :         fprintf (stderr, "Bad regular expression: %s\n", msg);
     845            0 :         free (msg);
     846            0 :         exit (EXIT_FAILURE);
     847              :     }
     848           15 :   }
     849              : };
     850              : 
     851              : /* A collection of filter functions for including/exclude functions in the
     852              :    output.  This is empty unless --include/--exclude is used.  */
     853              : static vector<fnfilter> filters;
     854              : 
     855              : /* Forward declarations.  */
     856              : static int process_args (int, char **);
     857              : static void print_usage (int) ATTRIBUTE_NORETURN;
     858              : static void print_version (void) ATTRIBUTE_NORETURN;
     859              : static void process_file (const char *);
     860              : static void process_all_functions (void);
     861              : static void generate_results (const char *);
     862              : static void create_file_names (const char *);
     863              : static char *canonicalize_name (const char *);
     864              : static unsigned find_source (const char *);
     865              : static void read_graph_file (void);
     866              : static int read_count_file (void);
     867              : static void solve_flow_graph (function_info *);
     868              : static void find_prime_paths (function_info *fn);
     869              : static void find_exception_blocks (function_info *);
     870              : static void add_branch_counts (coverage_info *, const arc_info *);
     871              : static void add_condition_counts (coverage_info *, const block_info *);
     872              : static void add_path_counts (coverage_info &, const function_info &);
     873              : static void add_line_counts (coverage_info *, function_info *);
     874              : static void executed_summary (unsigned, unsigned, unsigned);
     875              : static void function_summary (const coverage_info *);
     876              : static void file_summary (const coverage_info *);
     877              : static const char *format_gcov (gcov_type, gcov_type, int);
     878              : static void accumulate_line_counts (source_info *);
     879              : static void output_gcov_file (const char *, source_info *);
     880              : static int output_branch_count (FILE *, int, const arc_info *);
     881              : static void output_conditions (FILE *, const block_info *);
     882              : static void output_lines (FILE *, const source_info *);
     883              : static string make_gcov_file_name (const char *, const char *);
     884              : static char *mangle_name (const char *);
     885              : static void release_structures (void);
     886              : extern int main (int, char **);
     887              : static const vector<const char *>&
     888              : slurp (const source_info &src, FILE *gcov_file, const char *line_start);
     889              : 
     890         1450 : function_info::function_info (): m_name (NULL), m_demangled_name (NULL),
     891         1450 :   ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
     892         1450 :   artificial (0), is_group (0),
     893         1450 :   blocks (), blocks_executed (0), counts (),
     894         1450 :   start_line (0), start_column (0), end_line (0), end_column (0),
     895         1450 :   src (0), lines (), next (NULL)
     896              : {
     897         1450 : }
     898              : 
     899         1363 : function_info::~function_info ()
     900              : {
     901        13774 :   for (int i = blocks.size () - 1; i >= 0; i--)
     902              :     {
     903        12411 :       arc_info *arc, *arc_n;
     904              : 
     905        29110 :       for (arc = blocks[i].succ; arc; arc = arc_n)
     906              :         {
     907        16699 :           arc_n = arc->succ_next;
     908        16699 :           free (arc);
     909              :         }
     910              :     }
     911         1363 :   if (m_demangled_name != m_name)
     912         1361 :     free (m_demangled_name);
     913         1363 :   free (m_name);
     914         1363 : }
     915              : 
     916        11786 : bool function_info::group_line_p (unsigned n, unsigned src_idx)
     917              : {
     918        11786 :   return is_group && src == src_idx && start_line <= n && n <= end_line;
     919              : }
     920              : 
     921              : /* Check if the block ID is a tombstone.  */
     922              : static bool
     923         3418 : tombstone_p (unsigned id)
     924              : {
     925         3418 :   return id == unsigned (-1);
     926              : };
     927              : 
     928              : /* Remove tombstones from VEC.  Preserves the order of remaining values.  */
     929              : static vector<unsigned>
     930           42 : remove_tombstones (vector<unsigned> vec)
     931              : {
     932           42 :   vec.erase (remove_if (vec.begin (), vec.end (), tombstone_p), vec.end ());
     933           42 :   return vec;
     934              : }
     935              : 
     936              : /* Check if SUB is a a proper contiguous subsequence of SUPER with tombstones
     937              :    functioning as wildcards.
     938              : 
     939              :    If SUB and SUPER would be equal if tombstones are removed, SUB is not a
     940              :    proper subsequence and this function returns false.
     941              : 
     942              :    Examples:
     943              : 
     944              :    SUB:   2 -1 12
     945              :    SUPER: 2 -1 -1 12
     946              :    Returns false because both sequences become [2 12] without tombstones.
     947              : 
     948              :    SUB: 2 -1 12
     949              :    SUPER: 2 7 12
     950              :    Returns true because 2 12 appear in that order in SUPER and there is a
     951              :    tombstone between 2 and 12.
     952              : 
     953              :    SUB: 2 12
     954              :    SUPER: 2 7 12
     955              :    Returns false because 2 and 12 are not consecutive in SUPER.
     956              : 
     957              :    SUB: 12 7
     958              :    SUPER: 2 7 12
     959              :    Returns false because 7 is before 12 in SUPER.
     960              : 
     961              :    SUB: -1 7 12
     962              :    SUPER: -1 7 -1 12 -1
     963              :    Returns false because both sequences are 7 12 once tombstones are removed.
     964              : */
     965              : static bool
     966          645 : tombstone_subsequence_p (const vector<unsigned>& sub,
     967              :                          const vector<unsigned>& super)
     968              : {
     969          645 :   if (&sub == &super)
     970              :     return false;
     971              : 
     972          593 :   auto xend = sub.end ();
     973          593 :   auto yend = super.end ();
     974          593 :   auto xitr = find_if_not (sub.begin (), xend, tombstone_p);
     975          593 :   auto yitr = find_if_not (super.begin (), yend, tombstone_p);
     976              : 
     977              :   /* If SUB is empty or all tombstones it is included in any other path.  */
     978          593 :   if (xitr == xend)
     979              :     return true;
     980              :   /* If SUPER is empty or all tombstones it does not include anything.  */
     981          593 :   if (yitr == yend)
     982              :     return false;
     983              : 
     984          584 :   bool equivalent = *yitr == *xitr;
     985              :   /* Find the position in SUPER where the SUB may start.  */
     986          584 :   if (!equivalent)
     987              :     {
     988          434 :       yitr = find (yitr, yend, *xitr);
     989          434 :       if (yitr == yend)
     990              :         return false;
     991              :     }
     992              : 
     993         1406 :   for (; xitr != xend; ++xitr, ++yitr)
     994         1369 :     if (tombstone_p (*xitr))
     995              :       {
     996              :         /* Skip past any tombstones to find the next value.  We need to compare
     997              :            to the next non-tombstone value in SUPER to know if we skipped any
     998              :            values to check for equivalence, otherwise this could just be
     999              :            std::find for SUPER.  */
    1000          292 :         xitr = find_if_not (xitr, xend, tombstone_p);
    1001          292 :         yitr = find_if_not (yitr, yend, tombstone_p);
    1002              : 
    1003              :         /* If there are no more non-tombstone blocks i SUB we're almost done,
    1004              :            but we still need to if there are more blocks in SUPER.  */
    1005          292 :         if (xitr == xend)
    1006           15 :           return yitr != yend || !equivalent;
    1007              : 
    1008          277 :         if (yitr == yend)
    1009              :           return false;
    1010              : 
    1011              :         /* Now check for equivalence and look for the value in SUPER.  This is
    1012              :            a no-op if we found it already.  */
    1013          189 :         equivalent = equivalent && *yitr == *xitr;
    1014          189 :         yitr = find (yitr, yend, *xitr);
    1015          189 :         if (yitr == yend)
    1016              :           return false;
    1017              :       }
    1018         1077 :     else if (*yitr != *xitr)
    1019              :       return false;
    1020              : 
    1021           37 :   yitr = find_if_not (yitr, yend, tombstone_p);
    1022           37 :   return yitr == yend && !equivalent;
    1023              : }
    1024              : 
    1025              : /* Check if NEEDLE is a proper subsequence of any sequence in HAYSTACK except
    1026              :    itself.  Suppressed blocks/tombstones function as wildcards and match any
    1027              :    subsequence.  If two sequences are equal once tombstones are removed they
    1028              :    are not proper subsequences of eachother.
    1029              : 
    1030              :    We may get odd sequence when we remove parts of a path, so we
    1031              :    extend the when the path A subsumes B to include non-contiguous
    1032              :    subsequences.
    1033              : 
    1034              :    Given a set of prime paths:
    1035              :     2 3 4 12
    1036              :     2 3 5 6 12
    1037              :     2 3 5 7 8 10 12
    1038              :     2 3 5 7 8 9 10 12
    1039              :     2 3 5 7 8 9 11 12
    1040              : 
    1041              :    We have a blacklist of 3 4 5 6 8 9 10 which means these nodes should be
    1042              :    removed from all paths.  If we replace blacklisted nodes with tombstones
    1043              :    (-1) and remove duplicates we get:
    1044              :     2 -1 12
    1045              :     2 -1 7 -1 11 12
    1046              :     2 -1 7 -1 12
    1047              : 
    1048              :    A path is prime if it is not a subpath of any other paths.  Suppressed
    1049              :    segments may be covered by any sequence of nodes, so the path:
    1050              :     2 -1 7 -1 11 12
    1051              :    would subsume (<:) the other paths:
    1052              :     2 -1 12   <: 2 [7 11] 12
    1053              :     2 -1 7 12 <: 2 7 [11] 12
    1054              : 
    1055              :    Thus the only prime path is 2 7 11 12.  */
    1056              : static bool
    1057           75 : subsumed_by_any_p (const vector<unsigned>& needle,
    1058              :                    const vector<vector<unsigned>>& haystack)
    1059              : {
    1060           75 :   if (all_of (needle.begin (), needle.end (), tombstone_p))
    1061              :     return true;
    1062          687 :   for (const auto& seq : haystack)
    1063          645 :     if (tombstone_subsequence_p (needle, seq))
    1064           75 :       return true;
    1065              :   return false;
    1066              : }
    1067              : 
    1068              : /* Compute the new paths and coverage by ignoring the blocks in SUPPRESSED.
    1069              :    Does nothing when SUPPRESSED is empty.  This only adds the new
    1070              :    interpretation and does not change the observed path and coverage info.  */
    1071              : void
    1072         1363 : path_info::suppress_blocks (const vector<bool>& suppressed)
    1073              : {
    1074         1363 :   if (suppressed.empty ())
    1075         1078 :     return;
    1076              : 
    1077          285 :   const unsigned tombstone = unsigned (-1);
    1078              :   /* Clean up the paths by replacing suppressed blocks with tombstones.  */
    1079          285 :   vector<vector<unsigned>> ipaths;
    1080          285 :   ipaths.reserve (paths.size ());
    1081          360 :   for (const auto& path : paths)
    1082              :     {
    1083           75 :       vector<unsigned> tmp;
    1084           75 :       tmp.reserve (path.size ());
    1085          530 :       for (auto v : path)
    1086          649 :         tmp.push_back (!suppressed[v] ? v : tombstone);
    1087           75 :       ipaths.push_back (std::move (tmp));
    1088           75 :     }
    1089              : 
    1090              :   /* Changing paths means some paths may turn into subpaths, so we find and
    1091              :      store the new prime paths mapped to the original indices for later.
    1092              :      The new paths are map both sorts the paths and filters duplicates
    1093              :      duplicates.  */
    1094          285 :   map<vector<unsigned> /* path */, vector<size_t> /* indices */> nextpaths;
    1095          360 :   for (size_t i = 0; i != ipaths.size (); ++i)
    1096           75 :     if (!subsumed_by_any_p (ipaths[i], ipaths))
    1097           42 :       nextpaths[remove_tombstones (ipaths[i])].push_back (i);
    1098              : 
    1099              :   /* Record the coverage of the new paths.  The new paths may be the result
    1100              :      of merging paths, and if either original path is covered then the merged
    1101              :      path should be covered.  */
    1102          285 :   vector<gcov_type_unsigned> nextcovered;
    1103          285 :   const size_t nbits = path_info::bucketsize;
    1104          285 :   const size_t nbuckets = (nextpaths.size () + (nbits - 1)) / nbits;
    1105          285 :   nextcovered.resize (nbuckets);
    1106          285 :   std::size_t n = 0;
    1107          320 :   for (const auto& np : nextpaths)
    1108              :     {
    1109           35 :       const size_t bucket = n / bucketsize;
    1110           35 :       const uint64_t bit = n % bucketsize;
    1111           55 :       for (size_t index : np.second)
    1112           37 :         if (covered_p (index))
    1113              :           {
    1114           17 :             nextcovered[bucket] |= (gcov_type_unsigned (1) << bit);
    1115           17 :             break;
    1116              :           }
    1117           35 :       n++;
    1118              :     }
    1119          285 :   residual_covered.swap (nextcovered);
    1120              : 
    1121              :   /* Store the new paths.  The map iteration outputs the paths
    1122              :      lexicographically ordered.  */
    1123          320 :   for (auto& p : nextpaths)
    1124           35 :     residual_paths.push_back (std::move (p.first));
    1125          285 : }
    1126              : 
    1127              : /* Find the arc that connects BLOCK to the block with id DEST, or nullptr if it
    1128              :    doesn't exist.  */
    1129              : static const arc_info*
    1130         8279 : find_arc (const block_info &block, unsigned dest)
    1131              : {
    1132        34431 :   for (const arc_info *arc = block.succ; arc; arc = arc->succ_next)
    1133        34403 :     if (arc->dst->id == dest)
    1134              :       return arc;
    1135              :   return nullptr;
    1136              : }
    1137              : 
    1138              : /* Cycle detection!
    1139              :    There are a bajillion algorithms that do this.  Boost's function is named
    1140              :    hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
    1141              :    "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
    1142              :    (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
    1143              : 
    1144              :    The basic algorithm is simple: effectively, we're finding all simple paths
    1145              :    in a subgraph (that shrinks every iteration).  Duplicates are filtered by
    1146              :    "blocking" a path when a node is added to the path (this also prevents non-
    1147              :    simple paths)--the node is unblocked only when it participates in a cycle.
    1148              :    */
    1149              : 
    1150              : typedef vector<arc_info *> arc_vector_t;
    1151              : typedef vector<const block_info *> block_vector_t;
    1152              : 
    1153              : /* Handle cycle identified by EDGES, where the function finds minimum cs_count
    1154              :    and subtract the value from all counts.  The subtracted value is added
    1155              :    to COUNT.  Returns type of loop.  */
    1156              : 
    1157              : static void
    1158           16 : handle_cycle (const arc_vector_t &edges, int64_t &count)
    1159              : {
    1160              :   /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
    1161              :      that amount.  */
    1162           16 :   int64_t cycle_count = INTTYPE_MAXIMUM (int64_t);
    1163           52 :   for (unsigned i = 0; i < edges.size (); i++)
    1164              :     {
    1165           36 :       int64_t ecount = edges[i]->cs_count;
    1166           36 :       if (cycle_count > ecount)
    1167              :         cycle_count = ecount;
    1168              :     }
    1169           16 :   count += cycle_count;
    1170           52 :   for (unsigned i = 0; i < edges.size (); i++)
    1171           36 :     edges[i]->cs_count -= cycle_count;
    1172              : 
    1173           16 :   gcc_assert (cycle_count > 0);
    1174           16 : }
    1175              : 
    1176              : /* Unblock a block U from BLOCKED.  Apart from that, iterate all blocks
    1177              :    blocked by U in BLOCK_LISTS.  */
    1178              : 
    1179              : static void
    1180           34 : unblock (const block_info *u, block_vector_t &blocked,
    1181              :          vector<block_vector_t > &block_lists)
    1182              : {
    1183           34 :   block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u);
    1184           34 :   if (it == blocked.end ())
    1185            0 :     return;
    1186              : 
    1187           34 :   unsigned index = it - blocked.begin ();
    1188           34 :   blocked.erase (it);
    1189              : 
    1190           34 :   block_vector_t to_unblock (block_lists[index]);
    1191              : 
    1192           34 :   block_lists.erase (block_lists.begin () + index);
    1193              : 
    1194           34 :   for (block_vector_t::iterator it = to_unblock.begin ();
    1195           34 :        it != to_unblock.end (); it++)
    1196            0 :     unblock (*it, blocked, block_lists);
    1197           34 : }
    1198              : 
    1199              : /* Return true when PATH contains a zero cycle arc count.  */
    1200              : 
    1201              : static bool
    1202         1646 : path_contains_zero_or_negative_cycle_arc (arc_vector_t &path)
    1203              : {
    1204        11419 :   for (unsigned i = 0; i < path.size (); i++)
    1205         9773 :     if (path[i]->cs_count <= 0)
    1206              :       return true;
    1207              :   return false;
    1208              : }
    1209              : 
    1210              : /* Find circuit going to block V, PATH is provisional seen cycle.
    1211              :    BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
    1212              :    blocked by a block.  COUNT is accumulated count of the current LINE.
    1213              :    Returns what type of loop it contains.  */
    1214              : 
    1215              : static bool
    1216         9755 : circuit (block_info *v, arc_vector_t &path, block_info *start,
    1217              :          block_vector_t &blocked, vector<block_vector_t> &block_lists,
    1218              :          line_info &linfo, int64_t &count)
    1219              : {
    1220         9755 :   bool loop_found = false;
    1221              : 
    1222              :   /* Add v to the block list.  */
    1223        19510 :   gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
    1224         9755 :   blocked.push_back (v);
    1225         9755 :   block_lists.push_back (block_vector_t ());
    1226              : 
    1227        26784 :   for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
    1228              :     {
    1229        17029 :       block_info *w = arc->dst;
    1230        32396 :       if (w < start
    1231        12544 :           || arc->cs_count <= 0
    1232        23367 :           || !linfo.has_block (w))
    1233        15367 :         continue;
    1234              : 
    1235         1662 :       path.push_back (arc);
    1236         1662 :       if (w == start)
    1237              :         {
    1238              :           /* Cycle has been found.  */
    1239           16 :           handle_cycle (path, count);
    1240           16 :           loop_found = true;
    1241              :         }
    1242         1646 :       else if (!path_contains_zero_or_negative_cycle_arc (path)
    1243         3292 :                &&  find (blocked.begin (), blocked.end (), w) == blocked.end ())
    1244         1627 :         loop_found |= circuit (w, path, start, blocked, block_lists, linfo,
    1245              :                                count);
    1246              : 
    1247         1662 :       path.pop_back ();
    1248              :     }
    1249              : 
    1250         9755 :   if (loop_found)
    1251           34 :     unblock (v, blocked, block_lists);
    1252              :   else
    1253        26692 :     for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
    1254              :       {
    1255        16971 :         block_info *w = arc->dst;
    1256        32317 :         if (w < start
    1257        12492 :             || arc->cs_count <= 0
    1258        23257 :             || !linfo.has_block (w))
    1259        15346 :           continue;
    1260              : 
    1261         1625 :         size_t index
    1262         3250 :           = find (blocked.begin (), blocked.end (), w) - blocked.begin ();
    1263         1625 :         gcc_assert (index < blocked.size ());
    1264         1625 :         block_vector_t &list = block_lists[index];
    1265         3250 :         if (find (list.begin (), list.end (), v) == list.end ())
    1266         1625 :           list.push_back (v);
    1267              :       }
    1268              : 
    1269         9755 :   return loop_found;
    1270              : }
    1271              : 
    1272              : /* Find cycles for a LINFO.  */
    1273              : 
    1274              : static gcov_type
    1275         6136 : get_cycles_count (line_info &linfo)
    1276              : {
    1277              :   /* Note that this algorithm works even if blocks aren't in sorted order.
    1278              :      Each iteration of the circuit detection is completely independent
    1279              :      (except for reducing counts, but that shouldn't matter anyways).
    1280              :      Therefore, operating on a permuted order (i.e., non-sorted) only
    1281              :      has the effect of permuting the output cycles.  */
    1282              : 
    1283         6136 :   gcov_type count = 0;
    1284         6136 :   for (vector<block_info *>::iterator it = linfo.blocks.begin ();
    1285        14264 :        it != linfo.blocks.end (); it++)
    1286              :     {
    1287         8128 :       arc_vector_t path;
    1288         8128 :       block_vector_t blocked;
    1289         8128 :       vector<block_vector_t > block_lists;
    1290         8128 :       circuit (*it, path, *it, blocked, block_lists, linfo, count);
    1291         8128 :     }
    1292              : 
    1293         6136 :   return count;
    1294              : }
    1295              : 
    1296              : int
    1297          160 : main (int argc, char **argv)
    1298              : {
    1299          160 :   int argno;
    1300          160 :   int first_arg;
    1301          160 :   const char *p;
    1302              : 
    1303          160 :   p = argv[0] + strlen (argv[0]);
    1304          800 :   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
    1305          640 :     --p;
    1306          160 :   progname = p;
    1307              : 
    1308          160 :   xmalloc_set_program_name (progname);
    1309              : 
    1310              :   /* Unlock the stdio streams.  */
    1311          160 :   unlock_std_streams ();
    1312              : 
    1313          160 :   gcc_init_libintl ();
    1314              : 
    1315          160 :   diagnostic_initialize (global_dc, 0);
    1316              : 
    1317              :   /* Handle response files.  */
    1318          160 :   expandargv (&argc, &argv);
    1319              : 
    1320          160 :   argno = process_args (argc, argv);
    1321          160 :   if (optind == argc)
    1322            0 :     print_usage (true);
    1323              : 
    1324          160 :   if (argc - argno > 1)
    1325            0 :     multiple_files = 1;
    1326              : 
    1327          160 :   first_arg = argno;
    1328              : 
    1329          320 :   for (; argno != argc; argno++)
    1330              :     {
    1331          160 :       if (flag_display_progress)
    1332            0 :         printf ("Processing file %d out of %d\n", argno - first_arg + 1,
    1333              :                 argc - first_arg);
    1334          160 :       process_file (argv[argno]);
    1335              : 
    1336          160 :       if (flag_json_format || argno == argc - 1)
    1337              :         {
    1338          160 :           process_all_functions ();
    1339          160 :           generate_results (argv[argno]);
    1340          160 :           release_structures ();
    1341              :         }
    1342              :     }
    1343              : 
    1344          160 :   if (!flag_use_stdout)
    1345          160 :     executed_summary (total_lines, total_executed, total_suppressed);
    1346              : 
    1347          160 :   return return_code;
    1348              : }
    1349              : 
    1350              : /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
    1351              :    otherwise the output of --help.  */
    1352              : 
    1353              : static void
    1354            0 : print_usage (int error_p)
    1355              : {
    1356            0 :   FILE *file = error_p ? stderr : stdout;
    1357            0 :   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
    1358              : 
    1359            0 :   fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
    1360            0 :   fnotice (file, "Print code coverage information.\n\n");
    1361            0 :   fnotice (file, "  -a, --all-blocks                Show information for every basic block\n");
    1362            0 :   fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output\n");
    1363            0 :   fnotice (file, "  -c, --branch-counts             Output counts of branches taken\n\
    1364              :                                     rather than percentages\n");
    1365            0 :   fnotice (file, "  -g, --conditions                Include modified condition/decision\n\
    1366              :                                     coverage (masking MC/DC) in output\n");
    1367            0 :   fnotice (file, "  -e, --prime-paths               Show prime path coverage summary\n");
    1368            0 :   fnotice (file, "      --prime-paths-lines[=TYPE]  Include paths in output\n\
    1369              :                                     line trace mode - does not affect json\n\
    1370              :                                     TYPE is 'covered', 'uncovered', or 'both'\n\
    1371              :                                     and defaults to 'uncovered'\n");
    1372            0 :   fnotice (file, "      --prime-paths-source[=TYPE] Include paths in output\n\
    1373              :                                     source trace mode - does not affect json\n\
    1374              :                                     TYPE is 'covered', 'uncovered', or 'both'\n\
    1375              :                                     and defaults to 'uncovered'\n");
    1376            0 :   fnotice (file, "  -d, --display-progress          Display progress information\n");
    1377            0 :   fnotice (file, "  -D, --debug                        Display debugging dumps\n");
    1378            0 :   fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
    1379            0 :   fnotice (file, "      --include                   Include functions matching this regex\n");
    1380            0 :   fnotice (file, "      --exclude                   Exclude functions matching this regex\n");
    1381            0 :   fnotice (file, "  -h, --help                      Print this help, then exit\n");
    1382            0 :   fnotice (file, "  -j, --json-format               Output JSON intermediate format\n\
    1383              :                                     into .gcov.json.gz file\n");
    1384            0 :   fnotice (file, "  -H, --human-readable            Output human readable numbers\n");
    1385            0 :   fnotice (file, "  -k, --use-colors                Emit colored output\n");
    1386            0 :   fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
    1387              :                                     source files\n");
    1388            0 :   fnotice (file, "  -m, --demangled-names           Output demangled function names\n");
    1389            0 :   fnotice (file, "  -M, --filter-on-demangled       Make --include/--exclude match on demangled\n\
    1390              :                                     names. This does not imply -m\n");
    1391            0 :   fnotice (file, "  -n, --no-output                 Do not create an output file\n");
    1392            0 :   fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
    1393            0 :   fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
    1394            0 :   fnotice (file, "  -q, --use-hotness-colors        Emit perf-like colored output for hot lines\n");
    1395            0 :   fnotice (file, "  -r, --relative-only             Only show data for relative sources\n");
    1396            0 :   fnotice (file, "  -s, --source-prefix DIR         Source prefix to elide\n");
    1397            0 :   fnotice (file, "  -t, --stdout                    Output to stdout instead of a file\n");
    1398            0 :   fnotice (file, "  -u, --unconditional-branches    Show unconditional branch counts too\n");
    1399            0 :   fnotice (file, "  -v, --version                   Print version number, then exit\n");
    1400            0 :   fnotice (file, "  -w, --verbose                   Print verbose information\n");
    1401            0 :   fnotice (file, "  -x, --hash-filenames            Hash long pathnames\n");
    1402            0 :   fnotice (file, "\nObsolete options:\n");
    1403            0 :   fnotice (file, "  -i, --json-format               Replaced with -j, --json-format\n");
    1404            0 :   fnotice (file, "  -j, --human-readable            Replaced with -H, --human-readable\n");
    1405            0 :   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
    1406              :            bug_report_url);
    1407            0 :   exit (status);
    1408              : }
    1409              : 
    1410              : /* Print version information and exit.  */
    1411              : 
    1412              : static void
    1413            0 : print_version (void)
    1414              : {
    1415            0 :   fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
    1416            0 :   fnotice (stdout, "JSON format version: %s\n", GCOV_JSON_FORMAT_VERSION);
    1417            0 :   fprintf (stdout, "Copyright %s 2026 Free Software Foundation, Inc.\n",
    1418              :            _("(C)"));
    1419            0 :   fnotice (stdout,
    1420            0 :            _("This is free software; see the source for copying conditions.  There is NO\n\
    1421              : warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
    1422            0 :   exit (SUCCESS_EXIT_CODE);
    1423              : }
    1424              : 
    1425              : static const struct option options[] =
    1426              : {
    1427              :   { "help",                 no_argument,       NULL, 'h' },
    1428              :   { "version",              no_argument,       NULL, 'v' },
    1429              :   { "verbose",              no_argument,       NULL, 'w' },
    1430              :   { "all-blocks",           no_argument,       NULL, 'a' },
    1431              :   { "branch-probabilities", no_argument,       NULL, 'b' },
    1432              :   { "branch-counts",        no_argument,       NULL, 'c' },
    1433              :   { "conditions",         no_argument,       NULL, 'g' },
    1434              :   { "prime-paths",        no_argument,       NULL, 'e' },
    1435              :   { "prime-paths-lines",    optional_argument, NULL, 900 },
    1436              :   { "prime-paths-source",   optional_argument, NULL, 901 },
    1437              :   { "json-format",        no_argument,       NULL, 'j' },
    1438              :   { "include",              required_argument, NULL, 'I' },
    1439              :   { "exclude",              required_argument, NULL, 'E' },
    1440              :   { "human-readable",     no_argument,       NULL, 'H' },
    1441              :   { "no-output",            no_argument,       NULL, 'n' },
    1442              :   { "long-file-names",      no_argument,       NULL, 'l' },
    1443              :   { "function-summaries",   no_argument,       NULL, 'f' },
    1444              :   { "demangled-names",      no_argument,       NULL, 'm' },
    1445              :   { "filter-on-demangled",  no_argument,       NULL, 'M' },
    1446              :   { "preserve-paths",       no_argument,       NULL, 'p' },
    1447              :   { "relative-only",        no_argument,       NULL, 'r' },
    1448              :   { "object-directory",     required_argument, NULL, 'o' },
    1449              :   { "object-file",          required_argument, NULL, 'o' },
    1450              :   { "source-prefix",        required_argument, NULL, 's' },
    1451              :   { "stdout",             no_argument,       NULL, 't' },
    1452              :   { "unconditional-branches", no_argument,     NULL, 'u' },
    1453              :   { "display-progress",     no_argument,       NULL, 'd' },
    1454              :   { "hash-filenames",     no_argument,       NULL, 'x' },
    1455              :   { "use-colors",         no_argument,       NULL, 'k' },
    1456              :   { "use-hotness-colors",   no_argument,       NULL, 'q' },
    1457              :   { "debug",              no_argument,       NULL, 'D' },
    1458              :   { 0, 0, 0, 0 }
    1459              : };
    1460              : 
    1461              : /* Process args, return index to first non-arg.  */
    1462              : 
    1463              : static int
    1464          160 : process_args (int argc, char **argv)
    1465              : {
    1466          160 :   int opt;
    1467              : 
    1468          160 :   const char *opts = "abcdDefghHijklmMno:pqrs:tuvwx";
    1469          243 :   while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
    1470              :     {
    1471           83 :       switch (opt)
    1472              :         {
    1473           15 :         case 'a':
    1474           15 :           flag_all_blocks = 1;
    1475           15 :           break;
    1476           23 :         case 'b':
    1477           23 :           flag_branches = 1;
    1478           23 :           break;
    1479            2 :         case 'c':
    1480            2 :           flag_counts = 1;
    1481            2 :           break;
    1482            3 :         case 'e':
    1483            3 :           flag_prime_paths = true;
    1484            3 :           break;
    1485            8 :         case 900:
    1486            8 :           flag_prime_paths = true;
    1487            8 :           if (!optarg)
    1488            2 :             flag_prime_paths_lines_uncovered = true;
    1489            6 :           else if (strcmp (optarg, "uncovered") == 0)
    1490            0 :             flag_prime_paths_lines_uncovered = true;
    1491            6 :           else if (strcmp (optarg, "covered") == 0)
    1492            1 :             flag_prime_paths_lines_covered = true;
    1493            5 :           else if (strcmp (optarg, "both") == 0)
    1494              :             {
    1495            5 :                 flag_prime_paths_lines_covered = true;
    1496            5 :                 flag_prime_paths_lines_uncovered = true;
    1497              :             }
    1498              :           else
    1499              :             {
    1500            0 :               fnotice (stderr, "invalid argument '%s' for "
    1501              :                        "'--prime-paths-lines'. Valid arguments are: "
    1502              :                        "'covered', 'uncovered', 'both'\n", optarg);
    1503            0 :               exit (FATAL_EXIT_CODE);
    1504              :             }
    1505              :           break;
    1506            3 :         case 901:
    1507            3 :           flag_prime_paths = true;
    1508            3 :           if (!optarg)
    1509            0 :             flag_prime_paths_source_uncovered = true;
    1510            3 :           else if (strcmp (optarg, "uncovered") == 0)
    1511            0 :             flag_prime_paths_source_uncovered = true;
    1512            3 :           else if (strcmp (optarg, "covered") == 0)
    1513            0 :             flag_prime_paths_source_covered = true;
    1514            3 :           else if (strcmp (optarg, "both") == 0)
    1515              :             {
    1516            3 :                 flag_prime_paths_source_covered = true;
    1517            3 :                 flag_prime_paths_source_uncovered = true;
    1518              :             }
    1519              :           else
    1520              :             {
    1521            0 :               fnotice (stderr, "invalid argument '%s' for "
    1522              :                        "'--prime-paths-source'. Valid arguments are: "
    1523              :                        "'covered', 'uncovered', 'both'\n", optarg);
    1524            0 :               exit (FATAL_EXIT_CODE);
    1525              :             }
    1526              :           break;
    1527            0 :         case 'f':
    1528            0 :           flag_function_summary = 1;
    1529            0 :           break;
    1530            6 :         case 'g':
    1531            6 :           flag_conditions = 1;
    1532            6 :           break;
    1533            0 :         case 'h':
    1534            0 :           print_usage (false);
    1535              :           /* print_usage will exit.  */
    1536            0 :         case 'l':
    1537            0 :           flag_long_names = 1;
    1538            0 :           break;
    1539           12 :         case 'I':
    1540           12 :           default_keep = false;
    1541           12 :           filters.push_back (fnfilter {});
    1542           12 :           filters.back ().keep = true;
    1543           12 :           filters.back ().compile (optarg);
    1544           12 :           break;
    1545            3 :         case 'E':
    1546            3 :           filters.push_back (fnfilter {});
    1547            3 :           filters.back ().keep = false;
    1548            3 :           filters.back ().compile (optarg);
    1549            3 :           break;
    1550            3 :         case 'H':
    1551            3 :           flag_human_readable_numbers = 1;
    1552            3 :           break;
    1553            0 :         case 'k':
    1554            0 :           flag_use_colors = 1;
    1555            0 :           break;
    1556            0 :         case 'q':
    1557            0 :           flag_use_hotness_colors = 1;
    1558            0 :           break;
    1559            0 :         case 'm':
    1560            0 :           flag_demangled_names = 1;
    1561            0 :           break;
    1562            3 :         case 'M':
    1563            3 :           flag_filter_on_demangled = true;
    1564            3 :           break;
    1565            0 :         case 'n':
    1566            0 :           flag_gcov_file = 0;
    1567            0 :           break;
    1568            0 :         case 'o':
    1569            0 :           object_directory = optarg;
    1570            0 :           break;
    1571            0 :         case 's':
    1572            0 :           source_prefix = optarg;
    1573            0 :           source_length = strlen (source_prefix);
    1574            0 :           break;
    1575            0 :         case 'r':
    1576            0 :           flag_relative_only = 1;
    1577            0 :           break;
    1578            0 :         case 'p':
    1579            0 :           flag_preserve_paths = 1;
    1580            0 :           break;
    1581            0 :         case 'u':
    1582            0 :           flag_unconditional = 1;
    1583            0 :           break;
    1584            2 :         case 'i':
    1585            2 :         case 'j':
    1586            2 :           flag_json_format = 1;
    1587            2 :           flag_gcov_file = 1;
    1588            2 :           break;
    1589            0 :         case 'd':
    1590            0 :           flag_display_progress = 1;
    1591            0 :           break;
    1592            0 :         case 'x':
    1593            0 :           flag_hash_filenames = 1;
    1594            0 :           break;
    1595            0 :         case 'w':
    1596            0 :           flag_verbose = 1;
    1597            0 :           break;
    1598            0 :         case 't':
    1599            0 :           flag_use_stdout = 1;
    1600            0 :           break;
    1601            0 :         case 'D':
    1602            0 :           flag_debug = 1;
    1603            0 :           break;
    1604            0 :         case 'v':
    1605            0 :           print_version ();
    1606              :           /* print_version will exit.  */
    1607            0 :         default:
    1608            0 :           print_usage (true);
    1609              :           /* print_usage will exit.  */
    1610              :         }
    1611              :     }
    1612              : 
    1613          160 :   return optind;
    1614              : }
    1615              : 
    1616              : /* Output intermediate LINE sitting on LINE_NUM to JSON OBJECT.
    1617              :    Add FUNCTION_NAME to the LINE.  */
    1618              : 
    1619              : static void
    1620           71 : output_intermediate_json_line (json::array *object,
    1621              :                                line_info *line, unsigned line_num,
    1622              :                                const char *function_name)
    1623              : {
    1624           71 :   if (!line->exists)
    1625           71 :     return;
    1626              : 
    1627           31 :   json::object *lineo = new json::object ();
    1628           31 :   lineo->set_integer ("line_number", line_num);
    1629           31 :   if (function_name != NULL)
    1630           31 :     lineo->set_string ("function_name", function_name);
    1631           31 :   lineo->set_integer ("count", line->count);
    1632           31 :   lineo->set_bool ("unexecuted_block", line->has_unexecuted_block);
    1633              : 
    1634           31 :   json::array *bb_ids = new json::array ();
    1635           49 :   for (const block_info *block : line->blocks)
    1636           18 :     bb_ids->append (new json::integer_number (block->id));
    1637           31 :   lineo->set ("block_ids", bb_ids);
    1638              : 
    1639           31 :   json::array *branches = new json::array ();
    1640           31 :   lineo->set ("branches", branches);
    1641              : 
    1642           31 :   json::array *calls = new json::array ();
    1643           31 :   lineo->set ("calls", calls);
    1644              : 
    1645           31 :   vector<arc_info *>::const_iterator it;
    1646           31 :   if (flag_branches)
    1647           63 :     for (it = line->branches.begin (); it != line->branches.end ();
    1648           32 :          it++)
    1649              :       {
    1650           32 :         if ((*it)->suppressed)
    1651              :           {
    1652              :             /* Skip.  */
    1653              :           }
    1654           32 :         else if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
    1655              :           {
    1656           10 :             json::object *branch = new json::object ();
    1657           10 :             branch->set_integer ("count", (*it)->count);
    1658           10 :             branch->set_bool ("throw", (*it)->is_throw);
    1659           10 :             branch->set_bool ("fallthrough", (*it)->fall_through);
    1660           10 :             branch->set_integer ("source_block_id", (*it)->src->id);
    1661           10 :             branch->set_integer ("destination_block_id", (*it)->dst->id);
    1662           10 :             branches->append (branch);
    1663              :           }
    1664           22 :         else if ((*it)->is_call_non_return)
    1665              :           {
    1666            9 :             json::object *call = new json::object ();
    1667            9 :             gcov_type returns = (*it)->src->count - (*it)->count;
    1668            9 :             call->set_integer ("source_block_id", (*it)->src->id);
    1669            9 :             call->set_integer ("destination_block_id", (*it)->dst->id);
    1670            9 :             call->set_integer ("returned", returns);
    1671            9 :             calls->append (call);
    1672              :           }
    1673              :       }
    1674              : 
    1675           31 :   json::array *conditions = new json::array ();
    1676           31 :   lineo->set ("conditions", conditions);
    1677           31 :   if (flag_conditions)
    1678              :   {
    1679            0 :     vector<block_info *>::const_iterator it;
    1680            0 :     for (it = line->blocks.begin (); it != line->blocks.end (); it++)
    1681              :       {
    1682            0 :         if ((*it)->suppressed)
    1683            0 :           continue;
    1684              : 
    1685            0 :         const condition_info& info = (*it)->conditions;
    1686            0 :         if (info.n_terms == 0)
    1687            0 :             continue;
    1688              : 
    1689            0 :         const int count = 2 * info.n_terms;
    1690            0 :         const int covered = info.popcount ();
    1691              : 
    1692            0 :         json::object *cond = new json::object ();
    1693            0 :         cond->set_integer ("count", count);
    1694            0 :         cond->set_integer ("covered", covered);
    1695              : 
    1696            0 :         json::array *mtrue = new json::array ();
    1697            0 :         json::array *mfalse = new json::array ();
    1698            0 :         cond->set ("not_covered_true", mtrue);
    1699            0 :         cond->set ("not_covered_false", mfalse);
    1700              : 
    1701            0 :         if (count != covered)
    1702              :           {
    1703            0 :             for (unsigned i = 0; i < info.n_terms; i++)
    1704              :               {
    1705            0 :                 gcov_type_unsigned index = 1;
    1706            0 :                 index <<= i;
    1707            0 :                 if (!(index & info.truev))
    1708            0 :                     mtrue->append (new json::integer_number (i));
    1709            0 :                 if (!(index & info.falsev))
    1710            0 :                     mfalse->append (new json::integer_number (i));
    1711              :               }
    1712              :           }
    1713            0 :         conditions->append (cond);
    1714              :       }
    1715              :   }
    1716              : 
    1717           31 :   object->append (lineo);
    1718              : }
    1719              : 
    1720              : /* Strip filename extension in STR.  */
    1721              : 
    1722              : static string
    1723          160 : strip_extention (string str)
    1724              : {
    1725          160 :   string::size_type pos = str.rfind ('.');
    1726          160 :   if (pos != string::npos)
    1727          160 :     str = str.substr (0, pos);
    1728              : 
    1729          160 :   return str;
    1730              : }
    1731              : 
    1732              : /* Calculate md5sum for INPUT string and return it in hex string format.  */
    1733              : 
    1734              : static string
    1735            0 : get_md5sum (const char *input)
    1736              : {
    1737            0 :   md5_ctx ctx;
    1738            0 :   char md5sum[16];
    1739            0 :   string str;
    1740              : 
    1741            0 :   md5_init_ctx (&ctx);
    1742            0 :   md5_process_bytes (input, strlen (input), &ctx);
    1743            0 :   md5_finish_ctx (&ctx, md5sum);
    1744              : 
    1745            0 :   for (unsigned i = 0; i < 16; i++)
    1746              :     {
    1747            0 :       char b[3];
    1748            0 :       sprintf (b, "%02x", (unsigned char)md5sum[i]);
    1749            0 :       str += b;
    1750              :     }
    1751              : 
    1752            0 :   return str;
    1753              : }
    1754              : 
    1755              : /* Get the name of the gcov file.  The return value must be free'd.
    1756              : 
    1757              :    It appends the '.gcov' extension to the *basename* of the file.
    1758              :    The resulting file name will be in PWD.
    1759              : 
    1760              :    e.g.,
    1761              :    input: foo.da,       output: foo.da.gcov
    1762              :    input: a/b/foo.cc,   output: foo.cc.gcov  */
    1763              : 
    1764              : static string
    1765          160 : get_gcov_intermediate_filename (const char *input_file_name)
    1766              : {
    1767          160 :   string base = lbasename (input_file_name);
    1768          320 :   string str = strip_extention (base);
    1769              : 
    1770          160 :   if (flag_hash_filenames)
    1771              :     {
    1772            0 :       str += "##";
    1773            0 :       str += get_md5sum (input_file_name);
    1774              :     }
    1775          160 :   else if (flag_preserve_paths && base != input_file_name)
    1776              :     {
    1777            0 :       str += "##";
    1778            0 :       str += mangle_path (input_file_name);
    1779            0 :       str = strip_extention (str);
    1780              :     }
    1781              : 
    1782          160 :   str += ".gcov.json.gz";
    1783          160 :   return str.c_str ();
    1784          160 : }
    1785              : 
    1786              : /* Add prime path coverage from INFO to FUNCTION.  */
    1787              : static void
    1788            9 : json_set_prime_path_coverage (json::object &function, function_info &info)
    1789              : {
    1790            9 :   json::array *jpaths = new json::array ();
    1791           18 :   function.set_integer ("total_prime_paths", info.paths.path_count ());
    1792            9 :   function.set_integer ("covered_prime_paths", info.paths.covered_paths ());
    1793            9 :   function.set_integer ("suppressed_prime_paths",
    1794            9 :                         info.paths.suppressed_count ());
    1795            9 :   function.set ("prime_path_coverage", jpaths);
    1796              : 
    1797            9 :   size_t pathno = 0;
    1798           18 :   for (const vector<unsigned> &path : info.paths.get_paths ())
    1799              :     {
    1800            0 :       if (info.paths.covered_p (pathno++))
    1801            0 :         continue;
    1802              : 
    1803            0 :       gcc_assert (!path.empty ());
    1804              : 
    1805            0 :       json::object *jpath = new json::object ();
    1806            0 :       jpaths->append (jpath);
    1807            0 :       jpath->set_integer ("id", pathno - 1);
    1808              : 
    1809            0 :       json::array *jlist = new json::array ();
    1810            0 :       jpath->set ("sequence", jlist);
    1811              : 
    1812            0 :       for (size_t i = 0; i != path.size (); ++i)
    1813              :         {
    1814            0 :           const unsigned bb = path[i];
    1815            0 :           const block_info &block = info.blocks[bb];
    1816            0 :           const char *edge_kind = "";
    1817            0 :           if (i + 1 != path.size ())
    1818              :             {
    1819            0 :               const arc_info *arc = find_arc (block, path[i+1]);
    1820            0 :               if (!arc)
    1821              :                 edge_kind = "suppress";
    1822            0 :               else if (arc->true_value)
    1823              :                 edge_kind = "true";
    1824            0 :               else if (arc->false_value)
    1825              :                 edge_kind = "false";
    1826            0 :               else if (arc->fall_through)
    1827              :                 edge_kind = "fallthru";
    1828            0 :               else if (arc->is_throw)
    1829            0 :                 edge_kind = "throw";
    1830              :             }
    1831              : 
    1832            0 :           json::object *jblock = new json::object ();
    1833            0 :           json::array *jlocs = new json::array ();
    1834            0 :           jblock->set_integer ("block_id", block.id);
    1835            0 :           jblock->set ("locations", jlocs);
    1836            0 :           jblock->set_string ("edge_kind", edge_kind);
    1837            0 :           jlist->append (jblock);
    1838            0 :           for (const block_location_info &loc : block.locations)
    1839              :             {
    1840              :               /* loc.lines could be empty when a statement is not anchored to a
    1841              :                  source file -- see g++.dg/gcov/gcov-23.C.  */
    1842            0 :               if (loc.lines.empty ())
    1843            0 :                 continue;
    1844            0 :               json::object *jloc = new json::object ();
    1845            0 :               json::array *jline_numbers = new json::array ();
    1846            0 :               jlocs->append (jloc);
    1847            0 :               jloc->set_string ("file", sources[loc.source_file_idx].name);
    1848            0 :               jloc->set ("line_numbers", jline_numbers);
    1849            0 :               for (unsigned line : loc.lines)
    1850            0 :                 jline_numbers->append (new json::integer_number (line));
    1851              :             }
    1852              :         }
    1853              :     }
    1854            9 : }
    1855              : 
    1856              : /* Output the result in JSON intermediate format.
    1857              :    Source info SRC is dumped into JSON_FILES which is JSON array.  */
    1858              : 
    1859              : static void
    1860            2 : output_json_intermediate_file (json::array *json_files, source_info *src)
    1861              : {
    1862            2 :   json::object *root = new json::object ();
    1863            2 :   json_files->append (root);
    1864              : 
    1865            2 :   root->set_string ("file", src->name);
    1866              : 
    1867            2 :   json::array *functions = new json::array ();
    1868            2 :   root->set ("functions", functions);
    1869              : 
    1870            2 :   std::sort (src->functions.begin (), src->functions.end (),
    1871              :              function_line_start_cmp ());
    1872           11 :   for (vector<function_info *>::iterator it = src->functions.begin ();
    1873           11 :        it != src->functions.end (); it++)
    1874              :     {
    1875            9 :       json::object *function = new json::object ();
    1876            9 :       function->set_string ("name", (*it)->m_name);
    1877            9 :       function->set_string ("demangled_name", (*it)->get_demangled_name ());
    1878            9 :       function->set_integer ("start_line", (*it)->start_line);
    1879            9 :       function->set_integer ("start_column", (*it)->start_column);
    1880            9 :       function->set_integer ("end_line", (*it)->end_line);
    1881            9 :       function->set_integer ("end_column", (*it)->end_column);
    1882            9 :       function->set_integer ("blocks", (*it)->get_block_count ());
    1883            9 :       function->set_integer ("blocks_executed", (*it)->blocks_executed);
    1884            9 :       function->set_integer ("blocks_suppressed",
    1885            9 :                              count ((*it)->suppressed_blocks.begin (),
    1886            9 :                                     (*it)->suppressed_blocks.end (), true));
    1887            9 :       function->set_integer ("execution_count", (*it)->blocks[0].count);
    1888              : 
    1889            9 :       json_set_prime_path_coverage (*function, **it);
    1890            9 :       functions->append (function);
    1891              :     }
    1892              : 
    1893            2 :   json::array *lineso = new json::array ();
    1894            2 :   root->set ("lines", lineso);
    1895              : 
    1896            2 :   vector<function_info *> last_non_group_fns;
    1897              : 
    1898           71 :   for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
    1899              :     {
    1900           69 :       vector<function_info *> *fns = src->get_functions_at_location (line_num);
    1901              : 
    1902           69 :       if (fns != NULL)
    1903              :         /* Print info for all group functions that begin on the line.  */
    1904           16 :         for (vector<function_info *>::iterator it2 = fns->begin ();
    1905           16 :              it2 != fns->end (); it2++)
    1906              :           {
    1907            9 :             if (!(*it2)->is_group)
    1908            5 :               last_non_group_fns.push_back (*it2);
    1909              : 
    1910            9 :             vector<line_info> &lines = (*it2)->lines;
    1911              :             /* The LINES array is allocated only for group functions.  */
    1912           13 :             for (unsigned i = 0; i < lines.size (); i++)
    1913              :               {
    1914            4 :                 line_info *line = &lines[i];
    1915            4 :                 output_intermediate_json_line (lineso, line, line_num + i,
    1916            4 :                                                (*it2)->m_name);
    1917              :               }
    1918              :           }
    1919              : 
    1920              :       /* Follow with lines associated with the source file.  */
    1921           69 :       if (line_num < src->lines.size ())
    1922              :         {
    1923           67 :           unsigned size = last_non_group_fns.size ();
    1924           67 :           function_info *last_fn = size > 0 ? last_non_group_fns[size - 1] : NULL;
    1925           42 :           const char *fname = last_fn ? last_fn->m_name : NULL;
    1926           67 :           output_intermediate_json_line (lineso, &src->lines[line_num], line_num,
    1927              :                                          fname);
    1928              : 
    1929              :           /* Pop ending function from stack.  */
    1930           67 :           if (last_fn != NULL && last_fn->end_line == line_num)
    1931            5 :             last_non_group_fns.pop_back ();
    1932              :         }
    1933              :     }
    1934            2 : }
    1935              : 
    1936              : /* Function start pair.  */
    1937              : struct function_start
    1938              : {
    1939              :   unsigned source_file_idx;
    1940              :   unsigned start_line;
    1941              : };
    1942              : 
    1943              : /* Traits class for function start hash maps below.  */
    1944              : 
    1945              : struct function_start_pair_hash : typed_noop_remove <function_start>
    1946              : {
    1947              :   typedef function_start value_type;
    1948              :   typedef function_start compare_type;
    1949              : 
    1950              :   static hashval_t
    1951         3681 :   hash (const function_start &ref)
    1952              :   {
    1953         3681 :     inchash::hash hstate (0);
    1954         3681 :     hstate.add_int (ref.source_file_idx);
    1955         3681 :     hstate.add_int (ref.start_line);
    1956         3681 :     return hstate.end ();
    1957              :   }
    1958              : 
    1959              :   static bool
    1960         2368 :   equal (const function_start &ref1, const function_start &ref2)
    1961              :   {
    1962         2368 :     return (ref1.source_file_idx == ref2.source_file_idx
    1963         2368 :             && ref1.start_line == ref2.start_line);
    1964              :   }
    1965              : 
    1966              :   static void
    1967              :   mark_deleted (function_start &ref)
    1968              :   {
    1969              :     ref.start_line = ~1U;
    1970              :   }
    1971              : 
    1972              :   static const bool empty_zero_p = false;
    1973              : 
    1974              :   static void
    1975         5002 :   mark_empty (function_start &ref)
    1976              :   {
    1977         5002 :     ref.start_line = ~2U;
    1978              :   }
    1979              : 
    1980              :   static bool
    1981         4924 :   is_deleted (const function_start &ref)
    1982              :   {
    1983         4924 :     return ref.start_line == ~1U;
    1984              :   }
    1985              : 
    1986              :   static bool
    1987        22493 :   is_empty (const function_start &ref)
    1988              :   {
    1989        21237 :     return ref.start_line == ~2U;
    1990              :   }
    1991              : };
    1992              : 
    1993              : /* Process a single input file.  */
    1994              : 
    1995              : static void
    1996          160 : process_file (const char *file_name)
    1997              : {
    1998          160 :   create_file_names (file_name);
    1999              : 
    2000          320 :   for (unsigned i = 0; i < processed_files.size (); i++)
    2001            0 :     if (strcmp (da_file_name, processed_files[i]) == 0)
    2002              :       {
    2003            0 :         fnotice (stderr, "'%s' file is already processed\n",
    2004              :                  file_name);
    2005            0 :         return;
    2006              :       }
    2007              : 
    2008          160 :   processed_files.push_back (xstrdup (da_file_name));
    2009              : 
    2010          160 :   read_graph_file ();
    2011          160 :   read_count_file ();
    2012              : }
    2013              : 
    2014              : /* Process all functions in all files.  */
    2015              : 
    2016              : static void
    2017          160 : process_all_functions (void)
    2018              : {
    2019          160 :   hash_map<function_start_pair_hash, function_info *> fn_map;
    2020              : 
    2021              :   /* Identify group functions.  */
    2022         1568 :   for (vector<function_info *>::iterator it = functions.begin ();
    2023         1568 :        it != functions.end (); it++)
    2024         1408 :     if (!(*it)->artificial)
    2025              :       {
    2026         1363 :         function_start needle;
    2027         1363 :         needle.source_file_idx = (*it)->src;
    2028         1363 :         needle.start_line = (*it)->start_line;
    2029              : 
    2030         1363 :         function_info **slot = fn_map.get (needle);
    2031         1363 :         if (slot)
    2032              :           {
    2033          107 :             (*slot)->is_group = 1;
    2034          107 :             (*it)->is_group = 1;
    2035              :           }
    2036              :         else
    2037         1256 :           fn_map.put (needle, *it);
    2038              :       }
    2039              : 
    2040              :   /* Remove all artificial function.  */
    2041          160 :   functions.erase (remove_if (functions.begin (), functions.end (),
    2042          160 :                               function_info::is_artificial), functions.end ());
    2043              : 
    2044         1523 :   for (vector<function_info *>::iterator it = functions.begin ();
    2045         1523 :        it != functions.end (); it++)
    2046              :     {
    2047         1363 :       function_info *fn = *it;
    2048         1363 :       unsigned src = fn->src;
    2049              : 
    2050         1363 :       if (!fn->suppressed_blocks.empty ())
    2051              :         {
    2052              :           /* Set the ignore flag on blocks, arcs.  */
    2053         3152 :           for (block_info &b : fn->blocks)
    2054         5828 :             if (fn->suppressed_blocks[b.id] || fn->suppressed_p ())
    2055              :               {
    2056          951 :                 b.suppressed = 1;
    2057         2381 :                 for (arc_info *arc = b.succ; arc; arc = arc->succ_next)
    2058         1430 :                   arc->suppressed = 1;
    2059         1966 :                 for (arc_info *arc = b.pred; arc; arc = arc->pred_next)
    2060         1015 :                   arc->suppressed = 1;
    2061              :               }
    2062              :         }
    2063         1363 :       if (!fn->counts.empty () || no_data_file)
    2064              :         {
    2065         1363 :           source_info *s = &sources[src];
    2066         1363 :           s->add_function (fn);
    2067              : 
    2068              :           /* Mark last line in files touched by function.  */
    2069        15137 :           for (unsigned block_no = 0; block_no != fn->blocks.size ();
    2070              :                block_no++)
    2071              :             {
    2072        12411 :               block_info *block = &fn->blocks[block_no];
    2073        21627 :               for (unsigned i = 0; i < block->locations.size (); i++)
    2074              :                 {
    2075              :                   /* Sort lines of locations.  */
    2076        18432 :                   sort (block->locations[i].lines.begin (),
    2077         9216 :                         block->locations[i].lines.end ());
    2078              : 
    2079         9216 :                   if (!block->locations[i].lines.empty ())
    2080              :                     {
    2081         9213 :                       s = &sources[block->locations[i].source_file_idx];
    2082         9213 :                       unsigned last_line
    2083         9213 :                         = block->locations[i].lines.back ();
    2084              : 
    2085              :                       /* Record new lines for the function.  */
    2086         9213 :                       if (last_line >= s->lines.size ())
    2087              :                         {
    2088         1329 :                           s = &sources[block->locations[i].source_file_idx];
    2089         1329 :                           unsigned last_line
    2090         1329 :                             = block->locations[i].lines.back ();
    2091              : 
    2092              :                           /* Record new lines for the function.  */
    2093         1329 :                           if (last_line >= s->lines.size ())
    2094              :                             {
    2095              :                               /* Record new lines for a source file.  */
    2096         1329 :                               s->lines.resize (last_line + 1);
    2097              :                             }
    2098              :                         }
    2099              :                     }
    2100              : 
    2101        18432 :                   if (block->suppressed || fn->suppressed_p ())
    2102         2006 :                     for (unsigned ln : block->locations[i].lines)
    2103         1132 :                       s->lines[ln].suppressed = 1;
    2104              :                 }
    2105              :             }
    2106              : 
    2107              :           /* Make sure to include the last line for this function even when it
    2108              :              is not directly covered by a basic block, for example when } is on
    2109              :              its own line.  */
    2110         1363 :           if (sources[fn->src].lines.size () <= fn->end_line)
    2111          169 :             sources[fn->src].lines.resize (fn->end_line + 1);
    2112              : 
    2113              :           /* Allocate lines for group function, following start_line
    2114              :              and end_line information of the function.  */
    2115         1363 :           if (fn->is_group)
    2116          187 :             fn->lines.resize (fn->end_line - fn->start_line + 1);
    2117              : 
    2118              :           /* Propagate the suppressed flag too.  */
    2119         1363 :           if (fn->is_group)
    2120              :             {
    2121          187 :               const auto& source = sources[fn->src];
    2122         1832 :               for (unsigned ln = fn->start_line, dst = 0; ln <= fn->end_line;
    2123         1645 :                    ++ln, ++dst)
    2124         1645 :                 fn->lines[dst].suppressed = source.lines.at (ln).suppressed;
    2125              :             }
    2126              : 
    2127         1363 :           solve_flow_graph (fn);
    2128         1363 :           if (fn->has_catch)
    2129          112 :             find_exception_blocks (fn);
    2130              : 
    2131              :           /* For path coverage.  */
    2132         1363 :           find_prime_paths (fn);
    2133         1363 :           fn->paths.suppress_blocks (fn->suppressed_blocks);
    2134              :         }
    2135              :       else
    2136              :         {
    2137              :           /* The function was not in the executable -- some other
    2138              :              instance must have been selected.  */
    2139              :         }
    2140              :     }
    2141          160 : }
    2142              : 
    2143              : static void
    2144          236 : output_gcov_file (const char *file_name, source_info *src)
    2145              : {
    2146          236 :   string gcov_file_name_str
    2147          236 :     = make_gcov_file_name (file_name, src->coverage.name);
    2148          236 :   const char *gcov_file_name = gcov_file_name_str.c_str ();
    2149              : 
    2150          236 :   if (src->coverage.lines)
    2151              :     {
    2152          236 :       FILE *gcov_file = fopen (gcov_file_name, "w");
    2153          236 :       if (gcov_file)
    2154              :         {
    2155          236 :           fnotice (stdout, "Creating '%s'\n", gcov_file_name);
    2156          236 :           output_lines (gcov_file, src);
    2157          236 :           if (ferror (gcov_file))
    2158              :             {
    2159            0 :               fnotice (stderr, "Error writing output file '%s'\n",
    2160              :                        gcov_file_name);
    2161            0 :               return_code = 6;
    2162              :             }
    2163          236 :           fclose (gcov_file);
    2164              :         }
    2165              :       else
    2166              :         {
    2167            0 :           fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
    2168            0 :           return_code = 6;
    2169              :         }
    2170              :     }
    2171              :   else
    2172              :     {
    2173            0 :       unlink (gcov_file_name);
    2174            0 :       fnotice (stdout, "Removing '%s'\n", gcov_file_name);
    2175              :     }
    2176          236 : }
    2177              : 
    2178              : static void
    2179          160 : generate_results (const char *file_name)
    2180              : {
    2181          160 :   string gcov_intermediate_filename;
    2182              : 
    2183         1523 :   for (vector<function_info *>::iterator it = functions.begin ();
    2184         1523 :        it != functions.end (); it++)
    2185              :     {
    2186         1363 :       function_info *fn = *it;
    2187         1363 :       coverage_info coverage;
    2188              : 
    2189         1363 :       memset (&coverage, 0, sizeof (coverage));
    2190         1648 :       if (fn->suppressed_p ())
    2191           32 :         coverage.function_suppressed = 1;
    2192         1363 :       coverage.name = fn->get_name ();
    2193         2726 :       add_line_counts (flag_function_summary ? &coverage : NULL, fn);
    2194              : 
    2195         1363 :       if (!flag_function_summary)
    2196         1363 :         continue;
    2197              : 
    2198            0 :       for (const block_info& block : fn->blocks)
    2199            0 :         for (arc_info *arc = block.succ; arc; arc = arc->succ_next)
    2200            0 :           add_branch_counts (&coverage, arc);
    2201              : 
    2202            0 :       for (const block_info& block : fn->blocks)
    2203            0 :         add_condition_counts (&coverage, &block);
    2204              : 
    2205            0 :       add_path_counts (coverage, *fn);
    2206              : 
    2207            0 :       function_summary (&coverage);
    2208            0 :       fnotice (stdout, "\n");
    2209              :     }
    2210              : 
    2211          160 :   name_map needle;
    2212          160 :   needle.name = file_name;
    2213          160 :   vector<name_map>::iterator it
    2214          160 :     = std::find (names.begin (), names.end (), needle);
    2215          160 :   if (it != names.end ())
    2216            3 :     file_name = sources[it->src].coverage.name;
    2217              :   else
    2218          157 :     file_name = canonicalize_name (file_name);
    2219              : 
    2220          160 :   gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
    2221              : 
    2222          160 :   json::object *root = new json::object ();
    2223          160 :   root->set_string ("format_version", GCOV_JSON_FORMAT_VERSION);
    2224          160 :   root->set_string ("gcc_version", version_string);
    2225              : 
    2226          160 :   if (bbg_cwd != NULL)
    2227          160 :     root->set_string ("current_working_directory", bbg_cwd);
    2228          160 :   root->set_string ("data_file", file_name);
    2229              : 
    2230          160 :   json::array *json_files = new json::array ();
    2231          160 :   root->set ("files", json_files);
    2232              : 
    2233          398 :   for (vector<source_info>::iterator it = sources.begin ();
    2234          398 :        it != sources.end (); it++)
    2235              :     {
    2236          238 :       source_info *src = &(*it);
    2237          238 :       if (flag_relative_only)
    2238              :         {
    2239              :           /* Ignore this source, if it is an absolute path (after
    2240              :              source prefix removal).  */
    2241            0 :           char first = src->coverage.name[0];
    2242              : 
    2243              : #if HAVE_DOS_BASED_FILE_SYSTEM
    2244              :           if (first && src->coverage.name[1] == ':')
    2245              :             first = src->coverage.name[2];
    2246              : #endif
    2247            0 :           if (IS_DIR_SEPARATOR (first))
    2248            0 :             continue;
    2249              :         }
    2250              : 
    2251         1601 :       for (function_info *fn : src->functions)
    2252         1363 :         add_path_counts (src->coverage, *fn);
    2253              : 
    2254          238 :       accumulate_line_counts (src);
    2255          238 :       if (flag_debug)
    2256            0 :         src->debug ();
    2257              : 
    2258          238 :       if (!flag_use_stdout)
    2259          238 :         file_summary (&src->coverage);
    2260          238 :       total_lines += src->coverage.lines;
    2261          238 :       total_executed += src->coverage.lines_executed;
    2262          238 :       total_suppressed += src->coverage.lines_suppressed;
    2263          238 :       if (flag_gcov_file)
    2264              :         {
    2265          238 :           if (flag_json_format)
    2266              :             {
    2267            2 :               output_json_intermediate_file (json_files, src);
    2268            2 :               if (!flag_use_stdout)
    2269            2 :                 fnotice (stdout, "\n");
    2270              :             }
    2271              :           else
    2272              :             {
    2273          236 :               if (flag_use_stdout)
    2274              :                 {
    2275            0 :                   if (src->coverage.lines)
    2276            0 :                     output_lines (stdout, src);
    2277              :                 }
    2278              :               else
    2279              :                 {
    2280          236 :                   output_gcov_file (file_name, src);
    2281          236 :                   fnotice (stdout, "\n");
    2282              :                 }
    2283              :             }
    2284              :         }
    2285              :     }
    2286              : 
    2287          160 :   if (flag_gcov_file && flag_json_format)
    2288              :     {
    2289            2 :       if (flag_use_stdout)
    2290              :         {
    2291            0 :           root->dump (stdout, false);
    2292            0 :           printf ("\n");
    2293              :         }
    2294              :       else
    2295              :         {
    2296            2 :           pretty_printer pp;
    2297            2 :           root->print (&pp, false);
    2298            2 :           pp_formatted_text (&pp);
    2299              : 
    2300            2 :           fnotice (stdout, "Creating '%s'\n",
    2301              :                    gcov_intermediate_filename.c_str ());
    2302            2 :           gzFile output = gzopen (gcov_intermediate_filename.c_str (), "w");
    2303            2 :           if (output == NULL)
    2304              :             {
    2305            0 :               fnotice (stderr, "Cannot open JSON output file %s\n",
    2306              :                        gcov_intermediate_filename.c_str ());
    2307            0 :               return_code = 6;
    2308            0 :               return;
    2309              :             }
    2310              : 
    2311            2 :           if (gzputs (output, pp_formatted_text (&pp)) == EOF
    2312            2 :               || gzclose (output))
    2313              :             {
    2314            0 :               fnotice (stderr, "Error writing JSON output file %s\n",
    2315              :                        gcov_intermediate_filename.c_str ());
    2316            0 :               return_code = 6;
    2317            0 :               return;
    2318              :             }
    2319            2 :         }
    2320              :     }
    2321          160 : }
    2322              : 
    2323              : /* Release all memory used.  */
    2324              : 
    2325              : static void
    2326          160 : release_structures (void)
    2327              : {
    2328         1523 :   for (vector<function_info *>::iterator it = functions.begin ();
    2329         1523 :        it != functions.end (); it++)
    2330         1363 :     delete (*it);
    2331              : 
    2332          396 :   for (vector<const char *> *lines : source_lines)
    2333              :     {
    2334          236 :       if (lines)
    2335       102529 :         for (const char *line : *lines)
    2336       102293 :           free (const_cast <char*> (line));
    2337          236 :       delete (lines);
    2338              :     }
    2339          160 :   source_lines.resize (0);
    2340              : 
    2341          175 :   for (fnfilter &filter : filters)
    2342           15 :     regfree (&filter.regex);
    2343              : 
    2344          160 :   sources.resize (0);
    2345          160 :   names.resize (0);
    2346          160 :   functions.resize (0);
    2347          160 :   filters.resize (0);
    2348          160 :   ident_to_fn.clear ();
    2349          160 : }
    2350              : 
    2351              : /* Generate the names of the graph and data files.  If OBJECT_DIRECTORY
    2352              :    is not specified, these are named from FILE_NAME sans extension.  If
    2353              :    OBJECT_DIRECTORY is specified and is a directory, the files are in that
    2354              :    directory, but named from the basename of the FILE_NAME, sans extension.
    2355              :    Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
    2356              :    and the data files are named from that.  */
    2357              : 
    2358              : static void
    2359          160 : create_file_names (const char *file_name)
    2360              : {
    2361          160 :   char *cptr;
    2362          160 :   char *name;
    2363          160 :   int length = strlen (file_name);
    2364          160 :   int base;
    2365              : 
    2366              :   /* Free previous file names.  */
    2367          160 :   free (bbg_file_name);
    2368          160 :   free (da_file_name);
    2369          160 :   da_file_name = bbg_file_name = NULL;
    2370          160 :   bbg_file_time = 0;
    2371          160 :   bbg_stamp = 0;
    2372              : 
    2373          160 :   if (object_directory && object_directory[0])
    2374              :     {
    2375            0 :       struct stat status;
    2376              : 
    2377            0 :       length += strlen (object_directory) + 2;
    2378            0 :       name = XNEWVEC (char, length);
    2379            0 :       name[0] = 0;
    2380              : 
    2381            0 :       base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
    2382            0 :       strcat (name, object_directory);
    2383            0 :       if (base && (!IS_DIR_SEPARATOR (name[strlen (name) - 1])))
    2384            0 :         strcat (name, "/");
    2385              :     }
    2386              :   else
    2387              :     {
    2388          160 :       name = XNEWVEC (char, length + 1);
    2389          160 :       strcpy (name, file_name);
    2390          160 :       base = 0;
    2391              :     }
    2392              : 
    2393          160 :   if (base)
    2394              :     {
    2395              :       /* Append source file name.  */
    2396            0 :       const char *cptr = lbasename (file_name);
    2397            0 :       strcat (name, cptr ? cptr : file_name);
    2398              :     }
    2399              : 
    2400              :   /* Remove the extension.  */
    2401          160 :   cptr = strrchr (const_cast<char *> (lbasename (name)), '.');
    2402          160 :   if (cptr)
    2403          160 :     *cptr = 0;
    2404              : 
    2405          160 :   length = strlen (name);
    2406              : 
    2407          160 :   bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
    2408          160 :   strcpy (bbg_file_name, name);
    2409          160 :   strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
    2410              : 
    2411          160 :   da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
    2412          160 :   strcpy (da_file_name, name);
    2413          160 :   strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
    2414              : 
    2415          160 :   free (name);
    2416          160 :   return;
    2417              : }
    2418              : 
    2419              : /* Find or create a source file structure for FILE_NAME. Copies
    2420              :    FILE_NAME on creation */
    2421              : 
    2422              : static unsigned
    2423        10904 : find_source (const char *file_name)
    2424              : {
    2425        10904 :   char *canon;
    2426        10904 :   unsigned idx;
    2427        10904 :   struct stat status;
    2428              : 
    2429        10904 :   if (!file_name)
    2430            0 :     file_name = "<unknown>";
    2431              : 
    2432        10904 :   name_map needle;
    2433        10904 :   needle.name = file_name;
    2434              : 
    2435        10904 :   vector<name_map>::iterator it = std::find (names.begin (), names.end (),
    2436              :                                              needle);
    2437        10904 :   if (it != names.end ())
    2438              :     {
    2439        10665 :       idx = it->src;
    2440        10665 :       goto check_date;
    2441              :     }
    2442              : 
    2443              :   /* Not found, try the canonical name. */
    2444          239 :   canon = canonicalize_name (file_name);
    2445          239 :   needle.name = canon;
    2446          239 :   it = std::find (names.begin (), names.end (), needle);
    2447          239 :   if (it == names.end ())
    2448              :     {
    2449              :       /* Not found with canonical name, create a new source.  */
    2450          238 :       source_info *src;
    2451              : 
    2452          238 :       idx = sources.size ();
    2453          238 :       needle = name_map (canon, idx);
    2454          238 :       names.push_back (needle);
    2455              : 
    2456          238 :       sources.push_back (source_info ());
    2457          238 :       src = &sources.back ();
    2458          238 :       src->name = canon;
    2459          238 :       src->coverage.name = src->name;
    2460          238 :       src->index = idx;
    2461          238 :       if (source_length
    2462              : #if HAVE_DOS_BASED_FILE_SYSTEM
    2463              :           /* You lose if separators don't match exactly in the
    2464              :              prefix.  */
    2465              :           && !strncasecmp (source_prefix, src->coverage.name, source_length)
    2466              : #else
    2467            0 :           && !strncmp (source_prefix, src->coverage.name, source_length)
    2468              : #endif
    2469            0 :           && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
    2470            0 :         src->coverage.name += source_length + 1;
    2471          238 :       if (!stat (src->name, &status))
    2472          235 :         src->file_time = status.st_mtime;
    2473              :     }
    2474              :   else
    2475            1 :     idx = it->src;
    2476              : 
    2477          239 :   needle.name = file_name;
    2478          239 :   if (std::find (names.begin (), names.end (), needle) == names.end ())
    2479              :     {
    2480              :       /* Append the non-canonical name.  */
    2481            1 :       names.push_back (name_map (xstrdup (file_name), idx));
    2482              :     }
    2483              : 
    2484              :   /* Resort the name map.  */
    2485          239 :   std::sort (names.begin (), names.end ());
    2486              : 
    2487        10904 :  check_date:
    2488        10904 :   if (sources[idx].file_time > bbg_file_time)
    2489              :     {
    2490            0 :       static int info_emitted;
    2491              : 
    2492            0 :       fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
    2493              :                file_name, bbg_file_name);
    2494            0 :       if (!info_emitted)
    2495              :         {
    2496            0 :           fnotice (stderr,
    2497              :                    "(the message is displayed only once per source file)\n");
    2498            0 :           info_emitted = 1;
    2499              :         }
    2500            0 :       sources[idx].file_time = 0;
    2501              :     }
    2502              : 
    2503        10904 :   return idx;
    2504              : }
    2505              : 
    2506              : /* Read the notes file.  Save functions to FUNCTIONS global vector.  */
    2507              : 
    2508              : static void
    2509          160 : read_graph_file (void)
    2510              : {
    2511          160 :   unsigned version;
    2512          160 :   unsigned current_tag = 0;
    2513          160 :   unsigned tag;
    2514              : 
    2515          160 :   if (!gcov_open (bbg_file_name, 1))
    2516              :     {
    2517            0 :       fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
    2518            0 :       return_code = 1;
    2519            0 :       return;
    2520              :     }
    2521          160 :   bbg_file_time = gcov_time ();
    2522          160 :   if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
    2523              :     {
    2524            0 :       fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
    2525            0 :       return_code = 2;
    2526            0 :       gcov_close ();
    2527            0 :       return;
    2528              :     }
    2529              : 
    2530          160 :   version = gcov_read_unsigned ();
    2531          160 :   if (version != GCOV_VERSION)
    2532              :     {
    2533            0 :       char v[4], e[4];
    2534              : 
    2535            0 :       GCOV_UNSIGNED2STRING (v, version);
    2536            0 :       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
    2537              : 
    2538            0 :       fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
    2539              :                bbg_file_name, v, e);
    2540            0 :       return_code = 3;
    2541              :     }
    2542          160 :   bbg_stamp = gcov_read_unsigned ();
    2543              :   /* Read checksum.  */
    2544          160 :   gcov_read_unsigned ();
    2545          160 :   bbg_cwd = xstrdup (gcov_read_string ());
    2546          160 :   bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
    2547              : 
    2548          160 :   function_info *fn = NULL;
    2549        24519 :   while ((tag = gcov_read_unsigned ()))
    2550              :     {
    2551        24359 :       unsigned length = gcov_read_unsigned ();
    2552        24359 :       gcov_position_t base = gcov_position ();
    2553              : 
    2554        24359 :       if (tag == GCOV_TAG_FUNCTION)
    2555              :         {
    2556         1450 :           char *function_name;
    2557         1450 :           unsigned ident;
    2558         1450 :           unsigned lineno_checksum, cfg_checksum;
    2559              : 
    2560         1450 :           ident = gcov_read_unsigned ();
    2561         1450 :           lineno_checksum = gcov_read_unsigned ();
    2562         1450 :           cfg_checksum = gcov_read_unsigned ();
    2563         1450 :           function_name = xstrdup (gcov_read_string ());
    2564         1450 :           unsigned artificial = gcov_read_unsigned ();
    2565         1450 :           unsigned src_idx = find_source (gcov_read_string ());
    2566         1450 :           unsigned start_line = gcov_read_unsigned ();
    2567         1450 :           unsigned start_column = gcov_read_unsigned ();
    2568         1450 :           unsigned end_line = gcov_read_unsigned ();
    2569         1450 :           unsigned end_column = gcov_read_unsigned ();
    2570              : 
    2571         1450 :           fn = new function_info ();
    2572              : 
    2573         1450 :           fn->m_name = function_name;
    2574         1450 :           fn->ident = ident;
    2575         1450 :           fn->lineno_checksum = lineno_checksum;
    2576         1450 :           fn->cfg_checksum = cfg_checksum;
    2577         1450 :           fn->src = src_idx;
    2578         1450 :           fn->start_line = start_line;
    2579         1450 :           fn->start_column = start_column;
    2580         1450 :           fn->end_line = end_line;
    2581         1450 :           fn->end_column = end_column;
    2582         1450 :           fn->artificial = artificial;
    2583              : 
    2584         1450 :           current_tag = tag;
    2585              : 
    2586              :           /* This is separate from flag_demangled_names to support filtering on
    2587              :              mangled names while printing demangled names, or filtering on
    2588              :              demangled names while printing mangled names.  An independent flag
    2589              :              makes sure the function selection does not change even if
    2590              :              demangling is turned on/off.  */
    2591         1450 :           const char *fname = function_name;
    2592         1450 :           if (flag_filter_on_demangled)
    2593           12 :             fname = fn->get_demangled_name ();
    2594              : 
    2595         1450 :           bool keep = default_keep;
    2596         1522 :           for (const fnfilter &fn : filters)
    2597           72 :             if (regexec (&fn.regex, fname, 0, nullptr, 0) == 0)
    2598           26 :               keep = fn.keep;
    2599              : 
    2600         1450 :           if (keep)
    2601              :             {
    2602         1408 :               functions.push_back (fn);
    2603         1408 :               ident_to_fn[ident] = fn;
    2604              :             }
    2605              :         }
    2606        22909 :       else if (fn && tag == GCOV_TAG_BLOCKS)
    2607              :         {
    2608         1450 :           if (!fn->blocks.empty ())
    2609            0 :             fnotice (stderr, "%s:already seen blocks for '%s'\n",
    2610              :                      bbg_file_name, fn->get_name ());
    2611              :           else
    2612         1450 :             fn->blocks.resize (gcov_read_unsigned ());
    2613              :         }
    2614        21459 :       else if (fn && tag == GCOV_TAG_ARCS)
    2615              :         {
    2616        11366 :           unsigned src = gcov_read_unsigned ();
    2617        11366 :           fn->blocks[src].id = src;
    2618        11366 :           unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
    2619        11366 :           block_info *src_blk = &fn->blocks[src];
    2620        11366 :           unsigned mark_catches = 0;
    2621        11366 :           struct arc_info *arc;
    2622              : 
    2623        11366 :           if (src >= fn->blocks.size () || fn->blocks[src].succ)
    2624            0 :             goto corrupt;
    2625              : 
    2626        28482 :           while (num_dests--)
    2627              :             {
    2628        17116 :               unsigned dest = gcov_read_unsigned ();
    2629        17116 :               unsigned flags = gcov_read_unsigned ();
    2630              : 
    2631        17116 :               if (dest >= fn->blocks.size ())
    2632            0 :                 goto corrupt;
    2633        17116 :               arc = XCNEW (arc_info);
    2634              : 
    2635        17116 :               arc->dst = &fn->blocks[dest];
    2636              :               /* Set id in order to find EXIT_BLOCK.  */
    2637        17116 :               arc->dst->id = dest;
    2638        17116 :               arc->src = src_blk;
    2639              : 
    2640        17116 :               arc->count = 0;
    2641        17116 :               arc->count_valid = 0;
    2642        17116 :               arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
    2643        17116 :               arc->fake = !!(flags & GCOV_ARC_FAKE);
    2644        17116 :               arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
    2645        17116 :               arc->true_value = !!(flags & GCOV_ARC_TRUE);
    2646        17116 :               arc->false_value = !!(flags & GCOV_ARC_FALSE);
    2647        17116 :               arc->suppressed = 0;
    2648              : 
    2649        17116 :               arc->succ_next = src_blk->succ;
    2650        17116 :               src_blk->succ = arc;
    2651        17116 :               src_blk->num_succ++;
    2652              : 
    2653        17116 :               arc->pred_next = fn->blocks[dest].pred;
    2654        17116 :               fn->blocks[dest].pred = arc;
    2655        17116 :               fn->blocks[dest].num_pred++;
    2656              : 
    2657        17116 :               if (arc->fake)
    2658              :                 {
    2659         3225 :                   if (src)
    2660              :                     {
    2661              :                       /* Exceptional exit from this function, the
    2662              :                          source block must be a call.  */
    2663         3208 :                       fn->blocks[src].is_call_site = 1;
    2664         3208 :                       arc->is_call_non_return = 1;
    2665         3208 :                       mark_catches = 1;
    2666              :                     }
    2667              :                   else
    2668              :                     {
    2669              :                       /* Non-local return from a callee of this
    2670              :                          function.  The destination block is a setjmp.  */
    2671           17 :                       arc->is_nonlocal_return = 1;
    2672           17 :                       fn->blocks[dest].is_nonlocal_return = 1;
    2673              :                     }
    2674              :                 }
    2675              : 
    2676        17116 :               if (!arc->on_tree)
    2677         7200 :                 fn->counts.push_back (0);
    2678              :             }
    2679              : 
    2680        11366 :           if (mark_catches)
    2681              :             {
    2682              :               /* We have a fake exit from this block.  The other
    2683              :                  non-fall through exits must be to catch handlers.
    2684              :                  Mark them as catch arcs.  */
    2685              : 
    2686         9661 :               for (arc = src_blk->succ; arc; arc = arc->succ_next)
    2687         6453 :                 if (!arc->fake && !arc->fall_through)
    2688              :                   {
    2689          301 :                     arc->is_throw = 1;
    2690          301 :                     fn->has_catch = 1;
    2691              :                   }
    2692              :             }
    2693              :         }
    2694        10093 :       else if (fn && tag == GCOV_TAG_SUPPRESS)
    2695              :         {
    2696          285 :           const unsigned nblocks = GCOV_TAG_SUPPRESS_NUM (length);
    2697          285 :           if (!fn->suppressed_blocks.empty ())
    2698            0 :             fnotice (stderr, "%s:already seen suppressed blocks for '%s'\n",
    2699              :                      bbg_file_name, fn->get_name ());
    2700          285 :           fn->suppressed_blocks.resize (fn->blocks.size (), false);
    2701         1427 :           for (unsigned i = 0; i != nblocks; ++i)
    2702              :             {
    2703          857 :               const unsigned idx = gcov_read_unsigned ();
    2704          857 :               if (idx >= fn->blocks.size ())
    2705            0 :                 goto corrupt;
    2706          857 :               fn->suppressed_blocks[idx] = true;
    2707              :             }
    2708              :         }
    2709         9808 :       else if (fn && tag == GCOV_TAG_CONDS)
    2710              :         {
    2711          144 :           unsigned num_dests = GCOV_TAG_CONDS_NUM (length);
    2712              : 
    2713          144 :           if (!fn->conditions.empty ())
    2714            0 :             fnotice (stderr, "%s:already seen conditions for '%s'\n",
    2715              :                      bbg_file_name, fn->get_name ());
    2716              :           else
    2717          144 :             fn->conditions.resize (num_dests);
    2718              : 
    2719          389 :           for (unsigned i = 0; i < num_dests; ++i)
    2720              :             {
    2721          245 :               unsigned idx = gcov_read_unsigned ();
    2722              : 
    2723          245 :               if (idx >= fn->blocks.size ())
    2724            0 :                 goto corrupt;
    2725              : 
    2726          245 :               condition_info *info = &fn->blocks[idx].conditions;
    2727          245 :               info->n_terms = gcov_read_unsigned ();
    2728          245 :               fn->conditions[i] = info;
    2729              :             }
    2730              :     }
    2731         9664 :       else if (fn && tag == GCOV_TAG_PATHS)
    2732              :         {
    2733          295 :           const unsigned npaths = gcov_read_unsigned ();
    2734          295 :           const size_t nbits = path_info::bucketsize;
    2735          295 :           const size_t nbuckets = (npaths + (nbits - 1)) / nbits;
    2736          295 :           fn->paths.covered.assign (nbuckets, 0);
    2737          295 :         }
    2738         9369 :       else if (fn && tag == GCOV_TAG_LINES)
    2739              :         {
    2740         9369 :           unsigned blockno = gcov_read_unsigned ();
    2741         9369 :           block_info *block = &fn->blocks[blockno];
    2742              : 
    2743         9369 :           if (blockno >= fn->blocks.size ())
    2744            0 :             goto corrupt;
    2745              : 
    2746        52419 :           while (true)
    2747              :             {
    2748        30894 :               unsigned lineno = gcov_read_unsigned ();
    2749              : 
    2750        30894 :               if (lineno)
    2751        12071 :                 block->locations.back ().lines.push_back (lineno);
    2752              :               else
    2753              :                 {
    2754        18823 :                   const char *file_name = gcov_read_string ();
    2755              : 
    2756        18823 :                   if (!file_name)
    2757              :                     break;
    2758         9454 :                   block->locations.push_back (block_location_info
    2759         9454 :                                               (find_source (file_name)));
    2760              :                 }
    2761        21525 :             }
    2762         9369 :         }
    2763            0 :       else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
    2764              :         {
    2765            0 :           fn = NULL;
    2766            0 :           current_tag = 0;
    2767              :         }
    2768        24359 :       gcov_sync (base, length);
    2769        24359 :       if (gcov_is_error ())
    2770              :         {
    2771            0 :         corrupt:;
    2772            0 :           fnotice (stderr, "%s:corrupted\n", bbg_file_name);
    2773            0 :           return_code = 4;
    2774            0 :           break;
    2775              :         }
    2776              :     }
    2777          160 :   gcov_close ();
    2778              : 
    2779          160 :   if (functions.empty ())
    2780            3 :     fnotice (stderr, "%s:no functions found\n", bbg_file_name);
    2781              : }
    2782              : 
    2783              : /* Reads profiles from the count file and attach to each
    2784              :    function. Return nonzero if fatal error.  */
    2785              : 
    2786              : static int
    2787          160 : read_count_file (void)
    2788              : {
    2789          160 :   unsigned ix;
    2790          160 :   unsigned version;
    2791          160 :   unsigned tag;
    2792          160 :   function_info *fn = NULL;
    2793          160 :   int error = 0;
    2794          160 :   map<unsigned, function_info *>::iterator it;
    2795              : 
    2796          160 :   if (!gcov_open (da_file_name, 1))
    2797              :     {
    2798           14 :       fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
    2799              :                da_file_name);
    2800           14 :       no_data_file = 1;
    2801           14 :       return 0;
    2802              :     }
    2803          146 :   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
    2804              :     {
    2805            0 :       fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
    2806            0 :       return_code = 2;
    2807            0 :     cleanup:;
    2808            0 :       gcov_close ();
    2809            0 :       return 1;
    2810              :     }
    2811          146 :   version = gcov_read_unsigned ();
    2812          146 :   if (version != GCOV_VERSION)
    2813              :     {
    2814            0 :       char v[4], e[4];
    2815              : 
    2816            0 :       GCOV_UNSIGNED2STRING (v, version);
    2817            0 :       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
    2818              : 
    2819            0 :       fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
    2820              :                da_file_name, v, e);
    2821            0 :       return_code = 3;
    2822              :     }
    2823          146 :   tag = gcov_read_unsigned ();
    2824          146 :   if (tag != bbg_stamp)
    2825              :     {
    2826            0 :       fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
    2827            0 :       return_code = 5;
    2828            0 :       goto cleanup;
    2829              :     }
    2830              : 
    2831              :   /* Read checksum.  */
    2832          146 :   gcov_read_unsigned ();
    2833              : 
    2834         3299 :   while ((tag = gcov_read_unsigned ()))
    2835              :     {
    2836         3007 :       unsigned length = gcov_read_unsigned ();
    2837         3007 :       int read_length = (int)length;
    2838         3007 :       unsigned long base = gcov_position ();
    2839              : 
    2840         3007 :       if (tag == GCOV_TAG_OBJECT_SUMMARY)
    2841              :         {
    2842          146 :           struct gcov_summary summary;
    2843          146 :           gcov_read_summary (&summary);
    2844          146 :           object_runs = summary.runs;
    2845              :         }
    2846         2861 :       else if (tag == GCOV_TAG_FUNCTION && !length)
    2847              :         ; /* placeholder  */
    2848         2861 :       else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
    2849              :         {
    2850         1338 :           unsigned ident;
    2851         1338 :           ident = gcov_read_unsigned ();
    2852         1338 :           fn = NULL;
    2853         1338 :           it = ident_to_fn.find (ident);
    2854         1338 :           if (it != ident_to_fn.end ())
    2855         1296 :             fn = it->second;
    2856              : 
    2857         1296 :           if (!fn)
    2858              :             ;
    2859         1296 :           else if (gcov_read_unsigned () != fn->lineno_checksum
    2860         1296 :                    || gcov_read_unsigned () != fn->cfg_checksum)
    2861              :             {
    2862            0 :             mismatch:;
    2863            0 :               fnotice (stderr, "%s:profile mismatch for '%s'\n",
    2864              :                        da_file_name, fn->get_name ());
    2865            0 :               goto cleanup;
    2866              :             }
    2867              :         }
    2868         1523 :       else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_CONDS) && fn)
    2869              :         {
    2870          120 :           length = abs (read_length);
    2871          120 :           if (length != GCOV_TAG_COUNTER_LENGTH (2 * fn->conditions.size ()))
    2872            0 :               goto mismatch;
    2873              : 
    2874          120 :           if (read_length > 0)
    2875              :             {
    2876          358 :               for (ix = 0; ix != fn->conditions.size (); ix++)
    2877              :                 {
    2878          240 :                   fn->conditions[ix]->truev  |= gcov_read_counter ();
    2879          240 :                   fn->conditions[ix]->falsev |= gcov_read_counter ();
    2880              :                 }
    2881              :             }
    2882              :         }
    2883         1403 :       else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
    2884              :         {
    2885         1142 :           length = abs (read_length);
    2886         1142 :           if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
    2887            0 :             goto mismatch;
    2888              : 
    2889         1142 :           if (read_length > 0)
    2890         5897 :             for (ix = 0; ix != fn->counts.size (); ix++)
    2891         4863 :               fn->counts[ix] += gcov_read_counter ();
    2892              :         }
    2893          261 :       else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_PATHS) && fn)
    2894              :         {
    2895          213 :           vector<gcov_type_unsigned> &covered = fn->paths.covered;
    2896          213 :           length = abs (read_length);
    2897          213 :           if (length != GCOV_TAG_COUNTER_LENGTH (covered.size ()))
    2898            0 :             goto mismatch;
    2899              : 
    2900          213 :           if (read_length > 0)
    2901          276 :             for (ix = 0; ix != covered.size (); ix++)
    2902          142 :               covered[ix] = gcov_read_counter ();
    2903              :         }
    2904         3007 :       if (read_length < 0)
    2905              :         read_length = 0;
    2906         3007 :       gcov_sync (base, read_length);
    2907         3007 :       if ((error = gcov_is_error ()))
    2908              :         {
    2909            0 :           fnotice (stderr,
    2910              :                    error < 0
    2911              :                    ? N_("%s:overflowed\n")
    2912              :                    : N_("%s:corrupted\n"),
    2913              :                    da_file_name);
    2914            0 :           return_code = 4;
    2915            0 :           goto cleanup;
    2916              :         }
    2917              :     }
    2918              : 
    2919          146 :   gcov_close ();
    2920          146 :   return 0;
    2921              : }
    2922              : 
    2923              : /* Solve the flow graph. Propagate counts from the instrumented arcs
    2924              :    to the blocks and the uninstrumented arcs.  */
    2925              : 
    2926              : static void
    2927         1363 : solve_flow_graph (function_info *fn)
    2928              : {
    2929         1363 :   unsigned ix;
    2930         1363 :   arc_info *arc;
    2931         1363 :   gcov_type *count_ptr = &fn->counts.front ();
    2932         1363 :   block_info *blk;
    2933         1363 :   block_info *valid_blocks = NULL;    /* valid, but unpropagated blocks.  */
    2934         1363 :   block_info *invalid_blocks = NULL;  /* invalid, but inferable blocks.  */
    2935              : 
    2936              :   /* The arcs were built in reverse order.  Fix that now.  */
    2937        13774 :   for (ix = fn->blocks.size (); ix--;)
    2938              :     {
    2939        12411 :       arc_info *arc_p, *arc_n;
    2940              : 
    2941        29110 :       for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
    2942        16699 :            arc_p = arc, arc = arc_n)
    2943              :         {
    2944        16699 :           arc_n = arc->succ_next;
    2945        16699 :           arc->succ_next = arc_p;
    2946              :         }
    2947        12411 :       fn->blocks[ix].succ = arc_p;
    2948              : 
    2949        29110 :       for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
    2950        16699 :            arc_p = arc, arc = arc_n)
    2951              :         {
    2952        16699 :           arc_n = arc->pred_next;
    2953        16699 :           arc->pred_next = arc_p;
    2954              :         }
    2955        12411 :       fn->blocks[ix].pred = arc_p;
    2956              :     }
    2957              : 
    2958         1363 :   if (fn->blocks.size () < 2)
    2959            0 :     fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
    2960              :              bbg_file_name, fn->get_name ());
    2961              :   else
    2962              :     {
    2963         1363 :       if (fn->blocks[ENTRY_BLOCK].num_pred)
    2964            0 :         fnotice (stderr, "%s:'%s' has arcs to entry block\n",
    2965              :                  bbg_file_name, fn->get_name ());
    2966              :       else
    2967              :         /* We can't deduce the entry block counts from the lack of
    2968              :            predecessors.  */
    2969         1363 :         fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
    2970              : 
    2971         1363 :       if (fn->blocks[EXIT_BLOCK].num_succ)
    2972            0 :         fnotice (stderr, "%s:'%s' has arcs from exit block\n",
    2973              :                  bbg_file_name, fn->get_name ());
    2974              :       else
    2975              :         /* Likewise, we can't deduce exit block counts from the lack
    2976              :            of its successors.  */
    2977         1363 :         fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
    2978              :     }
    2979              : 
    2980              :   /* Propagate the measured counts, this must be done in the same
    2981              :      order as the code in profile.cc  */
    2982        13774 :   for (unsigned i = 0; i < fn->blocks.size (); i++)
    2983              :     {
    2984        12411 :       blk = &fn->blocks[i];
    2985        12411 :       block_info const *prev_dst = NULL;
    2986        12411 :       int out_of_order = 0;
    2987        12411 :       int non_fake_succ = 0;
    2988              : 
    2989        29110 :       for (arc = blk->succ; arc; arc = arc->succ_next)
    2990              :         {
    2991        16699 :           if (!arc->fake)
    2992        13571 :             non_fake_succ++;
    2993              : 
    2994        16699 :           if (!arc->on_tree)
    2995              :             {
    2996         7014 :               if (count_ptr)
    2997         7014 :                 arc->count = *count_ptr++;
    2998         7014 :               arc->count_valid = 1;
    2999         7014 :               blk->num_succ--;
    3000         7014 :               arc->dst->num_pred--;
    3001              :             }
    3002        16699 :           if (prev_dst && prev_dst > arc->dst)
    3003        16699 :             out_of_order = 1;
    3004        16699 :           prev_dst = arc->dst;
    3005              :         }
    3006        12411 :       if (non_fake_succ == 1)
    3007              :         {
    3008              :           /* If there is only one non-fake exit, it is an
    3009              :              unconditional branch.  */
    3010        20047 :           for (arc = blk->succ; arc; arc = arc->succ_next)
    3011        11314 :             if (!arc->fake)
    3012              :               {
    3013         8733 :                 arc->is_unconditional = 1;
    3014              :                 /* If this block is instrumenting a call, it might be
    3015              :                    an artificial block. It is not artificial if it has
    3016              :                    a non-fallthrough exit, or the destination of this
    3017              :                    arc has more than one entry.  Mark the destination
    3018              :                    block as a return site, if none of those conditions
    3019              :                    hold.  */
    3020         8733 :                 if (blk->is_call_site && arc->fall_through
    3021         2557 :                     && arc->dst->pred == arc && !arc->pred_next)
    3022         2166 :                   arc->dst->is_call_return = 1;
    3023              :               }
    3024              :         }
    3025              : 
    3026              :       /* Sort the successor arcs into ascending dst order. profile.cc
    3027              :          normally produces arcs in the right order, but sometimes with
    3028              :          one or two out of order.  We're not using a particularly
    3029              :          smart sort.  */
    3030        12411 :       if (out_of_order)
    3031              :         {
    3032              :           arc_info *start = blk->succ;
    3033              :           unsigned changes = 1;
    3034              : 
    3035        10003 :           while (changes)
    3036              :             {
    3037              :               arc_info *arc, *arc_p, *arc_n;
    3038              : 
    3039              :               changes = 0;
    3040        15892 :               for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
    3041              :                 {
    3042         9120 :                   if (arc->dst > arc_n->dst)
    3043              :                     {
    3044         4522 :                       changes = 1;
    3045         4522 :                       if (arc_p)
    3046         1010 :                         arc_p->succ_next = arc_n;
    3047              :                       else
    3048              :                         start = arc_n;
    3049         4522 :                       arc->succ_next = arc_n->succ_next;
    3050         4522 :                       arc_n->succ_next = arc;
    3051         4522 :                       arc_p = arc_n;
    3052              :                     }
    3053              :                   else
    3054              :                     {
    3055              :                       arc_p = arc;
    3056              :                       arc = arc_n;
    3057              :                     }
    3058              :                 }
    3059              :             }
    3060         3231 :           blk->succ = start;
    3061              :         }
    3062              : 
    3063              :       /* Place it on the invalid chain, it will be ignored if that's
    3064              :          wrong.  */
    3065        12411 :       blk->invalid_chain = 1;
    3066        12411 :       blk->chain = invalid_blocks;
    3067        12411 :       invalid_blocks = blk;
    3068              :     }
    3069              : 
    3070         6312 :   while (invalid_blocks || valid_blocks)
    3071              :     {
    3072        21507 :       while ((blk = invalid_blocks))
    3073              :         {
    3074        16558 :           gcov_type total = 0;
    3075        16558 :           const arc_info *arc;
    3076              : 
    3077        16558 :           invalid_blocks = blk->chain;
    3078        16558 :           blk->invalid_chain = 0;
    3079        16558 :           if (!blk->num_succ)
    3080         4473 :             for (arc = blk->succ; arc; arc = arc->succ_next)
    3081         2369 :               total += arc->count;
    3082        14454 :           else if (!blk->num_pred)
    3083        25842 :             for (arc = blk->pred; arc; arc = arc->pred_next)
    3084        15535 :               total += arc->count;
    3085              :           else
    3086         4147 :             continue;
    3087              : 
    3088        12411 :           blk->count = total;
    3089        12411 :           blk->count_valid = 1;
    3090        12411 :           blk->chain = valid_blocks;
    3091        12411 :           blk->valid_chain = 1;
    3092        12411 :           valid_blocks = blk;
    3093              :         }
    3094        17788 :       while ((blk = valid_blocks))
    3095              :         {
    3096        12839 :           gcov_type total;
    3097        12839 :           arc_info *arc, *inv_arc;
    3098              : 
    3099        12839 :           valid_blocks = blk->chain;
    3100        12839 :           blk->valid_chain = 0;
    3101        12839 :           if (blk->num_succ == 1)
    3102              :             {
    3103         8944 :               block_info *dst;
    3104              : 
    3105         8944 :               total = blk->count;
    3106         8944 :               inv_arc = NULL;
    3107        23274 :               for (arc = blk->succ; arc; arc = arc->succ_next)
    3108              :                 {
    3109        14330 :                   total -= arc->count;
    3110        14330 :                   if (!arc->count_valid)
    3111         8944 :                     inv_arc = arc;
    3112              :                 }
    3113         8944 :               dst = inv_arc->dst;
    3114         8944 :               inv_arc->count_valid = 1;
    3115         8944 :               inv_arc->count = total;
    3116         8944 :               blk->num_succ--;
    3117         8944 :               dst->num_pred--;
    3118         8944 :               if (dst->count_valid)
    3119              :                 {
    3120          206 :                   if (dst->num_pred == 1 && !dst->valid_chain)
    3121              :                     {
    3122           66 :                       dst->chain = valid_blocks;
    3123           66 :                       dst->valid_chain = 1;
    3124           66 :                       valid_blocks = dst;
    3125              :                     }
    3126              :                 }
    3127              :               else
    3128              :                 {
    3129         8738 :                   if (!dst->num_pred && !dst->invalid_chain)
    3130              :                     {
    3131         3950 :                       dst->chain = invalid_blocks;
    3132         3950 :                       dst->invalid_chain = 1;
    3133         3950 :                       invalid_blocks = dst;
    3134              :                     }
    3135              :                 }
    3136              :             }
    3137        12839 :           if (blk->num_pred == 1)
    3138              :             {
    3139          741 :               block_info *src;
    3140              : 
    3141          741 :               total = blk->count;
    3142          741 :               inv_arc = NULL;
    3143         1905 :               for (arc = blk->pred; arc; arc = arc->pred_next)
    3144              :                 {
    3145         1164 :                   total -= arc->count;
    3146         1164 :                   if (!arc->count_valid)
    3147          741 :                     inv_arc = arc;
    3148              :                 }
    3149          741 :               src = inv_arc->src;
    3150          741 :               inv_arc->count_valid = 1;
    3151          741 :               inv_arc->count = total;
    3152          741 :               blk->num_pred--;
    3153          741 :               src->num_succ--;
    3154          741 :               if (src->count_valid)
    3155              :                 {
    3156          401 :                   if (src->num_succ == 1 && !src->valid_chain)
    3157              :                     {
    3158          362 :                       src->chain = valid_blocks;
    3159          362 :                       src->valid_chain = 1;
    3160          362 :                       valid_blocks = src;
    3161              :                     }
    3162              :                 }
    3163              :               else
    3164              :                 {
    3165          340 :                   if (!src->num_succ && !src->invalid_chain)
    3166              :                     {
    3167          197 :                       src->chain = invalid_blocks;
    3168          197 :                       src->invalid_chain = 1;
    3169          197 :                       invalid_blocks = src;
    3170              :                     }
    3171              :                 }
    3172              :             }
    3173              :         }
    3174              :     }
    3175              : 
    3176              :   /* If the graph has been correctly solved, every block will have a
    3177              :      valid count.  */
    3178        13774 :   for (unsigned i = 0; i < fn->blocks.size (); i++)
    3179        12411 :     if (!fn->blocks[i].count_valid)
    3180              :       {
    3181            0 :         fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
    3182              :                  bbg_file_name, fn->get_name ());
    3183            0 :         break;
    3184              :       }
    3185         1363 : }
    3186              : 
    3187              : /* Find the prime paths of the function from the CFG and add to FN
    3188              :    using the same function as gcc.  It relies on gcc recording the CFG
    3189              :    faithfully.  Storing the paths explicitly takes up way too much
    3190              :    space to be practical, but this means we need to recompute the
    3191              :    (exact) same paths in gcov.  This should give paths in
    3192              :    lexicographical order so that the nth path in gcc is the nth path
    3193              :    in gcov.  ENTRY_BLOCK and EXIT_BLOCK are both removed from all
    3194              :    paths.  */
    3195              : static void
    3196         1363 : find_prime_paths (function_info *fn)
    3197              : {
    3198         1363 :   if (!flag_prime_paths)
    3199         1088 :     return;
    3200              : 
    3201              :   /* If paths.covered being empty then this function was not
    3202              :      instrumented, probably because it exceeded #-of-paths limit.  In
    3203              :      this case we don't want to find the prime paths as it will take
    3204              :      too long, and covered paths are not measured.  */
    3205          278 :   if (fn->paths.covered.empty ())
    3206              :     return;
    3207              : 
    3208          275 :   struct graph *cfg = new_graph (fn->blocks.size ());
    3209         2899 :   for (block_info &block : fn->blocks)
    3210              :     {
    3211         2624 :       cfg->vertices[block.id].data = &block;
    3212         6374 :       for (arc_info *arc = block.succ; arc; arc = arc->succ_next)
    3213         3750 :         if (!arc->fake)
    3214         3264 :           add_edge (cfg, arc->src->id, arc->dst->id)->data = arc;
    3215              :     }
    3216              : 
    3217          275 :   vec<vec<int>> prime_paths (struct graph*, size_t);
    3218              :   /* TODO: Pass extra information in the PATH_TAG section.  In case
    3219              :      that is empty this might still need to be tunable should the
    3220              :      coverage be requested without instrumentation.  */
    3221          275 :   vec<vec<int>> paths = prime_paths (cfg, (size_t)-1);
    3222          550 :   fn->paths.paths.reserve (paths.length ());
    3223         2828 :   for (vec<int> &path : paths)
    3224              :     {
    3225         2003 :       const int *begin = path.begin ();
    3226         2003 :       const int *end = path.end ();
    3227         4006 :       if (begin != end && path.last () == EXIT_BLOCK)
    3228         1340 :         --end;
    3229         2003 :       if (begin != end && *begin == ENTRY_BLOCK)
    3230         1430 :         ++begin;
    3231              : 
    3232         2003 :       if (begin == end)
    3233           45 :         continue;
    3234              : 
    3235              :       /* If this is an isolated vertex because abnormal edges and fake
    3236              :          edges are removed, don't include it.  */
    3237         1979 :       if (end - begin == 1 && !cfg->vertices[*begin].succ
    3238           24 :           && !cfg->vertices[*begin].pred)
    3239           21 :         continue;
    3240              : 
    3241         1958 :       fn->paths.paths.emplace_back (begin, end);
    3242              :     }
    3243              : 
    3244          275 :   release_vec_vec (paths);
    3245          275 :   free_graph (cfg);
    3246              : }
    3247              : 
    3248              : /* Mark all the blocks only reachable via an incoming catch.  */
    3249              : 
    3250              : static void
    3251          112 : find_exception_blocks (function_info *fn)
    3252              : {
    3253          112 :   unsigned ix;
    3254          112 :   block_info **queue = XALLOCAVEC (block_info *, fn->blocks.size ());
    3255              : 
    3256              :   /* First mark all blocks as exceptional.  */
    3257         2046 :   for (ix = fn->blocks.size (); ix--;)
    3258         1934 :     fn->blocks[ix].exceptional = 1;
    3259              : 
    3260              :   /* Now mark all the blocks reachable via non-fake edges */
    3261          112 :   queue[0] = &fn->blocks[0];
    3262          112 :   queue[0]->exceptional = 0;
    3263         1284 :   for (ix = 1; ix;)
    3264              :     {
    3265         1172 :       block_info *block = queue[--ix];
    3266         1172 :       const arc_info *arc;
    3267              : 
    3268         3159 :       for (arc = block->succ; arc; arc = arc->succ_next)
    3269         1987 :         if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
    3270              :           {
    3271         1060 :             arc->dst->exceptional = 0;
    3272         1060 :             queue[ix++] = arc->dst;
    3273              :           }
    3274              :     }
    3275          112 : }
    3276              : 
    3277              : 
    3278              : /* Increment totals in COVERAGE according to arc ARC.  */
    3279              : 
    3280              : static void
    3281         1313 : add_branch_counts (coverage_info *coverage, const arc_info *arc)
    3282              : {
    3283         1313 :   if (arc->is_call_non_return)
    3284              :     {
    3285          381 :       coverage->calls++;
    3286          381 :       if (arc->suppressed)
    3287            0 :         coverage->calls_suppressed++;
    3288          381 :       else if (arc->src->count)
    3289          348 :         coverage->calls_executed++;
    3290              :     }
    3291          932 :   else if (!arc->is_unconditional)
    3292              :     {
    3293          376 :       coverage->branches++;
    3294          376 :       if (arc->src->count && !arc->suppressed)
    3295          374 :         coverage->branches_executed++;
    3296          376 :       if (arc->count && !arc->suppressed)
    3297          304 :         coverage->branches_taken++;
    3298          376 :       if (arc->suppressed)
    3299            0 :         coverage->branches_suppressed++;
    3300              :     }
    3301         1313 : }
    3302              : 
    3303              : /* Increment totals in COVERAGE according to block BLOCK.  */
    3304              : 
    3305              : static void
    3306         8128 : add_condition_counts (coverage_info *coverage, const block_info *block)
    3307              : {
    3308         8128 :   coverage->conditions += 2 * block->conditions.n_terms;
    3309         8128 :   if (block->suppressed)
    3310          824 :     coverage->conditions_suppressed += 2 * block->conditions.n_terms;
    3311              :   else
    3312         7304 :     coverage->conditions_covered += block->conditions.popcount ();
    3313         8128 : }
    3314              : 
    3315              : /* Increment path totals, number of paths and number of covered paths,
    3316              :    in COVERAGE according to FN.  */
    3317              : 
    3318              : static void
    3319         1363 : add_path_counts (coverage_info &coverage, const function_info &fn)
    3320              : {
    3321         1363 :   coverage.paths += fn.paths.path_count ();
    3322         1363 :   coverage.paths_covered += fn.paths.covered_paths ();
    3323         1363 :   coverage.paths_suppressed += fn.paths.suppressed_count ();
    3324         1363 : }
    3325              : 
    3326              : /* Format COUNT, if flag_human_readable_numbers is set, return it human
    3327              :    readable format.  */
    3328              : 
    3329              : static char const *
    3330         4788 : format_count (gcov_type count)
    3331              : {
    3332         4788 :   static char buffer[64];
    3333         4788 :   const char *units = " kMGTPEZY";
    3334              : 
    3335         4788 :   if (count < 1000 || !flag_human_readable_numbers)
    3336              :     {
    3337         4746 :       sprintf (buffer, "%" PRId64, count);
    3338         4746 :       return buffer;
    3339              :     }
    3340              : 
    3341              :   unsigned i;
    3342              :   gcov_type divisor = 1;
    3343           96 :   for (i = 0; units[i+1]; i++, divisor *= 1000)
    3344              :     {
    3345           96 :       if (count + divisor / 2 < 1000 * divisor)
    3346              :         break;
    3347              :     }
    3348           42 :   float r = 1.0f * count / divisor;
    3349           42 :   sprintf (buffer, "%.1f%c", r, units[i]);
    3350           42 :   return buffer;
    3351              : }
    3352              : 
    3353              : /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
    3354              :    count.  If DECIMAL_PLACES >= 0, format TOP/BOTTOM * 100 to DECIMAL_PLACES.
    3355              :    If DECIMAL_PLACES is zero, no decimal point is printed. Only print 100% when
    3356              :    TOP==BOTTOM and only print 0% when TOP=0.  If DECIMAL_PLACES < 0, then simply
    3357              :    format TOP.  Return pointer to a static string.  */
    3358              : 
    3359              : static char const *
    3360         6315 : format_gcov (gcov_type top, gcov_type bottom, int decimal_places)
    3361              : {
    3362         6315 :   static char buffer[20];
    3363              : 
    3364         1527 :   if (decimal_places >= 0)
    3365              :     {
    3366         1527 :       float ratio = bottom ? 100.0f * top / bottom : 0;
    3367              : 
    3368              :       /* Round up to 1% if there's a small non-zero value.  */
    3369         1518 :       if (ratio > 0.0f && ratio < 0.5f && decimal_places == 0)
    3370         1527 :         ratio = 1.0f;
    3371         1527 :       sprintf (buffer, "%.*f%%", decimal_places, ratio);
    3372              :     }
    3373              :   else
    3374            0 :     return format_count (top);
    3375              : 
    3376         1527 :   return buffer;
    3377              : }
    3378              : 
    3379              : /* Summary of execution */
    3380              : 
    3381              : static void
    3382          398 : executed_summary (unsigned lines, unsigned executed, unsigned suppressed)
    3383              : {
    3384          398 :   if (lines && suppressed == 0)
    3385          365 :     fnotice (stdout, "Lines executed:%s of %d\n",
    3386              :              format_gcov (executed, lines, 2), lines);
    3387           33 :   else if (lines && suppressed > 0)
    3388           30 :     fnotice (stdout, "Lines executed:%s of %d (%d of %d suppressed)\n",
    3389              :              format_gcov (executed, lines - suppressed, 2), lines - suppressed,
    3390              :              suppressed, lines);
    3391              :   else
    3392            3 :     fnotice (stdout, "No executable lines\n");
    3393          398 : }
    3394              : 
    3395              : /* Output summary info for a function.  */
    3396              : 
    3397              : static void
    3398            0 : function_summary (const coverage_info *coverage)
    3399              : {
    3400            0 :   if (coverage->function_suppressed)
    3401              :     {
    3402            0 :       fnotice (stdout, "Function '%s' suppressed\n", coverage->name);
    3403            0 :       return;
    3404              :     }
    3405            0 :   fnotice (stdout, "%s '%s'\n", "Function", coverage->name);
    3406            0 :   executed_summary (coverage->lines, coverage->lines_executed,
    3407            0 :                     coverage->lines_suppressed);
    3408              : 
    3409            0 :   if (coverage->branches)
    3410              :     {
    3411            0 :       const int branches = coverage->branches - coverage->branches_suppressed;
    3412            0 :       if (coverage->branches_suppressed == 0)
    3413            0 :         fnotice (stdout, "Branches executed:%s of %d\n",
    3414            0 :                  format_gcov (coverage->branches_executed, coverage->branches,
    3415              :                               2),
    3416              :                  coverage->branches);
    3417              :       else
    3418            0 :         fnotice (stdout, "Branches executed:%s of %d (%d of %d suppressed)\n",
    3419            0 :                  format_gcov (coverage->branches_executed, branches, 2),
    3420              :                  branches, coverage->branches_suppressed, coverage->branches);
    3421            0 :       fnotice (stdout, "Taken at least once:%s of %d\n",
    3422            0 :                format_gcov (coverage->branches_taken, branches, 2), branches);
    3423              :     }
    3424              :   else
    3425            0 :     fnotice (stdout, "No branches\n");
    3426              : 
    3427            0 :   if (coverage->calls && coverage->calls == 0)
    3428              :     fnotice (stdout, "Calls executed:%s of %d\n",
    3429              :              format_gcov (coverage->calls_executed, coverage->calls, 2),
    3430              :              coverage->calls);
    3431            0 :   else if (coverage->calls && coverage->calls_suppressed > 0)
    3432            0 :     fnotice (stdout, "Calls executed:%s of %d (%d of %d suppressed)\n",
    3433            0 :              format_gcov (coverage->calls_executed, coverage->calls
    3434              :                           - coverage->calls_suppressed, 2),
    3435              :              coverage->calls - coverage->calls_suppressed,
    3436              :              coverage->calls_suppressed, coverage->calls);
    3437              :   else
    3438            0 :     fnotice (stdout, "No calls\n");
    3439              : 
    3440            0 :   if (flag_conditions)
    3441              :     {
    3442            0 :       if (coverage->conditions && coverage->conditions_suppressed == 0)
    3443            0 :         fnotice (stdout, "Condition outcomes covered:%s of %d\n",
    3444            0 :                  format_gcov (coverage->conditions_covered,
    3445              :                               coverage->conditions, 2),
    3446              :                  coverage->conditions);
    3447            0 :       if (coverage->conditions && coverage->conditions_suppressed > 0)
    3448            0 :         fnotice (stdout, "Condition outcomes covered:%s of %d"
    3449              :                  " (%d of %d suppressed)\n",
    3450            0 :                  format_gcov (coverage->conditions_covered,
    3451              :                               coverage->conditions
    3452              :                               - coverage->conditions_suppressed, 2),
    3453              :                  coverage->conditions - coverage->conditions_suppressed,
    3454              :                  coverage->conditions_suppressed, coverage->conditions);
    3455              :       else
    3456            0 :         fnotice (stdout, "No conditions\n");
    3457              :     }
    3458              : 
    3459            0 :   if (flag_prime_paths)
    3460              :     {
    3461            0 :       if (coverage->paths && coverage->paths_suppressed == 0)
    3462            0 :         fnotice (stdout, "Prime paths covered:%s of %d\n",
    3463            0 :                  format_gcov (coverage->paths_covered, coverage->paths, 2),
    3464              :                               coverage->paths);
    3465            0 :       else if (coverage->paths && coverage->paths_suppressed > 0)
    3466            0 :         fnotice (stdout, "Prime paths covered:%s of %d (%u of %u suppressed)\n",
    3467            0 :                  format_gcov (coverage->paths_covered, coverage->paths
    3468              :                               - coverage->paths_suppressed, 2),
    3469              :                  coverage->paths - coverage->paths_suppressed,
    3470              :                  coverage->paths_suppressed, coverage->paths);
    3471              :       else
    3472            0 :         fnotice (stdout, "No path information\n");
    3473              :     }
    3474              : }
    3475              : 
    3476              : /* Output summary info for a file.  */
    3477              : 
    3478              : static void
    3479          238 : file_summary (const coverage_info *coverage)
    3480              : {
    3481          238 :   fnotice (stdout, "%s '%s'\n", "File", coverage->name);
    3482          238 :   executed_summary (coverage->lines, coverage->lines_executed,
    3483          238 :                     coverage->lines_suppressed);
    3484              : 
    3485          238 :   if (flag_branches)
    3486              :     {
    3487           23 :       if (coverage->branches)
    3488              :         {
    3489           15 :           fnotice (stdout, "Branches executed:%s of %d\n",
    3490           15 :                    format_gcov (coverage->branches_executed,
    3491              :                                 coverage->branches, 2),
    3492              :                    coverage->branches);
    3493           15 :           fnotice (stdout, "Taken at least once:%s of %d\n",
    3494           15 :                    format_gcov (coverage->branches_taken,
    3495              :                                 coverage->branches, 2),
    3496           15 :                    coverage->branches);
    3497              :         }
    3498              :       else
    3499            8 :         fnotice (stdout, "No branches\n");
    3500           23 :       if (coverage->calls)
    3501           23 :         fnotice (stdout, "Calls executed:%s of %d\n",
    3502           23 :                  format_gcov (coverage->calls_executed, coverage->calls, 2),
    3503              :                  coverage->calls);
    3504              :       else
    3505            0 :         fnotice (stdout, "No calls\n");
    3506              : 
    3507              :     }
    3508              : 
    3509          238 :   if (flag_conditions)
    3510              :     {
    3511            6 :       if (coverage->conditions)
    3512            6 :         fnotice (stdout, "Condition outcomes covered:%s of %d\n",
    3513            6 :                  format_gcov (coverage->conditions_covered,
    3514              :                               coverage->conditions, 2),
    3515              :                  coverage->conditions);
    3516              :       else
    3517            0 :         fnotice (stdout, "No conditions\n");
    3518              :     }
    3519              : 
    3520          238 :   if (flag_prime_paths)
    3521              :     {
    3522           59 :       if (coverage->paths)
    3523           45 :         fnotice (stdout, "Prime paths covered:%s of %d\n",
    3524           45 :                  format_gcov (coverage->paths_covered, coverage->paths, 2),
    3525              :                               coverage->paths);
    3526              :       else
    3527           14 :         fnotice (stdout, "No path information\n");
    3528              :     }
    3529          238 : }
    3530              : 
    3531              : /* Canonicalize the filename NAME by canonicalizing directory
    3532              :    separators, eliding . components and resolving .. components
    3533              :    appropriately.  Always returns a unique string.  */
    3534              : 
    3535              : static char *
    3536          396 : canonicalize_name (const char *name)
    3537              : {
    3538              :   /* The canonical name cannot be longer than the incoming name.  */
    3539          396 :   char *result = XNEWVEC (char, strlen (name) + 1);
    3540          396 :   const char *base = name, *probe;
    3541          396 :   char *ptr = result;
    3542          396 :   char *dd_base;
    3543          396 :   int slash = 0;
    3544              : 
    3545              : #if HAVE_DOS_BASED_FILE_SYSTEM
    3546              :   if (base[0] && base[1] == ':')
    3547              :     {
    3548              :       result[0] = base[0];
    3549              :       result[1] = ':';
    3550              :       base += 2;
    3551              :       ptr += 2;
    3552              :     }
    3553              : #endif
    3554         3491 :   for (dd_base = ptr; *base; base = probe)
    3555              :     {
    3556              :       size_t len;
    3557              : 
    3558        21662 :       for (probe = base; *probe; probe++)
    3559        21266 :         if (IS_DIR_SEPARATOR (*probe))
    3560              :           break;
    3561              : 
    3562         2699 :       len = probe - base;
    3563         2699 :       if (len == 1 && base[0] == '.')
    3564              :         /* Elide a '.' directory */
    3565              :         ;
    3566         2698 :       else if (len == 2 && base[0] == '.' && base[1] == '.')
    3567              :         {
    3568              :           /* '..', we can only elide it and the previous directory, if
    3569              :              we're not a symlink.  */
    3570            0 :           struct stat ATTRIBUTE_UNUSED buf;
    3571              : 
    3572            0 :           *ptr = 0;
    3573            0 :           if (dd_base == ptr
    3574              : #if defined (S_ISLNK)
    3575              :               /* S_ISLNK is not POSIX.1-1996.  */
    3576            0 :               || stat (result, &buf) || S_ISLNK (buf.st_mode)
    3577              : #endif
    3578              :                 )
    3579              :             {
    3580              :               /* Cannot elide, or unreadable or a symlink.  */
    3581            0 :               dd_base = ptr + 2 + slash;
    3582            0 :               goto regular;
    3583              :             }
    3584            0 :           while (ptr != dd_base && *ptr != '/')
    3585            0 :             ptr--;
    3586            0 :           slash = ptr != result;
    3587            0 :         }
    3588              :       else
    3589              :         {
    3590         2698 :         regular:
    3591              :           /* Regular pathname component.  */
    3592         2698 :           if (slash)
    3593         2302 :             *ptr++ = '/';
    3594         2698 :           memcpy (ptr, base, len);
    3595         2698 :           ptr += len;
    3596         2698 :           slash = 1;
    3597              :         }
    3598              : 
    3599         5002 :       for (; IS_DIR_SEPARATOR (*probe); probe++)
    3600         2303 :         continue;
    3601         2303 :     }
    3602          396 :   *ptr = 0;
    3603              : 
    3604          396 :   return result;
    3605              : }
    3606              : 
    3607              : /* Generate an output file name. INPUT_NAME is the canonicalized main
    3608              :    input file and SRC_NAME is the canonicalized file name.
    3609              :    LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation.  With
    3610              :    long_output_names we prepend the processed name of the input file
    3611              :    to each output name (except when the current source file is the
    3612              :    input file, so you don't get a double concatenation). The two
    3613              :    components are separated by '##'.  With preserve_paths we create a
    3614              :    filename from all path components of the source file, replacing '/'
    3615              :    with '#', and .. with '^', without it we simply take the basename
    3616              :    component.  (Remember, the canonicalized name will already have
    3617              :    elided '.' components and converted \\ separators.)  */
    3618              : 
    3619              : static string
    3620          236 : make_gcov_file_name (const char *input_name, const char *src_name)
    3621              : {
    3622          236 :   string str;
    3623              : 
    3624              :   /* When hashing filenames, we shorten them by only using the filename
    3625              :      component and appending a hash of the full (mangled) pathname.  */
    3626          236 :   if (flag_hash_filenames)
    3627            0 :     str = (string (mangle_name (src_name)) + "##"
    3628            0 :            + get_md5sum (src_name) + ".gcov");
    3629              :   else
    3630              :     {
    3631          236 :       if (flag_long_names && input_name && strcmp (src_name, input_name) != 0)
    3632              :         {
    3633            0 :           str += mangle_name (input_name);
    3634            0 :           str += "##";
    3635              :         }
    3636              : 
    3637          236 :       str += mangle_name (src_name);
    3638          236 :       str += ".gcov";
    3639              :     }
    3640              : 
    3641          236 :   return str;
    3642              : }
    3643              : 
    3644              : /* Mangle BASE name, copy it at the beginning of PTR buffer and
    3645              :    return address of the \0 character of the buffer.  */
    3646              : 
    3647              : static char *
    3648          236 : mangle_name (char const *base)
    3649              : {
    3650              :   /* Generate the source filename part.  */
    3651          236 :   if (!flag_preserve_paths)
    3652          236 :     return xstrdup (lbasename (base));
    3653              :   else
    3654            0 :     return mangle_path (base);
    3655              : }
    3656              : 
    3657              : /* Scan through the bb_data for each line in the block, increment
    3658              :    the line number execution count indicated by the execution count of
    3659              :    the appropriate basic block.  */
    3660              : 
    3661              : static void
    3662         1363 : add_line_counts (coverage_info *coverage, function_info *fn)
    3663              : {
    3664         1363 :   bool has_any_line = false;
    3665              :   /* Scan each basic block.  */
    3666        13774 :   for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
    3667              :     {
    3668        12411 :       line_info *line = NULL;
    3669        12411 :       block_info *block = &fn->blocks[ix];
    3670        12411 :       if (block->count && ix && ix + 1 != fn->blocks.size ())
    3671         5506 :         fn->blocks_executed++;
    3672        21627 :       for (unsigned i = 0; i < block->locations.size (); i++)
    3673              :         {
    3674         9216 :           unsigned src_idx = block->locations[i].source_file_idx;
    3675         9216 :           vector<unsigned> &lines = block->locations[i].lines;
    3676              : 
    3677         9216 :           block->cycle.arc = NULL;
    3678         9216 :           block->cycle.ident = ~0U;
    3679              : 
    3680        21002 :           for (unsigned j = 0; j < lines.size (); j++)
    3681              :             {
    3682        11786 :               unsigned ln = lines[j];
    3683              : 
    3684              :               /* Line belongs to a function that is in a group.  */
    3685        11786 :               if (fn->group_line_p (ln, src_idx))
    3686              :                 {
    3687          782 :                   gcc_assert (lines[j] - fn->start_line < fn->lines.size ());
    3688          782 :                   line = &(fn->lines[lines[j] - fn->start_line]);
    3689          782 :                   if (coverage)
    3690              :                     {
    3691            0 :                       if (!line->exists)
    3692            0 :                         coverage->lines++;
    3693            0 :                       if (line->suppressed)
    3694            0 :                         coverage->lines_suppressed++;
    3695            0 :                       if (!line->count && block->count && !line->suppressed)
    3696            0 :                         coverage->lines_executed++;
    3697              :                     }
    3698          782 :                   line->exists = 1;
    3699          782 :                   if (!block->exceptional)
    3700              :                     {
    3701          765 :                       line->unexceptional = 1;
    3702          765 :                       if (block->count == 0)
    3703           21 :                         line->has_unexecuted_block = 1;
    3704              :                     }
    3705          782 :                   line->count += block->count;
    3706              :                 }
    3707              :               else
    3708              :                 {
    3709        11004 :                   gcc_assert (ln < sources[src_idx].lines.size ());
    3710        11004 :                   line = &(sources[src_idx].lines[ln]);
    3711        11004 :                   if (coverage)
    3712              :                     {
    3713            0 :                       if (!line->exists)
    3714            0 :                         coverage->lines++;
    3715            0 :                       if (!line->exists && line->suppressed)
    3716            0 :                         coverage->lines_suppressed++;
    3717            0 :                       if (!line->count && block->count && !line->suppressed)
    3718            0 :                         coverage->lines_executed++;
    3719              :                     }
    3720        11004 :                   line->exists = 1;
    3721        11004 :                   if (!block->exceptional)
    3722              :                     {
    3723        10375 :                       line->unexceptional = 1;
    3724        10375 :                       if (block->count == 0)
    3725         4214 :                         line->has_unexecuted_block = 1;
    3726              :                     }
    3727        11004 :                   line->count += block->count;
    3728              :                 }
    3729              :             }
    3730              : 
    3731         9216 :           has_any_line = true;
    3732              : 
    3733         9216 :           if (!ix || ix + 1 == fn->blocks.size ())
    3734              :             /* Entry or exit block.  */;
    3735         8128 :           else if (line != NULL)
    3736              :             {
    3737         8128 :               line->blocks.push_back (block);
    3738              : 
    3739         8128 :               if (flag_branches)
    3740              :                 {
    3741          748 :                   arc_info *arc;
    3742              : 
    3743         2061 :                   for (arc = block->succ; arc; arc = arc->succ_next)
    3744         1313 :                     line->branches.push_back (arc);
    3745              :                 }
    3746              :             }
    3747              :         }
    3748              :     }
    3749              : 
    3750         1363 :   if (!has_any_line)
    3751            0 :     fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name,
    3752              :              fn->get_name ());
    3753         1363 : }
    3754              : 
    3755              : /* Accumulate info for LINE that belongs to SRC source file.  If ADD_COVERAGE
    3756              :    is set to true, update source file summary.  */
    3757              : 
    3758        53999 : static void accumulate_line_info (line_info *line, source_info *src,
    3759              :                                   bool add_coverage)
    3760              : {
    3761        53999 :   if (add_coverage)
    3762        55312 :     for (vector<arc_info *>::iterator it = line->branches.begin ();
    3763        55312 :          it != line->branches.end (); it++)
    3764         1313 :       add_branch_counts (&src->coverage, *it);
    3765              : 
    3766        53999 :   if (add_coverage)
    3767        62127 :     for (vector<block_info *>::iterator it = line->blocks.begin ();
    3768        62127 :          it != line->blocks.end (); it++)
    3769         8128 :       add_condition_counts (&src->coverage, *it);
    3770              : 
    3771              : 
    3772        53999 :   if (!line->blocks.empty ())
    3773              :     {
    3774              :       /* The user expects the line count to be the number of times
    3775              :          a line has been executed.  Simply summing the block count
    3776              :          will give an artificially high number.  The Right Thing
    3777              :          is to sum the entry counts to the graph of blocks on this
    3778              :          line, then find the elementary cycles of the local graph
    3779              :          and add the transition counts of those cycles.  */
    3780        14264 :       gcov_type count = 0;
    3781              : 
    3782              :       /* Cycle detection.  */
    3783         8128 :       for (vector<block_info *>::iterator it = line->blocks.begin ();
    3784        14264 :            it != line->blocks.end (); it++)
    3785              :         {
    3786        17757 :           for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next)
    3787         9629 :             if (!line->has_block (arc->src))
    3788         7715 :               count += arc->count;
    3789        21878 :           for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next)
    3790        13750 :             arc->cs_count = arc->count;
    3791              :         }
    3792              : 
    3793              :       /* Now, add the count of loops entirely on this line.  */
    3794         6136 :       count += get_cycles_count (*line);
    3795         6136 :       line->count = count;
    3796              : 
    3797         6136 :       if (line->count > src->maximum_count)
    3798          245 :         src->maximum_count = line->count;
    3799              :     }
    3800              : 
    3801        53999 :   if (line->exists && add_coverage)
    3802              :     {
    3803         8609 :       src->coverage.lines++;
    3804         8609 :       if (line->suppressed)
    3805          957 :         src->coverage.lines_suppressed++;
    3806         8609 :       if (line->count && !line->suppressed)
    3807         4438 :         src->coverage.lines_executed++;
    3808              :     }
    3809        53999 : }
    3810              : 
    3811              : /* Accumulate the line counts of a file.  */
    3812              : 
    3813              : static void
    3814          238 : accumulate_line_counts (source_info *src)
    3815              : {
    3816              :   /* First work on group functions.  */
    3817         1601 :   for (vector<function_info *>::iterator it = src->functions.begin ();
    3818         1601 :        it != src->functions.end (); it++)
    3819              :     {
    3820         1363 :       function_info *fn = *it;
    3821              : 
    3822         1363 :       if (fn->src != src->index || !fn->is_group)
    3823         1176 :         continue;
    3824              : 
    3825         1832 :       for (vector<line_info>::iterator it2 = fn->lines.begin ();
    3826         1832 :            it2 != fn->lines.end (); it2++)
    3827              :           {
    3828         1645 :             line_info *line = &(*it2);
    3829         1645 :             accumulate_line_info (line, src, true);
    3830              :           }
    3831              :     }
    3832              : 
    3833              :   /* Work on global lines that line in source file SRC.  */
    3834        52592 :   for (vector<line_info>::iterator it = src->lines.begin ();
    3835        52592 :        it != src->lines.end (); it++)
    3836        52354 :     accumulate_line_info (&(*it), src, true);
    3837              : 
    3838              :   /* If not using intermediate mode, sum lines of group functions and
    3839              :      add them to lines that live in a source file.  */
    3840          238 :   if (!flag_json_format)
    3841         1590 :     for (vector<function_info *>::iterator it = src->functions.begin ();
    3842         1590 :          it != src->functions.end (); it++)
    3843              :       {
    3844         1354 :         function_info *fn = *it;
    3845              : 
    3846         1354 :         if (fn->src != src->index || !fn->is_group)
    3847         1171 :           continue;
    3848              : 
    3849         1824 :         for (unsigned i = 0; i < fn->lines.size (); i++)
    3850              :           {
    3851         1641 :             line_info *fn_line = &fn->lines[i];
    3852         1641 :             if (fn_line->exists)
    3853              :               {
    3854          547 :                 unsigned ln = fn->start_line + i;
    3855          547 :                 line_info *src_line = &src->lines[ln];
    3856              : 
    3857          547 :                 if (!src_line->exists)
    3858          238 :                   src->coverage.lines++;
    3859          547 :                 if (!src_line->exists && src_line->suppressed)
    3860           57 :                   src->coverage.lines_suppressed++;
    3861          547 :                 if (!src_line->count && fn_line->count && !src_line->suppressed)
    3862          175 :                   src->coverage.lines_executed++;
    3863              : 
    3864          547 :                 src_line->count += fn_line->count;
    3865          547 :                 src_line->exists = 1;
    3866              : 
    3867          547 :                 if (fn_line->has_unexecuted_block)
    3868           19 :                   src_line->has_unexecuted_block = 1;
    3869              : 
    3870          547 :                 if (fn_line->unexceptional)
    3871          547 :                   src_line->unexceptional = 1;
    3872              :               }
    3873              :           }
    3874              :       }
    3875          238 : }
    3876              : 
    3877              : /* Output information about the conditions in block BINFO.  The output includes
    3878              :  * a summary (n/m outcomes covered) and a list of the missing (uncovered)
    3879              :  * outcomes.  */
    3880              : 
    3881              : static void
    3882         1249 : output_conditions (FILE *gcov_file, const block_info *binfo)
    3883              : {
    3884         1249 :     const condition_info& info = binfo->conditions;
    3885         1249 :     if (info.n_terms == 0)
    3886              :         return;
    3887          242 :     if (binfo->suppressed)
    3888              :       return;
    3889              : 
    3890          242 :     const int expected = 2 * info.n_terms;
    3891          242 :     const int got = info.popcount ();
    3892              : 
    3893          242 :     fnotice (gcov_file, "condition outcomes covered %d/%d\n", got, expected);
    3894          242 :     if (expected == got)
    3895              :         return;
    3896              : 
    3897          579 :     for (unsigned i = 0; i < info.n_terms; i++)
    3898              :     {
    3899          414 :         gcov_type_unsigned index = 1;
    3900          414 :         index <<= i;
    3901          414 :         if ((index & info.truev & info.falsev))
    3902           42 :             continue;
    3903              : 
    3904          372 :         const char *t = (index & info.truev) ? "" : "true";
    3905          372 :         const char *f = (index & info.falsev) ? "" : " false";
    3906          372 :         fnotice (gcov_file, "condition %2u not covered (%s%s)\n", i, t, f + !t[0]);
    3907              :     }
    3908              : }
    3909              : 
    3910              : /* Output information about ARC number IX.  Returns nonzero if
    3911              :    anything is output.  */
    3912              : 
    3913              : static int
    3914         1281 : output_branch_count (FILE *gcov_file, int ix, const arc_info *arc)
    3915              : {
    3916         1281 :   if (arc->suppressed)
    3917              :     return 0;
    3918         1281 :   else if (arc->is_call_non_return)
    3919              :     {
    3920          372 :       if (arc->src->count)
    3921              :         {
    3922          340 :           fnotice (gcov_file, "call   %2d returned %s\n", ix,
    3923          340 :                    format_gcov (arc->src->count - arc->count,
    3924              :                                 arc->src->count, -flag_counts));
    3925              :         }
    3926              :       else
    3927           32 :         fnotice (gcov_file, "call   %2d never executed\n", ix);
    3928              :     }
    3929          909 :   else if (!arc->is_unconditional)
    3930              :     {
    3931          366 :       if (arc->src->count)
    3932          366 :         fnotice (gcov_file, "branch %2d taken %s%s", ix,
    3933          366 :                  format_gcov (arc->count, arc->src->count, -flag_counts),
    3934          366 :                  arc->fall_through ? " (fallthrough)"
    3935          191 :                  : arc->is_throw ? " (throw)" : "");
    3936              :       else
    3937            0 :         fnotice (gcov_file, "branch %2d never executed%s", ix,
    3938            0 :                  (arc->fall_through ? " (fallthrough)"
    3939            0 :                   : arc->is_throw ? " (throw)" : ""));
    3940              : 
    3941          366 :       if (flag_verbose)
    3942            0 :         fnotice (gcov_file, " (BB %d)", arc->dst->id);
    3943              : 
    3944          366 :       fnotice (gcov_file, "\n");
    3945              :     }
    3946          543 :   else if (flag_unconditional && !arc->dst->is_call_return)
    3947              :     {
    3948            0 :       if (arc->src->count)
    3949            0 :         fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
    3950            0 :                  format_gcov (arc->count, arc->src->count, -flag_counts));
    3951              :       else
    3952            0 :         fnotice (gcov_file, "unconditional %2d never executed\n", ix);
    3953              :     }
    3954              :   else
    3955              :     return 0;
    3956              :   return 1;
    3957              : }
    3958              : 
    3959              : static void
    3960              : print_source_line (FILE *f, const vector<const char *> &source_lines,
    3961              :                    unsigned line);
    3962              : 
    3963              : 
    3964              : /* Print a dense coverage report for PATH of FN to GCOV_FILE.  PATH should be
    3965              :    number PATHNO in the sorted set of paths.  This function prints a dense form
    3966              :    where only the line numbers, and optionally the source file the line comes
    3967              :    from, in the order they need to be executed to achieve coverage.  This
    3968              :    produces very long lines for large functions, but is a useful and greppable
    3969              :    output.
    3970              : 
    3971              :    Returns 1 if the path was printed, 0 otherwise.  */
    3972              : static unsigned
    3973         1462 : print_prime_path_lines (FILE *gcov_file, const function_info &fn,
    3974              :                         const vector<unsigned> &path, unsigned pathno)
    3975              : {
    3976         1462 :   const bool is_covered = fn.paths.covered_p (pathno);
    3977         1462 :   if (is_covered && !flag_prime_paths_lines_covered)
    3978              :     return 0;
    3979         1309 :   if (!is_covered && !flag_prime_paths_lines_uncovered)
    3980              :     return 0;
    3981              : 
    3982         1308 :   if (is_covered)
    3983          113 :     fprintf (gcov_file, "path %u covered: lines", pathno);
    3984              :   else
    3985         1308 :     fprintf (gcov_file, "path %u not covered: lines", pathno);
    3986              : 
    3987         8146 :   for (size_t k = 0; k != path.size (); ++k)
    3988              :     {
    3989         6725 :       const block_info &block = fn.blocks[path[k]];
    3990         6725 :       const char *edge_kind = "";
    3991         6725 :       if (k + 1 != path.size ())
    3992              :         {
    3993         5304 :           const arc_info *arc = find_arc (block, path[k+1]);
    3994         5304 :           if (!arc)
    3995              :             edge_kind = "(suppress)";
    3996         5276 :           else if (arc->true_value)
    3997              :             edge_kind = "(true)";
    3998         4229 :           else if (arc->false_value)
    3999              :             edge_kind = "(false)";
    4000         3380 :           else if (arc->is_throw)
    4001         6725 :             edge_kind = "(throw)";
    4002              :         }
    4003              : 
    4004        13336 :       for (const block_location_info &loc : block.locations)
    4005              :         {
    4006              :           /* loc.lines could be empty when a statement is not anchored to a
    4007              :              source file -- see g++.dg/gcov/gcov-23.C.  Since there is no
    4008              :              actual source line to list anyway we can skip this location.  */
    4009         6611 :           if (loc.lines.empty ())
    4010            3 :             continue;
    4011         6608 :           if (loc.source_file_idx == fn.src)
    4012         6569 :             fprintf (gcov_file, " %u%s", loc.lines.back (), edge_kind);
    4013              :           else
    4014           39 :             fprintf (gcov_file, " %s:%u%s", sources[loc.source_file_idx].name,
    4015           39 :                      loc.lines.back (), edge_kind);
    4016              :         }
    4017              :     }
    4018              : 
    4019         1421 :   fprintf (gcov_file, "\n");
    4020         1421 :   return 1;
    4021              : }
    4022              : 
    4023              : static unsigned
    4024         3328 : print_inlined_separator (FILE *gcov_file, unsigned current_index, const
    4025              :                          block_location_info &loc, const function_info &fn)
    4026              : {
    4027         3328 :   if (loc.source_file_idx != current_index && loc.source_file_idx == fn.src)
    4028           14 :     fprintf (gcov_file, "------------------\n");
    4029         3328 :   if (loc.source_file_idx != current_index && loc.source_file_idx != fn.src)
    4030           28 :     fprintf (gcov_file, "== inlined from %s ==\n",
    4031           28 :              sources[loc.source_file_idx].name);
    4032         3328 :   return loc.source_file_idx;
    4033              : }
    4034              : 
    4035              : /* Print a coverage report for PATH of FN to GCOV_FILE.  PATH should be number
    4036              :    PATHNO in the sorted set of paths.  This function prints the lines that need
    4037              :    to be executed (and in what order) to cover it.
    4038              : 
    4039              :    Returns 1 if the path was printed, 0 otherwise.  */
    4040              : static unsigned
    4041          445 : print_prime_path_source (FILE *gcov_file, const function_info &fn,
    4042              :                          const vector<unsigned> &path, unsigned pathno)
    4043              : {
    4044          445 :   const bool is_covered = fn.paths.covered_p (pathno);
    4045          445 :   if (is_covered && !flag_prime_paths_source_covered)
    4046              :     return 0;
    4047          366 :   if (!is_covered && !flag_prime_paths_source_uncovered)
    4048              :     return 0;
    4049              : 
    4050          366 :   if (is_covered)
    4051           79 :     fprintf (gcov_file, "path %u covered:\n", pathno);
    4052              :   else
    4053          366 :     fprintf (gcov_file, "path %u not covered:\n", pathno);
    4054          445 :   unsigned current = fn.src;
    4055         3865 :   for (size_t k = 0; k != path.size (); ++k)
    4056              :     {
    4057         3420 :       const unsigned bb = path[k];
    4058         3420 :       const block_info &block = fn.blocks[bb];
    4059         3420 :       gcc_checking_assert (block.id == bb);
    4060              : 
    4061         3420 :       const char *edge_kind = "";
    4062         3420 :       if (k + 1 != path.size ())
    4063              :         {
    4064         2975 :           const arc_info *arc = find_arc (block, path[k+1]);
    4065         2975 :           if (!arc)
    4066              :             edge_kind = "(suppress)";
    4067         2975 :           else if (arc->true_value)
    4068              :             edge_kind = "(true)";
    4069         2221 :           else if (arc->false_value)
    4070              :             edge_kind = "(false)";
    4071         1656 :           else if (arc->is_throw)
    4072         3420 :             edge_kind = "(throw)";
    4073              :         }
    4074              : 
    4075         6751 :       for (const block_location_info &loc : block.locations)
    4076              :         {
    4077              :           /* loc.lines could be empty when a statement is not anchored to a
    4078              :              source file -- see g++.dg/gcov/gcov-24.C.  Since there is no
    4079              :              actual source line to list anyway we can skip this location.  */
    4080         3331 :           if (loc.lines.empty ())
    4081            3 :             continue;
    4082         3328 :           const source_info &src = sources[loc.source_file_idx];
    4083         3328 :           const vector<const char *> &lines = slurp (src, gcov_file, "");
    4084         3328 :           current = print_inlined_separator (gcov_file, current, loc, fn);
    4085         7511 :           for (unsigned i = 0; i != loc.lines.size () - 1; ++i)
    4086              :             {
    4087          855 :               const unsigned line = loc.lines[i];
    4088          855 :               fprintf (gcov_file, "BB %2d: %-10s %3d", bb, "", line);
    4089          855 :               print_source_line (gcov_file, lines, line);
    4090              :             }
    4091              : 
    4092         3328 :           const unsigned line = loc.lines.back ();
    4093         3328 :           fprintf (gcov_file, "BB %2d: %-10s %3d", bb, edge_kind, line);
    4094         3328 :           print_source_line (gcov_file, lines, line);
    4095              :         }
    4096              :     }
    4097              : 
    4098          445 :   fputc ('\n', gcov_file);
    4099          445 :   return 1;
    4100              : }
    4101              : 
    4102              : /* Print path coverage counts for FN to GCOV_FILE.  LINES is the vector of
    4103              :    source lines for FN.  Note that unlike statements, branch counts, and
    4104              :    conditions, this is not anchored to source lines but the function root.  */
    4105              : static int
    4106         1333 : output_path_coverage (FILE *gcov_file, const function_info *fn)
    4107              : {
    4108         1333 :   if (!flag_prime_paths)
    4109              :     return 0;
    4110              : 
    4111          278 :   const path_info& paths = fn->paths;
    4112          556 :   if (fn->paths.get_paths ().empty ())
    4113            3 :     fnotice (gcov_file, "path coverage omitted\n");
    4114          275 :   else if (paths.suppressed_p ())
    4115           14 :     fnotice (gcov_file, "Prime paths covered %u of " HOST_SIZE_T_PRINT_UNSIGNED
    4116              :              " (" HOST_SIZE_T_PRINT_UNSIGNED " of " HOST_SIZE_T_PRINT_UNSIGNED
    4117              :              " suppressed)\n", fn->paths.covered_paths (),
    4118            7 :              (fmt_size_t)fn->paths.path_count (),
    4119            7 :              (fmt_size_t)fn->paths.suppressed_count (),
    4120            7 :              (fmt_size_t)fn->paths.paths.size ());
    4121              :   else
    4122          536 :     fnotice (gcov_file, "paths covered %u of " HOST_SIZE_T_PRINT_UNSIGNED "\n",
    4123          268 :              fn->paths.covered_paths (), (fmt_size_t)fn->paths.paths.size ());
    4124              : 
    4125          278 :   if (flag_prime_paths_lines_uncovered || flag_prime_paths_lines_covered)
    4126              :     {
    4127          202 :       unsigned pathno = 0;
    4128         1866 :       for (const vector<unsigned> &path : fn->paths.get_paths ())
    4129         1462 :         print_prime_path_lines (gcov_file, *fn, path, pathno++);
    4130              :     }
    4131              : 
    4132          278 :   if (flag_prime_paths_source_uncovered || flag_prime_paths_source_covered)
    4133              :     {
    4134          120 :       unsigned pathno = 0;
    4135          685 :       for (const vector<unsigned> &path : fn->paths.get_paths ())
    4136          445 :         print_prime_path_source (gcov_file, *fn, path, pathno++);
    4137              :     }
    4138              :   return 1;
    4139              : }
    4140              : 
    4141              : static const char *
    4142       102526 : read_line (FILE *file)
    4143              : {
    4144       102526 :   static char *string;
    4145       102526 :   static size_t string_len;
    4146       102526 :   size_t pos = 0;
    4147              : 
    4148       102526 :   if (!string_len)
    4149              :     {
    4150          152 :       string_len = 200;
    4151          152 :       string = XNEWVEC (char, string_len);
    4152              :     }
    4153              : 
    4154       102527 :   while (fgets (string + pos, string_len - pos, file))
    4155              :     {
    4156       102294 :       size_t len = strlen (string + pos);
    4157              : 
    4158       102294 :       if (len && string[pos + len - 1] == '\n')
    4159              :         {
    4160       102293 :           string[pos + len - 1] = 0;
    4161       102293 :           return string;
    4162              :         }
    4163            1 :       pos += len;
    4164              :       /* If the file contains NUL characters or an incomplete
    4165              :          last line, which can happen more than once in one run,
    4166              :          we have to avoid doubling the STRING_LEN unnecessarily.  */
    4167            1 :       if (pos > string_len / 2)
    4168              :         {
    4169            1 :           string_len *= 2;
    4170            1 :           string = XRESIZEVEC (char, string, string_len);
    4171              :         }
    4172              :     }
    4173              : 
    4174          233 :   return pos ? string : NULL;
    4175              : }
    4176              : 
    4177              : /* Get the vector with the contents SRC, possibly from a cache.  If
    4178              :    the reading fails, a message prefixed with LINE_START is written to
    4179              :    GCOV_FILE.  */
    4180              : static const vector<const char *>&
    4181         3564 : slurp (const source_info &src, FILE *gcov_file,
    4182              :        const char *line_start)
    4183              : {
    4184         3564 :   if (source_lines.size () <= src.index)
    4185          232 :     source_lines.resize (src.index + 1);
    4186              : 
    4187              :   /* Store vector pointers so that the returned references remain
    4188              :      stable and won't be broken by successive calls to slurp.  */
    4189         3564 :   if (!source_lines[src.index])
    4190          236 :     source_lines[src.index] = new vector<const char *> ();
    4191              : 
    4192         3564 :   if (!source_lines[src.index]->empty ())
    4193              :     return *source_lines[src.index];
    4194              : 
    4195          236 :   FILE *source_file = fopen (src.name, "r");
    4196          236 :   if (!source_file)
    4197            3 :     fnotice (stderr, "Cannot open source file %s\n", src.name);
    4198          233 :   else if (src.file_time == 0)
    4199            0 :     fprintf (gcov_file, "%sSource is newer than graph\n", line_start);
    4200              : 
    4201          236 :   const char *retval;
    4202          236 :   vector<const char *> &lines = *source_lines[src.index];
    4203          236 :   if (source_file)
    4204       102526 :     while ((retval = read_line (source_file)))
    4205       102293 :       lines.push_back (xstrdup (retval));
    4206              : 
    4207          233 :   if (source_file)
    4208          233 :     fclose (source_file);
    4209              :   return lines;
    4210              : }
    4211              : 
    4212              : /* Pad string S with spaces from left to have total width equal to 9.  */
    4213              : 
    4214              : static void
    4215        53606 : pad_count_string (string &s)
    4216              : {
    4217        53606 :   if (s.size () < 9)
    4218        53606 :     s.insert (0, 9 - s.size (), ' ');
    4219        53606 : }
    4220              : 
    4221              : /* Print GCOV line beginning to F stream.  If EXISTS is set to true, the
    4222              :    line exists in source file.  UNEXCEPTIONAL indicated that it's not in
    4223              :    an exceptional statement.  The output is printed for LINE_NUM of given
    4224              :    COUNT of executions.  EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
    4225              :    used to indicate non-executed blocks.  */
    4226              : 
    4227              : static void
    4228        53606 : output_line_beginning (FILE *f, bool exists, bool unexceptional,
    4229              :                        bool has_unexecuted_block,
    4230              :                        bool suppressed,
    4231              :                        gcov_type count, unsigned line_num,
    4232              :                        const char *exceptional_string,
    4233              :                        const char *unexceptional_string,
    4234              :                        unsigned int maximum_count)
    4235              : {
    4236        53606 :   string s;
    4237        53606 :   if (suppressed)
    4238              :     {
    4239         1011 :       s = "#";
    4240         1011 :       pad_count_string (s);
    4241              :     }
    4242        52595 :   else if (exists)
    4243              :     {
    4244         7843 :       if (count > 0)
    4245              :         {
    4246         4627 :           s = format_gcov (count, 0, -1);
    4247         4627 :           if (has_unexecuted_block
    4248           37 :               && bbg_supports_has_unexecuted_blocks)
    4249              :             {
    4250           37 :               if (flag_use_colors)
    4251              :                 {
    4252            0 :                   pad_count_string (s);
    4253            0 :                   s.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
    4254              :                                         COLOR_SEPARATOR COLOR_FG_WHITE));
    4255            0 :                   s += SGR_RESET;
    4256              :                 }
    4257              :               else
    4258           37 :                 s += "*";
    4259              :             }
    4260         4627 :           pad_count_string (s);
    4261              :         }
    4262              :       else
    4263              :         {
    4264         3216 :           if (flag_use_colors)
    4265              :             {
    4266            0 :               s = "0";
    4267            0 :               pad_count_string (s);
    4268            0 :               if (unexceptional)
    4269            0 :                 s.insert (0, SGR_SEQ (COLOR_BG_RED
    4270              :                                       COLOR_SEPARATOR COLOR_FG_WHITE));
    4271              :               else
    4272            0 :                 s.insert (0, SGR_SEQ (COLOR_BG_CYAN
    4273              :                                       COLOR_SEPARATOR COLOR_FG_WHITE));
    4274            0 :               s += SGR_RESET;
    4275              :             }
    4276              :           else
    4277              :             {
    4278         3216 :               s = unexceptional ? unexceptional_string : exceptional_string;
    4279         3216 :               pad_count_string (s);
    4280              :             }
    4281              :         }
    4282              :     }
    4283              :   else
    4284              :     {
    4285        44752 :       s = "-";
    4286        44752 :       pad_count_string (s);
    4287              :     }
    4288              : 
    4289              :   /* Format line number in output.  */
    4290        53606 :   char buffer[16];
    4291        53606 :   sprintf (buffer, "%5u", line_num);
    4292        53606 :   string linestr (buffer);
    4293              : 
    4294        53606 :   if (flag_use_hotness_colors && maximum_count)
    4295              :     {
    4296            0 :       if (count * 2 > maximum_count) /* > 50%.  */
    4297            0 :         linestr.insert (0, SGR_SEQ (COLOR_BG_RED));
    4298            0 :       else if (count * 5 > maximum_count) /* > 20%.  */
    4299            0 :         linestr.insert (0, SGR_SEQ (COLOR_BG_YELLOW));
    4300            0 :       else if (count * 10 > maximum_count) /* > 10%.  */
    4301            0 :         linestr.insert (0, SGR_SEQ (COLOR_BG_GREEN));
    4302            0 :       linestr += SGR_RESET;
    4303              :     }
    4304              : 
    4305        53606 :   fprintf (f, "%s:%s", s.c_str (), linestr.c_str ());
    4306        53606 : }
    4307              : 
    4308              : static void
    4309       107766 : print_source_line (FILE *f, const vector<const char *> &source_lines,
    4310              :                    unsigned line)
    4311              : {
    4312       107766 :   gcc_assert (line >= 1);
    4313       107766 :   gcc_assert (line <= source_lines.size ());
    4314              : 
    4315       107766 :   fprintf (f, ":%s\n", source_lines[line - 1]);
    4316       107766 : }
    4317              : 
    4318              : /* Output line details for LINE and print it to F file.  LINE lives on
    4319              :    LINE_NUM.  */
    4320              : 
    4321              : static void
    4322        53547 : output_line_details (FILE *f, const line_info *line, unsigned line_num)
    4323              : {
    4324        53547 :   if (flag_all_blocks)
    4325              :     {
    4326          273 :       arc_info *arc;
    4327          273 :       int jx = 0;
    4328          341 :       for (vector<block_info *>::const_iterator it = line->blocks.begin ();
    4329          341 :            it != line->blocks.end (); it++)
    4330              :         {
    4331           68 :           if (!(*it)->is_call_return)
    4332              :             {
    4333           59 :               output_line_beginning (f, line->exists,
    4334           59 :                                      (*it)->exceptional, false,
    4335           59 :                                      (*it)->suppressed,
    4336           59 :                                      (*it)->count, line_num,
    4337              :                                      "%%%%%", "$$$$$", 0);
    4338           59 :               fprintf (f, "-block %d", (*it)->id);
    4339           59 :               if (flag_verbose)
    4340            0 :                 fprintf (f, " (BB %u)", (*it)->id);
    4341           59 :               fprintf (f, "\n");
    4342              :             }
    4343           68 :           if (flag_branches)
    4344           72 :             for (arc = (*it)->succ; arc; arc = arc->succ_next)
    4345           42 :               jx += output_branch_count (f, jx, arc);
    4346              : 
    4347           68 :           if (flag_conditions)
    4348            0 :               output_conditions (f, *it);
    4349              :         }
    4350              :     }
    4351              :   else
    4352              :     {
    4353        53274 :       if (flag_branches)
    4354              :         {
    4355         1899 :           int ix;
    4356              : 
    4357         1899 :           ix = 0;
    4358         1899 :           for (vector<arc_info *>::const_iterator it = line->branches.begin ();
    4359         3138 :                   it != line->branches.end (); it++)
    4360         1239 :               ix += output_branch_count (f, ix, (*it));
    4361              :         }
    4362              : 
    4363        53274 :       if (flag_conditions)
    4364              :         {
    4365         3483 :           for (vector<block_info *>::const_iterator it = line->blocks.begin ();
    4366         3483 :                it != line->blocks.end (); it++)
    4367         1249 :               output_conditions (f, *it);
    4368              :         }
    4369              :     }
    4370        53547 : }
    4371              : 
    4372              : /* Output detail statistics about function FN to file F.  */
    4373              : 
    4374              : static void
    4375         1333 : output_function_details (FILE *f, function_info *fn)
    4376              : {
    4377         1333 :   if (!flag_branches)
    4378              :     return;
    4379              : 
    4380          161 :   arc_info *arc = fn->blocks[EXIT_BLOCK].pred;
    4381          161 :   gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
    4382          161 :   gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
    4383              : 
    4384          695 :   for (; arc; arc = arc->pred_next)
    4385          534 :     if (arc->fake)
    4386          374 :       return_count -= arc->count;
    4387              : 
    4388          161 :   fprintf (f, "function %s", fn->get_name ());
    4389          161 :   fprintf (f, " called %s",
    4390              :            format_gcov (called_count, 0, -1));
    4391          161 :   fprintf (f, " returned %s",
    4392              :            format_gcov (return_count, called_count, 0));
    4393          322 :   fprintf (f, " blocks executed %s",
    4394          161 :            format_gcov (fn->blocks_executed, fn->get_block_count (), 0));
    4395          161 :   fprintf (f, "\n");
    4396              : }
    4397              : 
    4398              : /* Read in the source file one line at a time, and output that line to
    4399              :    the gcov file preceded by its execution count and other
    4400              :    information.  */
    4401              : 
    4402              : static void
    4403          236 : output_lines (FILE *gcov_file, const source_info *src)
    4404              : {
    4405              : #define  DEFAULT_LINE_START "        -:    0:"
    4406              : #define FN_SEPARATOR "------------------\n"
    4407              : 
    4408              :   /* Print colorization legend.  */
    4409          236 :   if (flag_use_colors)
    4410            0 :     fprintf (gcov_file, "%s",
    4411              :              DEFAULT_LINE_START "Colorization: profile count: " \
    4412              :              SGR_SEQ (COLOR_BG_CYAN) "zero coverage (exceptional)" SGR_RESET \
    4413              :              " " \
    4414              :              SGR_SEQ (COLOR_BG_RED) "zero coverage (unexceptional)" SGR_RESET \
    4415              :              " " \
    4416              :              SGR_SEQ (COLOR_BG_MAGENTA) "unexecuted block" SGR_RESET "\n");
    4417              : 
    4418          236 :   if (flag_use_hotness_colors)
    4419            0 :     fprintf (gcov_file, "%s",
    4420              :              DEFAULT_LINE_START "Colorization: line numbers: hotness: " \
    4421              :              SGR_SEQ (COLOR_BG_RED) "> 50%" SGR_RESET " " \
    4422              :              SGR_SEQ (COLOR_BG_YELLOW) "> 20%" SGR_RESET " " \
    4423              :              SGR_SEQ (COLOR_BG_GREEN) "> 10%" SGR_RESET "\n");
    4424              : 
    4425          236 :   fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
    4426          236 :   if (!multiple_files)
    4427              :     {
    4428          236 :       fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
    4429          236 :       fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
    4430          236 :                no_data_file ? "-" : da_file_name);
    4431          236 :       fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
    4432              :     }
    4433              : 
    4434          236 :   const vector<const char *> &source_lines = slurp (*src, gcov_file,
    4435              :                                                     DEFAULT_LINE_START);
    4436          236 :   unsigned line_start_group = 0;
    4437          236 :   vector<function_info *> *fns;
    4438          459 :   unsigned filtered_line_end = !filters.empty () ? 0 : source_lines.size ();
    4439              : 
    4440       102309 :   for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
    4441              :     {
    4442       102086 :       if (line_num >= src->lines.size ())
    4443              :         {
    4444              :           /* If the src->lines is truncated because the rest of the functions
    4445              :              are filtered out we must stop here, and not fall back to printing
    4446              :              the rest of the file.  */
    4447        50049 :           if (!filters.empty ())
    4448              :             break;
    4449        50036 :           fprintf (gcov_file, "%9s:%5u", "-", line_num);
    4450        50036 :           print_source_line (gcov_file, source_lines, line_num);
    4451        50036 :           continue;
    4452              :         }
    4453              : 
    4454        52037 :       const line_info *line = &src->lines[line_num];
    4455              : 
    4456        52037 :       if (line_start_group == 0)
    4457              :         {
    4458        51509 :           fns = src->get_functions_at_location (line_num);
    4459        52745 :           if (fns != NULL && fns->size () > 1)
    4460              :             {
    4461              :               /* It's possible to have functions that partially overlap,
    4462              :                  thus take the maximum end_line of functions starting
    4463              :                  at LINE_NUM.  */
    4464          239 :               for (unsigned i = 0; i < fns->size (); i++)
    4465          168 :                 if ((*fns)[i]->end_line > line_start_group)
    4466              :                   line_start_group = (*fns)[i]->end_line;
    4467              : 
    4468              :               /* When filtering, src->lines will be cut short for the last
    4469              :                  selected function.  To make sure the "overlapping function"
    4470              :                  section is printed too, adjust the end so that it is within
    4471              :                  src->lines.  */
    4472           71 :               if (line_start_group >= src->lines.size ())
    4473            0 :                 line_start_group = src->lines.size () - 1;
    4474              : 
    4475           71 :               if (!filters.empty ())
    4476            6 :                 filtered_line_end = line_start_group;
    4477              :             }
    4478        52603 :           else if (fns != NULL && fns->size () == 1)
    4479              :             {
    4480         1165 :               function_info *fn = (*fns)[0];
    4481         1165 :               output_function_details (gcov_file, fn);
    4482         1165 :               output_path_coverage (gcov_file, fn);
    4483              : 
    4484              :               /* If functions are filtered, only the matching functions will be in
    4485              :                  fns and there is no need for extra checking.  */
    4486         1165 :               if (!filters.empty ())
    4487            9 :                 filtered_line_end = fn->end_line;
    4488              :             }
    4489              :         }
    4490              : 
    4491              :       /* For lines which don't exist in the .bb file, print '-' before
    4492              :          the source line.  For lines which exist but were never
    4493              :          executed, print '#####' or '=====' before the source line.  For lines
    4494              :          that were suppressed, print '#'.  Otherwise, print the execution count
    4495              :          before the source line.  There are 16 spaces of indentation added
    4496              :          before the source line so that tabs won't be messed up.  */
    4497        52037 :       if (line_num <= filtered_line_end)
    4498              :         {
    4499        51921 :           output_line_beginning (gcov_file, line->exists, line->unexceptional,
    4500        51921 :                                  line->has_unexecuted_block, line->suppressed,
    4501        51921 :                                  line->count,
    4502              :                                  line_num, "=====", "#####",
    4503        51921 :                                  src->maximum_count);
    4504              : 
    4505        51921 :           print_source_line (gcov_file, source_lines, line_num);
    4506        51921 :           output_line_details (gcov_file, line, line_num);
    4507              :         }
    4508              : 
    4509        52037 :       if (line_start_group == line_num)
    4510              :         {
    4511           71 :           for (vector<function_info *>::iterator it = fns->begin ();
    4512          239 :                it != fns->end (); it++)
    4513              :             {
    4514          168 :               function_info *fn = *it;
    4515          168 :               vector<line_info> &lines = fn->lines;
    4516              : 
    4517          168 :               fprintf (gcov_file, FN_SEPARATOR);
    4518              : 
    4519          168 :               string fn_name = fn->get_name ();
    4520          168 :               if (flag_use_colors)
    4521              :                 {
    4522            0 :                   fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN));
    4523            0 :                   fn_name += SGR_RESET;
    4524              :                 }
    4525              : 
    4526          168 :               fprintf (gcov_file, "%s:\n", fn_name.c_str ());
    4527              : 
    4528          168 :               output_function_details (gcov_file, fn);
    4529          168 :               output_path_coverage (gcov_file, fn);
    4530              : 
    4531              :               /* Print all lines covered by the function.  */
    4532         1962 :               for (unsigned i = 0; i < lines.size (); i++)
    4533              :                 {
    4534         1626 :                   line_info *line = &lines[i];
    4535         1626 :                   unsigned l = fn->start_line + i;
    4536              : 
    4537              :                   /* For lines which don't exist in the .bb file, print '-'
    4538              :                      before the source line.  For lines which exist but
    4539              :                      were never executed, print '#####' or '=====' before
    4540              :                      the source line.  For suppressed lines, print '#'.
    4541              :                      Otherwise, print the execution count before the source
    4542              :                      line.  There are 16 spaces of indentation added before the
    4543              :                      source line so that tabs won't be messed up.  */
    4544         1626 :                   output_line_beginning (gcov_file, line->exists,
    4545              :                                          line->unexceptional,
    4546              :                                          line->has_unexecuted_block,
    4547         1626 :                                          line->suppressed,
    4548              :                                          line->count,
    4549              :                                          l, "=====", "#####",
    4550         1626 :                                          src->maximum_count);
    4551              : 
    4552         1626 :                   print_source_line (gcov_file, source_lines, l);
    4553         1626 :                   output_line_details (gcov_file, line, l);
    4554              :                 }
    4555          168 :             }
    4556              : 
    4557           71 :           fprintf (gcov_file, FN_SEPARATOR);
    4558           71 :           line_start_group = 0;
    4559              :         }
    4560              :     }
    4561          236 : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.