OSDN Git Service

* gcov.c (output_data): Use HOST_WIDEST_INT_PRINT_DEC to output
[pf3gnuchains/gcc-fork.git] / gcc / gcov.c
index 9c0798d..0251a65 100644 (file)
@@ -1,6 +1,7 @@
 /* Gcov.c: prepend line execution counts and branch probabilities to a
    source file.
-   Copyright (C) 1990, 91, 92, 93, 94, 96, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
+   1999, 2000, 2001 Free Software Foundation, Inc.
    Contributed by James E. Wilson of Cygnus Support.
    Mangled by Bob Manson of Cygnus Support.
 
@@ -45,7 +46,9 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #include "system.h"
 #include "intl.h"
+#undef abort
 
+typedef HOST_WIDEST_INT gcov_type;
 #include "gcov-io.h"
 
 /* The .bb file format consists of several lists of 4-byte integers
@@ -102,7 +105,7 @@ struct sourcefile *sources;
 struct adj_list {
   int source;
   int target;
-  int arc_count;
+  gcov_type arc_count;
   unsigned int count_valid : 1;
   unsigned int on_tree : 1;
   unsigned int fake : 1;
@@ -121,9 +124,9 @@ struct adj_list {
 struct bb_info {
   struct adj_list *succ;
   struct adj_list *pred;
-  int succ_count;
-  int pred_count;
-  int exec_count;
+  gcov_type succ_count;
+  gcov_type pred_count;
+  gcov_type exec_count;
   unsigned int count_valid : 1;
   unsigned int on_tree : 1;
 #if 0
@@ -137,7 +140,8 @@ struct bb_info {
 
 struct arcdata
 {
-  int prob;
+  gcov_type hits;
+  gcov_type total;
   int call_insn;
   struct arcdata *next;
 };
@@ -212,22 +216,45 @@ static int output_function_summary = 0;
 
 static char *object_directory = 0;
 
+/* Output the number of times a branch was taken as opposed to the percentage
+   of times it was taken.  Turned on by the -c option */
+
+static int output_branch_counts = 0;
+
 /* Forward declarations.  */
-static void process_args PROTO ((int, char **));
-static void open_files PROTO ((void));
-static void read_files PROTO ((void));
-static void scan_for_source_files PROTO ((void));
-static void output_data PROTO ((void));
-static void print_usage PROTO ((void)) ATTRIBUTE_NORETURN;
+static void process_args PARAMS ((int, char **));
+static void open_files PARAMS ((void));
+static void read_files PARAMS ((void));
+static void scan_for_source_files PARAMS ((void));
+static void output_data PARAMS ((void));
+static void print_usage PARAMS ((void)) ATTRIBUTE_NORETURN;
+static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
+static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
+static void create_program_flow_graph PARAMS ((struct bb_info_list *));
+static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
+static void calculate_branch_probs PARAMS ((struct bb_info_list *, int,
+                                           struct arcdata **, int));
+static void function_summary PARAMS ((void));
+
+extern int main PARAMS ((int, char **));
 
 int
 main (argc, argv)
      int argc;
      char **argv;
 {
+/* LC_CTYPE determines the character set used by the terminal so it has be set
+   to output messages correctly.  */
+
+#ifdef HAVE_LC_MESSAGES
+  setlocale (LC_CTYPE, "");
   setlocale (LC_MESSAGES, "");
-  bindtextdomain (PACKAGE, localedir);
-  textdomain (PACKAGE);
+#else
+  setlocale (LC_ALL, "");
+#endif
+
+  (void) bindtextdomain (PACKAGE, localedir);
+  (void) textdomain (PACKAGE);
 
   process_args (argc, argv);
 
@@ -242,11 +269,12 @@ main (argc, argv)
   return 0;
 }
 
-static void fnotice    PVPROTO ((const char *, ...)) ATTRIBUTE_PRINTF_1;
+static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
 static void
-fnotice VPROTO ((const char *msgid, ...))
+fnotice VPARAMS ((FILE *file, const char *msgid, ...))
 {
 #ifndef ANSI_PROTOTYPES
+  FILE *file;
   const char *msgid;
 #endif
   va_list ap;
@@ -254,34 +282,22 @@ fnotice VPROTO ((const char *msgid, ...))
   VA_START (ap, msgid);
 
 #ifndef ANSI_PROTOTYPES
+  file = va_arg (ap, FILE *);
   msgid = va_arg (ap, const char *);
 #endif
 
-  vfprintf (stderr, _(msgid), ap);
+  vfprintf (file, _(msgid), ap);
   va_end (ap);
 }
 
