OSDN Git Service

* basic-block.h: Improve comments.
[pf3gnuchains/gcc-fork.git] / gcc / gcov.c
index eff68f1..457c4ad 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 Free Software Foundation, Inc.
+   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
    Contributed by James E. Wilson of Cygnus Support.
    Mangled by Bob Manson of Cygnus Support.
 
@@ -16,7 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with Gcov; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* ??? The code in final.c that produces the struct bb assumes that there is
    no padding between the fields.  This is not necessary true.  The current
@@ -43,8 +45,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "config.h"
 #include "system.h"
-#include <sys/stat.h>
-#include "gansidecl.h"
+#include "intl.h"
+#undef abort
 
 #include "gcov-io.h"
 
@@ -137,7 +139,8 @@ struct bb_info {
 
 struct arcdata
 {
-  int prob;
+  int hits;
+  int total;
   int call_insn;
   struct arcdata *next;
 };
@@ -212,20 +215,46 @@ 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));
-char * xmalloc ();
+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, "");
+#else
+  setlocale (LC_ALL, "");
+#endif
+
+  (void) bindtextdomain (PACKAGE, localedir);
+  (void) textdomain (PACKAGE);
+
   process_args (argc, argv);
 
   open_files ();
@@ -239,26 +268,35 @@ main (argc, argv)
   return 0;
 }
 
-char *
-xmalloc (size)
-     unsigned size;
+static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
+static void
+fnotice VPARAMS ((FILE *file, const char *msgid, ...))
 {
-  register char *value = (char *) malloc (size);
-  if (value == 0)
-    {
-      fprintf (stderr, "error: virtual memory exhausted");
-      exit (FATAL_EXIT_CODE);
-    }
-  return value;
+#ifndef ANSI_PROTOTYPES
+  FILE *file;
+  const char *msgid;
+#endif
+  va_list ap;
+
+  VA_START (ap, msgid);
+
+#ifndef ANSI_PROTOTYPES
+  file = va_arg (ap, FILE *);
+  msgid = va_arg (ap, const char *);
+#endif
+
+  vfprintf (file, _(msgid), ap);
+  va_end (ap);
 }
 
 /* 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 ()
 {
-  fprintf (stderr, "Internal gcc abort.\n");
+  fnotice (stderr, "Internal gcov abort.\n");
   exit (FATAL_EXIT_CODE);
 }
 \f
@@ -267,7 +305,7 @@ fancy_abort ()
 static void
 print_usage ()
 {
-  fprintf (stderr, "gcov [-b] [-v] [-n] [-l] [-f] [-o OBJDIR] file\n");
+  fnotice (stderr, "gcov [-b] [-v] [-n] [-l] [-f] [-o OBJDIR] file\n");
   exit (FATAL_EXIT_CODE);
 }
 
@@ -286,6 +324,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')
@@ -343,7 +383,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);
@@ -364,44 +404,44 @@ 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)
     {
-      fprintf (stderr, "Could not open basic block file %s.\n", bb_file_name);
+      fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
       exit (FATAL_EXIT_CODE);
     }
 
   /* 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)
     {
-      fprintf (stderr, "Could not open data file %s.\n", da_file_name);
-      fprintf (stderr, "Assuming that all execution counts are zero.\n");
+      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)
     {
-      fprintf (stderr, "Could not open program flow graph file %s.\n",
+      fnotice (stderr, "Could not open program flow graph file %s.\n",
               bbg_file_name);
       exit (FATAL_EXIT_CODE);
     }
@@ -412,7 +452,7 @@ open_files ()
   ungetc (getc (bbg_file), bbg_file);
   if (feof (bbg_file))
     {
-      fprintf (stderr, "No executable code associated with file %s.\n",
+      fnotice (stderr, "No executable code associated with file %s.\n",
               input_file_name);
       exit (FATAL_EXIT_CODE);
     }
@@ -480,10 +520,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;
@@ -541,7 +579,7 @@ create_program_flow_graph (bptr)
     for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
       if (! arcptr->on_tree)
        {
-         long tmp_count = 0;;
+         long tmp_count = 0;
          if (da_file && __read_long (&tmp_count, da_file, 8))
            abort();
 
@@ -713,10 +751,10 @@ read_files ()
   if (da_file)
     {
       if (feof (da_file))
-       fprintf (stderr, ".da file contents exhausted too early\n");
+       fnotice (stderr, ".da file contents exhausted too early\n");
       /* Should be at end of file now.  */
       if (__read_long (&total, da_file, 8) == 0)
