gcov.c revision 117395
150397Sobrien/* Gcov.c: prepend line execution counts and branch probabilities to a
250397Sobrien   source file.
390075Sobrien   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
490075Sobrien   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
550397Sobrien   Contributed by James E. Wilson of Cygnus Support.
650397Sobrien   Mangled by Bob Manson of Cygnus Support.
750397Sobrien
850397SobrienGcov is free software; you can redistribute it and/or modify
950397Sobrienit under the terms of the GNU General Public License as published by
1050397Sobrienthe Free Software Foundation; either version 2, or (at your option)
1150397Sobrienany later version.
1250397Sobrien
1350397SobrienGcov is distributed in the hope that it will be useful,
1450397Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1550397SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1650397SobrienGNU General Public License for more details.
1750397Sobrien
1850397SobrienYou should have received a copy of the GNU General Public License
1950397Sobrienalong with Gcov; see the file COPYING.  If not, write to
2052284Sobrienthe Free Software Foundation, 59 Temple Place - Suite 330,
2152284SobrienBoston, MA 02111-1307, USA.  */
2250397Sobrien
2350397Sobrien/* ??? The code in final.c that produces the struct bb assumes that there is
2450397Sobrien   no padding between the fields.  This is not necessary true.  The current
2550397Sobrien   code can only be trusted if longs and pointers are the same size.  */
2650397Sobrien
2750397Sobrien/* ??? No need to print an execution count on every line, could just print
2850397Sobrien   it on the first line of each block, and only print it on a subsequent
2950397Sobrien   line in the same block if the count changes.  */
3050397Sobrien
3150397Sobrien/* ??? Print a list of the ten blocks with the highest execution counts,
3250397Sobrien   and list the line numbers corresponding to those blocks.  Also, perhaps
3350397Sobrien   list the line numbers with the highest execution counts, only printing
3450397Sobrien   the first if there are several which are all listed in the same block.  */
3550397Sobrien
3650397Sobrien/* ??? Should have an option to print the number of basic blocks, and the
3750397Sobrien   percent of them that are covered.  */
3850397Sobrien
3950397Sobrien/* ??? Does not correctly handle the case where two .bb files refer to the
4050397Sobrien   same included source file.  For example, if one has a short file containing
4150397Sobrien   only inline functions, which is then included in two other files, then
4250397Sobrien   there will be two .bb files which refer to the include file, but there
4350397Sobrien   is no way to get the total execution counts for the included file, can
4450397Sobrien   only get execution counts for one or the other of the including files.  */
4550397Sobrien
4650397Sobrien#include "config.h"
4750397Sobrien#include "system.h"
4852284Sobrien#include "intl.h"
4990075Sobrien#include "version.h"
5052284Sobrien#undef abort
5150397Sobrien
5290075Sobrien#include <getopt.h>
5390075Sobrien
5490075Sobrientypedef HOST_WIDEST_INT gcov_type;
5550397Sobrien#include "gcov-io.h"
5650397Sobrien
5750397Sobrien/* The .bb file format consists of several lists of 4-byte integers
5850397Sobrien   which are the line numbers of each basic block in the file.  Each
5950397Sobrien   list is terminated by a zero.  These lists correspond to the basic
6050397Sobrien   blocks in the reconstructed program flow graph.
6150397Sobrien
6250397Sobrien   A line number of -1 indicates that a source file name (padded to a
6350397Sobrien   long boundary) follows.  The padded file name is followed by
6450397Sobrien   another -1 to make it easy to scan past file names.  A -2 indicates
6550397Sobrien   that a function name (padded to a long boundary) follows; the name
6650397Sobrien   is followed by another -2 to make it easy to scan past the function
6750397Sobrien   name.
6850397Sobrien
6950397Sobrien   The .bbg file contains enough info to enable gcov to reconstruct the
7050397Sobrien   program flow graph.  The first word is the number of basic blocks,
7150397Sobrien   the second word is the number of arcs, followed by the list of arcs
7250397Sobrien   (source bb, dest bb pairs), then a -1, then the number of instrumented
7350397Sobrien   arcs followed by the instrumented arcs, followed by another -1.  This
7450397Sobrien   is repeated for each function.
7550397Sobrien
7650397Sobrien   The .da file contains the execution count for each instrumented branch.
7750397Sobrien
7850397Sobrien   The .bb and .bbg files are created by giving GCC the -ftest-coverage option,
7950397Sobrien   and the .da files are created when an executable compiled with
8050397Sobrien   -fprofile-arcs is run.  */
8150397Sobrien
8250397Sobrien/* The functions in this file for creating and solution program flow graphs
8350397Sobrien   are very similar to functions in the gcc source file profile.c.  */
8450397Sobrien
8550397Sobrien/* This is the size of the buffer used to read in source file lines.  */
8650397Sobrien
8750397Sobrien#define STRING_SIZE 200
8850397Sobrien
8950397Sobrien/* One copy of this structure is created for each source file mentioned in the
9050397Sobrien   .bb file.  */
9150397Sobrien
9250397Sobrienstruct sourcefile
9350397Sobrien{
9450397Sobrien  char *name;
9550397Sobrien  int maxlineno;
9650397Sobrien  struct sourcefile *next;
9750397Sobrien};
9850397Sobrien
9950397Sobrien/* This points to the head of the sourcefile structure list.  */
10050397Sobrien
10150397Sobrienstruct sourcefile *sources;
10250397Sobrien
10350397Sobrien/* One of these is dynamically created whenever we identify an arc in the
10450397Sobrien   function.  */
10550397Sobrien
106117395Skanstruct adj_list
107117395Skan{
10850397Sobrien  int source;
10950397Sobrien  int target;
11090075Sobrien  gcov_type arc_count;
11150397Sobrien  unsigned int count_valid : 1;
11250397Sobrien  unsigned int on_tree : 1;
11350397Sobrien  unsigned int fake : 1;
11450397Sobrien  unsigned int fall_through : 1;
11550397Sobrien#if 0
11650397Sobrien  /* Not needed for gcov, but defined in profile.c.  */
11750397Sobrien  rtx branch_insn;
11850397Sobrien#endif
11950397Sobrien  struct adj_list *pred_next;
12050397Sobrien  struct adj_list *succ_next;
12150397Sobrien};
12250397Sobrien
12350397Sobrien/* Count the number of basic blocks, and create an array of these structures,
12450397Sobrien   one for each bb in the function.  */
12550397Sobrien
126117395Skanstruct bb_info
127117395Skan{
12850397Sobrien  struct adj_list *succ;
12950397Sobrien  struct adj_list *pred;
13090075Sobrien  gcov_type succ_count;
13190075Sobrien  gcov_type pred_count;
13290075Sobrien  gcov_type exec_count;
13350397Sobrien  unsigned int count_valid : 1;
13450397Sobrien  unsigned int on_tree : 1;
13550397Sobrien#if 0
13650397Sobrien  /* Not needed for gcov, but defined in profile.c.  */
13750397Sobrien  rtx first_insn;
13850397Sobrien#endif
13950397Sobrien};
14050397Sobrien
14150397Sobrien/* When outputting branch probabilities, one of these structures is created
14250397Sobrien   for each branch/call.  */
14350397Sobrien
14450397Sobrienstruct arcdata
14550397Sobrien{
14690075Sobrien  gcov_type hits;
14790075Sobrien  gcov_type total;
14850397Sobrien  int call_insn;
14950397Sobrien  struct arcdata *next;
15050397Sobrien};
15150397Sobrien
15250397Sobrien/* Used to save the list of bb_graphs, one per function.  */
15350397Sobrien
154117395Skanstruct bb_info_list
155117395Skan{
15650397Sobrien  /* Indexed by block number, holds the basic block graph for one function.  */
15750397Sobrien  struct bb_info *bb_graph;
15850397Sobrien  int num_blocks;
15950397Sobrien  struct bb_info_list *next;
16050397Sobrien};
16150397Sobrien
162117395Skan/* Used to hold information about each line.  */
163117395Skanstruct line_info
164117395Skan{
165117395Skan  gcov_type count;	      /* execution count */
166117395Skan  struct arcdata *branches;   /* list of branch probabilities for line.  */
167117395Skan  unsigned exists : 1;	      /* has code associated with it.  */
168117395Skan};
169117395Skan
170117395Skanstruct coverage
171117395Skan{
172117395Skan  int lines;
173117395Skan  int lines_executed;
174117395Skan
175117395Skan  int branches;
176117395Skan  int branches_executed;
177117395Skan  int branches_taken;
178117395Skan
179117395Skan  int calls;
180117395Skan  int calls_executed;
181117395Skan
182117395Skan  char *name;
183117395Skan};
184117395Skan
18550397Sobrien/* Holds a list of function basic block graphs.  */
18650397Sobrien
18750397Sobrienstatic struct bb_info_list *bb_graph_list = 0;
18850397Sobrien
189117395Skan/* Modification time of data files.  */
190117395Skan
191117395Skanstatic time_t bb_file_time;
192117395Skan
19350397Sobrien/* Name and file pointer of the input file for the basic block graph.  */
19450397Sobrien
19550397Sobrienstatic char *bbg_file_name;
19650397Sobrienstatic FILE *bbg_file;
19750397Sobrien
19850397Sobrien/* Name and file pointer of the input file for the arc count data.  */
19950397Sobrien
20050397Sobrienstatic char *da_file_name;
20150397Sobrienstatic FILE *da_file;
20250397Sobrien
20350397Sobrien/* Name and file pointer of the input file for the basic block line counts.  */
20450397Sobrien
20550397Sobrienstatic char *bb_file_name;
20650397Sobrienstatic FILE *bb_file;
20750397Sobrien
20850397Sobrien/* Holds the entire contents of the bb_file read into memory.  */
20950397Sobrien
21050397Sobrienstatic char *bb_data;
21150397Sobrien
21250397Sobrien/* Size of bb_data array in longs.  */
21350397Sobrien
21450397Sobrienstatic long bb_data_size;
21550397Sobrien
21650397Sobrien/* Name of the file mentioned on the command line.  */
21750397Sobrien
21850397Sobrienstatic char *input_file_name = 0;
21950397Sobrien
22050397Sobrien/* Output branch probabilities if true.  */
22150397Sobrien
22250397Sobrienstatic int output_branch_probs = 0;
22350397Sobrien
22450397Sobrien/* Output a gcov file if this is true.  This is on by default, and can
22550397Sobrien   be turned off by the -n option.  */
22650397Sobrien
22750397Sobrienstatic int output_gcov_file = 1;
22850397Sobrien
22950397Sobrien/* For included files, make the gcov output file name include the name of
23050397Sobrien   the input source file.  For example, if x.h is included in a.c, then the
23150397Sobrien   output file name is a.c.x.h.gcov instead of x.h.gcov.  This works only
23250397Sobrien   when a single source file is specified.  */
23350397Sobrien
23450397Sobrienstatic int output_long_names = 0;
23550397Sobrien
23650397Sobrien/* Output summary info for each function.  */
23750397Sobrien
23850397Sobrienstatic int output_function_summary = 0;
23950397Sobrien
240117395Skan/* Object directory file prefix.  This is the directory/file
241117395Skan   where .bb and .bbg files are looked for, if nonzero.  */
24250397Sobrien
24350397Sobrienstatic char *object_directory = 0;
24450397Sobrien
245117395Skan/* Preserve all pathname components. Needed when object files and
246117395Skan   source files are in subdirectories.  */
247117395Skanstatic int preserve_paths = 0;
248117395Skan
24990075Sobrien/* Output the number of times a branch was taken as opposed to the percentage
25090075Sobrien   of times it was taken.  Turned on by the -c option */
25190075Sobrien
25290075Sobrienstatic int output_branch_counts = 0;
25390075Sobrien
25450397Sobrien/* Forward declarations.  */
25590075Sobrienstatic void process_args PARAMS ((int, char **));
25690075Sobrienstatic void open_files PARAMS ((void));
25790075Sobrienstatic void read_files PARAMS ((void));
25890075Sobrienstatic void scan_for_source_files PARAMS ((void));
259117395Skanstatic void output_data PARAMS ((struct sourcefile *));
26090075Sobrienstatic void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
26190075Sobrienstatic void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
26290075Sobrienstatic void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
26390075Sobrienstatic struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
264117395Skanstatic gcov_type *read_profile PARAMS ((char *, long, int));
26590075Sobrienstatic void create_program_flow_graph PARAMS ((struct bb_info_list *));
26690075Sobrienstatic void solve_program_flow_graph PARAMS ((struct bb_info_list *));
267117395Skanstatic void accumulate_branch_counts PARAMS ((struct coverage *,
268117395Skan					      struct arcdata *));
269117395Skanstatic void calculate_branch_probs PARAMS ((struct bb_info *,
270117395Skan					    struct line_info *,
271117395Skan					    struct coverage *));
272117395Skanstatic void function_summary PARAMS ((struct coverage *, const char *));
273117395Skanstatic void init_line_info PARAMS ((struct line_info *,
274117395Skan				    struct coverage *, long));
275117395Skanstatic void output_line_info PARAMS ((FILE *, const struct line_info *,
276117395Skan				      const struct coverage *, long));
277117395Skanstatic char *make_gcov_file_name PARAMS ((char *));
278117395Skanstatic const char *format_hwint PARAMS ((HOST_WIDEST_INT, HOST_WIDEST_INT,
279117395Skan					 int));
28050397Sobrien
28190075Sobrienextern int main PARAMS ((int, char **));
28290075Sobrien
28350397Sobrienint
28450397Sobrienmain (argc, argv)
28550397Sobrien     int argc;
28650397Sobrien     char **argv;
28750397Sobrien{
288117395Skan  struct sourcefile *s_ptr;
289117395Skan
29090075Sobrien  gcc_init_libintl ();
29152284Sobrien
29250397Sobrien  process_args (argc, argv);
29350397Sobrien
29450397Sobrien  open_files ();
29550397Sobrien
29650397Sobrien  read_files ();
29750397Sobrien
29850397Sobrien  scan_for_source_files ();
29950397Sobrien
300117395Skan  for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
301117395Skan    output_data (s_ptr);
30250397Sobrien
30350397Sobrien  return 0;
30450397Sobrien}
30550397Sobrien
30690075Sobrienstatic void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
30752284Sobrienstatic void
30890075Sobrienfnotice VPARAMS ((FILE *file, const char *msgid, ...))
30952284Sobrien{
31090075Sobrien  VA_OPEN (ap, msgid);
31190075Sobrien  VA_FIXEDARG (ap, FILE *, file);
31290075Sobrien  VA_FIXEDARG (ap, const char *, msgid);
31352284Sobrien
31452284Sobrien  vfprintf (file, _(msgid), ap);
31590075Sobrien  VA_CLOSE (ap);
31652284Sobrien}
31752284Sobrien
31850397Sobrien/* More 'friendly' abort that prints the line and file.
31950397Sobrien   config.h can #define abort fancy_abort if you like that sort of thing.  */
32090075Sobrienextern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
32150397Sobrien
32250397Sobrienvoid
32350397Sobrienfancy_abort ()
32450397Sobrien{
32590075Sobrien  fnotice (stderr, "Internal gcov abort.\n");
32650397Sobrien  exit (FATAL_EXIT_CODE);
32750397Sobrien}
32850397Sobrien
32990075Sobrien/* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
33090075Sobrien   otherwise the output of --help.  */
33150397Sobrien
33250397Sobrienstatic void
33390075Sobrienprint_usage (error_p)
33490075Sobrien     int error_p;
33550397Sobrien{
33690075Sobrien  FILE *file = error_p ? stderr : stdout;
33790075Sobrien  int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
33890075Sobrien  fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
33990075Sobrien  fnotice (file, "Print code coverage information.\n\n");
34090075Sobrien  fnotice (file, "  -h, --help                      Print this help, then exit\n");
34190075Sobrien  fnotice (file, "  -v, --version                   Print version number, then exit\n");
34290075Sobrien  fnotice (file, "  -b, --branch-probabilities      Include branch probabilities in output\n");
34390075Sobrien  fnotice (file, "  -c, --branch-counts             Given counts of branches taken\n\
34490075Sobrien                                    rather than percentages\n");
34590075Sobrien  fnotice (file, "  -n, --no-output                 Do not create an output file\n");
34690075Sobrien  fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
34790075Sobrien                                    source files\n");
34890075Sobrien  fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
349117395Skan  fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
350117395Skan  fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
35190075Sobrien  fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
352117395Skan	   bug_report_url);
35390075Sobrien  exit (status);
35450397Sobrien}
35550397Sobrien
35690075Sobrien/* Print version information and exit.  */
35790075Sobrien
35890075Sobrienstatic void
35990075Sobrienprint_version ()
36090075Sobrien{
36190075Sobrien  fnotice (stdout, "gcov (GCC) %s\n", version_string);
36290075Sobrien  fnotice (stdout, "Copyright (C) 2001 Free Software Foundation, Inc.\n");
36390075Sobrien  fnotice (stdout,
36490075Sobrien	   "This is free software; see the source for copying conditions.  There is NO\n\
36590075Sobrienwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
36690075Sobrien  exit (SUCCESS_EXIT_CODE);
36790075Sobrien}
36890075Sobrien
36990075Sobrienstatic const struct option options[] =
37090075Sobrien{
37190075Sobrien  { "help",                 no_argument,       NULL, 'h' },
37290075Sobrien  { "version",              no_argument,       NULL, 'v' },
37390075Sobrien  { "branch-probabilities", no_argument,       NULL, 'b' },
37490075Sobrien  { "branch-counts",        no_argument,       NULL, 'c' },
37590075Sobrien  { "no-output",            no_argument,       NULL, 'n' },
37690075Sobrien  { "long-file-names",      no_argument,       NULL, 'l' },
37790075Sobrien  { "function-summaries",   no_argument,       NULL, 'f' },
378117395Skan  { "preserve-paths",       no_argument,       NULL, 'p' },
379117395Skan  { "object-directory",     required_argument, NULL, 'o' },
380117395Skan  { "object-file",          required_argument, NULL, 'o' },
38190075Sobrien};
38290075Sobrien
38350397Sobrien/* Parse the command line.  */
38450397Sobrien
38550397Sobrienstatic void
38650397Sobrienprocess_args (argc, argv)
38750397Sobrien     int argc;
38850397Sobrien     char **argv;
38950397Sobrien{
39090075Sobrien  int opt;
39150397Sobrien
392117395Skan  while ((opt = getopt_long (argc, argv, "hvbclnfo:p", options, NULL)) != -1)
39350397Sobrien    {
39490075Sobrien      switch (opt)
39550397Sobrien	{
39690075Sobrien	case 'h':
39790075Sobrien	  print_usage (false);
39890075Sobrien	  /* print_usage will exit.  */
39990075Sobrien	case 'v':
40090075Sobrien	  print_version ();
40190075Sobrien	  /* print_version will exit.  */
40290075Sobrien	case 'b':
40390075Sobrien	  output_branch_probs = 1;
40490075Sobrien	  break;
40590075Sobrien	case 'c':
40690075Sobrien	  output_branch_counts = 1;
40790075Sobrien	  break;
40890075Sobrien	case 'n':
40990075Sobrien	  output_gcov_file = 0;
41090075Sobrien	  break;
41190075Sobrien	case 'l':
41290075Sobrien	  output_long_names = 1;
41390075Sobrien	  break;
41490075Sobrien	case 'f':
41590075Sobrien	  output_function_summary = 1;
41690075Sobrien	  break;
41790075Sobrien	case 'o':
41890075Sobrien	  object_directory = optarg;
41990075Sobrien	  break;
420117395Skan	case 'p':
421117395Skan	  preserve_paths = 1;
422117395Skan	  break;
42390075Sobrien	default:
42490075Sobrien	  print_usage (true);
42590075Sobrien	  /* print_usage will exit.  */
42650397Sobrien	}
42750397Sobrien    }
42850397Sobrien
42990075Sobrien  if (optind != argc - 1)
43090075Sobrien    print_usage (true);
43190075Sobrien
43290075Sobrien  input_file_name = argv[optind];
43350397Sobrien}
43450397Sobrien
43550397Sobrien
436117395Skan/* Find and open the .bb, .da, and .bbg files. If OBJECT_DIRECTORY is
437117395Skan   not specified, these are looked for in the current directory, and
438117395Skan   named from the basename of the input_file_name sans extension. If
439117395Skan   OBJECT_DIRECTORY is specified and is a directory, the files are in
440117395Skan   that directory, but named from the basename of the input_file_name,
441117395Skan   sans extension. Otherwise OBJECT_DIRECTORY is taken to be the name
442117395Skan   of the object *file*, and the data files are named from that.  */
44350397Sobrien
44450397Sobrienstatic void
44550397Sobrienopen_files ()
44650397Sobrien{
44750397Sobrien  char *cptr;
448117395Skan  char *name;
449117395Skan  int length = strlen (input_file_name);
450117395Skan  int base;
451117395Skan
452117395Skan  if (object_directory && object_directory[0])
45350397Sobrien    {
454117395Skan      struct stat status;
45550397Sobrien
456117395Skan      length += strlen (object_directory) + 2;
457117395Skan      name = xmalloc (length);
458117395Skan      name[0] = 0;
459117395Skan
460117395Skan      base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
461117395Skan      strcat (name, object_directory);
462117395Skan      if (base && name[strlen (name) - 1] != '/')
463117395Skan	strcat (name, "/");
46450397Sobrien    }
46550397Sobrien  else
46650397Sobrien    {
467117395Skan      name = xmalloc (length + 1);
468117395Skan      name[0] = 0;
469117395Skan      base = 1;
47050397Sobrien    }
471117395Skan
472117395Skan  if (base)
473117395Skan    {
474117395Skan      /* Append source file name */
475117395Skan      cptr = strrchr (input_file_name, '/');
476117395Skan      cptr = cptr ? cptr + 1 : input_file_name;
47750397Sobrien
478117395Skan      strcat (name, cptr);
479117395Skan    }
480117395Skan  /* Remove the extension.  */
481117395Skan  cptr = strrchr (name, '.');
48250397Sobrien  if (cptr)
483117395Skan    *cptr = 0;
484117395Skan
485117395Skan  length = strlen (name);
486117395Skan  da_file_name = xmalloc (length + 4);
487117395Skan  bb_file_name = xmalloc (length + 4);
488117395Skan  bbg_file_name = xmalloc (length + 5);
48950397Sobrien
490117395Skan  strcpy (da_file_name, name);
491117395Skan  strcpy (bb_file_name, name);
492117395Skan  strcpy (bbg_file_name, name);
493117395Skan  strcpy (da_file_name + length, ".da");
494117395Skan  strcpy (bb_file_name + length, ".bb");
495117395Skan  strcpy (bbg_file_name + length, ".bbg");
49650397Sobrien
49790075Sobrien  bb_file = fopen (bb_file_name, "rb");
49850397Sobrien  if (bb_file == NULL)
49950397Sobrien    {
50052284Sobrien      fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
50150397Sobrien      exit (FATAL_EXIT_CODE);
50250397Sobrien    }
50350397Sobrien
504117395Skan  bbg_file = fopen (bbg_file_name, "rb");
505117395Skan  if (bbg_file == NULL)
506117395Skan    {
507117395Skan      fnotice (stderr, "Could not open program flow graph file %s.\n",
508117395Skan	       bbg_file_name);
509117395Skan      exit (FATAL_EXIT_CODE);
510117395Skan    }
511117395Skan
512117395Skan  {
513117395Skan    struct stat status;
514117395Skan
515117395Skan    if (!fstat (fileno (bb_file), &status))
516117395Skan      bb_file_time = status.st_mtime;
517117395Skan  }
518117395Skan
51950397Sobrien  /* If none of the functions in the file were executed, then there won't
52050397Sobrien     be a .da file.  Just assume that all counts are zero in this case.  */
52190075Sobrien  da_file = fopen (da_file_name, "rb");
52250397Sobrien  if (da_file == NULL)
52350397Sobrien    {
52452284Sobrien      fnotice (stderr, "Could not open data file %s.\n", da_file_name);
52552284Sobrien      fnotice (stderr, "Assuming that all execution counts are zero.\n");
52650397Sobrien    }
52790075Sobrien
52850397Sobrien  /* Check for empty .bbg file.  This indicates that there is no executable
52950397Sobrien     code in this source file.  */
53050397Sobrien  /* Set the EOF condition if at the end of file.  */
53150397Sobrien  ungetc (getc (bbg_file), bbg_file);
53250397Sobrien  if (feof (bbg_file))
53350397Sobrien    {
53452284Sobrien      fnotice (stderr, "No executable code associated with file %s.\n",
53550397Sobrien	       input_file_name);
53650397Sobrien      exit (FATAL_EXIT_CODE);
53750397Sobrien    }
53850397Sobrien}
53950397Sobrien
54050397Sobrien/* Initialize a new arc.  */
54150397Sobrien
54250397Sobrienstatic void
54350397Sobrieninit_arc (arcptr, source, target, bb_graph)
54450397Sobrien     struct adj_list *arcptr;
54550397Sobrien     int source, target;
54650397Sobrien     struct bb_info *bb_graph;
54750397Sobrien{
54850397Sobrien  arcptr->target = target;
54950397Sobrien  arcptr->source = source;
55050397Sobrien
55150397Sobrien  arcptr->arc_count = 0;
55250397Sobrien  arcptr->count_valid = 0;
55350397Sobrien  arcptr->on_tree = 0;
55450397Sobrien  arcptr->fake = 0;
55550397Sobrien  arcptr->fall_through = 0;
55650397Sobrien
55750397Sobrien  arcptr->succ_next = bb_graph[source].succ;
55850397Sobrien  bb_graph[source].succ = arcptr;
55950397Sobrien  bb_graph[source].succ_count++;
56050397Sobrien
56150397Sobrien  arcptr->pred_next = bb_graph[target].pred;
56250397Sobrien  bb_graph[target].pred = arcptr;
56350397Sobrien  bb_graph[target].pred_count++;
56450397Sobrien}
56550397Sobrien
56690075Sobrien/* Reverse the arcs on an arc list.  */
56750397Sobrien
56850397Sobrienstatic struct adj_list *
56950397Sobrienreverse_arcs (arcptr)
57050397Sobrien     struct adj_list *arcptr;
57150397Sobrien{
57250397Sobrien  struct adj_list *prev = 0;
57350397Sobrien  struct adj_list *next;
57450397Sobrien
57550397Sobrien  for ( ; arcptr; arcptr = next)
57650397Sobrien    {
57750397Sobrien      next = arcptr->succ_next;
57850397Sobrien      arcptr->succ_next = prev;
57950397Sobrien      prev = arcptr;
58050397Sobrien    }
58150397Sobrien
58250397Sobrien  return prev;
58350397Sobrien}
58450397Sobrien
585117395Skan/* Reads profiles from the .da file and compute a hybrid profile.  */
58650397Sobrien
587117395Skanstatic gcov_type *
588117395Skanread_profile (function_name, cfg_checksum, instr_arcs)
589117395Skan     char *function_name;
590117395Skan     long cfg_checksum;
591117395Skan     int instr_arcs;
592117395Skan{
593117395Skan  int i;
594117395Skan  int okay = 1;
595117395Skan  gcov_type *profile;
596117395Skan  char *function_name_buffer;
597117395Skan  int function_name_buffer_len;
598117395Skan
599117395Skan  profile = xmalloc (sizeof (gcov_type) * instr_arcs);
600117395Skan  function_name_buffer_len = strlen (function_name) + 1;
601117395Skan  function_name_buffer = xmalloc (function_name_buffer_len + 1);
602117395Skan
603117395Skan  for (i = 0; i < instr_arcs; i++)
604117395Skan    profile[i] = 0;
605117395Skan
606117395Skan  if (!da_file)
607117395Skan    return profile;
608117395Skan
609117395Skan  rewind (da_file);
610117395Skan  while (1)
611117395Skan    {
612117395Skan      long magic, extra_bytes;
613117395Skan      long func_count;
614117395Skan      int i;
615117395Skan
616117395Skan      if (__read_long (&magic, da_file, 4) != 0)
617117395Skan	break;
618117395Skan
619117395Skan      if (magic != -123)
620117395Skan	{
621117395Skan	  okay = 0;
622117395Skan	  break;
623117395Skan	}
624117395Skan
625117395Skan      if (__read_long (&func_count, da_file, 4) != 0)
626117395Skan	{
627117395Skan	  okay = 0;
628117395Skan	  break;
629117395Skan	}
630117395Skan
631117395Skan      if (__read_long (&extra_bytes, da_file, 4) != 0)
632117395Skan	{
633117395Skan	  okay = 0;
634117395Skan	  break;
635117395Skan	}
636117395Skan
637117395Skan      /* skip extra data emited by __bb_exit_func.  */
638117395Skan      fseek (da_file, extra_bytes, SEEK_CUR);
639117395Skan
640117395Skan      for (i = 0; i < func_count; i++)
641117395Skan	{
642117395Skan	  long arc_count;
643117395Skan	  long chksum;
644117395Skan	  int j;
645117395Skan
646117395Skan	  if (__read_gcov_string
647117395Skan	      (function_name_buffer, function_name_buffer_len, da_file,
648117395Skan	       -1) != 0)
649117395Skan	    {
650117395Skan	      okay = 0;
651117395Skan	      break;
652117395Skan	    }
653117395Skan
654117395Skan	  if (__read_long (&chksum, da_file, 4) != 0)
655117395Skan	    {
656117395Skan	      okay = 0;
657117395Skan	      break;
658117395Skan	    }
659117395Skan
660117395Skan	  if (__read_long (&arc_count, da_file, 4) != 0)
661117395Skan	    {
662117395Skan	      okay = 0;
663117395Skan	      break;
664117395Skan	    }
665117395Skan
666117395Skan	  if (strcmp (function_name_buffer, function_name) != 0
667117395Skan	      || arc_count != instr_arcs || chksum != cfg_checksum)
668117395Skan	    {
669117395Skan	      /* skip */
670117395Skan	      if (fseek (da_file, arc_count * 8, SEEK_CUR) < 0)
671117395Skan		{
672117395Skan		  okay = 0;
673117395Skan		  break;
674117395Skan		}
675117395Skan	    }
676117395Skan	  else
677117395Skan	    {
678117395Skan	      gcov_type tmp;
679117395Skan
680117395Skan	      for (j = 0; j < arc_count; j++)
681117395Skan		if (__read_gcov_type (&tmp, da_file, 8) != 0)
682117395Skan		  {
683117395Skan		    okay = 0;
684117395Skan		    break;
685117395Skan		  }
686117395Skan		else
687117395Skan		  {
688117395Skan		    profile[j] += tmp;
689117395Skan		  }
690117395Skan	    }
691117395Skan	}
692117395Skan
693117395Skan      if (!okay)
694117395Skan	break;
695117395Skan
696117395Skan    }
697117395Skan
698117395Skan  free (function_name_buffer);
699117395Skan
700117395Skan  if (!okay)
701117395Skan    {
702117395Skan      fprintf (stderr, ".da file corrupted!\n");
703117395Skan      free (profile);
704117395Skan      abort ();
705117395Skan    }
706117395Skan
707117395Skan  return profile;
708117395Skan}
709117395Skan
71050397Sobrien/* Construct the program flow graph from the .bbg file, and read in the data
71150397Sobrien   in the .da file.  */
71250397Sobrien
71350397Sobrienstatic void
71450397Sobriencreate_program_flow_graph (bptr)
71550397Sobrien     struct bb_info_list *bptr;
71650397Sobrien{
71750397Sobrien  long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
71850397Sobrien  int i;
71950397Sobrien  struct adj_list *arcptr;
72050397Sobrien  struct bb_info *bb_graph;
721117395Skan  long cfg_checksum;
722117395Skan  long instr_arcs = 0;
723117395Skan  gcov_type *profile;
724117395Skan  int profile_pos = 0;
725117395Skan  char *function_name;
726117395Skan  long function_name_len, tmp;
72750397Sobrien
728117395Skan  /* Read function name.  */
729117395Skan  __read_long (&tmp, bbg_file, 4);   /* ignore -1.  */
730117395Skan  __read_long (&function_name_len, bbg_file, 4);
731117395Skan  function_name = xmalloc (function_name_len + 1);
732117395Skan  fread (function_name, 1, function_name_len + 1, bbg_file);
733117395Skan
734117395Skan  /* Skip padding.  */
735117395Skan  tmp = (function_name_len + 1) % 4;
736117395Skan
737117395Skan  if (tmp)
738117395Skan    fseek (bbg_file, 4 - tmp, SEEK_CUR);
739117395Skan
740117395Skan  __read_long (&tmp, bbg_file, 4);   /* ignore -1.  */
741117395Skan
742117395Skan  /* Read the cfg checksum.  */
743117395Skan  __read_long (&cfg_checksum, bbg_file, 4);
744117395Skan
74550397Sobrien  /* Read the number of blocks.  */
74650397Sobrien  __read_long (&num_blocks, bbg_file, 4);
74750397Sobrien
74890075Sobrien  /* Create an array of size bb number of bb_info structs.  */
74990075Sobrien  bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
75050397Sobrien
75150397Sobrien  bptr->bb_graph = bb_graph;
75250397Sobrien  bptr->num_blocks = num_blocks;
75350397Sobrien
75450397Sobrien  /* Read and create each arc from the .bbg file.  */
75550397Sobrien  __read_long (&number_arcs, bbg_file, 4);
75650397Sobrien  for (i = 0; i < num_blocks; i++)
75750397Sobrien    {
75850397Sobrien      int j;
75950397Sobrien
76050397Sobrien      __read_long (&num_arcs_per_block, bbg_file, 4);
76150397Sobrien      for (j = 0; j < num_arcs_per_block; j++)
76250397Sobrien	{
76350397Sobrien	  if (number_arcs-- < 0)
76450397Sobrien	    abort ();
76550397Sobrien
76650397Sobrien	  src = i;
76750397Sobrien	  __read_long (&dest, bbg_file, 4);
76850397Sobrien
76950397Sobrien	  arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
77050397Sobrien	  init_arc (arcptr, src, dest, bb_graph);
77150397Sobrien
77250397Sobrien	  __read_long (&flag_bits, bbg_file, 4);
773117395Skan	  if (flag_bits & 0x1)
774117395Skan	    arcptr->on_tree++;
775117395Skan	  else
776117395Skan	    instr_arcs++;
77750397Sobrien	  arcptr->fake = !! (flag_bits & 0x2);
77850397Sobrien	  arcptr->fall_through = !! (flag_bits & 0x4);
77950397Sobrien	}
78050397Sobrien    }
78150397Sobrien
78250397Sobrien  if (number_arcs)
78350397Sobrien    abort ();
78450397Sobrien
78550397Sobrien  /* Read and ignore the -1 separating the arc list from the arc list of the
78650397Sobrien     next function.  */
78750397Sobrien  __read_long (&src, bbg_file, 4);
78850397Sobrien  if (src != -1)
78950397Sobrien    abort ();
79050397Sobrien
79150397Sobrien  /* Must reverse the order of all succ arcs, to ensure that they match
79250397Sobrien     the order of the data in the .da file.  */
79350397Sobrien
79450397Sobrien  for (i = 0; i < num_blocks; i++)
79550397Sobrien    if (bb_graph[i].succ)
79650397Sobrien      bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
79750397Sobrien
798117395Skan  /* Read profile from the .da file.  */
799117395Skan
800117395Skan  profile = read_profile (function_name, cfg_checksum, instr_arcs);
801117395Skan
80250397Sobrien  /* For each arc not on the spanning tree, set its execution count from
80350397Sobrien     the .da file.  */
80450397Sobrien
80550397Sobrien  /* The first count in the .da file is the number of times that the function
80650397Sobrien     was entered.  This is the exec_count for block zero.  */
80750397Sobrien
80850397Sobrien  /* This duplicates code in branch_prob in profile.c.  */
80950397Sobrien
81050397Sobrien  for (i = 0; i < num_blocks; i++)
81150397Sobrien    for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
81250397Sobrien      if (! arcptr->on_tree)
81350397Sobrien	{
814117395Skan	  arcptr->arc_count = profile[profile_pos++];
81550397Sobrien	  arcptr->count_valid = 1;
81650397Sobrien	  bb_graph[i].succ_count--;
81750397Sobrien	  bb_graph[arcptr->target].pred_count--;
81850397Sobrien	}
819117395Skan  free (profile);
820117395Skan  free (function_name);
82150397Sobrien}
82290075Sobrien
82350397Sobrienstatic void
82450397Sobriensolve_program_flow_graph (bptr)
82550397Sobrien     struct bb_info_list *bptr;
82650397Sobrien{
82790075Sobrien  int passes, changes;
82890075Sobrien  gcov_type total;
82950397Sobrien  int i;
83050397Sobrien  struct adj_list *arcptr;
83150397Sobrien  struct bb_info *bb_graph;
83250397Sobrien  int num_blocks;
83350397Sobrien
83450397Sobrien  num_blocks = bptr->num_blocks;
83550397Sobrien  bb_graph = bptr->bb_graph;
83650397Sobrien
83750397Sobrien  /* For every block in the file,
83850397Sobrien     - if every exit/entrance arc has a known count, then set the block count
83950397Sobrien     - if the block count is known, and every exit/entrance arc but one has
84050397Sobrien       a known execution count, then set the count of the remaining arc
84150397Sobrien
84250397Sobrien     As arc counts are set, decrement the succ/pred count, but don't delete
84350397Sobrien     the arc, that way we can easily tell when all arcs are known, or only
84450397Sobrien     one arc is unknown.  */
84550397Sobrien
84650397Sobrien  /* The order that the basic blocks are iterated through is important.
84750397Sobrien     Since the code that finds spanning trees starts with block 0, low numbered
84850397Sobrien     arcs are put on the spanning tree in preference to high numbered arcs.
84950397Sobrien     Hence, most instrumented arcs are at the end.  Graph solving works much
85050397Sobrien     faster if we propagate numbers from the end to the start.
85150397Sobrien
85250397Sobrien     This takes an average of slightly more than 3 passes.  */
85350397Sobrien
85450397Sobrien  changes = 1;
85550397Sobrien  passes = 0;
85650397Sobrien  while (changes)
85750397Sobrien    {
85850397Sobrien      passes++;
85950397Sobrien      changes = 0;
86050397Sobrien
86150397Sobrien      for (i = num_blocks - 1; i >= 0; i--)
86250397Sobrien	{
86350397Sobrien	  if (! bb_graph[i].count_valid)
86450397Sobrien	    {
86550397Sobrien	      if (bb_graph[i].succ_count == 0)
86650397Sobrien		{
86750397Sobrien		  total = 0;
86850397Sobrien		  for (arcptr = bb_graph[i].succ; arcptr;
86950397Sobrien		       arcptr = arcptr->succ_next)
87050397Sobrien		    total += arcptr->arc_count;
87150397Sobrien		  bb_graph[i].exec_count = total;
87250397Sobrien		  bb_graph[i].count_valid = 1;
87350397Sobrien		  changes = 1;
87450397Sobrien		}
87550397Sobrien	      else if (bb_graph[i].pred_count == 0)
87650397Sobrien		{
87750397Sobrien		  total = 0;
87850397Sobrien		  for (arcptr = bb_graph[i].pred; arcptr;
87950397Sobrien		       arcptr = arcptr->pred_next)
88050397Sobrien		    total += arcptr->arc_count;
88150397Sobrien		  bb_graph[i].exec_count = total;
88250397Sobrien		  bb_graph[i].count_valid = 1;
88350397Sobrien		  changes = 1;
88450397Sobrien		}
88550397Sobrien	    }
88650397Sobrien	  if (bb_graph[i].count_valid)
88750397Sobrien	    {
88850397Sobrien	      if (bb_graph[i].succ_count == 1)
88950397Sobrien		{
89050397Sobrien		  total = 0;
89150397Sobrien		  /* One of the counts will be invalid, but it is zero,
89250397Sobrien		     so adding it in also doesn't hurt.  */
89350397Sobrien		  for (arcptr = bb_graph[i].succ; arcptr;
89450397Sobrien		       arcptr = arcptr->succ_next)
89550397Sobrien		    total += arcptr->arc_count;
89650397Sobrien		  /* Calculate count for remaining arc by conservation.  */
89750397Sobrien		  total = bb_graph[i].exec_count - total;
89850397Sobrien		  /* Search for the invalid arc, and set its count.  */
89950397Sobrien		  for (arcptr = bb_graph[i].succ; arcptr;
90050397Sobrien		       arcptr = arcptr->succ_next)
90150397Sobrien		    if (! arcptr->count_valid)
90250397Sobrien		      break;
90350397Sobrien		  if (! arcptr)
90450397Sobrien		    abort ();
90550397Sobrien		  arcptr->count_valid = 1;
90650397Sobrien		  arcptr->arc_count = total;
90750397Sobrien		  bb_graph[i].succ_count--;
90850397Sobrien
90950397Sobrien		  bb_graph[arcptr->target].pred_count--;
91050397Sobrien		  changes = 1;
91150397Sobrien		}
91250397Sobrien	      if (bb_graph[i].pred_count == 1)
91350397Sobrien		{
91450397Sobrien		  total = 0;
91550397Sobrien		  /* One of the counts will be invalid, but it is zero,
91650397Sobrien		     so adding it in also doesn't hurt.  */
91750397Sobrien		  for (arcptr = bb_graph[i].pred; arcptr;
91850397Sobrien		       arcptr = arcptr->pred_next)
91950397Sobrien		    total += arcptr->arc_count;
92050397Sobrien		  /* Calculate count for remaining arc by conservation.  */
92150397Sobrien		  total = bb_graph[i].exec_count - total;
92250397Sobrien		  /* Search for the invalid arc, and set its count.  */
92350397Sobrien		  for (arcptr = bb_graph[i].pred; arcptr;
92450397Sobrien		       arcptr = arcptr->pred_next)
92550397Sobrien		    if (! arcptr->count_valid)
92650397Sobrien		      break;
92750397Sobrien		  if (! arcptr)
92850397Sobrien		    abort ();
92950397Sobrien		  arcptr->count_valid = 1;
93050397Sobrien		  arcptr->arc_count = total;
93150397Sobrien		  bb_graph[i].pred_count--;
93250397Sobrien
93350397Sobrien		  bb_graph[arcptr->source].succ_count--;
93450397Sobrien		  changes = 1;
93550397Sobrien		}
93650397Sobrien	    }
93750397Sobrien	}
93850397Sobrien    }
93990075Sobrien
94050397Sobrien  /* If the graph has been correctly solved, every block will have a
94150397Sobrien     succ and pred count of zero.  */
94250397Sobrien  for (i = 0; i < num_blocks; i++)
94350397Sobrien    if (bb_graph[i].succ_count || bb_graph[i].pred_count)
94450397Sobrien      abort ();
94550397Sobrien}
94650397Sobrien
94750397Sobrien
94850397Sobrienstatic void
94950397Sobrienread_files ()
95050397Sobrien{
95150397Sobrien  struct stat buf;
95250397Sobrien  struct bb_info_list *list_end = 0;
95350397Sobrien  struct bb_info_list *b_ptr;
95450397Sobrien
95550397Sobrien  while (! feof (bbg_file))
95650397Sobrien    {
95750397Sobrien      b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
95850397Sobrien
95950397Sobrien      b_ptr->next = 0;
96050397Sobrien      if (list_end)
96150397Sobrien	list_end->next = b_ptr;
96250397Sobrien      else
96350397Sobrien	bb_graph_list = b_ptr;
96450397Sobrien      list_end = b_ptr;
96550397Sobrien
96650397Sobrien      /* Read in the data in the .bbg file and reconstruct the program flow
96750397Sobrien	 graph for one function.  */
96850397Sobrien      create_program_flow_graph (b_ptr);
96950397Sobrien
97050397Sobrien      /* Set the EOF condition if at the end of file.  */
97150397Sobrien      ungetc (getc (bbg_file), bbg_file);
97250397Sobrien    }
97350397Sobrien
97450397Sobrien  /* Calculate all of the basic block execution counts and branch
97550397Sobrien     taken probabilities.  */
97650397Sobrien
97750397Sobrien  for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
97850397Sobrien    solve_program_flow_graph (b_ptr);
97950397Sobrien
98050397Sobrien  /* Read in all of the data from the .bb file.   This info will be accessed
98150397Sobrien     sequentially twice.  */
98250397Sobrien  stat (bb_file_name, &buf);
98350397Sobrien  bb_data_size = buf.st_size / 4;
98450397Sobrien
98550397Sobrien  bb_data = (char *) xmalloc ((unsigned) buf.st_size);
98650397Sobrien  fread (bb_data, sizeof (char), buf.st_size, bb_file);
98790075Sobrien
98850397Sobrien  fclose (bb_file);
98950397Sobrien  if (da_file)
99050397Sobrien    fclose (da_file);
99150397Sobrien  fclose (bbg_file);
99250397Sobrien}
99350397Sobrien
99450397Sobrien
99550397Sobrien/* Scan the data in the .bb file to find all source files referenced,
99650397Sobrien   and the largest line number mentioned in each one.  */
99750397Sobrien
99850397Sobrienstatic void
99950397Sobrienscan_for_source_files ()
100050397Sobrien{
100150397Sobrien  struct sourcefile *s_ptr = NULL;
100250397Sobrien  char *ptr;
100390075Sobrien  long count;
100450397Sobrien  long line_num;
100550397Sobrien
100650397Sobrien  /* Search the bb_data to find:
100750397Sobrien     1) The number of sources files contained herein, and
100850397Sobrien     2) The largest line number for each source file.  */
100950397Sobrien
101050397Sobrien  ptr = bb_data;
101150397Sobrien  sources = 0;
101250397Sobrien  for (count = 0; count < bb_data_size; count++)
101350397Sobrien    {
101450397Sobrien      __fetch_long (&line_num, ptr, 4);
101550397Sobrien      ptr += 4;
101650397Sobrien      if (line_num == -1)
101750397Sobrien	{
101850397Sobrien	  /* A source file name follows.  Check to see if we already have
101950397Sobrien	   a sourcefile structure for this file.  */
102050397Sobrien	  s_ptr = sources;
102150397Sobrien	  while (s_ptr && strcmp (s_ptr->name, ptr))
102250397Sobrien	    s_ptr = s_ptr->next;
102350397Sobrien
102450397Sobrien	  if (s_ptr == 0)
102550397Sobrien	    {
102650397Sobrien	      /* No sourcefile structure for this file name exists, create
102750397Sobrien		 a new one, and append it to the front of the sources list.  */
102850397Sobrien	      s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
102990075Sobrien	      s_ptr->name = xstrdup (ptr);
103050397Sobrien	      s_ptr->maxlineno = 0;
103150397Sobrien	      s_ptr->next = sources;
103250397Sobrien	      sources = s_ptr;
103350397Sobrien	    }
103450397Sobrien
103550397Sobrien	  /* Scan past the file name.  */
103650397Sobrien	  {
103750397Sobrien	    long delim;
103850397Sobrien	    do {
103950397Sobrien	      count++;
104050397Sobrien	      __fetch_long (&delim, ptr, 4);
104150397Sobrien	      ptr += 4;
104250397Sobrien	    } while (delim != line_num);
104350397Sobrien	  }
104450397Sobrien	}
104550397Sobrien      else if (line_num == -2)
104650397Sobrien	{
104750397Sobrien	  long delim;
104850397Sobrien
104950397Sobrien	  /* A function name follows.  Ignore it.  */
105050397Sobrien	  do {
105150397Sobrien	    count++;
105250397Sobrien	    __fetch_long (&delim, ptr, 4);
105350397Sobrien	    ptr += 4;
105450397Sobrien	  } while (delim != line_num);
105550397Sobrien	}
105650397Sobrien      /* There will be a zero before the first file name, in which case s_ptr
105750397Sobrien	 will still be uninitialized.  So, only try to set the maxlineno
1058117395Skan	 field if line_num is nonzero.  */
105950397Sobrien      else if (line_num > 0)
106050397Sobrien	{
106150397Sobrien	  if (s_ptr->maxlineno <= line_num)
106250397Sobrien	    s_ptr->maxlineno = line_num + 1;
106350397Sobrien	}
106450397Sobrien      else if (line_num < 0)
106550397Sobrien	{
106690075Sobrien	  /* Don't know what this is, but it's garbage.  */
106790075Sobrien	  abort ();
106850397Sobrien	}
106950397Sobrien    }
107050397Sobrien}
107150397Sobrien
107250397Sobrien
1073117395Skan/* Increment totals in FUNCTION according to arc A_PTR.  */
107450397Sobrien
1075117395Skanstatic void
1076117395Skanaccumulate_branch_counts (function, a_ptr)
1077117395Skan     struct coverage *function;
1078117395Skan     struct arcdata *a_ptr;
1079117395Skan{
1080117395Skan  if (a_ptr->call_insn)
1081117395Skan    {
1082117395Skan      function->calls++;
1083117395Skan      if (a_ptr->total)
1084117395Skan	function->calls_executed++;
1085117395Skan    }
1086117395Skan  else
1087117395Skan    {
1088117395Skan      function->branches++;
1089117395Skan      if (a_ptr->total)
1090117395Skan	function->branches_executed++;
1091117395Skan      if (a_ptr->hits)
1092117395Skan	function->branches_taken++;
1093117395Skan    }
1094117395Skan}
1095117395Skan
109650397Sobrien/* Calculate the branch taken probabilities for all arcs branches at the
109750397Sobrien   end of this block.  */
109850397Sobrien
109950397Sobrienstatic void
1100117395Skancalculate_branch_probs (block_ptr, line_info, function)
1101117395Skan     struct bb_info *block_ptr;
1102117395Skan     struct line_info *line_info;
1103117395Skan     struct coverage *function;
110450397Sobrien{
110590075Sobrien  gcov_type total;
110650397Sobrien  struct adj_list *arcptr;
110750397Sobrien
1108117395Skan  total = block_ptr->exec_count;
1109117395Skan  for (arcptr = block_ptr->succ; arcptr; arcptr = arcptr->succ_next)
111050397Sobrien    {
1111117395Skan      struct arcdata *a_ptr;
1112117395Skan
111350397Sobrien      /* Ignore fall through arcs as they aren't really branches.  */
111450397Sobrien      if (arcptr->fall_through)
111550397Sobrien	continue;
111690075Sobrien
111750397Sobrien      a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
111890075Sobrien      a_ptr->total = total;
1119117395Skan      a_ptr->hits = total ? arcptr->arc_count : 0;
112050397Sobrien      a_ptr->call_insn = arcptr->fake;
112150397Sobrien
1122117395Skan      if (function)
1123117395Skan	accumulate_branch_counts (function, a_ptr);
1124117395Skan      /* Prepend the new branch to the list.  */
1125117395Skan      a_ptr->next = line_info->branches;
1126117395Skan      line_info->branches = a_ptr;
1127117395Skan    }
1128117395Skan}
1129117395Skan
1130117395Skan/* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1131117395Skan   count.  If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1132117395Skan   If DP is zero, no decimal point is printed. Only print 100% when
1133117395Skan   TOP==BOTTOM and only print 0% when TOP=0.  If dp < 0, then simply
1134117395Skan   format TOP.  Return pointer to a static string.  */
1135117395Skan
1136117395Skanstatic char const *
1137117395Skanformat_hwint (top, bottom, dp)
1138117395Skan     HOST_WIDEST_INT top, bottom;
1139117395Skan     int dp;
1140117395Skan{
1141117395Skan  static char buffer[20];
1142117395Skan
1143117395Skan  if (dp >= 0)
1144117395Skan    {
1145117395Skan      float ratio = bottom ? (float)top / bottom : 0;
1146117395Skan      int ix;
1147117395Skan      unsigned limit = 100;
1148117395Skan      unsigned percent;
1149117395Skan
1150117395Skan      for (ix = dp; ix--; )
1151117395Skan	limit *= 10;
1152117395Skan
1153117395Skan      percent = (unsigned) (ratio * limit + (float)0.5);
1154117395Skan      if (percent <= 0 && top)
1155117395Skan	percent = 1;
1156117395Skan      else if (percent >= limit && top != bottom)
1157117395Skan	percent = limit - 1;
1158117395Skan      ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1159117395Skan      if (dp)
116050397Sobrien	{
1161117395Skan	  dp++;
1162117395Skan	  do
116350397Sobrien	    {
1164117395Skan	      buffer[ix+1] = buffer[ix];
1165117395Skan	      ix--;
116650397Sobrien	    }
1167117395Skan	  while (dp--);
1168117395Skan	  buffer[ix + 1] = '.';
116950397Sobrien	}
117050397Sobrien    }
1171117395Skan  else
1172117395Skan    sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, top);
1173117395Skan
1174117395Skan  return buffer;
117550397Sobrien}
117650397Sobrien
1177117395Skan
117850397Sobrien/* Output summary info for a function.  */
117950397Sobrien
118050397Sobrienstatic void
1181117395Skanfunction_summary (function, title)
1182117395Skan     struct coverage *function;
1183117395Skan     const char *title;
118450397Sobrien{
1185117395Skan  if (function->lines)
1186117395Skan    fnotice (stdout, "%s of %d lines executed in %s %s\n",
1187117395Skan	     format_hwint (function->lines_executed,
1188117395Skan			   function->lines, 2),
1189117395Skan	     function->lines, title, function->name);
119050397Sobrien  else
1191117395Skan    fnotice (stdout, "No executable lines in %s %s\n",
1192117395Skan	     title, function->name);
119350397Sobrien
119450397Sobrien  if (output_branch_probs)
119550397Sobrien    {
1196117395Skan      if (function->branches)
119750397Sobrien	{
1198117395Skan	  fnotice (stdout, "%s of %d branches executed in %s %s\n",
1199117395Skan		   format_hwint (function->branches_executed,
1200117395Skan				 function->branches, 2),
1201117395Skan		   function->branches, title, function->name);
120252284Sobrien	  fnotice (stdout,
1203117395Skan		"%s of %d branches taken at least once in %s %s\n",
1204117395Skan		   format_hwint (function->branches_taken,
1205117395Skan				 function->branches, 2),
1206117395Skan		   function->branches, title, function->name);
120750397Sobrien	}
120850397Sobrien      else
1209117395Skan	fnotice (stdout, "No branches in %s %s\n", title, function->name);
1210117395Skan      if (function->calls)
1211117395Skan	fnotice (stdout, "%s of %d calls executed in %s %s\n",
1212117395Skan		 format_hwint (function->calls_executed,
1213117395Skan			       function->calls, 2),
1214117395Skan		 function->calls, title, function->name);
121550397Sobrien      else
1216117395Skan	fnotice (stdout, "No calls in %s %s\n", title, function->name);
121750397Sobrien    }
121850397Sobrien}
121950397Sobrien
1220117395Skan/* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1221117395Skan   affect name generation. With preserve_paths we create a filename
1222117395Skan   from all path components of the source file, replacing '/' with
1223117395Skan   '#', without it we simply take the basename component. With
1224117395Skan   long_output_names we prepend the processed name of the input file
1225117395Skan   to each output name (except when the current source file is the
1226117395Skan   input file, so you don't get a double concatenation). The two
1227117395Skan   components are separated by '##'. Also '.' filename components are
1228117395Skan   removed and '..'  components are renamed to '^'.  */
122950397Sobrien
1230117395Skanstatic char *
1231117395Skanmake_gcov_file_name (src_name)
1232117395Skan     char *src_name;
1233117395Skan{
1234117395Skan  char *cptr;
1235117395Skan  char *name = xmalloc (strlen (src_name) + strlen (input_file_name) + 10);
1236117395Skan
1237117395Skan  name[0] = 0;
1238117395Skan  if (output_long_names && strcmp (src_name, input_file_name))
1239117395Skan    {
1240117395Skan      /* Generate the input filename part.  */
1241117395Skan      cptr = preserve_paths ? NULL : strrchr (input_file_name, '/');
1242117395Skan      cptr = cptr ? cptr + 1 : input_file_name;
1243117395Skan      strcat (name, cptr);
1244117395Skan      strcat (name, "##");
1245117395Skan    }
1246117395Skan
1247117395Skan  /* Generate the source filename part.  */
1248117395Skan  cptr = preserve_paths ? NULL : strrchr (src_name, '/');
1249117395Skan  cptr = cptr ? cptr + 1 : src_name;
1250117395Skan  strcat (name, cptr);
1251117395Skan
1252117395Skan  if (preserve_paths)
1253117395Skan    {
1254117395Skan      /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1255117395Skan      char *prev;
1256117395Skan
1257117395Skan      for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
1258117395Skan 	{
1259117395Skan 	  unsigned shift = 0;
1260117395Skan
1261117395Skan 	  if (prev + 1 == cptr && prev[0] == '.')
1262117395Skan 	    {
1263117395Skan 	      /* Remove '.' */
1264117395Skan 	      shift = 2;
1265117395Skan 	    }
1266117395Skan 	  else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
1267117395Skan 	    {
1268117395Skan 	      /* Convert '..' */
1269117395Skan 	      shift = 1;
1270117395Skan 	      prev[1] = '^';
1271117395Skan 	    }
1272117395Skan 	  else
1273117395Skan 	    *cptr++ = '#';
1274117395Skan 	  if (shift)
1275117395Skan 	    {
1276117395Skan 	      cptr = prev;
1277117395Skan 	      do
1278117395Skan 		prev[0] = prev[shift];
1279117395Skan	      while (*prev++);
1280117395Skan 	    }
1281117395Skan 	}
1282117395Skan    }
1283117395Skan
1284117395Skan  /* Don't strip off the ending for compatibility with tcov, since
1285117395Skan     this results in confusion if there is more than one file with the
1286117395Skan     same basename, e.g. tmp.c and tmp.h.  */
1287117395Skan  strcat (name, ".gcov");
1288117395Skan  return name;
1289117395Skan}
1290117395Skan
1291117395Skan/* Scan through the bb_data, and when the file name matches the
1292117395Skan   source file name, then for each following line number, increment
1293117395Skan   the line number execution count indicated by the execution count of
1294117395Skan   the appropriate basic block.  */
1295117395Skan
129650397Sobrienstatic void
1297117395Skaninit_line_info (line_info, total, maxlineno)
1298117395Skan     struct line_info *line_info;
1299117395Skan     struct coverage *total;
1300117395Skan     long maxlineno;
130150397Sobrien{
1302117395Skan  long block_num = 0;		/* current block number */
1303117395Skan  struct bb_info *block_ptr = NULL;	/* current block ptr */
1304117395Skan  struct coverage function;
1305117395Skan  struct coverage *func_ptr = NULL;
1306117395Skan  struct bb_info_list *current_graph = NULL; /* Graph for current function.  */
1307117395Skan  int is_this_file = 0;	/* We're scanning a block from the desired file.  */
1308117395Skan  char *ptr = bb_data;
130990075Sobrien  long count;
131050397Sobrien  long line_num;
1311117395Skan  struct line_info *line_ptr = 0; /* line info ptr.  */
1312117395Skan
1313117395Skan  memset (&function, 0, sizeof (function));
1314117395Skan  if (output_function_summary)
1315117395Skan    func_ptr = &function;
1316117395Skan
1317117395Skan  for (count = 0; count < bb_data_size; count++)
131850397Sobrien    {
1319117395Skan      __fetch_long (&line_num, ptr, 4);
1320117395Skan      ptr += 4;
1321117395Skan      if (line_num < 0)
132250397Sobrien	{
1323117395Skan	  long delim;
1324117395Skan
1325117395Skan	  if (line_num == -1)
132650397Sobrien	    {
1327117395Skan	      /* Marks the beginning of a file name.  Check to see
1328117395Skan	     	 whether this is the filename we are currently
1329117395Skan	     	 collecting data for.  */
1330117395Skan	      is_this_file = !strcmp (total->name, ptr);
133150397Sobrien	    }
1332117395Skan	  else if (line_num == -2)
133350397Sobrien	    {
1334117395Skan	      /* Marks the start of a new function.  Advance to the
1335117395Skan	     	 next program flow graph.  */
1336117395Skan	      if (!current_graph)
1337117395Skan		current_graph = bb_graph_list;
1338117395Skan	      else
133950397Sobrien		{
1340117395Skan		  if (block_num == current_graph->num_blocks - 1)
1341117395Skan		    /* Last block falls through to exit.  */
1342117395Skan		    ;
1343117395Skan		  else if (block_num == current_graph->num_blocks - 2)
134450397Sobrien		    {
1345117395Skan		      if (output_branch_probs && is_this_file)
1346117395Skan			calculate_branch_probs (block_ptr, line_ptr, func_ptr);
134750397Sobrien		    }
134850397Sobrien		  else
134950397Sobrien		    {
1350117395Skan		      fnotice (stderr,
1351117395Skan			       "didn't use all bb entries of graph, function %s\n",
1352117395Skan			       function.name);
1353117395Skan		      fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
1354117395Skan			       block_num, current_graph->num_blocks);
135550397Sobrien		    }
1356117395Skan		  if (func_ptr && is_this_file)
1357117395Skan		    function_summary (func_ptr, "function");
1358117395Skan		  current_graph = current_graph->next;
135950397Sobrien		}
1360117395Skan	      block_num = 0;
1361117395Skan	      block_ptr = current_graph->bb_graph;
1362117395Skan	      memset (&function, 0, sizeof (function));
1363117395Skan	      function.name = ptr;
136450397Sobrien	    }
1365117395Skan	  else
1366117395Skan	    {
1367117395Skan	      fnotice (stderr, "ERROR: unexpected line number %ld\n", line_num);
1368117395Skan	      abort ();
1369117395Skan	    }
1370117395Skan
1371117395Skan	  /* Scan past the string.  */
1372117395Skan	  for (delim = 0; delim != line_num; count++)
1373117395Skan	    {
1374117395Skan	      __fetch_long (&delim, ptr, 4);
1375117395Skan	      ptr += 4;
1376117395Skan	    }
137750397Sobrien	}
1378117395Skan      else if (!line_num)
137950397Sobrien	{
1380117395Skan	  /* Marks the end of a block.  */
1381117395Skan	  if (block_num >= current_graph->num_blocks)
138250397Sobrien	    {
1383117395Skan	      fnotice (stderr, "ERROR: too many basic blocks in function %s\n",
1384117395Skan		       function.name);
1385117395Skan	      abort ();
138650397Sobrien	    }
1387117395Skan
1388117395Skan	  if (output_branch_probs && is_this_file)
1389117395Skan	    calculate_branch_probs (block_ptr, line_ptr, func_ptr);
1390117395Skan
1391117395Skan	  block_num++;
1392117395Skan	  block_ptr++;
139350397Sobrien	}
1394117395Skan      else if (is_this_file)
139550397Sobrien	{
1396117395Skan	  if (line_num >= maxlineno)
139750397Sobrien	    {
1398117395Skan	      fnotice (stderr, "ERROR: out of range line number in function %s\n",
1399117395Skan		       function.name);
1400117395Skan	      abort ();
140150397Sobrien	    }
140250397Sobrien
1403117395Skan	  line_ptr = &line_info[line_num];
1404117395Skan	  if (func_ptr)
140550397Sobrien	    {
1406117395Skan	      if (!line_ptr->exists)
1407117395Skan		func_ptr->lines++;
1408117395Skan	      if (!line_ptr->count && block_ptr->exec_count)
1409117395Skan		func_ptr->lines_executed++;
1410117395Skan	    }
1411117395Skan
1412117395Skan	  /* Accumulate execution data for this line number.  */
1413117395Skan	  line_ptr->count += block_ptr->exec_count;
1414117395Skan	  line_ptr->exists = 1;
1415117395Skan	}
1416117395Skan    }
1417117395Skan
1418117395Skan  if (func_ptr && is_this_file)
1419117395Skan    function_summary (func_ptr, "function");
1420117395Skan
1421117395Skan  /* Calculate summary test coverage statistics.  */
1422117395Skan  for (line_num = 1, line_ptr = &line_info[line_num];
1423117395Skan       line_num < maxlineno; line_num++, line_ptr++)
1424117395Skan    {
1425117395Skan      struct arcdata *a_ptr, *prev, *next;
1426117395Skan
1427117395Skan      if (line_ptr->exists)
1428117395Skan	{
1429117395Skan	  total->lines++;
1430117395Skan	  if (line_ptr->count)
1431117395Skan	    total->lines_executed++;
1432117395Skan	}
143390075Sobrien
1434117395Skan      /* Total and reverse the branch information.  */
1435117395Skan      for (a_ptr = line_ptr->branches, prev = NULL; a_ptr; a_ptr = next)
1436117395Skan	{
1437117395Skan	  next = a_ptr->next;
1438117395Skan	  a_ptr->next = prev;
1439117395Skan	  prev = a_ptr;
144050397Sobrien
1441117395Skan	  accumulate_branch_counts (total, a_ptr);
1442117395Skan	}
1443117395Skan      line_ptr->branches = prev;
1444117395Skan    }
1445117395Skan}
144650397Sobrien
1447117395Skan/* Read in the source file one line at a time, and output that line to
1448117395Skan   the gcov file preceded by its execution count and other
1449117395Skan   information.  */
145050397Sobrien
1451117395Skanstatic void
1452117395Skanoutput_line_info (gcov_file, line_info, total, maxlineno)
1453117395Skan     FILE *gcov_file;
1454117395Skan     const struct line_info *line_info;
1455117395Skan     const struct coverage *total;
1456117395Skan     long maxlineno;
1457117395Skan{
1458117395Skan  FILE *source_file;
1459117395Skan  long line_num;                    /* current line number */
1460117395Skan  const struct line_info *line_ptr; /* current line info ptr.  */
1461117395Skan  char string[STRING_SIZE];         /* line buffer.  */
1462117395Skan  char const *retval = "";	    /* status of source file reading.  */
146350397Sobrien
1464117395Skan  fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, total->name);
1465117395Skan  fprintf (gcov_file, "%9s:%5d:Object:%s\n", "-", 0, bb_file_name);
1466117395Skan
1467117395Skan  source_file = fopen (total->name, "r");
1468117395Skan  if (!source_file)
1469117395Skan    {
1470117395Skan      fnotice (stderr, "Could not open source file %s.\n", total->name);
1471117395Skan      retval = NULL;
1472117395Skan    }
1473117395Skan  else
1474117395Skan    {
1475117395Skan      struct stat status;
1476117395Skan
1477117395Skan      if (!fstat (fileno (source_file), &status)
1478117395Skan	  && status.st_mtime > bb_file_time)
1479117395Skan	{
1480117395Skan	  fnotice (stderr, "Warning: source file %s is newer than %s\n",
1481117395Skan		   total->name, bb_file_name);
1482117395Skan	  fprintf (gcov_file, "%9s:%5d:Source is newer than compiler output\n",
1483117395Skan		   "-", 0);
1484117395Skan	}
1485117395Skan    }
148650397Sobrien
1487117395Skan  for (line_num = 1, line_ptr = &line_info[line_num];
1488117395Skan       line_num < maxlineno; line_num++, line_ptr++)
1489117395Skan    {
1490117395Skan      /* For lines which don't exist in the .bb file, print '-' before
1491117395Skan 	 the source line.  For lines which exist but were never
1492117395Skan 	 executed, print '#####' before the source line.  Otherwise,
1493117395Skan 	 print the execution count before the source line.  There are
1494117395Skan 	 16 spaces of indentation added before the source line so that
1495117395Skan 	 tabs won't be messed up.  */
1496117395Skan      fprintf (gcov_file, "%9s:%5ld:",
1497117395Skan	       !line_ptr->exists ? "-"
1498117395Skan	       : !line_ptr->count ? "#####"
1499117395Skan	       : format_hwint (line_ptr->count, 0, -1), line_num);
1500117395Skan
1501117395Skan      if (retval)
1502117395Skan	{
1503117395Skan	  /* Copy source line.  */
1504117395Skan	  do
150550397Sobrien	    {
1506117395Skan	      retval = fgets (string, STRING_SIZE, source_file);
1507117395Skan	      if (!retval)
1508117395Skan		{
1509117395Skan		  fnotice (stderr,
1510117395Skan			   "Unexpected EOF while reading source file %s.\n",
1511117395Skan			   total->name);
1512117395Skan		  break;
1513117395Skan		}
1514117395Skan	      fputs (retval, gcov_file);
151550397Sobrien	    }
1516117395Skan	  while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1517117395Skan	}
1518117395Skan      if (!retval)
1519117395Skan	fputs ("??\n", gcov_file);
1520117395Skan
1521117395Skan      if (output_branch_probs)
1522117395Skan	{
1523117395Skan	  int i;
1524117395Skan	  struct arcdata *a_ptr;
1525117395Skan
1526117395Skan	  for (i = 0, a_ptr = line_ptr->branches; a_ptr;
1527117395Skan	       a_ptr = a_ptr->next, i++)
152850397Sobrien	    {
1529117395Skan	      if (a_ptr->call_insn)
153050397Sobrien		{
1531117395Skan		  if (a_ptr->total == 0)
1532117395Skan		    fnotice (gcov_file, "call   %2d never executed\n", i);
153350397Sobrien		  else
1534117395Skan		    fnotice
1535117395Skan		      (gcov_file, "call   %2d returns %s\n", i,
1536117395Skan		       format_hwint (a_ptr->total - a_ptr->hits,
1537117395Skan				     a_ptr->total,
1538117395Skan				     -output_branch_counts));
153950397Sobrien		}
154050397Sobrien	      else
154150397Sobrien		{
1542117395Skan		  if (a_ptr->total == 0)
1543117395Skan		    fnotice (gcov_file, "branch %2d never executed\n", i);
1544117395Skan		  else
1545117395Skan		    fnotice
1546117395Skan		      (gcov_file, "branch %2d taken %s\n", i,
1547117395Skan		       format_hwint (a_ptr->hits, a_ptr->total,
1548117395Skan				     -output_branch_counts));
154950397Sobrien		}
155050397Sobrien	    }
1551117395Skan	}
1552117395Skan    }
1553117395Skan
1554117395Skan  /* Handle all remaining source lines.  There may be lines after the
1555117395Skan     last line of code.  */
1556117395Skan  if (retval)
1557117395Skan    {
1558117395Skan      for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
1559117395Skan	{
1560117395Skan	  fprintf (gcov_file, "%9s:%5ld:%s", "-", line_num, retval);
1561117395Skan
1562117395Skan	  while (!retval[0] || retval[strlen (retval) - 1] != '\n')
1563117395Skan	    {
1564117395Skan	      retval = fgets (string, STRING_SIZE, source_file);
1565117395Skan	      if (!retval)
1566117395Skan		break;
1567117395Skan	      fputs (retval, gcov_file);
1568117395Skan	    }
1569117395Skan	}
1570117395Skan    }
1571117395Skan
1572117395Skan  if (source_file)
1573117395Skan    fclose (source_file);
1574117395Skan}
157550397Sobrien
1576117395Skan/* Calculate line execution counts, and output a .gcov file for source
1577117395Skan   file S_PTR. Allocate an array big enough to hold a count for each
1578117395Skan   line.  Scan through the bb_data, and when the file name matches the
1579117395Skan   current file name, then for each following line number, increment
1580117395Skan   the line number execution count indicated by the execution count of
1581117395Skan   the appropriate basic block.  */
158250397Sobrien
1583117395Skanstatic void
1584117395Skanoutput_data (s_ptr)
1585117395Skan	     struct sourcefile *s_ptr;
1586117395Skan{
1587117395Skan  struct line_info *line_info	/* line info data */
1588117395Skan    = (struct line_info *) xcalloc (s_ptr->maxlineno,
1589117395Skan				    sizeof (struct line_info));
1590117395Skan  long line_num;
1591117395Skan  struct coverage total;
1592117395Skan
1593117395Skan  memset (&total, 0, sizeof (total));
1594117395Skan  total.name = s_ptr->name;
1595117395Skan
1596117395Skan  init_line_info (line_info, &total, s_ptr->maxlineno);
1597117395Skan  function_summary (&total, "file");
159850397Sobrien
1599117395Skan  if (output_gcov_file)
1600117395Skan    {
1601117395Skan      /* Now the statistics are ready.  Read in the source file one
1602117395Skan	 line at a time, and output that line to the gcov file
1603117395Skan	 preceded by its execution information.  */
1604117395Skan
1605117395Skan      char *gcov_file_name = make_gcov_file_name (total.name);
1606117395Skan      FILE *gcov_file = fopen (gcov_file_name, "w");
1607117395Skan
1608117395Skan      if (gcov_file)
1609117395Skan	{
1610117395Skan	  fnotice (stdout, "Creating %s.\n", gcov_file_name);
1611117395Skan	  output_line_info (gcov_file, line_info, &total, s_ptr->maxlineno);
1612117395Skan	  if (ferror (gcov_file))
1613117395Skan	    fnotice (stderr, "Error writing output file %s.\n",
1614117395Skan		     gcov_file_name);
1615117395Skan	  fclose (gcov_file);
1616117395Skan	}
1617117395Skan      else
1618117395Skan	fnotice (stderr, "Could not open output file %s.\n", gcov_file_name);
1619117395Skan      free (gcov_file_name);
1620117395Skan    }
162150397Sobrien
1622117395Skan  /* Free data.  */
1623117395Skan  for (line_num = 1; line_num != s_ptr->maxlineno; line_num++)
1624117395Skan    {
1625117395Skan      struct arcdata *branch, *next;
162650397Sobrien
1627117395Skan      for (branch = line_info[line_num].branches; branch; branch = next)
1628117395Skan	{
1629117395Skan	  next = branch->next;
1630117395Skan	  free (branch);
163150397Sobrien	}
163250397Sobrien    }
1633117395Skan  free (line_info);
163450397Sobrien}
1635