-
-PTR
-xmalloc (size)
-  size_t size;
-{
-  register PTR value = (PTR) malloc (size);
-  if (value == 0)
-    {
-      fnotice (stderr, "error: virtual memory exhausted");
-      exit (FATAL_EXIT_CODE);
-    }
-  return value;
-}
-
 /* More 'friendly' abort that prints the line and file.
    config.h can #define abort fancy_abort if you like that sort of thing.  */
+extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
 
 void
 fancy_abort ()
 {
-  fnotice (stderr, "Internal gcc abort.\n");
+  fnotice (stderr, "Internal gcov abort.\n");
   exit (FATAL_EXIT_CODE);
 }
 \f
@@ -309,6 +325,8 @@ process_args (argc, argv)
        {
          if (argv[i][1] == 'b')
            output_branch_probs = 1;
+         else if (argv[i][1] == 'c')
+           output_branch_counts = 1;
          else if (argv[i][1] == 'v')
            fputs (gcov_version_string, stderr);
          else if (argv[i][1] == 'n')
@@ -366,7 +384,7 @@ open_files ()
          strcat (bbg_file_name, "/");
        }
 
-      cptr = rindex (input_file_name, '/');
+      cptr = strrchr (input_file_name, '/');
       if (cptr)
        {
          strcat (da_file_name, cptr + 1);
@@ -387,25 +405,25 @@ open_files ()
       strcpy (bbg_file_name, input_file_name);
     }
 
-  cptr = rindex (bb_file_name, '.');
+  cptr = strrchr (bb_file_name, '.');
   if (cptr)
     strcpy (cptr, ".bb");
   else
     strcat (bb_file_name, ".bb");
 
-  cptr = rindex (da_file_name, '.');
+  cptr = strrchr (da_file_name, '.');
   if (cptr)
     strcpy (cptr, ".da");
   else
     strcat (da_file_name, ".da");
 
-  cptr = rindex (bbg_file_name, '.');
+  cptr = strrchr (bbg_file_name, '.');
   if (cptr)
     strcpy (cptr, ".bbg");
   else
     strcat (bbg_file_name, ".bbg");
 
-  bb_file = fopen (bb_file_name, "r");
+  bb_file = fopen (bb_file_name, "rb");
   if (bb_file == NULL)
     {
       fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
@@ -414,14 +432,14 @@ open_files ()
 
   /* If none of the functions in the file were executed, then there won't
      be a .da file.  Just assume that all counts are zero in this case.  */
-  da_file = fopen (da_file_name, "r");
+  da_file = fopen (da_file_name, "rb");
   if (da_file == NULL)
     {
       fnotice (stderr, "Could not open data file %s.\n", da_file_name);
       fnotice (stderr, "Assuming that all execution counts are zero.\n");
     }
-    
-  bbg_file = fopen (bbg_file_name, "r");
+
+  bbg_file = fopen (bbg_file_name, "rb");
   if (bbg_file == NULL)
     {
       fnotice (stderr, "Could not open program flow graph file %s.\n",
@@ -503,10 +521,8 @@ create_program_flow_graph (bptr)
   /* Read the number of blocks.  */
   __read_long (&num_blocks, bbg_file, 4);
 
-  /* Create an array of size bb number of bb_info structs.  Bzero it.  */
-  bb_graph = (struct bb_info *) xmalloc (num_blocks
-                                        * sizeof (struct bb_info));
-  bzero ((char *) bb_graph, sizeof (struct bb_info) * num_blocks);
+  /* Create an array of size bb number of bb_info structs.  */
+  bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
 
   bptr->bb_graph = bb_graph;
   bptr->num_blocks = num_blocks;
@@ -564,8 +580,8 @@ create_program_flow_graph (bptr)
     for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
       if (! arcptr->on_tree)
        {
-         long tmp_count = 0;;
-         if (da_file && __read_long (&tmp_count, da_file, 8))
+         gcov_type tmp_count = 0;
+         if (da_file && __read_gcov_type (&tmp_count, da_file, 8))
            abort();
 
          arcptr->arc_count = tmp_count;
@@ -574,12 +590,13 @@ create_program_flow_graph (bptr)
          bb_graph[arcptr->target].pred_count--;
        }
 }
-  
+
 static void
 solve_program_flow_graph (bptr)
      struct bb_info_list *bptr;
 {
-  int passes, changes, total;
+  int passes, changes;
+  gcov_type total;
   int i;
   struct adj_list *arcptr;
   struct bb_info *bb_graph;
@@ -690,7 +707,7 @@ solve_program_flow_graph (bptr)
            }
        }
     }
