150397Sobrien/* Gcov.c: prepend line execution counts and branch probabilities to a
250397Sobrien   source file.
3161651Skan   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
4161651Skan   2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
550397Sobrien   Contributed by James E. Wilson of Cygnus Support.
650397Sobrien   Mangled by Bob Manson of Cygnus Support.
7132718Skan   Mangled further by Nathan Sidwell <nathan@codesourcery.com>
850397Sobrien
950397SobrienGcov is free software; you can redistribute it and/or modify
1050397Sobrienit under the terms of the GNU General Public License as published by
1150397Sobrienthe Free Software Foundation; either version 2, or (at your option)
1250397Sobrienany later version.
1350397Sobrien
1450397SobrienGcov is distributed in the hope that it will be useful,
1550397Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1650397SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1750397SobrienGNU General Public License for more details.
1850397Sobrien
1950397SobrienYou should have received a copy of the GNU General Public License
2050397Sobrienalong with Gcov; see the file COPYING.  If not, write to
21169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor,
22169689SkanBoston, MA 02110-1301, USA.  */
2350397Sobrien
2450397Sobrien/* ??? Print a list of the ten blocks with the highest execution counts,
2550397Sobrien   and list the line numbers corresponding to those blocks.  Also, perhaps
2650397Sobrien   list the line numbers with the highest execution counts, only printing
2750397Sobrien   the first if there are several which are all listed in the same block.  */
2850397Sobrien
2950397Sobrien/* ??? Should have an option to print the number of basic blocks, and the
3050397Sobrien   percent of them that are covered.  */
3150397Sobrien
32132718Skan/* ??? Does not correctly handle the case where two .bb files refer to
33132718Skan   the same included source file.  For example, if one has a short
34132718Skan   file containing only inline functions, which is then included in
35132718Skan   two other files, then there will be two .bb files which refer to
36132718Skan   the include file, but there is no way to get the total execution
37132718Skan   counts for the included file, can only get execution counts for one
38132718Skan   or the other of the including files. this can be fixed by --ratios
39132718Skan   --long-file-names --preserve-paths and perl.  */
4050397Sobrien
41132718Skan/* Need an option to show individual block counts, and show
42132718Skan   probabilities of fall through arcs.  */
43132718Skan
4450397Sobrien#include "config.h"
4550397Sobrien#include "system.h"
46132718Skan#include "coretypes.h"
47132718Skan#include "tm.h"
4852284Sobrien#include "intl.h"
4990075Sobrien#include "version.h"
5050397Sobrien
5190075Sobrien#include <getopt.h>
5290075Sobrien
53132718Skan#define IN_GCOV 1
5450397Sobrien#include "gcov-io.h"
55132718Skan#include "gcov-io.c"
5650397Sobrien
57132718Skan/* The bbg file is generated by -ftest-coverage option. The da file is
58132718Skan   generated by a program compiled with -fprofile-arcs. Their formats
59132718Skan   are documented in gcov-io.h.  */
6050397Sobrien
6150397Sobrien/* The functions in this file for creating and solution program flow graphs
62132718Skan   are very similar to functions in the gcc source file profile.c.  In
63132718Skan   some places we make use of the knowledge of how profile.c works to
64132718Skan   select particular algorithms here.  */
6550397Sobrien
6650397Sobrien/* This is the size of the buffer used to read in source file lines.  */
6750397Sobrien
6850397Sobrien#define STRING_SIZE 200
6950397Sobrien
70132718Skanstruct function_info;
71132718Skanstruct block_info;
72132718Skanstruct source_info;
7350397Sobrien
74132718Skan/* Describes an arc between two basic blocks.  */
75132718Skan
76132718Skantypedef struct arc_info
7750397Sobrien{
78132718Skan  /* source and destination blocks.  */
79132718Skan  struct block_info *src;
80132718Skan  struct block_info *dst;
8150397Sobrien
82132718Skan  /* transition counts.  */
83132718Skan  gcov_type count;
84132718Skan  /* used in cycle search, so that we do not clobber original counts.  */
85132718Skan  gcov_type cs_count;
8650397Sobrien
8750397Sobrien  unsigned int count_valid : 1;
8850397Sobrien  unsigned int on_tree : 1;
8950397Sobrien  unsigned int fake : 1;
9050397Sobrien  unsigned int fall_through : 1;
9150397Sobrien
92132718Skan  /* Arc is for a function that abnormally returns.  */
93132718Skan  unsigned int is_call_non_return : 1;
9450397Sobrien
95132718Skan  /* Arc is for catch/setjump.  */
96132718Skan  unsigned int is_nonlocal_return : 1;
9750397Sobrien
98132718Skan  /* Is an unconditional branch.  */
99132718Skan  unsigned int is_unconditional : 1;
10050397Sobrien
101132718Skan  /* Loop making arc.  */
102132718Skan  unsigned int cycle : 1;
103132718Skan
104132718Skan  /* Next branch on line.  */
105132718Skan  struct arc_info *line_next;
106132718Skan
107132718Skan  /* Links to next arc on src and dst lists.  */
108132718Skan  struct arc_info *succ_next;
109132718Skan  struct arc_info *pred_next;
110132718Skan} arc_t;
111132718Skan
112132718Skan/* Describes a basic block. Contains lists of arcs to successor and
113132718Skan   predecessor blocks.  */
114132718Skan
115132718Skantypedef struct block_info
11650397Sobrien{
117132718Skan  /* Chain of exit and entry arcs.  */
118132718Skan  arc_t *succ;
119132718Skan  arc_t *pred;
12050397Sobrien
121132718Skan  /* Number of unprocessed exit and entry arcs.  */
122132718Skan  gcov_type num_succ;
123132718Skan  gcov_type num_pred;
12450397Sobrien
125132718Skan  /* Block execution count.  */
126132718Skan  gcov_type count;
127132718Skan  unsigned flags : 13;
128132718Skan  unsigned count_valid : 1;
129132718Skan  unsigned valid_chain : 1;
130132718Skan  unsigned invalid_chain : 1;
131132718Skan
132132718Skan  /* Block is a call instrumenting site.  */
133132718Skan  unsigned is_call_site : 1; /* Does the call.  */
134132718Skan  unsigned is_call_return : 1; /* Is the return.  */
135132718Skan
136132718Skan  /* Block is a landing pad for longjmp or throw.  */
137132718Skan  unsigned is_nonlocal_return : 1;
138132718Skan
139132718Skan  union
140132718Skan  {
141132718Skan    struct
142132718Skan    {
143132718Skan     /* Array of line numbers and source files. source files are
144132718Skan        introduced by a linenumber of zero, the next 'line number' is
145132718Skan        the number of the source file.  Always starts with a source
146132718Skan        file.  */
147132718Skan      unsigned *encoding;
148132718Skan      unsigned num;
149132718Skan    } line; /* Valid until blocks are linked onto lines */
150132718Skan    struct
151132718Skan    {
152132718Skan      /* Single line graph cycle workspace.  Used for all-blocks
153132718Skan	 mode.  */
154132718Skan      arc_t *arc;
155132718Skan      unsigned ident;
156132718Skan    } cycle; /* Used in all-blocks mode, after blocks are linked onto
157132718Skan	       lines.  */
158132718Skan  } u;
159132718Skan
160132718Skan  /* Temporary chain for solving graph, and for chaining blocks on one
161132718Skan     line.  */
162132718Skan  struct block_info *chain;
163132718Skan
164132718Skan} block_t;
165132718Skan
166132718Skan/* Describes a single function. Contains an array of basic blocks.  */
167132718Skan
168132718Skantypedef struct function_info
169117395Skan{
170132718Skan  /* Name of function.  */
171132718Skan  char *name;
172132718Skan  unsigned ident;
173132718Skan  unsigned checksum;
17450397Sobrien
175132718Skan  /* Array of basic blocks.  */
176132718Skan  block_t *blocks;
177132718Skan  unsigned num_blocks;
178132718Skan  unsigned blocks_executed;
179132718Skan
180132718Skan  /* Raw arc coverage counts.  */
181132718Skan  gcov_type *counts;
182132718Skan  unsigned num_counts;
183132718Skan
184132718Skan  /* First line number.  */
185132718Skan  unsigned line;
186132718Skan  struct source_info *src;
187132718Skan
188132718Skan  /* Next function in same source file.  */
189132718Skan  struct function_info *line_next;
190132718Skan
191132718Skan  /* Next function.  */
192132718Skan  struct function_info *next;
193132718Skan} function_t;
194132718Skan
195132718Skan/* Describes coverage of a file or function.  */
196132718Skan
197132718Skantypedef struct coverage_info
198117395Skan{
199117395Skan  int lines;
200117395Skan  int lines_executed;
201132718Skan
202117395Skan  int branches;
203117395Skan  int branches_executed;
204117395Skan  int branches_taken;
205132718Skan
206117395Skan  int calls;
207117395Skan  int calls_executed;
208132718Skan
209117395Skan  char *name;
210132718Skan} coverage_t;
211117395Skan
212132718Skan/* Describes a single line of source. Contains a chain of basic blocks
213132718Skan   with code on it.  */
21450397Sobrien
215132718Skantypedef struct line_info
216132718Skan{
217132718Skan  gcov_type count;	   /* execution count */
218132718Skan  union
219132718Skan  {
220132718Skan    arc_t *branches;	   /* branches from blocks that end on this
221132718Skan			      line. Used for branch-counts when not
222132718Skan			      all-blocks mode.  */
223132718Skan    block_t *blocks;       /* blocks which start on this line.  Used
224132718Skan			      in all-blocks mode.  */
225132718Skan  } u;
226132718Skan  unsigned exists : 1;
227132718Skan} line_t;
22850397Sobrien
229132718Skan/* Describes a file mentioned in the block graph.  Contains an array
230132718Skan   of line info.  */
231117395Skan
232132718Skantypedef struct source_info
233132718Skan{
234132718Skan  /* Name of source file.  */
235132718Skan  char *name;
236132718Skan  unsigned index;
237117395Skan
238132718Skan  /* Array of line information.  */
239132718Skan  line_t *lines;
240132718Skan  unsigned num_lines;
24150397Sobrien
242132718Skan  coverage_t coverage;
24350397Sobrien
244132718Skan  /* Functions in this source file.  These are in ascending line
245132718Skan     number order.  */
246132718Skan  function_t *functions;
24750397Sobrien
248132718Skan  /* Next source file.  */
249132718Skan  struct source_info *next;
250132718Skan} source_t;
25150397Sobrien
252132718Skan/* Holds a list of function basic block graphs.  */
25350397Sobrien
254132718Skanstatic function_t *functions;
25550397Sobrien
256132718Skan/* This points to the head of the sourcefile structure list.  */
25750397Sobrien
258132718Skanstatic source_t *sources;
25950397Sobrien
260132718Skan/* This holds data summary information.  */
26150397Sobrien
262132718Skanstatic struct gcov_summary object_summary;
263132718Skanstatic unsigned program_count;
26450397Sobrien
265132718Skan/* Modification time of graph file.  */
26650397Sobrien
267132718Skanstatic time_t bbg_file_time;
26850397Sobrien
269132718Skan/* Name and file pointer of the input file for the basic block graph.  */
27050397Sobrien
271132718Skanstatic char *bbg_file_name;
27250397Sobrien
273132718Skan/* Stamp of the bbg file */
274132718Skanstatic unsigned bbg_stamp;
275132718Skan
276132718Skan/* Name and file pointer of the input file for the arc count data.  */
277132718Skan
278132718Skanstatic char *da_file_name;
279132718Skan
280169689Skan/* Data file is missing.  */
281169689Skan
282169689Skanstatic int no_data_file;
283169689Skan
284132718Skan/* Output branch probabilities.  */
285132718Skan
286132718Skanstatic int flag_branches = 0;
287132718Skan
288132718Skan/* Show unconditional branches too.  */
289132718Skanstatic int flag_unconditional = 0;
290132718Skan
29150397Sobrien/* Output a gcov file if this is true.  This is on by default, and can
29250397Sobrien   be turned off by the -n option.  */
29350397Sobrien
294132718Skanstatic int flag_gcov_file = 1;
29550397Sobrien
296132718Skan/* For included files, make the gcov output file name include the name
297132718Skan   of the input source file.  For example, if x.h is included in a.c,
298132718Skan   then the output file name is a.c##x.h.gcov instead of x.h.gcov.  */
29950397Sobrien
300132718Skanstatic int flag_long_names = 0;
30150397Sobrien
302132718Skan/* Output count information for every basic block, not merely those
303132718Skan   that contain line number information.  */
304132718Skan
305132718Skanstatic int flag_all_blocks = 0;
306132718Skan
30750397Sobrien/* Output summary info for each function.  */
30850397Sobrien
309132718Skanstatic int flag_function_summary = 0;
31050397Sobrien
311132718Skan/* Object directory file prefix.  This is the directory/file where the
312132718Skan   graph and data files are looked for, if nonzero.  */
31350397Sobrien
31450397Sobrienstatic char *object_directory = 0;
31550397Sobrien
316117395Skan/* Preserve all pathname components. Needed when object files and
317132718Skan   source files are in subdirectories. '/' is mangled as '#', '.' is
318132718Skan   elided and '..' mangled to '^'.  */
319117395Skan
320132718Skanstatic int flag_preserve_paths = 0;
321132718Skan
32290075Sobrien/* Output the number of times a branch was taken as opposed to the percentage
323132718Skan   of times it was taken.  */
32490075Sobrien
325132718Skanstatic int flag_counts = 0;
32690075Sobrien
32750397Sobrien/* Forward declarations.  */
328132718Skanstatic void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2;
329132718Skanstatic int process_args (int, char **);
330132718Skanstatic void print_usage (int) ATTRIBUTE_NORETURN;
331132718Skanstatic void print_version (void) ATTRIBUTE_NORETURN;
332132718Skanstatic void process_file (const char *);
333132718Skanstatic void create_file_names (const char *);
334132718Skanstatic source_t *find_source (const char *);
335132718Skanstatic int read_graph_file (void);
336132718Skanstatic int read_count_file (void);
337132718Skanstatic void solve_flow_graph (function_t *);
338132718Skanstatic void add_branch_counts (coverage_t *, const arc_t *);
339132718Skanstatic void add_line_counts (coverage_t *, function_t *);
340132718Skanstatic void function_summary (const coverage_t *, const char *);
341132718Skanstatic const char *format_gcov (gcov_type, gcov_type, int);
342132718Skanstatic void accumulate_line_counts (source_t *);
343132718Skanstatic int output_branch_count (FILE *, int, const arc_t *);
344132718Skanstatic void output_lines (FILE *, const source_t *);
345132718Skanstatic char *make_gcov_file_name (const char *, const char *);
346132718Skanstatic void release_structures (void);
347132718Skanextern int main (int, char **);
34850397Sobrien
34950397Sobrienint
350132718Skanmain (int argc, char **argv)
35150397Sobrien{
352132718Skan  int argno;
353132718Skan
354169689Skan  /* Unlock the stdio streams.  */
355169689Skan  unlock_std_streams ();
356169689Skan
35790075Sobrien  gcc_init_libintl ();
35852284Sobrien
359132718Skan  argno = process_args (argc, argv);
360132718Skan  if (optind == argc)
361132718Skan    print_usage (true);
36250397Sobrien
363132718Skan  for (; argno != argc; argno++)
364132718Skan    {
365132718Skan      release_structures ();
36650397Sobrien
367132718Skan      process_file (argv[argno]);
368132718Skan    }
36950397Sobrien
37050397Sobrien  return 0;
37150397Sobrien}
37250397Sobrien
37352284Sobrienstatic void
374169689Skanfnotice (FILE *file, const char *cmsgid, ...)
37552284Sobrien{
376132718Skan  va_list ap;
37752284Sobrien
378169689Skan  va_start (ap, cmsgid);
379169689Skan  vfprintf (file, _(cmsgid), ap);
380132718Skan  va_end (ap);
38152284Sobrien}
38250397Sobrien
38390075Sobrien/* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
38490075Sobrien   otherwise the output of --help.  */
38550397Sobrien
38650397Sobrienstatic void
387132718Skanprint_usage (int error_p)
38850397Sobrien{
38990075Sobrien  FILE *file = error_p ? stderr : stdout;
39090075Sobrien  int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
391132718Skan
39290075Sobrien  fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
39390075Sobrien  fnotice (file, "Print code coverage information.\n\n");
39490075Sobrien  fnotice (file, "  -h, --help                      Print this help, then exit\n");
39590075Sobrien  fnotice (file, "  -v, --version                   Print version number, then exit\n");
396132718Skan  fnotice (file, "  -a, --all-blocks                Show information for every basic block\n");
39790075Sobrien  fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output\n");
39890075Sobrien  fnotice (file, "  -c, --branch-counts             Given counts of branches taken\n\
39990075Sobrien                                    rather than percentages\n");
40090075Sobrien  fnotice (file, "  -n, --no-output                 Do not create an output file\n");
40190075Sobrien  fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
40290075Sobrien                                    source files\n");
40390075Sobrien  fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
404117395Skan  fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
405117395Skan  fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
406132718Skan  fnotice (file, "  -u, --unconditional-branches    Show unconditional branch counts too\n");
40790075Sobrien  fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
408117395Skan	   bug_report_url);
40990075Sobrien  exit (status);
41050397Sobrien}
41150397Sobrien
41290075Sobrien/* Print version information and exit.  */
41390075Sobrien
41490075Sobrienstatic void
415132718Skanprint_version (void)
41690075Sobrien{
41790075Sobrien  fnotice (stdout, "gcov (GCC) %s\n", version_string);
418161651Skan  fprintf (stdout, "Copyright %s 2006 Free Software Foundation, Inc.\n",
419132718Skan	   _("(C)"));
420260012Spfg  fnotice (stdout, "%s",
421132718Skan	   _("This is free software; see the source for copying conditions.\n"
422132718Skan	     "There is NO warranty; not even for MERCHANTABILITY or \n"
423132718Skan	     "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
42490075Sobrien  exit (SUCCESS_EXIT_CODE);
42590075Sobrien}
42690075Sobrien
42790075Sobrienstatic const struct option options[] =
42890075Sobrien{
42990075Sobrien  { "help",                 no_argument,       NULL, 'h' },
43090075Sobrien  { "version",              no_argument,       NULL, 'v' },
431132718Skan  { "all-blocks",           no_argument,       NULL, 'a' },
43290075Sobrien  { "branch-probabilities", no_argument,       NULL, 'b' },
43390075Sobrien  { "branch-counts",        no_argument,       NULL, 'c' },
43490075Sobrien  { "no-output",            no_argument,       NULL, 'n' },
43590075Sobrien  { "long-file-names",      no_argument,       NULL, 'l' },
43690075Sobrien  { "function-summaries",   no_argument,       NULL, 'f' },
437117395Skan  { "preserve-paths",       no_argument,       NULL, 'p' },
438117395Skan  { "object-directory",     required_argument, NULL, 'o' },
439117395Skan  { "object-file",          required_argument, NULL, 'o' },
440132718Skan  { "unconditional-branches", no_argument,     NULL, 'u' },
441132718Skan  { 0, 0, 0, 0 }
44290075Sobrien};
44390075Sobrien
444132718Skan/* Process args, return index to first non-arg.  */
44550397Sobrien
446132718Skanstatic int
447132718Skanprocess_args (int argc, char **argv)
44850397Sobrien{
44990075Sobrien  int opt;
45050397Sobrien
451132718Skan  while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1)
45250397Sobrien    {
45390075Sobrien      switch (opt)
45450397Sobrien	{
455132718Skan	case 'a':
456132718Skan	  flag_all_blocks = 1;
457132718Skan	  break;
45890075Sobrien	case 'b':
459132718Skan	  flag_branches = 1;
46090075Sobrien	  break;
46190075Sobrien	case 'c':
462132718Skan	  flag_counts = 1;
46390075Sobrien	  break;
464132718Skan	case 'f':
465132718Skan	  flag_function_summary = 1;
46690075Sobrien	  break;
467132718Skan	case 'h':
468132718Skan	  print_usage (false);
469132718Skan	  /* print_usage will exit.  */
47090075Sobrien	case 'l':
471132718Skan	  flag_long_names = 1;
47290075Sobrien	  break;
473132718Skan	case 'n':
474132718Skan	  flag_gcov_file = 0;
47590075Sobrien	  break;
47690075Sobrien	case 'o':
47790075Sobrien	  object_directory = optarg;
47890075Sobrien	  break;
479117395Skan	case 'p':
480132718Skan	  flag_preserve_paths = 1;
481117395Skan	  break;
482132718Skan	case 'u':
483132718Skan	  flag_unconditional = 1;
484132718Skan	  break;
485132718Skan	case 'v':
486132718Skan	  print_version ();
487132718Skan	  /* print_version will exit.  */
48890075Sobrien	default:
48990075Sobrien	  print_usage (true);
49090075Sobrien	  /* print_usage will exit.  */
49150397Sobrien	}
49250397Sobrien    }
49350397Sobrien
494132718Skan  return optind;
495132718Skan}
49690075Sobrien
497132718Skan/* Process a single source file.  */
498132718Skan
499132718Skanstatic void
500132718Skanprocess_file (const char *file_name)
501132718Skan{
502132718Skan  source_t *src;
503132718Skan  function_t *fn;
504132718Skan
505132718Skan  create_file_names (file_name);
506132718Skan  if (read_graph_file ())
507132718Skan    return;
508132718Skan
509132718Skan  if (!functions)
510132718Skan    {
511132718Skan      fnotice (stderr, "%s:no functions found\n", bbg_file_name);
512132718Skan      return;
513132718Skan    }
514132718Skan
515132718Skan  if (read_count_file ())
516132718Skan    return;
517132718Skan
518132718Skan  for (fn = functions; fn; fn = fn->next)
519132718Skan    solve_flow_graph (fn);
520132718Skan  for (src = sources; src; src = src->next)
521169689Skan    src->lines = XCNEWVEC (line_t, src->num_lines);
522132718Skan  for (fn = functions; fn; fn = fn->next)
523132718Skan    {
524132718Skan      coverage_t coverage;
525132718Skan
526132718Skan      memset (&coverage, 0, sizeof (coverage));
527132718Skan      coverage.name = fn->name;
528132718Skan      add_line_counts (flag_function_summary ? &coverage : NULL, fn);
529132718Skan      if (flag_function_summary)
530132718Skan	{
531132718Skan	  function_summary (&coverage, "Function");
532132718Skan	  fnotice (stdout, "\n");
533132718Skan	}
534132718Skan    }
535132718Skan
536132718Skan  for (src = sources; src; src = src->next)
537132718Skan    {
538132718Skan      accumulate_line_counts (src);
539132718Skan      function_summary (&src->coverage, "File");
540132718Skan      if (flag_gcov_file)
541132718Skan	{
542132718Skan	  char *gcov_file_name = make_gcov_file_name (file_name, src->name);
543132718Skan	  FILE *gcov_file = fopen (gcov_file_name, "w");
544132718Skan
545132718Skan	  if (gcov_file)
546132718Skan	    {
547169689Skan	      fnotice (stdout, "%s:creating '%s'\n",
548132718Skan		       src->name, gcov_file_name);
549132718Skan	      output_lines (gcov_file, src);
550132718Skan	      if (ferror (gcov_file))
551169689Skan		    fnotice (stderr, "%s:error writing output file '%s'\n",
552132718Skan			     src->name, gcov_file_name);
553132718Skan	      fclose (gcov_file);
554132718Skan	    }
555132718Skan	  else
556169689Skan	    fnotice (stderr, "%s:could not open output file '%s'\n",
557132718Skan		     src->name, gcov_file_name);
558132718Skan	  free (gcov_file_name);
559132718Skan	}
560132718Skan      fnotice (stdout, "\n");
561132718Skan    }
56250397Sobrien}
56350397Sobrien
564132718Skan/* Release all memory used.  */
56550397Sobrien
566132718Skanstatic void
567132718Skanrelease_structures (void)
568132718Skan{
569132718Skan  function_t *fn;
570132718Skan  source_t *src;
571132718Skan
572132718Skan  free (bbg_file_name);
573132718Skan  free (da_file_name);
574132718Skan  da_file_name = bbg_file_name = NULL;
575132718Skan  bbg_file_time = 0;
576132718Skan  bbg_stamp = 0;
577132718Skan
578132718Skan  while ((src = sources))
579132718Skan    {
580132718Skan      sources = src->next;
581132718Skan
582132718Skan      free (src->name);
583132718Skan      free (src->lines);
584132718Skan    }
585132718Skan
586132718Skan  while ((fn = functions))
587132718Skan    {
588132718Skan      unsigned ix;
589132718Skan      block_t *block;
590132718Skan
591132718Skan      functions = fn->next;
592132718Skan      for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
593132718Skan	{
594132718Skan	  arc_t *arc, *arc_n;
595132718Skan
596132718Skan	  for (arc = block->succ; arc; arc = arc_n)
597132718Skan	    {
598132718Skan	      arc_n = arc->succ_next;
599132718Skan	      free (arc);
600132718Skan	    }
601132718Skan	}
602132718Skan      free (fn->blocks);
603132718Skan      free (fn->counts);
604132718Skan    }
605132718Skan}
606132718Skan
607132718Skan/* Generate the names of the graph and data files. If OBJECT_DIRECTORY
608132718Skan   is not specified, these are looked for in the current directory,
609132718Skan   and named from the basename of the FILE_NAME sans extension. If
610117395Skan   OBJECT_DIRECTORY is specified and is a directory, the files are in
611132718Skan   that directory, but named from the basename of the FILE_NAME, sans
612132718Skan   extension. Otherwise OBJECT_DIRECTORY is taken to be the name of
613132718Skan   the object *file*, and the data files are named from that.  */
61450397Sobrien
61550397Sobrienstatic void
616132718Skancreate_file_names (const char *file_name)
61750397Sobrien{
61850397Sobrien  char *cptr;
619117395Skan  char *name;
620132718Skan  int length = strlen (file_name);
621117395Skan  int base;
622132718Skan
623117395Skan  if (object_directory && object_directory[0])
62450397Sobrien    {
625117395Skan      struct stat status;
62650397Sobrien
627117395Skan      length += strlen (object_directory) + 2;
628169689Skan      name = XNEWVEC (char, length);
629117395Skan      name[0] = 0;
630132718Skan
631117395Skan      base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
632117395Skan      strcat (name, object_directory);
633117395Skan      if (base && name[strlen (name) - 1] != '/')
634117395Skan	strcat (name, "/");
63550397Sobrien    }
63650397Sobrien  else
63750397Sobrien    {
638169689Skan      name = XNEWVEC (char, length + 1);
639117395Skan      name[0] = 0;
640117395Skan      base = 1;
64150397Sobrien    }
642132718Skan
643117395Skan  if (base)
644117395Skan    {
645132718Skan      /* Append source file name.  */
646132718Skan      cptr = strrchr (file_name, '/');
647132718Skan      strcat (name, cptr ? cptr + 1 : file_name);
648132718Skan    }
64950397Sobrien
650117395Skan  /* Remove the extension.  */
651117395Skan  cptr = strrchr (name, '.');
65250397Sobrien  if (cptr)
653117395Skan    *cptr = 0;
654132718Skan
655132718Skan  length = strlen (name);
656117395Skan
657169689Skan  bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1);
658132718Skan  strcpy (bbg_file_name, name);
659132718Skan  strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
66050397Sobrien
661169689Skan  da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1);
662117395Skan  strcpy (da_file_name, name);
663132718Skan  strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
66450397Sobrien
665169689Skan  free (name);
666132718Skan  return;
667132718Skan}
66850397Sobrien
669132718Skan/* Find or create a source file structure for FILE_NAME. Copies
670132718Skan   FILE_NAME on creation */
671117395Skan
672132718Skanstatic source_t *
673132718Skanfind_source (const char *file_name)
674132718Skan{
675132718Skan  source_t *src;
67690075Sobrien
677132718Skan  if (!file_name)
678132718Skan    file_name = "<unknown>";
67950397Sobrien
680132718Skan  for (src = sources; src; src = src->next)
681132718Skan    if (!strcmp (file_name, src->name))
682132718Skan      return src;
68350397Sobrien
684169689Skan  src = XCNEW (source_t);
685132718Skan  src->name = xstrdup (file_name);
686132718Skan  src->coverage.name = src->name;
687132718Skan  src->index = sources ? sources->index + 1 : 1;
688132718Skan  src->next = sources;
689132718Skan  sources = src;
69050397Sobrien
691132718Skan  return src;
69250397Sobrien}
69350397Sobrien
694132718Skan/* Read the graph file. Return nonzero on fatal error.  */
69550397Sobrien
696132718Skanstatic int
697132718Skanread_graph_file (void)
69850397Sobrien{
699132718Skan  unsigned version;
700132718Skan  unsigned current_tag = 0;
701132718Skan  struct function_info *fn = NULL;
702132718Skan  source_t *src = NULL;
703132718Skan  unsigned ix;
704132718Skan  unsigned tag;
70550397Sobrien
706132718Skan  if (!gcov_open (bbg_file_name, 1))
70750397Sobrien    {
708132718Skan      fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
709132718Skan      return 1;
71050397Sobrien    }
711132718Skan  bbg_file_time = gcov_time ();
712132718Skan  if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
713132718Skan    {
714132718Skan      fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
715132718Skan      gcov_close ();
716132718Skan      return 1;
717132718Skan    }
71850397Sobrien
719132718Skan  version = gcov_read_unsigned ();
720132718Skan  if (version != GCOV_VERSION)
721132718Skan    {
722132718Skan      char v[4], e[4];
72350397Sobrien
724132718Skan      GCOV_UNSIGNED2STRING (v, version);
725132718Skan      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
72650397Sobrien
727169689Skan      fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
728132718Skan	       bbg_file_name, v, e);
729132718Skan    }
730132718Skan  bbg_stamp = gcov_read_unsigned ();
731117395Skan
732132718Skan  while ((tag = gcov_read_unsigned ()))
733117395Skan    {
734132718Skan      unsigned length = gcov_read_unsigned ();
735132718Skan      gcov_position_t base = gcov_position ();
736117395Skan
737132718Skan      if (tag == GCOV_TAG_FUNCTION)
738117395Skan	{
739132718Skan	  char *function_name;
740132718Skan	  unsigned ident, checksum, lineno;
741132718Skan	  source_t *src;
742132718Skan	  function_t *probe, *prev;
743117395Skan
744132718Skan	  ident = gcov_read_unsigned ();
745132718Skan	  checksum = gcov_read_unsigned ();
746132718Skan	  function_name = xstrdup (gcov_read_string ());
747132718Skan	  src = find_source (gcov_read_string ());
748132718Skan	  lineno = gcov_read_unsigned ();
749117395Skan
750169689Skan	  fn = XCNEW (function_t);
751132718Skan	  fn->name = function_name;
752132718Skan	  fn->ident = ident;
753132718Skan	  fn->checksum = checksum;
754132718Skan	  fn->src = src;
755132718Skan	  fn->line = lineno;
756117395Skan
757132718Skan	  fn->next = functions;
758132718Skan	  functions = fn;
759132718Skan	  current_tag = tag;
760117395Skan
761132718Skan	  if (lineno >= src->num_lines)
762132718Skan	    src->num_lines = lineno + 1;
763132718Skan	  /* Now insert it into the source file's list of
764132718Skan	     functions. Normally functions will be encountered in
765132718Skan	     ascending order, so a simple scan is quick.  */
766132718Skan	  for (probe = src->functions, prev = NULL;
767132718Skan	       probe && probe->line > lineno;
768132718Skan	       prev = probe, probe = probe->line_next)
769132718Skan	    continue;
770132718Skan	  fn->line_next = probe;
771132718Skan	  if (prev)
772132718Skan	    prev->line_next = fn;
773132718Skan	  else
774132718Skan	    src->functions = fn;
775132718Skan	}
776132718Skan      else if (fn && tag == GCOV_TAG_BLOCKS)
777117395Skan	{
778132718Skan	  if (fn->blocks)
779169689Skan	    fnotice (stderr, "%s:already seen blocks for '%s'\n",
780132718Skan		     bbg_file_name, fn->name);
781117395Skan	  else
782117395Skan	    {
783132718Skan	      unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
784132718Skan	      fn->num_blocks = num_blocks;
785117395Skan
786169689Skan	      fn->blocks = XCNEWVEC (block_t, fn->num_blocks);
787132718Skan	      for (ix = 0; ix != num_blocks; ix++)
788132718Skan		fn->blocks[ix].flags = gcov_read_unsigned ();
789117395Skan	    }
790117395Skan	}
791132718Skan      else if (fn && tag == GCOV_TAG_ARCS)
792132718Skan	{
793132718Skan	  unsigned src = gcov_read_unsigned ();
794132718Skan	  unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
795117395Skan
796132718Skan	  if (src >= fn->num_blocks || fn->blocks[src].succ)
797132718Skan	    goto corrupt;
798117395Skan
799132718Skan	  while (num_dests--)
800132718Skan	    {
801132718Skan	      struct arc_info *arc;
802132718Skan	      unsigned dest = gcov_read_unsigned ();
803132718Skan	      unsigned flags = gcov_read_unsigned ();
804117395Skan
805132718Skan	      if (dest >= fn->num_blocks)
806132718Skan		goto corrupt;
807169689Skan	      arc = XCNEW (arc_t);
808117395Skan
809132718Skan	      arc->dst = &fn->blocks[dest];
810132718Skan	      arc->src = &fn->blocks[src];
811117395Skan
812132718Skan	      arc->count = 0;
813132718Skan	      arc->count_valid = 0;
814132718Skan	      arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
815132718Skan	      arc->fake = !!(flags & GCOV_ARC_FAKE);
816132718Skan	      arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
817117395Skan
818132718Skan	      arc->succ_next = fn->blocks[src].succ;
819132718Skan	      fn->blocks[src].succ = arc;
820132718Skan	      fn->blocks[src].num_succ++;
82150397Sobrien
822132718Skan	      arc->pred_next = fn->blocks[dest].pred;
823132718Skan	      fn->blocks[dest].pred = arc;
824132718Skan	      fn->blocks[dest].num_pred++;
82550397Sobrien
826132718Skan	      if (arc->fake)
827132718Skan		{
828132718Skan		  if (src)
829132718Skan		    {
830132718Skan		      /* Exceptional exit from this function, the
831132718Skan			 source block must be a call.  */
832132718Skan		      fn->blocks[src].is_call_site = 1;
833132718Skan		      arc->is_call_non_return = 1;
834132718Skan		    }
835132718Skan		  else
836132718Skan		    {
837132718Skan		      /* Non-local return from a callee of this
838132718Skan		         function. The destination block is a catch or
839132718Skan		         setjmp.  */
840132718Skan		      arc->is_nonlocal_return = 1;
841132718Skan		      fn->blocks[dest].is_nonlocal_return = 1;
842132718Skan		    }
843132718Skan		}
844117395Skan
845132718Skan	      if (!arc->on_tree)
846132718Skan		fn->num_counts++;
847132718Skan	    }
848132718Skan	}
849132718Skan      else if (fn && tag == GCOV_TAG_LINES)
850132718Skan	{
851132718Skan	  unsigned blockno = gcov_read_unsigned ();
852169689Skan	  unsigned *line_nos = XCNEWVEC (unsigned, length - 1);
853117395Skan
854132718Skan	  if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
855132718Skan	    goto corrupt;
856117395Skan
857132718Skan	  for (ix = 0; ;  )
858132718Skan	    {
859132718Skan	      unsigned lineno = gcov_read_unsigned ();
860117395Skan
861132718Skan	      if (lineno)
862132718Skan		{
863132718Skan		  if (!ix)
864132718Skan		    {
865132718Skan		      line_nos[ix++] = 0;
866132718Skan		      line_nos[ix++] = src->index;
867132718Skan		    }
868132718Skan		  line_nos[ix++] = lineno;
869132718Skan		  if (lineno >= src->num_lines)
870132718Skan		    src->num_lines = lineno + 1;
871132718Skan		}
872132718Skan	      else
873132718Skan		{
874132718Skan		  const char *file_name = gcov_read_string ();
875117395Skan
876132718Skan		  if (!file_name)
877132718Skan		    break;
878132718Skan		  src = find_source (file_name);
87950397Sobrien
880132718Skan		  line_nos[ix++] = 0;
881132718Skan		  line_nos[ix++] = src->index;
882132718Skan		}
883132718Skan	    }
88450397Sobrien
885132718Skan	  fn->blocks[blockno].u.line.encoding = line_nos;
886132718Skan	  fn->blocks[blockno].u.line.num = ix;
887132718Skan	}
888132718Skan      else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
88950397Sobrien	{
890132718Skan	  fn = NULL;
891132718Skan	  current_tag = 0;
89250397Sobrien	}
893132718Skan      gcov_sync (base, length);
894132718Skan      if (gcov_is_error ())
895169689Skan	{
896169689Skan	corrupt:;
897169689Skan	  fnotice (stderr, "%s:corrupted\n", bbg_file_name);
898169689Skan	  gcov_close ();
899169689Skan	  return 1;
900169689Skan	}
90150397Sobrien    }
902132718Skan  gcov_close ();
90350397Sobrien
904132718Skan  /* We built everything backwards, so nreverse them all.  */
90550397Sobrien
906132718Skan  /* Reverse sources. Not strictly necessary, but we'll then process
907132718Skan     them in the 'expected' order.  */
908132718Skan  {
909132718Skan    source_t *src, *src_p, *src_n;
91050397Sobrien
911132718Skan    for (src_p = NULL, src = sources; src; src_p = src, src = src_n)
912132718Skan      {
913132718Skan	src_n = src->next;
914132718Skan	src->next = src_p;
915132718Skan      }
916132718Skan    sources =  src_p;
917132718Skan  }
91850397Sobrien
919132718Skan  /* Reverse functions.  */
920132718Skan  {
921132718Skan    function_t *fn, *fn_p, *fn_n;
92250397Sobrien
923132718Skan    for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn_n)
924132718Skan      {
925132718Skan	unsigned ix;
926117395Skan
927132718Skan	fn_n = fn->next;
928132718Skan	fn->next = fn_p;
929117395Skan
930132718Skan	/* Reverse the arcs.  */
931132718Skan	for (ix = fn->num_blocks; ix--;)
932132718Skan	  {
933132718Skan	    arc_t *arc, *arc_p, *arc_n;
93450397Sobrien
935132718Skan	    for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
936132718Skan		 arc_p = arc, arc = arc_n)
937132718Skan	      {
938132718Skan		arc_n = arc->succ_next;
939132718Skan		arc->succ_next = arc_p;
940132718Skan	      }
941132718Skan	    fn->blocks[ix].succ = arc_p;
94250397Sobrien
943132718Skan	    for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
944132718Skan		 arc_p = arc, arc = arc_n)
945132718Skan	      {
946132718Skan		arc_n = arc->pred_next;
947132718Skan		arc->pred_next = arc_p;
948132718Skan	      }
949132718Skan	    fn->blocks[ix].pred = arc_p;
950132718Skan	  }
951132718Skan      }
952132718Skan    functions = fn_p;
953132718Skan  }
954132718Skan  return 0;
95550397Sobrien}
95690075Sobrien
957132718Skan/* Reads profiles from the count file and attach to each
958132718Skan   function. Return nonzero if fatal error.  */
959132718Skan
960132718Skanstatic int
961132718Skanread_count_file (void)
96250397Sobrien{
963132718Skan  unsigned ix;
964132718Skan  unsigned version;
965132718Skan  unsigned tag;
966132718Skan  function_t *fn = NULL;
967132718Skan  int error = 0;
96850397Sobrien
969132718Skan  if (!gcov_open (da_file_name, 1))
970132718Skan    {
971169689Skan      fnotice (stderr, "%s:cannot open data file, assuming not executed\n",
972169689Skan	       da_file_name);
973169689Skan      no_data_file = 1;
974169689Skan      return 0;
975132718Skan    }
976132718Skan  if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
977132718Skan    {
978132718Skan      fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
979132718Skan    cleanup:;
980132718Skan      gcov_close ();
981132718Skan      return 1;
982132718Skan    }
983132718Skan  version = gcov_read_unsigned ();
984132718Skan  if (version != GCOV_VERSION)
985132718Skan    {
986132718Skan      char v[4], e[4];
98750397Sobrien
988132718Skan      GCOV_UNSIGNED2STRING (v, version);
989132718Skan      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
990132718Skan
991169689Skan      fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
992132718Skan	       da_file_name, v, e);
993132718Skan    }
994132718Skan  tag = gcov_read_unsigned ();
995132718Skan  if (tag != bbg_stamp)
996132718Skan    {
997132718Skan      fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
998132718Skan      goto cleanup;
999132718Skan    }
100050397Sobrien
1001132718Skan  while ((tag = gcov_read_unsigned ()))
100250397Sobrien    {
1003132718Skan      unsigned length = gcov_read_unsigned ();
1004132718Skan      unsigned long base = gcov_position ();
100550397Sobrien
1006132718Skan      if (tag == GCOV_TAG_OBJECT_SUMMARY)
1007132718Skan	gcov_read_summary (&object_summary);
1008132718Skan      else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1009132718Skan	program_count++;
1010132718Skan      else if (tag == GCOV_TAG_FUNCTION)
101150397Sobrien	{
1012132718Skan	  unsigned ident = gcov_read_unsigned ();
1013132718Skan	  struct function_info *fn_n = functions;
1014132718Skan
1015132718Skan	  for (fn = fn ? fn->next : NULL; ; fn = fn->next)
101650397Sobrien	    {
1017132718Skan	      if (fn)
1018132718Skan		;
1019132718Skan	      else if ((fn = fn_n))
1020132718Skan		fn_n = NULL;
1021132718Skan	      else
102250397Sobrien		{
1023169689Skan		  fnotice (stderr, "%s:unknown function '%u'\n",
1024132718Skan			   da_file_name, ident);
1025132718Skan		  break;
102650397Sobrien		}
1027132718Skan	      if (fn->ident == ident)
1028132718Skan		break;
102950397Sobrien	    }
1030132718Skan
1031132718Skan	  if (!fn)
1032132718Skan	    ;
1033132718Skan	  else if (gcov_read_unsigned () != fn->checksum)
103450397Sobrien	    {
1035132718Skan	    mismatch:;
1036169689Skan	      fnotice (stderr, "%s:profile mismatch for '%s'\n",
1037132718Skan		       da_file_name, fn->name);
1038132718Skan	      goto cleanup;
1039132718Skan	    }
1040132718Skan	}
1041132718Skan      else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1042132718Skan	{
1043132718Skan	  if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
1044132718Skan	    goto mismatch;
104550397Sobrien
1046132718Skan	  if (!fn->counts)
1047169689Skan	    fn->counts = XCNEWVEC (gcov_type, fn->num_counts);
104850397Sobrien
1049132718Skan	  for (ix = 0; ix != fn->num_counts; ix++)
1050132718Skan	    fn->counts[ix] += gcov_read_counter ();
105150397Sobrien	}
1052132718Skan      gcov_sync (base, length);
1053132718Skan      if ((error = gcov_is_error ()))
1054169689Skan	{
1055169689Skan	  fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1056169689Skan		   da_file_name);
1057169689Skan	  goto cleanup;
1058169689Skan	}
105950397Sobrien    }
106090075Sobrien
1061132718Skan  gcov_close ();
1062132718Skan  return 0;
106350397Sobrien}
106450397Sobrien
1065132718Skan/* Solve the flow graph. Propagate counts from the instrumented arcs
1066132718Skan   to the blocks and the uninstrumented arcs.  */
106750397Sobrien
106850397Sobrienstatic void
1069132718Skansolve_flow_graph (function_t *fn)
107050397Sobrien{
1071132718Skan  unsigned ix;
1072132718Skan  arc_t *arc;
1073132718Skan  gcov_type *count_ptr = fn->counts;
1074132718Skan  block_t *blk;
1075132718Skan  block_t *valid_blocks = NULL;    /* valid, but unpropagated blocks.  */
1076132718Skan  block_t *invalid_blocks = NULL;  /* invalid, but inferable blocks.  */
107750397Sobrien
1078132718Skan  if (fn->num_blocks < 2)
1079169689Skan    fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
1080132718Skan	     bbg_file_name, fn->name);
1081132718Skan  else
108250397Sobrien    {
1083132718Skan      if (fn->blocks[0].num_pred)
1084169689Skan	fnotice (stderr, "%s:'%s' has arcs to entry block\n",
1085132718Skan		 bbg_file_name, fn->name);
1086132718Skan      else
1087132718Skan	/* We can't deduce the entry block counts from the lack of
1088132718Skan	   predecessors.  */
1089132718Skan	fn->blocks[0].num_pred = ~(unsigned)0;
109050397Sobrien
1091132718Skan      if (fn->blocks[fn->num_blocks - 1].num_succ)
1092169689Skan	fnotice (stderr, "%s:'%s' has arcs from exit block\n",
1093132718Skan		 bbg_file_name, fn->name);
109450397Sobrien      else
1095132718Skan	/* Likewise, we can't deduce exit block counts from the lack
1096132718Skan	   of its successors.  */
1097132718Skan	fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0;
109850397Sobrien    }
109950397Sobrien
1100132718Skan  /* Propagate the measured counts, this must be done in the same
1101132718Skan     order as the code in profile.c  */
1102132718Skan  for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
1103132718Skan    {
1104132718Skan      block_t const *prev_dst = NULL;
1105132718Skan      int out_of_order = 0;
1106132718Skan      int non_fake_succ = 0;
110750397Sobrien
1108132718Skan      for (arc = blk->succ; arc; arc = arc->succ_next)
1109132718Skan	{
1110132718Skan	  if (!arc->fake)
1111132718Skan	    non_fake_succ++;
111250397Sobrien
1113132718Skan	  if (!arc->on_tree)
1114132718Skan	    {
1115132718Skan	      if (count_ptr)
1116132718Skan		arc->count = *count_ptr++;
1117132718Skan	      arc->count_valid = 1;
1118132718Skan	      blk->num_succ--;
1119132718Skan	      arc->dst->num_pred--;
1120132718Skan	    }
1121132718Skan	  if (prev_dst && prev_dst > arc->dst)
1122132718Skan	    out_of_order = 1;
1123132718Skan	  prev_dst = arc->dst;
1124132718Skan	}
1125132718Skan      if (non_fake_succ == 1)
1126132718Skan	{
1127132718Skan	  /* If there is only one non-fake exit, it is an
1128132718Skan	     unconditional branch.  */
1129132718Skan	  for (arc = blk->succ; arc; arc = arc->succ_next)
1130132718Skan	    if (!arc->fake)
1131132718Skan	      {
1132132718Skan		arc->is_unconditional = 1;
1133132718Skan		/* If this block is instrumenting a call, it might be
1134132718Skan		   an artificial block. It is not artificial if it has
1135132718Skan		   a non-fallthrough exit, or the destination of this
1136132718Skan		   arc has more than one entry.  Mark the destination
1137132718Skan		   block as a return site, if none of those conditions
1138132718Skan		   hold.  */
1139132718Skan		if (blk->is_call_site && arc->fall_through
1140132718Skan		    && arc->dst->pred == arc && !arc->pred_next)
1141132718Skan		  arc->dst->is_call_return = 1;
1142132718Skan	      }
1143132718Skan	}
114450397Sobrien
1145132718Skan      /* Sort the successor arcs into ascending dst order. profile.c
1146132718Skan	 normally produces arcs in the right order, but sometimes with
1147132718Skan	 one or two out of order.  We're not using a particularly
1148132718Skan	 smart sort.  */
1149132718Skan      if (out_of_order)
1150132718Skan	{
1151132718Skan	  arc_t *start = blk->succ;
1152132718Skan	  unsigned changes = 1;
115390075Sobrien
1154132718Skan	  while (changes)
1155132718Skan	    {
1156132718Skan	      arc_t *arc, *arc_p, *arc_n;
115750397Sobrien
1158132718Skan	      changes = 0;
1159132718Skan	      for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1160132718Skan		{
1161132718Skan		  if (arc->dst > arc_n->dst)
1162132718Skan		    {
1163132718Skan		      changes = 1;
1164132718Skan		      if (arc_p)
1165132718Skan			arc_p->succ_next = arc_n;
1166132718Skan		      else
1167132718Skan			start = arc_n;
1168132718Skan		      arc->succ_next = arc_n->succ_next;
1169132718Skan		      arc_n->succ_next = arc;
1170132718Skan		      arc_p = arc_n;
1171132718Skan		    }
1172132718Skan		  else
1173132718Skan		    {
1174132718Skan		      arc_p = arc;
1175132718Skan		      arc = arc_n;
1176132718Skan		    }
1177132718Skan		}
1178132718Skan	    }
1179132718Skan	  blk->succ = start;
1180132718Skan	}
118150397Sobrien
1182132718Skan      /* Place it on the invalid chain, it will be ignored if that's
1183132718Skan	 wrong.  */
1184132718Skan      blk->invalid_chain = 1;
1185132718Skan      blk->chain = invalid_blocks;
1186132718Skan      invalid_blocks = blk;
1187132718Skan    }
118850397Sobrien
1189132718Skan  while (invalid_blocks || valid_blocks)
1190132718Skan    {
1191132718Skan      while ((blk = invalid_blocks))
1192132718Skan	{
1193132718Skan	  gcov_type total = 0;
1194132718Skan	  const arc_t *arc;
119550397Sobrien
1196132718Skan	  invalid_blocks = blk->chain;
1197132718Skan	  blk->invalid_chain = 0;
1198132718Skan	  if (!blk->num_succ)
1199132718Skan	    for (arc = blk->succ; arc; arc = arc->succ_next)
1200132718Skan	      total += arc->count;
1201132718Skan	  else if (!blk->num_pred)
1202132718Skan	    for (arc = blk->pred; arc; arc = arc->pred_next)
1203132718Skan	      total += arc->count;
1204132718Skan	  else
1205132718Skan	    continue;
120650397Sobrien
1207132718Skan	  blk->count = total;
1208132718Skan	  blk->count_valid = 1;
1209132718Skan	  blk->chain = valid_blocks;
1210132718Skan	  blk->valid_chain = 1;
1211132718Skan	  valid_blocks = blk;
1212132718Skan	}
1213132718Skan      while ((blk = valid_blocks))
121450397Sobrien	{
1215132718Skan	  gcov_type total;
1216132718Skan	  arc_t *arc, *inv_arc;
121750397Sobrien
1218132718Skan	  valid_blocks = blk->chain;
1219132718Skan	  blk->valid_chain = 0;
1220132718Skan	  if (blk->num_succ == 1)
122150397Sobrien	    {
1222132718Skan	      block_t *dst;
1223132718Skan
1224132718Skan	      total = blk->count;
1225132718Skan	      inv_arc = NULL;
1226132718Skan	      for (arc = blk->succ; arc; arc = arc->succ_next)
1227132718Skan		{
1228132718Skan		  total -= arc->count;
1229132718Skan		  if (!arc->count_valid)
1230132718Skan		    inv_arc = arc;
1231132718Skan		}
1232132718Skan	      dst = inv_arc->dst;
1233132718Skan	      inv_arc->count_valid = 1;
1234132718Skan	      inv_arc->count = total;
1235132718Skan	      blk->num_succ--;
1236132718Skan	      dst->num_pred--;
1237132718Skan	      if (dst->count_valid)
1238132718Skan		{
1239132718Skan		  if (dst->num_pred == 1 && !dst->valid_chain)
1240132718Skan		    {
1241132718Skan		      dst->chain = valid_blocks;
1242132718Skan		      dst->valid_chain = 1;
1243132718Skan		      valid_blocks = dst;
1244132718Skan		    }
1245132718Skan		}
1246132718Skan	      else
1247132718Skan		{
1248132718Skan		  if (!dst->num_pred && !dst->invalid_chain)
1249132718Skan		    {
1250132718Skan		      dst->chain = invalid_blocks;
1251132718Skan		      dst->invalid_chain = 1;
1252132718Skan		      invalid_blocks = dst;
1253132718Skan		    }
1254132718Skan		}
125550397Sobrien	    }
1256132718Skan	  if (blk->num_pred == 1)
1257132718Skan	    {
1258132718Skan	      block_t *src;
125950397Sobrien
1260132718Skan	      total = blk->count;
1261132718Skan	      inv_arc = NULL;
1262132718Skan	      for (arc = blk->pred; arc; arc = arc->pred_next)
1263132718Skan		{
1264132718Skan		  total -= arc->count;
1265132718Skan		  if (!arc->count_valid)
1266132718Skan		    inv_arc = arc;
1267132718Skan		}
1268132718Skan	      src = inv_arc->src;
1269132718Skan	      inv_arc->count_valid = 1;
1270132718Skan	      inv_arc->count = total;
1271132718Skan	      blk->num_pred--;
1272132718Skan	      src->num_succ--;
1273132718Skan	      if (src->count_valid)
1274132718Skan		{
1275132718Skan		  if (src->num_succ == 1 && !src->valid_chain)
1276132718Skan		    {
1277132718Skan		      src->chain = valid_blocks;
1278132718Skan		      src->valid_chain = 1;
1279132718Skan		      valid_blocks = src;
1280132718Skan		    }
1281132718Skan		}
1282132718Skan	      else
1283132718Skan		{
1284132718Skan		  if (!src->num_succ && !src->invalid_chain)
1285132718Skan		    {
1286132718Skan		      src->chain = invalid_blocks;
1287132718Skan		      src->invalid_chain = 1;
1288132718Skan		      invalid_blocks = src;
1289132718Skan		    }
1290132718Skan		}
1291132718Skan	    }
129250397Sobrien	}
1293132718Skan    }
129450397Sobrien
1295132718Skan  /* If the graph has been correctly solved, every block will have a
1296132718Skan     valid count.  */
1297132718Skan  for (ix = 0; ix < fn->num_blocks; ix++)
1298132718Skan    if (!fn->blocks[ix].count_valid)
1299132718Skan      {
1300169689Skan	fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
1301132718Skan		 bbg_file_name, fn->name);
1302132718Skan	break;
1303132718Skan      }
130450397Sobrien}
1305132718Skan
130650397Sobrien
130750397Sobrien
1308132718Skan/* Increment totals in COVERAGE according to arc ARC.  */
130950397Sobrien
1310117395Skanstatic void
1311132718Skanadd_branch_counts (coverage_t *coverage, const arc_t *arc)
1312117395Skan{
1313132718Skan  if (arc->is_call_non_return)
1314117395Skan    {
1315132718Skan      coverage->calls++;
1316132718Skan      if (arc->src->count)
1317132718Skan	coverage->calls_executed++;
1318117395Skan    }
1319132718Skan  else if (!arc->is_unconditional)
1320117395Skan    {
1321132718Skan      coverage->branches++;
1322132718Skan      if (arc->src->count)
1323132718Skan	coverage->branches_executed++;
1324132718Skan      if (arc->count)
1325132718Skan	coverage->branches_taken++;
1326117395Skan    }
1327117395Skan}
1328117395Skan
1329117395Skan/* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1330117395Skan   count.  If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1331117395Skan   If DP is zero, no decimal point is printed. Only print 100% when
1332117395Skan   TOP==BOTTOM and only print 0% when TOP=0.  If dp < 0, then simply
1333117395Skan   format TOP.  Return pointer to a static string.  */
1334117395Skan
1335117395Skanstatic char const *
1336132718Skanformat_gcov (gcov_type top, gcov_type bottom, int dp)
1337117395Skan{
1338117395Skan  static char buffer[20];
1339132718Skan
1340117395Skan  if (dp >= 0)
1341117395Skan    {
1342117395Skan      float ratio = bottom ? (float)top / bottom : 0;
1343117395Skan      int ix;
1344117395Skan      unsigned limit = 100;
1345117395Skan      unsigned percent;
1346132718Skan
1347117395Skan      for (ix = dp; ix--; )
1348117395Skan	limit *= 10;
1349132718Skan
1350117395Skan      percent = (unsigned) (ratio * limit + (float)0.5);
1351117395Skan      if (percent <= 0 && top)
1352117395Skan	percent = 1;
1353117395Skan      else if (percent >= limit && top != bottom)
1354117395Skan	percent = limit - 1;
1355117395Skan      ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1356117395Skan      if (dp)
135750397Sobrien	{
1358117395Skan	  dp++;
1359117395Skan	  do
136050397Sobrien	    {
1361117395Skan	      buffer[ix+1] = buffer[ix];
1362117395Skan	      ix--;
136350397Sobrien	    }
1364117395Skan	  while (dp--);
1365117395Skan	  buffer[ix + 1] = '.';
136650397Sobrien	}
136750397Sobrien    }
1368117395Skan  else
1369132718Skan    sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
1370132718Skan
1371117395Skan  return buffer;
137250397Sobrien}
137350397Sobrien
1374117395Skan
137550397Sobrien/* Output summary info for a function.  */
137650397Sobrien
137750397Sobrienstatic void
1378132718Skanfunction_summary (const coverage_t *coverage, const char *title)
137950397Sobrien{
1380169689Skan  fnotice (stdout, "%s '%s'\n", title, coverage->name);
1381132718Skan
1382132718Skan  if (coverage->lines)
1383132718Skan    fnotice (stdout, "Lines executed:%s of %d\n",
1384132718Skan	     format_gcov (coverage->lines_executed, coverage->lines, 2),
1385132718Skan	     coverage->lines);
138650397Sobrien  else
1387169689Skan    fnotice (stdout, "No executable lines\n");
138850397Sobrien
1389132718Skan  if (flag_branches)
139050397Sobrien    {
1391132718Skan      if (coverage->branches)
139250397Sobrien	{
1393132718Skan	  fnotice (stdout, "Branches executed:%s of %d\n",
1394132718Skan		   format_gcov (coverage->branches_executed,
1395132718Skan				coverage->branches, 2),
1396132718Skan		   coverage->branches);
1397132718Skan	  fnotice (stdout, "Taken at least once:%s of %d\n",
1398132718Skan		   format_gcov (coverage->branches_taken,
1399132718Skan				coverage->branches, 2),
1400132718Skan		   coverage->branches);
140150397Sobrien	}
140250397Sobrien      else
1403132718Skan	fnotice (stdout, "No branches\n");
1404132718Skan      if (coverage->calls)
1405132718Skan	fnotice (stdout, "Calls executed:%s of %d\n",
1406132718Skan		 format_gcov (coverage->calls_executed, coverage->calls, 2),
1407132718Skan		 coverage->calls);
140850397Sobrien      else
1409132718Skan	fnotice (stdout, "No calls\n");
141050397Sobrien    }
141150397Sobrien}
141250397Sobrien
1413117395Skan/* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1414117395Skan   affect name generation. With preserve_paths we create a filename
1415117395Skan   from all path components of the source file, replacing '/' with
1416117395Skan   '#', without it we simply take the basename component. With
1417117395Skan   long_output_names we prepend the processed name of the input file
1418117395Skan   to each output name (except when the current source file is the
1419117395Skan   input file, so you don't get a double concatenation). The two
1420117395Skan   components are separated by '##'. Also '.' filename components are
1421117395Skan   removed and '..'  components are renamed to '^'.  */
142250397Sobrien
1423117395Skanstatic char *
1424132718Skanmake_gcov_file_name (const char *input_name, const char *src_name)
1425117395Skan{
1426117395Skan  char *cptr;
1427169689Skan  char *name = XNEWVEC (char, strlen (src_name) + strlen (input_name) + 10);
1428132718Skan
1429117395Skan  name[0] = 0;
1430132718Skan  if (flag_long_names && strcmp (src_name, input_name))
1431117395Skan    {
1432117395Skan      /* Generate the input filename part.  */
1433132718Skan      cptr = flag_preserve_paths ? NULL : strrchr (input_name, '/');
1434132718Skan      strcat (name, cptr ? cptr + 1 : input_name);
1435117395Skan      strcat (name, "##");
1436117395Skan    }
1437132718Skan
1438117395Skan  /* Generate the source filename part.  */
1439132718Skan  cptr = flag_preserve_paths ? NULL : strrchr (src_name, '/');
1440132718Skan  strcat (name, cptr ? cptr + 1 : src_name);
1441132718Skan
1442132718Skan  if (flag_preserve_paths)
1443117395Skan    {
1444117395Skan      /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1445117395Skan      char *prev;
1446132718Skan
1447117395Skan      for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
1448132718Skan	{
1449132718Skan	  unsigned shift = 0;
1450132718Skan
1451132718Skan	  if (prev + 1 == cptr && prev[0] == '.')
1452132718Skan	    {
1453132718Skan	      /* Remove '.' */
1454132718Skan	      shift = 2;
1455132718Skan	    }
1456132718Skan	  else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
1457132718Skan	    {
1458132718Skan	      /* Convert '..' */
1459132718Skan	      shift = 1;
1460132718Skan	      prev[1] = '^';
1461132718Skan	    }
1462132718Skan	  else
1463132718Skan	    *cptr++ = '#';
1464132718Skan	  if (shift)
1465132718Skan	    {
1466132718Skan	      cptr = prev;
1467132718Skan	      do
1468132718Skan		prev[0] = prev[shift];
1469117395Skan	      while (*prev++);
1470132718Skan	    }
1471132718Skan	}
1472117395Skan    }
1473132718Skan
1474117395Skan  strcat (name, ".gcov");
1475117395Skan  return name;
1476117395Skan}
1477117395Skan
1478132718Skan/* Scan through the bb_data for each line in the block, increment
1479117395Skan   the line number execution count indicated by the execution count of
1480117395Skan   the appropriate basic block.  */
1481117395Skan
148250397Sobrienstatic void
1483132718Skanadd_line_counts (coverage_t *coverage, function_t *fn)
148450397Sobrien{
1485132718Skan  unsigned ix;
1486132718Skan  line_t *line = NULL; /* This is propagated from one iteration to the
1487132718Skan			  next.  */
1488132718Skan
1489132718Skan  /* Scan each basic block.  */
1490132718Skan  for (ix = 0; ix != fn->num_blocks; ix++)
149150397Sobrien    {
1492132718Skan      block_t *block = &fn->blocks[ix];
1493132718Skan      unsigned *encoding;
1494132718Skan      const source_t *src = NULL;
1495132718Skan      unsigned jx;
1496132718Skan
1497132718Skan      if (block->count && ix && ix + 1 != fn->num_blocks)
1498132718Skan	fn->blocks_executed++;
1499132718Skan      for (jx = 0, encoding = block->u.line.encoding;
1500132718Skan	   jx != block->u.line.num; jx++, encoding++)
1501132718Skan	if (!*encoding)
1502132718Skan	  {
1503132718Skan	    unsigned src_n = *++encoding;
1504132718Skan
1505132718Skan	    for (src = sources; src->index != src_n; src = src->next)
1506132718Skan	      continue;
1507132718Skan	    jx++;
1508132718Skan	  }
1509132718Skan	else
1510132718Skan	  {
1511132718Skan	    line = &src->lines[*encoding];
1512132718Skan
1513132718Skan	    if (coverage)
1514132718Skan	      {
1515132718Skan		if (!line->exists)
1516132718Skan		  coverage->lines++;
1517132718Skan		if (!line->count && block->count)
1518132718Skan		  coverage->lines_executed++;
1519132718Skan	      }
1520132718Skan	    line->exists = 1;
1521132718Skan	    line->count += block->count;
1522132718Skan	  }
1523132718Skan      free (block->u.line.encoding);
1524132718Skan      block->u.cycle.arc = NULL;
1525132718Skan      block->u.cycle.ident = ~0U;
1526132718Skan
1527132718Skan      if (!ix || ix + 1 == fn->num_blocks)
1528132718Skan	/* Entry or exit block */;
1529132718Skan      else if (flag_all_blocks)
153050397Sobrien	{
1531132718Skan	  line_t *block_line = line ? line : &fn->src->lines[fn->line];
1532117395Skan
1533132718Skan	  block->chain = block_line->u.blocks;
1534132718Skan	  block_line->u.blocks = block;
1535132718Skan	}
1536132718Skan      else if (flag_branches)
1537132718Skan	{
1538132718Skan	  arc_t *arc;
1539132718Skan
1540132718Skan	  for (arc = block->succ; arc; arc = arc->succ_next)
1541117395Skan	    {
1542132718Skan	      arc->line_next = line->u.branches;
1543132718Skan	      line->u.branches = arc;
1544132718Skan	      if (coverage && !arc->is_unconditional)
1545132718Skan		add_branch_counts (coverage, arc);
1546117395Skan	    }
154750397Sobrien	}
1548132718Skan    }
1549132718Skan  if (!line)
1550169689Skan    fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
1551132718Skan}
1552132718Skan
1553132718Skan/* Accumulate the line counts of a file.  */
1554132718Skan
1555132718Skanstatic void
1556132718Skanaccumulate_line_counts (source_t *src)
1557132718Skan{
1558132718Skan  line_t *line;
1559132718Skan  function_t *fn, *fn_p, *fn_n;
1560132718Skan  unsigned ix;
1561132718Skan
1562132718Skan  /* Reverse the function order.  */
1563132718Skan  for (fn = src->functions, fn_p = NULL; fn;
1564132718Skan       fn_p = fn, fn = fn_n)
1565132718Skan    {
1566132718Skan      fn_n = fn->line_next;
1567132718Skan      fn->line_next = fn_p;
1568132718Skan    }
1569132718Skan  src->functions = fn_p;
1570132718Skan
1571132718Skan  for (ix = src->num_lines, line = src->lines; ix--; line++)
1572132718Skan    {
1573132718Skan      if (!flag_all_blocks)
157450397Sobrien	{
1575132718Skan	  arc_t *arc, *arc_p, *arc_n;
1576132718Skan
1577132718Skan	  /* Total and reverse the branch information.  */
1578132718Skan	  for (arc = line->u.branches, arc_p = NULL; arc;
1579132718Skan	       arc_p = arc, arc = arc_n)
158050397Sobrien	    {
1581132718Skan	      arc_n = arc->line_next;
1582132718Skan	      arc->line_next = arc_p;
1583132718Skan
1584132718Skan	      add_branch_counts (&src->coverage, arc);
158550397Sobrien	    }
1586132718Skan	  line->u.branches = arc_p;
158750397Sobrien	}
1588132718Skan      else if (line->u.blocks)
158950397Sobrien	{
1590132718Skan	  /* The user expects the line count to be the number of times
1591132718Skan	     a line has been executed. Simply summing the block count
1592132718Skan	     will give an artificially high number.  The Right Thing
1593132718Skan	     is to sum the entry counts to the graph of blocks on this
1594132718Skan	     line, then find the elementary cycles of the local graph
1595132718Skan	     and add the transition counts of those cycles.  */
1596132718Skan	  block_t *block, *block_p, *block_n;
1597132718Skan	  gcov_type count = 0;
1598132718Skan
1599132718Skan	  /* Reverse the block information.  */
1600132718Skan	  for (block = line->u.blocks, block_p = NULL; block;
1601132718Skan	       block_p = block, block = block_n)
160250397Sobrien	    {
1603132718Skan	      block_n = block->chain;
1604132718Skan	      block->chain = block_p;
1605132718Skan	      block->u.cycle.ident = ix;
160650397Sobrien	    }
1607132718Skan	  line->u.blocks = block_p;
160850397Sobrien
1609132718Skan	  /* Sum the entry arcs.  */
1610132718Skan	  for (block = line->u.blocks; block; block = block->chain)
161150397Sobrien	    {
1612132718Skan	      arc_t *arc;
1613132718Skan
1614132718Skan	      for (arc = block->pred; arc; arc = arc->pred_next)
1615132718Skan		{
1616132718Skan		  if (arc->src->u.cycle.ident != ix)
1617132718Skan		    count += arc->count;
1618132718Skan		  if (flag_branches)
1619132718Skan		    add_branch_counts (&src->coverage, arc);
1620132718Skan		}
1621132718Skan
1622132718Skan	      /* Initialize the cs_count.  */
1623132718Skan	      for (arc = block->succ; arc; arc = arc->succ_next)
1624132718Skan		arc->cs_count = arc->count;
1625117395Skan	    }
1626132718Skan
1627132718Skan	  /* Find the loops. This uses the algorithm described in
1628132718Skan	     Tiernan 'An Efficient Search Algorithm to Find the
1629132718Skan	     Elementary Circuits of a Graph', CACM Dec 1970. We hold
1630132718Skan	     the P array by having each block point to the arc that
1631132718Skan	     connects to the previous block. The H array is implicitly
1632132718Skan	     held because of the arc ordering, and the block's
1633132718Skan	     previous arc pointer.
1634132718Skan
1635132718Skan	     Although the algorithm is O(N^3) for highly connected
1636132718Skan	     graphs, at worst we'll have O(N^2), as most blocks have
1637132718Skan	     only one or two exits. Most graphs will be small.
1638132718Skan
1639132718Skan	     For each loop we find, locate the arc with the smallest
1640132718Skan	     transition count, and add that to the cumulative
1641132718Skan	     count.  Decrease flow over the cycle and remove the arc
1642132718Skan	     from consideration.  */
1643132718Skan	  for (block = line->u.blocks; block; block = block->chain)
1644132718Skan	    {
1645132718Skan	      block_t *head = block;
1646132718Skan	      arc_t *arc;
1647132718Skan
1648132718Skan	    next_vertex:;
1649132718Skan	      arc = head->succ;
1650132718Skan	    current_vertex:;
1651132718Skan	      while (arc)
1652132718Skan		{
1653132718Skan		  block_t *dst = arc->dst;
1654132718Skan		  if (/* Already used that arc.  */
1655132718Skan		      arc->cycle
1656132718Skan		      /* Not to same graph, or before first vertex.  */
1657132718Skan		      || dst->u.cycle.ident != ix
1658132718Skan		      /* Already in path.  */
1659132718Skan		      || dst->u.cycle.arc)
1660132718Skan		    {
1661132718Skan		      arc = arc->succ_next;
1662132718Skan		      continue;
1663132718Skan		    }
1664132718Skan
1665132718Skan		  if (dst == block)
1666132718Skan		    {
1667132718Skan		      /* Found a closing arc.  */
1668132718Skan		      gcov_type cycle_count = arc->cs_count;
1669132718Skan		      arc_t *cycle_arc = arc;
1670132718Skan		      arc_t *probe_arc;
1671132718Skan
1672132718Skan		      /* Locate the smallest arc count of the loop.  */
1673132718Skan		      for (dst = head; (probe_arc = dst->u.cycle.arc);
1674132718Skan			   dst = probe_arc->src)
1675132718Skan			if (cycle_count > probe_arc->cs_count)
1676132718Skan			  {
1677132718Skan			    cycle_count = probe_arc->cs_count;
1678132718Skan			    cycle_arc = probe_arc;
1679132718Skan			  }
1680132718Skan
1681132718Skan		      count += cycle_count;
1682132718Skan		      cycle_arc->cycle = 1;
1683132718Skan
1684132718Skan		      /* Remove the flow from the cycle.  */
1685132718Skan		      arc->cs_count -= cycle_count;
1686132718Skan		      for (dst = head; (probe_arc = dst->u.cycle.arc);
1687132718Skan			   dst = probe_arc->src)
1688132718Skan			probe_arc->cs_count -= cycle_count;
1689132718Skan
1690132718Skan		      /* Unwind to the cyclic arc.  */
1691132718Skan		      while (head != cycle_arc->src)
1692132718Skan			{
1693132718Skan			  arc = head->u.cycle.arc;
1694132718Skan			  head->u.cycle.arc = NULL;
1695132718Skan			  head = arc->src;
1696132718Skan			}
1697132718Skan		      /* Move on.  */
1698132718Skan		      arc = arc->succ_next;
1699132718Skan		      continue;
1700132718Skan		    }
1701132718Skan
1702132718Skan		  /* Add new block to chain.  */
1703132718Skan		  dst->u.cycle.arc = arc;
1704132718Skan		  head = dst;
1705132718Skan		  goto next_vertex;
1706132718Skan		}
1707132718Skan	      /* We could not add another vertex to the path. Remove
1708132718Skan		 the last vertex from the list.  */
1709132718Skan	      arc = head->u.cycle.arc;
1710132718Skan	      if (arc)
1711132718Skan		{
1712132718Skan		  /* It was not the first vertex. Move onto next arc.  */
1713132718Skan		  head->u.cycle.arc = NULL;
1714132718Skan		  head = arc->src;
1715132718Skan		  arc = arc->succ_next;
1716132718Skan		  goto current_vertex;
1717132718Skan		}
1718132718Skan	      /* Mark this block as unusable.  */
1719132718Skan	      block->u.cycle.ident = ~0U;
1720132718Skan	    }
1721132718Skan
1722132718Skan	  line->count = count;
1723117395Skan	}
1724132718Skan
1725132718Skan      if (line->exists)
1726117395Skan	{
1727132718Skan	  src->coverage.lines++;
1728132718Skan	  if (line->count)
1729132718Skan	    src->coverage.lines_executed++;
1730117395Skan	}
1731132718Skan    }
1732132718Skan}
173390075Sobrien
1734169689Skan/* Output information about ARC number IX.  Returns nonzero if
1735132718Skan   anything is output.  */
1736132718Skan
1737132718Skanstatic int
1738132718Skanoutput_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
1739132718Skan{
1740132718Skan
1741132718Skan  if (arc->is_call_non_return)
1742132718Skan    {
1743132718Skan      if (arc->src->count)
1744117395Skan	{
1745132718Skan	  fnotice (gcov_file, "call   %2d returned %s\n", ix,
1746132718Skan		   format_gcov (arc->src->count - arc->count,
1747132718Skan				arc->src->count, -flag_counts));
1748117395Skan	}
1749132718Skan      else
1750132718Skan	fnotice (gcov_file, "call   %2d never executed\n", ix);
1751117395Skan    }
1752132718Skan  else if (!arc->is_unconditional)
1753132718Skan    {
1754132718Skan      if (arc->src->count)
1755132718Skan	fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
1756132718Skan		 format_gcov (arc->count, arc->src->count, -flag_counts),
1757132718Skan		 arc->fall_through ? " (fallthrough)" : "");
1758132718Skan      else
1759132718Skan	fnotice (gcov_file, "branch %2d never executed\n", ix);
1760132718Skan    }
1761132718Skan  else if (flag_unconditional && !arc->dst->is_call_return)
1762132718Skan    {
1763132718Skan      if (arc->src->count)
1764132718Skan	fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
1765132718Skan		 format_gcov (arc->count, arc->src->count, -flag_counts));
1766132718Skan      else
1767132718Skan	fnotice (gcov_file, "unconditional %2d never executed\n", ix);
1768132718Skan    }
1769132718Skan  else
1770132718Skan    return 0;
1771132718Skan  return 1;
1772132718Skan
1773117395Skan}
177450397Sobrien
1775117395Skan/* Read in the source file one line at a time, and output that line to
1776117395Skan   the gcov file preceded by its execution count and other
1777117395Skan   information.  */
177850397Sobrien
1779117395Skanstatic void
1780132718Skanoutput_lines (FILE *gcov_file, const source_t *src)
1781117395Skan{
1782117395Skan  FILE *source_file;
1783132718Skan  unsigned line_num;	/* current line number.  */
1784132718Skan  const line_t *line;           /* current line info ptr.  */
1785132718Skan  char string[STRING_SIZE];     /* line buffer.  */
1786132718Skan  char const *retval = "";	/* status of source file reading.  */
1787169689Skan  function_t *fn = NULL;
178850397Sobrien
1789132718Skan  fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
1790132718Skan  fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
1791169689Skan  fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
1792169689Skan	   no_data_file ? "-" : da_file_name);
1793132718Skan  fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
1794132718Skan	   object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
1795132718Skan  fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
1796132718Skan
1797132718Skan  source_file = fopen (src->name, "r");
1798117395Skan  if (!source_file)
1799117395Skan    {
1800132718Skan      fnotice (stderr, "%s:cannot open source file\n", src->name);
1801117395Skan      retval = NULL;
1802117395Skan    }
1803117395Skan  else
1804117395Skan    {
1805117395Skan      struct stat status;
1806132718Skan
1807117395Skan      if (!fstat (fileno (source_file), &status)
1808132718Skan	  && status.st_mtime > bbg_file_time)
1809117395Skan	{
1810169689Skan	  fnotice (stderr, "%s:source file is newer than graph file '%s'\n",
1811132718Skan		   src->name, bbg_file_name);
1812132718Skan	  fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n",
1813117395Skan		   "-", 0);
1814117395Skan	}
1815117395Skan    }
181650397Sobrien
1817169689Skan  if (flag_branches)
1818169689Skan    fn = src->functions;
1819169689Skan
1820132718Skan  for (line_num = 1, line = &src->lines[line_num];
1821132718Skan       line_num < src->num_lines; line_num++, line++)
1822117395Skan    {
1823132718Skan      for (; fn && fn->line == line_num; fn = fn->line_next)
1824132718Skan	{
1825132718Skan	  arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
1826132718Skan	  gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
1827169689Skan
1828132718Skan	  for (; arc; arc = arc->pred_next)
1829132718Skan	    if (arc->fake)
1830132718Skan	      return_count -= arc->count;
1831169689Skan
1832132718Skan	  fprintf (gcov_file, "function %s", fn->name);
1833132718Skan	  fprintf (gcov_file, " called %s",
1834132718Skan		   format_gcov (fn->blocks[0].count, 0, -1));
1835132718Skan	  fprintf (gcov_file, " returned %s",
1836132718Skan		   format_gcov (return_count, fn->blocks[0].count, 0));
1837132718Skan	  fprintf (gcov_file, " blocks executed %s",
1838132718Skan		   format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
1839132718Skan	  fprintf (gcov_file, "\n");
1840132718Skan	}
1841132718Skan
1842117395Skan      /* For lines which don't exist in the .bb file, print '-' before
1843132718Skan	 the source line.  For lines which exist but were never
1844132718Skan	 executed, print '#####' before the source line.  Otherwise,
1845132718Skan	 print the execution count before the source line.  There are
1846132718Skan	 16 spaces of indentation added before the source line so that
1847132718Skan	 tabs won't be messed up.  */
1848132718Skan      fprintf (gcov_file, "%9s:%5u:",
1849132718Skan	       !line->exists ? "-" : !line->count ? "#####"
1850132718Skan	       : format_gcov (line->count, 0, -1), line_num);
1851132718Skan
1852117395Skan      if (retval)
1853117395Skan	{
1854117395Skan	  /* Copy source line.  */
1855117395Skan	  do
185650397Sobrien	    {
1857117395Skan	      retval = fgets (string, STRING_SIZE, source_file);
1858117395Skan	      if (!retval)
1859132718Skan		break;
1860117395Skan	      fputs (retval, gcov_file);
186150397Sobrien	    }
1862117395Skan	  while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1863117395Skan	}
1864117395Skan      if (!retval)
1865132718Skan	fputs ("/*EOF*/\n", gcov_file);
1866132718Skan
1867132718Skan      if (flag_all_blocks)
1868117395Skan	{
1869132718Skan	  block_t *block;
1870132718Skan	  arc_t *arc;
1871132718Skan	  int ix, jx;
1872132718Skan
1873132718Skan	  for (ix = jx = 0, block = line->u.blocks; block;
1874132718Skan	       block = block->chain)
187550397Sobrien	    {
1876132718Skan	      if (!block->is_call_return)
1877132718Skan		fprintf (gcov_file, "%9s:%5u-block %2d\n",
1878132718Skan			 !line->exists ? "-" : !block->count ? "$$$$$"
1879132718Skan			 : format_gcov (block->count, 0, -1),
1880132718Skan			 line_num, ix++);
1881132718Skan	      if (flag_branches)
1882132718Skan		for (arc = block->succ; arc; arc = arc->succ_next)
1883132718Skan		  jx += output_branch_count (gcov_file, jx, arc);
188450397Sobrien	    }
1885117395Skan	}
1886132718Skan      else if (flag_branches)
1887132718Skan	{
1888132718Skan	  int ix;
1889132718Skan	  arc_t *arc;
1890132718Skan
1891132718Skan	  for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
1892132718Skan	    ix += output_branch_count (gcov_file, ix, arc);
1893132718Skan	}
1894117395Skan    }
1895132718Skan
1896117395Skan  /* Handle all remaining source lines.  There may be lines after the
1897117395Skan     last line of code.  */
1898117395Skan  if (retval)
1899117395Skan    {
1900117395Skan      for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
1901117395Skan	{
1902132718Skan	  fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval);
1903132718Skan
1904117395Skan	  while (!retval[0] || retval[strlen (retval) - 1] != '\n')
1905117395Skan	    {
1906117395Skan	      retval = fgets (string, STRING_SIZE, source_file);
1907117395Skan	      if (!retval)
1908117395Skan		break;
1909117395Skan	      fputs (retval, gcov_file);
1910117395Skan	    }
1911117395Skan	}
1912117395Skan    }
1913132718Skan
1914117395Skan  if (source_file)
1915117395Skan    fclose (source_file);
1916117395Skan}
1917