gcov.c revision 161651
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
2152284Sobrienthe Free Software Foundation, 59 Temple Place - Suite 330,
2252284SobrienBoston, MA 02111-1307, 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"
5052284Sobrien#undef abort
5150397Sobrien
5290075Sobrien#include <getopt.h>
5390075Sobrien
54132718Skan#define IN_GCOV 1
5550397Sobrien#include "gcov-io.h"
56132718Skan#include "gcov-io.c"
5750397Sobrien
58132718Skan/* The bbg file is generated by -ftest-coverage option. The da file is
59132718Skan   generated by a program compiled with -fprofile-arcs. Their formats
60132718Skan   are documented in gcov-io.h.  */
6150397Sobrien
6250397Sobrien/* The functions in this file for creating and solution program flow graphs
63132718Skan   are very similar to functions in the gcc source file profile.c.  In
64132718Skan   some places we make use of the knowledge of how profile.c works to
65132718Skan   select particular algorithms here.  */
6650397Sobrien
6750397Sobrien/* This is the size of the buffer used to read in source file lines.  */
6850397Sobrien
6950397Sobrien#define STRING_SIZE 200
7050397Sobrien
71132718Skanstruct function_info;
72132718Skanstruct block_info;
73132718Skanstruct source_info;
7450397Sobrien
75132718Skan/* Describes an arc between two basic blocks.  */
76132718Skan
77132718Skantypedef struct arc_info
7850397Sobrien{
79132718Skan  /* source and destination blocks.  */
80132718Skan  struct block_info *src;
81132718Skan  struct block_info *dst;
8250397Sobrien
83132718Skan  /* transition counts.  */
84132718Skan  gcov_type count;
85132718Skan  /* used in cycle search, so that we do not clobber original counts.  */
86132718Skan  gcov_type cs_count;
8750397Sobrien
8850397Sobrien  unsigned int count_valid : 1;
8950397Sobrien  unsigned int on_tree : 1;
9050397Sobrien  unsigned int fake : 1;
9150397Sobrien  unsigned int fall_through : 1;
9250397Sobrien
93132718Skan  /* Arc is for a function that abnormally returns.  */
94132718Skan  unsigned int is_call_non_return : 1;
9550397Sobrien
96132718Skan  /* Arc is for catch/setjump.  */
97132718Skan  unsigned int is_nonlocal_return : 1;
9850397Sobrien
99132718Skan  /* Is an unconditional branch.  */
100132718Skan  unsigned int is_unconditional : 1;
10150397Sobrien
102132718Skan  /* Loop making arc.  */
103132718Skan  unsigned int cycle : 1;
104132718Skan
105132718Skan  /* Next branch on line.  */
106132718Skan  struct arc_info *line_next;
107132718Skan
108132718Skan  /* Links to next arc on src and dst lists.  */
109132718Skan  struct arc_info *succ_next;
110132718Skan  struct arc_info *pred_next;
111132718Skan} arc_t;
112132718Skan
113132718Skan/* Describes a basic block. Contains lists of arcs to successor and
114132718Skan   predecessor blocks.  */
115132718Skan
116132718Skantypedef struct block_info
11750397Sobrien{
118132718Skan  /* Chain of exit and entry arcs.  */
119132718Skan  arc_t *succ;
120132718Skan  arc_t *pred;
12150397Sobrien
122132718Skan  /* Number of unprocessed exit and entry arcs.  */
123132718Skan  gcov_type num_succ;
124132718Skan  gcov_type num_pred;
12550397Sobrien
126132718Skan  /* Block execution count.  */
127132718Skan  gcov_type count;
128132718Skan  unsigned flags : 13;
129132718Skan  unsigned count_valid : 1;
130132718Skan  unsigned valid_chain : 1;
131132718Skan  unsigned invalid_chain : 1;
132132718Skan
133132718Skan  /* Block is a call instrumenting site.  */
134132718Skan  unsigned is_call_site : 1; /* Does the call.  */
135132718Skan  unsigned is_call_return : 1; /* Is the return.  */
136132718Skan
137132718Skan  /* Block is a landing pad for longjmp or throw.  */
138132718Skan  unsigned is_nonlocal_return : 1;
139132718Skan
140132718Skan  union
141132718Skan  {
142132718Skan    struct
143132718Skan    {
144132718Skan     /* Array of line numbers and source files. source files are
145132718Skan        introduced by a linenumber of zero, the next 'line number' is
146132718Skan        the number of the source file.  Always starts with a source
147132718Skan        file.  */
148132718Skan      unsigned *encoding;
149132718Skan      unsigned num;
150132718Skan    } line; /* Valid until blocks are linked onto lines */
151132718Skan    struct
152132718Skan    {
153132718Skan      /* Single line graph cycle workspace.  Used for all-blocks
154132718Skan	 mode.  */
155132718Skan      arc_t *arc;
156132718Skan      unsigned ident;
157132718Skan    } cycle; /* Used in all-blocks mode, after blocks are linked onto
158132718Skan	       lines.  */
159132718Skan  } u;
160132718Skan
161132718Skan  /* Temporary chain for solving graph, and for chaining blocks on one
162132718Skan     line.  */
163132718Skan  struct block_info *chain;
164132718Skan
165132718Skan} block_t;
166132718Skan
167132718Skan/* Describes a single function. Contains an array of basic blocks.  */
168132718Skan
169132718Skantypedef struct function_info
170117395Skan{
171132718Skan  /* Name of function.  */
172132718Skan  char *name;
173132718Skan  unsigned ident;
174132718Skan  unsigned checksum;
17550397Sobrien
176132718Skan  /* Array of basic blocks.  */
177132718Skan  block_t *blocks;
178132718Skan  unsigned num_blocks;
179132718Skan  unsigned blocks_executed;
180132718Skan
181132718Skan  /* Raw arc coverage counts.  */
182132718Skan  gcov_type *counts;
183132718Skan  unsigned num_counts;
184132718Skan
185132718Skan  /* First line number.  */
186132718Skan  unsigned line;
187132718Skan  struct source_info *src;
188132718Skan
189132718Skan  /* Next function in same source file.  */
190132718Skan  struct function_info *line_next;
191132718Skan
192132718Skan  /* Next function.  */
193132718Skan  struct function_info *next;
194132718Skan} function_t;
195132718Skan
196132718Skan/* Describes coverage of a file or function.  */
197132718Skan
198132718Skantypedef struct coverage_info
199117395Skan{
200117395Skan  int lines;
201117395Skan  int lines_executed;
202132718Skan
203117395Skan  int branches;
204117395Skan  int branches_executed;
205117395Skan  int branches_taken;
206132718Skan
207117395Skan  int calls;
208117395Skan  int calls_executed;
209132718Skan
210117395Skan  char *name;
211132718Skan} coverage_t;
212117395Skan
213132718Skan/* Describes a single line of source. Contains a chain of basic blocks
214132718Skan   with code on it.  */
21550397Sobrien
216132718Skantypedef struct line_info
217132718Skan{
218132718Skan  gcov_type count;	   /* execution count */
219132718Skan  union
220132718Skan  {
221132718Skan    arc_t *branches;	   /* branches from blocks that end on this
222132718Skan			      line. Used for branch-counts when not
223132718Skan			      all-blocks mode.  */
224132718Skan    block_t *blocks;       /* blocks which start on this line.  Used
225132718Skan			      in all-blocks mode.  */
226132718Skan  } u;
227132718Skan  unsigned exists : 1;
228132718Skan} line_t;
22950397Sobrien
230132718Skan/* Describes a file mentioned in the block graph.  Contains an array
231132718Skan   of line info.  */
232117395Skan
233132718Skantypedef struct source_info
234132718Skan{
235132718Skan  /* Name of source file.  */
236132718Skan  char *name;
237132718Skan  unsigned index;
238117395Skan
239132718Skan  /* Array of line information.  */
240132718Skan  line_t *lines;
241132718Skan  unsigned num_lines;
24250397Sobrien
243132718Skan  coverage_t coverage;
24450397Sobrien
245132718Skan  /* Functions in this source file.  These are in ascending line
246132718Skan     number order.  */
247132718Skan  function_t *functions;
24850397Sobrien
249132718Skan  /* Next source file.  */
250132718Skan  struct source_info *next;
251132718Skan} source_t;
25250397Sobrien
253132718Skan/* Holds a list of function basic block graphs.  */
25450397Sobrien
255132718Skanstatic function_t *functions;
25650397Sobrien
257132718Skan/* This points to the head of the sourcefile structure list.  */
25850397Sobrien
259132718Skanstatic source_t *sources;
26050397Sobrien
261132718Skan/* This holds data summary information.  */
26250397Sobrien
263132718Skanstatic struct gcov_summary object_summary;
264132718Skanstatic unsigned program_count;
26550397Sobrien
266132718Skan/* Modification time of graph file.  */
26750397Sobrien
268132718Skanstatic time_t bbg_file_time;
26950397Sobrien
270132718Skan/* Name and file pointer of the input file for the basic block graph.  */
27150397Sobrien
272132718Skanstatic char *bbg_file_name;
27350397Sobrien
274132718Skan/* Stamp of the bbg file */
275132718Skanstatic unsigned bbg_stamp;
276132718Skan
277132718Skan/* Name and file pointer of the input file for the arc count data.  */
278132718Skan
279132718Skanstatic char *da_file_name;
280132718Skan
281132718Skan/* Output branch probabilities.  */
282132718Skan
283132718Skanstatic int flag_branches = 0;
284132718Skan
285132718Skan/* Show unconditional branches too.  */
286132718Skanstatic int flag_unconditional = 0;
287132718Skan
28850397Sobrien/* Output a gcov file if this is true.  This is on by default, and can
28950397Sobrien   be turned off by the -n option.  */
29050397Sobrien
291132718Skanstatic int flag_gcov_file = 1;
29250397Sobrien
293132718Skan/* For included files, make the gcov output file name include the name
294132718Skan   of the input source file.  For example, if x.h is included in a.c,
295132718Skan   then the output file name is a.c##x.h.gcov instead of x.h.gcov.  */
29650397Sobrien
297132718Skanstatic int flag_long_names = 0;
29850397Sobrien
299132718Skan/* Output count information for every basic block, not merely those
300132718Skan   that contain line number information.  */
301132718Skan
302132718Skanstatic int flag_all_blocks = 0;
303132718Skan
30450397Sobrien/* Output summary info for each function.  */
30550397Sobrien
306132718Skanstatic int flag_function_summary = 0;
30750397Sobrien
308132718Skan/* Object directory file prefix.  This is the directory/file where the
309132718Skan   graph and data files are looked for, if nonzero.  */
31050397Sobrien
31150397Sobrienstatic char *object_directory = 0;
31250397Sobrien
313117395Skan/* Preserve all pathname components. Needed when object files and
314132718Skan   source files are in subdirectories. '/' is mangled as '#', '.' is
315132718Skan   elided and '..' mangled to '^'.  */
316117395Skan
317132718Skanstatic int flag_preserve_paths = 0;
318132718Skan
31990075Sobrien/* Output the number of times a branch was taken as opposed to the percentage
320132718Skan   of times it was taken.  */
32190075Sobrien
322132718Skanstatic int flag_counts = 0;
32390075Sobrien
32450397Sobrien/* Forward declarations.  */
325132718Skanstatic void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2;
326132718Skanstatic int process_args (int, char **);
327132718Skanstatic void print_usage (int) ATTRIBUTE_NORETURN;
328132718Skanstatic void print_version (void) ATTRIBUTE_NORETURN;
329132718Skanstatic void process_file (const char *);
330132718Skanstatic void create_file_names (const char *);
331132718Skanstatic source_t *find_source (const char *);
332132718Skanstatic int read_graph_file (void);
333132718Skanstatic int read_count_file (void);
334132718Skanstatic void solve_flow_graph (function_t *);
335132718Skanstatic void add_branch_counts (coverage_t *, const arc_t *);
336132718Skanstatic void add_line_counts (coverage_t *, function_t *);
337132718Skanstatic void function_summary (const coverage_t *, const char *);
338132718Skanstatic const char *format_gcov (gcov_type, gcov_type, int);
339132718Skanstatic void accumulate_line_counts (source_t *);
340132718Skanstatic int output_branch_count (FILE *, int, const arc_t *);
341132718Skanstatic void output_lines (FILE *, const source_t *);
342132718Skanstatic char *make_gcov_file_name (const char *, const char *);
343132718Skanstatic void release_structures (void);
344132718Skanextern int main (int, char **);
34550397Sobrien
34650397Sobrienint
347132718Skanmain (int argc, char **argv)
34850397Sobrien{
349132718Skan  int argno;
350132718Skan
35190075Sobrien  gcc_init_libintl ();
35252284Sobrien
353132718Skan  argno = process_args (argc, argv);
354132718Skan  if (optind == argc)
355132718Skan    print_usage (true);
35650397Sobrien
357132718Skan  for (; argno != argc; argno++)
358132718Skan    {
359132718Skan      release_structures ();
36050397Sobrien
361132718Skan      process_file (argv[argno]);
362132718Skan    }
36350397Sobrien
36450397Sobrien  return 0;
36550397Sobrien}
36650397Sobrien
36752284Sobrienstatic void
368132718Skanfnotice (FILE *file, const char *msgid, ...)
36952284Sobrien{
370132718Skan  va_list ap;
37152284Sobrien
372132718Skan  va_start (ap, msgid);
37352284Sobrien  vfprintf (file, _(msgid), ap);
374132718Skan  va_end (ap);
37552284Sobrien}
37652284Sobrien
37750397Sobrien/* More 'friendly' abort that prints the line and file.
37850397Sobrien   config.h can #define abort fancy_abort if you like that sort of thing.  */
379132718Skanextern void fancy_abort (void) ATTRIBUTE_NORETURN;
38050397Sobrien
38150397Sobrienvoid
382132718Skanfancy_abort (void)
38350397Sobrien{
38490075Sobrien  fnotice (stderr, "Internal gcov abort.\n");
38550397Sobrien  exit (FATAL_EXIT_CODE);
38650397Sobrien}
38750397Sobrien
38890075Sobrien/* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
38990075Sobrien   otherwise the output of --help.  */
39050397Sobrien
39150397Sobrienstatic void
392132718Skanprint_usage (int error_p)
39350397Sobrien{
39490075Sobrien  FILE *file = error_p ? stderr : stdout;
39590075Sobrien  int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
396132718Skan
39790075Sobrien  fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
39890075Sobrien  fnotice (file, "Print code coverage information.\n\n");
39990075Sobrien  fnotice (file, "  -h, --help                      Print this help, then exit\n");
40090075Sobrien  fnotice (file, "  -v, --version                   Print version number, then exit\n");
401132718Skan  fnotice (file, "  -a, --all-blocks                Show information for every basic block\n");
40290075Sobrien  fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output\n");
40390075Sobrien  fnotice (file, "  -c, --branch-counts             Given counts of branches taken\n\
40490075Sobrien                                    rather than percentages\n");
40590075Sobrien  fnotice (file, "  -n, --no-output                 Do not create an output file\n");
40690075Sobrien  fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
40790075Sobrien                                    source files\n");
40890075Sobrien  fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
409117395Skan  fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
410117395Skan  fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
411132718Skan  fnotice (file, "  -u, --unconditional-branches    Show unconditional branch counts too\n");
41290075Sobrien  fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
413117395Skan	   bug_report_url);
41490075Sobrien  exit (status);
41550397Sobrien}
41650397Sobrien
41790075Sobrien/* Print version information and exit.  */
41890075Sobrien
41990075Sobrienstatic void
420132718Skanprint_version (void)
42190075Sobrien{
42290075Sobrien  fnotice (stdout, "gcov (GCC) %s\n", version_string);
423161651Skan  fprintf (stdout, "Copyright %s 2006 Free Software Foundation, Inc.\n",
424132718Skan	   _("(C)"));
42590075Sobrien  fnotice (stdout,
426132718Skan	   _("This is free software; see the source for copying conditions.\n"
427132718Skan	     "There is NO warranty; not even for MERCHANTABILITY or \n"
428132718Skan	     "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
42990075Sobrien  exit (SUCCESS_EXIT_CODE);
43090075Sobrien}
43190075Sobrien
43290075Sobrienstatic const struct option options[] =
43390075Sobrien{
43490075Sobrien  { "help",                 no_argument,       NULL, 'h' },
43590075Sobrien  { "version",              no_argument,       NULL, 'v' },
436132718Skan  { "all-blocks",           no_argument,       NULL, 'a' },
43790075Sobrien  { "branch-probabilities", no_argument,       NULL, 'b' },
43890075Sobrien  { "branch-counts",        no_argument,       NULL, 'c' },
43990075Sobrien  { "no-output",            no_argument,       NULL, 'n' },
44090075Sobrien  { "long-file-names",      no_argument,       NULL, 'l' },
44190075Sobrien  { "function-summaries",   no_argument,       NULL, 'f' },
442117395Skan  { "preserve-paths",       no_argument,       NULL, 'p' },
443117395Skan  { "object-directory",     required_argument, NULL, 'o' },
444117395Skan  { "object-file",          required_argument, NULL, 'o' },
445132718Skan  { "unconditional-branches", no_argument,     NULL, 'u' },
446132718Skan  { 0, 0, 0, 0 }
44790075Sobrien};
44890075Sobrien
449132718Skan/* Process args, return index to first non-arg.  */
45050397Sobrien
451132718Skanstatic int
452132718Skanprocess_args (int argc, char **argv)
45350397Sobrien{
45490075Sobrien  int opt;
45550397Sobrien
456132718Skan  while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1)
45750397Sobrien    {
45890075Sobrien      switch (opt)
45950397Sobrien	{
460132718Skan	case 'a':
461132718Skan	  flag_all_blocks = 1;
462132718Skan	  break;
46390075Sobrien	case 'b':
464132718Skan	  flag_branches = 1;
46590075Sobrien	  break;
46690075Sobrien	case 'c':
467132718Skan	  flag_counts = 1;
46890075Sobrien	  break;
469132718Skan	case 'f':
470132718Skan	  flag_function_summary = 1;
47190075Sobrien	  break;
472132718Skan	case 'h':
473132718Skan	  print_usage (false);
474132718Skan	  /* print_usage will exit.  */
47590075Sobrien	case 'l':
476132718Skan	  flag_long_names = 1;
47790075Sobrien	  break;
478132718Skan	case 'n':
479132718Skan	  flag_gcov_file = 0;
48090075Sobrien	  break;
48190075Sobrien	case 'o':
48290075Sobrien	  object_directory = optarg;
48390075Sobrien	  break;
484117395Skan	case 'p':
485132718Skan	  flag_preserve_paths = 1;
486117395Skan	  break;
487132718Skan	case 'u':
488132718Skan	  flag_unconditional = 1;
489132718Skan	  break;
490132718Skan	case 'v':
491132718Skan	  print_version ();
492132718Skan	  /* print_version will exit.  */
49390075Sobrien	default:
49490075Sobrien	  print_usage (true);
49590075Sobrien	  /* print_usage will exit.  */
49650397Sobrien	}
49750397Sobrien    }
49850397Sobrien
499132718Skan  return optind;
500132718Skan}
50190075Sobrien
502132718Skan/* Process a single source file.  */
503132718Skan
504132718Skanstatic void
505132718Skanprocess_file (const char *file_name)
506132718Skan{
507132718Skan  source_t *src;
508132718Skan  function_t *fn;
509132718Skan
510132718Skan  create_file_names (file_name);
511132718Skan  if (read_graph_file ())
512132718Skan    return;
513132718Skan
514132718Skan  if (!functions)
515132718Skan    {
516132718Skan      fnotice (stderr, "%s:no functions found\n", bbg_file_name);
517132718Skan      return;
518132718Skan    }
519132718Skan
520132718Skan  if (read_count_file ())
521132718Skan    return;
522132718Skan
523132718Skan  for (fn = functions; fn; fn = fn->next)
524132718Skan    solve_flow_graph (fn);
525132718Skan  for (src = sources; src; src = src->next)
526132718Skan    src->lines = xcalloc (src->num_lines, sizeof (line_t));
527132718Skan  for (fn = functions; fn; fn = fn->next)
528132718Skan    {
529132718Skan      coverage_t coverage;
530132718Skan
531132718Skan      memset (&coverage, 0, sizeof (coverage));
532132718Skan      coverage.name = fn->name;
533132718Skan      add_line_counts (flag_function_summary ? &coverage : NULL, fn);
534132718Skan      if (flag_function_summary)
535132718Skan	{
536132718Skan	  function_summary (&coverage, "Function");
537132718Skan	  fnotice (stdout, "\n");
538132718Skan	}
539132718Skan    }
540132718Skan
541132718Skan  for (src = sources; src; src = src->next)
542132718Skan    {
543132718Skan      accumulate_line_counts (src);
544132718Skan      function_summary (&src->coverage, "File");
545132718Skan      if (flag_gcov_file)
546132718Skan	{
547132718Skan	  char *gcov_file_name = make_gcov_file_name (file_name, src->name);
548132718Skan	  FILE *gcov_file = fopen (gcov_file_name, "w");
549132718Skan
550132718Skan	  if (gcov_file)
551132718Skan	    {
552132718Skan	      fnotice (stdout, "%s:creating `%s'\n",
553132718Skan		       src->name, gcov_file_name);
554132718Skan	      output_lines (gcov_file, src);
555132718Skan	      if (ferror (gcov_file))
556132718Skan		    fnotice (stderr, "%s:error writing output file `%s'\n",
557132718Skan			     src->name, gcov_file_name);
558132718Skan	      fclose (gcov_file);
559132718Skan	    }
560132718Skan	  else
561132718Skan	    fnotice (stderr, "%s:could not open output file `%s'\n",
562132718Skan		     src->name, gcov_file_name);
563132718Skan	  free (gcov_file_name);
564132718Skan	}
565132718Skan      fnotice (stdout, "\n");
566132718Skan    }
56750397Sobrien}
56850397Sobrien
569132718Skan/* Release all memory used.  */
57050397Sobrien
571132718Skanstatic void
572132718Skanrelease_structures (void)
573132718Skan{
574132718Skan  function_t *fn;
575132718Skan  source_t *src;
576132718Skan
577132718Skan  free (bbg_file_name);
578132718Skan  free (da_file_name);
579132718Skan  da_file_name = bbg_file_name = NULL;
580132718Skan  bbg_file_time = 0;
581132718Skan  bbg_stamp = 0;
582132718Skan
583132718Skan  while ((src = sources))
584132718Skan    {
585132718Skan      sources = src->next;
586132718Skan
587132718Skan      free (src->name);
588132718Skan      free (src->lines);
589132718Skan    }
590132718Skan
591132718Skan  while ((fn = functions))
592132718Skan    {
593132718Skan      unsigned ix;
594132718Skan      block_t *block;
595132718Skan
596132718Skan      functions = fn->next;
597132718Skan      for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
598132718Skan	{
599132718Skan	  arc_t *arc, *arc_n;
600132718Skan
601132718Skan	  for (arc = block->succ; arc; arc = arc_n)
602132718Skan	    {
603132718Skan	      arc_n = arc->succ_next;
604132718Skan	      free (arc);
605132718Skan	    }
606132718Skan	}
607132718Skan      free (fn->blocks);
608132718Skan      free (fn->counts);
609132718Skan    }
610132718Skan}
611132718Skan
612132718Skan/* Generate the names of the graph and data files. If OBJECT_DIRECTORY
613132718Skan   is not specified, these are looked for in the current directory,
614132718Skan   and named from the basename of the FILE_NAME sans extension. If
615117395Skan   OBJECT_DIRECTORY is specified and is a directory, the files are in
616132718Skan   that directory, but named from the basename of the FILE_NAME, sans
617132718Skan   extension. Otherwise OBJECT_DIRECTORY is taken to be the name of
618132718Skan   the object *file*, and the data files are named from that.  */
61950397Sobrien
62050397Sobrienstatic void
621132718Skancreate_file_names (const char *file_name)
62250397Sobrien{
62350397Sobrien  char *cptr;
624117395Skan  char *name;
625132718Skan  int length = strlen (file_name);
626117395Skan  int base;
627132718Skan
628117395Skan  if (object_directory && object_directory[0])
62950397Sobrien    {
630117395Skan      struct stat status;
63150397Sobrien
632117395Skan      length += strlen (object_directory) + 2;
633117395Skan      name = xmalloc (length);
634117395Skan      name[0] = 0;
635132718Skan
636117395Skan      base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
637117395Skan      strcat (name, object_directory);
638117395Skan      if (base && name[strlen (name) - 1] != '/')
639117395Skan	strcat (name, "/");
64050397Sobrien    }
64150397Sobrien  else
64250397Sobrien    {
643117395Skan      name = xmalloc (length + 1);
644117395Skan      name[0] = 0;
645117395Skan      base = 1;
64650397Sobrien    }
647132718Skan
648117395Skan  if (base)
649117395Skan    {
650132718Skan      /* Append source file name.  */
651132718Skan      cptr = strrchr (file_name, '/');
652132718Skan      strcat (name, cptr ? cptr + 1 : file_name);
653132718Skan    }
65450397Sobrien
655117395Skan  /* Remove the extension.  */
656117395Skan  cptr = strrchr (name, '.');
65750397Sobrien  if (cptr)
658117395Skan    *cptr = 0;
659132718Skan
660132718Skan  length = strlen (name);
661117395Skan
662132718Skan  bbg_file_name = xmalloc (length + strlen (GCOV_NOTE_SUFFIX) + 1);
663132718Skan  strcpy (bbg_file_name, name);
664132718Skan  strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX);
66550397Sobrien
666132718Skan  da_file_name = xmalloc (length + strlen (GCOV_DATA_SUFFIX) + 1);
667117395Skan  strcpy (da_file_name, name);
668132718Skan  strcpy (da_file_name + length, GCOV_DATA_SUFFIX);
66950397Sobrien
670132718Skan  return;
671132718Skan}
67250397Sobrien
673132718Skan/* Find or create a source file structure for FILE_NAME. Copies
674132718Skan   FILE_NAME on creation */
675117395Skan
676132718Skanstatic source_t *
677132718Skanfind_source (const char *file_name)
678132718Skan{
679132718Skan  source_t *src;
68090075Sobrien
681132718Skan  if (!file_name)
682132718Skan    file_name = "<unknown>";
68350397Sobrien
684132718Skan  for (src = sources; src; src = src->next)
685132718Skan    if (!strcmp (file_name, src->name))
686132718Skan      return src;
68750397Sobrien
688132718Skan  src = xcalloc (1, sizeof (source_t));
689132718Skan  src->name = xstrdup (file_name);
690132718Skan  src->coverage.name = src->name;
691132718Skan  src->index = sources ? sources->index + 1 : 1;
692132718Skan  src->next = sources;
693132718Skan  sources = src;
69450397Sobrien
695132718Skan  return src;
69650397Sobrien}
69750397Sobrien
698132718Skan/* Read the graph file. Return nonzero on fatal error.  */
69950397Sobrien
700132718Skanstatic int
701132718Skanread_graph_file (void)
70250397Sobrien{
703132718Skan  unsigned version;
704132718Skan  unsigned current_tag = 0;
705132718Skan  struct function_info *fn = NULL;
706132718Skan  source_t *src = NULL;
707132718Skan  unsigned ix;
708132718Skan  unsigned tag;
70950397Sobrien
710132718Skan  if (!gcov_open (bbg_file_name, 1))
71150397Sobrien    {
712132718Skan      fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name);
713132718Skan      return 1;
71450397Sobrien    }
715132718Skan  bbg_file_time = gcov_time ();
716132718Skan  if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC))
717132718Skan    {
718132718Skan      fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name);
719132718Skan      gcov_close ();
720132718Skan      return 1;
721132718Skan    }
72250397Sobrien
723132718Skan  version = gcov_read_unsigned ();
724132718Skan  if (version != GCOV_VERSION)
725132718Skan    {
726132718Skan      char v[4], e[4];
72750397Sobrien
728132718Skan      GCOV_UNSIGNED2STRING (v, version);
729132718Skan      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
73050397Sobrien
731132718Skan      fnotice (stderr, "%s:version `%.4s', prefer `%.4s'\n",
732132718Skan	       bbg_file_name, v, e);
733132718Skan    }
734132718Skan  bbg_stamp = gcov_read_unsigned ();
735117395Skan
736132718Skan  while ((tag = gcov_read_unsigned ()))
737117395Skan    {
738132718Skan      unsigned length = gcov_read_unsigned ();
739132718Skan      gcov_position_t base = gcov_position ();
740117395Skan
741132718Skan      if (tag == GCOV_TAG_FUNCTION)
742117395Skan	{
743132718Skan	  char *function_name;
744132718Skan	  unsigned ident, checksum, lineno;
745132718Skan	  source_t *src;
746132718Skan	  function_t *probe, *prev;
747117395Skan
748132718Skan	  ident = gcov_read_unsigned ();
749132718Skan	  checksum = gcov_read_unsigned ();
750132718Skan	  function_name = xstrdup (gcov_read_string ());
751132718Skan	  src = find_source (gcov_read_string ());
752132718Skan	  lineno = gcov_read_unsigned ();
753117395Skan
754132718Skan	  fn = xcalloc (1, sizeof (function_t));
755132718Skan	  fn->name = function_name;
756132718Skan	  fn->ident = ident;
757132718Skan	  fn->checksum = checksum;
758132718Skan	  fn->src = src;
759132718Skan	  fn->line = lineno;
760117395Skan
761132718Skan	  fn->next = functions;
762132718Skan	  functions = fn;
763132718Skan	  current_tag = tag;
764117395Skan
765132718Skan	  if (lineno >= src->num_lines)
766132718Skan	    src->num_lines = lineno + 1;
767132718Skan	  /* Now insert it into the source file's list of
768132718Skan	     functions. Normally functions will be encountered in
769132718Skan	     ascending order, so a simple scan is quick.  */
770132718Skan	  for (probe = src->functions, prev = NULL;
771132718Skan	       probe && probe->line > lineno;
772132718Skan	       prev = probe, probe = probe->line_next)
773132718Skan	    continue;
774132718Skan	  fn->line_next = probe;
775132718Skan	  if (prev)
776132718Skan	    prev->line_next = fn;
777132718Skan	  else
778132718Skan	    src->functions = fn;
779132718Skan	}
780132718Skan      else if (fn && tag == GCOV_TAG_BLOCKS)
781117395Skan	{
782132718Skan	  if (fn->blocks)
783132718Skan	    fnotice (stderr, "%s:already seen blocks for `%s'\n",
784132718Skan		     bbg_file_name, fn->name);
785117395Skan	  else
786117395Skan	    {
787132718Skan	      unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length);
788132718Skan	      fn->num_blocks = num_blocks;
789117395Skan
790132718Skan	      fn->blocks = xcalloc (fn->num_blocks, sizeof (block_t));
791132718Skan	      for (ix = 0; ix != num_blocks; ix++)
792132718Skan		fn->blocks[ix].flags = gcov_read_unsigned ();
793117395Skan	    }
794117395Skan	}
795132718Skan      else if (fn && tag == GCOV_TAG_ARCS)
796132718Skan	{
797132718Skan	  unsigned src = gcov_read_unsigned ();
798132718Skan	  unsigned num_dests = GCOV_TAG_ARCS_NUM (length);
799117395Skan
800132718Skan	  if (src >= fn->num_blocks || fn->blocks[src].succ)
801132718Skan	    goto corrupt;
802117395Skan
803132718Skan	  while (num_dests--)
804132718Skan	    {
805132718Skan	      struct arc_info *arc;
806132718Skan	      unsigned dest = gcov_read_unsigned ();
807132718Skan	      unsigned flags = gcov_read_unsigned ();
808117395Skan
809132718Skan	      if (dest >= fn->num_blocks)
810132718Skan		goto corrupt;
811132718Skan	      arc = xcalloc (1, sizeof (arc_t));
812117395Skan
813132718Skan	      arc->dst = &fn->blocks[dest];
814132718Skan	      arc->src = &fn->blocks[src];
815117395Skan
816132718Skan	      arc->count = 0;
817132718Skan	      arc->count_valid = 0;
818132718Skan	      arc->on_tree = !!(flags & GCOV_ARC_ON_TREE);
819132718Skan	      arc->fake = !!(flags & GCOV_ARC_FAKE);
820132718Skan	      arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH);
821117395Skan
822132718Skan	      arc->succ_next = fn->blocks[src].succ;
823132718Skan	      fn->blocks[src].succ = arc;
824132718Skan	      fn->blocks[src].num_succ++;
82550397Sobrien
826132718Skan	      arc->pred_next = fn->blocks[dest].pred;
827132718Skan	      fn->blocks[dest].pred = arc;
828132718Skan	      fn->blocks[dest].num_pred++;
82950397Sobrien
830132718Skan	      if (arc->fake)
831132718Skan		{
832132718Skan		  if (src)
833132718Skan		    {
834132718Skan		      /* Exceptional exit from this function, the
835132718Skan			 source block must be a call.  */
836132718Skan		      fn->blocks[src].is_call_site = 1;
837132718Skan		      arc->is_call_non_return = 1;
838132718Skan		    }
839132718Skan		  else
840132718Skan		    {
841132718Skan		      /* Non-local return from a callee of this
842132718Skan		         function. The destination block is a catch or
843132718Skan		         setjmp.  */
844132718Skan		      arc->is_nonlocal_return = 1;
845132718Skan		      fn->blocks[dest].is_nonlocal_return = 1;
846132718Skan		    }
847132718Skan		}
848117395Skan
849132718Skan	      if (!arc->on_tree)
850132718Skan		fn->num_counts++;
851132718Skan	    }
852132718Skan	}
853132718Skan      else if (fn && tag == GCOV_TAG_LINES)
854132718Skan	{
855132718Skan	  unsigned blockno = gcov_read_unsigned ();
856132718Skan	  unsigned *line_nos = xcalloc (length - 1, sizeof (unsigned));
857117395Skan
858132718Skan	  if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding)
859132718Skan	    goto corrupt;
860117395Skan
861132718Skan	  for (ix = 0; ;  )
862132718Skan	    {
863132718Skan	      unsigned lineno = gcov_read_unsigned ();
864117395Skan
865132718Skan	      if (lineno)
866132718Skan		{
867132718Skan		  if (!ix)
868132718Skan		    {
869132718Skan		      line_nos[ix++] = 0;
870132718Skan		      line_nos[ix++] = src->index;
871132718Skan		    }
872132718Skan		  line_nos[ix++] = lineno;
873132718Skan		  if (lineno >= src->num_lines)
874132718Skan		    src->num_lines = lineno + 1;
875132718Skan		}
876132718Skan	      else
877132718Skan		{
878132718Skan		  const char *file_name = gcov_read_string ();
879117395Skan
880132718Skan		  if (!file_name)
881132718Skan		    break;
882132718Skan		  src = find_source (file_name);
88350397Sobrien
884132718Skan		  line_nos[ix++] = 0;
885132718Skan		  line_nos[ix++] = src->index;
886132718Skan		}
887132718Skan	    }
88850397Sobrien
889132718Skan	  fn->blocks[blockno].u.line.encoding = line_nos;
890132718Skan	  fn->blocks[blockno].u.line.num = ix;
891132718Skan	}
892132718Skan      else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
89350397Sobrien	{
894132718Skan	  fn = NULL;
895132718Skan	  current_tag = 0;
89650397Sobrien	}
897132718Skan      gcov_sync (base, length);
898132718Skan      if (gcov_is_error ())
899132718Skan	break;
90050397Sobrien    }
901132718Skan  if (!gcov_is_eof ())
902132718Skan    {
903132718Skan    corrupt:;
904132718Skan      fnotice (stderr, "%s:corrupted\n", bbg_file_name);
905132718Skan      gcov_close ();
906132718Skan      return 1;
907132718Skan    }
908132718Skan  gcov_close ();
90950397Sobrien
910132718Skan  /* We built everything backwards, so nreverse them all.  */
91150397Sobrien
912132718Skan  /* Reverse sources. Not strictly necessary, but we'll then process
913132718Skan     them in the 'expected' order.  */
914132718Skan  {
915132718Skan    source_t *src, *src_p, *src_n;
91650397Sobrien
917132718Skan    for (src_p = NULL, src = sources; src; src_p = src, src = src_n)
918132718Skan      {
919132718Skan	src_n = src->next;
920132718Skan	src->next = src_p;
921132718Skan      }
922132718Skan    sources =  src_p;
923132718Skan  }
92450397Sobrien
925132718Skan  /* Reverse functions.  */
926132718Skan  {
927132718Skan    function_t *fn, *fn_p, *fn_n;
92850397Sobrien
929132718Skan    for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn_n)
930132718Skan      {
931132718Skan	unsigned ix;
932117395Skan
933132718Skan	fn_n = fn->next;
934132718Skan	fn->next = fn_p;
935117395Skan
936132718Skan	/* Reverse the arcs.  */
937132718Skan	for (ix = fn->num_blocks; ix--;)
938132718Skan	  {
939132718Skan	    arc_t *arc, *arc_p, *arc_n;
94050397Sobrien
941132718Skan	    for (arc_p = NULL, arc = fn->blocks[ix].succ; arc;
942132718Skan		 arc_p = arc, arc = arc_n)
943132718Skan	      {
944132718Skan		arc_n = arc->succ_next;
945132718Skan		arc->succ_next = arc_p;
946132718Skan	      }
947132718Skan	    fn->blocks[ix].succ = arc_p;
94850397Sobrien
949132718Skan	    for (arc_p = NULL, arc = fn->blocks[ix].pred; arc;
950132718Skan		 arc_p = arc, arc = arc_n)
951132718Skan	      {
952132718Skan		arc_n = arc->pred_next;
953132718Skan		arc->pred_next = arc_p;
954132718Skan	      }
955132718Skan	    fn->blocks[ix].pred = arc_p;
956132718Skan	  }
957132718Skan      }
958132718Skan    functions = fn_p;
959132718Skan  }
960132718Skan  return 0;
96150397Sobrien}
96290075Sobrien
963132718Skan/* Reads profiles from the count file and attach to each
964132718Skan   function. Return nonzero if fatal error.  */
965132718Skan
966132718Skanstatic int
967132718Skanread_count_file (void)
96850397Sobrien{
969132718Skan  unsigned ix;
970132718Skan  unsigned version;
971132718Skan  unsigned tag;
972132718Skan  function_t *fn = NULL;
973132718Skan  int error = 0;
97450397Sobrien
975132718Skan  if (!gcov_open (da_file_name, 1))
976132718Skan    {
977132718Skan      fnotice (stderr, "%s:cannot open data file\n", da_file_name);
978132718Skan      return 1;
979132718Skan    }
980132718Skan  if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
981132718Skan    {
982132718Skan      fnotice (stderr, "%s:not a gcov data file\n", da_file_name);
983132718Skan    cleanup:;
984132718Skan      gcov_close ();
985132718Skan      return 1;
986132718Skan    }
987132718Skan  version = gcov_read_unsigned ();
988132718Skan  if (version != GCOV_VERSION)
989132718Skan    {
990132718Skan      char v[4], e[4];
99150397Sobrien
992132718Skan      GCOV_UNSIGNED2STRING (v, version);
993132718Skan      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
994132718Skan
995132718Skan      fnotice (stderr, "%s:version `%.4s', prefer version `%.4s'\n",
996132718Skan	       da_file_name, v, e);
997132718Skan    }
998132718Skan  tag = gcov_read_unsigned ();
999132718Skan  if (tag != bbg_stamp)
1000132718Skan    {
1001132718Skan      fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
1002132718Skan      goto cleanup;
1003132718Skan    }
100450397Sobrien
1005132718Skan  while ((tag = gcov_read_unsigned ()))
100650397Sobrien    {
1007132718Skan      unsigned length = gcov_read_unsigned ();
1008132718Skan      unsigned long base = gcov_position ();
100950397Sobrien
1010132718Skan      if (tag == GCOV_TAG_OBJECT_SUMMARY)
1011132718Skan	gcov_read_summary (&object_summary);
1012132718Skan      else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
1013132718Skan	program_count++;
1014132718Skan      else if (tag == GCOV_TAG_FUNCTION)
101550397Sobrien	{
1016132718Skan	  unsigned ident = gcov_read_unsigned ();
1017132718Skan	  struct function_info *fn_n = functions;
1018132718Skan
1019132718Skan	  for (fn = fn ? fn->next : NULL; ; fn = fn->next)
102050397Sobrien	    {
1021132718Skan	      if (fn)
1022132718Skan		;
1023132718Skan	      else if ((fn = fn_n))
1024132718Skan		fn_n = NULL;
1025132718Skan	      else
102650397Sobrien		{
1027132718Skan		  fnotice (stderr, "%s:unknown function `%u'\n",
1028132718Skan			   da_file_name, ident);
1029132718Skan		  break;
103050397Sobrien		}
1031132718Skan	      if (fn->ident == ident)
1032132718Skan		break;
103350397Sobrien	    }
1034132718Skan
1035132718Skan	  if (!fn)
1036132718Skan	    ;
1037132718Skan	  else if (gcov_read_unsigned () != fn->checksum)
103850397Sobrien	    {
1039132718Skan	    mismatch:;
1040132718Skan	      fnotice (stderr, "%s:profile mismatch for `%s'\n",
1041132718Skan		       da_file_name, fn->name);
1042132718Skan	      goto cleanup;
1043132718Skan	    }
1044132718Skan	}
1045132718Skan      else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
1046132718Skan	{
1047132718Skan	  if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts))
1048132718Skan	    goto mismatch;
104950397Sobrien
1050132718Skan	  if (!fn->counts)
1051132718Skan	    fn->counts = xcalloc (fn->num_counts, sizeof (gcov_type));
105250397Sobrien
1053132718Skan	  for (ix = 0; ix != fn->num_counts; ix++)
1054132718Skan	    fn->counts[ix] += gcov_read_counter ();
105550397Sobrien	}
1056132718Skan      gcov_sync (base, length);
1057132718Skan      if ((error = gcov_is_error ()))
1058132718Skan	break;
105950397Sobrien    }
106090075Sobrien
1061132718Skan  if (!gcov_is_eof ())
1062132718Skan    {
1063132718Skan      fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
1064132718Skan	       da_file_name);
1065132718Skan      goto cleanup;
1066132718Skan    }
1067132718Skan
1068132718Skan  gcov_close ();
1069132718Skan  return 0;
107050397Sobrien}
107150397Sobrien
1072132718Skan/* Solve the flow graph. Propagate counts from the instrumented arcs
1073132718Skan   to the blocks and the uninstrumented arcs.  */
107450397Sobrien
107550397Sobrienstatic void
1076132718Skansolve_flow_graph (function_t *fn)
107750397Sobrien{
1078132718Skan  unsigned ix;
1079132718Skan  arc_t *arc;
1080132718Skan  gcov_type *count_ptr = fn->counts;
1081132718Skan  block_t *blk;
1082132718Skan  block_t *valid_blocks = NULL;    /* valid, but unpropagated blocks.  */
1083132718Skan  block_t *invalid_blocks = NULL;  /* invalid, but inferable blocks.  */
108450397Sobrien
1085132718Skan  if (fn->num_blocks < 2)
1086132718Skan    fnotice (stderr, "%s:`%s' lacks entry and/or exit blocks\n",
1087132718Skan	     bbg_file_name, fn->name);
1088132718Skan  else
108950397Sobrien    {
1090132718Skan      if (fn->blocks[0].num_pred)
1091132718Skan	fnotice (stderr, "%s:`%s' has arcs to entry block\n",
1092132718Skan		 bbg_file_name, fn->name);
1093132718Skan      else
1094132718Skan	/* We can't deduce the entry block counts from the lack of
1095132718Skan	   predecessors.  */
1096132718Skan	fn->blocks[0].num_pred = ~(unsigned)0;
109750397Sobrien
1098132718Skan      if (fn->blocks[fn->num_blocks - 1].num_succ)
1099132718Skan	fnotice (stderr, "%s:`%s' has arcs from exit block\n",
1100132718Skan		 bbg_file_name, fn->name);
110150397Sobrien      else
1102132718Skan	/* Likewise, we can't deduce exit block counts from the lack
1103132718Skan	   of its successors.  */
1104132718Skan	fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0;
110550397Sobrien    }
110650397Sobrien
1107132718Skan  /* Propagate the measured counts, this must be done in the same
1108132718Skan     order as the code in profile.c  */
1109132718Skan  for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
1110132718Skan    {
1111132718Skan      block_t const *prev_dst = NULL;
1112132718Skan      int out_of_order = 0;
1113132718Skan      int non_fake_succ = 0;
111450397Sobrien
1115132718Skan      for (arc = blk->succ; arc; arc = arc->succ_next)
1116132718Skan	{
1117132718Skan	  if (!arc->fake)
1118132718Skan	    non_fake_succ++;
111950397Sobrien
1120132718Skan	  if (!arc->on_tree)
1121132718Skan	    {
1122132718Skan	      if (count_ptr)
1123132718Skan		arc->count = *count_ptr++;
1124132718Skan	      arc->count_valid = 1;
1125132718Skan	      blk->num_succ--;
1126132718Skan	      arc->dst->num_pred--;
1127132718Skan	    }
1128132718Skan	  if (prev_dst && prev_dst > arc->dst)
1129132718Skan	    out_of_order = 1;
1130132718Skan	  prev_dst = arc->dst;
1131132718Skan	}
1132132718Skan      if (non_fake_succ == 1)
1133132718Skan	{
1134132718Skan	  /* If there is only one non-fake exit, it is an
1135132718Skan	     unconditional branch.  */
1136132718Skan	  for (arc = blk->succ; arc; arc = arc->succ_next)
1137132718Skan	    if (!arc->fake)
1138132718Skan	      {
1139132718Skan		arc->is_unconditional = 1;
1140132718Skan		/* If this block is instrumenting a call, it might be
1141132718Skan		   an artificial block. It is not artificial if it has
1142132718Skan		   a non-fallthrough exit, or the destination of this
1143132718Skan		   arc has more than one entry.  Mark the destination
1144132718Skan		   block as a return site, if none of those conditions
1145132718Skan		   hold.  */
1146132718Skan		if (blk->is_call_site && arc->fall_through
1147132718Skan		    && arc->dst->pred == arc && !arc->pred_next)
1148132718Skan		  arc->dst->is_call_return = 1;
1149132718Skan	      }
1150132718Skan	}
115150397Sobrien
1152132718Skan      /* Sort the successor arcs into ascending dst order. profile.c
1153132718Skan	 normally produces arcs in the right order, but sometimes with
1154132718Skan	 one or two out of order.  We're not using a particularly
1155132718Skan	 smart sort.  */
1156132718Skan      if (out_of_order)
1157132718Skan	{
1158132718Skan	  arc_t *start = blk->succ;
1159132718Skan	  unsigned changes = 1;
116090075Sobrien
1161132718Skan	  while (changes)
1162132718Skan	    {
1163132718Skan	      arc_t *arc, *arc_p, *arc_n;
116450397Sobrien
1165132718Skan	      changes = 0;
1166132718Skan	      for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);)
1167132718Skan		{
1168132718Skan		  if (arc->dst > arc_n->dst)
1169132718Skan		    {
1170132718Skan		      changes = 1;
1171132718Skan		      if (arc_p)
1172132718Skan			arc_p->succ_next = arc_n;
1173132718Skan		      else
1174132718Skan			start = arc_n;
1175132718Skan		      arc->succ_next = arc_n->succ_next;
1176132718Skan		      arc_n->succ_next = arc;
1177132718Skan		      arc_p = arc_n;
1178132718Skan		    }
1179132718Skan		  else
1180132718Skan		    {
1181132718Skan		      arc_p = arc;
1182132718Skan		      arc = arc_n;
1183132718Skan		    }
1184132718Skan		}
1185132718Skan	    }
1186132718Skan	  blk->succ = start;
1187132718Skan	}
118850397Sobrien
1189132718Skan      /* Place it on the invalid chain, it will be ignored if that's
1190132718Skan	 wrong.  */
1191132718Skan      blk->invalid_chain = 1;
1192132718Skan      blk->chain = invalid_blocks;
1193132718Skan      invalid_blocks = blk;
1194132718Skan    }
119550397Sobrien
1196132718Skan  while (invalid_blocks || valid_blocks)
1197132718Skan    {
1198132718Skan      while ((blk = invalid_blocks))
1199132718Skan	{
1200132718Skan	  gcov_type total = 0;
1201132718Skan	  const arc_t *arc;
120250397Sobrien
1203132718Skan	  invalid_blocks = blk->chain;
1204132718Skan	  blk->invalid_chain = 0;
1205132718Skan	  if (!blk->num_succ)
1206132718Skan	    for (arc = blk->succ; arc; arc = arc->succ_next)
1207132718Skan	      total += arc->count;
1208132718Skan	  else if (!blk->num_pred)
1209132718Skan	    for (arc = blk->pred; arc; arc = arc->pred_next)
1210132718Skan	      total += arc->count;
1211132718Skan	  else
1212132718Skan	    continue;
121350397Sobrien
1214132718Skan	  blk->count = total;
1215132718Skan	  blk->count_valid = 1;
1216132718Skan	  blk->chain = valid_blocks;
1217132718Skan	  blk->valid_chain = 1;
1218132718Skan	  valid_blocks = blk;
1219132718Skan	}
1220132718Skan      while ((blk = valid_blocks))
122150397Sobrien	{
1222132718Skan	  gcov_type total;
1223132718Skan	  arc_t *arc, *inv_arc;
122450397Sobrien
1225132718Skan	  valid_blocks = blk->chain;
1226132718Skan	  blk->valid_chain = 0;
1227132718Skan	  if (blk->num_succ == 1)
122850397Sobrien	    {
1229132718Skan	      block_t *dst;
1230132718Skan
1231132718Skan	      total = blk->count;
1232132718Skan	      inv_arc = NULL;
1233132718Skan	      for (arc = blk->succ; arc; arc = arc->succ_next)
1234132718Skan		{
1235132718Skan		  total -= arc->count;
1236132718Skan		  if (!arc->count_valid)
1237132718Skan		    inv_arc = arc;
1238132718Skan		}
1239132718Skan	      dst = inv_arc->dst;
1240132718Skan	      inv_arc->count_valid = 1;
1241132718Skan	      inv_arc->count = total;
1242132718Skan	      blk->num_succ--;
1243132718Skan	      dst->num_pred--;
1244132718Skan	      if (dst->count_valid)
1245132718Skan		{
1246132718Skan		  if (dst->num_pred == 1 && !dst->valid_chain)
1247132718Skan		    {
1248132718Skan		      dst->chain = valid_blocks;
1249132718Skan		      dst->valid_chain = 1;
1250132718Skan		      valid_blocks = dst;
1251132718Skan		    }
1252132718Skan		}
1253132718Skan	      else
1254132718Skan		{
1255132718Skan		  if (!dst->num_pred && !dst->invalid_chain)
1256132718Skan		    {
1257132718Skan		      dst->chain = invalid_blocks;
1258132718Skan		      dst->invalid_chain = 1;
1259132718Skan		      invalid_blocks = dst;
1260132718Skan		    }
1261132718Skan		}
126250397Sobrien	    }
1263132718Skan	  if (blk->num_pred == 1)
1264132718Skan	    {
1265132718Skan	      block_t *src;
126650397Sobrien
1267132718Skan	      total = blk->count;
1268132718Skan	      inv_arc = NULL;
1269132718Skan	      for (arc = blk->pred; arc; arc = arc->pred_next)
1270132718Skan		{
1271132718Skan		  total -= arc->count;
1272132718Skan		  if (!arc->count_valid)
1273132718Skan		    inv_arc = arc;
1274132718Skan		}
1275132718Skan	      src = inv_arc->src;
1276132718Skan	      inv_arc->count_valid = 1;
1277132718Skan	      inv_arc->count = total;
1278132718Skan	      blk->num_pred--;
1279132718Skan	      src->num_succ--;
1280132718Skan	      if (src->count_valid)
1281132718Skan		{
1282132718Skan		  if (src->num_succ == 1 && !src->valid_chain)
1283132718Skan		    {
1284132718Skan		      src->chain = valid_blocks;
1285132718Skan		      src->valid_chain = 1;
1286132718Skan		      valid_blocks = src;
1287132718Skan		    }
1288132718Skan		}
1289132718Skan	      else
1290132718Skan		{
1291132718Skan		  if (!src->num_succ && !src->invalid_chain)
1292132718Skan		    {
1293132718Skan		      src->chain = invalid_blocks;
1294132718Skan		      src->invalid_chain = 1;
1295132718Skan		      invalid_blocks = src;
1296132718Skan		    }
1297132718Skan		}
1298132718Skan	    }
129950397Sobrien	}
1300132718Skan    }
130150397Sobrien
1302132718Skan  /* If the graph has been correctly solved, every block will have a
1303132718Skan     valid count.  */
1304132718Skan  for (ix = 0; ix < fn->num_blocks; ix++)
1305132718Skan    if (!fn->blocks[ix].count_valid)
1306132718Skan      {
1307132718Skan	fnotice (stderr, "%s:graph is unsolvable for `%s'\n",
1308132718Skan		 bbg_file_name, fn->name);
1309132718Skan	break;
1310132718Skan      }
131150397Sobrien}
1312132718Skan
131350397Sobrien
131450397Sobrien
1315132718Skan/* Increment totals in COVERAGE according to arc ARC.  */
131650397Sobrien
1317117395Skanstatic void
1318132718Skanadd_branch_counts (coverage_t *coverage, const arc_t *arc)
1319117395Skan{
1320132718Skan  if (arc->is_call_non_return)
1321117395Skan    {
1322132718Skan      coverage->calls++;
1323132718Skan      if (arc->src->count)
1324132718Skan	coverage->calls_executed++;
1325117395Skan    }
1326132718Skan  else if (!arc->is_unconditional)
1327117395Skan    {
1328132718Skan      coverage->branches++;
1329132718Skan      if (arc->src->count)
1330132718Skan	coverage->branches_executed++;
1331132718Skan      if (arc->count)
1332132718Skan	coverage->branches_taken++;
1333117395Skan    }
1334117395Skan}
1335117395Skan
1336117395Skan/* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1337117395Skan   count.  If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1338117395Skan   If DP is zero, no decimal point is printed. Only print 100% when
1339117395Skan   TOP==BOTTOM and only print 0% when TOP=0.  If dp < 0, then simply
1340117395Skan   format TOP.  Return pointer to a static string.  */
1341117395Skan
1342117395Skanstatic char const *
1343132718Skanformat_gcov (gcov_type top, gcov_type bottom, int dp)
1344117395Skan{
1345117395Skan  static char buffer[20];
1346132718Skan
1347117395Skan  if (dp >= 0)
1348117395Skan    {
1349117395Skan      float ratio = bottom ? (float)top / bottom : 0;
1350117395Skan      int ix;
1351117395Skan      unsigned limit = 100;
1352117395Skan      unsigned percent;
1353132718Skan
1354117395Skan      for (ix = dp; ix--; )
1355117395Skan	limit *= 10;
1356132718Skan
1357117395Skan      percent = (unsigned) (ratio * limit + (float)0.5);
1358117395Skan      if (percent <= 0 && top)
1359117395Skan	percent = 1;
1360117395Skan      else if (percent >= limit && top != bottom)
1361117395Skan	percent = limit - 1;
1362117395Skan      ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1363117395Skan      if (dp)
136450397Sobrien	{
1365117395Skan	  dp++;
1366117395Skan	  do
136750397Sobrien	    {
1368117395Skan	      buffer[ix+1] = buffer[ix];
1369117395Skan	      ix--;
137050397Sobrien	    }
1371117395Skan	  while (dp--);
1372117395Skan	  buffer[ix + 1] = '.';
137350397Sobrien	}
137450397Sobrien    }
1375117395Skan  else
1376132718Skan    sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top);
1377132718Skan
1378117395Skan  return buffer;
137950397Sobrien}
138050397Sobrien
1381117395Skan
138250397Sobrien/* Output summary info for a function.  */
138350397Sobrien
138450397Sobrienstatic void
1385132718Skanfunction_summary (const coverage_t *coverage, const char *title)
138650397Sobrien{
1387132718Skan  fnotice (stdout, "%s `%s'\n", title, coverage->name);
1388132718Skan
1389132718Skan  if (coverage->lines)
1390132718Skan    fnotice (stdout, "Lines executed:%s of %d\n",
1391132718Skan	     format_gcov (coverage->lines_executed, coverage->lines, 2),
1392132718Skan	     coverage->lines);
139350397Sobrien  else
1394132718Skan    fnotice (stdout, "No executable lines");
139550397Sobrien
1396132718Skan  if (flag_branches)
139750397Sobrien    {
1398132718Skan      if (coverage->branches)
139950397Sobrien	{
1400132718Skan	  fnotice (stdout, "Branches executed:%s of %d\n",
1401132718Skan		   format_gcov (coverage->branches_executed,
1402132718Skan				coverage->branches, 2),
1403132718Skan		   coverage->branches);
1404132718Skan	  fnotice (stdout, "Taken at least once:%s of %d\n",
1405132718Skan		   format_gcov (coverage->branches_taken,
1406132718Skan				coverage->branches, 2),
1407132718Skan		   coverage->branches);
140850397Sobrien	}
140950397Sobrien      else
1410132718Skan	fnotice (stdout, "No branches\n");
1411132718Skan      if (coverage->calls)
1412132718Skan	fnotice (stdout, "Calls executed:%s of %d\n",
1413132718Skan		 format_gcov (coverage->calls_executed, coverage->calls, 2),
1414132718Skan		 coverage->calls);
141550397Sobrien      else
1416132718Skan	fnotice (stdout, "No calls\n");
141750397Sobrien    }
141850397Sobrien}
141950397Sobrien
1420117395Skan/* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1421117395Skan   affect name generation. With preserve_paths we create a filename
1422117395Skan   from all path components of the source file, replacing '/' with
1423117395Skan   '#', without it we simply take the basename component. With
1424117395Skan   long_output_names we prepend the processed name of the input file
1425117395Skan   to each output name (except when the current source file is the
1426117395Skan   input file, so you don't get a double concatenation). The two
1427117395Skan   components are separated by '##'. Also '.' filename components are
1428117395Skan   removed and '..'  components are renamed to '^'.  */
142950397Sobrien
1430117395Skanstatic char *
1431132718Skanmake_gcov_file_name (const char *input_name, const char *src_name)
1432117395Skan{
1433117395Skan  char *cptr;
1434132718Skan  char *name = xmalloc (strlen (src_name) + strlen (input_name) + 10);
1435132718Skan
1436117395Skan  name[0] = 0;
1437132718Skan  if (flag_long_names && strcmp (src_name, input_name))
1438117395Skan    {
1439117395Skan      /* Generate the input filename part.  */
1440132718Skan      cptr = flag_preserve_paths ? NULL : strrchr (input_name, '/');
1441132718Skan      strcat (name, cptr ? cptr + 1 : input_name);
1442117395Skan      strcat (name, "##");
1443117395Skan    }
1444132718Skan
1445117395Skan  /* Generate the source filename part.  */
1446132718Skan  cptr = flag_preserve_paths ? NULL : strrchr (src_name, '/');
1447132718Skan  strcat (name, cptr ? cptr + 1 : src_name);
1448132718Skan
1449132718Skan  if (flag_preserve_paths)
1450117395Skan    {
1451117395Skan      /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1452117395Skan      char *prev;
1453132718Skan
1454117395Skan      for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
1455132718Skan	{
1456132718Skan	  unsigned shift = 0;
1457132718Skan
1458132718Skan	  if (prev + 1 == cptr && prev[0] == '.')
1459132718Skan	    {
1460132718Skan	      /* Remove '.' */
1461132718Skan	      shift = 2;
1462132718Skan	    }
1463132718Skan	  else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
1464132718Skan	    {
1465132718Skan	      /* Convert '..' */
1466132718Skan	      shift = 1;
1467132718Skan	      prev[1] = '^';
1468132718Skan	    }
1469132718Skan	  else
1470132718Skan	    *cptr++ = '#';
1471132718Skan	  if (shift)
1472132718Skan	    {
1473132718Skan	      cptr = prev;
1474132718Skan	      do
1475132718Skan		prev[0] = prev[shift];
1476117395Skan	      while (*prev++);
1477132718Skan	    }
1478132718Skan	}
1479117395Skan    }
1480132718Skan
1481117395Skan  strcat (name, ".gcov");
1482117395Skan  return name;
1483117395Skan}
1484117395Skan
1485132718Skan/* Scan through the bb_data for each line in the block, increment
1486117395Skan   the line number execution count indicated by the execution count of
1487117395Skan   the appropriate basic block.  */
1488117395Skan
148950397Sobrienstatic void
1490132718Skanadd_line_counts (coverage_t *coverage, function_t *fn)
149150397Sobrien{
1492132718Skan  unsigned ix;
1493132718Skan  line_t *line = NULL; /* This is propagated from one iteration to the
1494132718Skan			  next.  */
1495132718Skan
1496132718Skan  /* Scan each basic block.  */
1497132718Skan  for (ix = 0; ix != fn->num_blocks; ix++)
149850397Sobrien    {
1499132718Skan      block_t *block = &fn->blocks[ix];
1500132718Skan      unsigned *encoding;
1501132718Skan      const source_t *src = NULL;
1502132718Skan      unsigned jx;
1503132718Skan
1504132718Skan      if (block->count && ix && ix + 1 != fn->num_blocks)
1505132718Skan	fn->blocks_executed++;
1506132718Skan      for (jx = 0, encoding = block->u.line.encoding;
1507132718Skan	   jx != block->u.line.num; jx++, encoding++)
1508132718Skan	if (!*encoding)
1509132718Skan	  {
1510132718Skan	    unsigned src_n = *++encoding;
1511132718Skan
1512132718Skan	    for (src = sources; src->index != src_n; src = src->next)
1513132718Skan	      continue;
1514132718Skan	    jx++;
1515132718Skan	  }
1516132718Skan	else
1517132718Skan	  {
1518132718Skan	    line = &src->lines[*encoding];
1519132718Skan
1520132718Skan	    if (coverage)
1521132718Skan	      {
1522132718Skan		if (!line->exists)
1523132718Skan		  coverage->lines++;
1524132718Skan		if (!line->count && block->count)
1525132718Skan		  coverage->lines_executed++;
1526132718Skan	      }
1527132718Skan	    line->exists = 1;
1528132718Skan	    line->count += block->count;
1529132718Skan	  }
1530132718Skan      free (block->u.line.encoding);
1531132718Skan      block->u.cycle.arc = NULL;
1532132718Skan      block->u.cycle.ident = ~0U;
1533132718Skan
1534132718Skan      if (!ix || ix + 1 == fn->num_blocks)
1535132718Skan	/* Entry or exit block */;
1536132718Skan      else if (flag_all_blocks)
153750397Sobrien	{
1538132718Skan	  line_t *block_line = line ? line : &fn->src->lines[fn->line];
1539117395Skan
1540132718Skan	  block->chain = block_line->u.blocks;
1541132718Skan	  block_line->u.blocks = block;
1542132718Skan	}
1543132718Skan      else if (flag_branches)
1544132718Skan	{
1545132718Skan	  arc_t *arc;
1546132718Skan
1547132718Skan	  for (arc = block->succ; arc; arc = arc->succ_next)
1548117395Skan	    {
1549132718Skan	      arc->line_next = line->u.branches;
1550132718Skan	      line->u.branches = arc;
1551132718Skan	      if (coverage && !arc->is_unconditional)
1552132718Skan		add_branch_counts (coverage, arc);
1553117395Skan	    }
155450397Sobrien	}
1555132718Skan    }
1556132718Skan  if (!line)
1557132718Skan    fnotice (stderr, "%s:no lines for `%s'\n", bbg_file_name, fn->name);
1558132718Skan}
1559132718Skan
1560132718Skan/* Accumulate the line counts of a file.  */
1561132718Skan
1562132718Skanstatic void
1563132718Skanaccumulate_line_counts (source_t *src)
1564132718Skan{
1565132718Skan  line_t *line;
1566132718Skan  function_t *fn, *fn_p, *fn_n;
1567132718Skan  unsigned ix;
1568132718Skan
1569132718Skan  /* Reverse the function order.  */
1570132718Skan  for (fn = src->functions, fn_p = NULL; fn;
1571132718Skan       fn_p = fn, fn = fn_n)
1572132718Skan    {
1573132718Skan      fn_n = fn->line_next;
1574132718Skan      fn->line_next = fn_p;
1575132718Skan    }
1576132718Skan  src->functions = fn_p;
1577132718Skan
1578132718Skan  for (ix = src->num_lines, line = src->lines; ix--; line++)
1579132718Skan    {
1580132718Skan      if (!flag_all_blocks)
158150397Sobrien	{
1582132718Skan	  arc_t *arc, *arc_p, *arc_n;
1583132718Skan
1584132718Skan	  /* Total and reverse the branch information.  */
1585132718Skan	  for (arc = line->u.branches, arc_p = NULL; arc;
1586132718Skan	       arc_p = arc, arc = arc_n)
158750397Sobrien	    {
1588132718Skan	      arc_n = arc->line_next;
1589132718Skan	      arc->line_next = arc_p;
1590132718Skan
1591132718Skan	      add_branch_counts (&src->coverage, arc);
159250397Sobrien	    }
1593132718Skan	  line->u.branches = arc_p;
159450397Sobrien	}
1595132718Skan      else if (line->u.blocks)
159650397Sobrien	{
1597132718Skan	  /* The user expects the line count to be the number of times
1598132718Skan	     a line has been executed. Simply summing the block count
1599132718Skan	     will give an artificially high number.  The Right Thing
1600132718Skan	     is to sum the entry counts to the graph of blocks on this
1601132718Skan	     line, then find the elementary cycles of the local graph
1602132718Skan	     and add the transition counts of those cycles.  */
1603132718Skan	  block_t *block, *block_p, *block_n;
1604132718Skan	  gcov_type count = 0;
1605132718Skan
1606132718Skan	  /* Reverse the block information.  */
1607132718Skan	  for (block = line->u.blocks, block_p = NULL; block;
1608132718Skan	       block_p = block, block = block_n)
160950397Sobrien	    {
1610132718Skan	      block_n = block->chain;
1611132718Skan	      block->chain = block_p;
1612132718Skan	      block->u.cycle.ident = ix;
161350397Sobrien	    }
1614132718Skan	  line->u.blocks = block_p;
161550397Sobrien
1616132718Skan	  /* Sum the entry arcs.  */
1617132718Skan	  for (block = line->u.blocks; block; block = block->chain)
161850397Sobrien	    {
1619132718Skan	      arc_t *arc;
1620132718Skan
1621132718Skan	      for (arc = block->pred; arc; arc = arc->pred_next)
1622132718Skan		{
1623132718Skan		  if (arc->src->u.cycle.ident != ix)
1624132718Skan		    count += arc->count;
1625132718Skan		  if (flag_branches)
1626132718Skan		    add_branch_counts (&src->coverage, arc);
1627132718Skan		}
1628132718Skan
1629132718Skan	      /* Initialize the cs_count.  */
1630132718Skan	      for (arc = block->succ; arc; arc = arc->succ_next)
1631132718Skan		arc->cs_count = arc->count;
1632117395Skan	    }
1633132718Skan
1634132718Skan	  /* Find the loops. This uses the algorithm described in
1635132718Skan	     Tiernan 'An Efficient Search Algorithm to Find the
1636132718Skan	     Elementary Circuits of a Graph', CACM Dec 1970. We hold
1637132718Skan	     the P array by having each block point to the arc that
1638132718Skan	     connects to the previous block. The H array is implicitly
1639132718Skan	     held because of the arc ordering, and the block's
1640132718Skan	     previous arc pointer.
1641132718Skan
1642132718Skan	     Although the algorithm is O(N^3) for highly connected
1643132718Skan	     graphs, at worst we'll have O(N^2), as most blocks have
1644132718Skan	     only one or two exits. Most graphs will be small.
1645132718Skan
1646132718Skan	     For each loop we find, locate the arc with the smallest
1647132718Skan	     transition count, and add that to the cumulative
1648132718Skan	     count.  Decrease flow over the cycle and remove the arc
1649132718Skan	     from consideration.  */
1650132718Skan	  for (block = line->u.blocks; block; block = block->chain)
1651132718Skan	    {
1652132718Skan	      block_t *head = block;
1653132718Skan	      arc_t *arc;
1654132718Skan
1655132718Skan	    next_vertex:;
1656132718Skan	      arc = head->succ;
1657132718Skan	    current_vertex:;
1658132718Skan	      while (arc)
1659132718Skan		{
1660132718Skan		  block_t *dst = arc->dst;
1661132718Skan		  if (/* Already used that arc.  */
1662132718Skan		      arc->cycle
1663132718Skan		      /* Not to same graph, or before first vertex.  */
1664132718Skan		      || dst->u.cycle.ident != ix
1665132718Skan		      /* Already in path.  */
1666132718Skan		      || dst->u.cycle.arc)
1667132718Skan		    {
1668132718Skan		      arc = arc->succ_next;
1669132718Skan		      continue;
1670132718Skan		    }
1671132718Skan
1672132718Skan		  if (dst == block)
1673132718Skan		    {
1674132718Skan		      /* Found a closing arc.  */
1675132718Skan		      gcov_type cycle_count = arc->cs_count;
1676132718Skan		      arc_t *cycle_arc = arc;
1677132718Skan		      arc_t *probe_arc;
1678132718Skan
1679132718Skan		      /* Locate the smallest arc count of the loop.  */
1680132718Skan		      for (dst = head; (probe_arc = dst->u.cycle.arc);
1681132718Skan			   dst = probe_arc->src)
1682132718Skan			if (cycle_count > probe_arc->cs_count)
1683132718Skan			  {
1684132718Skan			    cycle_count = probe_arc->cs_count;
1685132718Skan			    cycle_arc = probe_arc;
1686132718Skan			  }
1687132718Skan
1688132718Skan		      count += cycle_count;
1689132718Skan		      cycle_arc->cycle = 1;
1690132718Skan
1691132718Skan		      /* Remove the flow from the cycle.  */
1692132718Skan		      arc->cs_count -= cycle_count;
1693132718Skan		      for (dst = head; (probe_arc = dst->u.cycle.arc);
1694132718Skan			   dst = probe_arc->src)
1695132718Skan			probe_arc->cs_count -= cycle_count;
1696132718Skan
1697132718Skan		      /* Unwind to the cyclic arc.  */
1698132718Skan		      while (head != cycle_arc->src)
1699132718Skan			{
1700132718Skan			  arc = head->u.cycle.arc;
1701132718Skan			  head->u.cycle.arc = NULL;
1702132718Skan			  head = arc->src;
1703132718Skan			}
1704132718Skan		      /* Move on.  */
1705132718Skan		      arc = arc->succ_next;
1706132718Skan		      continue;
1707132718Skan		    }
1708132718Skan
1709132718Skan		  /* Add new block to chain.  */
1710132718Skan		  dst->u.cycle.arc = arc;
1711132718Skan		  head = dst;
1712132718Skan		  goto next_vertex;
1713132718Skan		}
1714132718Skan	      /* We could not add another vertex to the path. Remove
1715132718Skan		 the last vertex from the list.  */
1716132718Skan	      arc = head->u.cycle.arc;
1717132718Skan	      if (arc)
1718132718Skan		{
1719132718Skan		  /* It was not the first vertex. Move onto next arc.  */
1720132718Skan		  head->u.cycle.arc = NULL;
1721132718Skan		  head = arc->src;
1722132718Skan		  arc = arc->succ_next;
1723132718Skan		  goto current_vertex;
1724132718Skan		}
1725132718Skan	      /* Mark this block as unusable.  */
1726132718Skan	      block->u.cycle.ident = ~0U;
1727132718Skan	    }
1728132718Skan
1729132718Skan	  line->count = count;
1730117395Skan	}
1731132718Skan
1732132718Skan      if (line->exists)
1733117395Skan	{
1734132718Skan	  src->coverage.lines++;
1735132718Skan	  if (line->count)
1736132718Skan	    src->coverage.lines_executed++;
1737117395Skan	}
1738132718Skan    }
1739132718Skan}
174090075Sobrien
1741132718Skan/* Ouput information about ARC number IX.  Returns nonzero if
1742132718Skan   anything is output.  */
1743132718Skan
1744132718Skanstatic int
1745132718Skanoutput_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
1746132718Skan{
1747132718Skan
1748132718Skan  if (arc->is_call_non_return)
1749132718Skan    {
1750132718Skan      if (arc->src->count)
1751117395Skan	{
1752132718Skan	  fnotice (gcov_file, "call   %2d returned %s\n", ix,
1753132718Skan		   format_gcov (arc->src->count - arc->count,
1754132718Skan				arc->src->count, -flag_counts));
1755117395Skan	}
1756132718Skan      else
1757132718Skan	fnotice (gcov_file, "call   %2d never executed\n", ix);
1758117395Skan    }
1759132718Skan  else if (!arc->is_unconditional)
1760132718Skan    {
1761132718Skan      if (arc->src->count)
1762132718Skan	fnotice (gcov_file, "branch %2d taken %s%s\n", ix,
1763132718Skan		 format_gcov (arc->count, arc->src->count, -flag_counts),
1764132718Skan		 arc->fall_through ? " (fallthrough)" : "");
1765132718Skan      else
1766132718Skan	fnotice (gcov_file, "branch %2d never executed\n", ix);
1767132718Skan    }
1768132718Skan  else if (flag_unconditional && !arc->dst->is_call_return)
1769132718Skan    {
1770132718Skan      if (arc->src->count)
1771132718Skan	fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
1772132718Skan		 format_gcov (arc->count, arc->src->count, -flag_counts));
1773132718Skan      else
1774132718Skan	fnotice (gcov_file, "unconditional %2d never executed\n", ix);
1775132718Skan    }
1776132718Skan  else
1777132718Skan    return 0;
1778132718Skan  return 1;
1779132718Skan
1780117395Skan}
178150397Sobrien
1782117395Skan/* Read in the source file one line at a time, and output that line to
1783117395Skan   the gcov file preceded by its execution count and other
1784117395Skan   information.  */
178550397Sobrien
1786117395Skanstatic void
1787132718Skanoutput_lines (FILE *gcov_file, const source_t *src)
1788117395Skan{
1789117395Skan  FILE *source_file;
1790132718Skan  unsigned line_num;	/* current line number.  */
1791132718Skan  const line_t *line;           /* current line info ptr.  */
1792132718Skan  char string[STRING_SIZE];     /* line buffer.  */
1793132718Skan  char const *retval = "";	/* status of source file reading.  */
1794132718Skan  function_t *fn = src->functions;
179550397Sobrien
1796132718Skan  fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
1797132718Skan  fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
1798132718Skan  fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, da_file_name);
1799132718Skan  fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
1800132718Skan	   object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
1801132718Skan  fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
1802132718Skan
1803132718Skan  source_file = fopen (src->name, "r");
1804117395Skan  if (!source_file)
1805117395Skan    {
1806132718Skan      fnotice (stderr, "%s:cannot open source file\n", src->name);
1807117395Skan      retval = NULL;
1808117395Skan    }
1809117395Skan  else
1810117395Skan    {
1811117395Skan      struct stat status;
1812132718Skan
1813117395Skan      if (!fstat (fileno (source_file), &status)
1814132718Skan	  && status.st_mtime > bbg_file_time)
1815117395Skan	{
1816132718Skan	  fnotice (stderr, "%s:source file is newer than graph file `%s'\n",
1817132718Skan		   src->name, bbg_file_name);
1818132718Skan	  fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n",
1819117395Skan		   "-", 0);
1820117395Skan	}
1821117395Skan    }
182250397Sobrien
1823132718Skan  for (line_num = 1, line = &src->lines[line_num];
1824132718Skan       line_num < src->num_lines; line_num++, line++)
1825117395Skan    {
1826132718Skan      for (; fn && fn->line == line_num; fn = fn->line_next)
1827132718Skan	{
1828132718Skan	  arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
1829132718Skan	  gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
1830132718Skan
1831132718Skan	  for (; arc; arc = arc->pred_next)
1832132718Skan	    if (arc->fake)
1833132718Skan	      return_count -= arc->count;
1834132718Skan
1835132718Skan	  fprintf (gcov_file, "function %s", fn->name);
1836132718Skan	  fprintf (gcov_file, " called %s",
1837132718Skan		   format_gcov (fn->blocks[0].count, 0, -1));
1838132718Skan	  fprintf (gcov_file, " returned %s",
1839132718Skan		   format_gcov (return_count, fn->blocks[0].count, 0));
1840132718Skan	  fprintf (gcov_file, " blocks executed %s",
1841132718Skan		   format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
1842132718Skan	  fprintf (gcov_file, "\n");
1843132718Skan	}
1844132718Skan
1845117395Skan      /* For lines which don't exist in the .bb file, print '-' before
1846132718Skan	 the source line.  For lines which exist but were never
1847132718Skan	 executed, print '#####' before the source line.  Otherwise,
1848132718Skan	 print the execution count before the source line.  There are
1849132718Skan	 16 spaces of indentation added before the source line so that
1850132718Skan	 tabs won't be messed up.  */
1851132718Skan      fprintf (gcov_file, "%9s:%5u:",
1852132718Skan	       !line->exists ? "-" : !line->count ? "#####"
1853132718Skan	       : format_gcov (line->count, 0, -1), line_num);
1854132718Skan
1855117395Skan      if (retval)
1856117395Skan	{
1857117395Skan	  /* Copy source line.  */
1858117395Skan	  do
185950397Sobrien	    {
1860117395Skan	      retval = fgets (string, STRING_SIZE, source_file);
1861117395Skan	      if (!retval)
1862132718Skan		break;
1863117395Skan	      fputs (retval, gcov_file);
186450397Sobrien	    }
1865117395Skan	  while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1866117395Skan	}
1867117395Skan      if (!retval)
1868132718Skan	fputs ("/*EOF*/\n", gcov_file);
1869132718Skan
1870132718Skan      if (flag_all_blocks)
1871117395Skan	{
1872132718Skan	  block_t *block;
1873132718Skan	  arc_t *arc;
1874132718Skan	  int ix, jx;
1875132718Skan
1876132718Skan	  for (ix = jx = 0, block = line->u.blocks; block;
1877132718Skan	       block = block->chain)
187850397Sobrien	    {
1879132718Skan	      if (!block->is_call_return)
1880132718Skan		fprintf (gcov_file, "%9s:%5u-block %2d\n",
1881132718Skan			 !line->exists ? "-" : !block->count ? "$$$$$"
1882132718Skan			 : format_gcov (block->count, 0, -1),
1883132718Skan			 line_num, ix++);
1884132718Skan	      if (flag_branches)
1885132718Skan		for (arc = block->succ; arc; arc = arc->succ_next)
1886132718Skan		  jx += output_branch_count (gcov_file, jx, arc);
188750397Sobrien	    }
1888117395Skan	}
1889132718Skan      else if (flag_branches)
1890132718Skan	{
1891132718Skan	  int ix;
1892132718Skan	  arc_t *arc;
1893132718Skan
1894132718Skan	  for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
1895132718Skan	    ix += output_branch_count (gcov_file, ix, arc);
1896132718Skan	}
1897117395Skan    }
1898132718Skan
1899117395Skan  /* Handle all remaining source lines.  There may be lines after the
1900117395Skan     last line of code.  */
1901117395Skan  if (retval)
1902117395Skan    {
1903117395Skan      for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
1904117395Skan	{
1905132718Skan	  fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval);
1906132718Skan
1907117395Skan	  while (!retval[0] || retval[strlen (retval) - 1] != '\n')
1908117395Skan	    {
1909117395Skan	      retval = fgets (string, STRING_SIZE, source_file);
1910117395Skan	      if (!retval)
1911117395Skan		break;
1912117395Skan	      fputs (retval, gcov_file);
1913117395Skan	    }
1914117395Skan	}
1915117395Skan    }
1916132718Skan
1917117395Skan  if (source_file)
1918117395Skan    fclose (source_file);
1919117395Skan}
1920