-             
+
   /* If the graph has been correctly solved, every block will have a
      succ and pred count of zero.  */
   for (i = 0; i < num_blocks; i++)
@@ -755,7 +772,7 @@ read_files ()
 
   bb_data = (char *) xmalloc ((unsigned) buf.st_size);
   fread (bb_data, sizeof (char), buf.st_size, bb_file);
-  
+
   fclose (bb_file);
   if (da_file)
     fclose (da_file);
@@ -797,8 +814,7 @@ scan_for_source_files ()
              /* No sourcefile structure for this file name exists, create
                 a new one, and append it to the front of the sources list.  */
              s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
-             s_ptr->name = xmalloc (strlen ((char *) ptr) + 1);
-             strcpy (s_ptr->name, (char *) ptr);
+             s_ptr->name = xstrdup (ptr);
              s_ptr->maxlineno = 0;
              s_ptr->next = sources;
              sources = s_ptr;
@@ -874,12 +890,13 @@ calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num)
 
       if (arcptr->fall_through)
        continue;
-                     
+
       a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
+      a_ptr->total = total;
       if (total == 0)
-       a_ptr->prob = -1;
+          a_ptr->hits = 0;
       else
-       a_ptr->prob = ((arcptr->arc_count * 100) + (total >> 1)) / total;
+          a_ptr->hits = arcptr->arc_count;
       a_ptr->call_insn = arcptr->fake;
 
       if (output_function_summary)
@@ -887,15 +904,15 @@ calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num)
          if (a_ptr->call_insn)
            {
              function_calls++;
-             if (a_ptr->prob != -1)
+             if (a_ptr->total != 0)
                function_calls_executed++;
            }
          else
            {
              function_branches++;
-             if (a_ptr->prob != -1)
+             if (a_ptr->total != 0)
                function_branches_executed++;
-             if (a_ptr->prob > 0)
+             if (a_ptr->hits > 0)
                function_branches_taken++;
            }
        }
