xref: /dflybsd-src/contrib/gcc-8.0/gcc/gcov.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj /* Gcov.c: prepend line execution counts and branch probabilities to a
2*38fd1498Szrj    source file.
3*38fd1498Szrj    Copyright (C) 1990-2018 Free Software Foundation, Inc.
4*38fd1498Szrj    Contributed by James E. Wilson of Cygnus Support.
5*38fd1498Szrj    Mangled by Bob Manson of Cygnus Support.
6*38fd1498Szrj    Mangled further by Nathan Sidwell <nathan@codesourcery.com>
7*38fd1498Szrj 
8*38fd1498Szrj Gcov is free software; you can redistribute it and/or modify
9*38fd1498Szrj it under the terms of the GNU General Public License as published by
10*38fd1498Szrj the Free Software Foundation; either version 3, or (at your option)
11*38fd1498Szrj any later version.
12*38fd1498Szrj 
13*38fd1498Szrj Gcov is distributed in the hope that it will be useful,
14*38fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
15*38fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*38fd1498Szrj GNU General Public License for more details.
17*38fd1498Szrj 
18*38fd1498Szrj You should have received a copy of the GNU General Public License
19*38fd1498Szrj along with Gcov; see the file COPYING3.  If not see
20*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
21*38fd1498Szrj 
22*38fd1498Szrj /* ??? Print a list of the ten blocks with the highest execution counts,
23*38fd1498Szrj    and list the line numbers corresponding to those blocks.  Also, perhaps
24*38fd1498Szrj    list the line numbers with the highest execution counts, only printing
25*38fd1498Szrj    the first if there are several which are all listed in the same block.  */
26*38fd1498Szrj 
27*38fd1498Szrj /* ??? Should have an option to print the number of basic blocks, and the
28*38fd1498Szrj    percent of them that are covered.  */
29*38fd1498Szrj 
30*38fd1498Szrj /* Need an option to show individual block counts, and show
31*38fd1498Szrj    probabilities of fall through arcs.  */
32*38fd1498Szrj 
33*38fd1498Szrj #include "config.h"
34*38fd1498Szrj #define INCLUDE_ALGORITHM
35*38fd1498Szrj #define INCLUDE_VECTOR
36*38fd1498Szrj #define INCLUDE_STRING
37*38fd1498Szrj #define INCLUDE_MAP
38*38fd1498Szrj #define INCLUDE_SET
39*38fd1498Szrj #include "system.h"
40*38fd1498Szrj #include "coretypes.h"
41*38fd1498Szrj #include "tm.h"
42*38fd1498Szrj #include "intl.h"
43*38fd1498Szrj #include "diagnostic.h"
44*38fd1498Szrj #include "version.h"
45*38fd1498Szrj #include "demangle.h"
46*38fd1498Szrj #include "color-macros.h"
47*38fd1498Szrj 
48*38fd1498Szrj #include <getopt.h>
49*38fd1498Szrj 
50*38fd1498Szrj #include "md5.h"
51*38fd1498Szrj 
52*38fd1498Szrj using namespace std;
53*38fd1498Szrj 
54*38fd1498Szrj #define IN_GCOV 1
55*38fd1498Szrj #include "gcov-io.h"
56*38fd1498Szrj #include "gcov-io.c"
57*38fd1498Szrj 
58*38fd1498Szrj /* The gcno file is generated by -ftest-coverage option. The gcda file is
59*38fd1498Szrj    generated by a program compiled with -fprofile-arcs. Their formats
60*38fd1498Szrj    are documented in gcov-io.h.  */
61*38fd1498Szrj 
62*38fd1498Szrj /* The functions in this file for creating and solution program flow graphs
63*38fd1498Szrj    are very similar to functions in the gcc source file profile.c.  In
64*38fd1498Szrj    some places we make use of the knowledge of how profile.c works to
65*38fd1498Szrj    select particular algorithms here.  */
66*38fd1498Szrj 
67*38fd1498Szrj /* The code validates that the profile information read in corresponds
68*38fd1498Szrj    to the code currently being compiled.  Rather than checking for
69*38fd1498Szrj    identical files, the code below compares a checksum on the CFG
70*38fd1498Szrj    (based on the order of basic blocks and the arcs in the CFG).  If
71*38fd1498Szrj    the CFG checksum in the gcda file match the CFG checksum in the
72*38fd1498Szrj    gcno file, the profile data will be used.  */
73*38fd1498Szrj 
74*38fd1498Szrj /* This is the size of the buffer used to read in source file lines.  */
75*38fd1498Szrj 
76*38fd1498Szrj struct function_info;
77*38fd1498Szrj struct block_info;
78*38fd1498Szrj struct source_info;
79*38fd1498Szrj 
80*38fd1498Szrj /* Describes an arc between two basic blocks.  */
81*38fd1498Szrj 
82*38fd1498Szrj struct arc_info
83*38fd1498Szrj {
84*38fd1498Szrj   /* source and destination blocks.  */
85*38fd1498Szrj   struct block_info *src;
86*38fd1498Szrj   struct block_info *dst;
87*38fd1498Szrj 
88*38fd1498Szrj   /* transition counts.  */
89*38fd1498Szrj   gcov_type count;
90*38fd1498Szrj   /* used in cycle search, so that we do not clobber original counts.  */
91*38fd1498Szrj   gcov_type cs_count;
92*38fd1498Szrj 
93*38fd1498Szrj   unsigned int count_valid : 1;
94*38fd1498Szrj   unsigned int on_tree : 1;
95*38fd1498Szrj   unsigned int fake : 1;
96*38fd1498Szrj   unsigned int fall_through : 1;
97*38fd1498Szrj 
98*38fd1498Szrj   /* Arc to a catch handler.  */
99*38fd1498Szrj   unsigned int is_throw : 1;
100*38fd1498Szrj 
101*38fd1498Szrj   /* Arc is for a function that abnormally returns.  */
102*38fd1498Szrj   unsigned int is_call_non_return : 1;
103*38fd1498Szrj 
104*38fd1498Szrj   /* Arc is for catch/setjmp.  */
105*38fd1498Szrj   unsigned int is_nonlocal_return : 1;
106*38fd1498Szrj 
107*38fd1498Szrj   /* Is an unconditional branch.  */
108*38fd1498Szrj   unsigned int is_unconditional : 1;
109*38fd1498Szrj 
110*38fd1498Szrj   /* Loop making arc.  */
111*38fd1498Szrj   unsigned int cycle : 1;
112*38fd1498Szrj 
113*38fd1498Szrj   /* Links to next arc on src and dst lists.  */
114*38fd1498Szrj   struct arc_info *succ_next;
115*38fd1498Szrj   struct arc_info *pred_next;
116*38fd1498Szrj };
117*38fd1498Szrj 
118*38fd1498Szrj /* Describes which locations (lines and files) are associated with
119*38fd1498Szrj    a basic block.  */
120*38fd1498Szrj 
121*38fd1498Szrj struct block_location_info
122*38fd1498Szrj {
123*38fd1498Szrj   block_location_info (unsigned _source_file_idx):
124*38fd1498Szrj     source_file_idx (_source_file_idx)
125*38fd1498Szrj   {}
126*38fd1498Szrj 
127*38fd1498Szrj   unsigned source_file_idx;
128*38fd1498Szrj   vector<unsigned> lines;
129*38fd1498Szrj };
130*38fd1498Szrj 
131*38fd1498Szrj /* Describes a basic block. Contains lists of arcs to successor and
132*38fd1498Szrj    predecessor blocks.  */
133*38fd1498Szrj 
134*38fd1498Szrj struct block_info
135*38fd1498Szrj {
136*38fd1498Szrj   /* Constructor.  */
137*38fd1498Szrj   block_info ();
138*38fd1498Szrj 
139*38fd1498Szrj   /* Chain of exit and entry arcs.  */
140*38fd1498Szrj   arc_info *succ;
141*38fd1498Szrj   arc_info *pred;
142*38fd1498Szrj 
143*38fd1498Szrj   /* Number of unprocessed exit and entry arcs.  */
144*38fd1498Szrj   gcov_type num_succ;
145*38fd1498Szrj   gcov_type num_pred;
146*38fd1498Szrj 
147*38fd1498Szrj   unsigned id;
148*38fd1498Szrj 
149*38fd1498Szrj   /* Block execution count.  */
150*38fd1498Szrj   gcov_type count;
151*38fd1498Szrj   unsigned count_valid : 1;
152*38fd1498Szrj   unsigned valid_chain : 1;
153*38fd1498Szrj   unsigned invalid_chain : 1;
154*38fd1498Szrj   unsigned exceptional : 1;
155*38fd1498Szrj 
156*38fd1498Szrj   /* Block is a call instrumenting site.  */
157*38fd1498Szrj   unsigned is_call_site : 1; /* Does the call.  */
158*38fd1498Szrj   unsigned is_call_return : 1; /* Is the return.  */
159*38fd1498Szrj 
160*38fd1498Szrj   /* Block is a landing pad for longjmp or throw.  */
161*38fd1498Szrj   unsigned is_nonlocal_return : 1;
162*38fd1498Szrj 
163*38fd1498Szrj   vector<block_location_info> locations;
164*38fd1498Szrj 
165*38fd1498Szrj   struct
166*38fd1498Szrj   {
167*38fd1498Szrj     /* Single line graph cycle workspace.  Used for all-blocks
168*38fd1498Szrj        mode.  */
169*38fd1498Szrj     arc_info *arc;
170*38fd1498Szrj     unsigned ident;
171*38fd1498Szrj   } cycle; /* Used in all-blocks mode, after blocks are linked onto
172*38fd1498Szrj 	     lines.  */
173*38fd1498Szrj 
174*38fd1498Szrj   /* Temporary chain for solving graph, and for chaining blocks on one
175*38fd1498Szrj      line.  */
176*38fd1498Szrj   struct block_info *chain;
177*38fd1498Szrj 
178*38fd1498Szrj };
179*38fd1498Szrj 
180*38fd1498Szrj block_info::block_info (): succ (NULL), pred (NULL), num_succ (0), num_pred (0),
181*38fd1498Szrj   id (0), count (0), count_valid (0), valid_chain (0), invalid_chain (0),
182*38fd1498Szrj   exceptional (0), is_call_site (0), is_call_return (0), is_nonlocal_return (0),
183*38fd1498Szrj   locations (), chain (NULL)
184*38fd1498Szrj {
185*38fd1498Szrj   cycle.arc = NULL;
186*38fd1498Szrj }
187*38fd1498Szrj 
188*38fd1498Szrj /* Describes a single line of source.  Contains a chain of basic blocks
189*38fd1498Szrj    with code on it.  */
190*38fd1498Szrj 
191*38fd1498Szrj struct line_info
192*38fd1498Szrj {
193*38fd1498Szrj   /* Default constructor.  */
194*38fd1498Szrj   line_info ();
195*38fd1498Szrj 
196*38fd1498Szrj   /* Return true when NEEDLE is one of basic blocks the line belongs to.  */
197*38fd1498Szrj   bool has_block (block_info *needle);
198*38fd1498Szrj 
199*38fd1498Szrj   /* Execution count.  */
200*38fd1498Szrj   gcov_type count;
201*38fd1498Szrj 
202*38fd1498Szrj   /* Branches from blocks that end on this line.  */
203*38fd1498Szrj   vector<arc_info *> branches;
204*38fd1498Szrj 
205*38fd1498Szrj   /* blocks which start on this line.  Used in all-blocks mode.  */
206*38fd1498Szrj   vector<block_info *> blocks;
207*38fd1498Szrj 
208*38fd1498Szrj   unsigned exists : 1;
209*38fd1498Szrj   unsigned unexceptional : 1;
210*38fd1498Szrj   unsigned has_unexecuted_block : 1;
211*38fd1498Szrj };
212*38fd1498Szrj 
213*38fd1498Szrj line_info::line_info (): count (0), branches (), blocks (), exists (false),
214*38fd1498Szrj   unexceptional (0), has_unexecuted_block (0)
215*38fd1498Szrj {
216*38fd1498Szrj }
217*38fd1498Szrj 
218*38fd1498Szrj bool
219*38fd1498Szrj line_info::has_block (block_info *needle)
220*38fd1498Szrj {
221*38fd1498Szrj   return std::find (blocks.begin (), blocks.end (), needle) != blocks.end ();
222*38fd1498Szrj }
223*38fd1498Szrj 
224*38fd1498Szrj /* Describes a single function. Contains an array of basic blocks.  */
225*38fd1498Szrj 
226*38fd1498Szrj struct function_info
227*38fd1498Szrj {
228*38fd1498Szrj   function_info ();
229*38fd1498Szrj   ~function_info ();
230*38fd1498Szrj 
231*38fd1498Szrj   /* Return true when line N belongs to the function in source file SRC_IDX.
232*38fd1498Szrj      The line must be defined in body of the function, can't be inlined.  */
233*38fd1498Szrj   bool group_line_p (unsigned n, unsigned src_idx);
234*38fd1498Szrj 
235*38fd1498Szrj   /* Function filter based on function_info::artificial variable.  */
236*38fd1498Szrj 
237*38fd1498Szrj   static inline bool
238*38fd1498Szrj   is_artificial (function_info *fn)
239*38fd1498Szrj   {
240*38fd1498Szrj     return fn->artificial;
241*38fd1498Szrj   }
242*38fd1498Szrj 
243*38fd1498Szrj   /* Name of function.  */
244*38fd1498Szrj   char *name;
245*38fd1498Szrj   char *demangled_name;
246*38fd1498Szrj   unsigned ident;
247*38fd1498Szrj   unsigned lineno_checksum;
248*38fd1498Szrj   unsigned cfg_checksum;
249*38fd1498Szrj 
250*38fd1498Szrj   /* The graph contains at least one fake incoming edge.  */
251*38fd1498Szrj   unsigned has_catch : 1;
252*38fd1498Szrj 
253*38fd1498Szrj   /* True when the function is artificial and does not exist
254*38fd1498Szrj      in a source file.  */
255*38fd1498Szrj   unsigned artificial : 1;
256*38fd1498Szrj 
257*38fd1498Szrj   /* True when multiple functions start at a line in a source file.  */
258*38fd1498Szrj   unsigned is_group : 1;
259*38fd1498Szrj 
260*38fd1498Szrj   /* Array of basic blocks.  Like in GCC, the entry block is
261*38fd1498Szrj      at blocks[0] and the exit block is at blocks[1].  */
262*38fd1498Szrj #define ENTRY_BLOCK (0)
263*38fd1498Szrj #define EXIT_BLOCK (1)
264*38fd1498Szrj   vector<block_info> blocks;
265*38fd1498Szrj   unsigned blocks_executed;
266*38fd1498Szrj 
267*38fd1498Szrj   /* Raw arc coverage counts.  */
268*38fd1498Szrj   vector<gcov_type> counts;
269*38fd1498Szrj 
270*38fd1498Szrj   /* First line number.  */
271*38fd1498Szrj   unsigned start_line;
272*38fd1498Szrj 
273*38fd1498Szrj   /* First line column.  */
274*38fd1498Szrj   unsigned start_column;
275*38fd1498Szrj 
276*38fd1498Szrj   /* Last line number.  */
277*38fd1498Szrj   unsigned end_line;
278*38fd1498Szrj 
279*38fd1498Szrj   /* Index of source file where the function is defined.  */
280*38fd1498Szrj   unsigned src;
281*38fd1498Szrj 
282*38fd1498Szrj   /* Vector of line information.  */
283*38fd1498Szrj   vector<line_info> lines;
284*38fd1498Szrj 
285*38fd1498Szrj   /* Next function.  */
286*38fd1498Szrj   struct function_info *next;
287*38fd1498Szrj };
288*38fd1498Szrj 
289*38fd1498Szrj /* Function info comparer that will sort functions according to starting
290*38fd1498Szrj    line.  */
291*38fd1498Szrj 
292*38fd1498Szrj struct function_line_start_cmp
293*38fd1498Szrj {
294*38fd1498Szrj   inline bool operator() (const function_info *lhs,
295*38fd1498Szrj 			  const function_info *rhs)
296*38fd1498Szrj     {
297*38fd1498Szrj       return (lhs->start_line == rhs->start_line
298*38fd1498Szrj 	      ? lhs->start_column < rhs->start_column
299*38fd1498Szrj 	      : lhs->start_line < rhs->start_line);
300*38fd1498Szrj     }
301*38fd1498Szrj };
302*38fd1498Szrj 
303*38fd1498Szrj /* Describes coverage of a file or function.  */
304*38fd1498Szrj 
305*38fd1498Szrj struct coverage_info
306*38fd1498Szrj {
307*38fd1498Szrj   int lines;
308*38fd1498Szrj   int lines_executed;
309*38fd1498Szrj 
310*38fd1498Szrj   int branches;
311*38fd1498Szrj   int branches_executed;
312*38fd1498Szrj   int branches_taken;
313*38fd1498Szrj 
314*38fd1498Szrj   int calls;
315*38fd1498Szrj   int calls_executed;
316*38fd1498Szrj 
317*38fd1498Szrj   char *name;
318*38fd1498Szrj };
319*38fd1498Szrj 
320*38fd1498Szrj /* Describes a file mentioned in the block graph.  Contains an array
321*38fd1498Szrj    of line info.  */
322*38fd1498Szrj 
323*38fd1498Szrj struct source_info
324*38fd1498Szrj {
325*38fd1498Szrj   /* Default constructor.  */
326*38fd1498Szrj   source_info ();
327*38fd1498Szrj 
328*38fd1498Szrj   vector<function_info *> get_functions_at_location (unsigned line_num) const;
329*38fd1498Szrj 
330*38fd1498Szrj   /* Index of the source_info in sources vector.  */
331*38fd1498Szrj   unsigned index;
332*38fd1498Szrj 
333*38fd1498Szrj   /* Canonical name of source file.  */
334*38fd1498Szrj   char *name;
335*38fd1498Szrj   time_t file_time;
336*38fd1498Szrj 
337*38fd1498Szrj   /* Vector of line information.  */
338*38fd1498Szrj   vector<line_info> lines;
339*38fd1498Szrj 
340*38fd1498Szrj   coverage_info coverage;
341*38fd1498Szrj 
342*38fd1498Szrj   /* Functions in this source file.  These are in ascending line
343*38fd1498Szrj      number order.  */
344*38fd1498Szrj   vector <function_info *> functions;
345*38fd1498Szrj };
346*38fd1498Szrj 
347*38fd1498Szrj source_info::source_info (): index (0), name (NULL), file_time (),
348*38fd1498Szrj   lines (), coverage (), functions ()
349*38fd1498Szrj {
350*38fd1498Szrj }
351*38fd1498Szrj 
352*38fd1498Szrj vector<function_info *>
353*38fd1498Szrj source_info::get_functions_at_location (unsigned line_num) const
354*38fd1498Szrj {
355*38fd1498Szrj   vector<function_info *> r;
356*38fd1498Szrj 
357*38fd1498Szrj   for (vector<function_info *>::const_iterator it = functions.begin ();
358*38fd1498Szrj        it != functions.end (); it++)
359*38fd1498Szrj     {
360*38fd1498Szrj       if ((*it)->start_line == line_num && (*it)->src == index)
361*38fd1498Szrj 	r.push_back (*it);
362*38fd1498Szrj     }
363*38fd1498Szrj 
364*38fd1498Szrj   std::sort (r.begin (), r.end (), function_line_start_cmp ());
365*38fd1498Szrj 
366*38fd1498Szrj   return r;
367*38fd1498Szrj }
368*38fd1498Szrj 
369*38fd1498Szrj class name_map
370*38fd1498Szrj {
371*38fd1498Szrj public:
372*38fd1498Szrj   name_map ()
373*38fd1498Szrj   {
374*38fd1498Szrj   }
375*38fd1498Szrj 
376*38fd1498Szrj   name_map (char *_name, unsigned _src): name (_name), src (_src)
377*38fd1498Szrj   {
378*38fd1498Szrj   }
379*38fd1498Szrj 
380*38fd1498Szrj   bool operator== (const name_map &rhs) const
381*38fd1498Szrj   {
382*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM
383*38fd1498Szrj     return strcasecmp (this->name, rhs.name) == 0;
384*38fd1498Szrj #else
385*38fd1498Szrj     return strcmp (this->name, rhs.name) == 0;
386*38fd1498Szrj #endif
387*38fd1498Szrj   }
388*38fd1498Szrj 
389*38fd1498Szrj   bool operator< (const name_map &rhs) const
390*38fd1498Szrj   {
391*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM
392*38fd1498Szrj     return strcasecmp (this->name, rhs.name) < 0;
393*38fd1498Szrj #else
394*38fd1498Szrj     return strcmp (this->name, rhs.name) < 0;
395*38fd1498Szrj #endif
396*38fd1498Szrj   }
397*38fd1498Szrj 
398*38fd1498Szrj   const char *name;  /* Source file name */
399*38fd1498Szrj   unsigned src;  /* Source file */
400*38fd1498Szrj };
401*38fd1498Szrj 
402*38fd1498Szrj /* Vector of all functions.  */
403*38fd1498Szrj static vector<function_info *> functions;
404*38fd1498Szrj 
405*38fd1498Szrj /* Vector of source files.  */
406*38fd1498Szrj static vector<source_info> sources;
407*38fd1498Szrj 
408*38fd1498Szrj /* Mapping of file names to sources */
409*38fd1498Szrj static vector<name_map> names;
410*38fd1498Szrj 
411*38fd1498Szrj /* This holds data summary information.  */
412*38fd1498Szrj 
413*38fd1498Szrj static unsigned object_runs;
414*38fd1498Szrj static unsigned program_count;
415*38fd1498Szrj 
416*38fd1498Szrj static unsigned total_lines;
417*38fd1498Szrj static unsigned total_executed;
418*38fd1498Szrj 
419*38fd1498Szrj /* Modification time of graph file.  */
420*38fd1498Szrj 
421*38fd1498Szrj static time_t bbg_file_time;
422*38fd1498Szrj 
423*38fd1498Szrj /* Name of the notes (gcno) output file.  The "bbg" prefix is for
424*38fd1498Szrj    historical reasons, when the notes file contained only the
425*38fd1498Szrj    basic block graph notes.  */
426*38fd1498Szrj 
427*38fd1498Szrj static char *bbg_file_name;
428*38fd1498Szrj 
429*38fd1498Szrj /* Stamp of the bbg file */
430*38fd1498Szrj static unsigned bbg_stamp;
431*38fd1498Szrj 
432*38fd1498Szrj /* Supports has_unexecuted_blocks functionality.  */
433*38fd1498Szrj static unsigned bbg_supports_has_unexecuted_blocks;
434*38fd1498Szrj 
435*38fd1498Szrj /* Name and file pointer of the input file for the count data (gcda).  */
436*38fd1498Szrj 
437*38fd1498Szrj static char *da_file_name;
438*38fd1498Szrj 
439*38fd1498Szrj /* Data file is missing.  */
440*38fd1498Szrj 
441*38fd1498Szrj static int no_data_file;
442*38fd1498Szrj 
443*38fd1498Szrj /* If there is several input files, compute and display results after
444*38fd1498Szrj    reading all data files.  This way if two or more gcda file refer to
445*38fd1498Szrj    the same source file (eg inline subprograms in a .h file), the
446*38fd1498Szrj    counts are added.  */
447*38fd1498Szrj 
448*38fd1498Szrj static int multiple_files = 0;
449*38fd1498Szrj 
450*38fd1498Szrj /* Output branch probabilities.  */
451*38fd1498Szrj 
452*38fd1498Szrj static int flag_branches = 0;
453*38fd1498Szrj 
454*38fd1498Szrj /* Show unconditional branches too.  */
455*38fd1498Szrj static int flag_unconditional = 0;
456*38fd1498Szrj 
457*38fd1498Szrj /* Output a gcov file if this is true.  This is on by default, and can
458*38fd1498Szrj    be turned off by the -n option.  */
459*38fd1498Szrj 
460*38fd1498Szrj static int flag_gcov_file = 1;
461*38fd1498Szrj 
462*38fd1498Szrj /* Output progress indication if this is true.  This is off by default
463*38fd1498Szrj    and can be turned on by the -d option.  */
464*38fd1498Szrj 
465*38fd1498Szrj static int flag_display_progress = 0;
466*38fd1498Szrj 
467*38fd1498Szrj /* Output *.gcov file in intermediate format used by 'lcov'.  */
468*38fd1498Szrj 
469*38fd1498Szrj static int flag_intermediate_format = 0;
470*38fd1498Szrj 
471*38fd1498Szrj /* Output demangled function names.  */
472*38fd1498Szrj 
473*38fd1498Szrj static int flag_demangled_names = 0;
474*38fd1498Szrj 
475*38fd1498Szrj /* For included files, make the gcov output file name include the name
476*38fd1498Szrj    of the input source file.  For example, if x.h is included in a.c,
477*38fd1498Szrj    then the output file name is a.c##x.h.gcov instead of x.h.gcov.  */
478*38fd1498Szrj 
479*38fd1498Szrj static int flag_long_names = 0;
480*38fd1498Szrj 
481*38fd1498Szrj /* For situations when a long name can potentially hit filesystem path limit,
482*38fd1498Szrj    let's calculate md5sum of the path and append it to a file name.  */
483*38fd1498Szrj 
484*38fd1498Szrj static int flag_hash_filenames = 0;
485*38fd1498Szrj 
486*38fd1498Szrj /* Print verbose informations.  */
487*38fd1498Szrj 
488*38fd1498Szrj static int flag_verbose = 0;
489*38fd1498Szrj 
490*38fd1498Szrj /* Print colored output.  */
491*38fd1498Szrj 
492*38fd1498Szrj static int flag_use_colors = 0;
493*38fd1498Szrj 
494*38fd1498Szrj /* Output count information for every basic block, not merely those
495*38fd1498Szrj    that contain line number information.  */
496*38fd1498Szrj 
497*38fd1498Szrj static int flag_all_blocks = 0;
498*38fd1498Szrj 
499*38fd1498Szrj /* Output human readable numbers.  */
500*38fd1498Szrj 
501*38fd1498Szrj static int flag_human_readable_numbers = 0;
502*38fd1498Szrj 
503*38fd1498Szrj /* Output summary info for each function.  */
504*38fd1498Szrj 
505*38fd1498Szrj static int flag_function_summary = 0;
506*38fd1498Szrj 
507*38fd1498Szrj /* Object directory file prefix.  This is the directory/file where the
508*38fd1498Szrj    graph and data files are looked for, if nonzero.  */
509*38fd1498Szrj 
510*38fd1498Szrj static char *object_directory = 0;
511*38fd1498Szrj 
512*38fd1498Szrj /* Source directory prefix.  This is removed from source pathnames
513*38fd1498Szrj    that match, when generating the output file name.  */
514*38fd1498Szrj 
515*38fd1498Szrj static char *source_prefix = 0;
516*38fd1498Szrj static size_t source_length = 0;
517*38fd1498Szrj 
518*38fd1498Szrj /* Only show data for sources with relative pathnames.  Absolute ones
519*38fd1498Szrj    usually indicate a system header file, which although it may
520*38fd1498Szrj    contain inline functions, is usually uninteresting.  */
521*38fd1498Szrj static int flag_relative_only = 0;
522*38fd1498Szrj 
523*38fd1498Szrj /* Preserve all pathname components. Needed when object files and
524*38fd1498Szrj    source files are in subdirectories. '/' is mangled as '#', '.' is
525*38fd1498Szrj    elided and '..' mangled to '^'.  */
526*38fd1498Szrj 
527*38fd1498Szrj static int flag_preserve_paths = 0;
528*38fd1498Szrj 
529*38fd1498Szrj /* Output the number of times a branch was taken as opposed to the percentage
530*38fd1498Szrj    of times it was taken.  */
531*38fd1498Szrj 
532*38fd1498Szrj static int flag_counts = 0;
533*38fd1498Szrj 
534*38fd1498Szrj /* Forward declarations.  */
535*38fd1498Szrj static int process_args (int, char **);
536*38fd1498Szrj static void print_usage (int) ATTRIBUTE_NORETURN;
537*38fd1498Szrj static void print_version (void) ATTRIBUTE_NORETURN;
538*38fd1498Szrj static void process_file (const char *);
539*38fd1498Szrj static void generate_results (const char *);
540*38fd1498Szrj static void create_file_names (const char *);
541*38fd1498Szrj static char *canonicalize_name (const char *);
542*38fd1498Szrj static unsigned find_source (const char *);
543*38fd1498Szrj static void read_graph_file (void);
544*38fd1498Szrj static int read_count_file (void);
545*38fd1498Szrj static void solve_flow_graph (function_info *);
546*38fd1498Szrj static void find_exception_blocks (function_info *);
547*38fd1498Szrj static void add_branch_counts (coverage_info *, const arc_info *);
548*38fd1498Szrj static void add_line_counts (coverage_info *, function_info *);
549*38fd1498Szrj static void executed_summary (unsigned, unsigned);
550*38fd1498Szrj static void function_summary (const coverage_info *, const char *);
551*38fd1498Szrj static const char *format_gcov (gcov_type, gcov_type, int);
552*38fd1498Szrj static void accumulate_line_counts (source_info *);
553*38fd1498Szrj static void output_gcov_file (const char *, source_info *);
554*38fd1498Szrj static int output_branch_count (FILE *, int, const arc_info *);
555*38fd1498Szrj static void output_lines (FILE *, const source_info *);
556*38fd1498Szrj static char *make_gcov_file_name (const char *, const char *);
557*38fd1498Szrj static char *mangle_name (const char *, char *);
558*38fd1498Szrj static void release_structures (void);
559*38fd1498Szrj extern int main (int, char **);
560*38fd1498Szrj 
561*38fd1498Szrj function_info::function_info (): name (NULL), demangled_name (NULL),
562*38fd1498Szrj   ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
563*38fd1498Szrj   artificial (0), is_group (0),
564*38fd1498Szrj   blocks (), blocks_executed (0), counts (),
565*38fd1498Szrj   start_line (0), start_column (), end_line (0), src (0), lines (), next (NULL)
566*38fd1498Szrj {
567*38fd1498Szrj }
568*38fd1498Szrj 
569*38fd1498Szrj function_info::~function_info ()
570*38fd1498Szrj {
571*38fd1498Szrj   for (int i = blocks.size () - 1; i >= 0; i--)
572*38fd1498Szrj     {
573*38fd1498Szrj       arc_info *arc, *arc_n;
574*38fd1498Szrj 
575*38fd1498Szrj       for (arc = blocks[i].succ; arc; arc = arc_n)
576*38fd1498Szrj 	{
577*38fd1498Szrj 	  arc_n = arc->succ_next;
578*38fd1498Szrj 	  free (arc);
579*38fd1498Szrj 	}
580*38fd1498Szrj     }
581*38fd1498Szrj   if (flag_demangled_names && demangled_name != name)
582*38fd1498Szrj     free (demangled_name);
583*38fd1498Szrj   free (name);
584*38fd1498Szrj }
585*38fd1498Szrj 
586*38fd1498Szrj bool function_info::group_line_p (unsigned n, unsigned src_idx)
587*38fd1498Szrj {
588*38fd1498Szrj   return is_group && src == src_idx && start_line <= n && n <= end_line;
589*38fd1498Szrj }
590*38fd1498Szrj 
591*38fd1498Szrj /* Cycle detection!
592*38fd1498Szrj    There are a bajillion algorithms that do this.  Boost's function is named
593*38fd1498Szrj    hawick_cycles, so I used the algorithm by K. A. Hawick and H. A. James in
594*38fd1498Szrj    "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
595*38fd1498Szrj    (url at <http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf>).
596*38fd1498Szrj 
597*38fd1498Szrj    The basic algorithm is simple: effectively, we're finding all simple paths
598*38fd1498Szrj    in a subgraph (that shrinks every iteration).  Duplicates are filtered by
599*38fd1498Szrj    "blocking" a path when a node is added to the path (this also prevents non-
600*38fd1498Szrj    simple paths)--the node is unblocked only when it participates in a cycle.
601*38fd1498Szrj    */
602*38fd1498Szrj 
603*38fd1498Szrj typedef vector<arc_info *> arc_vector_t;
604*38fd1498Szrj typedef vector<const block_info *> block_vector_t;
605*38fd1498Szrj 
606*38fd1498Szrj /* Enum with types of loop in CFG.  */
607*38fd1498Szrj 
608*38fd1498Szrj enum loop_type
609*38fd1498Szrj {
610*38fd1498Szrj   NO_LOOP = 0,
611*38fd1498Szrj   LOOP = 1,
612*38fd1498Szrj   NEGATIVE_LOOP = 3
613*38fd1498Szrj };
614*38fd1498Szrj 
615*38fd1498Szrj /* Loop_type operator that merges two values: A and B.  */
616*38fd1498Szrj 
617*38fd1498Szrj inline loop_type& operator |= (loop_type& a, loop_type b)
618*38fd1498Szrj {
619*38fd1498Szrj     return a = static_cast<loop_type> (a | b);
620*38fd1498Szrj }
621*38fd1498Szrj 
622*38fd1498Szrj /* Handle cycle identified by EDGES, where the function finds minimum cs_count
623*38fd1498Szrj    and subtract the value from all counts.  The subtracted value is added
624*38fd1498Szrj    to COUNT.  Returns type of loop.  */
625*38fd1498Szrj 
626*38fd1498Szrj static loop_type
627*38fd1498Szrj handle_cycle (const arc_vector_t &edges, int64_t &count)
628*38fd1498Szrj {
629*38fd1498Szrj   /* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
630*38fd1498Szrj      that amount.  */
631*38fd1498Szrj   int64_t cycle_count = INTTYPE_MAXIMUM (int64_t);
632*38fd1498Szrj   for (unsigned i = 0; i < edges.size (); i++)
633*38fd1498Szrj     {
634*38fd1498Szrj       int64_t ecount = edges[i]->cs_count;
635*38fd1498Szrj       if (cycle_count > ecount)
636*38fd1498Szrj 	cycle_count = ecount;
637*38fd1498Szrj     }
638*38fd1498Szrj   count += cycle_count;
639*38fd1498Szrj   for (unsigned i = 0; i < edges.size (); i++)
640*38fd1498Szrj     edges[i]->cs_count -= cycle_count;
641*38fd1498Szrj 
642*38fd1498Szrj   return cycle_count < 0 ? NEGATIVE_LOOP : LOOP;
643*38fd1498Szrj }
644*38fd1498Szrj 
645*38fd1498Szrj /* Unblock a block U from BLOCKED.  Apart from that, iterate all blocks
646*38fd1498Szrj    blocked by U in BLOCK_LISTS.  */
647*38fd1498Szrj 
648*38fd1498Szrj static void
649*38fd1498Szrj unblock (const block_info *u, block_vector_t &blocked,
650*38fd1498Szrj 	 vector<block_vector_t > &block_lists)
651*38fd1498Szrj {
652*38fd1498Szrj   block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u);
653*38fd1498Szrj   if (it == blocked.end ())
654*38fd1498Szrj     return;
655*38fd1498Szrj 
656*38fd1498Szrj   unsigned index = it - blocked.begin ();
657*38fd1498Szrj   blocked.erase (it);
658*38fd1498Szrj 
659*38fd1498Szrj   block_vector_t to_unblock (block_lists[index]);
660*38fd1498Szrj 
661*38fd1498Szrj   block_lists.erase (block_lists.begin () + index);
662*38fd1498Szrj 
663*38fd1498Szrj   for (block_vector_t::iterator it = to_unblock.begin ();
664*38fd1498Szrj        it != to_unblock.end (); it++)
665*38fd1498Szrj     unblock (*it, blocked, block_lists);
666*38fd1498Szrj }
667*38fd1498Szrj 
668*38fd1498Szrj /* Find circuit going to block V, PATH is provisional seen cycle.
669*38fd1498Szrj    BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
670*38fd1498Szrj    blocked by a block.  COUNT is accumulated count of the current LINE.
671*38fd1498Szrj    Returns what type of loop it contains.  */
672*38fd1498Szrj 
673*38fd1498Szrj static loop_type
674*38fd1498Szrj circuit (block_info *v, arc_vector_t &path, block_info *start,
675*38fd1498Szrj 	 block_vector_t &blocked, vector<block_vector_t> &block_lists,
676*38fd1498Szrj 	 line_info &linfo, int64_t &count)
677*38fd1498Szrj {
678*38fd1498Szrj   loop_type result = NO_LOOP;
679*38fd1498Szrj 
680*38fd1498Szrj   /* Add v to the block list.  */
681*38fd1498Szrj   gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
682*38fd1498Szrj   blocked.push_back (v);
683*38fd1498Szrj   block_lists.push_back (block_vector_t ());
684*38fd1498Szrj 
685*38fd1498Szrj   for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
686*38fd1498Szrj     {
687*38fd1498Szrj       block_info *w = arc->dst;
688*38fd1498Szrj       if (w < start || !linfo.has_block (w))
689*38fd1498Szrj 	continue;
690*38fd1498Szrj 
691*38fd1498Szrj       path.push_back (arc);
692*38fd1498Szrj       if (w == start)
693*38fd1498Szrj 	/* Cycle has been found.  */
694*38fd1498Szrj 	result |= handle_cycle (path, count);
695*38fd1498Szrj       else if (find (blocked.begin (), blocked.end (), w) == blocked.end ())
696*38fd1498Szrj 	result |= circuit (w, path, start, blocked, block_lists, linfo, count);
697*38fd1498Szrj 
698*38fd1498Szrj       path.pop_back ();
699*38fd1498Szrj     }
700*38fd1498Szrj 
701*38fd1498Szrj   if (result != NO_LOOP)
702*38fd1498Szrj     unblock (v, blocked, block_lists);
703*38fd1498Szrj   else
704*38fd1498Szrj     for (arc_info *arc = v->succ; arc; arc = arc->succ_next)
705*38fd1498Szrj       {
706*38fd1498Szrj 	block_info *w = arc->dst;
707*38fd1498Szrj 	if (w < start || !linfo.has_block (w))
708*38fd1498Szrj 	  continue;
709*38fd1498Szrj 
710*38fd1498Szrj 	size_t index
711*38fd1498Szrj 	  = find (blocked.begin (), blocked.end (), w) - blocked.begin ();
712*38fd1498Szrj 	gcc_assert (index < blocked.size ());
713*38fd1498Szrj 	block_vector_t &list = block_lists[index];
714*38fd1498Szrj 	if (find (list.begin (), list.end (), v) == list.end ())
715*38fd1498Szrj 	  list.push_back (v);
716*38fd1498Szrj       }
717*38fd1498Szrj 
718*38fd1498Szrj   return result;
719*38fd1498Szrj }
720*38fd1498Szrj 
721*38fd1498Szrj /* Find cycles for a LINFO.  If HANDLE_NEGATIVE_CYCLES is set and the line
722*38fd1498Szrj    contains a negative loop, then perform the same function once again.  */
723*38fd1498Szrj 
724*38fd1498Szrj static gcov_type
725*38fd1498Szrj get_cycles_count (line_info &linfo, bool handle_negative_cycles = true)
726*38fd1498Szrj {
727*38fd1498Szrj   /* Note that this algorithm works even if blocks aren't in sorted order.
728*38fd1498Szrj      Each iteration of the circuit detection is completely independent
729*38fd1498Szrj      (except for reducing counts, but that shouldn't matter anyways).
730*38fd1498Szrj      Therefore, operating on a permuted order (i.e., non-sorted) only
731*38fd1498Szrj      has the effect of permuting the output cycles.  */
732*38fd1498Szrj 
733*38fd1498Szrj   loop_type result = NO_LOOP;
734*38fd1498Szrj   gcov_type count = 0;
735*38fd1498Szrj   for (vector<block_info *>::iterator it = linfo.blocks.begin ();
736*38fd1498Szrj        it != linfo.blocks.end (); it++)
737*38fd1498Szrj     {
738*38fd1498Szrj       arc_vector_t path;
739*38fd1498Szrj       block_vector_t blocked;
740*38fd1498Szrj       vector<block_vector_t > block_lists;
741*38fd1498Szrj       result |= circuit (*it, path, *it, blocked, block_lists, linfo,
742*38fd1498Szrj 			 count);
743*38fd1498Szrj     }
744*38fd1498Szrj 
745*38fd1498Szrj   /* If we have a negative cycle, repeat the find_cycles routine.  */
746*38fd1498Szrj   if (result == NEGATIVE_LOOP && handle_negative_cycles)
747*38fd1498Szrj     count += get_cycles_count (linfo, false);
748*38fd1498Szrj 
749*38fd1498Szrj   return count;
750*38fd1498Szrj }
751*38fd1498Szrj 
752*38fd1498Szrj int
753*38fd1498Szrj main (int argc, char **argv)
754*38fd1498Szrj {
755*38fd1498Szrj   int argno;
756*38fd1498Szrj   int first_arg;
757*38fd1498Szrj   const char *p;
758*38fd1498Szrj 
759*38fd1498Szrj   p = argv[0] + strlen (argv[0]);
760*38fd1498Szrj   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
761*38fd1498Szrj     --p;
762*38fd1498Szrj   progname = p;
763*38fd1498Szrj 
764*38fd1498Szrj   xmalloc_set_program_name (progname);
765*38fd1498Szrj 
766*38fd1498Szrj   /* Unlock the stdio streams.  */
767*38fd1498Szrj   unlock_std_streams ();
768*38fd1498Szrj 
769*38fd1498Szrj   gcc_init_libintl ();
770*38fd1498Szrj 
771*38fd1498Szrj   diagnostic_initialize (global_dc, 0);
772*38fd1498Szrj 
773*38fd1498Szrj   /* Handle response files.  */
774*38fd1498Szrj   expandargv (&argc, &argv);
775*38fd1498Szrj 
776*38fd1498Szrj   argno = process_args (argc, argv);
777*38fd1498Szrj   if (optind == argc)
778*38fd1498Szrj     print_usage (true);
779*38fd1498Szrj 
780*38fd1498Szrj   if (argc - argno > 1)
781*38fd1498Szrj     multiple_files = 1;
782*38fd1498Szrj 
783*38fd1498Szrj   first_arg = argno;
784*38fd1498Szrj 
785*38fd1498Szrj   for (; argno != argc; argno++)
786*38fd1498Szrj     {
787*38fd1498Szrj       if (flag_display_progress)
788*38fd1498Szrj 	printf ("Processing file %d out of %d\n", argno - first_arg + 1,
789*38fd1498Szrj 		argc - first_arg);
790*38fd1498Szrj       process_file (argv[argno]);
791*38fd1498Szrj 
792*38fd1498Szrj       if (flag_intermediate_format || argno == argc - 1)
793*38fd1498Szrj 	{
794*38fd1498Szrj 	  generate_results (argv[argno]);
795*38fd1498Szrj 	  release_structures ();
796*38fd1498Szrj 	}
797*38fd1498Szrj     }
798*38fd1498Szrj 
799*38fd1498Szrj   return 0;
800*38fd1498Szrj }
801*38fd1498Szrj 
802*38fd1498Szrj /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
803*38fd1498Szrj    otherwise the output of --help.  */
804*38fd1498Szrj 
805*38fd1498Szrj static void
806*38fd1498Szrj print_usage (int error_p)
807*38fd1498Szrj {
808*38fd1498Szrj   FILE *file = error_p ? stderr : stdout;
809*38fd1498Szrj   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
810*38fd1498Szrj 
811*38fd1498Szrj   fnotice (file, "Usage: gcov [OPTION...] SOURCE|OBJ...\n\n");
812*38fd1498Szrj   fnotice (file, "Print code coverage information.\n\n");
813*38fd1498Szrj   fnotice (file, "  -a, --all-blocks                Show information for every basic block\n");
814*38fd1498Szrj   fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output\n");
815*38fd1498Szrj   fnotice (file, "  -c, --branch-counts             Output counts of branches taken\n\
816*38fd1498Szrj                                     rather than percentages\n");
817*38fd1498Szrj   fnotice (file, "  -d, --display-progress          Display progress information\n");
818*38fd1498Szrj   fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
819*38fd1498Szrj   fnotice (file, "  -h, --help                      Print this help, then exit\n");
820*38fd1498Szrj   fnotice (file, "  -i, --intermediate-format       Output .gcov file in intermediate text format\n");
821*38fd1498Szrj   fnotice (file, "  -j, --human-readable            Output human readable numbers\n");
822*38fd1498Szrj   fnotice (file, "  -k, --use-colors                Emit colored output\n");
823*38fd1498Szrj   fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
824*38fd1498Szrj                                     source files\n");
825*38fd1498Szrj   fnotice (file, "  -m, --demangled-names           Output demangled function names\n");
826*38fd1498Szrj   fnotice (file, "  -n, --no-output                 Do not create an output file\n");
827*38fd1498Szrj   fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
828*38fd1498Szrj   fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
829*38fd1498Szrj   fnotice (file, "  -r, --relative-only             Only show data for relative sources\n");
830*38fd1498Szrj   fnotice (file, "  -s, --source-prefix DIR         Source prefix to elide\n");
831*38fd1498Szrj   fnotice (file, "  -u, --unconditional-branches    Show unconditional branch counts too\n");
832*38fd1498Szrj   fnotice (file, "  -v, --version                   Print version number, then exit\n");
833*38fd1498Szrj   fnotice (file, "  -w, --verbose                   Print verbose informations\n");
834*38fd1498Szrj   fnotice (file, "  -x, --hash-filenames            Hash long pathnames\n");
835*38fd1498Szrj   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
836*38fd1498Szrj 	   bug_report_url);
837*38fd1498Szrj   exit (status);
838*38fd1498Szrj }
839*38fd1498Szrj 
840*38fd1498Szrj /* Print version information and exit.  */
841*38fd1498Szrj 
842*38fd1498Szrj static void
843*38fd1498Szrj print_version (void)
844*38fd1498Szrj {
845*38fd1498Szrj   fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
846*38fd1498Szrj   fprintf (stdout, "Copyright %s 2018 Free Software Foundation, Inc.\n",
847*38fd1498Szrj 	   _("(C)"));
848*38fd1498Szrj   fnotice (stdout,
849*38fd1498Szrj 	   _("This is free software; see the source for copying conditions.\n"
850*38fd1498Szrj 	     "There is NO warranty; not even for MERCHANTABILITY or \n"
851*38fd1498Szrj 	     "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
852*38fd1498Szrj   exit (SUCCESS_EXIT_CODE);
853*38fd1498Szrj }
854*38fd1498Szrj 
855*38fd1498Szrj static const struct option options[] =
856*38fd1498Szrj {
857*38fd1498Szrj   { "help",                 no_argument,       NULL, 'h' },
858*38fd1498Szrj   { "version",              no_argument,       NULL, 'v' },
859*38fd1498Szrj   { "verbose",              no_argument,       NULL, 'w' },
860*38fd1498Szrj   { "all-blocks",           no_argument,       NULL, 'a' },
861*38fd1498Szrj   { "branch-probabilities", no_argument,       NULL, 'b' },
862*38fd1498Szrj   { "branch-counts",        no_argument,       NULL, 'c' },
863*38fd1498Szrj   { "intermediate-format",  no_argument,       NULL, 'i' },
864*38fd1498Szrj   { "human-readable",	    no_argument,       NULL, 'j' },
865*38fd1498Szrj   { "no-output",            no_argument,       NULL, 'n' },
866*38fd1498Szrj   { "long-file-names",      no_argument,       NULL, 'l' },
867*38fd1498Szrj   { "function-summaries",   no_argument,       NULL, 'f' },
868*38fd1498Szrj   { "demangled-names",      no_argument,       NULL, 'm' },
869*38fd1498Szrj   { "preserve-paths",       no_argument,       NULL, 'p' },
870*38fd1498Szrj   { "relative-only",        no_argument,       NULL, 'r' },
871*38fd1498Szrj   { "object-directory",     required_argument, NULL, 'o' },
872*38fd1498Szrj   { "object-file",          required_argument, NULL, 'o' },
873*38fd1498Szrj   { "source-prefix",        required_argument, NULL, 's' },
874*38fd1498Szrj   { "unconditional-branches", no_argument,     NULL, 'u' },
875*38fd1498Szrj   { "display-progress",     no_argument,       NULL, 'd' },
876*38fd1498Szrj   { "hash-filenames",	    no_argument,       NULL, 'x' },
877*38fd1498Szrj   { "use-colors",	    no_argument,       NULL, 'k' },
878*38fd1498Szrj   { 0, 0, 0, 0 }
879*38fd1498Szrj };
880*38fd1498Szrj 
881*38fd1498Szrj /* Process args, return index to first non-arg.  */
882*38fd1498Szrj 
883*38fd1498Szrj static int
884*38fd1498Szrj process_args (int argc, char **argv)
885*38fd1498Szrj {
886*38fd1498Szrj   int opt;
887*38fd1498Szrj 
888*38fd1498Szrj   const char *opts = "abcdfhijklmno:prs:uvwx";
889*38fd1498Szrj   while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
890*38fd1498Szrj     {
891*38fd1498Szrj       switch (opt)
892*38fd1498Szrj 	{
893*38fd1498Szrj 	case 'a':
894*38fd1498Szrj 	  flag_all_blocks = 1;
895*38fd1498Szrj 	  break;
896*38fd1498Szrj 	case 'b':
897*38fd1498Szrj 	  flag_branches = 1;
898*38fd1498Szrj 	  break;
899*38fd1498Szrj 	case 'c':
900*38fd1498Szrj 	  flag_counts = 1;
901*38fd1498Szrj 	  break;
902*38fd1498Szrj 	case 'f':
903*38fd1498Szrj 	  flag_function_summary = 1;
904*38fd1498Szrj 	  break;
905*38fd1498Szrj 	case 'h':
906*38fd1498Szrj 	  print_usage (false);
907*38fd1498Szrj 	  /* print_usage will exit.  */
908*38fd1498Szrj 	case 'l':
909*38fd1498Szrj 	  flag_long_names = 1;
910*38fd1498Szrj 	  break;
911*38fd1498Szrj 	case 'j':
912*38fd1498Szrj 	  flag_human_readable_numbers = 1;
913*38fd1498Szrj 	  break;
914*38fd1498Szrj 	case 'k':
915*38fd1498Szrj 	  flag_use_colors = 1;
916*38fd1498Szrj 	  break;
917*38fd1498Szrj 	case 'm':
918*38fd1498Szrj 	  flag_demangled_names = 1;
919*38fd1498Szrj 	  break;
920*38fd1498Szrj 	case 'n':
921*38fd1498Szrj 	  flag_gcov_file = 0;
922*38fd1498Szrj 	  break;
923*38fd1498Szrj 	case 'o':
924*38fd1498Szrj 	  object_directory = optarg;
925*38fd1498Szrj 	  break;
926*38fd1498Szrj 	case 's':
927*38fd1498Szrj 	  source_prefix = optarg;
928*38fd1498Szrj 	  source_length = strlen (source_prefix);
929*38fd1498Szrj 	  break;
930*38fd1498Szrj 	case 'r':
931*38fd1498Szrj 	  flag_relative_only = 1;
932*38fd1498Szrj 	  break;
933*38fd1498Szrj 	case 'p':
934*38fd1498Szrj 	  flag_preserve_paths = 1;
935*38fd1498Szrj 	  break;
936*38fd1498Szrj 	case 'u':
937*38fd1498Szrj 	  flag_unconditional = 1;
938*38fd1498Szrj 	  break;
939*38fd1498Szrj 	case 'i':
940*38fd1498Szrj           flag_intermediate_format = 1;
941*38fd1498Szrj           flag_gcov_file = 1;
942*38fd1498Szrj           break;
943*38fd1498Szrj         case 'd':
944*38fd1498Szrj           flag_display_progress = 1;
945*38fd1498Szrj           break;
946*38fd1498Szrj 	case 'x':
947*38fd1498Szrj 	  flag_hash_filenames = 1;
948*38fd1498Szrj 	  break;
949*38fd1498Szrj 	case 'w':
950*38fd1498Szrj 	  flag_verbose = 1;
951*38fd1498Szrj 	  break;
952*38fd1498Szrj 	case 'v':
953*38fd1498Szrj 	  print_version ();
954*38fd1498Szrj 	  /* print_version will exit.  */
955*38fd1498Szrj 	default:
956*38fd1498Szrj 	  print_usage (true);
957*38fd1498Szrj 	  /* print_usage will exit.  */
958*38fd1498Szrj 	}
959*38fd1498Szrj     }
960*38fd1498Szrj 
961*38fd1498Szrj   return optind;
962*38fd1498Szrj }
963*38fd1498Szrj 
964*38fd1498Szrj /* Output intermediate LINE sitting on LINE_NUM to output file F.  */
965*38fd1498Szrj 
966*38fd1498Szrj static void
967*38fd1498Szrj output_intermediate_line (FILE *f, line_info *line, unsigned line_num)
968*38fd1498Szrj {
969*38fd1498Szrj   if (!line->exists)
970*38fd1498Szrj     return;
971*38fd1498Szrj 
972*38fd1498Szrj   fprintf (f, "lcount:%u,%s,%d\n", line_num,
973*38fd1498Szrj 	   format_gcov (line->count, 0, -1),
974*38fd1498Szrj 	   line->has_unexecuted_block);
975*38fd1498Szrj 
976*38fd1498Szrj   vector<arc_info *>::const_iterator it;
977*38fd1498Szrj   if (flag_branches)
978*38fd1498Szrj     for (it = line->branches.begin (); it != line->branches.end ();
979*38fd1498Szrj 	 it++)
980*38fd1498Szrj       {
981*38fd1498Szrj 	if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
982*38fd1498Szrj 	  {
983*38fd1498Szrj 	    const char *branch_type;
984*38fd1498Szrj 	    /* branch:<line_num>,<branch_coverage_infoype>
985*38fd1498Szrj 	       branch_coverage_infoype
986*38fd1498Szrj 	       : notexec (Branch not executed)
987*38fd1498Szrj 	       : taken (Branch executed and taken)
988*38fd1498Szrj 	       : nottaken (Branch executed, but not taken)
989*38fd1498Szrj 	       */
990*38fd1498Szrj 	    if ((*it)->src->count)
991*38fd1498Szrj 		 branch_type
992*38fd1498Szrj 			= ((*it)->count > 0) ? "taken" : "nottaken";
993*38fd1498Szrj 	    else
994*38fd1498Szrj 	      branch_type = "notexec";
995*38fd1498Szrj 	    fprintf (f, "branch:%d,%s\n", line_num, branch_type);
996*38fd1498Szrj 	  }
997*38fd1498Szrj       }
998*38fd1498Szrj }
999*38fd1498Szrj 
1000*38fd1498Szrj /* Get the name of the gcov file.  The return value must be free'd.
1001*38fd1498Szrj 
1002*38fd1498Szrj    It appends the '.gcov' extension to the *basename* of the file.
1003*38fd1498Szrj    The resulting file name will be in PWD.
1004*38fd1498Szrj 
1005*38fd1498Szrj    e.g.,
1006*38fd1498Szrj    input: foo.da,       output: foo.da.gcov
1007*38fd1498Szrj    input: a/b/foo.cc,   output: foo.cc.gcov  */
1008*38fd1498Szrj 
1009*38fd1498Szrj static char *
1010*38fd1498Szrj get_gcov_intermediate_filename (const char *file_name)
1011*38fd1498Szrj {
1012*38fd1498Szrj   const char *gcov = ".gcov";
1013*38fd1498Szrj   char *result;
1014*38fd1498Szrj   const char *cptr;
1015*38fd1498Szrj 
1016*38fd1498Szrj   /* Find the 'basename'.  */
1017*38fd1498Szrj   cptr = lbasename (file_name);
1018*38fd1498Szrj 
1019*38fd1498Szrj   result = XNEWVEC (char, strlen (cptr) + strlen (gcov) + 1);
1020*38fd1498Szrj   sprintf (result, "%s%s", cptr, gcov);
1021*38fd1498Szrj 
1022*38fd1498Szrj   return result;
1023*38fd1498Szrj }
1024*38fd1498Szrj 
1025*38fd1498Szrj /* Output the result in intermediate format used by 'lcov'.
1026*38fd1498Szrj 
1027*38fd1498Szrj The intermediate format contains a single file named 'foo.cc.gcov',
1028*38fd1498Szrj with no source code included.
1029*38fd1498Szrj 
1030*38fd1498Szrj The default gcov outputs multiple files: 'foo.cc.gcov',
1031*38fd1498Szrj 'iostream.gcov', 'ios_base.h.gcov', etc. with source code
1032*38fd1498Szrj included. Instead the intermediate format here outputs only a single
1033*38fd1498Szrj file 'foo.cc.gcov' similar to the above example. */
1034*38fd1498Szrj 
1035*38fd1498Szrj static void
1036*38fd1498Szrj output_intermediate_file (FILE *gcov_file, source_info *src)
1037*38fd1498Szrj {
1038*38fd1498Szrj   fprintf (gcov_file, "version:%s\n", version_string);
1039*38fd1498Szrj   fprintf (gcov_file, "file:%s\n", src->name);    /* source file name */
1040*38fd1498Szrj 
1041*38fd1498Szrj   std::sort (src->functions.begin (), src->functions.end (),
1042*38fd1498Szrj 	     function_line_start_cmp ());
1043*38fd1498Szrj   for (vector<function_info *>::iterator it = src->functions.begin ();
1044*38fd1498Szrj        it != src->functions.end (); it++)
1045*38fd1498Szrj     {
1046*38fd1498Szrj       /* function:<name>,<line_number>,<execution_count> */
1047*38fd1498Szrj       fprintf (gcov_file, "function:%d,%d,%s,%s\n", (*it)->start_line,
1048*38fd1498Szrj 	       (*it)->end_line, format_gcov ((*it)->blocks[0].count, 0, -1),
1049*38fd1498Szrj 	       flag_demangled_names ? (*it)->demangled_name : (*it)->name);
1050*38fd1498Szrj     }
1051*38fd1498Szrj 
1052*38fd1498Szrj   for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
1053*38fd1498Szrj     {
1054*38fd1498Szrj       vector<function_info *> fns = src->get_functions_at_location (line_num);
1055*38fd1498Szrj 
1056*38fd1498Szrj       /* Print first group functions that begin on the line.  */
1057*38fd1498Szrj       for (vector<function_info *>::iterator it2 = fns.begin ();
1058*38fd1498Szrj 	   it2 != fns.end (); it2++)
1059*38fd1498Szrj 	{
1060*38fd1498Szrj 	  vector<line_info> &lines = (*it2)->lines;
1061*38fd1498Szrj 	  for (unsigned i = 0; i < lines.size (); i++)
1062*38fd1498Szrj 	    {
1063*38fd1498Szrj 	      line_info *line = &lines[i];
1064*38fd1498Szrj 	      output_intermediate_line (gcov_file, line, line_num + i);
1065*38fd1498Szrj 	    }
1066*38fd1498Szrj 	}
1067*38fd1498Szrj 
1068*38fd1498Szrj       /* Follow with lines associated with the source file.  */
1069*38fd1498Szrj       output_intermediate_line (gcov_file, &src->lines[line_num], line_num);
1070*38fd1498Szrj     }
1071*38fd1498Szrj }
1072*38fd1498Szrj 
1073*38fd1498Szrj /* Function start pair.  */
1074*38fd1498Szrj struct function_start
1075*38fd1498Szrj {
1076*38fd1498Szrj   unsigned source_file_idx;
1077*38fd1498Szrj   unsigned start_line;
1078*38fd1498Szrj };
1079*38fd1498Szrj 
1080*38fd1498Szrj /* Traits class for function start hash maps below.  */
1081*38fd1498Szrj 
1082*38fd1498Szrj struct function_start_pair_hash : typed_noop_remove <function_start>
1083*38fd1498Szrj {
1084*38fd1498Szrj   typedef function_start value_type;
1085*38fd1498Szrj   typedef function_start compare_type;
1086*38fd1498Szrj 
1087*38fd1498Szrj   static hashval_t
1088*38fd1498Szrj   hash (const function_start &ref)
1089*38fd1498Szrj   {
1090*38fd1498Szrj     inchash::hash hstate (0);
1091*38fd1498Szrj     hstate.add_int (ref.source_file_idx);
1092*38fd1498Szrj     hstate.add_int (ref.start_line);
1093*38fd1498Szrj     return hstate.end ();
1094*38fd1498Szrj   }
1095*38fd1498Szrj 
1096*38fd1498Szrj   static bool
1097*38fd1498Szrj   equal (const function_start &ref1, const function_start &ref2)
1098*38fd1498Szrj   {
1099*38fd1498Szrj     return (ref1.source_file_idx == ref2.source_file_idx
1100*38fd1498Szrj 	    && ref1.start_line == ref2.start_line);
1101*38fd1498Szrj   }
1102*38fd1498Szrj 
1103*38fd1498Szrj   static void
1104*38fd1498Szrj   mark_deleted (function_start &ref)
1105*38fd1498Szrj   {
1106*38fd1498Szrj     ref.start_line = ~1U;
1107*38fd1498Szrj   }
1108*38fd1498Szrj 
1109*38fd1498Szrj   static void
1110*38fd1498Szrj   mark_empty (function_start &ref)
1111*38fd1498Szrj   {
1112*38fd1498Szrj     ref.start_line = ~2U;
1113*38fd1498Szrj   }
1114*38fd1498Szrj 
1115*38fd1498Szrj   static bool
1116*38fd1498Szrj   is_deleted (const function_start &ref)
1117*38fd1498Szrj   {
1118*38fd1498Szrj     return ref.start_line == ~1U;
1119*38fd1498Szrj   }
1120*38fd1498Szrj 
1121*38fd1498Szrj   static bool
1122*38fd1498Szrj   is_empty (const function_start &ref)
1123*38fd1498Szrj   {
1124*38fd1498Szrj     return ref.start_line == ~2U;
1125*38fd1498Szrj   }
1126*38fd1498Szrj };
1127*38fd1498Szrj 
1128*38fd1498Szrj /* Process a single input file.  */
1129*38fd1498Szrj 
1130*38fd1498Szrj static void
1131*38fd1498Szrj process_file (const char *file_name)
1132*38fd1498Szrj {
1133*38fd1498Szrj   create_file_names (file_name);
1134*38fd1498Szrj   read_graph_file ();
1135*38fd1498Szrj   if (functions.empty ())
1136*38fd1498Szrj     return;
1137*38fd1498Szrj 
1138*38fd1498Szrj   read_count_file ();
1139*38fd1498Szrj 
1140*38fd1498Szrj   hash_map<function_start_pair_hash, function_info *> fn_map;
1141*38fd1498Szrj 
1142*38fd1498Szrj   /* Identify group functions.  */
1143*38fd1498Szrj   for (vector<function_info *>::iterator it = functions.begin ();
1144*38fd1498Szrj        it != functions.end (); it++)
1145*38fd1498Szrj     if (!(*it)->artificial)
1146*38fd1498Szrj       {
1147*38fd1498Szrj 	function_start needle;
1148*38fd1498Szrj 	needle.source_file_idx = (*it)->src;
1149*38fd1498Szrj 	needle.start_line = (*it)->start_line;
1150*38fd1498Szrj 
1151*38fd1498Szrj 	function_info **slot = fn_map.get (needle);
1152*38fd1498Szrj 	if (slot)
1153*38fd1498Szrj 	  {
1154*38fd1498Szrj 	    (*slot)->is_group = 1;
1155*38fd1498Szrj 	    (*it)->is_group = 1;
1156*38fd1498Szrj 	  }
1157*38fd1498Szrj 	else
1158*38fd1498Szrj 	  fn_map.put (needle, *it);
1159*38fd1498Szrj       }
1160*38fd1498Szrj 
1161*38fd1498Szrj   /* Remove all artificial function.  */
1162*38fd1498Szrj   functions.erase (remove_if (functions.begin (), functions.end (),
1163*38fd1498Szrj 			      function_info::is_artificial), functions.end ());
1164*38fd1498Szrj 
1165*38fd1498Szrj   for (vector<function_info *>::iterator it = functions.begin ();
1166*38fd1498Szrj        it != functions.end (); it++)
1167*38fd1498Szrj     {
1168*38fd1498Szrj       function_info *fn = *it;
1169*38fd1498Szrj       unsigned src = fn->src;
1170*38fd1498Szrj 
1171*38fd1498Szrj       if (!fn->counts.empty () || no_data_file)
1172*38fd1498Szrj 	{
1173*38fd1498Szrj 	  source_info *s = &sources[src];
1174*38fd1498Szrj 	  s->functions.push_back (fn);
1175*38fd1498Szrj 
1176*38fd1498Szrj 	  /* Mark last line in files touched by function.  */
1177*38fd1498Szrj 	  for (unsigned block_no = 0; block_no != fn->blocks.size ();
1178*38fd1498Szrj 	       block_no++)
1179*38fd1498Szrj 	    {
1180*38fd1498Szrj 	      block_info *block = &fn->blocks[block_no];
1181*38fd1498Szrj 	      for (unsigned i = 0; i < block->locations.size (); i++)
1182*38fd1498Szrj 		{
1183*38fd1498Szrj 		  /* Sort lines of locations.  */
1184*38fd1498Szrj 		  sort (block->locations[i].lines.begin (),
1185*38fd1498Szrj 			block->locations[i].lines.end ());
1186*38fd1498Szrj 
1187*38fd1498Szrj 		  if (!block->locations[i].lines.empty ())
1188*38fd1498Szrj 		    {
1189*38fd1498Szrj 		      s = &sources[block->locations[i].source_file_idx];
1190*38fd1498Szrj 		      unsigned last_line
1191*38fd1498Szrj 			= block->locations[i].lines.back ();
1192*38fd1498Szrj 
1193*38fd1498Szrj 		      /* Record new lines for the function.  */
1194*38fd1498Szrj 		      if (last_line >= s->lines.size ())
1195*38fd1498Szrj 			{
1196*38fd1498Szrj 			  s = &sources[block->locations[i].source_file_idx];
1197*38fd1498Szrj 			  unsigned last_line
1198*38fd1498Szrj 			    = block->locations[i].lines.back ();
1199*38fd1498Szrj 
1200*38fd1498Szrj 			  /* Record new lines for the function.  */
1201*38fd1498Szrj 			  if (last_line >= s->lines.size ())
1202*38fd1498Szrj 			    {
1203*38fd1498Szrj 			      /* Record new lines for a source file.  */
1204*38fd1498Szrj 			      s->lines.resize (last_line + 1);
1205*38fd1498Szrj 			    }
1206*38fd1498Szrj 			}
1207*38fd1498Szrj 		    }
1208*38fd1498Szrj 		}
1209*38fd1498Szrj 	    }
1210*38fd1498Szrj 
1211*38fd1498Szrj 	  /* Allocate lines for group function, following start_line
1212*38fd1498Szrj 	     and end_line information of the function.  */
1213*38fd1498Szrj 	  if (fn->is_group)
1214*38fd1498Szrj 	    fn->lines.resize (fn->end_line - fn->start_line + 1);
1215*38fd1498Szrj 
1216*38fd1498Szrj 
1217*38fd1498Szrj 	  solve_flow_graph (fn);
1218*38fd1498Szrj 	  if (fn->has_catch)
1219*38fd1498Szrj 	    find_exception_blocks (fn);
1220*38fd1498Szrj 	}
1221*38fd1498Szrj       else
1222*38fd1498Szrj 	{
1223*38fd1498Szrj 	  /* The function was not in the executable -- some other
1224*38fd1498Szrj 	     instance must have been selected.  */
1225*38fd1498Szrj 	}
1226*38fd1498Szrj     }
1227*38fd1498Szrj }
1228*38fd1498Szrj 
1229*38fd1498Szrj static void
1230*38fd1498Szrj output_gcov_file (const char *file_name, source_info *src)
1231*38fd1498Szrj {
1232*38fd1498Szrj   char *gcov_file_name = make_gcov_file_name (file_name, src->coverage.name);
1233*38fd1498Szrj 
1234*38fd1498Szrj   if (src->coverage.lines)
1235*38fd1498Szrj     {
1236*38fd1498Szrj       FILE *gcov_file = fopen (gcov_file_name, "w");
1237*38fd1498Szrj       if (gcov_file)
1238*38fd1498Szrj 	{
1239*38fd1498Szrj 	  fnotice (stdout, "Creating '%s'\n", gcov_file_name);
1240*38fd1498Szrj 	  output_lines (gcov_file, src);
1241*38fd1498Szrj 	  if (ferror (gcov_file))
1242*38fd1498Szrj 	    fnotice (stderr, "Error writing output file '%s'\n",
1243*38fd1498Szrj 		     gcov_file_name);
1244*38fd1498Szrj 	  fclose (gcov_file);
1245*38fd1498Szrj 	}
1246*38fd1498Szrj       else
1247*38fd1498Szrj 	fnotice (stderr, "Could not open output file '%s'\n", gcov_file_name);
1248*38fd1498Szrj     }
1249*38fd1498Szrj   else
1250*38fd1498Szrj     {
1251*38fd1498Szrj       unlink (gcov_file_name);
1252*38fd1498Szrj       fnotice (stdout, "Removing '%s'\n", gcov_file_name);
1253*38fd1498Szrj     }
1254*38fd1498Szrj   free (gcov_file_name);
1255*38fd1498Szrj }
1256*38fd1498Szrj 
1257*38fd1498Szrj static void
1258*38fd1498Szrj generate_results (const char *file_name)
1259*38fd1498Szrj {
1260*38fd1498Szrj   FILE *gcov_intermediate_file = NULL;
1261*38fd1498Szrj   char *gcov_intermediate_filename = NULL;
1262*38fd1498Szrj 
1263*38fd1498Szrj   for (vector<function_info *>::iterator it = functions.begin ();
1264*38fd1498Szrj        it != functions.end (); it++)
1265*38fd1498Szrj     {
1266*38fd1498Szrj       function_info *fn = *it;
1267*38fd1498Szrj       coverage_info coverage;
1268*38fd1498Szrj 
1269*38fd1498Szrj       memset (&coverage, 0, sizeof (coverage));
1270*38fd1498Szrj       coverage.name = flag_demangled_names ? fn->demangled_name : fn->name;
1271*38fd1498Szrj       add_line_counts (flag_function_summary ? &coverage : NULL, fn);
1272*38fd1498Szrj       if (flag_function_summary)
1273*38fd1498Szrj 	{
1274*38fd1498Szrj 	  function_summary (&coverage, "Function");
1275*38fd1498Szrj 	  fnotice (stdout, "\n");
1276*38fd1498Szrj 	}
1277*38fd1498Szrj     }
1278*38fd1498Szrj 
1279*38fd1498Szrj   name_map needle;
1280*38fd1498Szrj 
1281*38fd1498Szrj   if (file_name)
1282*38fd1498Szrj     {
1283*38fd1498Szrj       needle.name = file_name;
1284*38fd1498Szrj       vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1285*38fd1498Szrj 						 needle);
1286*38fd1498Szrj       if (it != names.end ())
1287*38fd1498Szrj 	file_name = sources[it->src].coverage.name;
1288*38fd1498Szrj       else
1289*38fd1498Szrj 	file_name = canonicalize_name (file_name);
1290*38fd1498Szrj     }
1291*38fd1498Szrj 
1292*38fd1498Szrj   if (flag_gcov_file && flag_intermediate_format)
1293*38fd1498Szrj     {
1294*38fd1498Szrj       /* Open the intermediate file.  */
1295*38fd1498Szrj       gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
1296*38fd1498Szrj       gcov_intermediate_file = fopen (gcov_intermediate_filename, "w");
1297*38fd1498Szrj       if (!gcov_intermediate_file)
1298*38fd1498Szrj 	{
1299*38fd1498Szrj 	  fnotice (stderr, "Cannot open intermediate output file %s\n",
1300*38fd1498Szrj 		   gcov_intermediate_filename);
1301*38fd1498Szrj 	  return;
1302*38fd1498Szrj 	}
1303*38fd1498Szrj     }
1304*38fd1498Szrj 
1305*38fd1498Szrj   for (vector<source_info>::iterator it = sources.begin ();
1306*38fd1498Szrj        it != sources.end (); it++)
1307*38fd1498Szrj     {
1308*38fd1498Szrj       source_info *src = &(*it);
1309*38fd1498Szrj       if (flag_relative_only)
1310*38fd1498Szrj 	{
1311*38fd1498Szrj 	  /* Ignore this source, if it is an absolute path (after
1312*38fd1498Szrj 	     source prefix removal).  */
1313*38fd1498Szrj 	  char first = src->coverage.name[0];
1314*38fd1498Szrj 
1315*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM
1316*38fd1498Szrj 	  if (first && src->coverage.name[1] == ':')
1317*38fd1498Szrj 	    first = src->coverage.name[2];
1318*38fd1498Szrj #endif
1319*38fd1498Szrj 	  if (IS_DIR_SEPARATOR (first))
1320*38fd1498Szrj 	    continue;
1321*38fd1498Szrj 	}
1322*38fd1498Szrj 
1323*38fd1498Szrj       accumulate_line_counts (src);
1324*38fd1498Szrj       function_summary (&src->coverage, "File");
1325*38fd1498Szrj       total_lines += src->coverage.lines;
1326*38fd1498Szrj       total_executed += src->coverage.lines_executed;
1327*38fd1498Szrj       if (flag_gcov_file)
1328*38fd1498Szrj 	{
1329*38fd1498Szrj 	  if (flag_intermediate_format)
1330*38fd1498Szrj 	    /* Output the intermediate format without requiring source
1331*38fd1498Szrj 	       files.  This outputs a section to a *single* file.  */
1332*38fd1498Szrj 	    output_intermediate_file (gcov_intermediate_file, src);
1333*38fd1498Szrj 	  else
1334*38fd1498Szrj 	    output_gcov_file (file_name, src);
1335*38fd1498Szrj 	  fnotice (stdout, "\n");
1336*38fd1498Szrj 	}
1337*38fd1498Szrj     }
1338*38fd1498Szrj 
1339*38fd1498Szrj   if (flag_gcov_file && flag_intermediate_format)
1340*38fd1498Szrj     {
1341*38fd1498Szrj       /* Now we've finished writing the intermediate file.  */
1342*38fd1498Szrj       fclose (gcov_intermediate_file);
1343*38fd1498Szrj       XDELETEVEC (gcov_intermediate_filename);
1344*38fd1498Szrj     }
1345*38fd1498Szrj 
1346*38fd1498Szrj   if (!file_name)
1347*38fd1498Szrj     executed_summary (total_lines, total_executed);
1348*38fd1498Szrj }
1349*38fd1498Szrj 
1350*38fd1498Szrj /* Release all memory used.  */
1351*38fd1498Szrj 
1352*38fd1498Szrj static void
1353*38fd1498Szrj release_structures (void)
1354*38fd1498Szrj {
1355*38fd1498Szrj   for (vector<function_info *>::iterator it = functions.begin ();
1356*38fd1498Szrj        it != functions.end (); it++)
1357*38fd1498Szrj     delete (*it);
1358*38fd1498Szrj 
1359*38fd1498Szrj   sources.resize (0);
1360*38fd1498Szrj   names.resize (0);
1361*38fd1498Szrj   functions.resize (0);
1362*38fd1498Szrj }
1363*38fd1498Szrj 
1364*38fd1498Szrj /* Generate the names of the graph and data files.  If OBJECT_DIRECTORY
1365*38fd1498Szrj    is not specified, these are named from FILE_NAME sans extension.  If
1366*38fd1498Szrj    OBJECT_DIRECTORY is specified and is a directory, the files are in that
1367*38fd1498Szrj    directory, but named from the basename of the FILE_NAME, sans extension.
1368*38fd1498Szrj    Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
1369*38fd1498Szrj    and the data files are named from that.  */
1370*38fd1498Szrj 
1371*38fd1498Szrj static void
1372*38fd1498Szrj create_file_names (const char *file_name)
1373*38fd1498Szrj {
1374*38fd1498Szrj   char *cptr;
1375*38fd1498Szrj   char *name;
1376*38fd1498Szrj   int length = strlen (file_name);
1377*38fd1498Szrj   int base;
1378*38fd1498Szrj 
1379*38fd1498Szrj   /* Free previous file names.  */
1380*38fd1498Szrj   free (bbg_file_name);
1381*38fd1498Szrj   free (da_file_name);
1382*38fd1498Szrj   da_file_name = bbg_file_name = NULL;
1383*38fd1498Szrj   bbg_file_time = 0;
1384*38fd1498Szrj   bbg_stamp = 0;
1385*38fd1498Szrj 
1386*38fd1498Szrj   if (object_directory && object_directory[0])
1387*38fd1498Szrj     {
1388*38fd1498Szrj       struct stat status;
1389*38fd1498Szrj 
1390*38fd1498Szrj       length += strlen (object_directory) + 2;
1391*38fd1498Szrj       name = XNEWVEC (char, length);
1392*38fd1498Szrj       name[0] = 0;
1393*38fd1498Szrj 
1394*38fd1498Szrj       base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
1395*38fd1498Szrj       strcat (name, object_directory);
1396*38fd1498Szrj       if (base && (!IS_DIR_SEPARATOR (name[strlen (name) - 1])))
1397*38fd1498Szrj 	strcat (name, "/");
1398*38fd1498Szrj     }
1399*38fd1498Szrj   else
1400*38fd1498Szrj     {
1401*38fd1498Szrj       name = XNEWVEC (char, length + 1);
1402*38fd1498Szrj       strcpy (name, file_name);
1403*38fd1498Szrj       base = 0;
1404*38fd1498Szrj     }
1405*38fd1498Szrj 
1406*38fd1498Szrj   if (base)
1407*38fd1498Szrj     {
1408*38fd1498Szrj       /* Append source file name.  */
1409*38fd1498Szrj       const char *cptr = lbasename (file_name);
1410*38fd1498Szrj       strcat (name, cptr ? cptr : file_name);
1411*38fd1498Szrj     }
1412*38fd1498Szrj 
1413*38fd1498Szrj   /* Remove the extension.  */
1414*38fd1498Szrj   cptr = strrchr (CONST_CAST (char *, lbasename (name)), '.');
1415*38fd1498Szrj   if (cptr)
1416*38fd1498Szrj     *cptr = 0;
1417*38fd1498Szrj 
1418*38fd1498Szrj   length = strlen (name);
1419*38fd1498Szrj 
1420*38fd1498Szrj   bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
1421*38fd1498Szrj   strcpy (bbg_file_name, name);
1422*38fd1498Szrj   strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
1423*38fd1498Szrj 
1424*38fd1498Szrj   da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
1425*38fd1498Szrj   strcpy (da_file_name, name);
1426*38fd1498Szrj   strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
1427*38fd1498Szrj 
1428*38fd1498Szrj   free (name);
1429*38fd1498Szrj   return;
1430*38fd1498Szrj }
1431*38fd1498Szrj 
1432*38fd1498Szrj /* Find or create a source file structure for FILE_NAME. Copies
1433*38fd1498Szrj    FILE_NAME on creation */
1434*38fd1498Szrj 
1435*38fd1498Szrj static unsigned
1436*38fd1498Szrj find_source (const char *file_name)
1437*38fd1498Szrj {
1438*38fd1498Szrj   char *canon;
1439*38fd1498Szrj   unsigned idx;
1440*38fd1498Szrj   struct stat status;
1441*38fd1498Szrj 
1442*38fd1498Szrj   if (!file_name)
1443*38fd1498Szrj     file_name = "<unknown>";
1444*38fd1498Szrj 
1445*38fd1498Szrj   name_map needle;
1446*38fd1498Szrj   needle.name = file_name;
1447*38fd1498Szrj 
1448*38fd1498Szrj   vector<name_map>::iterator it = std::find (names.begin (), names.end (),
1449*38fd1498Szrj 					     needle);
1450*38fd1498Szrj   if (it != names.end ())
1451*38fd1498Szrj     {
1452*38fd1498Szrj       idx = it->src;
1453*38fd1498Szrj       goto check_date;
1454*38fd1498Szrj     }
1455*38fd1498Szrj 
1456*38fd1498Szrj   /* Not found, try the canonical name. */
1457*38fd1498Szrj   canon = canonicalize_name (file_name);
1458*38fd1498Szrj   needle.name = canon;
1459*38fd1498Szrj   it = std::find (names.begin (), names.end (), needle);
1460*38fd1498Szrj   if (it == names.end ())
1461*38fd1498Szrj     {
1462*38fd1498Szrj       /* Not found with canonical name, create a new source.  */
1463*38fd1498Szrj       source_info *src;
1464*38fd1498Szrj 
1465*38fd1498Szrj       idx = sources.size ();
1466*38fd1498Szrj       needle = name_map (canon, idx);
1467*38fd1498Szrj       names.push_back (needle);
1468*38fd1498Szrj 
1469*38fd1498Szrj       sources.push_back (source_info ());
1470*38fd1498Szrj       src = &sources.back ();
1471*38fd1498Szrj       src->name = canon;
1472*38fd1498Szrj       src->coverage.name = src->name;
1473*38fd1498Szrj       src->index = idx;
1474*38fd1498Szrj       if (source_length
1475*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM
1476*38fd1498Szrj 	  /* You lose if separators don't match exactly in the
1477*38fd1498Szrj 	     prefix.  */
1478*38fd1498Szrj 	  && !strncasecmp (source_prefix, src->coverage.name, source_length)
1479*38fd1498Szrj #else
1480*38fd1498Szrj 	  && !strncmp (source_prefix, src->coverage.name, source_length)
1481*38fd1498Szrj #endif
1482*38fd1498Szrj 	  && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
1483*38fd1498Szrj 	src->coverage.name += source_length + 1;
1484*38fd1498Szrj       if (!stat (src->name, &status))
1485*38fd1498Szrj 	src->file_time = status.st_mtime;
1486*38fd1498Szrj     }
1487*38fd1498Szrj   else
1488*38fd1498Szrj     idx = it->src;
1489*38fd1498Szrj 
1490*38fd1498Szrj   needle.name = file_name;
1491*38fd1498Szrj   if (std::find (names.begin (), names.end (), needle) == names.end ())
1492*38fd1498Szrj     {
1493*38fd1498Szrj       /* Append the non-canonical name.  */
1494*38fd1498Szrj       names.push_back (name_map (xstrdup (file_name), idx));
1495*38fd1498Szrj     }
1496*38fd1498Szrj 
1497*38fd1498Szrj   /* Resort the name map.  */
1498*38fd1498Szrj   std::sort (names.begin (), names.end ());
1499*38fd1498Szrj 
1500*38fd1498Szrj  check_date:
1501*38fd1498Szrj   if (sources[idx].file_time > bbg_file_time)
1502*38fd1498Szrj     {
1503*38fd1498Szrj       static int info_emitted;
1504*38fd1498Szrj 
1505*38fd1498Szrj       fnotice (stderr, "%s:source file is newer than notes file '%s'\n",
1506*38fd1498Szrj 	       file_name, bbg_file_name);
1507*38fd1498Szrj       if (!info_emitted)
1508*38fd1498Szrj 	{
1509*38fd1498Szrj 	  fnotice (stderr,
1510*38fd1498Szrj 		   "(the message is displayed only once per source file)\n");
1511*38fd1498Szrj 	  info_emitted = 1;
1512*38fd1498Szrj 	}
1513*38fd1498Szrj       sources[idx].file_time = 0;
1514*38fd1498Szrj     }
1515*38fd1498Szrj 
1516*38fd1498Szrj   return idx;
1517*38fd1498Szrj }
1518*38fd1498Szrj 
1519*38fd1498Szrj /* Read the notes file.  Save functions to FUNCTIONS global vector.  */
1520*38fd1498Szrj 
1521*38fd1498Szrj static void
1522*38fd1498Szrj read_graph_file (void)
1523*38fd1498Szrj {
1524*38fd1498Szrj   unsigned version;
1525*38fd1498Szrj   unsigned current_tag = 0;
1526*38fd1498Szrj   unsigned tag;
1527*38fd1498Szrj 
1528*38fd1498Szrj   if (!gcov_open (bbg_file_name, 1))
1529*38fd1498Szrj     {
1530*38fd1498Szrj       fnotice (stderr, "%s:cannot open notes file\n", bbg_file_name);
1531*38fd1498Szrj       return;
1532*38fd1498Szrj     }
1533*38fd1498Szrj   bbg_file_time = gcov_time ();
1534*38fd1498Szrj   if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1535*38fd1498Szrj     {
1536*38fd1498Szrj       fnotice (stderr, "%s:not a gcov notes file\n", bbg_file_name);
1537*38fd1498Szrj       gcov_close ();
1538*38fd1498Szrj       return;
1539*38fd1498Szrj     }
1540*38fd1498Szrj 
1541*38fd1498Szrj   version = gcov_read_unsigned ();
1542*38fd1498Szrj   if (version != GCOV_VERSION)
1543*38fd1498Szrj     {
1544*38fd1498Szrj       char v[4], e[4];
1545*38fd1498Szrj 
1546*38fd1498Szrj       GCOV_UNSIGNED2STRING (v, version);
1547*38fd1498Szrj       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1548*38fd1498Szrj 
1549*38fd1498Szrj       fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1550*38fd1498Szrj 	       bbg_file_name, v, e);
1551*38fd1498Szrj     }
1552*38fd1498Szrj   bbg_stamp = gcov_read_unsigned ();
1553*38fd1498Szrj   bbg_supports_has_unexecuted_blocks = gcov_read_unsigned ();
1554*38fd1498Szrj 
1555*38fd1498Szrj   function_info *fn = NULL;
1556*38fd1498Szrj   while ((tag = gcov_read_unsigned ()))
1557*38fd1498Szrj     {
1558*38fd1498Szrj       unsigned length = gcov_read_unsigned ();
1559*38fd1498Szrj       gcov_position_t base = gcov_position ();
1560*38fd1498Szrj 
1561*38fd1498Szrj       if (tag == GCOV_TAG_FUNCTION)
1562*38fd1498Szrj 	{
1563*38fd1498Szrj 	  char *function_name;
1564*38fd1498Szrj 	  unsigned ident;
1565*38fd1498Szrj 	  unsigned lineno_checksum, cfg_checksum;
1566*38fd1498Szrj 
1567*38fd1498Szrj 	  ident = gcov_read_unsigned ();
1568*38fd1498Szrj 	  lineno_checksum = gcov_read_unsigned ();
1569*38fd1498Szrj 	  cfg_checksum = gcov_read_unsigned ();
1570*38fd1498Szrj 	  function_name = xstrdup (gcov_read_string ());
1571*38fd1498Szrj 	  unsigned artificial = gcov_read_unsigned ();
1572*38fd1498Szrj 	  unsigned src_idx = find_source (gcov_read_string ());
1573*38fd1498Szrj 	  unsigned start_line = gcov_read_unsigned ();
1574*38fd1498Szrj 	  unsigned start_column = gcov_read_unsigned ();
1575*38fd1498Szrj 	  unsigned end_line = gcov_read_unsigned ();
1576*38fd1498Szrj 
1577*38fd1498Szrj 	  fn = new function_info ();
1578*38fd1498Szrj 	  functions.push_back (fn);
1579*38fd1498Szrj 	  fn->name = function_name;
1580*38fd1498Szrj 	  if (flag_demangled_names)
1581*38fd1498Szrj 	    {
1582*38fd1498Szrj 	      fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS);
1583*38fd1498Szrj 	      if (!fn->demangled_name)
1584*38fd1498Szrj 		fn->demangled_name = fn->name;
1585*38fd1498Szrj 	    }
1586*38fd1498Szrj 	  fn->ident = ident;
1587*38fd1498Szrj 	  fn->lineno_checksum = lineno_checksum;
1588*38fd1498Szrj 	  fn->cfg_checksum = cfg_checksum;
1589*38fd1498Szrj 	  fn->src = src_idx;
1590*38fd1498Szrj 	  fn->start_line = start_line;
1591*38fd1498Szrj 	  fn->start_column = start_column;
1592*38fd1498Szrj 	  fn->end_line = end_line;
1593*38fd1498Szrj 	  fn->artificial = artificial;
1594*38fd1498Szrj 
1595*38fd1498Szrj 	  current_tag = tag;
1596*38fd1498Szrj 	}
1597*38fd1498Szrj       else if (fn && tag == GCOV_TAG_BLOCKS)
1598*38fd1498Szrj 	{
1599*38fd1498Szrj 	  if (!fn->blocks.empty ())
1600*38fd1498Szrj 	    fnotice (stderr, "%s:already seen blocks for '%s'\n",
1601*38fd1498Szrj 		     bbg_file_name, fn->name);
1602*38fd1498Szrj 	  else
1603*38fd1498Szrj 	    fn->blocks.resize (gcov_read_unsigned ());
1604*38fd1498Szrj 	}
1605*38fd1498Szrj       else if (fn && tag == GCOV_TAG_ARCS)
1606*38fd1498Szrj 	{
1607*38fd1498Szrj 	  unsigned src = gcov_read_unsigned ();
1608*38fd1498Szrj 	  fn->blocks[src].id = src;
1609*38fd1498Szrj 	  unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1610*38fd1498Szrj 	  block_info *src_blk = &fn->blocks[src];
1611*38fd1498Szrj 	  unsigned mark_catches = 0;
1612*38fd1498Szrj 	  struct arc_info *arc;
1613*38fd1498Szrj 
1614*38fd1498Szrj 	  if (src >= fn->blocks.size () || fn->blocks[src].succ)
1615*38fd1498Szrj 	    goto corrupt;
1616*38fd1498Szrj 
1617*38fd1498Szrj 	  while (num_dests--)
1618*38fd1498Szrj 	    {
1619*38fd1498Szrj 	      unsigned dest = gcov_read_unsigned ();
1620*38fd1498Szrj 	      unsigned flags = gcov_read_unsigned ();
1621*38fd1498Szrj 
1622*38fd1498Szrj 	      if (dest >= fn->blocks.size ())
1623*38fd1498Szrj 		goto corrupt;
1624*38fd1498Szrj 	      arc = XCNEW (arc_info);
1625*38fd1498Szrj 
1626*38fd1498Szrj 	      arc->dst = &fn->blocks[dest];
1627*38fd1498Szrj 	      arc->src = src_blk;
1628*38fd1498Szrj 
1629*38fd1498Szrj 	      arc->count = 0;
1630*38fd1498Szrj 	      arc->count_valid = 0;
1631*38fd1498Szrj 	      arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
1632*38fd1498Szrj 	      arc->fake = !!(flags & GCOV_ARC_FAKE);
1633*38fd1498Szrj 	      arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
1634*38fd1498Szrj 
1635*38fd1498Szrj 	      arc->succ_next = src_blk->succ;
1636*38fd1498Szrj 	      src_blk->succ = arc;
1637*38fd1498Szrj 	      src_blk->num_succ++;
1638*38fd1498Szrj 
1639*38fd1498Szrj 	      arc->pred_next = fn->blocks[dest].pred;
1640*38fd1498Szrj 	      fn->blocks[dest].pred = arc;
1641*38fd1498Szrj 	      fn->blocks[dest].num_pred++;
1642*38fd1498Szrj 
1643*38fd1498Szrj 	      if (arc->fake)
1644*38fd1498Szrj 		{
1645*38fd1498Szrj 		  if (src)
1646*38fd1498Szrj 		    {
1647*38fd1498Szrj 		      /* Exceptional exit from this function, the
1648*38fd1498Szrj 			 source block must be a call.  */
1649*38fd1498Szrj 		      fn->blocks[src].is_call_site = 1;
1650*38fd1498Szrj 		      arc->is_call_non_return = 1;
1651*38fd1498Szrj 		      mark_catches = 1;
1652*38fd1498Szrj 		    }
1653*38fd1498Szrj 		  else
1654*38fd1498Szrj 		    {
1655*38fd1498Szrj 		      /* Non-local return from a callee of this
1656*38fd1498Szrj 			 function.  The destination block is a setjmp.  */
1657*38fd1498Szrj 		      arc->is_nonlocal_return = 1;
1658*38fd1498Szrj 		      fn->blocks[dest].is_nonlocal_return = 1;
1659*38fd1498Szrj 		    }
1660*38fd1498Szrj 		}
1661*38fd1498Szrj 
1662*38fd1498Szrj 	      if (!arc->on_tree)
1663*38fd1498Szrj 		fn->counts.push_back (0);
1664*38fd1498Szrj 	    }
1665*38fd1498Szrj 
1666*38fd1498Szrj 	  if (mark_catches)
1667*38fd1498Szrj 	    {
1668*38fd1498Szrj 	      /* We have a fake exit from this block.  The other
1669*38fd1498Szrj 		 non-fall through exits must be to catch handlers.
1670*38fd1498Szrj 		 Mark them as catch arcs.  */
1671*38fd1498Szrj 
1672*38fd1498Szrj 	      for (arc = src_blk->succ; arc; arc = arc->succ_next)
1673*38fd1498Szrj 		if (!arc->fake && !arc->fall_through)
1674*38fd1498Szrj 		  {
1675*38fd1498Szrj 		    arc->is_throw = 1;
1676*38fd1498Szrj 		    fn->has_catch = 1;
1677*38fd1498Szrj 		  }
1678*38fd1498Szrj 	    }
1679*38fd1498Szrj 	}
1680*38fd1498Szrj       else if (fn && tag == GCOV_TAG_LINES)
1681*38fd1498Szrj 	{
1682*38fd1498Szrj 	  unsigned blockno = gcov_read_unsigned ();
1683*38fd1498Szrj 	  block_info *block = &fn->blocks[blockno];
1684*38fd1498Szrj 
1685*38fd1498Szrj 	  if (blockno >= fn->blocks.size ())
1686*38fd1498Szrj 	    goto corrupt;
1687*38fd1498Szrj 
1688*38fd1498Szrj 	  while (true)
1689*38fd1498Szrj 	    {
1690*38fd1498Szrj 	      unsigned lineno = gcov_read_unsigned ();
1691*38fd1498Szrj 
1692*38fd1498Szrj 	      if (lineno)
1693*38fd1498Szrj 		block->locations.back ().lines.push_back (lineno);
1694*38fd1498Szrj 	      else
1695*38fd1498Szrj 		{
1696*38fd1498Szrj 		  const char *file_name = gcov_read_string ();
1697*38fd1498Szrj 
1698*38fd1498Szrj 		  if (!file_name)
1699*38fd1498Szrj 		    break;
1700*38fd1498Szrj 		  block->locations.push_back (block_location_info
1701*38fd1498Szrj 					      (find_source (file_name)));
1702*38fd1498Szrj 		}
1703*38fd1498Szrj 	    }
1704*38fd1498Szrj 	}
1705*38fd1498Szrj       else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
1706*38fd1498Szrj 	{
1707*38fd1498Szrj 	  fn = NULL;
1708*38fd1498Szrj 	  current_tag = 0;
1709*38fd1498Szrj 	}
1710*38fd1498Szrj       gcov_sync (base, length);
1711*38fd1498Szrj       if (gcov_is_error ())
1712*38fd1498Szrj 	{
1713*38fd1498Szrj 	corrupt:;
1714*38fd1498Szrj 	  fnotice (stderr, "%s:corrupted\n", bbg_file_name);
1715*38fd1498Szrj 	  break;
1716*38fd1498Szrj 	}
1717*38fd1498Szrj     }
1718*38fd1498Szrj   gcov_close ();
1719*38fd1498Szrj 
1720*38fd1498Szrj   if (functions.empty ())
1721*38fd1498Szrj     fnotice (stderr, "%s:no functions found\n", bbg_file_name);
1722*38fd1498Szrj }
1723*38fd1498Szrj 
1724*38fd1498Szrj /* Reads profiles from the count file and attach to each
1725*38fd1498Szrj    function. Return nonzero if fatal error.  */
1726*38fd1498Szrj 
1727*38fd1498Szrj static int
1728*38fd1498Szrj read_count_file (void)
1729*38fd1498Szrj {
1730*38fd1498Szrj   unsigned ix;
1731*38fd1498Szrj   unsigned version;
1732*38fd1498Szrj   unsigned tag;
1733*38fd1498Szrj   function_info *fn = NULL;
1734*38fd1498Szrj   int error = 0;
1735*38fd1498Szrj 
1736*38fd1498Szrj   if (!gcov_open (da_file_name, 1))
1737*38fd1498Szrj     {
1738*38fd1498Szrj       fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
1739*38fd1498Szrj 	       da_file_name);
1740*38fd1498Szrj       no_data_file = 1;
1741*38fd1498Szrj       return 0;
1742*38fd1498Szrj     }
1743*38fd1498Szrj   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
1744*38fd1498Szrj     {
1745*38fd1498Szrj       fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
1746*38fd1498Szrj     cleanup:;
1747*38fd1498Szrj       gcov_close ();
1748*38fd1498Szrj       return 1;
1749*38fd1498Szrj     }
1750*38fd1498Szrj   version = gcov_read_unsigned ();
1751*38fd1498Szrj   if (version != GCOV_VERSION)
1752*38fd1498Szrj     {
1753*38fd1498Szrj       char v[4], e[4];
1754*38fd1498Szrj 
1755*38fd1498Szrj       GCOV_UNSIGNED2STRING (v, version);
1756*38fd1498Szrj       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1757*38fd1498Szrj 
1758*38fd1498Szrj       fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
1759*38fd1498Szrj 	       da_file_name, v, e);
1760*38fd1498Szrj     }
1761*38fd1498Szrj   tag = gcov_read_unsigned ();
1762*38fd1498Szrj   if (tag != bbg_stamp)
1763*38fd1498Szrj     {
1764*38fd1498Szrj       fnotice (stderr, "%s:stamp mismatch with notes file\n", da_file_name);
1765*38fd1498Szrj       goto cleanup;
1766*38fd1498Szrj     }
1767*38fd1498Szrj 
1768*38fd1498Szrj   while ((tag = gcov_read_unsigned ()))
1769*38fd1498Szrj     {
1770*38fd1498Szrj       unsigned length = gcov_read_unsigned ();
1771*38fd1498Szrj       unsigned long base = gcov_position ();
1772*38fd1498Szrj 
1773*38fd1498Szrj       if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1774*38fd1498Szrj 	{
1775*38fd1498Szrj 	  struct gcov_summary summary;
1776*38fd1498Szrj 	  gcov_read_summary (&summary);
1777*38fd1498Szrj 	  object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs;
1778*38fd1498Szrj 	  program_count++;
1779*38fd1498Szrj 	}
1780*38fd1498Szrj       else if (tag == GCOV_TAG_FUNCTION && !length)
1781*38fd1498Szrj 	; /* placeholder  */
1782*38fd1498Szrj       else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
1783*38fd1498Szrj 	{
1784*38fd1498Szrj 	  unsigned ident;
1785*38fd1498Szrj 
1786*38fd1498Szrj 	  /* Try to find the function in the list.  To speed up the
1787*38fd1498Szrj 	     search, first start from the last function found.  */
1788*38fd1498Szrj 	  ident = gcov_read_unsigned ();
1789*38fd1498Szrj 
1790*38fd1498Szrj 	  fn = NULL;
1791*38fd1498Szrj 	  for (vector<function_info *>::reverse_iterator it
1792*38fd1498Szrj 	       = functions.rbegin (); it != functions.rend (); it++)
1793*38fd1498Szrj 	    {
1794*38fd1498Szrj 	      if ((*it)->ident == ident)
1795*38fd1498Szrj 		{
1796*38fd1498Szrj 		  fn = *it;
1797*38fd1498Szrj 		  break;
1798*38fd1498Szrj 		}
1799*38fd1498Szrj 	    }
1800*38fd1498Szrj 
1801*38fd1498Szrj 	  if (!fn)
1802*38fd1498Szrj 	    ;
1803*38fd1498Szrj 	  else if (gcov_read_unsigned () != fn->lineno_checksum
1804*38fd1498Szrj 		   || gcov_read_unsigned () != fn->cfg_checksum)
1805*38fd1498Szrj 	    {
1806*38fd1498Szrj 	    mismatch:;
1807*38fd1498Szrj 	      fnotice (stderr, "%s:profile mismatch for '%s'\n",
1808*38fd1498Szrj 		       da_file_name, fn->name);
1809*38fd1498Szrj 	      goto cleanup;
1810*38fd1498Szrj 	    }
1811*38fd1498Szrj 	}
1812*38fd1498Szrj       else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1813*38fd1498Szrj 	{
1814*38fd1498Szrj 	  if (length != GCOV_TAG_COUNTER_LENGTH (fn->counts.size ()))
1815*38fd1498Szrj 	    goto mismatch;
1816*38fd1498Szrj 
1817*38fd1498Szrj 	  for (ix = 0; ix != fn->counts.size (); ix++)
1818*38fd1498Szrj 	    fn->counts[ix] += gcov_read_counter ();
1819*38fd1498Szrj 	}
1820*38fd1498Szrj       gcov_sync (base, length);
1821*38fd1498Szrj       if ((error = gcov_is_error ()))
1822*38fd1498Szrj 	{
1823*38fd1498Szrj 	  fnotice (stderr,
1824*38fd1498Szrj 		   error < 0
1825*38fd1498Szrj 		   ? N_("%s:overflowed\n")
1826*38fd1498Szrj 		   : N_("%s:corrupted\n"),
1827*38fd1498Szrj 		   da_file_name);
1828*38fd1498Szrj 	  goto cleanup;
1829*38fd1498Szrj 	}
1830*38fd1498Szrj     }
1831*38fd1498Szrj 
1832*38fd1498Szrj   gcov_close ();
1833*38fd1498Szrj   return 0;
1834*38fd1498Szrj }
1835*38fd1498Szrj 
1836*38fd1498Szrj /* Solve the flow graph. Propagate counts from the instrumented arcs
1837*38fd1498Szrj    to the blocks and the uninstrumented arcs.  */
1838*38fd1498Szrj 
1839*38fd1498Szrj static void
1840*38fd1498Szrj solve_flow_graph (function_info *fn)
1841*38fd1498Szrj {
1842*38fd1498Szrj   unsigned ix;
1843*38fd1498Szrj   arc_info *arc;
1844*38fd1498Szrj   gcov_type *count_ptr = &fn->counts.front ();
1845*38fd1498Szrj   block_info *blk;
1846*38fd1498Szrj   block_info *valid_blocks = NULL;    /* valid, but unpropagated blocks.  */
1847*38fd1498Szrj   block_info *invalid_blocks = NULL;  /* invalid, but inferable blocks.  */
1848*38fd1498Szrj 
1849*38fd1498Szrj   /* The arcs were built in reverse order.  Fix that now.  */
1850*38fd1498Szrj   for (ix = fn->blocks.size (); ix--;)
1851*38fd1498Szrj     {
1852*38fd1498Szrj       arc_info *arc_p, *arc_n;
1853*38fd1498Szrj 
1854*38fd1498Szrj       for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
1855*38fd1498Szrj 	   arc_p = arc, arc = arc_n)
1856*38fd1498Szrj 	{
1857*38fd1498Szrj 	  arc_n = arc->succ_next;
1858*38fd1498Szrj 	  arc->succ_next = arc_p;
1859*38fd1498Szrj 	}
1860*38fd1498Szrj       fn->blocks[ix].succ = arc_p;
1861*38fd1498Szrj 
1862*38fd1498Szrj       for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
1863*38fd1498Szrj 	   arc_p = arc, arc = arc_n)
1864*38fd1498Szrj 	{
1865*38fd1498Szrj 	  arc_n = arc->pred_next;
1866*38fd1498Szrj 	  arc->pred_next = arc_p;
1867*38fd1498Szrj 	}
1868*38fd1498Szrj       fn->blocks[ix].pred = arc_p;
1869*38fd1498Szrj     }
1870*38fd1498Szrj 
1871*38fd1498Szrj   if (fn->blocks.size () < 2)
1872*38fd1498Szrj     fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
1873*38fd1498Szrj 	     bbg_file_name, fn->name);
1874*38fd1498Szrj   else
1875*38fd1498Szrj     {
1876*38fd1498Szrj       if (fn->blocks[ENTRY_BLOCK].num_pred)
1877*38fd1498Szrj 	fnotice (stderr, "%s:'%s' has arcs to entry block\n",
1878*38fd1498Szrj 		 bbg_file_name, fn->name);
1879*38fd1498Szrj       else
1880*38fd1498Szrj 	/* We can't deduce the entry block counts from the lack of
1881*38fd1498Szrj 	   predecessors.  */
1882*38fd1498Szrj 	fn->blocks[ENTRY_BLOCK].num_pred = ~(unsigned)0;
1883*38fd1498Szrj 
1884*38fd1498Szrj       if (fn->blocks[EXIT_BLOCK].num_succ)
1885*38fd1498Szrj 	fnotice (stderr, "%s:'%s' has arcs from exit block\n",
1886*38fd1498Szrj 		 bbg_file_name, fn->name);
1887*38fd1498Szrj       else
1888*38fd1498Szrj 	/* Likewise, we can't deduce exit block counts from the lack
1889*38fd1498Szrj 	   of its successors.  */
1890*38fd1498Szrj 	fn->blocks[EXIT_BLOCK].num_succ = ~(unsigned)0;
1891*38fd1498Szrj     }
1892*38fd1498Szrj 
1893*38fd1498Szrj   /* Propagate the measured counts, this must be done in the same
1894*38fd1498Szrj      order as the code in profile.c  */
1895*38fd1498Szrj   for (unsigned i = 0; i < fn->blocks.size (); i++)
1896*38fd1498Szrj     {
1897*38fd1498Szrj       blk = &fn->blocks[i];
1898*38fd1498Szrj       block_info const *prev_dst = NULL;
1899*38fd1498Szrj       int out_of_order = 0;
1900*38fd1498Szrj       int non_fake_succ = 0;
1901*38fd1498Szrj 
1902*38fd1498Szrj       for (arc = blk->succ; arc; arc = arc->succ_next)
1903*38fd1498Szrj 	{
1904*38fd1498Szrj 	  if (!arc->fake)
1905*38fd1498Szrj 	    non_fake_succ++;
1906*38fd1498Szrj 
1907*38fd1498Szrj 	  if (!arc->on_tree)
1908*38fd1498Szrj 	    {
1909*38fd1498Szrj 	      if (count_ptr)
1910*38fd1498Szrj 		arc->count = *count_ptr++;
1911*38fd1498Szrj 	      arc->count_valid = 1;
1912*38fd1498Szrj 	      blk->num_succ--;
1913*38fd1498Szrj 	      arc->dst->num_pred--;
1914*38fd1498Szrj 	    }
1915*38fd1498Szrj 	  if (prev_dst && prev_dst > arc->dst)
1916*38fd1498Szrj 	    out_of_order = 1;
1917*38fd1498Szrj 	  prev_dst = arc->dst;
1918*38fd1498Szrj 	}
1919*38fd1498Szrj       if (non_fake_succ == 1)
1920*38fd1498Szrj 	{
1921*38fd1498Szrj 	  /* If there is only one non-fake exit, it is an
1922*38fd1498Szrj 	     unconditional branch.  */
1923*38fd1498Szrj 	  for (arc = blk->succ; arc; arc = arc->succ_next)
1924*38fd1498Szrj 	    if (!arc->fake)
1925*38fd1498Szrj 	      {
1926*38fd1498Szrj 		arc->is_unconditional = 1;
1927*38fd1498Szrj 		/* If this block is instrumenting a call, it might be
1928*38fd1498Szrj 		   an artificial block. It is not artificial if it has
1929*38fd1498Szrj 		   a non-fallthrough exit, or the destination of this
1930*38fd1498Szrj 		   arc has more than one entry.  Mark the destination
1931*38fd1498Szrj 		   block as a return site, if none of those conditions
1932*38fd1498Szrj 		   hold.  */
1933*38fd1498Szrj 		if (blk->is_call_site && arc->fall_through
1934*38fd1498Szrj 		    && arc->dst->pred == arc && !arc->pred_next)
1935*38fd1498Szrj 		  arc->dst->is_call_return = 1;
1936*38fd1498Szrj 	      }
1937*38fd1498Szrj 	}
1938*38fd1498Szrj 
1939*38fd1498Szrj       /* Sort the successor arcs into ascending dst order. profile.c
1940*38fd1498Szrj 	 normally produces arcs in the right order, but sometimes with
1941*38fd1498Szrj 	 one or two out of order.  We're not using a particularly
1942*38fd1498Szrj 	 smart sort.  */
1943*38fd1498Szrj       if (out_of_order)
1944*38fd1498Szrj 	{
1945*38fd1498Szrj 	  arc_info *start = blk->succ;
1946*38fd1498Szrj 	  unsigned changes = 1;
1947*38fd1498Szrj 
1948*38fd1498Szrj 	  while (changes)
1949*38fd1498Szrj 	    {
1950*38fd1498Szrj 	      arc_info *arc, *arc_p, *arc_n;
1951*38fd1498Szrj 
1952*38fd1498Szrj 	      changes = 0;
1953*38fd1498Szrj 	      for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1954*38fd1498Szrj 		{
1955*38fd1498Szrj 		  if (arc->dst > arc_n->dst)
1956*38fd1498Szrj 		    {
1957*38fd1498Szrj 		      changes = 1;
1958*38fd1498Szrj 		      if (arc_p)
1959*38fd1498Szrj 			arc_p->succ_next = arc_n;
1960*38fd1498Szrj 		      else
1961*38fd1498Szrj 			start = arc_n;
1962*38fd1498Szrj 		      arc->succ_next = arc_n->succ_next;
1963*38fd1498Szrj 		      arc_n->succ_next = arc;
1964*38fd1498Szrj 		      arc_p = arc_n;
1965*38fd1498Szrj 		    }
1966*38fd1498Szrj 		  else
1967*38fd1498Szrj 		    {
1968*38fd1498Szrj 		      arc_p = arc;
1969*38fd1498Szrj 		      arc = arc_n;
1970*38fd1498Szrj 		    }
1971*38fd1498Szrj 		}
1972*38fd1498Szrj 	    }
1973*38fd1498Szrj 	  blk->succ = start;
1974*38fd1498Szrj 	}
1975*38fd1498Szrj 
1976*38fd1498Szrj       /* Place it on the invalid chain, it will be ignored if that's
1977*38fd1498Szrj 	 wrong.  */
1978*38fd1498Szrj       blk->invalid_chain = 1;
1979*38fd1498Szrj       blk->chain = invalid_blocks;
1980*38fd1498Szrj       invalid_blocks = blk;
1981*38fd1498Szrj     }
1982*38fd1498Szrj 
1983*38fd1498Szrj   while (invalid_blocks || valid_blocks)
1984*38fd1498Szrj     {
1985*38fd1498Szrj       while ((blk = invalid_blocks))
1986*38fd1498Szrj 	{
1987*38fd1498Szrj 	  gcov_type total = 0;
1988*38fd1498Szrj 	  const arc_info *arc;
1989*38fd1498Szrj 
1990*38fd1498Szrj 	  invalid_blocks = blk->chain;
1991*38fd1498Szrj 	  blk->invalid_chain = 0;
1992*38fd1498Szrj 	  if (!blk->num_succ)
1993*38fd1498Szrj 	    for (arc = blk->succ; arc; arc = arc->succ_next)
1994*38fd1498Szrj 	      total += arc->count;
1995*38fd1498Szrj 	  else if (!blk->num_pred)
1996*38fd1498Szrj 	    for (arc = blk->pred; arc; arc = arc->pred_next)
1997*38fd1498Szrj 	      total += arc->count;
1998*38fd1498Szrj 	  else
1999*38fd1498Szrj 	    continue;
2000*38fd1498Szrj 
2001*38fd1498Szrj 	  blk->count = total;
2002*38fd1498Szrj 	  blk->count_valid = 1;
2003*38fd1498Szrj 	  blk->chain = valid_blocks;
2004*38fd1498Szrj 	  blk->valid_chain = 1;
2005*38fd1498Szrj 	  valid_blocks = blk;
2006*38fd1498Szrj 	}
2007*38fd1498Szrj       while ((blk = valid_blocks))
2008*38fd1498Szrj 	{
2009*38fd1498Szrj 	  gcov_type total;
2010*38fd1498Szrj 	  arc_info *arc, *inv_arc;
2011*38fd1498Szrj 
2012*38fd1498Szrj 	  valid_blocks = blk->chain;
2013*38fd1498Szrj 	  blk->valid_chain = 0;
2014*38fd1498Szrj 	  if (blk->num_succ == 1)
2015*38fd1498Szrj 	    {
2016*38fd1498Szrj 	      block_info *dst;
2017*38fd1498Szrj 
2018*38fd1498Szrj 	      total = blk->count;
2019*38fd1498Szrj 	      inv_arc = NULL;
2020*38fd1498Szrj 	      for (arc = blk->succ; arc; arc = arc->succ_next)
2021*38fd1498Szrj 		{
2022*38fd1498Szrj 		  total -= arc->count;
2023*38fd1498Szrj 		  if (!arc->count_valid)
2024*38fd1498Szrj 		    inv_arc = arc;
2025*38fd1498Szrj 		}
2026*38fd1498Szrj 	      dst = inv_arc->dst;
2027*38fd1498Szrj 	      inv_arc->count_valid = 1;
2028*38fd1498Szrj 	      inv_arc->count = total;
2029*38fd1498Szrj 	      blk->num_succ--;
2030*38fd1498Szrj 	      dst->num_pred--;
2031*38fd1498Szrj 	      if (dst->count_valid)
2032*38fd1498Szrj 		{
2033*38fd1498Szrj 		  if (dst->num_pred == 1 && !dst->valid_chain)
2034*38fd1498Szrj 		    {
2035*38fd1498Szrj 		      dst->chain = valid_blocks;
2036*38fd1498Szrj 		      dst->valid_chain = 1;
2037*38fd1498Szrj 		      valid_blocks = dst;
2038*38fd1498Szrj 		    }
2039*38fd1498Szrj 		}
2040*38fd1498Szrj 	      else
2041*38fd1498Szrj 		{
2042*38fd1498Szrj 		  if (!dst->num_pred && !dst->invalid_chain)
2043*38fd1498Szrj 		    {
2044*38fd1498Szrj 		      dst->chain = invalid_blocks;
2045*38fd1498Szrj 		      dst->invalid_chain = 1;
2046*38fd1498Szrj 		      invalid_blocks = dst;
2047*38fd1498Szrj 		    }
2048*38fd1498Szrj 		}
2049*38fd1498Szrj 	    }
2050*38fd1498Szrj 	  if (blk->num_pred == 1)
2051*38fd1498Szrj 	    {
2052*38fd1498Szrj 	      block_info *src;
2053*38fd1498Szrj 
2054*38fd1498Szrj 	      total = blk->count;
2055*38fd1498Szrj 	      inv_arc = NULL;
2056*38fd1498Szrj 	      for (arc = blk->pred; arc; arc = arc->pred_next)
2057*38fd1498Szrj 		{
2058*38fd1498Szrj 		  total -= arc->count;
2059*38fd1498Szrj 		  if (!arc->count_valid)
2060*38fd1498Szrj 		    inv_arc = arc;
2061*38fd1498Szrj 		}
2062*38fd1498Szrj 	      src = inv_arc->src;
2063*38fd1498Szrj 	      inv_arc->count_valid = 1;
2064*38fd1498Szrj 	      inv_arc->count = total;
2065*38fd1498Szrj 	      blk->num_pred--;
2066*38fd1498Szrj 	      src->num_succ--;
2067*38fd1498Szrj 	      if (src->count_valid)
2068*38fd1498Szrj 		{
2069*38fd1498Szrj 		  if (src->num_succ == 1 && !src->valid_chain)
2070*38fd1498Szrj 		    {
2071*38fd1498Szrj 		      src->chain = valid_blocks;
2072*38fd1498Szrj 		      src->valid_chain = 1;
2073*38fd1498Szrj 		      valid_blocks = src;
2074*38fd1498Szrj 		    }
2075*38fd1498Szrj 		}
2076*38fd1498Szrj 	      else
2077*38fd1498Szrj 		{
2078*38fd1498Szrj 		  if (!src->num_succ && !src->invalid_chain)
2079*38fd1498Szrj 		    {
2080*38fd1498Szrj 		      src->chain = invalid_blocks;
2081*38fd1498Szrj 		      src->invalid_chain = 1;
2082*38fd1498Szrj 		      invalid_blocks = src;
2083*38fd1498Szrj 		    }
2084*38fd1498Szrj 		}
2085*38fd1498Szrj 	    }
2086*38fd1498Szrj 	}
2087*38fd1498Szrj     }
2088*38fd1498Szrj 
2089*38fd1498Szrj   /* If the graph has been correctly solved, every block will have a
2090*38fd1498Szrj      valid count.  */
2091*38fd1498Szrj   for (unsigned i = 0; ix < fn->blocks.size (); i++)
2092*38fd1498Szrj     if (!fn->blocks[i].count_valid)
2093*38fd1498Szrj       {
2094*38fd1498Szrj 	fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
2095*38fd1498Szrj 		 bbg_file_name, fn->name);
2096*38fd1498Szrj 	break;
2097*38fd1498Szrj       }
2098*38fd1498Szrj }
2099*38fd1498Szrj 
2100*38fd1498Szrj /* Mark all the blocks only reachable via an incoming catch.  */
2101*38fd1498Szrj 
2102*38fd1498Szrj static void
2103*38fd1498Szrj find_exception_blocks (function_info *fn)
2104*38fd1498Szrj {
2105*38fd1498Szrj   unsigned ix;
2106*38fd1498Szrj   block_info **queue = XALLOCAVEC (block_info *, fn->blocks.size ());
2107*38fd1498Szrj 
2108*38fd1498Szrj   /* First mark all blocks as exceptional.  */
2109*38fd1498Szrj   for (ix = fn->blocks.size (); ix--;)
2110*38fd1498Szrj     fn->blocks[ix].exceptional = 1;
2111*38fd1498Szrj 
2112*38fd1498Szrj   /* Now mark all the blocks reachable via non-fake edges */
2113*38fd1498Szrj   queue[0] = &fn->blocks[0];
2114*38fd1498Szrj   queue[0]->exceptional = 0;
2115*38fd1498Szrj   for (ix = 1; ix;)
2116*38fd1498Szrj     {
2117*38fd1498Szrj       block_info *block = queue[--ix];
2118*38fd1498Szrj       const arc_info *arc;
2119*38fd1498Szrj 
2120*38fd1498Szrj       for (arc = block->succ; arc; arc = arc->succ_next)
2121*38fd1498Szrj 	if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
2122*38fd1498Szrj 	  {
2123*38fd1498Szrj 	    arc->dst->exceptional = 0;
2124*38fd1498Szrj 	    queue[ix++] = arc->dst;
2125*38fd1498Szrj 	  }
2126*38fd1498Szrj     }
2127*38fd1498Szrj }
2128*38fd1498Szrj 
2129*38fd1498Szrj 
2130*38fd1498Szrj /* Increment totals in COVERAGE according to arc ARC.  */
2131*38fd1498Szrj 
2132*38fd1498Szrj static void
2133*38fd1498Szrj add_branch_counts (coverage_info *coverage, const arc_info *arc)
2134*38fd1498Szrj {
2135*38fd1498Szrj   if (arc->is_call_non_return)
2136*38fd1498Szrj     {
2137*38fd1498Szrj       coverage->calls++;
2138*38fd1498Szrj       if (arc->src->count)
2139*38fd1498Szrj 	coverage->calls_executed++;
2140*38fd1498Szrj     }
2141*38fd1498Szrj   else if (!arc->is_unconditional)
2142*38fd1498Szrj     {
2143*38fd1498Szrj       coverage->branches++;
2144*38fd1498Szrj       if (arc->src->count)
2145*38fd1498Szrj 	coverage->branches_executed++;
2146*38fd1498Szrj       if (arc->count)
2147*38fd1498Szrj 	coverage->branches_taken++;
2148*38fd1498Szrj     }
2149*38fd1498Szrj }
2150*38fd1498Szrj 
2151*38fd1498Szrj /* Format COUNT, if flag_human_readable_numbers is set, return it human
2152*38fd1498Szrj    readable format.  */
2153*38fd1498Szrj 
2154*38fd1498Szrj static char const *
2155*38fd1498Szrj format_count (gcov_type count)
2156*38fd1498Szrj {
2157*38fd1498Szrj   static char buffer[64];
2158*38fd1498Szrj   const char *units = " kMGTPEZY";
2159*38fd1498Szrj 
2160*38fd1498Szrj   if (count < 1000 || !flag_human_readable_numbers)
2161*38fd1498Szrj     {
2162*38fd1498Szrj       sprintf (buffer, "%" PRId64, count);
2163*38fd1498Szrj       return buffer;
2164*38fd1498Szrj     }
2165*38fd1498Szrj 
2166*38fd1498Szrj   unsigned i;
2167*38fd1498Szrj   gcov_type divisor = 1;
2168*38fd1498Szrj   for (i = 0; units[i+1]; i++, divisor *= 1000)
2169*38fd1498Szrj     {
2170*38fd1498Szrj       if (count + divisor / 2 < 1000 * divisor)
2171*38fd1498Szrj 	break;
2172*38fd1498Szrj     }
2173*38fd1498Szrj   gcov_type r  = (count + divisor / 2) / divisor;
2174*38fd1498Szrj   sprintf (buffer, "%" PRId64 "%c", r, units[i]);
2175*38fd1498Szrj   return buffer;
2176*38fd1498Szrj }
2177*38fd1498Szrj 
2178*38fd1498Szrj /* Format a GCOV_TYPE integer as either a percent ratio, or absolute
2179*38fd1498Szrj    count.  If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
2180*38fd1498Szrj    If DP is zero, no decimal point is printed. Only print 100% when
2181*38fd1498Szrj    TOP==BOTTOM and only print 0% when TOP=0.  If dp < 0, then simply
2182*38fd1498Szrj    format TOP.  Return pointer to a static string.  */
2183*38fd1498Szrj 
2184*38fd1498Szrj static char const *
2185*38fd1498Szrj format_gcov (gcov_type top, gcov_type bottom, int dp)
2186*38fd1498Szrj {
2187*38fd1498Szrj   static char buffer[20];
2188*38fd1498Szrj 
2189*38fd1498Szrj   /* Handle invalid values that would result in a misleading value.  */
2190*38fd1498Szrj   if (bottom != 0 && top > bottom && dp >= 0)
2191*38fd1498Szrj     {
2192*38fd1498Szrj       sprintf (buffer, "NAN %%");
2193*38fd1498Szrj       return buffer;
2194*38fd1498Szrj     }
2195*38fd1498Szrj 
2196*38fd1498Szrj   if (dp >= 0)
2197*38fd1498Szrj     {
2198*38fd1498Szrj       float ratio = bottom ? (float)top / bottom : 0;
2199*38fd1498Szrj       int ix;
2200*38fd1498Szrj       unsigned limit = 100;
2201*38fd1498Szrj       unsigned percent;
2202*38fd1498Szrj 
2203*38fd1498Szrj       for (ix = dp; ix--; )
2204*38fd1498Szrj 	limit *= 10;
2205*38fd1498Szrj 
2206*38fd1498Szrj       percent = (unsigned) (ratio * limit + (float)0.5);
2207*38fd1498Szrj       if (percent <= 0 && top)
2208*38fd1498Szrj 	percent = 1;
2209*38fd1498Szrj       else if (percent >= limit && top != bottom)
2210*38fd1498Szrj 	percent = limit - 1;
2211*38fd1498Szrj       ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
2212*38fd1498Szrj       if (dp)
2213*38fd1498Szrj 	{
2214*38fd1498Szrj 	  dp++;
2215*38fd1498Szrj 	  do
2216*38fd1498Szrj 	    {
2217*38fd1498Szrj 	      buffer[ix+1] = buffer[ix];
2218*38fd1498Szrj 	      ix--;
2219*38fd1498Szrj 	    }
2220*38fd1498Szrj 	  while (dp--);
2221*38fd1498Szrj 	  buffer[ix + 1] = '.';
2222*38fd1498Szrj 	}
2223*38fd1498Szrj     }
2224*38fd1498Szrj   else
2225*38fd1498Szrj     return format_count (top);
2226*38fd1498Szrj 
2227*38fd1498Szrj   return buffer;
2228*38fd1498Szrj }
2229*38fd1498Szrj 
2230*38fd1498Szrj /* Summary of execution */
2231*38fd1498Szrj 
2232*38fd1498Szrj static void
2233*38fd1498Szrj executed_summary (unsigned lines, unsigned executed)
2234*38fd1498Szrj {
2235*38fd1498Szrj   if (lines)
2236*38fd1498Szrj     fnotice (stdout, "Lines executed:%s of %d\n",
2237*38fd1498Szrj 	     format_gcov (executed, lines, 2), lines);
2238*38fd1498Szrj   else
2239*38fd1498Szrj     fnotice (stdout, "No executable lines\n");
2240*38fd1498Szrj }
2241*38fd1498Szrj 
2242*38fd1498Szrj /* Output summary info for a function or file.  */
2243*38fd1498Szrj 
2244*38fd1498Szrj static void
2245*38fd1498Szrj function_summary (const coverage_info *coverage, const char *title)
2246*38fd1498Szrj {
2247*38fd1498Szrj   fnotice (stdout, "%s '%s'\n", title, coverage->name);
2248*38fd1498Szrj   executed_summary (coverage->lines, coverage->lines_executed);
2249*38fd1498Szrj 
2250*38fd1498Szrj   if (flag_branches)
2251*38fd1498Szrj     {
2252*38fd1498Szrj       if (coverage->branches)
2253*38fd1498Szrj 	{
2254*38fd1498Szrj 	  fnotice (stdout, "Branches executed:%s of %d\n",
2255*38fd1498Szrj 		   format_gcov (coverage->branches_executed,
2256*38fd1498Szrj 				coverage->branches, 2),
2257*38fd1498Szrj 		   coverage->branches);
2258*38fd1498Szrj 	  fnotice (stdout, "Taken at least once:%s of %d\n",
2259*38fd1498Szrj 		   format_gcov (coverage->branches_taken,
2260*38fd1498Szrj 				coverage->branches, 2),
2261*38fd1498Szrj 		   coverage->branches);
2262*38fd1498Szrj 	}
2263*38fd1498Szrj       else
2264*38fd1498Szrj 	fnotice (stdout, "No branches\n");
2265*38fd1498Szrj       if (coverage->calls)
2266*38fd1498Szrj 	fnotice (stdout, "Calls executed:%s of %d\n",
2267*38fd1498Szrj 		 format_gcov (coverage->calls_executed, coverage->calls, 2),
2268*38fd1498Szrj 		 coverage->calls);
2269*38fd1498Szrj       else
2270*38fd1498Szrj 	fnotice (stdout, "No calls\n");
2271*38fd1498Szrj     }
2272*38fd1498Szrj }
2273*38fd1498Szrj 
2274*38fd1498Szrj /* Canonicalize the filename NAME by canonicalizing directory
2275*38fd1498Szrj    separators, eliding . components and resolving .. components
2276*38fd1498Szrj    appropriately.  Always returns a unique string.  */
2277*38fd1498Szrj 
2278*38fd1498Szrj static char *
2279*38fd1498Szrj canonicalize_name (const char *name)
2280*38fd1498Szrj {
2281*38fd1498Szrj   /* The canonical name cannot be longer than the incoming name.  */
2282*38fd1498Szrj   char *result = XNEWVEC (char, strlen (name) + 1);
2283*38fd1498Szrj   const char *base = name, *probe;
2284*38fd1498Szrj   char *ptr = result;
2285*38fd1498Szrj   char *dd_base;
2286*38fd1498Szrj   int slash = 0;
2287*38fd1498Szrj 
2288*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM
2289*38fd1498Szrj   if (base[0] && base[1] == ':')
2290*38fd1498Szrj     {
2291*38fd1498Szrj       result[0] = base[0];
2292*38fd1498Szrj       result[1] = ':';
2293*38fd1498Szrj       base += 2;
2294*38fd1498Szrj       ptr += 2;
2295*38fd1498Szrj     }
2296*38fd1498Szrj #endif
2297*38fd1498Szrj   for (dd_base = ptr; *base; base = probe)
2298*38fd1498Szrj     {
2299*38fd1498Szrj       size_t len;
2300*38fd1498Szrj 
2301*38fd1498Szrj       for (probe = base; *probe; probe++)
2302*38fd1498Szrj 	if (IS_DIR_SEPARATOR (*probe))
2303*38fd1498Szrj 	  break;
2304*38fd1498Szrj 
2305*38fd1498Szrj       len = probe - base;
2306*38fd1498Szrj       if (len == 1 && base[0] == '.')
2307*38fd1498Szrj 	/* Elide a '.' directory */
2308*38fd1498Szrj 	;
2309*38fd1498Szrj       else if (len == 2 && base[0] == '.' && base[1] == '.')
2310*38fd1498Szrj 	{
2311*38fd1498Szrj 	  /* '..', we can only elide it and the previous directory, if
2312*38fd1498Szrj 	     we're not a symlink.  */
2313*38fd1498Szrj 	  struct stat ATTRIBUTE_UNUSED buf;
2314*38fd1498Szrj 
2315*38fd1498Szrj 	  *ptr = 0;
2316*38fd1498Szrj 	  if (dd_base == ptr
2317*38fd1498Szrj #if defined (S_ISLNK)
2318*38fd1498Szrj 	      /* S_ISLNK is not POSIX.1-1996.  */
2319*38fd1498Szrj 	      || stat (result, &buf) || S_ISLNK (buf.st_mode)
2320*38fd1498Szrj #endif
2321*38fd1498Szrj 		)
2322*38fd1498Szrj 	    {
2323*38fd1498Szrj 	      /* Cannot elide, or unreadable or a symlink.  */
2324*38fd1498Szrj 	      dd_base = ptr + 2 + slash;
2325*38fd1498Szrj 	      goto regular;
2326*38fd1498Szrj 	    }
2327*38fd1498Szrj 	  while (ptr != dd_base && *ptr != '/')
2328*38fd1498Szrj 	    ptr--;
2329*38fd1498Szrj 	  slash = ptr != result;
2330*38fd1498Szrj 	}
2331*38fd1498Szrj       else
2332*38fd1498Szrj 	{
2333*38fd1498Szrj 	regular:
2334*38fd1498Szrj 	  /* Regular pathname component.  */
2335*38fd1498Szrj 	  if (slash)
2336*38fd1498Szrj 	    *ptr++ = '/';
2337*38fd1498Szrj 	  memcpy (ptr, base, len);
2338*38fd1498Szrj 	  ptr += len;
2339*38fd1498Szrj 	  slash = 1;
2340*38fd1498Szrj 	}
2341*38fd1498Szrj 
2342*38fd1498Szrj       for (; IS_DIR_SEPARATOR (*probe); probe++)
2343*38fd1498Szrj 	continue;
2344*38fd1498Szrj     }
2345*38fd1498Szrj   *ptr = 0;
2346*38fd1498Szrj 
2347*38fd1498Szrj   return result;
2348*38fd1498Szrj }
2349*38fd1498Szrj 
2350*38fd1498Szrj /* Print hex representation of 16 bytes from SUM and write it to BUFFER.  */
2351*38fd1498Szrj 
2352*38fd1498Szrj static void
2353*38fd1498Szrj md5sum_to_hex (const char *sum, char *buffer)
2354*38fd1498Szrj {
2355*38fd1498Szrj   for (unsigned i = 0; i < 16; i++)
2356*38fd1498Szrj     sprintf (buffer + (2 * i), "%02x", (unsigned char)sum[i]);
2357*38fd1498Szrj }
2358*38fd1498Szrj 
2359*38fd1498Szrj /* Generate an output file name. INPUT_NAME is the canonicalized main
2360*38fd1498Szrj    input file and SRC_NAME is the canonicalized file name.
2361*38fd1498Szrj    LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation.  With
2362*38fd1498Szrj    long_output_names we prepend the processed name of the input file
2363*38fd1498Szrj    to each output name (except when the current source file is the
2364*38fd1498Szrj    input file, so you don't get a double concatenation). The two
2365*38fd1498Szrj    components are separated by '##'.  With preserve_paths we create a
2366*38fd1498Szrj    filename from all path components of the source file, replacing '/'
2367*38fd1498Szrj    with '#', and .. with '^', without it we simply take the basename
2368*38fd1498Szrj    component.  (Remember, the canonicalized name will already have
2369*38fd1498Szrj    elided '.' components and converted \\ separators.)  */
2370*38fd1498Szrj 
2371*38fd1498Szrj static char *
2372*38fd1498Szrj make_gcov_file_name (const char *input_name, const char *src_name)
2373*38fd1498Szrj {
2374*38fd1498Szrj   char *ptr;
2375*38fd1498Szrj   char *result;
2376*38fd1498Szrj 
2377*38fd1498Szrj   if (flag_long_names && input_name && strcmp (src_name, input_name))
2378*38fd1498Szrj     {
2379*38fd1498Szrj       /* Generate the input filename part.  */
2380*38fd1498Szrj       result = XNEWVEC (char, strlen (input_name) + strlen (src_name) + 10);
2381*38fd1498Szrj 
2382*38fd1498Szrj       ptr = result;
2383*38fd1498Szrj       ptr = mangle_name (input_name, ptr);
2384*38fd1498Szrj       ptr[0] = ptr[1] = '#';
2385*38fd1498Szrj       ptr += 2;
2386*38fd1498Szrj     }
2387*38fd1498Szrj   else
2388*38fd1498Szrj     {
2389*38fd1498Szrj       result = XNEWVEC (char, strlen (src_name) + 10);
2390*38fd1498Szrj       ptr = result;
2391*38fd1498Szrj     }
2392*38fd1498Szrj 
2393*38fd1498Szrj   ptr = mangle_name (src_name, ptr);
2394*38fd1498Szrj   strcpy (ptr, ".gcov");
2395*38fd1498Szrj 
2396*38fd1498Szrj   /* When hashing filenames, we shorten them by only using the filename
2397*38fd1498Szrj      component and appending a hash of the full (mangled) pathname.  */
2398*38fd1498Szrj   if (flag_hash_filenames)
2399*38fd1498Szrj     {
2400*38fd1498Szrj       md5_ctx ctx;
2401*38fd1498Szrj       char md5sum[16];
2402*38fd1498Szrj       char md5sum_hex[33];
2403*38fd1498Szrj 
2404*38fd1498Szrj       md5_init_ctx (&ctx);
2405*38fd1498Szrj       md5_process_bytes (src_name, strlen (src_name), &ctx);
2406*38fd1498Szrj       md5_finish_ctx (&ctx, md5sum);
2407*38fd1498Szrj       md5sum_to_hex (md5sum, md5sum_hex);
2408*38fd1498Szrj       free (result);
2409*38fd1498Szrj 
2410*38fd1498Szrj       result = XNEWVEC (char, strlen (src_name) + 50);
2411*38fd1498Szrj       ptr = result;
2412*38fd1498Szrj       ptr = mangle_name (src_name, ptr);
2413*38fd1498Szrj       ptr[0] = ptr[1] = '#';
2414*38fd1498Szrj       ptr += 2;
2415*38fd1498Szrj       memcpy (ptr, md5sum_hex, 32);
2416*38fd1498Szrj       ptr += 32;
2417*38fd1498Szrj       strcpy (ptr, ".gcov");
2418*38fd1498Szrj     }
2419*38fd1498Szrj 
2420*38fd1498Szrj   return result;
2421*38fd1498Szrj }
2422*38fd1498Szrj 
2423*38fd1498Szrj static char *
2424*38fd1498Szrj mangle_name (char const *base, char *ptr)
2425*38fd1498Szrj {
2426*38fd1498Szrj   size_t len;
2427*38fd1498Szrj 
2428*38fd1498Szrj   /* Generate the source filename part.  */
2429*38fd1498Szrj   if (!flag_preserve_paths)
2430*38fd1498Szrj     {
2431*38fd1498Szrj       base = lbasename (base);
2432*38fd1498Szrj       len = strlen (base);
2433*38fd1498Szrj       memcpy (ptr, base, len);
2434*38fd1498Szrj       ptr += len;
2435*38fd1498Szrj     }
2436*38fd1498Szrj   else
2437*38fd1498Szrj     {
2438*38fd1498Szrj       /* Convert '/' to '#', convert '..' to '^',
2439*38fd1498Szrj 	 convert ':' to '~' on DOS based file system.  */
2440*38fd1498Szrj       const char *probe;
2441*38fd1498Szrj 
2442*38fd1498Szrj #if HAVE_DOS_BASED_FILE_SYSTEM
2443*38fd1498Szrj       if (base[0] && base[1] == ':')
2444*38fd1498Szrj 	{
2445*38fd1498Szrj 	  ptr[0] = base[0];
2446*38fd1498Szrj 	  ptr[1] = '~';
2447*38fd1498Szrj 	  ptr += 2;
2448*38fd1498Szrj 	  base += 2;
2449*38fd1498Szrj 	}
2450*38fd1498Szrj #endif
2451*38fd1498Szrj       for (; *base; base = probe)
2452*38fd1498Szrj 	{
2453*38fd1498Szrj 	  size_t len;
2454*38fd1498Szrj 
2455*38fd1498Szrj 	  for (probe = base; *probe; probe++)
2456*38fd1498Szrj 	    if (*probe == '/')
2457*38fd1498Szrj 	      break;
2458*38fd1498Szrj 	  len = probe - base;
2459*38fd1498Szrj 	  if (len == 2 && base[0] == '.' && base[1] == '.')
2460*38fd1498Szrj 	    *ptr++ = '^';
2461*38fd1498Szrj 	  else
2462*38fd1498Szrj 	    {
2463*38fd1498Szrj 	      memcpy (ptr, base, len);
2464*38fd1498Szrj 	      ptr += len;
2465*38fd1498Szrj 	    }
2466*38fd1498Szrj 	  if (*probe)
2467*38fd1498Szrj 	    {
2468*38fd1498Szrj 	      *ptr++ = '#';
2469*38fd1498Szrj 	      probe++;
2470*38fd1498Szrj 	    }
2471*38fd1498Szrj 	}
2472*38fd1498Szrj     }
2473*38fd1498Szrj 
2474*38fd1498Szrj   return ptr;
2475*38fd1498Szrj }
2476*38fd1498Szrj 
2477*38fd1498Szrj /* Scan through the bb_data for each line in the block, increment
2478*38fd1498Szrj    the line number execution count indicated by the execution count of
2479*38fd1498Szrj    the appropriate basic block.  */
2480*38fd1498Szrj 
2481*38fd1498Szrj static void
2482*38fd1498Szrj add_line_counts (coverage_info *coverage, function_info *fn)
2483*38fd1498Szrj {
2484*38fd1498Szrj   bool has_any_line = false;
2485*38fd1498Szrj   /* Scan each basic block.  */
2486*38fd1498Szrj   for (unsigned ix = 0; ix != fn->blocks.size (); ix++)
2487*38fd1498Szrj     {
2488*38fd1498Szrj       line_info *line = NULL;
2489*38fd1498Szrj       block_info *block = &fn->blocks[ix];
2490*38fd1498Szrj       if (block->count && ix && ix + 1 != fn->blocks.size ())
2491*38fd1498Szrj 	fn->blocks_executed++;
2492*38fd1498Szrj       for (unsigned i = 0; i < block->locations.size (); i++)
2493*38fd1498Szrj 	{
2494*38fd1498Szrj 	  unsigned src_idx = block->locations[i].source_file_idx;
2495*38fd1498Szrj 	  vector<unsigned> &lines = block->locations[i].lines;
2496*38fd1498Szrj 
2497*38fd1498Szrj 	  block->cycle.arc = NULL;
2498*38fd1498Szrj 	  block->cycle.ident = ~0U;
2499*38fd1498Szrj 
2500*38fd1498Szrj 	  for (unsigned j = 0; j < lines.size (); j++)
2501*38fd1498Szrj 	    {
2502*38fd1498Szrj 	      unsigned ln = lines[j];
2503*38fd1498Szrj 
2504*38fd1498Szrj 	      /* Line belongs to a function that is in a group.  */
2505*38fd1498Szrj 	      if (fn->group_line_p (ln, src_idx))
2506*38fd1498Szrj 		{
2507*38fd1498Szrj 		  gcc_assert (lines[j] - fn->start_line < fn->lines.size ());
2508*38fd1498Szrj 		  line = &(fn->lines[lines[j] - fn->start_line]);
2509*38fd1498Szrj 		  line->exists = 1;
2510*38fd1498Szrj 		  if (!block->exceptional)
2511*38fd1498Szrj 		    {
2512*38fd1498Szrj 		      line->unexceptional = 1;
2513*38fd1498Szrj 		      if (block->count == 0)
2514*38fd1498Szrj 			line->has_unexecuted_block = 1;
2515*38fd1498Szrj 		    }
2516*38fd1498Szrj 		  line->count += block->count;
2517*38fd1498Szrj 		}
2518*38fd1498Szrj 	      else
2519*38fd1498Szrj 		{
2520*38fd1498Szrj 		  gcc_assert (ln < sources[src_idx].lines.size ());
2521*38fd1498Szrj 		  line = &(sources[src_idx].lines[ln]);
2522*38fd1498Szrj 		  if (coverage)
2523*38fd1498Szrj 		    {
2524*38fd1498Szrj 		      if (!line->exists)
2525*38fd1498Szrj 			coverage->lines++;
2526*38fd1498Szrj 		      if (!line->count && block->count)
2527*38fd1498Szrj 			coverage->lines_executed++;
2528*38fd1498Szrj 		    }
2529*38fd1498Szrj 		  line->exists = 1;
2530*38fd1498Szrj 		  if (!block->exceptional)
2531*38fd1498Szrj 		    {
2532*38fd1498Szrj 		      line->unexceptional = 1;
2533*38fd1498Szrj 		      if (block->count == 0)
2534*38fd1498Szrj 			line->has_unexecuted_block = 1;
2535*38fd1498Szrj 		    }
2536*38fd1498Szrj 		  line->count += block->count;
2537*38fd1498Szrj 		}
2538*38fd1498Szrj 	    }
2539*38fd1498Szrj 
2540*38fd1498Szrj 	  has_any_line = true;
2541*38fd1498Szrj 
2542*38fd1498Szrj 	  if (!ix || ix + 1 == fn->blocks.size ())
2543*38fd1498Szrj 	    /* Entry or exit block.  */;
2544*38fd1498Szrj 	  else if (line != NULL)
2545*38fd1498Szrj 	    {
2546*38fd1498Szrj 	      line->blocks.push_back (block);
2547*38fd1498Szrj 
2548*38fd1498Szrj 	      if (flag_branches)
2549*38fd1498Szrj 		{
2550*38fd1498Szrj 		  arc_info *arc;
2551*38fd1498Szrj 
2552*38fd1498Szrj 		  for (arc = block->succ; arc; arc = arc->succ_next)
2553*38fd1498Szrj 		    line->branches.push_back (arc);
2554*38fd1498Szrj 		}
2555*38fd1498Szrj 	    }
2556*38fd1498Szrj 	}
2557*38fd1498Szrj     }
2558*38fd1498Szrj 
2559*38fd1498Szrj   if (!has_any_line)
2560*38fd1498Szrj     fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
2561*38fd1498Szrj }
2562*38fd1498Szrj 
2563*38fd1498Szrj /* Accumulate info for LINE that belongs to SRC source file.  If ADD_COVERAGE
2564*38fd1498Szrj    is set to true, update source file summary.  */
2565*38fd1498Szrj 
2566*38fd1498Szrj static void accumulate_line_info (line_info *line, source_info *src,
2567*38fd1498Szrj 				  bool add_coverage)
2568*38fd1498Szrj {
2569*38fd1498Szrj   if (add_coverage)
2570*38fd1498Szrj     for (vector<arc_info *>::iterator it = line->branches.begin ();
2571*38fd1498Szrj 	 it != line->branches.end (); it++)
2572*38fd1498Szrj       add_branch_counts (&src->coverage, *it);
2573*38fd1498Szrj 
2574*38fd1498Szrj   if (!line->blocks.empty ())
2575*38fd1498Szrj     {
2576*38fd1498Szrj       /* The user expects the line count to be the number of times
2577*38fd1498Szrj 	 a line has been executed.  Simply summing the block count
2578*38fd1498Szrj 	 will give an artificially high number.  The Right Thing
2579*38fd1498Szrj 	 is to sum the entry counts to the graph of blocks on this
2580*38fd1498Szrj 	 line, then find the elementary cycles of the local graph
2581*38fd1498Szrj 	 and add the transition counts of those cycles.  */
2582*38fd1498Szrj       gcov_type count = 0;
2583*38fd1498Szrj 
2584*38fd1498Szrj       /* Cycle detection.  */
2585*38fd1498Szrj       for (vector<block_info *>::iterator it = line->blocks.begin ();
2586*38fd1498Szrj 	   it != line->blocks.end (); it++)
2587*38fd1498Szrj 	{
2588*38fd1498Szrj 	  for (arc_info *arc = (*it)->pred; arc; arc = arc->pred_next)
2589*38fd1498Szrj 	    if (!line->has_block (arc->src))
2590*38fd1498Szrj 	      count += arc->count;
2591*38fd1498Szrj 	  for (arc_info *arc = (*it)->succ; arc; arc = arc->succ_next)
2592*38fd1498Szrj 	    arc->cs_count = arc->count;
2593*38fd1498Szrj 	}
2594*38fd1498Szrj 
2595*38fd1498Szrj       /* Now, add the count of loops entirely on this line.  */
2596*38fd1498Szrj       count += get_cycles_count (*line);
2597*38fd1498Szrj       line->count = count;
2598*38fd1498Szrj     }
2599*38fd1498Szrj 
2600*38fd1498Szrj   if (line->exists && add_coverage)
2601*38fd1498Szrj     {
2602*38fd1498Szrj       src->coverage.lines++;
2603*38fd1498Szrj       if (line->count)
2604*38fd1498Szrj 	src->coverage.lines_executed++;
2605*38fd1498Szrj     }
2606*38fd1498Szrj }
2607*38fd1498Szrj 
2608*38fd1498Szrj /* Accumulate the line counts of a file.  */
2609*38fd1498Szrj 
2610*38fd1498Szrj static void
2611*38fd1498Szrj accumulate_line_counts (source_info *src)
2612*38fd1498Szrj {
2613*38fd1498Szrj   /* First work on group functions.  */
2614*38fd1498Szrj   for (vector<function_info *>::iterator it = src->functions.begin ();
2615*38fd1498Szrj        it != src->functions.end (); it++)
2616*38fd1498Szrj     {
2617*38fd1498Szrj       function_info *fn = *it;
2618*38fd1498Szrj 
2619*38fd1498Szrj       if (fn->src != src->index || !fn->is_group)
2620*38fd1498Szrj 	continue;
2621*38fd1498Szrj 
2622*38fd1498Szrj       for (vector<line_info>::iterator it2 = fn->lines.begin ();
2623*38fd1498Szrj 	   it2 != fn->lines.end (); it2++)
2624*38fd1498Szrj 	  {
2625*38fd1498Szrj 	    line_info *line = &(*it2);
2626*38fd1498Szrj 	    accumulate_line_info (line, src, false);
2627*38fd1498Szrj 	  }
2628*38fd1498Szrj     }
2629*38fd1498Szrj 
2630*38fd1498Szrj   /* Work on global lines that line in source file SRC.  */
2631*38fd1498Szrj   for (vector<line_info>::iterator it = src->lines.begin ();
2632*38fd1498Szrj        it != src->lines.end (); it++)
2633*38fd1498Szrj     accumulate_line_info (&(*it), src, true);
2634*38fd1498Szrj 
2635*38fd1498Szrj   /* If not using intermediate mode, sum lines of group functions and
2636*38fd1498Szrj      add them to lines that live in a source file.  */
2637*38fd1498Szrj   if (!flag_intermediate_format)
2638*38fd1498Szrj     for (vector<function_info *>::iterator it = src->functions.begin ();
2639*38fd1498Szrj 	 it != src->functions.end (); it++)
2640*38fd1498Szrj       {
2641*38fd1498Szrj 	function_info *fn = *it;
2642*38fd1498Szrj 
2643*38fd1498Szrj 	if (fn->src != src->index || !fn->is_group)
2644*38fd1498Szrj 	  continue;
2645*38fd1498Szrj 
2646*38fd1498Szrj 	for (unsigned i = 0; i < fn->lines.size (); i++)
2647*38fd1498Szrj 	  {
2648*38fd1498Szrj 	    line_info *fn_line = &fn->lines[i];
2649*38fd1498Szrj 	    if (fn_line->exists)
2650*38fd1498Szrj 	      {
2651*38fd1498Szrj 		unsigned ln = fn->start_line + i;
2652*38fd1498Szrj 		line_info *src_line = &src->lines[ln];
2653*38fd1498Szrj 
2654*38fd1498Szrj 		if (!src_line->exists)
2655*38fd1498Szrj 		  src->coverage.lines++;
2656*38fd1498Szrj 		if (!src_line->count && fn_line->count)
2657*38fd1498Szrj 		  src->coverage.lines_executed++;
2658*38fd1498Szrj 
2659*38fd1498Szrj 		src_line->count += fn_line->count;
2660*38fd1498Szrj 		src_line->exists = 1;
2661*38fd1498Szrj 
2662*38fd1498Szrj 		if (fn_line->has_unexecuted_block)
2663*38fd1498Szrj 		  src_line->has_unexecuted_block = 1;
2664*38fd1498Szrj 
2665*38fd1498Szrj 		if (fn_line->unexceptional)
2666*38fd1498Szrj 		  src_line->unexceptional = 1;
2667*38fd1498Szrj 	      }
2668*38fd1498Szrj 	  }
2669*38fd1498Szrj       }
2670*38fd1498Szrj }
2671*38fd1498Szrj 
2672*38fd1498Szrj /* Output information about ARC number IX.  Returns nonzero if
2673*38fd1498Szrj    anything is output.  */
2674*38fd1498Szrj 
2675*38fd1498Szrj static int
2676*38fd1498Szrj output_branch_count (FILE *gcov_file, int ix, const arc_info *arc)
2677*38fd1498Szrj {
2678*38fd1498Szrj   if (arc->is_call_non_return)
2679*38fd1498Szrj     {
2680*38fd1498Szrj       if (arc->src->count)
2681*38fd1498Szrj 	{
2682*38fd1498Szrj 	  fnotice (gcov_file, "call   %2d returned %s\n", ix,
2683*38fd1498Szrj 		   format_gcov (arc->src->count - arc->count,
2684*38fd1498Szrj 				arc->src->count, -flag_counts));
2685*38fd1498Szrj 	}
2686*38fd1498Szrj       else
2687*38fd1498Szrj 	fnotice (gcov_file, "call   %2d never executed\n", ix);
2688*38fd1498Szrj     }
2689*38fd1498Szrj   else if (!arc->is_unconditional)
2690*38fd1498Szrj     {
2691*38fd1498Szrj       if (arc->src->count)
2692*38fd1498Szrj 	fnotice (gcov_file, "branch %2d taken %s%s", ix,
2693*38fd1498Szrj 		 format_gcov (arc->count, arc->src->count, -flag_counts),
2694*38fd1498Szrj 		 arc->fall_through ? " (fallthrough)"
2695*38fd1498Szrj 		 : arc->is_throw ? " (throw)" : "");
2696*38fd1498Szrj       else
2697*38fd1498Szrj 	fnotice (gcov_file, "branch %2d never executed", ix);
2698*38fd1498Szrj 
2699*38fd1498Szrj       if (flag_verbose)
2700*38fd1498Szrj 	fnotice (gcov_file, " (BB %d)", arc->dst->id);
2701*38fd1498Szrj 
2702*38fd1498Szrj       fnotice (gcov_file, "\n");
2703*38fd1498Szrj     }
2704*38fd1498Szrj   else if (flag_unconditional && !arc->dst->is_call_return)
2705*38fd1498Szrj     {
2706*38fd1498Szrj       if (arc->src->count)
2707*38fd1498Szrj 	fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
2708*38fd1498Szrj 		 format_gcov (arc->count, arc->src->count, -flag_counts));
2709*38fd1498Szrj       else
2710*38fd1498Szrj 	fnotice (gcov_file, "unconditional %2d never executed\n", ix);
2711*38fd1498Szrj     }
2712*38fd1498Szrj   else
2713*38fd1498Szrj     return 0;
2714*38fd1498Szrj   return 1;
2715*38fd1498Szrj }
2716*38fd1498Szrj 
2717*38fd1498Szrj static const char *
2718*38fd1498Szrj read_line (FILE *file)
2719*38fd1498Szrj {
2720*38fd1498Szrj   static char *string;
2721*38fd1498Szrj   static size_t string_len;
2722*38fd1498Szrj   size_t pos = 0;
2723*38fd1498Szrj   char *ptr;
2724*38fd1498Szrj 
2725*38fd1498Szrj   if (!string_len)
2726*38fd1498Szrj     {
2727*38fd1498Szrj       string_len = 200;
2728*38fd1498Szrj       string = XNEWVEC (char, string_len);
2729*38fd1498Szrj     }
2730*38fd1498Szrj 
2731*38fd1498Szrj   while ((ptr = fgets (string + pos, string_len - pos, file)))
2732*38fd1498Szrj     {
2733*38fd1498Szrj       size_t len = strlen (string + pos);
2734*38fd1498Szrj 
2735*38fd1498Szrj       if (len && string[pos + len - 1] == '\n')
2736*38fd1498Szrj 	{
2737*38fd1498Szrj 	  string[pos + len - 1] = 0;
2738*38fd1498Szrj 	  return string;
2739*38fd1498Szrj 	}
2740*38fd1498Szrj       pos += len;
2741*38fd1498Szrj       /* If the file contains NUL characters or an incomplete
2742*38fd1498Szrj 	 last line, which can happen more than once in one run,
2743*38fd1498Szrj 	 we have to avoid doubling the STRING_LEN unnecessarily.  */
2744*38fd1498Szrj       if (pos > string_len / 2)
2745*38fd1498Szrj 	{
2746*38fd1498Szrj 	  string_len *= 2;
2747*38fd1498Szrj 	  string = XRESIZEVEC (char, string, string_len);
2748*38fd1498Szrj 	}
2749*38fd1498Szrj     }
2750*38fd1498Szrj 
2751*38fd1498Szrj   return pos ? string : NULL;
2752*38fd1498Szrj }
2753*38fd1498Szrj 
2754*38fd1498Szrj /* Pad string S with spaces from left to have total width equal to 9.  */
2755*38fd1498Szrj 
2756*38fd1498Szrj static void
2757*38fd1498Szrj pad_count_string (string &s)
2758*38fd1498Szrj {
2759*38fd1498Szrj   if (s.size () < 9)
2760*38fd1498Szrj     s.insert (0, 9 - s.size (), ' ');
2761*38fd1498Szrj }
2762*38fd1498Szrj 
2763*38fd1498Szrj /* Print GCOV line beginning to F stream.  If EXISTS is set to true, the
2764*38fd1498Szrj    line exists in source file.  UNEXCEPTIONAL indicated that it's not in
2765*38fd1498Szrj    an exceptional statement.  The output is printed for LINE_NUM of given
2766*38fd1498Szrj    COUNT of executions.  EXCEPTIONAL_STRING and UNEXCEPTIONAL_STRING are
2767*38fd1498Szrj    used to indicate non-executed blocks.  */
2768*38fd1498Szrj 
2769*38fd1498Szrj static void
2770*38fd1498Szrj output_line_beginning (FILE *f, bool exists, bool unexceptional,
2771*38fd1498Szrj 		       bool has_unexecuted_block,
2772*38fd1498Szrj 		       gcov_type count, unsigned line_num,
2773*38fd1498Szrj 		       const char *exceptional_string,
2774*38fd1498Szrj 		       const char *unexceptional_string)
2775*38fd1498Szrj {
2776*38fd1498Szrj   string s;
2777*38fd1498Szrj   if (exists)
2778*38fd1498Szrj     {
2779*38fd1498Szrj       if (count > 0)
2780*38fd1498Szrj 	{
2781*38fd1498Szrj 	  s = format_gcov (count, 0, -1);
2782*38fd1498Szrj 	  if (has_unexecuted_block
2783*38fd1498Szrj 	      && bbg_supports_has_unexecuted_blocks)
2784*38fd1498Szrj 	    {
2785*38fd1498Szrj 	      if (flag_use_colors)
2786*38fd1498Szrj 		{
2787*38fd1498Szrj 		  pad_count_string (s);
2788*38fd1498Szrj 		  s.insert (0, SGR_SEQ (COLOR_BG_MAGENTA
2789*38fd1498Szrj 					COLOR_SEPARATOR COLOR_FG_WHITE));
2790*38fd1498Szrj 		  s += SGR_RESET;
2791*38fd1498Szrj 		}
2792*38fd1498Szrj 	      else
2793*38fd1498Szrj 		s += "*";
2794*38fd1498Szrj 	    }
2795*38fd1498Szrj 	  pad_count_string (s);
2796*38fd1498Szrj 	}
2797*38fd1498Szrj       else
2798*38fd1498Szrj 	{
2799*38fd1498Szrj 	  if (flag_use_colors)
2800*38fd1498Szrj 	    {
2801*38fd1498Szrj 	      s = "0";
2802*38fd1498Szrj 	      pad_count_string (s);
2803*38fd1498Szrj 	      if (unexceptional)
2804*38fd1498Szrj 		s.insert (0, SGR_SEQ (COLOR_BG_RED
2805*38fd1498Szrj 				      COLOR_SEPARATOR COLOR_FG_WHITE));
2806*38fd1498Szrj 	      else
2807*38fd1498Szrj 		s.insert (0, SGR_SEQ (COLOR_BG_CYAN
2808*38fd1498Szrj 				      COLOR_SEPARATOR COLOR_FG_WHITE));
2809*38fd1498Szrj 	      s += SGR_RESET;
2810*38fd1498Szrj 	    }
2811*38fd1498Szrj 	  else
2812*38fd1498Szrj 	    {
2813*38fd1498Szrj 	      s = unexceptional ? unexceptional_string : exceptional_string;
2814*38fd1498Szrj 	      pad_count_string (s);
2815*38fd1498Szrj 	    }
2816*38fd1498Szrj 	}
2817*38fd1498Szrj     }
2818*38fd1498Szrj   else
2819*38fd1498Szrj     {
2820*38fd1498Szrj       s = "-";
2821*38fd1498Szrj       pad_count_string (s);
2822*38fd1498Szrj     }
2823*38fd1498Szrj 
2824*38fd1498Szrj   fprintf (f, "%s:%5u", s.c_str (), line_num);
2825*38fd1498Szrj }
2826*38fd1498Szrj 
2827*38fd1498Szrj static void
2828*38fd1498Szrj print_source_line (FILE *f, const vector<const char *> &source_lines,
2829*38fd1498Szrj 		   unsigned line)
2830*38fd1498Szrj {
2831*38fd1498Szrj   gcc_assert (line >= 1);
2832*38fd1498Szrj   gcc_assert (line <= source_lines.size ());
2833*38fd1498Szrj 
2834*38fd1498Szrj   fprintf (f, ":%s\n", source_lines[line - 1]);
2835*38fd1498Szrj }
2836*38fd1498Szrj 
2837*38fd1498Szrj /* Output line details for LINE and print it to F file.  LINE lives on
2838*38fd1498Szrj    LINE_NUM.  */
2839*38fd1498Szrj 
2840*38fd1498Szrj static void
2841*38fd1498Szrj output_line_details (FILE *f, const line_info *line, unsigned line_num)
2842*38fd1498Szrj {
2843*38fd1498Szrj   if (flag_all_blocks)
2844*38fd1498Szrj     {
2845*38fd1498Szrj       arc_info *arc;
2846*38fd1498Szrj       int ix, jx;
2847*38fd1498Szrj 
2848*38fd1498Szrj       ix = jx = 0;
2849*38fd1498Szrj       for (vector<block_info *>::const_iterator it = line->blocks.begin ();
2850*38fd1498Szrj 	   it != line->blocks.end (); it++)
2851*38fd1498Szrj 	{
2852*38fd1498Szrj 	  if (!(*it)->is_call_return)
2853*38fd1498Szrj 	    {
2854*38fd1498Szrj 	      output_line_beginning (f, line->exists,
2855*38fd1498Szrj 				     (*it)->exceptional, false,
2856*38fd1498Szrj 				     (*it)->count, line_num,
2857*38fd1498Szrj 				     "%%%%%", "$$$$$");
2858*38fd1498Szrj 	      fprintf (f, "-block %2d", ix++);
2859*38fd1498Szrj 	      if (flag_verbose)
2860*38fd1498Szrj 		fprintf (f, " (BB %u)", (*it)->id);
2861*38fd1498Szrj 	      fprintf (f, "\n");
2862*38fd1498Szrj 	    }
2863*38fd1498Szrj 	  if (flag_branches)
2864*38fd1498Szrj 	    for (arc = (*it)->succ; arc; arc = arc->succ_next)
2865*38fd1498Szrj 	      jx += output_branch_count (f, jx, arc);
2866*38fd1498Szrj 	}
2867*38fd1498Szrj     }
2868*38fd1498Szrj   else if (flag_branches)
2869*38fd1498Szrj     {
2870*38fd1498Szrj       int ix;
2871*38fd1498Szrj 
2872*38fd1498Szrj       ix = 0;
2873*38fd1498Szrj       for (vector<arc_info *>::const_iterator it = line->branches.begin ();
2874*38fd1498Szrj 	   it != line->branches.end (); it++)
2875*38fd1498Szrj 	ix += output_branch_count (f, ix, (*it));
2876*38fd1498Szrj     }
2877*38fd1498Szrj }
2878*38fd1498Szrj 
2879*38fd1498Szrj /* Output detail statistics about function FN to file F.  */
2880*38fd1498Szrj 
2881*38fd1498Szrj static void
2882*38fd1498Szrj output_function_details (FILE *f, const function_info *fn)
2883*38fd1498Szrj {
2884*38fd1498Szrj   if (!flag_branches)
2885*38fd1498Szrj     return;
2886*38fd1498Szrj 
2887*38fd1498Szrj   arc_info *arc = fn->blocks[EXIT_BLOCK].pred;
2888*38fd1498Szrj   gcov_type return_count = fn->blocks[EXIT_BLOCK].count;
2889*38fd1498Szrj   gcov_type called_count = fn->blocks[ENTRY_BLOCK].count;
2890*38fd1498Szrj 
2891*38fd1498Szrj   for (; arc; arc = arc->pred_next)
2892*38fd1498Szrj     if (arc->fake)
2893*38fd1498Szrj       return_count -= arc->count;
2894*38fd1498Szrj 
2895*38fd1498Szrj   fprintf (f, "function %s",
2896*38fd1498Szrj 	   flag_demangled_names ? fn->demangled_name : fn->name);
2897*38fd1498Szrj   fprintf (f, " called %s",
2898*38fd1498Szrj 	   format_gcov (called_count, 0, -1));
2899*38fd1498Szrj   fprintf (f, " returned %s",
2900*38fd1498Szrj 	   format_gcov (return_count, called_count, 0));
2901*38fd1498Szrj   fprintf (f, " blocks executed %s",
2902*38fd1498Szrj 	   format_gcov (fn->blocks_executed, fn->blocks.size () - 2,
2903*38fd1498Szrj 			0));
2904*38fd1498Szrj   fprintf (f, "\n");
2905*38fd1498Szrj }
2906*38fd1498Szrj 
2907*38fd1498Szrj /* Read in the source file one line at a time, and output that line to
2908*38fd1498Szrj    the gcov file preceded by its execution count and other
2909*38fd1498Szrj    information.  */
2910*38fd1498Szrj 
2911*38fd1498Szrj static void
2912*38fd1498Szrj output_lines (FILE *gcov_file, const source_info *src)
2913*38fd1498Szrj {
2914*38fd1498Szrj #define  DEFAULT_LINE_START "        -:    0:"
2915*38fd1498Szrj #define FN_SEPARATOR "------------------\n"
2916*38fd1498Szrj 
2917*38fd1498Szrj   FILE *source_file;
2918*38fd1498Szrj   const char *retval;
2919*38fd1498Szrj 
2920*38fd1498Szrj   fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
2921*38fd1498Szrj   if (!multiple_files)
2922*38fd1498Szrj     {
2923*38fd1498Szrj       fprintf (gcov_file, DEFAULT_LINE_START "Graph:%s\n", bbg_file_name);
2924*38fd1498Szrj       fprintf (gcov_file, DEFAULT_LINE_START "Data:%s\n",
2925*38fd1498Szrj 	       no_data_file ? "-" : da_file_name);
2926*38fd1498Szrj       fprintf (gcov_file, DEFAULT_LINE_START "Runs:%u\n", object_runs);
2927*38fd1498Szrj     }
2928*38fd1498Szrj   fprintf (gcov_file, DEFAULT_LINE_START "Programs:%u\n", program_count);
2929*38fd1498Szrj 
2930*38fd1498Szrj   source_file = fopen (src->name, "r");
2931*38fd1498Szrj   if (!source_file)
2932*38fd1498Szrj     fnotice (stderr, "Cannot open source file %s\n", src->name);
2933*38fd1498Szrj   else if (src->file_time == 0)
2934*38fd1498Szrj     fprintf (gcov_file, DEFAULT_LINE_START "Source is newer than graph\n");
2935*38fd1498Szrj 
2936*38fd1498Szrj   vector<const char *> source_lines;
2937*38fd1498Szrj   if (source_file)
2938*38fd1498Szrj     while ((retval = read_line (source_file)) != NULL)
2939*38fd1498Szrj       source_lines.push_back (xstrdup (retval));
2940*38fd1498Szrj 
2941*38fd1498Szrj   unsigned line_start_group = 0;
2942*38fd1498Szrj   vector<function_info *> fns;
2943*38fd1498Szrj 
2944*38fd1498Szrj   for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
2945*38fd1498Szrj     {
2946*38fd1498Szrj       if (line_num >= src->lines.size ())
2947*38fd1498Szrj 	{
2948*38fd1498Szrj 	  fprintf (gcov_file, "%9s:%5u", "-", line_num);
2949*38fd1498Szrj 	  print_source_line (gcov_file, source_lines, line_num);
2950*38fd1498Szrj 	  continue;
2951*38fd1498Szrj 	}
2952*38fd1498Szrj 
2953*38fd1498Szrj       const line_info *line = &src->lines[line_num];
2954*38fd1498Szrj 
2955*38fd1498Szrj       if (line_start_group == 0)
2956*38fd1498Szrj 	{
2957*38fd1498Szrj 	  fns = src->get_functions_at_location (line_num);
2958*38fd1498Szrj 	  if (fns.size () > 1)
2959*38fd1498Szrj 	    {
2960*38fd1498Szrj 	      /* It's possible to have functions that partially overlap,
2961*38fd1498Szrj 		 thus take the maximum end_line of functions starting
2962*38fd1498Szrj 		 at LINE_NUM.  */
2963*38fd1498Szrj 	      for (unsigned i = 0; i < fns.size (); i++)
2964*38fd1498Szrj 		if (fns[i]->end_line > line_start_group)
2965*38fd1498Szrj 		  line_start_group = fns[i]->end_line;
2966*38fd1498Szrj 	    }
2967*38fd1498Szrj 	  else if (fns.size () == 1)
2968*38fd1498Szrj 	    {
2969*38fd1498Szrj 	      function_info *fn = fns[0];
2970*38fd1498Szrj 	      output_function_details (gcov_file, fn);
2971*38fd1498Szrj 	    }
2972*38fd1498Szrj 	}
2973*38fd1498Szrj 
2974*38fd1498Szrj       /* For lines which don't exist in the .bb file, print '-' before
2975*38fd1498Szrj 	 the source line.  For lines which exist but were never
2976*38fd1498Szrj 	 executed, print '#####' or '=====' before the source line.
2977*38fd1498Szrj 	 Otherwise, print the execution count before the source line.
2978*38fd1498Szrj 	 There are 16 spaces of indentation added before the source
2979*38fd1498Szrj 	 line so that tabs won't be messed up.  */
2980*38fd1498Szrj       output_line_beginning (gcov_file, line->exists, line->unexceptional,
2981*38fd1498Szrj 			     line->has_unexecuted_block, line->count,
2982*38fd1498Szrj 			     line_num, "=====", "#####");
2983*38fd1498Szrj 
2984*38fd1498Szrj       print_source_line (gcov_file, source_lines, line_num);
2985*38fd1498Szrj       output_line_details (gcov_file, line, line_num);
2986*38fd1498Szrj 
2987*38fd1498Szrj       if (line_start_group == line_num)
2988*38fd1498Szrj 	{
2989*38fd1498Szrj 	  for (vector<function_info *>::iterator it = fns.begin ();
2990*38fd1498Szrj 	       it != fns.end (); it++)
2991*38fd1498Szrj 	    {
2992*38fd1498Szrj 	      function_info *fn = *it;
2993*38fd1498Szrj 	      vector<line_info> &lines = fn->lines;
2994*38fd1498Szrj 
2995*38fd1498Szrj 	      fprintf (gcov_file, FN_SEPARATOR);
2996*38fd1498Szrj 
2997*38fd1498Szrj 	      string fn_name
2998*38fd1498Szrj 		= flag_demangled_names ? fn->demangled_name : fn->name;
2999*38fd1498Szrj 
3000*38fd1498Szrj 	      if (flag_use_colors)
3001*38fd1498Szrj 		{
3002*38fd1498Szrj 		  fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN));
3003*38fd1498Szrj 		  fn_name += SGR_RESET;
3004*38fd1498Szrj 		}
3005*38fd1498Szrj 
3006*38fd1498Szrj 	      fprintf (gcov_file, "%s:\n", fn_name.c_str ());
3007*38fd1498Szrj 
3008*38fd1498Szrj 	      output_function_details (gcov_file, fn);
3009*38fd1498Szrj 
3010*38fd1498Szrj 	      /* Print all lines covered by the function.  */
3011*38fd1498Szrj 	      for (unsigned i = 0; i < lines.size (); i++)
3012*38fd1498Szrj 		{
3013*38fd1498Szrj 		  line_info *line = &lines[i];
3014*38fd1498Szrj 		  unsigned l = fn->start_line + i;
3015*38fd1498Szrj 
3016*38fd1498Szrj 		  /* For lines which don't exist in the .bb file, print '-'
3017*38fd1498Szrj 		     before the source line.  For lines which exist but
3018*38fd1498Szrj 		     were never executed, print '#####' or '=====' before
3019*38fd1498Szrj 		     the source line.  Otherwise, print the execution count
3020*38fd1498Szrj 		     before the source line.
3021*38fd1498Szrj 		     There are 16 spaces of indentation added before the source
3022*38fd1498Szrj 		     line so that tabs won't be messed up.  */
3023*38fd1498Szrj 		  output_line_beginning (gcov_file, line->exists,
3024*38fd1498Szrj 					 line->unexceptional,
3025*38fd1498Szrj 					 line->has_unexecuted_block,
3026*38fd1498Szrj 					 line->count,
3027*38fd1498Szrj 					 l, "=====", "#####");
3028*38fd1498Szrj 
3029*38fd1498Szrj 		  print_source_line (gcov_file, source_lines, l);
3030*38fd1498Szrj 		  output_line_details (gcov_file, line, l);
3031*38fd1498Szrj 		}
3032*38fd1498Szrj 	    }
3033*38fd1498Szrj 
3034*38fd1498Szrj 	  fprintf (gcov_file, FN_SEPARATOR);
3035*38fd1498Szrj 	  line_start_group = 0;
3036*38fd1498Szrj 	}
3037*38fd1498Szrj     }
3038*38fd1498Szrj 
3039*38fd1498Szrj   if (source_file)
3040*38fd1498Szrj     fclose (source_file);
3041*38fd1498Szrj }
3042