xref: /dragonfly/contrib/gcc-4.7/gcc/gcov.c (revision e4b17023)
1*e4b17023SJohn Marino /* Gcov.c: prepend line execution counts and branch probabilities to a
2*e4b17023SJohn Marino    source file.
3*e4b17023SJohn Marino    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
4*e4b17023SJohn Marino    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
5*e4b17023SJohn Marino    Free Software Foundation, Inc.
6*e4b17023SJohn Marino    Contributed by James E. Wilson of Cygnus Support.
7*e4b17023SJohn Marino    Mangled by Bob Manson of Cygnus Support.
8*e4b17023SJohn Marino    Mangled further by Nathan Sidwell <nathan@codesourcery.com>
9*e4b17023SJohn Marino 
10*e4b17023SJohn Marino Gcov is free software; you can redistribute it and/or modify
11*e4b17023SJohn Marino it under the terms of the GNU General Public License as published by
12*e4b17023SJohn Marino the Free Software Foundation; either version 3, or (at your option)
13*e4b17023SJohn Marino any later version.
14*e4b17023SJohn Marino 
15*e4b17023SJohn Marino Gcov is distributed in the hope that it will be useful,
16*e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
17*e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*e4b17023SJohn Marino GNU General Public License for more details.
19*e4b17023SJohn Marino 
20*e4b17023SJohn Marino You should have received a copy of the GNU General Public License
21*e4b17023SJohn Marino along with Gcov; see the file COPYING3.  If not see
22*e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
23*e4b17023SJohn Marino 
24*e4b17023SJohn Marino /* ??? Print a list of the ten blocks with the highest execution counts,
25*e4b17023SJohn Marino    and list the line numbers corresponding to those blocks.  Also, perhaps
26*e4b17023SJohn Marino    list the line numbers with the highest execution counts, only printing
27*e4b17023SJohn Marino    the first if there are several which are all listed in the same block.  */
28*e4b17023SJohn Marino 
29*e4b17023SJohn Marino /* ??? Should have an option to print the number of basic blocks, and the
30*e4b17023SJohn Marino    percent of them that are covered.  */
31*e4b17023SJohn Marino 
32*e4b17023SJohn Marino /* Need an option to show individual block counts, and show
33*e4b17023SJohn Marino    probabilities of fall through arcs.  */
34*e4b17023SJohn Marino 
35*e4b17023SJohn Marino #include "config.h"
36*e4b17023SJohn Marino #include "system.h"
37*e4b17023SJohn Marino #include "coretypes.h"
38*e4b17023SJohn Marino #include "tm.h"
39*e4b17023SJohn Marino #include "intl.h"
40*e4b17023SJohn Marino #include "diagnostic.h"
41*e4b17023SJohn Marino #include "version.h"
42*e4b17023SJohn Marino 
43*e4b17023SJohn Marino #include <getopt.h>
44*e4b17023SJohn Marino 
45*e4b17023SJohn Marino #define IN_GCOV 1
46*e4b17023SJohn Marino #include "gcov-io.h"
47*e4b17023SJohn Marino #include "gcov-io.c"
48*e4b17023SJohn Marino 
49*e4b17023SJohn Marino /* The gcno file is generated by -ftest-coverage option. The gcda file is
50*e4b17023SJohn Marino    generated by a program compiled with -fprofile-arcs. Their formats
51*e4b17023SJohn Marino    are documented in gcov-io.h.  */
52*e4b17023SJohn Marino 
53*e4b17023SJohn Marino /* The functions in this file for creating and solution program flow graphs
54*e4b17023SJohn Marino    are very similar to functions in the gcc source file profile.c.  In
55*e4b17023SJohn Marino    some places we make use of the knowledge of how profile.c works to
56*e4b17023SJohn Marino    select particular algorithms here.  */
57*e4b17023SJohn Marino 
58*e4b17023SJohn Marino /* The code validates that the profile information read in corresponds
59*e4b17023SJohn Marino    to the code currently being compiled.  Rather than checking for
60*e4b17023SJohn Marino    identical files, the code below computes a checksum on the CFG
61*e4b17023SJohn Marino    (based on the order of basic blocks and the arcs in the CFG).  If
62*e4b17023SJohn Marino    the CFG checksum in the gcda file match the CFG checksum for the
63*e4b17023SJohn Marino    code currently being compiled, the profile data will be used.  */
64*e4b17023SJohn Marino 
65*e4b17023SJohn Marino /* This is the size of the buffer used to read in source file lines.  */
66*e4b17023SJohn Marino 
67*e4b17023SJohn Marino struct function_info;
68*e4b17023SJohn Marino struct block_info;
69*e4b17023SJohn Marino struct source_info;
70*e4b17023SJohn Marino 
71*e4b17023SJohn Marino /* Describes an arc between two basic blocks.  */
72*e4b17023SJohn Marino 
73*e4b17023SJohn Marino typedef struct arc_info
74*e4b17023SJohn Marino {
75*e4b17023SJohn Marino   /* source and destination blocks.  */
76*e4b17023SJohn Marino   struct block_info *src;
77*e4b17023SJohn Marino   struct block_info *dst;
78*e4b17023SJohn Marino 
79*e4b17023SJohn Marino   /* transition counts.  */
80*e4b17023SJohn Marino   gcov_type count;
81*e4b17023SJohn Marino   /* used in cycle search, so that we do not clobber original counts.  */
82*e4b17023SJohn Marino   gcov_type cs_count;
83*e4b17023SJohn Marino 
84*e4b17023SJohn Marino   unsigned int count_valid : 1;
85*e4b17023SJohn Marino   unsigned int on_tree : 1;
86*e4b17023SJohn Marino   unsigned int fake : 1;
87*e4b17023SJohn Marino   unsigned int fall_through : 1;
88*e4b17023SJohn Marino 
89*e4b17023SJohn Marino   /* Arc to a catch handler.  */
90*e4b17023SJohn Marino   unsigned int is_throw : 1;
91*e4b17023SJohn Marino 
92*e4b17023SJohn Marino   /* Arc is for a function that abnormally returns.  */
93*e4b17023SJohn Marino   unsigned int is_call_non_return : 1;
94*e4b17023SJohn Marino 
95*e4b17023SJohn Marino   /* Arc is for catch/setjmp.  */
96*e4b17023SJohn Marino   unsigned int is_nonlocal_return : 1;
97*e4b17023SJohn Marino 
98*e4b17023SJohn Marino   /* Is an unconditional branch.  */
99*e4b17023SJohn Marino   unsigned int is_unconditional : 1;
100*e4b17023SJohn Marino 
101*e4b17023SJohn Marino   /* Loop making arc.  */
102*e4b17023SJohn Marino   unsigned int cycle : 1;
103*e4b17023SJohn Marino 
104*e4b17023SJohn Marino   /* Next branch on line.  */
105*e4b17023SJohn Marino   struct arc_info *line_next;
106*e4b17023SJohn Marino 
107*e4b17023SJohn Marino   /* Links to next arc on src and dst lists.  */
108*e4b17023SJohn Marino   struct arc_info *succ_next;
109*e4b17023SJohn Marino   struct arc_info *pred_next;
110*e4b17023SJohn Marino } arc_t;
111*e4b17023SJohn Marino 
112*e4b17023SJohn Marino /* Describes a basic block. Contains lists of arcs to successor and
113*e4b17023SJohn Marino    predecessor blocks.  */
114*e4b17023SJohn Marino 
115*e4b17023SJohn Marino typedef struct block_info
116*e4b17023SJohn Marino {
117*e4b17023SJohn Marino   /* Chain of exit and entry arcs.  */
118*e4b17023SJohn Marino   arc_t *succ;
119*e4b17023SJohn Marino   arc_t *pred;
120*e4b17023SJohn Marino 
121*e4b17023SJohn Marino   /* Number of unprocessed exit and entry arcs.  */
122*e4b17023SJohn Marino   gcov_type num_succ;
123*e4b17023SJohn Marino   gcov_type num_pred;
124*e4b17023SJohn Marino 
125*e4b17023SJohn Marino   /* Block execution count.  */
126*e4b17023SJohn Marino   gcov_type count;
127*e4b17023SJohn Marino   unsigned flags : 12;
128*e4b17023SJohn Marino   unsigned count_valid : 1;
129*e4b17023SJohn Marino   unsigned valid_chain : 1;
130*e4b17023SJohn Marino   unsigned invalid_chain : 1;
131*e4b17023SJohn Marino   unsigned exceptional : 1;
132*e4b17023SJohn Marino 
133*e4b17023SJohn Marino   /* Block is a call instrumenting site.  */
134*e4b17023SJohn Marino   unsigned is_call_site : 1; /* Does the call.  */
135*e4b17023SJohn Marino   unsigned is_call_return : 1; /* Is the return.  */
136*e4b17023SJohn Marino 
137*e4b17023SJohn Marino   /* Block is a landing pad for longjmp or throw.  */
138*e4b17023SJohn Marino   unsigned is_nonlocal_return : 1;
139*e4b17023SJohn Marino 
140*e4b17023SJohn Marino   union
141*e4b17023SJohn Marino   {
142*e4b17023SJohn Marino     struct
143*e4b17023SJohn Marino     {
144*e4b17023SJohn Marino      /* Array of line numbers and source files. source files are
145*e4b17023SJohn Marino         introduced by a linenumber of zero, the next 'line number' is
146*e4b17023SJohn Marino         the number of the source file.  Always starts with a source
147*e4b17023SJohn Marino         file.  */
148*e4b17023SJohn Marino       unsigned *encoding;
149*e4b17023SJohn Marino       unsigned num;
150*e4b17023SJohn Marino     } line; /* Valid until blocks are linked onto lines */
151*e4b17023SJohn Marino     struct
152*e4b17023SJohn Marino     {
153*e4b17023SJohn Marino       /* Single line graph cycle workspace.  Used for all-blocks
154*e4b17023SJohn Marino 	 mode.  */
155*e4b17023SJohn Marino       arc_t *arc;
156*e4b17023SJohn Marino       unsigned ident;
157*e4b17023SJohn Marino     } cycle; /* Used in all-blocks mode, after blocks are linked onto
158*e4b17023SJohn Marino 	       lines.  */
159*e4b17023SJohn Marino   } u;
160*e4b17023SJohn Marino 
161*e4b17023SJohn Marino   /* Temporary chain for solving graph, and for chaining blocks on one
162*e4b17023SJohn Marino      line.  */
163*e4b17023SJohn Marino   struct block_info *chain;
164*e4b17023SJohn Marino 
165*e4b17023SJohn Marino } block_t;
166*e4b17023SJohn Marino 
167*e4b17023SJohn Marino /* Describes a single function. Contains an array of basic blocks.  */
168*e4b17023SJohn Marino 
169*e4b17023SJohn Marino typedef struct function_info
170*e4b17023SJohn Marino {
171*e4b17023SJohn Marino   /* Name of function.  */
172*e4b17023SJohn Marino   char *name;
173*e4b17023SJohn Marino   unsigned ident;
174*e4b17023SJohn Marino   unsigned lineno_checksum;
175*e4b17023SJohn Marino   unsigned cfg_checksum;
176*e4b17023SJohn Marino 
177*e4b17023SJohn Marino   /* The graph contains at least one fake incoming edge.  */
178*e4b17023SJohn Marino   unsigned has_catch : 1;
179*e4b17023SJohn Marino 
180*e4b17023SJohn Marino   /* Array of basic blocks.  */
181*e4b17023SJohn Marino   block_t *blocks;
182*e4b17023SJohn Marino   unsigned num_blocks;
183*e4b17023SJohn Marino   unsigned blocks_executed;
184*e4b17023SJohn Marino 
185*e4b17023SJohn Marino   /* Raw arc coverage counts.  */
186*e4b17023SJohn Marino   gcov_type *counts;
187*e4b17023SJohn Marino   unsigned num_counts;
188*e4b17023SJohn Marino 
189*e4b17023SJohn Marino   /* First line number & file.  */
190*e4b17023SJohn Marino   unsigned line;
191*e4b17023SJohn Marino   unsigned src;
192*e4b17023SJohn Marino 
193*e4b17023SJohn Marino   /* Next function in same source file.  */
194*e4b17023SJohn Marino   struct function_info *line_next;
195*e4b17023SJohn Marino 
196*e4b17023SJohn Marino   /* Next function.  */
197*e4b17023SJohn Marino   struct function_info *next;
198*e4b17023SJohn Marino } function_t;
199*e4b17023SJohn Marino 
200*e4b17023SJohn Marino /* Describes coverage of a file or function.  */
201*e4b17023SJohn Marino 
202*e4b17023SJohn Marino typedef struct coverage_info
203*e4b17023SJohn Marino {
204*e4b17023SJohn Marino   int lines;
205*e4b17023SJohn Marino   int lines_executed;
206*e4b17023SJohn Marino 
207*e4b17023SJohn Marino   int branches;
208*e4b17023SJohn Marino   int branches_executed;
209*e4b17023SJohn Marino   int branches_taken;
210*e4b17023SJohn Marino 
211*e4b17023SJohn Marino   int calls;
212*e4b17023SJohn Marino   int calls_executed;
213*e4b17023SJohn Marino 
214*e4b17023SJohn Marino   char *name;
215*e4b17023SJohn Marino } coverage_t;
216*e4b17023SJohn Marino 
217*e4b17023SJohn Marino /* Describes a single line of source. Contains a chain of basic blocks
218*e4b17023SJohn Marino    with code on it.  */
219*e4b17023SJohn Marino 
220*e4b17023SJohn Marino typedef struct line_info
221*e4b17023SJohn Marino {
222*e4b17023SJohn Marino   gcov_type count;	   /* execution count */
223*e4b17023SJohn Marino   union
224*e4b17023SJohn Marino   {
225*e4b17023SJohn Marino     arc_t *branches;	   /* branches from blocks that end on this
226*e4b17023SJohn Marino 			      line. Used for branch-counts when not
227*e4b17023SJohn Marino 			      all-blocks mode.  */
228*e4b17023SJohn Marino     block_t *blocks;       /* blocks which start on this line.  Used
229*e4b17023SJohn Marino 			      in all-blocks mode.  */
230*e4b17023SJohn Marino   } u;
231*e4b17023SJohn Marino   unsigned exists : 1;
232*e4b17023SJohn Marino   unsigned unexceptional : 1;
233*e4b17023SJohn Marino } line_t;
234*e4b17023SJohn Marino 
235*e4b17023SJohn Marino /* Describes a file mentioned in the block graph.  Contains an array
236*e4b17023SJohn Marino    of line info.  */
237*e4b17023SJohn Marino 
238*e4b17023SJohn Marino typedef struct source_info
239*e4b17023SJohn Marino {
240*e4b17023SJohn Marino   /* Canonical name of source file.  */
241*e4b17023SJohn Marino   char *name;
242*e4b17023SJohn Marino   time_t file_time;
243*e4b17023SJohn Marino 
244*e4b17023SJohn Marino   /* Array of line information.  */
245*e4b17023SJohn Marino   line_t *lines;
246*e4b17023SJohn Marino   unsigned num_lines;
247*e4b17023SJohn Marino 
248*e4b17023SJohn Marino   coverage_t coverage;
249*e4b17023SJohn Marino 
250*e4b17023SJohn Marino   /* Functions in this source file.  These are in ascending line
251*e4b17023SJohn Marino      number order.  */
252*e4b17023SJohn Marino   function_t *functions;
253*e4b17023SJohn Marino } source_t;
254*e4b17023SJohn Marino 
255*e4b17023SJohn Marino typedef struct name_map
256*e4b17023SJohn Marino {
257*e4b17023SJohn Marino   char *name;  /* Source file name */
258*e4b17023SJohn Marino   unsigned src;  /* Source file */
259*e4b17023SJohn Marino } name_map_t;
260*e4b17023SJohn Marino 
261*e4b17023SJohn Marino /* Holds a list of function basic block graphs.  */
262*e4b17023SJohn Marino 
263*e4b17023SJohn Marino static function_t *functions;
264*e4b17023SJohn Marino static function_t **fn_end = &functions;
265*e4b17023SJohn Marino 
266*e4b17023SJohn Marino static source_t *sources;   /* Array of source files  */
267*e4b17023SJohn Marino static unsigned n_sources;  /* Number of sources */
268*e4b17023SJohn Marino static unsigned a_sources;  /* Allocated sources */
269*e4b17023SJohn Marino 
270*e4b17023SJohn Marino static name_map_t *names;   /* Mapping of file names to sources */
271*e4b17023SJohn Marino static unsigned n_names;    /* Number of names */
272*e4b17023SJohn Marino static unsigned a_names;    /* Allocated names */
273*e4b17023SJohn Marino 
274*e4b17023SJohn Marino /* This holds data summary information.  */
275*e4b17023SJohn Marino 
276*e4b17023SJohn Marino static unsigned object_runs;
277*e4b17023SJohn Marino static unsigned program_count;
278*e4b17023SJohn Marino 
279*e4b17023SJohn Marino static unsigned total_lines;
280*e4b17023SJohn Marino static unsigned total_executed;
281*e4b17023SJohn Marino 
282*e4b17023SJohn Marino /* Modification time of graph file.  */
283*e4b17023SJohn Marino 
284*e4b17023SJohn Marino static time_t bbg_file_time;
285*e4b17023SJohn Marino 
286*e4b17023SJohn Marino /* Name and file pointer of the input file for the basic block graph.  */
287*e4b17023SJohn Marino 
288*e4b17023SJohn Marino static char *bbg_file_name;
289*e4b17023SJohn Marino 
290*e4b17023SJohn Marino /* Stamp of the bbg file */
291*e4b17023SJohn Marino static unsigned bbg_stamp;
292*e4b17023SJohn Marino 
293*e4b17023SJohn Marino /* Name and file pointer of the input file for the arc count data.  */
294*e4b17023SJohn Marino 
295*e4b17023SJohn Marino static char *da_file_name;
296*e4b17023SJohn Marino 
297*e4b17023SJohn Marino /* Data file is missing.  */
298*e4b17023SJohn Marino 
299*e4b17023SJohn Marino static int no_data_file;
300*e4b17023SJohn Marino 
301*e4b17023SJohn Marino /* If there is several input files, compute and display results after
302*e4b17023SJohn Marino    reading all data files.  This way if two or more gcda file refer to
303*e4b17023SJohn Marino    the same source file (eg inline subprograms in a .h file), the
304*e4b17023SJohn Marino    counts are added.  */
305*e4b17023SJohn Marino 
306*e4b17023SJohn Marino static int multiple_files = 0;
307*e4b17023SJohn Marino 
308*e4b17023SJohn Marino /* Output branch probabilities.  */
309*e4b17023SJohn Marino 
310*e4b17023SJohn Marino static int flag_branches = 0;
311*e4b17023SJohn Marino 
312*e4b17023SJohn Marino /* Show unconditional branches too.  */
313*e4b17023SJohn Marino static int flag_unconditional = 0;
314*e4b17023SJohn Marino 
315*e4b17023SJohn Marino /* Output a gcov file if this is true.  This is on by default, and can
316*e4b17023SJohn Marino    be turned off by the -n option.  */
317*e4b17023SJohn Marino 
318*e4b17023SJohn Marino static int flag_gcov_file = 1;
319*e4b17023SJohn Marino 
320*e4b17023SJohn Marino /* Output progress indication if this is true.  This is off by default
321*e4b17023SJohn Marino    and can be turned on by the -d option.  */
322*e4b17023SJohn Marino 
323*e4b17023SJohn Marino static int flag_display_progress = 0;
324*e4b17023SJohn Marino 
325*e4b17023SJohn Marino /* For included files, make the gcov output file name include the name
326*e4b17023SJohn Marino    of the input source file.  For example, if x.h is included in a.c,
327*e4b17023SJohn Marino    then the output file name is a.c##x.h.gcov instead of x.h.gcov.  */
328*e4b17023SJohn Marino 
329*e4b17023SJohn Marino static int flag_long_names = 0;
330*e4b17023SJohn Marino 
331*e4b17023SJohn Marino /* Output count information for every basic block, not merely those
332*e4b17023SJohn Marino    that contain line number information.  */
333*e4b17023SJohn Marino 
334*e4b17023SJohn Marino static int flag_all_blocks = 0;
335*e4b17023SJohn Marino 
336*e4b17023SJohn Marino /* Output summary info for each function.  */
337*e4b17023SJohn Marino 
338*e4b17023SJohn Marino static int flag_function_summary = 0;
339*e4b17023SJohn Marino 
340*e4b17023SJohn Marino /* Object directory file prefix.  This is the directory/file where the
341*e4b17023SJohn Marino    graph and data files are looked for, if nonzero.  */
342*e4b17023SJohn Marino 
343*e4b17023SJohn Marino static char *object_directory = 0;
344*e4b17023SJohn Marino 
345*e4b17023SJohn Marino /* Source directory prefix.  This is removed from source pathnames
346*e4b17023SJohn Marino    that match, when generating the output file name.  */
347*e4b17023SJohn Marino 
348*e4b17023SJohn Marino static char *source_prefix = 0;
349*e4b17023SJohn Marino static size_t source_length = 0;
350*e4b17023SJohn Marino 
351*e4b17023SJohn Marino /* Only show data for sources with relative pathnames.  Absolute ones
352*e4b17023SJohn Marino    usually indicate a system header file, which although it may
353*e4b17023SJohn Marino    contain inline functions, is usually uninteresting.  */
354*e4b17023SJohn Marino static int flag_relative_only = 0;
355*e4b17023SJohn Marino 
356*e4b17023SJohn Marino /* Preserve all pathname components. Needed when object files and
357*e4b17023SJohn Marino    source files are in subdirectories. '/' is mangled as '#', '.' is
358*e4b17023SJohn Marino    elided and '..' mangled to '^'.  */
359*e4b17023SJohn Marino 
360*e4b17023SJohn Marino static int flag_preserve_paths = 0;
361*e4b17023SJohn Marino 
362*e4b17023SJohn Marino /* Output the number of times a branch was taken as opposed to the percentage
363*e4b17023SJohn Marino    of times it was taken.  */
364*e4b17023SJohn Marino 
365*e4b17023SJohn Marino static int flag_counts = 0;
366*e4b17023SJohn Marino 
367*e4b17023SJohn Marino /* Forward declarations.  */
368*e4b17023SJohn Marino static int process_args (int, char **);
369*e4b17023SJohn Marino static void print_usage (int) ATTRIBUTE_NORETURN;
370*e4b17023SJohn Marino static void print_version (void) ATTRIBUTE_NORETURN;
371*e4b17023SJohn Marino static void process_file (const char *);
372*e4b17023SJohn Marino static void generate_results (const char *);
373*e4b17023SJohn Marino static void create_file_names (const char *);
374*e4b17023SJohn Marino static int name_search (const void *, const void *);
375*e4b17023SJohn Marino static int name_sort (const void *, const void *);
376*e4b17023SJohn Marino static char *canonicalize_name (const char *);
377*e4b17023SJohn Marino static unsigned find_source (const char *);
378*e4b17023SJohn Marino static function_t *read_graph_file (void);
379*e4b17023SJohn Marino static int read_count_file (function_t *);
380*e4b17023SJohn Marino static void solve_flow_graph (function_t *);
381*e4b17023SJohn Marino static void find_exception_blocks (function_t *);
382*e4b17023SJohn Marino static void add_branch_counts (coverage_t *, const arc_t *);
383*e4b17023SJohn Marino static void add_line_counts (coverage_t *, function_t *);
384*e4b17023SJohn Marino static void executed_summary (unsigned, unsigned);
385*e4b17023SJohn Marino static void function_summary (const coverage_t *, const char *);
386*e4b17023SJohn Marino static const char *format_gcov (gcov_type, gcov_type, int);
387*e4b17023SJohn Marino static void accumulate_line_counts (source_t *);
388*e4b17023SJohn Marino static int output_branch_count (FILE *, int, const arc_t *);
389*e4b17023SJohn Marino static void output_lines (FILE *, const source_t *);
390*e4b17023SJohn Marino static char *make_gcov_file_name (const char *, const char *);
391*e4b17023SJohn Marino static char *mangle_name (const char *, char *);
392*e4b17023SJohn Marino static void release_structures (void);
393*e4b17023SJohn Marino static void release_function (function_t *);
394*e4b17023SJohn Marino extern int main (int, char **);
395*e4b17023SJohn Marino 
396*e4b17023SJohn Marino int
main(int argc,char ** argv)397*e4b17023SJohn Marino main (int argc, char **argv)
398*e4b17023SJohn Marino {
399*e4b17023SJohn Marino   int argno;
400*e4b17023SJohn Marino   int first_arg;
401*e4b17023SJohn Marino   const char *p;
402*e4b17023SJohn Marino 
403*e4b17023SJohn Marino   p = argv[0] + strlen (argv[0]);
404*e4b17023SJohn Marino   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
405*e4b17023SJohn Marino     --p;
406*e4b17023SJohn Marino   progname = p;
407*e4b17023SJohn Marino 
408*e4b17023SJohn Marino   xmalloc_set_program_name (progname);
409*e4b17023SJohn Marino 
410*e4b17023SJohn Marino   /* Unlock the stdio streams.  */
411*e4b17023SJohn Marino   unlock_std_streams ();
412*e4b17023SJohn Marino 
413*e4b17023SJohn Marino   gcc_init_libintl ();
414*e4b17023SJohn Marino 
415*e4b17023SJohn Marino   diagnostic_initialize (global_dc, 0);
416*e4b17023SJohn Marino 
417*e4b17023SJohn Marino   /* Handle response files.  */
418*e4b17023SJohn Marino   expandargv (&argc, &argv);
419*e4b17023SJohn Marino 
420*e4b17023SJohn Marino   a_names = 10;
421*e4b17023SJohn Marino   names = XNEWVEC (name_map_t, a_names);
422*e4b17023SJohn Marino   a_sources = 10;
423*e4b17023SJohn Marino   sources = XNEWVEC (source_t, a_sources);
424*e4b17023SJohn Marino 
425*e4b17023SJohn Marino   argno = process_args (argc, argv);
426*e4b17023SJohn Marino   if (optind == argc)
427*e4b17023SJohn Marino     print_usage (true);
428*e4b17023SJohn Marino 
429*e4b17023SJohn Marino   if (argc - argno > 1)
430*e4b17023SJohn Marino     multiple_files = 1;
431*e4b17023SJohn Marino 
432*e4b17023SJohn Marino   first_arg = argno;
433*e4b17023SJohn Marino 
434*e4b17023SJohn Marino   for (; argno != argc; argno++)
435*e4b17023SJohn Marino     {
436*e4b17023SJohn Marino       if (flag_display_progress)
437*e4b17023SJohn Marino         printf("Processing file %d out of %d\n",
438*e4b17023SJohn Marino                argno - first_arg + 1, argc - first_arg);
439*e4b17023SJohn Marino       process_file (argv[argno]);
440*e4b17023SJohn Marino     }
441*e4b17023SJohn Marino 
442*e4b17023SJohn Marino   generate_results (multiple_files ? NULL : argv[argc - 1]);
443*e4b17023SJohn Marino 
444*e4b17023SJohn Marino   release_structures ();
445*e4b17023SJohn Marino 
446*e4b17023SJohn Marino   return 0;
447*e4b17023SJohn Marino }
448*e4b17023SJohn Marino 
449*e4b17023SJohn Marino /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
450*e4b17023SJohn Marino    otherwise the output of --help.  */
451*e4b17023SJohn Marino 
452*e4b17023SJohn Marino static void
print_usage(int error_p)453*e4b17023SJohn Marino print_usage (int error_p)
454*e4b17023SJohn Marino {
455*e4b17023SJohn Marino   FILE *file = error_p ? stderr : stdout;
456*e4b17023SJohn Marino   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
457*e4b17023SJohn Marino 
458*e4b17023SJohn Marino   fnotice (file, "Usage: gcov [OPTION]... SOURCE|OBJ...\n\n");
459*e4b17023SJohn Marino   fnotice (file, "Print code coverage information.\n\n");
460*e4b17023SJohn Marino   fnotice (file, "  -h, --help                      Print this help, then exit\n");
461*e4b17023SJohn Marino   fnotice (file, "  -v, --version                   Print version number, then exit\n");
462*e4b17023SJohn Marino   fnotice (file, "  -a, --all-blocks                Show information for every basic block\n");
463*e4b17023SJohn Marino   fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output\n");
464*e4b17023SJohn Marino   fnotice (file, "  -c, --branch-counts             Given counts of branches taken\n\
465*e4b17023SJohn Marino                                     rather than percentages\n");
466*e4b17023SJohn Marino   fnotice (file, "  -n, --no-output                 Do not create an output file\n");
467*e4b17023SJohn Marino   fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
468*e4b17023SJohn Marino                                     source files\n");
469*e4b17023SJohn Marino   fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
470*e4b17023SJohn Marino   fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
471*e4b17023SJohn Marino   fnotice (file, "  -s, --source-prefix DIR         Source prefix to elide\n");
472*e4b17023SJohn Marino   fnotice (file, "  -r, --relative-only             Only show data for relative sources\n");
473*e4b17023SJohn Marino   fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
474*e4b17023SJohn Marino   fnotice (file, "  -u, --unconditional-branches    Show unconditional branch counts too\n");
475*e4b17023SJohn Marino   fnotice (file, "  -d, --display-progress          Display progress information\n");
476*e4b17023SJohn Marino   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
477*e4b17023SJohn Marino 	   bug_report_url);
478*e4b17023SJohn Marino   exit (status);
479*e4b17023SJohn Marino }
480*e4b17023SJohn Marino 
481*e4b17023SJohn Marino /* Print version information and exit.  */
482*e4b17023SJohn Marino 
483*e4b17023SJohn Marino static void
print_version(void)484*e4b17023SJohn Marino print_version (void)
485*e4b17023SJohn Marino {
486*e4b17023SJohn Marino   fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string);
487*e4b17023SJohn Marino   fprintf (stdout, "Copyright %s 2012 Free Software Foundation, Inc.\n",
488*e4b17023SJohn Marino 	   _("(C)"));
489*e4b17023SJohn Marino   fnotice (stdout,
490*e4b17023SJohn Marino 	   _("This is free software; see the source for copying conditions.\n"
491*e4b17023SJohn Marino 	     "There is NO warranty; not even for MERCHANTABILITY or \n"
492*e4b17023SJohn Marino 	     "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
493*e4b17023SJohn Marino   exit (SUCCESS_EXIT_CODE);
494*e4b17023SJohn Marino }
495*e4b17023SJohn Marino 
496*e4b17023SJohn Marino static const struct option options[] =
497*e4b17023SJohn Marino {
498*e4b17023SJohn Marino   { "help",                 no_argument,       NULL, 'h' },
499*e4b17023SJohn Marino   { "version",              no_argument,       NULL, 'v' },
500*e4b17023SJohn Marino   { "all-blocks",           no_argument,       NULL, 'a' },
501*e4b17023SJohn Marino   { "branch-probabilities", no_argument,       NULL, 'b' },
502*e4b17023SJohn Marino   { "branch-counts",        no_argument,       NULL, 'c' },
503*e4b17023SJohn Marino   { "no-output",            no_argument,       NULL, 'n' },
504*e4b17023SJohn Marino   { "long-file-names",      no_argument,       NULL, 'l' },
505*e4b17023SJohn Marino   { "function-summaries",   no_argument,       NULL, 'f' },
506*e4b17023SJohn Marino   { "preserve-paths",       no_argument,       NULL, 'p' },
507*e4b17023SJohn Marino   { "relative-only",        no_argument,       NULL, 'r' },
508*e4b17023SJohn Marino   { "object-directory",     required_argument, NULL, 'o' },
509*e4b17023SJohn Marino   { "object-file",          required_argument, NULL, 'o' },
510*e4b17023SJohn Marino   { "source-prefix",        required_argument, NULL, 's' },
511*e4b17023SJohn Marino   { "unconditional-branches", no_argument,     NULL, 'u' },
512*e4b17023SJohn Marino   { "display-progress",     no_argument,       NULL, 'd' },
513*e4b17023SJohn Marino   { 0, 0, 0, 0 }
514*e4b17023SJohn Marino };
515*e4b17023SJohn Marino 
516*e4b17023SJohn Marino /* Process args, return index to first non-arg.  */
517*e4b17023SJohn Marino 
518*e4b17023SJohn Marino static int
process_args(int argc,char ** argv)519*e4b17023SJohn Marino process_args (int argc, char **argv)
520*e4b17023SJohn Marino {
521*e4b17023SJohn Marino   int opt;
522*e4b17023SJohn Marino 
523*e4b17023SJohn Marino   while ((opt = getopt_long (argc, argv, "abcdfhlno:s:pruv", options, NULL)) != -1)
524*e4b17023SJohn Marino     {
525*e4b17023SJohn Marino       switch (opt)
526*e4b17023SJohn Marino 	{
527*e4b17023SJohn Marino 	case 'a':
528*e4b17023SJohn Marino 	  flag_all_blocks = 1;
529*e4b17023SJohn Marino 	  break;
530*e4b17023SJohn Marino 	case 'b':
531*e4b17023SJohn Marino 	  flag_branches = 1;
532*e4b17023SJohn Marino 	  break;
533*e4b17023SJohn Marino 	case 'c':
534*e4b17023SJohn Marino 	  flag_counts = 1;
535*e4b17023SJohn Marino 	  break;
536*e4b17023SJohn Marino 	case 'f':
537*e4b17023SJohn Marino 	  flag_function_summary = 1;
538*e4b17023SJohn Marino 	  break;
539*e4b17023SJohn Marino 	case 'h':
540*e4b17023SJohn Marino 	  print_usage (false);
541*e4b17023SJohn Marino 	  /* print_usage will exit.  */
542*e4b17023SJohn Marino 	case 'l':
543*e4b17023SJohn Marino 	  flag_long_names = 1;
544*e4b17023SJohn Marino 	  break;
545*e4b17023SJohn Marino 	case 'n':
546*e4b17023SJohn Marino 	  flag_gcov_file = 0;
547*e4b17023SJohn Marino 	  break;
548*e4b17023SJohn Marino 	case 'o':
549*e4b17023SJohn Marino 	  object_directory = optarg;
550*e4b17023SJohn Marino 	  break;
551*e4b17023SJohn Marino 	case 's':
552*e4b17023SJohn Marino 	  source_prefix = optarg;
553*e4b17023SJohn Marino 	  source_length = strlen (source_prefix);
554*e4b17023SJohn Marino 	  break;
555*e4b17023SJohn Marino 	case 'r':
556*e4b17023SJohn Marino 	  flag_relative_only = 1;
557*e4b17023SJohn Marino 	  break;
558*e4b17023SJohn Marino 	case 'p':
559*e4b17023SJohn Marino 	  flag_preserve_paths = 1;
560*e4b17023SJohn Marino 	  break;
561*e4b17023SJohn Marino 	case 'u':
562*e4b17023SJohn Marino 	  flag_unconditional = 1;
563*e4b17023SJohn Marino 	  break;
564*e4b17023SJohn Marino         case 'd':
565*e4b17023SJohn Marino           flag_display_progress = 1;
566*e4b17023SJohn Marino           break;
567*e4b17023SJohn Marino 	case 'v':
568*e4b17023SJohn Marino 	  print_version ();
569*e4b17023SJohn Marino 	  /* print_version will exit.  */
570*e4b17023SJohn Marino 	default:
571*e4b17023SJohn Marino 	  print_usage (true);
572*e4b17023SJohn Marino 	  /* print_usage will exit.  */
573*e4b17023SJohn Marino 	}
574*e4b17023SJohn Marino     }
575*e4b17023SJohn Marino 
576*e4b17023SJohn Marino   return optind;
577*e4b17023SJohn Marino }
578*e4b17023SJohn Marino 
579*e4b17023SJohn Marino /* Process a single input file.  */
580*e4b17023SJohn Marino 
581*e4b17023SJohn Marino static void
process_file(const char * file_name)582*e4b17023SJohn Marino process_file (const char *file_name)
583*e4b17023SJohn Marino {
584*e4b17023SJohn Marino   function_t *fns;
585*e4b17023SJohn Marino 
586*e4b17023SJohn Marino   create_file_names (file_name);
587*e4b17023SJohn Marino   fns = read_graph_file ();
588*e4b17023SJohn Marino   if (!fns)
589*e4b17023SJohn Marino     return;
590*e4b17023SJohn Marino 
591*e4b17023SJohn Marino   read_count_file (fns);
592*e4b17023SJohn Marino   while (fns)
593*e4b17023SJohn Marino     {
594*e4b17023SJohn Marino       function_t *fn = fns;
595*e4b17023SJohn Marino 
596*e4b17023SJohn Marino       fns = fn->next;
597*e4b17023SJohn Marino       fn->next = NULL;
598*e4b17023SJohn Marino       if (fn->counts)
599*e4b17023SJohn Marino 	{
600*e4b17023SJohn Marino 	  unsigned src = fn->src;
601*e4b17023SJohn Marino 	  unsigned line = fn->line;
602*e4b17023SJohn Marino 	  unsigned block_no;
603*e4b17023SJohn Marino 	  function_t *probe, **prev;
604*e4b17023SJohn Marino 
605*e4b17023SJohn Marino 	  /* Now insert it into the source file's list of
606*e4b17023SJohn Marino 	     functions. Normally functions will be encountered in
607*e4b17023SJohn Marino 	     ascending order, so a simple scan is quick.  Note we're
608*e4b17023SJohn Marino 	     building this list in reverse order.  */
609*e4b17023SJohn Marino 	  for (prev = &sources[src].functions;
610*e4b17023SJohn Marino 	       (probe = *prev); prev = &probe->line_next)
611*e4b17023SJohn Marino 	    if (probe->line <= line)
612*e4b17023SJohn Marino 	      break;
613*e4b17023SJohn Marino 	  fn->line_next = probe;
614*e4b17023SJohn Marino 	  *prev = fn;
615*e4b17023SJohn Marino 
616*e4b17023SJohn Marino 	  /* Mark last line in files touched by function.  */
617*e4b17023SJohn Marino 	  for (block_no = 0; block_no != fn->num_blocks; block_no++)
618*e4b17023SJohn Marino 	    {
619*e4b17023SJohn Marino 	      unsigned *enc = fn->blocks[block_no].u.line.encoding;
620*e4b17023SJohn Marino 	      unsigned num = fn->blocks[block_no].u.line.num;
621*e4b17023SJohn Marino 
622*e4b17023SJohn Marino 	      for (; num--; enc++)
623*e4b17023SJohn Marino 		if (!*enc)
624*e4b17023SJohn Marino 		  {
625*e4b17023SJohn Marino 		    if (enc[1] != src)
626*e4b17023SJohn Marino 		      {
627*e4b17023SJohn Marino 			if (line >= sources[src].num_lines)
628*e4b17023SJohn Marino 			  sources[src].num_lines = line + 1;
629*e4b17023SJohn Marino 			line = 0;
630*e4b17023SJohn Marino 			src = enc[1];
631*e4b17023SJohn Marino 		      }
632*e4b17023SJohn Marino 		    enc++;
633*e4b17023SJohn Marino 		    num--;
634*e4b17023SJohn Marino 		  }
635*e4b17023SJohn Marino 		else if (*enc > line)
636*e4b17023SJohn Marino 		  line = *enc;
637*e4b17023SJohn Marino 	    }
638*e4b17023SJohn Marino 	  if (line >= sources[src].num_lines)
639*e4b17023SJohn Marino 	    sources[src].num_lines = line + 1;
640*e4b17023SJohn Marino 
641*e4b17023SJohn Marino 	  solve_flow_graph (fn);
642*e4b17023SJohn Marino 	  if (fn->has_catch)
643*e4b17023SJohn Marino 	    find_exception_blocks (fn);
644*e4b17023SJohn Marino 	  *fn_end = fn;
645*e4b17023SJohn Marino 	  fn_end = &fn->next;
646*e4b17023SJohn Marino 	}
647*e4b17023SJohn Marino       else
648*e4b17023SJohn Marino 	/* The function was not in the executable -- some other
649*e4b17023SJohn Marino 	   instance must have been selected.  */
650*e4b17023SJohn Marino 	release_function (fn);
651*e4b17023SJohn Marino     }
652*e4b17023SJohn Marino }
653*e4b17023SJohn Marino 
654*e4b17023SJohn Marino static void
generate_results(const char * file_name)655*e4b17023SJohn Marino generate_results (const char *file_name)
656*e4b17023SJohn Marino {
657*e4b17023SJohn Marino   unsigned ix;
658*e4b17023SJohn Marino   source_t *src;
659*e4b17023SJohn Marino   function_t *fn;
660*e4b17023SJohn Marino 
661*e4b17023SJohn Marino   for (ix = n_sources, src = sources; ix--; src++)
662*e4b17023SJohn Marino     if (src->num_lines)
663*e4b17023SJohn Marino       src->lines = XCNEWVEC (line_t, src->num_lines);
664*e4b17023SJohn Marino 
665*e4b17023SJohn Marino   for (fn = functions; fn; fn = fn->next)
666*e4b17023SJohn Marino     {
667*e4b17023SJohn Marino       coverage_t coverage;
668*e4b17023SJohn Marino 
669*e4b17023SJohn Marino       memset (&coverage, 0, sizeof (coverage));
670*e4b17023SJohn Marino       coverage.name = fn->name;
671*e4b17023SJohn Marino       add_line_counts (flag_function_summary ? &coverage : NULL, fn);
672*e4b17023SJohn Marino       if (flag_function_summary)
673*e4b17023SJohn Marino 	{
674*e4b17023SJohn Marino 	  function_summary (&coverage, "Function");
675*e4b17023SJohn Marino 	  fnotice (stdout, "\n");
676*e4b17023SJohn Marino 	}
677*e4b17023SJohn Marino     }
678*e4b17023SJohn Marino 
679*e4b17023SJohn Marino   if (file_name)
680*e4b17023SJohn Marino     {
681*e4b17023SJohn Marino       name_map_t *name_map = (name_map_t *)bsearch
682*e4b17023SJohn Marino 	(file_name, names, n_names, sizeof (*names), name_search);
683*e4b17023SJohn Marino       if (name_map)
684*e4b17023SJohn Marino 	file_name = sources[name_map->src].coverage.name;
685*e4b17023SJohn Marino       else
686*e4b17023SJohn Marino 	file_name = canonicalize_name (file_name);
687*e4b17023SJohn Marino     }
688*e4b17023SJohn Marino 
689*e4b17023SJohn Marino   for (ix = n_sources, src = sources; ix--; src++)
690*e4b17023SJohn Marino     {
691*e4b17023SJohn Marino       if (flag_relative_only)
692*e4b17023SJohn Marino 	{
693*e4b17023SJohn Marino 	  /* Ignore this source, if it is an absolute path (after
694*e4b17023SJohn Marino 	     source prefix removal).  */
695*e4b17023SJohn Marino 	  char first = src->coverage.name[0];
696*e4b17023SJohn Marino 
697*e4b17023SJohn Marino #if HAVE_DOS_BASED_FILE_SYSTEM
698*e4b17023SJohn Marino 	  if (first && src->coverage.name[1] == ':')
699*e4b17023SJohn Marino 	    first = src->coverage.name[2];
700*e4b17023SJohn Marino #endif
701*e4b17023SJohn Marino 	  if (IS_DIR_SEPARATOR (first))
702*e4b17023SJohn Marino 	    continue;
703*e4b17023SJohn Marino 	}
704*e4b17023SJohn Marino 
705*e4b17023SJohn Marino       accumulate_line_counts (src);
706*e4b17023SJohn Marino       function_summary (&src->coverage, "File");
707*e4b17023SJohn Marino       total_lines += src->coverage.lines;
708*e4b17023SJohn Marino       total_executed += src->coverage.lines_executed;
709*e4b17023SJohn Marino       if (flag_gcov_file)
710*e4b17023SJohn Marino 	{
711*e4b17023SJohn Marino 	  char *gcov_file_name
712*e4b17023SJohn Marino 	    = make_gcov_file_name (file_name, src->coverage.name);
713*e4b17023SJohn Marino 
714*e4b17023SJohn Marino 	  if (src->coverage.lines)
715*e4b17023SJohn Marino 	    {
716*e4b17023SJohn Marino 	      FILE *gcov_file = fopen (gcov_file_name, "w");
717*e4b17023SJohn Marino 
718*e4b17023SJohn Marino 	      if (gcov_file)
719*e4b17023SJohn Marino 		{
720*e4b17023SJohn Marino 		  fnotice (stdout, "Creating '%s'\n", gcov_file_name);
721*e4b17023SJohn Marino 		  output_lines (gcov_file, src);
722*e4b17023SJohn Marino 		  if (ferror (gcov_file))
723*e4b17023SJohn Marino 		    fnotice (stderr, "Error writing output file '%s'\n",
724*e4b17023SJohn Marino 			     gcov_file_name);
725*e4b17023SJohn Marino 		  fclose (gcov_file);
726*e4b17023SJohn Marino 		}
727*e4b17023SJohn Marino 	      else
728*e4b17023SJohn Marino 		fnotice (stderr, "Could not open output file '%s'\n",
729*e4b17023SJohn Marino 			 gcov_file_name);
730*e4b17023SJohn Marino 	    }
731*e4b17023SJohn Marino 	  else
732*e4b17023SJohn Marino 	    {
733*e4b17023SJohn Marino 	      unlink (gcov_file_name);
734*e4b17023SJohn Marino 	      fnotice (stdout, "Removing '%s'\n", gcov_file_name);
735*e4b17023SJohn Marino 	    }
736*e4b17023SJohn Marino 	  free (gcov_file_name);
737*e4b17023SJohn Marino 	}
738*e4b17023SJohn Marino       fnotice (stdout, "\n");
739*e4b17023SJohn Marino     }
740*e4b17023SJohn Marino 
741*e4b17023SJohn Marino   if (!file_name)
742*e4b17023SJohn Marino     executed_summary (total_lines, total_executed);
743*e4b17023SJohn Marino }
744*e4b17023SJohn Marino 
745*e4b17023SJohn Marino /* Release a function structure */
746*e4b17023SJohn Marino 
747*e4b17023SJohn Marino static void
release_function(function_t * fn)748*e4b17023SJohn Marino release_function (function_t *fn)
749*e4b17023SJohn Marino {
750*e4b17023SJohn Marino   unsigned ix;
751*e4b17023SJohn Marino   block_t *block;
752*e4b17023SJohn Marino 
753*e4b17023SJohn Marino   for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
754*e4b17023SJohn Marino     {
755*e4b17023SJohn Marino       arc_t *arc, *arc_n;
756*e4b17023SJohn Marino 
757*e4b17023SJohn Marino       for (arc = block->succ; arc; arc = arc_n)
758*e4b17023SJohn Marino 	{
759*e4b17023SJohn Marino 	  arc_n = arc->succ_next;
760*e4b17023SJohn Marino 	  free (arc);
761*e4b17023SJohn Marino 	}
762*e4b17023SJohn Marino     }
763*e4b17023SJohn Marino   free (fn->blocks);
764*e4b17023SJohn Marino   free (fn->counts);
765*e4b17023SJohn Marino }
766*e4b17023SJohn Marino 
767*e4b17023SJohn Marino /* Release all memory used.  */
768*e4b17023SJohn Marino 
769*e4b17023SJohn Marino static void
release_structures(void)770*e4b17023SJohn Marino release_structures (void)
771*e4b17023SJohn Marino {
772*e4b17023SJohn Marino   unsigned ix;
773*e4b17023SJohn Marino   function_t *fn;
774*e4b17023SJohn Marino 
775*e4b17023SJohn Marino   for (ix = n_sources; ix--;)
776*e4b17023SJohn Marino     free (sources[ix].lines);
777*e4b17023SJohn Marino   free (sources);
778*e4b17023SJohn Marino 
779*e4b17023SJohn Marino   for (ix = n_names; ix--;)
780*e4b17023SJohn Marino     free (names[ix].name);
781*e4b17023SJohn Marino   free (names);
782*e4b17023SJohn Marino 
783*e4b17023SJohn Marino   while ((fn = functions))
784*e4b17023SJohn Marino     {
785*e4b17023SJohn Marino       functions = fn->next;
786*e4b17023SJohn Marino       release_function (fn);
787*e4b17023SJohn Marino     }
788*e4b17023SJohn Marino }
789*e4b17023SJohn Marino 
790*e4b17023SJohn Marino /* Generate the names of the graph and data files.  If OBJECT_DIRECTORY
791*e4b17023SJohn Marino    is not specified, these are named from FILE_NAME sans extension.  If
792*e4b17023SJohn Marino    OBJECT_DIRECTORY is specified and is a directory, the files are in that
793*e4b17023SJohn Marino    directory, but named from the basename of the FILE_NAME, sans extension.
794*e4b17023SJohn Marino    Otherwise OBJECT_DIRECTORY is taken to be the name of the object *file*
795*e4b17023SJohn Marino    and the data files are named from that.  */
796*e4b17023SJohn Marino 
797*e4b17023SJohn Marino static void
create_file_names(const char * file_name)798*e4b17023SJohn Marino create_file_names (const char *file_name)
799*e4b17023SJohn Marino {
800*e4b17023SJohn Marino   char *cptr;
801*e4b17023SJohn Marino   char *name;
802*e4b17023SJohn Marino   int length = strlen (file_name);
803*e4b17023SJohn Marino   int base;
804*e4b17023SJohn Marino 
805*e4b17023SJohn Marino   /* Free previous file names.  */
806*e4b17023SJohn Marino   free (bbg_file_name);
807*e4b17023SJohn Marino   free (da_file_name);
808*e4b17023SJohn Marino   da_file_name = bbg_file_name = NULL;
809*e4b17023SJohn Marino   bbg_file_time = 0;
810*e4b17023SJohn Marino   bbg_stamp = 0;
811*e4b17023SJohn Marino 
812*e4b17023SJohn Marino   if (object_directory && object_directory[0])
813*e4b17023SJohn Marino     {
814*e4b17023SJohn Marino       struct stat status;
815*e4b17023SJohn Marino 
816*e4b17023SJohn Marino       length += strlen (object_directory) + 2;
817*e4b17023SJohn Marino       name = XNEWVEC (char, length);
818*e4b17023SJohn Marino       name[0] = 0;
819*e4b17023SJohn Marino 
820*e4b17023SJohn Marino       base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
821*e4b17023SJohn Marino       strcat (name, object_directory);
822*e4b17023SJohn Marino       if (base && (! IS_DIR_SEPARATOR (name[strlen (name) - 1])))
823*e4b17023SJohn Marino 	strcat (name, "/");
824*e4b17023SJohn Marino     }
825*e4b17023SJohn Marino   else
826*e4b17023SJohn Marino     {
827*e4b17023SJohn Marino       name = XNEWVEC (char, length + 1);
828*e4b17023SJohn Marino       strcpy (name, file_name);
829*e4b17023SJohn Marino       base = 0;
830*e4b17023SJohn Marino     }
831*e4b17023SJohn Marino 
832*e4b17023SJohn Marino   if (base)
833*e4b17023SJohn Marino     {
834*e4b17023SJohn Marino       /* Append source file name.  */
835*e4b17023SJohn Marino       const char *cptr = lbasename (file_name);
836*e4b17023SJohn Marino       strcat (name, cptr ? cptr : file_name);
837*e4b17023SJohn Marino     }
838*e4b17023SJohn Marino 
839*e4b17023SJohn Marino   /* Remove the extension.  */
840*e4b17023SJohn Marino   cptr = strrchr (name, '.');
841*e4b17023SJohn Marino   if (cptr)
842*e4b17023SJohn Marino     *cptr = 0;
843*e4b17023SJohn Marino 
844*e4b17023SJohn Marino   length = strlen (name);
845*e4b17023SJohn Marino 
846*e4b17023SJohn Marino   bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
847*e4b17023SJohn Marino   strcpy (bbg_file_name, name);
848*e4b17023SJohn Marino   strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
849*e4b17023SJohn Marino 
850*e4b17023SJohn Marino   da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
851*e4b17023SJohn Marino   strcpy (da_file_name, name);
852*e4b17023SJohn Marino   strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
853*e4b17023SJohn Marino 
854*e4b17023SJohn Marino   free (name);
855*e4b17023SJohn Marino   return;
856*e4b17023SJohn Marino }
857*e4b17023SJohn Marino 
858*e4b17023SJohn Marino /* A is a string and B is a pointer to name_map_t.  Compare for file
859*e4b17023SJohn Marino    name orderability.  */
860*e4b17023SJohn Marino 
861*e4b17023SJohn Marino static int
name_search(const void * a_,const void * b_)862*e4b17023SJohn Marino name_search (const void *a_, const void *b_)
863*e4b17023SJohn Marino {
864*e4b17023SJohn Marino   const char *a = (const char *)a_;
865*e4b17023SJohn Marino   const name_map_t *b = (const name_map_t *)b_;
866*e4b17023SJohn Marino 
867*e4b17023SJohn Marino #if HAVE_DOS_BASED_FILE_SYSTEM
868*e4b17023SJohn Marino   return strcasecmp (a, b->name);
869*e4b17023SJohn Marino #else
870*e4b17023SJohn Marino   return strcmp (a, b->name);
871*e4b17023SJohn Marino #endif
872*e4b17023SJohn Marino }
873*e4b17023SJohn Marino 
874*e4b17023SJohn Marino /* A and B are a pointer to name_map_t.  Compare for file name
875*e4b17023SJohn Marino    orderability.  */
876*e4b17023SJohn Marino 
877*e4b17023SJohn Marino static int
name_sort(const void * a_,const void * b_)878*e4b17023SJohn Marino name_sort (const void *a_, const void *b_)
879*e4b17023SJohn Marino {
880*e4b17023SJohn Marino   const name_map_t *a = (const name_map_t *)a_;
881*e4b17023SJohn Marino   return name_search (a->name, b_);
882*e4b17023SJohn Marino }
883*e4b17023SJohn Marino 
884*e4b17023SJohn Marino /* Find or create a source file structure for FILE_NAME. Copies
885*e4b17023SJohn Marino    FILE_NAME on creation */
886*e4b17023SJohn Marino 
887*e4b17023SJohn Marino static unsigned
find_source(const char * file_name)888*e4b17023SJohn Marino find_source (const char *file_name)
889*e4b17023SJohn Marino {
890*e4b17023SJohn Marino   name_map_t *name_map;
891*e4b17023SJohn Marino   char *canon;
892*e4b17023SJohn Marino   unsigned idx;
893*e4b17023SJohn Marino   struct stat status;
894*e4b17023SJohn Marino 
895*e4b17023SJohn Marino   if (!file_name)
896*e4b17023SJohn Marino     file_name = "<unknown>";
897*e4b17023SJohn Marino   name_map = (name_map_t *)bsearch
898*e4b17023SJohn Marino     (file_name, names, n_names, sizeof (*names), name_search);
899*e4b17023SJohn Marino   if (name_map)
900*e4b17023SJohn Marino     {
901*e4b17023SJohn Marino       idx = name_map->src;
902*e4b17023SJohn Marino       goto check_date;
903*e4b17023SJohn Marino     }
904*e4b17023SJohn Marino 
905*e4b17023SJohn Marino   if (n_names + 2 > a_names)
906*e4b17023SJohn Marino     {
907*e4b17023SJohn Marino       /* Extend the name map array -- we'll be inserting one or two
908*e4b17023SJohn Marino 	 entries.  */
909*e4b17023SJohn Marino       a_names *= 2;
910*e4b17023SJohn Marino       name_map = XNEWVEC (name_map_t, a_names);
911*e4b17023SJohn Marino       memcpy (name_map, names, n_names * sizeof (*names));
912*e4b17023SJohn Marino       free (names);
913*e4b17023SJohn Marino       names = name_map;
914*e4b17023SJohn Marino     }
915*e4b17023SJohn Marino 
916*e4b17023SJohn Marino   /* Not found, try the canonical name. */
917*e4b17023SJohn Marino   canon = canonicalize_name (file_name);
918*e4b17023SJohn Marino   name_map = (name_map_t *)bsearch
919*e4b17023SJohn Marino     (canon, names, n_names, sizeof (*names), name_search);
920*e4b17023SJohn Marino   if (!name_map)
921*e4b17023SJohn Marino     {
922*e4b17023SJohn Marino       /* Not found with canonical name, create a new source.  */
923*e4b17023SJohn Marino       source_t *src;
924*e4b17023SJohn Marino 
925*e4b17023SJohn Marino       if (n_sources == a_sources)
926*e4b17023SJohn Marino 	{
927*e4b17023SJohn Marino 	  a_sources *= 2;
928*e4b17023SJohn Marino 	  src = XNEWVEC (source_t, a_sources);
929*e4b17023SJohn Marino 	  memcpy (src, sources, n_sources * sizeof (*sources));
930*e4b17023SJohn Marino 	  free (sources);
931*e4b17023SJohn Marino 	  sources = src;
932*e4b17023SJohn Marino 	}
933*e4b17023SJohn Marino 
934*e4b17023SJohn Marino       idx = n_sources;
935*e4b17023SJohn Marino 
936*e4b17023SJohn Marino       name_map = &names[n_names++];
937*e4b17023SJohn Marino       name_map->name = canon;
938*e4b17023SJohn Marino       name_map->src = idx;
939*e4b17023SJohn Marino 
940*e4b17023SJohn Marino       src = &sources[n_sources++];
941*e4b17023SJohn Marino       memset (src, 0, sizeof (*src));
942*e4b17023SJohn Marino       src->name = canon;
943*e4b17023SJohn Marino       src->coverage.name = src->name;
944*e4b17023SJohn Marino       if (source_length
945*e4b17023SJohn Marino #if HAVE_DOS_BASED_FILE_SYSTEM
946*e4b17023SJohn Marino 	  /* You lose if separators don't match exactly in the
947*e4b17023SJohn Marino 	     prefix.  */
948*e4b17023SJohn Marino 	  && !strncasecmp (source_prefix, src->coverage.name, source_length)
949*e4b17023SJohn Marino #else
950*e4b17023SJohn Marino 	  && !strncmp (source_prefix, src->coverage.name, source_length)
951*e4b17023SJohn Marino #endif
952*e4b17023SJohn Marino 	  && IS_DIR_SEPARATOR (src->coverage.name[source_length]))
953*e4b17023SJohn Marino 	src->coverage.name += source_length + 1;
954*e4b17023SJohn Marino       if (!stat (src->name, &status))
955*e4b17023SJohn Marino 	src->file_time = status.st_mtime;
956*e4b17023SJohn Marino     }
957*e4b17023SJohn Marino   else
958*e4b17023SJohn Marino     idx = name_map->src;
959*e4b17023SJohn Marino 
960*e4b17023SJohn Marino   if (name_search (file_name, name_map))
961*e4b17023SJohn Marino     {
962*e4b17023SJohn Marino       /* Append the non-canonical name.  */
963*e4b17023SJohn Marino       name_map = &names[n_names++];
964*e4b17023SJohn Marino       name_map->name = xstrdup (file_name);
965*e4b17023SJohn Marino       name_map->src = idx;
966*e4b17023SJohn Marino     }
967*e4b17023SJohn Marino 
968*e4b17023SJohn Marino   /* Resort the name map.  */
969*e4b17023SJohn Marino   qsort (names, n_names, sizeof (*names), name_sort);
970*e4b17023SJohn Marino 
971*e4b17023SJohn Marino  check_date:
972*e4b17023SJohn Marino   if (sources[idx].file_time > bbg_file_time)
973*e4b17023SJohn Marino     {
974*e4b17023SJohn Marino       static int info_emitted;
975*e4b17023SJohn Marino 
976*e4b17023SJohn Marino       fnotice (stderr, "%s:source file is newer than graph file '%s'\n",
977*e4b17023SJohn Marino 	       file_name, bbg_file_name);
978*e4b17023SJohn Marino       if (!info_emitted)
979*e4b17023SJohn Marino 	{
980*e4b17023SJohn Marino 	  fnotice (stderr,
981*e4b17023SJohn Marino 		   "(the message is only displayed one per source file)\n");
982*e4b17023SJohn Marino 	  info_emitted = 1;
983*e4b17023SJohn Marino 	}
984*e4b17023SJohn Marino       sources[idx].file_time = 0;
985*e4b17023SJohn Marino     }
986*e4b17023SJohn Marino 
987*e4b17023SJohn Marino   return idx;
988*e4b17023SJohn Marino }
989*e4b17023SJohn Marino 
990*e4b17023SJohn Marino /* Read the graph file.  Return list of functions read -- in reverse order.  */
991*e4b17023SJohn Marino 
992*e4b17023SJohn Marino static function_t *
read_graph_file(void)993*e4b17023SJohn Marino read_graph_file (void)
994*e4b17023SJohn Marino {
995*e4b17023SJohn Marino   unsigned version;
996*e4b17023SJohn Marino   unsigned current_tag = 0;
997*e4b17023SJohn Marino   function_t *fn = NULL;
998*e4b17023SJohn Marino   function_t *fns = NULL;
999*e4b17023SJohn Marino   function_t **fns_end = &fns;
1000*e4b17023SJohn Marino   unsigned src_idx = 0;
1001*e4b17023SJohn Marino   unsigned ix;
1002*e4b17023SJohn Marino   unsigned tag;
1003*e4b17023SJohn Marino 
1004*e4b17023SJohn Marino   if (!gcov_open (bbg_file_name, 1))
1005*e4b17023SJohn Marino     {
1006*e4b17023SJohn Marino       fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
1007*e4b17023SJohn Marino       return fns;
1008*e4b17023SJohn Marino     }
1009*e4b17023SJohn Marino   bbg_file_time = gcov_time ();
1010*e4b17023SJohn Marino   if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
1011*e4b17023SJohn Marino     {
1012*e4b17023SJohn Marino       fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
1013*e4b17023SJohn Marino       gcov_close ();
1014*e4b17023SJohn Marino       return fns;
1015*e4b17023SJohn Marino     }
1016*e4b17023SJohn Marino 
1017*e4b17023SJohn Marino   version = gcov_read_unsigned ();
1018*e4b17023SJohn Marino   if (version != GCOV_VERSION)
1019*e4b17023SJohn Marino     {
1020*e4b17023SJohn Marino       char v[4], e[4];
1021*e4b17023SJohn Marino 
1022*e4b17023SJohn Marino       GCOV_UNSIGNED2STRING (v, version);
1023*e4b17023SJohn Marino       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1024*e4b17023SJohn Marino 
1025*e4b17023SJohn Marino       fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
1026*e4b17023SJohn Marino 	       bbg_file_name, v, e);
1027*e4b17023SJohn Marino     }
1028*e4b17023SJohn Marino   bbg_stamp = gcov_read_unsigned ();
1029*e4b17023SJohn Marino 
1030*e4b17023SJohn Marino   while ((tag = gcov_read_unsigned ()))
1031*e4b17023SJohn Marino     {
1032*e4b17023SJohn Marino       unsigned length = gcov_read_unsigned ();
1033*e4b17023SJohn Marino       gcov_position_t base = gcov_position ();
1034*e4b17023SJohn Marino 
1035*e4b17023SJohn Marino       if (tag == GCOV_TAG_FUNCTION)
1036*e4b17023SJohn Marino 	{
1037*e4b17023SJohn Marino 	  char *function_name;
1038*e4b17023SJohn Marino 	  unsigned ident, lineno;
1039*e4b17023SJohn Marino 	  unsigned lineno_checksum, cfg_checksum;
1040*e4b17023SJohn Marino 
1041*e4b17023SJohn Marino 	  ident = gcov_read_unsigned ();
1042*e4b17023SJohn Marino 	  lineno_checksum = gcov_read_unsigned ();
1043*e4b17023SJohn Marino 	  cfg_checksum = gcov_read_unsigned ();
1044*e4b17023SJohn Marino 	  function_name = xstrdup (gcov_read_string ());
1045*e4b17023SJohn Marino 	  src_idx = find_source (gcov_read_string ());
1046*e4b17023SJohn Marino 	  lineno = gcov_read_unsigned ();
1047*e4b17023SJohn Marino 
1048*e4b17023SJohn Marino 	  fn = XCNEW (function_t);
1049*e4b17023SJohn Marino 	  fn->name = function_name;
1050*e4b17023SJohn Marino 	  fn->ident = ident;
1051*e4b17023SJohn Marino 	  fn->lineno_checksum = lineno_checksum;
1052*e4b17023SJohn Marino 	  fn->cfg_checksum = cfg_checksum;
1053*e4b17023SJohn Marino 	  fn->src = src_idx;
1054*e4b17023SJohn Marino 	  fn->line = lineno;
1055*e4b17023SJohn Marino 
1056*e4b17023SJohn Marino 	  fn->line_next = NULL;
1057*e4b17023SJohn Marino 	  fn->next = NULL;
1058*e4b17023SJohn Marino 	  *fns_end = fn;
1059*e4b17023SJohn Marino 	  fns_end = &fn->next;
1060*e4b17023SJohn Marino 	  current_tag = tag;
1061*e4b17023SJohn Marino 	}
1062*e4b17023SJohn Marino       else if (fn && tag == GCOV_TAG_BLOCKS)
1063*e4b17023SJohn Marino 	{
1064*e4b17023SJohn Marino 	  if (fn->blocks)
1065*e4b17023SJohn Marino 	    fnotice (stderr, "%s:already seen blocks for '%s'\n",
1066*e4b17023SJohn Marino 		     bbg_file_name, fn->name);
1067*e4b17023SJohn Marino 	  else
1068*e4b17023SJohn Marino 	    {
1069*e4b17023SJohn Marino 	      unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
1070*e4b17023SJohn Marino 	      fn->num_blocks = num_blocks;
1071*e4b17023SJohn Marino 
1072*e4b17023SJohn Marino 	      fn->blocks = XCNEWVEC (block_t, fn->num_blocks);
1073*e4b17023SJohn Marino 	      for (ix = 0; ix != num_blocks; ix++)
1074*e4b17023SJohn Marino 		fn->blocks[ix].flags = gcov_read_unsigned ();
1075*e4b17023SJohn Marino 	    }
1076*e4b17023SJohn Marino 	}
1077*e4b17023SJohn Marino       else if (fn && tag == GCOV_TAG_ARCS)
1078*e4b17023SJohn Marino 	{
1079*e4b17023SJohn Marino 	  unsigned src = gcov_read_unsigned ();
1080*e4b17023SJohn Marino 	  unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
1081*e4b17023SJohn Marino 	  block_t *src_blk = &fn->blocks[src];
1082*e4b17023SJohn Marino 	  unsigned mark_catches = 0;
1083*e4b17023SJohn Marino 	  struct arc_info *arc;
1084*e4b17023SJohn Marino 
1085*e4b17023SJohn Marino 	  if (src >= fn->num_blocks || fn->blocks[src].succ)
1086*e4b17023SJohn Marino 	    goto corrupt;
1087*e4b17023SJohn Marino 
1088*e4b17023SJohn Marino 	  while (num_dests--)
1089*e4b17023SJohn Marino 	    {
1090*e4b17023SJohn Marino 	      unsigned dest = gcov_read_unsigned ();
1091*e4b17023SJohn Marino 	      unsigned flags = gcov_read_unsigned ();
1092*e4b17023SJohn Marino 
1093*e4b17023SJohn Marino 	      if (dest >= fn->num_blocks)
1094*e4b17023SJohn Marino 		goto corrupt;
1095*e4b17023SJohn Marino 	      arc = XCNEW (arc_t);
1096*e4b17023SJohn Marino 
1097*e4b17023SJohn Marino 	      arc->dst = &fn->blocks[dest];
1098*e4b17023SJohn Marino 	      arc->src = src_blk;
1099*e4b17023SJohn Marino 
1100*e4b17023SJohn Marino 	      arc->count = 0;
1101*e4b17023SJohn Marino 	      arc->count_valid = 0;
1102*e4b17023SJohn Marino 	      arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
1103*e4b17023SJohn Marino 	      arc->fake = !!(flags & GCOV_ARC_FAKE);
1104*e4b17023SJohn Marino 	      arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
1105*e4b17023SJohn Marino 
1106*e4b17023SJohn Marino 	      arc->succ_next = src_blk->succ;
1107*e4b17023SJohn Marino 	      src_blk->succ = arc;
1108*e4b17023SJohn Marino 	      src_blk->num_succ++;
1109*e4b17023SJohn Marino 
1110*e4b17023SJohn Marino 	      arc->pred_next = fn->blocks[dest].pred;
1111*e4b17023SJohn Marino 	      fn->blocks[dest].pred = arc;
1112*e4b17023SJohn Marino 	      fn->blocks[dest].num_pred++;
1113*e4b17023SJohn Marino 
1114*e4b17023SJohn Marino 	      if (arc->fake)
1115*e4b17023SJohn Marino 		{
1116*e4b17023SJohn Marino 		  if (src)
1117*e4b17023SJohn Marino 		    {
1118*e4b17023SJohn Marino 		      /* Exceptional exit from this function, the
1119*e4b17023SJohn Marino 			 source block must be a call.  */
1120*e4b17023SJohn Marino 		      fn->blocks[src].is_call_site = 1;
1121*e4b17023SJohn Marino 		      arc->is_call_non_return = 1;
1122*e4b17023SJohn Marino 		      mark_catches = 1;
1123*e4b17023SJohn Marino 		    }
1124*e4b17023SJohn Marino 		  else
1125*e4b17023SJohn Marino 		    {
1126*e4b17023SJohn Marino 		      /* Non-local return from a callee of this
1127*e4b17023SJohn Marino 		         function. The destination block is a setjmp.  */
1128*e4b17023SJohn Marino 		      arc->is_nonlocal_return = 1;
1129*e4b17023SJohn Marino 		      fn->blocks[dest].is_nonlocal_return = 1;
1130*e4b17023SJohn Marino 		    }
1131*e4b17023SJohn Marino 		}
1132*e4b17023SJohn Marino 
1133*e4b17023SJohn Marino 	      if (!arc->on_tree)
1134*e4b17023SJohn Marino 		fn->num_counts++;
1135*e4b17023SJohn Marino 	    }
1136*e4b17023SJohn Marino 
1137*e4b17023SJohn Marino 	  if (mark_catches)
1138*e4b17023SJohn Marino 	    {
1139*e4b17023SJohn Marino 	      /* We have a fake exit from this block.  The other
1140*e4b17023SJohn Marino 		 non-fall through exits must be to catch handlers.
1141*e4b17023SJohn Marino 		 Mark them as catch arcs.  */
1142*e4b17023SJohn Marino 
1143*e4b17023SJohn Marino 	      for (arc = src_blk->succ; arc; arc = arc->succ_next)
1144*e4b17023SJohn Marino 		if (!arc->fake && !arc->fall_through)
1145*e4b17023SJohn Marino 		  {
1146*e4b17023SJohn Marino 		    arc->is_throw = 1;
1147*e4b17023SJohn Marino 		    fn->has_catch = 1;
1148*e4b17023SJohn Marino 		  }
1149*e4b17023SJohn Marino 	    }
1150*e4b17023SJohn Marino 	}
1151*e4b17023SJohn Marino       else if (fn && tag == GCOV_TAG_LINES)
1152*e4b17023SJohn Marino 	{
1153*e4b17023SJohn Marino 	  unsigned blockno = gcov_read_unsigned ();
1154*e4b17023SJohn Marino 	  unsigned *line_nos = XCNEWVEC (unsigned, length - 1);
1155*e4b17023SJohn Marino 
1156*e4b17023SJohn Marino 	  if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
1157*e4b17023SJohn Marino 	    goto corrupt;
1158*e4b17023SJohn Marino 
1159*e4b17023SJohn Marino 	  for (ix = 0; ;  )
1160*e4b17023SJohn Marino 	    {
1161*e4b17023SJohn Marino 	      unsigned lineno = gcov_read_unsigned ();
1162*e4b17023SJohn Marino 
1163*e4b17023SJohn Marino 	      if (lineno)
1164*e4b17023SJohn Marino 		{
1165*e4b17023SJohn Marino 		  if (!ix)
1166*e4b17023SJohn Marino 		    {
1167*e4b17023SJohn Marino 		      line_nos[ix++] = 0;
1168*e4b17023SJohn Marino 		      line_nos[ix++] = src_idx;
1169*e4b17023SJohn Marino 		    }
1170*e4b17023SJohn Marino 		  line_nos[ix++] = lineno;
1171*e4b17023SJohn Marino 		}
1172*e4b17023SJohn Marino 	      else
1173*e4b17023SJohn Marino 		{
1174*e4b17023SJohn Marino 		  const char *file_name = gcov_read_string ();
1175*e4b17023SJohn Marino 
1176*e4b17023SJohn Marino 		  if (!file_name)
1177*e4b17023SJohn Marino 		    break;
1178*e4b17023SJohn Marino 		  src_idx = find_source (file_name);
1179*e4b17023SJohn Marino 		  line_nos[ix++] = 0;
1180*e4b17023SJohn Marino 		  line_nos[ix++] = src_idx;
1181*e4b17023SJohn Marino 		}
1182*e4b17023SJohn Marino 	    }
1183*e4b17023SJohn Marino 
1184*e4b17023SJohn Marino 	  fn->blocks[blockno].u.line.encoding = line_nos;
1185*e4b17023SJohn Marino 	  fn->blocks[blockno].u.line.num = ix;
1186*e4b17023SJohn Marino 	}
1187*e4b17023SJohn Marino       else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
1188*e4b17023SJohn Marino 	{
1189*e4b17023SJohn Marino 	  fn = NULL;
1190*e4b17023SJohn Marino 	  current_tag = 0;
1191*e4b17023SJohn Marino 	}
1192*e4b17023SJohn Marino       gcov_sync (base, length);
1193*e4b17023SJohn Marino       if (gcov_is_error ())
1194*e4b17023SJohn Marino 	{
1195*e4b17023SJohn Marino 	corrupt:;
1196*e4b17023SJohn Marino 	  fnotice (stderr, "%s:corrupted\n", bbg_file_name);
1197*e4b17023SJohn Marino 	  break;
1198*e4b17023SJohn Marino 	}
1199*e4b17023SJohn Marino     }
1200*e4b17023SJohn Marino   gcov_close ();
1201*e4b17023SJohn Marino 
1202*e4b17023SJohn Marino   if (!fns)
1203*e4b17023SJohn Marino     fnotice (stderr, "%s:no functions found\n", bbg_file_name);
1204*e4b17023SJohn Marino 
1205*e4b17023SJohn Marino   return fns;
1206*e4b17023SJohn Marino }
1207*e4b17023SJohn Marino 
1208*e4b17023SJohn Marino /* Reads profiles from the count file and attach to each
1209*e4b17023SJohn Marino    function. Return nonzero if fatal error.  */
1210*e4b17023SJohn Marino 
1211*e4b17023SJohn Marino static int
read_count_file(function_t * fns)1212*e4b17023SJohn Marino read_count_file (function_t *fns)
1213*e4b17023SJohn Marino {
1214*e4b17023SJohn Marino   unsigned ix;
1215*e4b17023SJohn Marino   unsigned version;
1216*e4b17023SJohn Marino   unsigned tag;
1217*e4b17023SJohn Marino   function_t *fn = NULL;
1218*e4b17023SJohn Marino   int error = 0;
1219*e4b17023SJohn Marino 
1220*e4b17023SJohn Marino   if (!gcov_open (da_file_name, 1))
1221*e4b17023SJohn Marino     {
1222*e4b17023SJohn Marino       fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
1223*e4b17023SJohn Marino 	       da_file_name);
1224*e4b17023SJohn Marino       no_data_file = 1;
1225*e4b17023SJohn Marino       return 0;
1226*e4b17023SJohn Marino     }
1227*e4b17023SJohn Marino   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
1228*e4b17023SJohn Marino     {
1229*e4b17023SJohn Marino       fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
1230*e4b17023SJohn Marino     cleanup:;
1231*e4b17023SJohn Marino       gcov_close ();
1232*e4b17023SJohn Marino       return 1;
1233*e4b17023SJohn Marino     }
1234*e4b17023SJohn Marino   version = gcov_read_unsigned ();
1235*e4b17023SJohn Marino   if (version != GCOV_VERSION)
1236*e4b17023SJohn Marino     {
1237*e4b17023SJohn Marino       char v[4], e[4];
1238*e4b17023SJohn Marino 
1239*e4b17023SJohn Marino       GCOV_UNSIGNED2STRING (v, version);
1240*e4b17023SJohn Marino       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
1241*e4b17023SJohn Marino 
1242*e4b17023SJohn Marino       fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
1243*e4b17023SJohn Marino 	       da_file_name, v, e);
1244*e4b17023SJohn Marino     }
1245*e4b17023SJohn Marino   tag = gcov_read_unsigned ();
1246*e4b17023SJohn Marino   if (tag != bbg_stamp)
1247*e4b17023SJohn Marino     {
1248*e4b17023SJohn Marino       fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
1249*e4b17023SJohn Marino       goto cleanup;
1250*e4b17023SJohn Marino     }
1251*e4b17023SJohn Marino 
1252*e4b17023SJohn Marino   while ((tag = gcov_read_unsigned ()))
1253*e4b17023SJohn Marino     {
1254*e4b17023SJohn Marino       unsigned length = gcov_read_unsigned ();
1255*e4b17023SJohn Marino       unsigned long base = gcov_position ();
1256*e4b17023SJohn Marino 
1257*e4b17023SJohn Marino       if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1258*e4b17023SJohn Marino 	{
1259*e4b17023SJohn Marino 	  struct gcov_summary summary;
1260*e4b17023SJohn Marino 	  gcov_read_summary (&summary);
1261*e4b17023SJohn Marino 	  object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs;
1262*e4b17023SJohn Marino 	  program_count++;
1263*e4b17023SJohn Marino 	}
1264*e4b17023SJohn Marino       else if (tag == GCOV_TAG_FUNCTION && !length)
1265*e4b17023SJohn Marino 	; /* placeholder  */
1266*e4b17023SJohn Marino       else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
1267*e4b17023SJohn Marino 	{
1268*e4b17023SJohn Marino 	  unsigned ident;
1269*e4b17023SJohn Marino 	  struct function_info *fn_n;
1270*e4b17023SJohn Marino 
1271*e4b17023SJohn Marino 	  /* Try to find the function in the list.  To speed up the
1272*e4b17023SJohn Marino 	     search, first start from the last function found.  */
1273*e4b17023SJohn Marino 	  ident = gcov_read_unsigned ();
1274*e4b17023SJohn Marino 	  fn_n = fns;
1275*e4b17023SJohn Marino 	  for (fn = fn ? fn->next : NULL; ; fn = fn->next)
1276*e4b17023SJohn Marino 	    {
1277*e4b17023SJohn Marino 	      if (fn)
1278*e4b17023SJohn Marino 		;
1279*e4b17023SJohn Marino 	      else if ((fn = fn_n))
1280*e4b17023SJohn Marino 		fn_n = NULL;
1281*e4b17023SJohn Marino 	      else
1282*e4b17023SJohn Marino 		{
1283*e4b17023SJohn Marino 		  fnotice (stderr, "%s:unknown function '%u'\n",
1284*e4b17023SJohn Marino 			   da_file_name, ident);
1285*e4b17023SJohn Marino 		  break;
1286*e4b17023SJohn Marino 		}
1287*e4b17023SJohn Marino 	      if (fn->ident == ident)
1288*e4b17023SJohn Marino 		break;
1289*e4b17023SJohn Marino 	    }
1290*e4b17023SJohn Marino 
1291*e4b17023SJohn Marino 	  if (!fn)
1292*e4b17023SJohn Marino 	    ;
1293*e4b17023SJohn Marino 	  else if (gcov_read_unsigned () != fn->lineno_checksum
1294*e4b17023SJohn Marino 		   || gcov_read_unsigned () != fn->cfg_checksum)
1295*e4b17023SJohn Marino 	    {
1296*e4b17023SJohn Marino 	    mismatch:;
1297*e4b17023SJohn Marino 	      fnotice (stderr, "%s:profile mismatch for '%s'\n",
1298*e4b17023SJohn Marino 		       da_file_name, fn->name);
1299*e4b17023SJohn Marino 	      goto cleanup;
1300*e4b17023SJohn Marino 	    }
1301*e4b17023SJohn Marino 	}
1302*e4b17023SJohn Marino       else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1303*e4b17023SJohn Marino 	{
1304*e4b17023SJohn Marino 	  if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
1305*e4b17023SJohn Marino 	    goto mismatch;
1306*e4b17023SJohn Marino 
1307*e4b17023SJohn Marino 	  if (!fn->counts)
1308*e4b17023SJohn Marino 	    fn->counts = XCNEWVEC (gcov_type, fn->num_counts);
1309*e4b17023SJohn Marino 
1310*e4b17023SJohn Marino 	  for (ix = 0; ix != fn->num_counts; ix++)
1311*e4b17023SJohn Marino 	    fn->counts[ix] += gcov_read_counter ();
1312*e4b17023SJohn Marino 	}
1313*e4b17023SJohn Marino       gcov_sync (base, length);
1314*e4b17023SJohn Marino       if ((error = gcov_is_error ()))
1315*e4b17023SJohn Marino 	{
1316*e4b17023SJohn Marino 	  fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1317*e4b17023SJohn Marino 		   da_file_name);
1318*e4b17023SJohn Marino 	  goto cleanup;
1319*e4b17023SJohn Marino 	}
1320*e4b17023SJohn Marino     }
1321*e4b17023SJohn Marino 
1322*e4b17023SJohn Marino   gcov_close ();
1323*e4b17023SJohn Marino   return 0;
1324*e4b17023SJohn Marino }
1325*e4b17023SJohn Marino 
1326*e4b17023SJohn Marino /* Solve the flow graph. Propagate counts from the instrumented arcs
1327*e4b17023SJohn Marino    to the blocks and the uninstrumented arcs.  */
1328*e4b17023SJohn Marino 
1329*e4b17023SJohn Marino static void
solve_flow_graph(function_t * fn)1330*e4b17023SJohn Marino solve_flow_graph (function_t *fn)
1331*e4b17023SJohn Marino {
1332*e4b17023SJohn Marino   unsigned ix;
1333*e4b17023SJohn Marino   arc_t *arc;
1334*e4b17023SJohn Marino   gcov_type *count_ptr = fn->counts;
1335*e4b17023SJohn Marino   block_t *blk;
1336*e4b17023SJohn Marino   block_t *valid_blocks = NULL;    /* valid, but unpropagated blocks.  */
1337*e4b17023SJohn Marino   block_t *invalid_blocks = NULL;  /* invalid, but inferable blocks.  */
1338*e4b17023SJohn Marino 
1339*e4b17023SJohn Marino   /* The arcs were built in reverse order.  Fix that now.  */
1340*e4b17023SJohn Marino   for (ix = fn->num_blocks; ix--;)
1341*e4b17023SJohn Marino     {
1342*e4b17023SJohn Marino       arc_t *arc_p, *arc_n;
1343*e4b17023SJohn Marino 
1344*e4b17023SJohn Marino       for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
1345*e4b17023SJohn Marino 	   arc_p = arc, arc = arc_n)
1346*e4b17023SJohn Marino 	{
1347*e4b17023SJohn Marino 	  arc_n = arc->succ_next;
1348*e4b17023SJohn Marino 	  arc->succ_next = arc_p;
1349*e4b17023SJohn Marino 	}
1350*e4b17023SJohn Marino       fn->blocks[ix].succ = arc_p;
1351*e4b17023SJohn Marino 
1352*e4b17023SJohn Marino       for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
1353*e4b17023SJohn Marino 	   arc_p = arc, arc = arc_n)
1354*e4b17023SJohn Marino 	{
1355*e4b17023SJohn Marino 	  arc_n = arc->pred_next;
1356*e4b17023SJohn Marino 	  arc->pred_next = arc_p;
1357*e4b17023SJohn Marino 	}
1358*e4b17023SJohn Marino       fn->blocks[ix].pred = arc_p;
1359*e4b17023SJohn Marino     }
1360*e4b17023SJohn Marino 
1361*e4b17023SJohn Marino   if (fn->num_blocks < 2)
1362*e4b17023SJohn Marino     fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
1363*e4b17023SJohn Marino 	     bbg_file_name, fn->name);
1364*e4b17023SJohn Marino   else
1365*e4b17023SJohn Marino     {
1366*e4b17023SJohn Marino       if (fn->blocks[0].num_pred)
1367*e4b17023SJohn Marino 	fnotice (stderr, "%s:'%s' has arcs to entry block\n",
1368*e4b17023SJohn Marino 		 bbg_file_name, fn->name);
1369*e4b17023SJohn Marino       else
1370*e4b17023SJohn Marino 	/* We can't deduce the entry block counts from the lack of
1371*e4b17023SJohn Marino 	   predecessors.  */
1372*e4b17023SJohn Marino 	fn->blocks[0].num_pred = ~(unsigned)0;
1373*e4b17023SJohn Marino 
1374*e4b17023SJohn Marino       if (fn->blocks[fn->num_blocks - 1].num_succ)
1375*e4b17023SJohn Marino 	fnotice (stderr, "%s:'%s' has arcs from exit block\n",
1376*e4b17023SJohn Marino 		 bbg_file_name, fn->name);
1377*e4b17023SJohn Marino       else
1378*e4b17023SJohn Marino 	/* Likewise, we can't deduce exit block counts from the lack
1379*e4b17023SJohn Marino 	   of its successors.  */
1380*e4b17023SJohn Marino 	fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0;
1381*e4b17023SJohn Marino     }
1382*e4b17023SJohn Marino 
1383*e4b17023SJohn Marino   /* Propagate the measured counts, this must be done in the same
1384*e4b17023SJohn Marino      order as the code in profile.c  */
1385*e4b17023SJohn Marino   for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
1386*e4b17023SJohn Marino     {
1387*e4b17023SJohn Marino       block_t const *prev_dst = NULL;
1388*e4b17023SJohn Marino       int out_of_order = 0;
1389*e4b17023SJohn Marino       int non_fake_succ = 0;
1390*e4b17023SJohn Marino 
1391*e4b17023SJohn Marino       for (arc = blk->succ; arc; arc = arc->succ_next)
1392*e4b17023SJohn Marino 	{
1393*e4b17023SJohn Marino 	  if (!arc->fake)
1394*e4b17023SJohn Marino 	    non_fake_succ++;
1395*e4b17023SJohn Marino 
1396*e4b17023SJohn Marino 	  if (!arc->on_tree)
1397*e4b17023SJohn Marino 	    {
1398*e4b17023SJohn Marino 	      if (count_ptr)
1399*e4b17023SJohn Marino 		arc->count = *count_ptr++;
1400*e4b17023SJohn Marino 	      arc->count_valid = 1;
1401*e4b17023SJohn Marino 	      blk->num_succ--;
1402*e4b17023SJohn Marino 	      arc->dst->num_pred--;
1403*e4b17023SJohn Marino 	    }
1404*e4b17023SJohn Marino 	  if (prev_dst && prev_dst > arc->dst)
1405*e4b17023SJohn Marino 	    out_of_order = 1;
1406*e4b17023SJohn Marino 	  prev_dst = arc->dst;
1407*e4b17023SJohn Marino 	}
1408*e4b17023SJohn Marino       if (non_fake_succ == 1)
1409*e4b17023SJohn Marino 	{
1410*e4b17023SJohn Marino 	  /* If there is only one non-fake exit, it is an
1411*e4b17023SJohn Marino 	     unconditional branch.  */
1412*e4b17023SJohn Marino 	  for (arc = blk->succ; arc; arc = arc->succ_next)
1413*e4b17023SJohn Marino 	    if (!arc->fake)
1414*e4b17023SJohn Marino 	      {
1415*e4b17023SJohn Marino 		arc->is_unconditional = 1;
1416*e4b17023SJohn Marino 		/* If this block is instrumenting a call, it might be
1417*e4b17023SJohn Marino 		   an artificial block. It is not artificial if it has
1418*e4b17023SJohn Marino 		   a non-fallthrough exit, or the destination of this
1419*e4b17023SJohn Marino 		   arc has more than one entry.  Mark the destination
1420*e4b17023SJohn Marino 		   block as a return site, if none of those conditions
1421*e4b17023SJohn Marino 		   hold.  */
1422*e4b17023SJohn Marino 		if (blk->is_call_site && arc->fall_through
1423*e4b17023SJohn Marino 		    && arc->dst->pred == arc && !arc->pred_next)
1424*e4b17023SJohn Marino 		  arc->dst->is_call_return = 1;
1425*e4b17023SJohn Marino 	      }
1426*e4b17023SJohn Marino 	}
1427*e4b17023SJohn Marino 
1428*e4b17023SJohn Marino       /* Sort the successor arcs into ascending dst order. profile.c
1429*e4b17023SJohn Marino 	 normally produces arcs in the right order, but sometimes with
1430*e4b17023SJohn Marino 	 one or two out of order.  We're not using a particularly
1431*e4b17023SJohn Marino 	 smart sort.  */
1432*e4b17023SJohn Marino       if (out_of_order)
1433*e4b17023SJohn Marino 	{
1434*e4b17023SJohn Marino 	  arc_t *start = blk->succ;
1435*e4b17023SJohn Marino 	  unsigned changes = 1;
1436*e4b17023SJohn Marino 
1437*e4b17023SJohn Marino 	  while (changes)
1438*e4b17023SJohn Marino 	    {
1439*e4b17023SJohn Marino 	      arc_t *arc, *arc_p, *arc_n;
1440*e4b17023SJohn Marino 
1441*e4b17023SJohn Marino 	      changes = 0;
1442*e4b17023SJohn Marino 	      for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1443*e4b17023SJohn Marino 		{
1444*e4b17023SJohn Marino 		  if (arc->dst > arc_n->dst)
1445*e4b17023SJohn Marino 		    {
1446*e4b17023SJohn Marino 		      changes = 1;
1447*e4b17023SJohn Marino 		      if (arc_p)
1448*e4b17023SJohn Marino 			arc_p->succ_next = arc_n;
1449*e4b17023SJohn Marino 		      else
1450*e4b17023SJohn Marino 			start = arc_n;
1451*e4b17023SJohn Marino 		      arc->succ_next = arc_n->succ_next;
1452*e4b17023SJohn Marino 		      arc_n->succ_next = arc;
1453*e4b17023SJohn Marino 		      arc_p = arc_n;
1454*e4b17023SJohn Marino 		    }
1455*e4b17023SJohn Marino 		  else
1456*e4b17023SJohn Marino 		    {
1457*e4b17023SJohn Marino 		      arc_p = arc;
1458*e4b17023SJohn Marino 		      arc = arc_n;
1459*e4b17023SJohn Marino 		    }
1460*e4b17023SJohn Marino 		}
1461*e4b17023SJohn Marino 	    }
1462*e4b17023SJohn Marino 	  blk->succ = start;
1463*e4b17023SJohn Marino 	}
1464*e4b17023SJohn Marino 
1465*e4b17023SJohn Marino       /* Place it on the invalid chain, it will be ignored if that's
1466*e4b17023SJohn Marino 	 wrong.  */
1467*e4b17023SJohn Marino       blk->invalid_chain = 1;
1468*e4b17023SJohn Marino       blk->chain = invalid_blocks;
1469*e4b17023SJohn Marino       invalid_blocks = blk;
1470*e4b17023SJohn Marino     }
1471*e4b17023SJohn Marino 
1472*e4b17023SJohn Marino   while (invalid_blocks || valid_blocks)
1473*e4b17023SJohn Marino     {
1474*e4b17023SJohn Marino       while ((blk = invalid_blocks))
1475*e4b17023SJohn Marino 	{
1476*e4b17023SJohn Marino 	  gcov_type total = 0;
1477*e4b17023SJohn Marino 	  const arc_t *arc;
1478*e4b17023SJohn Marino 
1479*e4b17023SJohn Marino 	  invalid_blocks = blk->chain;
1480*e4b17023SJohn Marino 	  blk->invalid_chain = 0;
1481*e4b17023SJohn Marino 	  if (!blk->num_succ)
1482*e4b17023SJohn Marino 	    for (arc = blk->succ; arc; arc = arc->succ_next)
1483*e4b17023SJohn Marino 	      total += arc->count;
1484*e4b17023SJohn Marino 	  else if (!blk->num_pred)
1485*e4b17023SJohn Marino 	    for (arc = blk->pred; arc; arc = arc->pred_next)
1486*e4b17023SJohn Marino 	      total += arc->count;
1487*e4b17023SJohn Marino 	  else
1488*e4b17023SJohn Marino 	    continue;
1489*e4b17023SJohn Marino 
1490*e4b17023SJohn Marino 	  blk->count = total;
1491*e4b17023SJohn Marino 	  blk->count_valid = 1;
1492*e4b17023SJohn Marino 	  blk->chain = valid_blocks;
1493*e4b17023SJohn Marino 	  blk->valid_chain = 1;
1494*e4b17023SJohn Marino 	  valid_blocks = blk;
1495*e4b17023SJohn Marino 	}
1496*e4b17023SJohn Marino       while ((blk = valid_blocks))
1497*e4b17023SJohn Marino 	{
1498*e4b17023SJohn Marino 	  gcov_type total;
1499*e4b17023SJohn Marino 	  arc_t *arc, *inv_arc;
1500*e4b17023SJohn Marino 
1501*e4b17023SJohn Marino 	  valid_blocks = blk->chain;
1502*e4b17023SJohn Marino 	  blk->valid_chain = 0;
1503*e4b17023SJohn Marino 	  if (blk->num_succ == 1)
1504*e4b17023SJohn Marino 	    {
1505*e4b17023SJohn Marino 	      block_t *dst;
1506*e4b17023SJohn Marino 
1507*e4b17023SJohn Marino 	      total = blk->count;
1508*e4b17023SJohn Marino 	      inv_arc = NULL;
1509*e4b17023SJohn Marino 	      for (arc = blk->succ; arc; arc = arc->succ_next)
1510*e4b17023SJohn Marino 		{
1511*e4b17023SJohn Marino 		  total -= arc->count;
1512*e4b17023SJohn Marino 		  if (!arc->count_valid)
1513*e4b17023SJohn Marino 		    inv_arc = arc;
1514*e4b17023SJohn Marino 		}
1515*e4b17023SJohn Marino 	      dst = inv_arc->dst;
1516*e4b17023SJohn Marino 	      inv_arc->count_valid = 1;
1517*e4b17023SJohn Marino 	      inv_arc->count = total;
1518*e4b17023SJohn Marino 	      blk->num_succ--;
1519*e4b17023SJohn Marino 	      dst->num_pred--;
1520*e4b17023SJohn Marino 	      if (dst->count_valid)
1521*e4b17023SJohn Marino 		{
1522*e4b17023SJohn Marino 		  if (dst->num_pred == 1 && !dst->valid_chain)
1523*e4b17023SJohn Marino 		    {
1524*e4b17023SJohn Marino 		      dst->chain = valid_blocks;
1525*e4b17023SJohn Marino 		      dst->valid_chain = 1;
1526*e4b17023SJohn Marino 		      valid_blocks = dst;
1527*e4b17023SJohn Marino 		    }
1528*e4b17023SJohn Marino 		}
1529*e4b17023SJohn Marino 	      else
1530*e4b17023SJohn Marino 		{
1531*e4b17023SJohn Marino 		  if (!dst->num_pred && !dst->invalid_chain)
1532*e4b17023SJohn Marino 		    {
1533*e4b17023SJohn Marino 		      dst->chain = invalid_blocks;
1534*e4b17023SJohn Marino 		      dst->invalid_chain = 1;
1535*e4b17023SJohn Marino 		      invalid_blocks = dst;
1536*e4b17023SJohn Marino 		    }
1537*e4b17023SJohn Marino 		}
1538*e4b17023SJohn Marino 	    }
1539*e4b17023SJohn Marino 	  if (blk->num_pred == 1)
1540*e4b17023SJohn Marino 	    {
1541*e4b17023SJohn Marino 	      block_t *src;
1542*e4b17023SJohn Marino 
1543*e4b17023SJohn Marino 	      total = blk->count;
1544*e4b17023SJohn Marino 	      inv_arc = NULL;
1545*e4b17023SJohn Marino 	      for (arc = blk->pred; arc; arc = arc->pred_next)
1546*e4b17023SJohn Marino 		{
1547*e4b17023SJohn Marino 		  total -= arc->count;
1548*e4b17023SJohn Marino 		  if (!arc->count_valid)
1549*e4b17023SJohn Marino 		    inv_arc = arc;
1550*e4b17023SJohn Marino 		}
1551*e4b17023SJohn Marino 	      src = inv_arc->src;
1552*e4b17023SJohn Marino 	      inv_arc->count_valid = 1;
1553*e4b17023SJohn Marino 	      inv_arc->count = total;
1554*e4b17023SJohn Marino 	      blk->num_pred--;
1555*e4b17023SJohn Marino 	      src->num_succ--;
1556*e4b17023SJohn Marino 	      if (src->count_valid)
1557*e4b17023SJohn Marino 		{
1558*e4b17023SJohn Marino 		  if (src->num_succ == 1 && !src->valid_chain)
1559*e4b17023SJohn Marino 		    {
1560*e4b17023SJohn Marino 		      src->chain = valid_blocks;
1561*e4b17023SJohn Marino 		      src->valid_chain = 1;
1562*e4b17023SJohn Marino 		      valid_blocks = src;
1563*e4b17023SJohn Marino 		    }
1564*e4b17023SJohn Marino 		}
1565*e4b17023SJohn Marino 	      else
1566*e4b17023SJohn Marino 		{
1567*e4b17023SJohn Marino 		  if (!src->num_succ && !src->invalid_chain)
1568*e4b17023SJohn Marino 		    {
1569*e4b17023SJohn Marino 		      src->chain = invalid_blocks;
1570*e4b17023SJohn Marino 		      src->invalid_chain = 1;
1571*e4b17023SJohn Marino 		      invalid_blocks = src;
1572*e4b17023SJohn Marino 		    }
1573*e4b17023SJohn Marino 		}
1574*e4b17023SJohn Marino 	    }
1575*e4b17023SJohn Marino 	}
1576*e4b17023SJohn Marino     }
1577*e4b17023SJohn Marino 
1578*e4b17023SJohn Marino   /* If the graph has been correctly solved, every block will have a
1579*e4b17023SJohn Marino      valid count.  */
1580*e4b17023SJohn Marino   for (ix = 0; ix < fn->num_blocks; ix++)
1581*e4b17023SJohn Marino     if (!fn->blocks[ix].count_valid)
1582*e4b17023SJohn Marino       {
1583*e4b17023SJohn Marino 	fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
1584*e4b17023SJohn Marino 		 bbg_file_name, fn->name);
1585*e4b17023SJohn Marino 	break;
1586*e4b17023SJohn Marino       }
1587*e4b17023SJohn Marino }
1588*e4b17023SJohn Marino 
1589*e4b17023SJohn Marino /* Mark all the blocks only reachable via an incoming catch.  */
1590*e4b17023SJohn Marino 
1591*e4b17023SJohn Marino static void
find_exception_blocks(function_t * fn)1592*e4b17023SJohn Marino find_exception_blocks (function_t *fn)
1593*e4b17023SJohn Marino {
1594*e4b17023SJohn Marino   unsigned ix;
1595*e4b17023SJohn Marino   block_t **queue = XALLOCAVEC (block_t *, fn->num_blocks);
1596*e4b17023SJohn Marino 
1597*e4b17023SJohn Marino   /* First mark all blocks as exceptional.  */
1598*e4b17023SJohn Marino   for (ix = fn->num_blocks; ix--;)
1599*e4b17023SJohn Marino     fn->blocks[ix].exceptional = 1;
1600*e4b17023SJohn Marino 
1601*e4b17023SJohn Marino   /* Now mark all the blocks reachable via non-fake edges */
1602*e4b17023SJohn Marino   queue[0] = fn->blocks;
1603*e4b17023SJohn Marino   queue[0]->exceptional = 0;
1604*e4b17023SJohn Marino   for (ix = 1; ix;)
1605*e4b17023SJohn Marino     {
1606*e4b17023SJohn Marino       block_t *block = queue[--ix];
1607*e4b17023SJohn Marino       const arc_t *arc;
1608*e4b17023SJohn Marino 
1609*e4b17023SJohn Marino       for (arc = block->succ; arc; arc = arc->succ_next)
1610*e4b17023SJohn Marino 	if (!arc->fake && !arc->is_throw && arc->dst->exceptional)
1611*e4b17023SJohn Marino 	  {
1612*e4b17023SJohn Marino 	    arc->dst->exceptional = 0;
1613*e4b17023SJohn Marino 	    queue[ix++] = arc->dst;
1614*e4b17023SJohn Marino 	  }
1615*e4b17023SJohn Marino     }
1616*e4b17023SJohn Marino }
1617*e4b17023SJohn Marino 
1618*e4b17023SJohn Marino 
1619*e4b17023SJohn Marino /* Increment totals in COVERAGE according to arc ARC.  */
1620*e4b17023SJohn Marino 
1621*e4b17023SJohn Marino static void
add_branch_counts(coverage_t * coverage,const arc_t * arc)1622*e4b17023SJohn Marino add_branch_counts (coverage_t *coverage, const arc_t *arc)
1623*e4b17023SJohn Marino {
1624*e4b17023SJohn Marino   if (arc->is_call_non_return)
1625*e4b17023SJohn Marino     {
1626*e4b17023SJohn Marino       coverage->calls++;
1627*e4b17023SJohn Marino       if (arc->src->count)
1628*e4b17023SJohn Marino 	coverage->calls_executed++;
1629*e4b17023SJohn Marino     }
1630*e4b17023SJohn Marino   else if (!arc->is_unconditional)
1631*e4b17023SJohn Marino     {
1632*e4b17023SJohn Marino       coverage->branches++;
1633*e4b17023SJohn Marino       if (arc->src->count)
1634*e4b17023SJohn Marino 	coverage->branches_executed++;
1635*e4b17023SJohn Marino       if (arc->count)
1636*e4b17023SJohn Marino 	coverage->branches_taken++;
1637*e4b17023SJohn Marino     }
1638*e4b17023SJohn Marino }
1639*e4b17023SJohn Marino 
1640*e4b17023SJohn Marino /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1641*e4b17023SJohn Marino    count.  If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1642*e4b17023SJohn Marino    If DP is zero, no decimal point is printed. Only print 100% when
1643*e4b17023SJohn Marino    TOP==BOTTOM and only print 0% when TOP=0.  If dp < 0, then simply
1644*e4b17023SJohn Marino    format TOP.  Return pointer to a static string.  */
1645*e4b17023SJohn Marino 
1646*e4b17023SJohn Marino static char const *
format_gcov(gcov_type top,gcov_type bottom,int dp)1647*e4b17023SJohn Marino format_gcov (gcov_type top, gcov_type bottom, int dp)
1648*e4b17023SJohn Marino {
1649*e4b17023SJohn Marino   static char buffer[20];
1650*e4b17023SJohn Marino 
1651*e4b17023SJohn Marino   if (dp >= 0)
1652*e4b17023SJohn Marino     {
1653*e4b17023SJohn Marino       float ratio = bottom ? (float)top / bottom : 0;
1654*e4b17023SJohn Marino       int ix;
1655*e4b17023SJohn Marino       unsigned limit = 100;
1656*e4b17023SJohn Marino       unsigned percent;
1657*e4b17023SJohn Marino 
1658*e4b17023SJohn Marino       for (ix = dp; ix--; )
1659*e4b17023SJohn Marino 	limit *= 10;
1660*e4b17023SJohn Marino 
1661*e4b17023SJohn Marino       percent = (unsigned) (ratio * limit + (float)0.5);
1662*e4b17023SJohn Marino       if (percent <= 0 && top)
1663*e4b17023SJohn Marino 	percent = 1;
1664*e4b17023SJohn Marino       else if (percent >= limit && top != bottom)
1665*e4b17023SJohn Marino 	percent = limit - 1;
1666*e4b17023SJohn Marino       ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1667*e4b17023SJohn Marino       if (dp)
1668*e4b17023SJohn Marino 	{
1669*e4b17023SJohn Marino 	  dp++;
1670*e4b17023SJohn Marino 	  do
1671*e4b17023SJohn Marino 	    {
1672*e4b17023SJohn Marino 	      buffer[ix+1] = buffer[ix];
1673*e4b17023SJohn Marino 	      ix--;
1674*e4b17023SJohn Marino 	    }
1675*e4b17023SJohn Marino 	  while (dp--);
1676*e4b17023SJohn Marino 	  buffer[ix + 1] = '.';
1677*e4b17023SJohn Marino 	}
1678*e4b17023SJohn Marino     }
1679*e4b17023SJohn Marino   else
1680*e4b17023SJohn Marino     sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
1681*e4b17023SJohn Marino 
1682*e4b17023SJohn Marino   return buffer;
1683*e4b17023SJohn Marino }
1684*e4b17023SJohn Marino 
1685*e4b17023SJohn Marino /* Summary of execution */
1686*e4b17023SJohn Marino 
1687*e4b17023SJohn Marino static void
executed_summary(unsigned lines,unsigned executed)1688*e4b17023SJohn Marino executed_summary (unsigned lines, unsigned executed)
1689*e4b17023SJohn Marino {
1690*e4b17023SJohn Marino   if (lines)
1691*e4b17023SJohn Marino     fnotice (stdout, "Lines executed:%s of %d\n",
1692*e4b17023SJohn Marino 	     format_gcov (executed, lines, 2), lines);
1693*e4b17023SJohn Marino   else
1694*e4b17023SJohn Marino     fnotice (stdout, "No executable lines\n");
1695*e4b17023SJohn Marino }
1696*e4b17023SJohn Marino 
1697*e4b17023SJohn Marino /* Output summary info for a function or file.  */
1698*e4b17023SJohn Marino 
1699*e4b17023SJohn Marino static void
function_summary(const coverage_t * coverage,const char * title)1700*e4b17023SJohn Marino function_summary (const coverage_t *coverage, const char *title)
1701*e4b17023SJohn Marino {
1702*e4b17023SJohn Marino   fnotice (stdout, "%s '%s'\n", title, coverage->name);
1703*e4b17023SJohn Marino   executed_summary (coverage->lines, coverage->lines_executed);
1704*e4b17023SJohn Marino 
1705*e4b17023SJohn Marino   if (flag_branches)
1706*e4b17023SJohn Marino     {
1707*e4b17023SJohn Marino       if (coverage->branches)
1708*e4b17023SJohn Marino 	{
1709*e4b17023SJohn Marino 	  fnotice (stdout, "Branches executed:%s of %d\n",
1710*e4b17023SJohn Marino 		   format_gcov (coverage->branches_executed,
1711*e4b17023SJohn Marino 				coverage->branches, 2),
1712*e4b17023SJohn Marino 		   coverage->branches);
1713*e4b17023SJohn Marino 	  fnotice (stdout, "Taken at least once:%s of %d\n",
1714*e4b17023SJohn Marino 		   format_gcov (coverage->branches_taken,
1715*e4b17023SJohn Marino 				coverage->branches, 2),
1716*e4b17023SJohn Marino 		   coverage->branches);
1717*e4b17023SJohn Marino 	}
1718*e4b17023SJohn Marino       else
1719*e4b17023SJohn Marino 	fnotice (stdout, "No branches\n");
1720*e4b17023SJohn Marino       if (coverage->calls)
1721*e4b17023SJohn Marino 	fnotice (stdout, "Calls executed:%s of %d\n",
1722*e4b17023SJohn Marino 		 format_gcov (coverage->calls_executed, coverage->calls, 2),
1723*e4b17023SJohn Marino 		 coverage->calls);
1724*e4b17023SJohn Marino       else
1725*e4b17023SJohn Marino 	fnotice (stdout, "No calls\n");
1726*e4b17023SJohn Marino     }
1727*e4b17023SJohn Marino }
1728*e4b17023SJohn Marino 
1729*e4b17023SJohn Marino /* Canonicalize the filename NAME by canonicalizing directory
1730*e4b17023SJohn Marino    separators, eliding . components and resolving .. components
1731*e4b17023SJohn Marino    appropriately.  Always returns a unique string.  */
1732*e4b17023SJohn Marino 
1733*e4b17023SJohn Marino static char *
canonicalize_name(const char * name)1734*e4b17023SJohn Marino canonicalize_name (const char *name)
1735*e4b17023SJohn Marino {
1736*e4b17023SJohn Marino   /* The canonical name cannot be longer than the incoming name.  */
1737*e4b17023SJohn Marino   char *result = XNEWVEC (char, strlen (name) + 1);
1738*e4b17023SJohn Marino   const char *base = name, *probe;
1739*e4b17023SJohn Marino   char *ptr = result;
1740*e4b17023SJohn Marino   char *dd_base;
1741*e4b17023SJohn Marino   int slash = 0;
1742*e4b17023SJohn Marino 
1743*e4b17023SJohn Marino #if HAVE_DOS_BASED_FILE_SYSTEM
1744*e4b17023SJohn Marino   if (base[0] && base[1] == ':')
1745*e4b17023SJohn Marino     {
1746*e4b17023SJohn Marino       result[0] = base[0];
1747*e4b17023SJohn Marino       result[1] = ':';
1748*e4b17023SJohn Marino       base += 2;
1749*e4b17023SJohn Marino       ptr += 2;
1750*e4b17023SJohn Marino     }
1751*e4b17023SJohn Marino #endif
1752*e4b17023SJohn Marino   for (dd_base = ptr; *base; base = probe)
1753*e4b17023SJohn Marino     {
1754*e4b17023SJohn Marino       size_t len;
1755*e4b17023SJohn Marino 
1756*e4b17023SJohn Marino       for (probe = base; *probe; probe++)
1757*e4b17023SJohn Marino 	if (IS_DIR_SEPARATOR (*probe))
1758*e4b17023SJohn Marino 	  break;
1759*e4b17023SJohn Marino 
1760*e4b17023SJohn Marino       len = probe - base;
1761*e4b17023SJohn Marino       if (len == 1 && base[0] == '.')
1762*e4b17023SJohn Marino 	/* Elide a '.' directory */
1763*e4b17023SJohn Marino 	;
1764*e4b17023SJohn Marino       else if (len == 2 && base[0] == '.' && base[1] == '.')
1765*e4b17023SJohn Marino 	{
1766*e4b17023SJohn Marino 	  /* '..', we can only elide it and the previous directory, if
1767*e4b17023SJohn Marino 	     we're not a symlink.  */
1768*e4b17023SJohn Marino 	  struct stat ATTRIBUTE_UNUSED buf;
1769*e4b17023SJohn Marino 
1770*e4b17023SJohn Marino 	  *ptr = 0;
1771*e4b17023SJohn Marino 	  if (dd_base == ptr
1772*e4b17023SJohn Marino #if defined (S_ISLNK)
1773*e4b17023SJohn Marino 	      /* S_ISLNK is not POSIX.1-1996.  */
1774*e4b17023SJohn Marino 	      || stat (result, &buf) || S_ISLNK (buf.st_mode)
1775*e4b17023SJohn Marino #endif
1776*e4b17023SJohn Marino 	      )
1777*e4b17023SJohn Marino 	    {
1778*e4b17023SJohn Marino 	      /* Cannot elide, or unreadable or a symlink.  */
1779*e4b17023SJohn Marino 	      dd_base = ptr + 2 + slash;
1780*e4b17023SJohn Marino 	      goto regular;
1781*e4b17023SJohn Marino 	    }
1782*e4b17023SJohn Marino 	  while (ptr != dd_base && *ptr != '/')
1783*e4b17023SJohn Marino 	    ptr--;
1784*e4b17023SJohn Marino 	  slash = ptr != result;
1785*e4b17023SJohn Marino 	}
1786*e4b17023SJohn Marino       else
1787*e4b17023SJohn Marino 	{
1788*e4b17023SJohn Marino 	regular:
1789*e4b17023SJohn Marino 	  /* Regular pathname component.  */
1790*e4b17023SJohn Marino 	  if (slash)
1791*e4b17023SJohn Marino 	    *ptr++ = '/';
1792*e4b17023SJohn Marino 	  memcpy (ptr, base, len);
1793*e4b17023SJohn Marino 	  ptr += len;
1794*e4b17023SJohn Marino 	  slash = 1;
1795*e4b17023SJohn Marino 	}
1796*e4b17023SJohn Marino 
1797*e4b17023SJohn Marino       for (; IS_DIR_SEPARATOR (*probe); probe++)
1798*e4b17023SJohn Marino 	continue;
1799*e4b17023SJohn Marino     }
1800*e4b17023SJohn Marino   *ptr = 0;
1801*e4b17023SJohn Marino 
1802*e4b17023SJohn Marino   return result;
1803*e4b17023SJohn Marino }
1804*e4b17023SJohn Marino 
1805*e4b17023SJohn Marino /* Generate an output file name. INPUT_NAME is the canonicalized main
1806*e4b17023SJohn Marino    input file and SRC_NAME is the canonicalized file name.
1807*e4b17023SJohn Marino    LONG_OUTPUT_NAMES and PRESERVE_PATHS affect name generation.  With
1808*e4b17023SJohn Marino    long_output_names we prepend the processed name of the input file
1809*e4b17023SJohn Marino    to each output name (except when the current source file is the
1810*e4b17023SJohn Marino    input file, so you don't get a double concatenation). The two
1811*e4b17023SJohn Marino    components are separated by '##'.  With preserve_paths we create a
1812*e4b17023SJohn Marino    filename from all path components of the source file, replacing '/'
1813*e4b17023SJohn Marino    with '#', and .. with '^', without it we simply take the basename
1814*e4b17023SJohn Marino    component.  (Remember, the canonicalized name will already have
1815*e4b17023SJohn Marino    elided '.' components and converted \\ separators.)  */
1816*e4b17023SJohn Marino 
1817*e4b17023SJohn Marino static char *
make_gcov_file_name(const char * input_name,const char * src_name)1818*e4b17023SJohn Marino make_gcov_file_name (const char *input_name, const char *src_name)
1819*e4b17023SJohn Marino {
1820*e4b17023SJohn Marino   char *ptr;
1821*e4b17023SJohn Marino   char *result;
1822*e4b17023SJohn Marino 
1823*e4b17023SJohn Marino   if (flag_long_names && input_name && strcmp (src_name, input_name))
1824*e4b17023SJohn Marino     {
1825*e4b17023SJohn Marino       /* Generate the input filename part.  */
1826*e4b17023SJohn Marino       result = XNEWVEC (char, strlen (input_name) + strlen (src_name) + 10);
1827*e4b17023SJohn Marino 
1828*e4b17023SJohn Marino       ptr = result;
1829*e4b17023SJohn Marino       ptr = mangle_name (input_name, ptr);
1830*e4b17023SJohn Marino       ptr[0] = ptr[1] = '#';
1831*e4b17023SJohn Marino       ptr += 2;
1832*e4b17023SJohn Marino     }
1833*e4b17023SJohn Marino   else
1834*e4b17023SJohn Marino     {
1835*e4b17023SJohn Marino       result = XNEWVEC (char, strlen (src_name) + 10);
1836*e4b17023SJohn Marino       ptr = result;
1837*e4b17023SJohn Marino     }
1838*e4b17023SJohn Marino 
1839*e4b17023SJohn Marino   ptr = mangle_name (src_name, ptr);
1840*e4b17023SJohn Marino   strcpy (ptr, ".gcov");
1841*e4b17023SJohn Marino 
1842*e4b17023SJohn Marino   return result;
1843*e4b17023SJohn Marino }
1844*e4b17023SJohn Marino 
1845*e4b17023SJohn Marino static char *
mangle_name(char const * base,char * ptr)1846*e4b17023SJohn Marino mangle_name (char const *base, char *ptr)
1847*e4b17023SJohn Marino {
1848*e4b17023SJohn Marino   size_t len;
1849*e4b17023SJohn Marino 
1850*e4b17023SJohn Marino   /* Generate the source filename part.  */
1851*e4b17023SJohn Marino   if (!flag_preserve_paths)
1852*e4b17023SJohn Marino     {
1853*e4b17023SJohn Marino       base = lbasename (base);
1854*e4b17023SJohn Marino       len = strlen (base);
1855*e4b17023SJohn Marino       memcpy (ptr, base, len);
1856*e4b17023SJohn Marino       ptr += len;
1857*e4b17023SJohn Marino     }
1858*e4b17023SJohn Marino   else
1859*e4b17023SJohn Marino     {
1860*e4b17023SJohn Marino       /* Convert '/' to '#', convert '..' to '^',
1861*e4b17023SJohn Marino 	 convert ':' to '~' on DOS based file system.  */
1862*e4b17023SJohn Marino       const char *probe;
1863*e4b17023SJohn Marino 
1864*e4b17023SJohn Marino #if HAVE_DOS_BASED_FILE_SYSTEM
1865*e4b17023SJohn Marino       if (base[0] && base[1] == ':')
1866*e4b17023SJohn Marino 	{
1867*e4b17023SJohn Marino 	  ptr[0] = base[0];
1868*e4b17023SJohn Marino 	  ptr[1] = '~';
1869*e4b17023SJohn Marino 	  ptr += 2;
1870*e4b17023SJohn Marino 	  base += 2;
1871*e4b17023SJohn Marino 	}
1872*e4b17023SJohn Marino #endif
1873*e4b17023SJohn Marino       for (; *base; base = probe)
1874*e4b17023SJohn Marino 	{
1875*e4b17023SJohn Marino 	  size_t len;
1876*e4b17023SJohn Marino 
1877*e4b17023SJohn Marino 	  for (probe = base; *probe; probe++)
1878*e4b17023SJohn Marino 	    if (*probe == '/')
1879*e4b17023SJohn Marino 	      break;
1880*e4b17023SJohn Marino 	  len = probe - base;
1881*e4b17023SJohn Marino 	  if (len == 2 && base[0] == '.' && base[1] == '.')
1882*e4b17023SJohn Marino 	    *ptr++ = '^';
1883*e4b17023SJohn Marino 	  else
1884*e4b17023SJohn Marino 	    {
1885*e4b17023SJohn Marino 	      memcpy (ptr, base, len);
1886*e4b17023SJohn Marino 	      ptr += len;
1887*e4b17023SJohn Marino 	    }
1888*e4b17023SJohn Marino 	  if (*probe)
1889*e4b17023SJohn Marino 	    {
1890*e4b17023SJohn Marino 	      *ptr++ = '#';
1891*e4b17023SJohn Marino 	      probe++;
1892*e4b17023SJohn Marino 	    }
1893*e4b17023SJohn Marino 	}
1894*e4b17023SJohn Marino     }
1895*e4b17023SJohn Marino 
1896*e4b17023SJohn Marino   return ptr;
1897*e4b17023SJohn Marino }
1898*e4b17023SJohn Marino 
1899*e4b17023SJohn Marino /* Scan through the bb_data for each line in the block, increment
1900*e4b17023SJohn Marino    the line number execution count indicated by the execution count of
1901*e4b17023SJohn Marino    the appropriate basic block.  */
1902*e4b17023SJohn Marino 
1903*e4b17023SJohn Marino static void
add_line_counts(coverage_t * coverage,function_t * fn)1904*e4b17023SJohn Marino add_line_counts (coverage_t *coverage, function_t *fn)
1905*e4b17023SJohn Marino {
1906*e4b17023SJohn Marino   unsigned ix;
1907*e4b17023SJohn Marino   line_t *line = NULL; /* This is propagated from one iteration to the
1908*e4b17023SJohn Marino 			  next.  */
1909*e4b17023SJohn Marino 
1910*e4b17023SJohn Marino   /* Scan each basic block.  */
1911*e4b17023SJohn Marino   for (ix = 0; ix != fn->num_blocks; ix++)
1912*e4b17023SJohn Marino     {
1913*e4b17023SJohn Marino       block_t *block = &fn->blocks[ix];
1914*e4b17023SJohn Marino       unsigned *encoding;
1915*e4b17023SJohn Marino       const source_t *src = NULL;
1916*e4b17023SJohn Marino       unsigned jx;
1917*e4b17023SJohn Marino 
1918*e4b17023SJohn Marino       if (block->count && ix && ix + 1 != fn->num_blocks)
1919*e4b17023SJohn Marino 	fn->blocks_executed++;
1920*e4b17023SJohn Marino       for (jx = 0, encoding = block->u.line.encoding;
1921*e4b17023SJohn Marino 	   jx != block->u.line.num; jx++, encoding++)
1922*e4b17023SJohn Marino 	if (!*encoding)
1923*e4b17023SJohn Marino 	  {
1924*e4b17023SJohn Marino 	    src = &sources[*++encoding];
1925*e4b17023SJohn Marino 	    jx++;
1926*e4b17023SJohn Marino 	  }
1927*e4b17023SJohn Marino 	else
1928*e4b17023SJohn Marino 	  {
1929*e4b17023SJohn Marino 	    line = &src->lines[*encoding];
1930*e4b17023SJohn Marino 
1931*e4b17023SJohn Marino 	    if (coverage)
1932*e4b17023SJohn Marino 	      {
1933*e4b17023SJohn Marino 		if (!line->exists)
1934*e4b17023SJohn Marino 		  coverage->lines++;
1935*e4b17023SJohn Marino 		if (!line->count && block->count)
1936*e4b17023SJohn Marino 		  coverage->lines_executed++;
1937*e4b17023SJohn Marino 	      }
1938*e4b17023SJohn Marino 	    line->exists = 1;
1939*e4b17023SJohn Marino 	    if (!block->exceptional)
1940*e4b17023SJohn Marino 	      line->unexceptional = 1;
1941*e4b17023SJohn Marino 	    line->count += block->count;
1942*e4b17023SJohn Marino 	  }
1943*e4b17023SJohn Marino       free (block->u.line.encoding);
1944*e4b17023SJohn Marino       block->u.cycle.arc = NULL;
1945*e4b17023SJohn Marino       block->u.cycle.ident = ~0U;
1946*e4b17023SJohn Marino 
1947*e4b17023SJohn Marino       if (!ix || ix + 1 == fn->num_blocks)
1948*e4b17023SJohn Marino 	/* Entry or exit block */;
1949*e4b17023SJohn Marino       else if (flag_all_blocks)
1950*e4b17023SJohn Marino 	{
1951*e4b17023SJohn Marino 	  line_t *block_line = line;
1952*e4b17023SJohn Marino 
1953*e4b17023SJohn Marino 	  if (!block_line)
1954*e4b17023SJohn Marino 	    block_line = &sources[fn->src].lines[fn->line];
1955*e4b17023SJohn Marino 
1956*e4b17023SJohn Marino 	  block->chain = block_line->u.blocks;
1957*e4b17023SJohn Marino 	  block_line->u.blocks = block;
1958*e4b17023SJohn Marino 	}
1959*e4b17023SJohn Marino       else if (flag_branches)
1960*e4b17023SJohn Marino 	{
1961*e4b17023SJohn Marino 	  arc_t *arc;
1962*e4b17023SJohn Marino 
1963*e4b17023SJohn Marino 	  for (arc = block->succ; arc; arc = arc->succ_next)
1964*e4b17023SJohn Marino 	    {
1965*e4b17023SJohn Marino 	      arc->line_next = line->u.branches;
1966*e4b17023SJohn Marino 	      line->u.branches = arc;
1967*e4b17023SJohn Marino 	      if (coverage && !arc->is_unconditional)
1968*e4b17023SJohn Marino 		add_branch_counts (coverage, arc);
1969*e4b17023SJohn Marino 	    }
1970*e4b17023SJohn Marino 	}
1971*e4b17023SJohn Marino     }
1972*e4b17023SJohn Marino   if (!line)
1973*e4b17023SJohn Marino     fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
1974*e4b17023SJohn Marino }
1975*e4b17023SJohn Marino 
1976*e4b17023SJohn Marino /* Accumulate the line counts of a file.  */
1977*e4b17023SJohn Marino 
1978*e4b17023SJohn Marino static void
accumulate_line_counts(source_t * src)1979*e4b17023SJohn Marino accumulate_line_counts (source_t *src)
1980*e4b17023SJohn Marino {
1981*e4b17023SJohn Marino   line_t *line;
1982*e4b17023SJohn Marino   function_t *fn, *fn_p, *fn_n;
1983*e4b17023SJohn Marino   unsigned ix;
1984*e4b17023SJohn Marino 
1985*e4b17023SJohn Marino   /* Reverse the function order.  */
1986*e4b17023SJohn Marino   for (fn = src->functions, fn_p = NULL; fn;
1987*e4b17023SJohn Marino        fn_p = fn, fn = fn_n)
1988*e4b17023SJohn Marino     {
1989*e4b17023SJohn Marino       fn_n = fn->line_next;
1990*e4b17023SJohn Marino       fn->line_next = fn_p;
1991*e4b17023SJohn Marino     }
1992*e4b17023SJohn Marino   src->functions = fn_p;
1993*e4b17023SJohn Marino 
1994*e4b17023SJohn Marino   for (ix = src->num_lines, line = src->lines; ix--; line++)
1995*e4b17023SJohn Marino     {
1996*e4b17023SJohn Marino       if (!flag_all_blocks)
1997*e4b17023SJohn Marino 	{
1998*e4b17023SJohn Marino 	  arc_t *arc, *arc_p, *arc_n;
1999*e4b17023SJohn Marino 
2000*e4b17023SJohn Marino 	  /* Total and reverse the branch information.  */
2001*e4b17023SJohn Marino 	  for (arc = line->u.branches, arc_p = NULL; arc;
2002*e4b17023SJohn Marino 	       arc_p = arc, arc = arc_n)
2003*e4b17023SJohn Marino 	    {
2004*e4b17023SJohn Marino 	      arc_n = arc->line_next;
2005*e4b17023SJohn Marino 	      arc->line_next = arc_p;
2006*e4b17023SJohn Marino 
2007*e4b17023SJohn Marino 	      add_branch_counts (&src->coverage, arc);
2008*e4b17023SJohn Marino 	    }
2009*e4b17023SJohn Marino 	  line->u.branches = arc_p;
2010*e4b17023SJohn Marino 	}
2011*e4b17023SJohn Marino       else if (line->u.blocks)
2012*e4b17023SJohn Marino 	{
2013*e4b17023SJohn Marino 	  /* The user expects the line count to be the number of times
2014*e4b17023SJohn Marino 	     a line has been executed. Simply summing the block count
2015*e4b17023SJohn Marino 	     will give an artificially high number.  The Right Thing
2016*e4b17023SJohn Marino 	     is to sum the entry counts to the graph of blocks on this
2017*e4b17023SJohn Marino 	     line, then find the elementary cycles of the local graph
2018*e4b17023SJohn Marino 	     and add the transition counts of those cycles.  */
2019*e4b17023SJohn Marino 	  block_t *block, *block_p, *block_n;
2020*e4b17023SJohn Marino 	  gcov_type count = 0;
2021*e4b17023SJohn Marino 
2022*e4b17023SJohn Marino 	  /* Reverse the block information.  */
2023*e4b17023SJohn Marino 	  for (block = line->u.blocks, block_p = NULL; block;
2024*e4b17023SJohn Marino 	       block_p = block, block = block_n)
2025*e4b17023SJohn Marino 	    {
2026*e4b17023SJohn Marino 	      block_n = block->chain;
2027*e4b17023SJohn Marino 	      block->chain = block_p;
2028*e4b17023SJohn Marino 	      block->u.cycle.ident = ix;
2029*e4b17023SJohn Marino 	    }
2030*e4b17023SJohn Marino 	  line->u.blocks = block_p;
2031*e4b17023SJohn Marino 
2032*e4b17023SJohn Marino 	  /* Sum the entry arcs.  */
2033*e4b17023SJohn Marino 	  for (block = line->u.blocks; block; block = block->chain)
2034*e4b17023SJohn Marino 	    {
2035*e4b17023SJohn Marino 	      arc_t *arc;
2036*e4b17023SJohn Marino 
2037*e4b17023SJohn Marino 	      for (arc = block->pred; arc; arc = arc->pred_next)
2038*e4b17023SJohn Marino 		{
2039*e4b17023SJohn Marino 		  if (arc->src->u.cycle.ident != ix)
2040*e4b17023SJohn Marino 		    count += arc->count;
2041*e4b17023SJohn Marino 		  if (flag_branches)
2042*e4b17023SJohn Marino 		    add_branch_counts (&src->coverage, arc);
2043*e4b17023SJohn Marino 		}
2044*e4b17023SJohn Marino 
2045*e4b17023SJohn Marino 	      /* Initialize the cs_count.  */
2046*e4b17023SJohn Marino 	      for (arc = block->succ; arc; arc = arc->succ_next)
2047*e4b17023SJohn Marino 		arc->cs_count = arc->count;
2048*e4b17023SJohn Marino 	    }
2049*e4b17023SJohn Marino 
2050*e4b17023SJohn Marino 	  /* Find the loops. This uses the algorithm described in
2051*e4b17023SJohn Marino 	     Tiernan 'An Efficient Search Algorithm to Find the
2052*e4b17023SJohn Marino 	     Elementary Circuits of a Graph', CACM Dec 1970. We hold
2053*e4b17023SJohn Marino 	     the P array by having each block point to the arc that
2054*e4b17023SJohn Marino 	     connects to the previous block. The H array is implicitly
2055*e4b17023SJohn Marino 	     held because of the arc ordering, and the block's
2056*e4b17023SJohn Marino 	     previous arc pointer.
2057*e4b17023SJohn Marino 
2058*e4b17023SJohn Marino 	     Although the algorithm is O(N^3) for highly connected
2059*e4b17023SJohn Marino 	     graphs, at worst we'll have O(N^2), as most blocks have
2060*e4b17023SJohn Marino 	     only one or two exits. Most graphs will be small.
2061*e4b17023SJohn Marino 
2062*e4b17023SJohn Marino 	     For each loop we find, locate the arc with the smallest
2063*e4b17023SJohn Marino 	     transition count, and add that to the cumulative
2064*e4b17023SJohn Marino 	     count.  Decrease flow over the cycle and remove the arc
2065*e4b17023SJohn Marino 	     from consideration.  */
2066*e4b17023SJohn Marino 	  for (block = line->u.blocks; block; block = block->chain)
2067*e4b17023SJohn Marino 	    {
2068*e4b17023SJohn Marino 	      block_t *head = block;
2069*e4b17023SJohn Marino 	      arc_t *arc;
2070*e4b17023SJohn Marino 
2071*e4b17023SJohn Marino 	    next_vertex:;
2072*e4b17023SJohn Marino 	      arc = head->succ;
2073*e4b17023SJohn Marino 	    current_vertex:;
2074*e4b17023SJohn Marino 	      while (arc)
2075*e4b17023SJohn Marino 		{
2076*e4b17023SJohn Marino 		  block_t *dst = arc->dst;
2077*e4b17023SJohn Marino 		  if (/* Already used that arc.  */
2078*e4b17023SJohn Marino 		      arc->cycle
2079*e4b17023SJohn Marino 		      /* Not to same graph, or before first vertex.  */
2080*e4b17023SJohn Marino 		      || dst->u.cycle.ident != ix
2081*e4b17023SJohn Marino 		      /* Already in path.  */
2082*e4b17023SJohn Marino 		      || dst->u.cycle.arc)
2083*e4b17023SJohn Marino 		    {
2084*e4b17023SJohn Marino 		      arc = arc->succ_next;
2085*e4b17023SJohn Marino 		      continue;
2086*e4b17023SJohn Marino 		    }
2087*e4b17023SJohn Marino 
2088*e4b17023SJohn Marino 		  if (dst == block)
2089*e4b17023SJohn Marino 		    {
2090*e4b17023SJohn Marino 		      /* Found a closing arc.  */
2091*e4b17023SJohn Marino 		      gcov_type cycle_count = arc->cs_count;
2092*e4b17023SJohn Marino 		      arc_t *cycle_arc = arc;
2093*e4b17023SJohn Marino 		      arc_t *probe_arc;
2094*e4b17023SJohn Marino 
2095*e4b17023SJohn Marino 		      /* Locate the smallest arc count of the loop.  */
2096*e4b17023SJohn Marino 		      for (dst = head; (probe_arc = dst->u.cycle.arc);
2097*e4b17023SJohn Marino 			   dst = probe_arc->src)
2098*e4b17023SJohn Marino 			if (cycle_count > probe_arc->cs_count)
2099*e4b17023SJohn Marino 			  {
2100*e4b17023SJohn Marino 			    cycle_count = probe_arc->cs_count;
2101*e4b17023SJohn Marino 			    cycle_arc = probe_arc;
2102*e4b17023SJohn Marino 			  }
2103*e4b17023SJohn Marino 
2104*e4b17023SJohn Marino 		      count += cycle_count;
2105*e4b17023SJohn Marino 		      cycle_arc->cycle = 1;
2106*e4b17023SJohn Marino 
2107*e4b17023SJohn Marino 		      /* Remove the flow from the cycle.  */
2108*e4b17023SJohn Marino 		      arc->cs_count -= cycle_count;
2109*e4b17023SJohn Marino 		      for (dst = head; (probe_arc = dst->u.cycle.arc);
2110*e4b17023SJohn Marino 			   dst = probe_arc->src)
2111*e4b17023SJohn Marino 			probe_arc->cs_count -= cycle_count;
2112*e4b17023SJohn Marino 
2113*e4b17023SJohn Marino 		      /* Unwind to the cyclic arc.  */
2114*e4b17023SJohn Marino 		      while (head != cycle_arc->src)
2115*e4b17023SJohn Marino 			{
2116*e4b17023SJohn Marino 			  arc = head->u.cycle.arc;
2117*e4b17023SJohn Marino 			  head->u.cycle.arc = NULL;
2118*e4b17023SJohn Marino 			  head = arc->src;
2119*e4b17023SJohn Marino 			}
2120*e4b17023SJohn Marino 		      /* Move on.  */
2121*e4b17023SJohn Marino 		      arc = arc->succ_next;
2122*e4b17023SJohn Marino 		      continue;
2123*e4b17023SJohn Marino 		    }
2124*e4b17023SJohn Marino 
2125*e4b17023SJohn Marino 		  /* Add new block to chain.  */
2126*e4b17023SJohn Marino 		  dst->u.cycle.arc = arc;
2127*e4b17023SJohn Marino 		  head = dst;
2128*e4b17023SJohn Marino 		  goto next_vertex;
2129*e4b17023SJohn Marino 		}
2130*e4b17023SJohn Marino 	      /* We could not add another vertex to the path. Remove
2131*e4b17023SJohn Marino 		 the last vertex from the list.  */
2132*e4b17023SJohn Marino 	      arc = head->u.cycle.arc;
2133*e4b17023SJohn Marino 	      if (arc)
2134*e4b17023SJohn Marino 		{
2135*e4b17023SJohn Marino 		  /* It was not the first vertex. Move onto next arc.  */
2136*e4b17023SJohn Marino 		  head->u.cycle.arc = NULL;
2137*e4b17023SJohn Marino 		  head = arc->src;
2138*e4b17023SJohn Marino 		  arc = arc->succ_next;
2139*e4b17023SJohn Marino 		  goto current_vertex;
2140*e4b17023SJohn Marino 		}
2141*e4b17023SJohn Marino 	      /* Mark this block as unusable.  */
2142*e4b17023SJohn Marino 	      block->u.cycle.ident = ~0U;
2143*e4b17023SJohn Marino 	    }
2144*e4b17023SJohn Marino 
2145*e4b17023SJohn Marino 	  line->count = count;
2146*e4b17023SJohn Marino 	}
2147*e4b17023SJohn Marino 
2148*e4b17023SJohn Marino       if (line->exists)
2149*e4b17023SJohn Marino 	{
2150*e4b17023SJohn Marino 	  src->coverage.lines++;
2151*e4b17023SJohn Marino 	  if (line->count)
2152*e4b17023SJohn Marino 	    src->coverage.lines_executed++;
2153*e4b17023SJohn Marino 	}
2154*e4b17023SJohn Marino     }
2155*e4b17023SJohn Marino }
2156*e4b17023SJohn Marino 
2157*e4b17023SJohn Marino /* Output information about ARC number IX.  Returns nonzero if
2158*e4b17023SJohn Marino    anything is output.  */
2159*e4b17023SJohn Marino 
2160*e4b17023SJohn Marino static int
output_branch_count(FILE * gcov_file,int ix,const arc_t * arc)2161*e4b17023SJohn Marino output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
2162*e4b17023SJohn Marino {
2163*e4b17023SJohn Marino   if (arc->is_call_non_return)
2164*e4b17023SJohn Marino     {
2165*e4b17023SJohn Marino       if (arc->src->count)
2166*e4b17023SJohn Marino 	{
2167*e4b17023SJohn Marino 	  fnotice (gcov_file, "call   %2d returned %s\n", ix,
2168*e4b17023SJohn Marino 		   format_gcov (arc->src->count - arc->count,
2169*e4b17023SJohn Marino 				arc->src->count, -flag_counts));
2170*e4b17023SJohn Marino 	}
2171*e4b17023SJohn Marino       else
2172*e4b17023SJohn Marino 	fnotice (gcov_file, "call   %2d never executed\n", ix);
2173*e4b17023SJohn Marino     }
2174*e4b17023SJohn Marino   else if (!arc->is_unconditional)
2175*e4b17023SJohn Marino     {
2176*e4b17023SJohn Marino       if (arc->src->count)
2177*e4b17023SJohn Marino 	fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
2178*e4b17023SJohn Marino 		 format_gcov (arc->count, arc->src->count, -flag_counts),
2179*e4b17023SJohn Marino 		 arc->fall_through ? " (fallthrough)"
2180*e4b17023SJohn Marino 		 : arc->is_throw ? " (throw)" : "");
2181*e4b17023SJohn Marino       else
2182*e4b17023SJohn Marino 	fnotice (gcov_file, "branch %2d never executed\n", ix);
2183*e4b17023SJohn Marino     }
2184*e4b17023SJohn Marino   else if (flag_unconditional && !arc->dst->is_call_return)
2185*e4b17023SJohn Marino     {
2186*e4b17023SJohn Marino       if (arc->src->count)
2187*e4b17023SJohn Marino 	fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
2188*e4b17023SJohn Marino 		 format_gcov (arc->count, arc->src->count, -flag_counts));
2189*e4b17023SJohn Marino       else
2190*e4b17023SJohn Marino 	fnotice (gcov_file, "unconditional %2d never executed\n", ix);
2191*e4b17023SJohn Marino     }
2192*e4b17023SJohn Marino   else
2193*e4b17023SJohn Marino     return 0;
2194*e4b17023SJohn Marino   return 1;
2195*e4b17023SJohn Marino 
2196*e4b17023SJohn Marino }
2197*e4b17023SJohn Marino 
2198*e4b17023SJohn Marino static const char *
read_line(FILE * file)2199*e4b17023SJohn Marino read_line (FILE *file)
2200*e4b17023SJohn Marino {
2201*e4b17023SJohn Marino   static char *string;
2202*e4b17023SJohn Marino   static size_t string_len;
2203*e4b17023SJohn Marino   size_t pos = 0;
2204*e4b17023SJohn Marino   char *ptr;
2205*e4b17023SJohn Marino 
2206*e4b17023SJohn Marino   if (!string_len)
2207*e4b17023SJohn Marino     {
2208*e4b17023SJohn Marino       string_len = 200;
2209*e4b17023SJohn Marino       string = XNEWVEC (char, string_len);
2210*e4b17023SJohn Marino     }
2211*e4b17023SJohn Marino 
2212*e4b17023SJohn Marino   while ((ptr = fgets (string + pos, string_len - pos, file)))
2213*e4b17023SJohn Marino     {
2214*e4b17023SJohn Marino       size_t len = strlen (string + pos);
2215*e4b17023SJohn Marino 
2216*e4b17023SJohn Marino       if (string[pos + len - 1] == '\n')
2217*e4b17023SJohn Marino 	{
2218*e4b17023SJohn Marino 	  string[pos + len - 1] = 0;
2219*e4b17023SJohn Marino 	  return string;
2220*e4b17023SJohn Marino 	}
2221*e4b17023SJohn Marino       pos += len;
2222*e4b17023SJohn Marino       ptr = XNEWVEC (char, string_len * 2);
2223*e4b17023SJohn Marino       if (ptr)
2224*e4b17023SJohn Marino 	{
2225*e4b17023SJohn Marino 	  memcpy (ptr, string, pos);
2226*e4b17023SJohn Marino 	  string = ptr;
2227*e4b17023SJohn Marino 	  string_len += 2;
2228*e4b17023SJohn Marino 	}
2229*e4b17023SJohn Marino       else
2230*e4b17023SJohn Marino 	pos = 0;
2231*e4b17023SJohn Marino     }
2232*e4b17023SJohn Marino 
2233*e4b17023SJohn Marino   return pos ? string : NULL;
2234*e4b17023SJohn Marino }
2235*e4b17023SJohn Marino 
2236*e4b17023SJohn Marino /* Read in the source file one line at a time, and output that line to
2237*e4b17023SJohn Marino    the gcov file preceded by its execution count and other
2238*e4b17023SJohn Marino    information.  */
2239*e4b17023SJohn Marino 
2240*e4b17023SJohn Marino static void
output_lines(FILE * gcov_file,const source_t * src)2241*e4b17023SJohn Marino output_lines (FILE *gcov_file, const source_t *src)
2242*e4b17023SJohn Marino {
2243*e4b17023SJohn Marino   FILE *source_file;
2244*e4b17023SJohn Marino   unsigned line_num;	/* current line number.  */
2245*e4b17023SJohn Marino   const line_t *line;           /* current line info ptr.  */
2246*e4b17023SJohn Marino   const char *retval = "";	/* status of source file reading.  */
2247*e4b17023SJohn Marino   function_t *fn = NULL;
2248*e4b17023SJohn Marino 
2249*e4b17023SJohn Marino   fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->coverage.name);
2250*e4b17023SJohn Marino   if (!multiple_files)
2251*e4b17023SJohn Marino     {
2252*e4b17023SJohn Marino       fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
2253*e4b17023SJohn Marino       fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
2254*e4b17023SJohn Marino 	       no_data_file ? "-" : da_file_name);
2255*e4b17023SJohn Marino       fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, object_runs);
2256*e4b17023SJohn Marino     }
2257*e4b17023SJohn Marino   fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
2258*e4b17023SJohn Marino 
2259*e4b17023SJohn Marino   source_file = fopen (src->name, "r");
2260*e4b17023SJohn Marino   if (!source_file)
2261*e4b17023SJohn Marino     {
2262*e4b17023SJohn Marino       fnotice (stderr, "Cannot open source file %s\n", src->name);
2263*e4b17023SJohn Marino       retval = NULL;
2264*e4b17023SJohn Marino     }
2265*e4b17023SJohn Marino   else if (src->file_time == 0)
2266*e4b17023SJohn Marino     fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0);
2267*e4b17023SJohn Marino 
2268*e4b17023SJohn Marino   if (flag_branches)
2269*e4b17023SJohn Marino     fn = src->functions;
2270*e4b17023SJohn Marino 
2271*e4b17023SJohn Marino   for (line_num = 1, line = &src->lines[line_num];
2272*e4b17023SJohn Marino        line_num < src->num_lines; line_num++, line++)
2273*e4b17023SJohn Marino     {
2274*e4b17023SJohn Marino       for (; fn && fn->line == line_num; fn = fn->line_next)
2275*e4b17023SJohn Marino 	{
2276*e4b17023SJohn Marino 	  arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
2277*e4b17023SJohn Marino 	  gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
2278*e4b17023SJohn Marino 
2279*e4b17023SJohn Marino 	  for (; arc; arc = arc->pred_next)
2280*e4b17023SJohn Marino 	    if (arc->fake)
2281*e4b17023SJohn Marino 	      return_count -= arc->count;
2282*e4b17023SJohn Marino 
2283*e4b17023SJohn Marino 	  fprintf (gcov_file, "function %s", fn->name);
2284*e4b17023SJohn Marino 	  fprintf (gcov_file, " called %s",
2285*e4b17023SJohn Marino 		   format_gcov (fn->blocks[0].count, 0, -1));
2286*e4b17023SJohn Marino 	  fprintf (gcov_file, " returned %s",
2287*e4b17023SJohn Marino 		   format_gcov (return_count, fn->blocks[0].count, 0));
2288*e4b17023SJohn Marino 	  fprintf (gcov_file, " blocks executed %s",
2289*e4b17023SJohn Marino 		   format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
2290*e4b17023SJohn Marino 	  fprintf (gcov_file, "\n");
2291*e4b17023SJohn Marino 	}
2292*e4b17023SJohn Marino 
2293*e4b17023SJohn Marino       if (retval)
2294*e4b17023SJohn Marino 	retval = read_line (source_file);
2295*e4b17023SJohn Marino 
2296*e4b17023SJohn Marino       /* For lines which don't exist in the .bb file, print '-' before
2297*e4b17023SJohn Marino 	 the source line.  For lines which exist but were never
2298*e4b17023SJohn Marino 	 executed, print '#####' or '=====' before the source line.
2299*e4b17023SJohn Marino 	 Otherwise, print the execution count before the source line.
2300*e4b17023SJohn Marino 	 There are 16 spaces of indentation added before the source
2301*e4b17023SJohn Marino 	 line so that tabs won't be messed up.  */
2302*e4b17023SJohn Marino       fprintf (gcov_file, "%9s:%5u:%s\n",
2303*e4b17023SJohn Marino 	       !line->exists ? "-" : line->count
2304*e4b17023SJohn Marino 	       ? format_gcov (line->count, 0, -1)
2305*e4b17023SJohn Marino 	       : line->unexceptional ? "#####" : "=====", line_num,
2306*e4b17023SJohn Marino 	       retval ? retval : "/*EOF*/");
2307*e4b17023SJohn Marino 
2308*e4b17023SJohn Marino       if (flag_all_blocks)
2309*e4b17023SJohn Marino 	{
2310*e4b17023SJohn Marino 	  block_t *block;
2311*e4b17023SJohn Marino 	  arc_t *arc;
2312*e4b17023SJohn Marino 	  int ix, jx;
2313*e4b17023SJohn Marino 
2314*e4b17023SJohn Marino 	  for (ix = jx = 0, block = line->u.blocks; block;
2315*e4b17023SJohn Marino 	       block = block->chain)
2316*e4b17023SJohn Marino 	    {
2317*e4b17023SJohn Marino 	      if (!block->is_call_return)
2318*e4b17023SJohn Marino 		fprintf (gcov_file, "%9s:%5u-block %2d\n",
2319*e4b17023SJohn Marino 			 !line->exists ? "-" : block->count
2320*e4b17023SJohn Marino 			 ? format_gcov (block->count, 0, -1)
2321*e4b17023SJohn Marino 			 : block->exceptional ? "%%%%%" : "$$$$$",
2322*e4b17023SJohn Marino 			 line_num, ix++);
2323*e4b17023SJohn Marino 	      if (flag_branches)
2324*e4b17023SJohn Marino 		for (arc = block->succ; arc; arc = arc->succ_next)
2325*e4b17023SJohn Marino 		  jx += output_branch_count (gcov_file, jx, arc);
2326*e4b17023SJohn Marino 	    }
2327*e4b17023SJohn Marino 	}
2328*e4b17023SJohn Marino       else if (flag_branches)
2329*e4b17023SJohn Marino 	{
2330*e4b17023SJohn Marino 	  int ix;
2331*e4b17023SJohn Marino 	  arc_t *arc;
2332*e4b17023SJohn Marino 
2333*e4b17023SJohn Marino 	  for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
2334*e4b17023SJohn Marino 	    ix += output_branch_count (gcov_file, ix, arc);
2335*e4b17023SJohn Marino 	}
2336*e4b17023SJohn Marino     }
2337*e4b17023SJohn Marino 
2338*e4b17023SJohn Marino   /* Handle all remaining source lines.  There may be lines after the
2339*e4b17023SJohn Marino      last line of code.  */
2340*e4b17023SJohn Marino   if (retval)
2341*e4b17023SJohn Marino     {
2342*e4b17023SJohn Marino       for (; (retval = read_line (source_file)); line_num++)
2343*e4b17023SJohn Marino 	fprintf (gcov_file, "%9s:%5u:%s\n", "-", line_num, retval);
2344*e4b17023SJohn Marino     }
2345*e4b17023SJohn Marino 
2346*e4b17023SJohn Marino   if (source_file)
2347*e4b17023SJohn Marino     fclose (source_file);
2348*e4b17023SJohn Marino }
2349