-       fprintf (stderr, ".da file contents not exhausted\n");
+       fnotice (stderr, ".da file contents not exhausted\n");
     }
 
   /* Calculate all of the basic block execution counts and branch
@@ -774,8 +812,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;
@@ -853,10 +890,11 @@ calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num)
        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)
@@ -864,15 +902,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++;
            }
        }
@@ -897,33 +935,33 @@ static void
 function_summary ()
 {
   if (function_source_lines)
-    fprintf (stdout, "%6.2f%% 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
-    fprintf (stdout, "No executable source lines in function %s\n",
+    fnotice (stdout, "No executable source lines in function %s\n",
             function_name);
 
   if (output_branch_probs)
     {
       if (function_branches)
        {
-         fprintf (stdout, "%6.2f%% 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);
-         fprintf (stdout,
+         fnotice (stdout,
                "%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
-       fprintf (stdout, "No branches in function %s\n", function_name);
+       fnotice (stdout, "No branches in function %s\n", function_name);
       if (function_calls)
-       fprintf (stdout, "%6.2f%% 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
-       fprintf (stdout, "No calls in function %s\n", function_name);
+       fnotice (stdout, "No calls in function %s\n", function_name);
     }
 }
 
@@ -978,7 +1016,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);
@@ -991,17 +1035,11 @@ 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 = (long *) xcalloc (sizeof (long), 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.  */
@@ -1054,10 +1092,10 @@ output_data ()
                      }
                    else
                      {
-                       fprintf (stderr,
+                       fnotice (stderr,
                                 "didn't use all bb entries of graph, function %s\n",
                                 function_name);
-                       fprintf (stderr, "block_num = %ld, num_blocks = %d\n",
+                       fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
                                 block_num, current_graph->num_blocks);
                      }
 
@@ -1095,7 +1133,7 @@ output_data ()
 
                if (block_num >= current_graph->num_blocks)
                  {
-                   fprintf (stderr, "ERROR: too many basic blocks in .bb file %s\n",
+                   fnotice (stderr, "ERROR: too many basic blocks in .bb file %s\n",
                             function_name);
                    abort ();
                  }
@@ -1155,15 +1193,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++;
                    }
                }
@@ -1171,34 +1209,34 @@ output_data ()
        }
 
       if (total_source_lines)
-       fprintf (stdout,
+       fnotice (stdout,
                 "%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
-       fprintf (stdout, "No executable source lines in file %s\n",
+       fnotice (stdout, "No executable source lines in file %s\n",
                 source_file_name);
 
       if (output_branch_probs)
        {
          if (total_branches)
            {
-             fprintf (stdout, "%6.2f%% 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);
-             fprintf (stdout,
+             fnotice (stdout,
                    "%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
-           fprintf (stdout, "No branches in file %s\n", source_file_name);
+           fnotice (stdout, "No branches in file %s\n", source_file_name);
          if (total_calls)
-           fprintf (stdout, "%6.2f%% 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
-           fprintf (stdout, "No calls in file %s\n", source_file_name);
+           fnotice (stdout, "No calls in file %s\n", source_file_name);
        }
 
       if (output_gcov_file)
@@ -1210,7 +1248,7 @@ output_data ()
          source_file = fopen (source_file_name, "r");
          if (source_file == NULL)
            {
-             fprintf (stderr, "Could not open source file %s.\n",
+             fnotice (stderr, "Could not open source file %s.\n",
                       source_file_name);
              free (line_counts);
              free (line_exists);
@@ -1218,7 +1256,7 @@ output_data ()
            }
 
          count = strlen (source_file_name);
-         cptr = rindex (s_ptr->name, '/');
+         cptr = strrchr (s_ptr->name, '/');
          if (cptr)
            cptr = cptr + 1;
          else
@@ -1227,7 +1265,7 @@ output_data ()
            {
              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
@@ -1235,7 +1273,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
@@ -1244,7 +1282,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
@@ -1260,7 +1298,7 @@ output_data ()
 
          if (gcov_file == NULL)
            {
-             fprintf (stderr, "Could not open output file %s.\n",
+             fnotice (stderr, "Could not open output file %s.\n",
                       gcov_file_name);
              fclose (source_file);
              free (line_counts);
@@ -1268,7 +1306,7 @@ output_data ()
              continue;
            }
 
-         fprintf (stdout, "Creating %s.\n", gcov_file_name);
+         fnotice (stdout, "Creating %s.\n", gcov_file_name);
 
          for (count = 1; count < s_ptr->maxlineno; count++)
            {
@@ -1311,29 +1349,48 @@ output_data ()
                    {
                      if (a_ptr->call_insn)
                        {
-                         if (a_ptr->prob == -1)
-                           fprintf (gcov_file, "call %d never executed\n", i);
-                         else
-                           fprintf (gcov_file,
-                                    "call %d returns = %d%%\n",
-                                    i, 100 - a_ptr->prob);
+                         if (a_ptr->total == 0)
+                           fnotice (gcov_file, "call %d never executed\n", i);
+                           else
+                             {
+                               if (output_branch_counts)
+                                 fnotice (gcov_file,
+                                          "call %d returns = %d\n",
+                                          i, a_ptr->total - a_ptr->hits);
+                               else
+                                  fnotice (gcov_file,
+                                          "call %d returns = %d%%\n",
+                                           i, 100 - ((a_ptr->hits * 100) +
+                                           (a_ptr->total >> 1))/a_ptr->total);
+                             }
                        }
                      else
                        {
-                         if (a_ptr->prob == -1)
-                           fprintf (gcov_file, "branch %d never executed\n",
+                         if (a_ptr->total == 0)
+                           fnotice (gcov_file, "branch %d never executed\n",
                                     i);
                          else
-                           fprintf (gcov_file, "branch %d taken = %d%%\n", i,
-                                    a_ptr->prob);
+                           {
+                             if (output_branch_counts)
+                               fnotice (gcov_file,
+                                        "branch %d taken = %d\n",
+                                         i, a_ptr->hits);
+                             else
+                                fnotice (gcov_file,
+                                         "branch %d taken = %d%%\n", i,
+                                         ((a_ptr->hits * 100) +
+                                          (a_ptr->total >> 1))/
+                                          a_ptr->total);
+
+                           }
                        }
-                   }
-               }
+                  }
+             }
 
              /* Gracefully handle errors while reading the source file.  */
              if (retval == NULL)
                {
-                 fprintf (stderr,
+                 fnotice (stderr,
                           "Unexpected EOF while reading source file %s.\n",
                           source_file_name);
                  break;