@@ -920,7 +937,7 @@ static void
 function_summary ()
 {
   if (function_source_lines)
-    fnotice (stdout, "%6.2lf%% of %d source lines executed in function %s\n",
+    fnotice (stdout, "%6.2f%% of %d source lines executed in function %s\n",
             (((double) function_source_lines_executed / function_source_lines)
              * 100), function_source_lines, function_name);
   else
@@ -931,18 +948,18 @@ function_summary ()
     {
       if (function_branches)
        {
-         fnotice (stdout, "%6.2lf%% of %d branches executed in function %s\n",
+         fnotice (stdout, "%6.2f%% of %d branches executed in function %s\n",
                   (((double) function_branches_executed / function_branches)
                    * 100), function_branches, function_name);
          fnotice (stdout,
-               "%6.2lf%% of %d branches taken at least once in function %s\n",
+               "%6.2f%% of %d branches taken at least once in function %s\n",
                   (((double) function_branches_taken / function_branches)
                    * 100), function_branches, function_name);
        }
       else
        fnotice (stdout, "No branches in function %s\n", function_name);
       if (function_calls)
-       fnotice (stdout, "%6.2lf%% of %d calls executed in function %s\n",
+       fnotice (stdout, "%6.2f%% of %d calls executed in function %s\n",
                 (((double) function_calls_executed / function_calls)
                  * 100), function_calls, function_name);
       else
@@ -960,7 +977,7 @@ output_data ()
   int this_file;
   /* An array indexed by line number which indicates how many times that line
      was executed.  */
-  long *line_counts;
+  gcov_type *line_counts;
   /* An array indexed by line number which indicates whether the line was
      present in the bb file (i.e. whether it had code associate with it).
      Lines never executed are those which both exist, and have zero execution
@@ -1001,7 +1018,13 @@ output_data ()
     {
       /* If this is a relative file name, and an object directory has been
         specified, then make it relative to the object directory name.  */
-      if (*s_ptr->name != '/' && object_directory != 0
+      if (! (*s_ptr->name == '/' || *s_ptr->name == DIR_SEPARATOR
+            /* Check for disk name on MS-DOS-based systems.  */
+            || (DIR_SEPARATOR == '\\'
+                && s_ptr->name[1] == ':'
+                && (s_ptr->name[2] == DIR_SEPARATOR
+                    || s_ptr->name[2] == '/')))
+         && object_directory != 0
          && *object_directory != '\0')
        {
          int objdir_count = strlen (object_directory);
@@ -1014,18 +1037,12 @@ output_data ()
       else
        source_file_name = s_ptr->name;
 
-      line_counts = (long *) xmalloc (sizeof (long) * s_ptr->maxlineno);
-      bzero ((char *) line_counts, sizeof (long) * s_ptr->maxlineno);
-      line_exists = xmalloc (s_ptr->maxlineno);
-      bzero (line_exists, s_ptr->maxlineno);
+      line_counts = (gcov_type *) xcalloc (sizeof (gcov_type), s_ptr->maxlineno);
+      line_exists = xcalloc (1, s_ptr->maxlineno);
       if (output_branch_probs)
-       {
-         branch_probs = (struct arcdata **) xmalloc (sizeof (struct arcdata *)
-                                                     * s_ptr->maxlineno);
-         bzero ((char *) branch_probs, 
-                sizeof (struct arcdata *) * s_ptr->maxlineno);
-       }
-      
+       branch_probs = (struct arcdata **)
+         xcalloc (sizeof (struct arcdata *), s_ptr->maxlineno);
+
       /* There will be a zero at the beginning of the bb info, before the
         first list of line numbers, so must initialize block_num to 0.  */
       block_num = 0;
@@ -1049,7 +1066,7 @@ output_data ()
                  this_file = 0;
                else
                  this_file = 1;
-             
+
                /* Scan past the file name.  */
                do {
                  count++;
@@ -1080,7 +1097,7 @@ output_data ()
                        fnotice (stderr,
                                 "didn't use all bb entries of graph, function %s\n",
                                 function_name);
-                       fnotice (stderr, "block_num = %d, num_blocks = %d\n",
+                       fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
                                 block_num, current_graph->num_blocks);
                      }
 
@@ -1122,7 +1139,7 @@ output_data ()
                             function_name);
                    abort ();
                  }
-                 
+
                if (output_branch_probs && this_file)
                  calculate_branch_probs (current_graph, block_num,
                                          branch_probs, last_line_num);
@@ -1178,15 +1195,15 @@ output_data ()
                  if (a_ptr->call_insn)
                    {
                      total_calls++;
-                     if (a_ptr->prob != -1)
+                     if (a_ptr->total != 0)
                        total_calls_executed++;
                    }
                  else
                    {
                      total_branches++;
-                     if (a_ptr->prob != -1)
+                     if (a_ptr->total != 0)
                        total_branches_executed++;
-                     if (a_ptr->prob > 0)
+                     if (a_ptr->hits > 0)
                        total_branches_taken++;
                    }
                }
@@ -1195,7 +1212,7 @@ output_data ()
 
       if (total_source_lines)
        fnotice (stdout,
-                "%6.2lf%% of %d source lines executed in file %s\n",
+                "%6.2f%% of %d source lines executed in file %s\n",
                 (((double) total_source_lines_executed / total_source_lines)
                  * 100), total_source_lines, source_file_name);
       else
@@ -1206,18 +1223,18 @@ output_data ()
        {
          if (total_branches)
            {
-             fnotice (stdout, "%6.2lf%% of %d branches executed in file %s\n",
+             fnotice (stdout, "%6.2f%% of %d branches executed in file %s\n",
                       (((double) total_branches_executed / total_branches)
                        * 100), total_branches, source_file_name);
              fnotice (stdout,
-                   "%6.2lf%% of %d branches taken at least once in file %s\n",
+                   "%6.2f%% of %d branches taken at least once in file %s\n",
                       (((double) total_branches_taken / total_branches)
                        * 100), total_branches, source_file_name);
            }
          else
            fnotice (stdout, "No branches in file %s\n", source_file_name);
          if (total_calls)
-           fnotice (stdout, "%6.2lf%% of %d calls executed in file %s\n",
+           fnotice (stdout, "%6.2f%% of %d calls executed in file %s\n",
                     (((double) total_calls_executed / total_calls)
                      * 100), total_calls, source_file_name);
          else
@@ -1229,7 +1246,7 @@ output_data ()
          /* Now the statistics are ready.  Read in the source file one line
             at a time, and output that line to the gcov file preceded by
             its execution count if non zero.  */
-      
+
          source_file = fopen (source_file_name, "r");
          if (source_file == NULL)
            {
@@ -1241,7 +1258,7 @@ output_data ()
            }
 
          count = strlen (source_file_name);
-         cptr = rindex (s_ptr->name, '/');
+         cptr = strrchr (s_ptr->name, '/');
          if (cptr)
            cptr = cptr + 1;
          else
@@ -1249,8 +1266,8 @@ output_data ()
          if (output_long_names && strcmp (cptr, input_file_name))
            {
              gcov_file_name = xmalloc (count + 7 + strlen (input_file_name));
-             
-             cptr = rindex (input_file_name, '/');
+
+             cptr = strrchr (input_file_name, '/');
              if (cptr)
                strcpy (gcov_file_name, cptr + 1);
              else
@@ -1258,7 +1275,7 @@ output_data ()
 
              strcat (gcov_file_name, ".");
 
-             cptr = rindex (source_file_name, '/');
+             cptr = strrchr (source_file_name, '/');
              if (cptr)
                strcat (gcov_file_name, cptr + 1);
              else
@@ -1267,7 +1284,7 @@ output_data ()
          else
            {
              gcov_file_name = xmalloc (count + 6);
-             cptr = rindex (source_file_name, '/');
+             cptr = strrchr (source_file_name, '/');
              if (cptr)
                strcpy (gcov_file_name, cptr + 1);
              else
@@ -1309,8 +1326,12 @@ output_data ()
              if (line_exists[count])
                {
                  if (line_counts[count])
-                   fprintf (gcov_file, "%12ld    %s", line_counts[count],
-                            string);
+                   {
+                     char c[20];
+                     sprintf (c, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)line_counts[count]);
+                     fprintf (gcov_file, "%12s    %s", c,
+                              string);
+                   }
                  else
                    fprintf (gcov_file, "      ######    %s", string);
                }
@@ -1334,24 +1355,47 @@ output_data ()
                    {
                      if (a_ptr->call_insn)
                        {
-                         if (a_ptr->prob == -1)
+                         if (a_ptr->total == 0)
                            fnotice (gcov_file, "call %d never executed\n", i);
-                         else
-                           fnotice (gcov_file,
-                                    "call %d returns = %d%%\n",
-                                    i, 100 - a_ptr->prob);
+                           else
+                             {
+                               if (output_branch_counts)
+                                 fnotice (gcov_file,
+                                          "call %d returns = "
+                                          HOST_WIDEST_INT_PRINT_DEC "\n",
+                                          i, a_ptr->total - a_ptr->hits);
+                               else
+                                  fnotice (gcov_file,
+                                          "call %d returns = "
+                                          HOST_WIDEST_INT_PRINT_DEC "%%\n",
+                                           i, 100 - ((a_ptr->hits * 100) +
+                                           (a_ptr->total >> 1))/a_ptr->total);
+                             }
                        }
                      else
                        {
-                         if (a_ptr->prob == -1)
+                         if (a_ptr->total == 0)
                            fnotice (gcov_file, "branch %d never executed\n",
                                     i);
                          else
-                           fnotice (gcov_file, "branch %d taken = %d%%\n", i,
-                                    a_ptr->prob);
+                           {
+                             if (output_branch_counts)
+                               fnotice (gcov_file,
+                                        "branch %d taken = "
+                                        HOST_WIDEST_INT_PRINT_DEC "\n",
+                                         i, a_ptr->hits);
+                             else
+                                fnotice (gcov_file,
+                                         "branch %d taken = "
+                                        HOST_WIDEST_INT_PRINT_DEC "%%\n", i,
+                                         ((a_ptr->hits * 100) +
+                                          (a_ptr->total >> 1))/
+                                          a_ptr->total);
+
+                           }
                        }
-                   }
-               }
+                  }
+             }
 
              /* Gracefully handle errors while reading the source file.  */
              if (retval == NULL)