OSDN Git Service

2005-10-17 Paul Thomas <pault@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / gcov.c
index 4c9af4d..adce8c8 100644 (file)
@@ -1,7 +1,7 @@
 /* Gcov.c: prepend line execution counts and branch probabilities to a
    source file.
    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by James E. Wilson of Cygnus Support.
    Mangled by Bob Manson of Cygnus Support.
    Mangled further by Nathan Sidwell <nathan@codesourcery.com>
@@ -18,8 +18,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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 /* ??? Print a list of the ten blocks with the highest execution counts,
    and list the line numbers corresponding to those blocks.  Also, perhaps
@@ -47,7 +47,6 @@ Boston, MA 02111-1307, USA.  */
 #include "tm.h"
 #include "intl.h"
 #include "version.h"
-#undef abort
 
 #include <getopt.h>
 
@@ -82,6 +81,8 @@ typedef struct arc_info
 
   /* transition counts.  */
   gcov_type count;
+  /* used in cycle search, so that we do not clobber original counts.  */
+  gcov_type cs_count;
 
   unsigned int count_valid : 1;
   unsigned int on_tree : 1;
@@ -346,6 +347,9 @@ main (int argc, char **argv)
 {
   int argno;
 
+  /* Unlock the stdio streams.  */
+  unlock_std_streams ();
+
   gcc_init_libintl ();
 
   argno = process_args (argc, argv);
@@ -363,25 +367,14 @@ main (int argc, char **argv)
 }
 
 static void
-fnotice (FILE *file, const char *msgid, ...)
+fnotice (FILE *file, const char *cmsgid, ...)
 {
   va_list ap;
 
-  va_start (ap, msgid);
-  vfprintf (file, _(msgid), ap);
+  va_start (ap, cmsgid);
+  vfprintf (file, _(cmsgid), 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 (void) ATTRIBUTE_NORETURN;
-
-void
-fancy_abort (void)
-{
-  fnotice (stderr, "Internal gcov abort.\n");
-  exit (FATAL_EXIT_CODE);
-}
 \f
 /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
    otherwise the output of --help.  */
@@ -418,11 +411,12 @@ static void
 print_version (void)
 {
   fnotice (stdout, "gcov (GCC) %s\n", version_string);
-  fnotice (stdout, "Copyright (C) 2003 Free Software Foundation, Inc.\n");
+  fprintf (stdout, "Copyright %s 2004 Free Software Foundation, Inc.\n",
+          _("(C)"));
   fnotice (stdout,
-          "This is free software; see the source for copying conditions.\n"
-          "There is NO warranty; not even for MERCHANTABILITY or \n"
-          "FITNESS FOR A PARTICULAR PURPOSE.\n\n");
+          _("This is free software; see the source for copying conditions.\n"
+            "There is NO warranty; not even for MERCHANTABILITY or \n"
+            "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
   exit (SUCCESS_EXIT_CODE);
 }
 
@@ -546,16 +540,16 @@ process_file (const char *file_name)
 
          if (gcov_file)
            {
-             fnotice (stdout, "%s:creating `%s'\n",
+             fnotice (stdout, "%s:creating '%s'\n",
                       src->name, gcov_file_name);
              output_lines (gcov_file, src);
              if (ferror (gcov_file))
-                   fnotice (stderr, "%s:error writing output file `%s'\n",
+                   fnotice (stderr, "%s:error writing output file '%s'\n",
                             src->name, gcov_file_name);
              fclose (gcov_file);
            }
          else
-           fnotice (stderr, "%s:could not open output file `%s'\n",
+           fnotice (stderr, "%s:could not open output file '%s'\n",
                     src->name, gcov_file_name);
          free (gcov_file_name);
        }
@@ -725,7 +719,7 @@ read_graph_file (void)
       GCOV_UNSIGNED2STRING (v, version);
       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
 
-      fnotice (stderr, "%s:version `%.4s', prefer `%.4s'\n",
+      fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n",
               bbg_file_name, v, e);
     }
   bbg_stamp = gcov_read_unsigned ();
@@ -777,7 +771,7 @@ read_graph_file (void)
       else if (fn && tag == GCOV_TAG_BLOCKS)
        {
          if (fn->blocks)
-           fnotice (stderr, "%s:already seen blocks for `%s'\n",
+           fnotice (stderr, "%s:already seen blocks for '%s'\n",
                     bbg_file_name, fn->name);
          else
            {
@@ -893,18 +887,16 @@ read_graph_file (void)
        }
       gcov_sync (base, length);
       if (gcov_is_error ())
-       break;
-    }
-  if (!gcov_is_eof ())
-    {
-    corrupt:;
-      fnotice (stderr, "%s:corrupted\n", bbg_file_name);
-      gcov_close ();
-      return 1;
+       {
+       corrupt:;
+         fnotice (stderr, "%s:corrupted\n", bbg_file_name);
+         gcov_close ();
+         return 1;
+       }
     }
   gcov_close ();
 
-  /* We built everything backwards, so nreverse them all */
+  /* We built everything backwards, so nreverse them all */
 
   /* Reverse sources. Not strictly necessary, but we'll then process
      them in the 'expected' order.  */
@@ -989,7 +981,7 @@ read_count_file (void)
       GCOV_UNSIGNED2STRING (v, version);
       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
       
-      fnotice (stderr, "%s:version `%.4s', prefer version `%.4s'\n",
+      fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n",
               da_file_name, v, e);
     }
   tag = gcov_read_unsigned ();
@@ -1021,7 +1013,7 @@ read_count_file (void)
                fn_n = NULL;
              else
                {
-                 fnotice (stderr, "%s:unknown function `%u'\n",
+                 fnotice (stderr, "%s:unknown function '%u'\n",
                           da_file_name, ident);
                  break;
                }
@@ -1034,7 +1026,7 @@ read_count_file (void)
          else if (gcov_read_unsigned () != fn->checksum)
            {
            mismatch:;
-             fnotice (stderr, "%s:profile mismatch for `%s'\n",
+             fnotice (stderr, "%s:profile mismatch for '%s'\n",
                       da_file_name, fn->name);
              goto cleanup;
            }
@@ -1052,14 +1044,11 @@ read_count_file (void)
        }
       gcov_sync (base, length);
       if ((error = gcov_is_error ()))
-       break;
-    }
-
-  if (!gcov_is_eof ())
-    {
-      fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
-              da_file_name);
-      goto cleanup;
+       {
+         fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n",
+                  da_file_name);
+         goto cleanup;
+       }
     }
 
   gcov_close ();
@@ -1080,12 +1069,12 @@ solve_flow_graph (function_t *fn)
   block_t *invalid_blocks = NULL;  /* invalid, but inferable blocks.  */
 
   if (fn->num_blocks < 2)
-    fnotice (stderr, "%s:`%s' lacks entry and/or exit blocks\n",
+    fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
             bbg_file_name, fn->name);
   else
     {
       if (fn->blocks[0].num_pred)
-       fnotice (stderr, "%s:`%s' has arcs to entry block\n",
+       fnotice (stderr, "%s:'%s' has arcs to entry block\n",
                 bbg_file_name, fn->name);
       else
        /* We can't deduce the entry block counts from the lack of
@@ -1093,7 +1082,7 @@ solve_flow_graph (function_t *fn)
        fn->blocks[0].num_pred = ~(unsigned)0;
 
       if (fn->blocks[fn->num_blocks - 1].num_succ)
-       fnotice (stderr, "%s:`%s' has arcs from exit block\n",
+       fnotice (stderr, "%s:'%s' has arcs from exit block\n",
                 bbg_file_name, fn->name);
       else
        /* Likewise, we can't deduce exit block counts from the lack
@@ -1301,7 +1290,7 @@ solve_flow_graph (function_t *fn)
   for (ix = 0; ix < fn->num_blocks; ix++)
     if (!fn->blocks[ix].count_valid)
       {
-       fnotice (stderr, "%s:graph is unsolvable for `%s'\n",
+       fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
                 bbg_file_name, fn->name);
        break;
       }
@@ -1381,14 +1370,14 @@ format_gcov (gcov_type top, gcov_type bottom, int dp)
 static void
 function_summary (const coverage_t *coverage, const char *title)
 {
-  fnotice (stdout, "%s `%s'\n", title, coverage->name);
+  fnotice (stdout, "%s '%s'\n", title, coverage->name);
 
   if (coverage->lines)
     fnotice (stdout, "Lines executed:%s of %d\n",
             format_gcov (coverage->lines_executed, coverage->lines, 2),
             coverage->lines);
   else
-    fnotice (stdout, "No executable lines");
+    fnotice (stdout, "No executable lines\n");
 
   if (flag_branches)
     {
@@ -1551,7 +1540,7 @@ add_line_counts (coverage_t *coverage, function_t *fn)
        }
     }
   if (!line)
-    fnotice (stderr, "%s:no lines for `%s'\n", bbg_file_name, fn->name);
+    fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
 }
 
 /* Accumulate the line counts of a file.  */
@@ -1622,6 +1611,10 @@ accumulate_line_counts (source_t *src)
                  if (flag_branches)
                    add_branch_counts (&src->coverage, arc);
                }
+
+             /* Initialize the cs_count.  */
+             for (arc = block->succ; arc; arc = arc->succ_next)
+               arc->cs_count = arc->count;
            }
 
          /* Find the loops. This uses the algorithm described in
@@ -1638,7 +1631,8 @@ accumulate_line_counts (source_t *src)
 
             For each loop we find, locate the arc with the smallest
             transition count, and add that to the cumulative
-            count. Remove the arc from consideration.  */
+            count.  Decrease flow over the cycle and remove the arc
+            from consideration.  */
          for (block = line->u.blocks; block; block = block->chain)
            {
              block_t *head = block;
@@ -1664,25 +1658,33 @@ accumulate_line_counts (source_t *src)
                  if (dst == block)
                    {
                      /* Found a closing arc.  */
-                     gcov_type cycle_count = arc->count;
+                     gcov_type cycle_count = arc->cs_count;
                      arc_t *cycle_arc = arc;
                      arc_t *probe_arc;
 
                      /* Locate the smallest arc count of the loop.  */
                      for (dst = head; (probe_arc = dst->u.cycle.arc);
                           dst = probe_arc->src)
-                       if (cycle_count > probe_arc->count)
+                       if (cycle_count > probe_arc->cs_count)
                          {
-                           cycle_count = probe_arc->count;
+                           cycle_count = probe_arc->cs_count;
                            cycle_arc = probe_arc;
                          }
 
                      count += cycle_count;
                      cycle_arc->cycle = 1;
+
+                     /* Remove the flow from the cycle.  */
+                     arc->cs_count -= cycle_count;
+                     for (dst = head; (probe_arc = dst->u.cycle.arc);
+                          dst = probe_arc->src)
+                       probe_arc->cs_count -= cycle_count;
+
                      /* Unwind to the cyclic arc.  */
                      while (head != cycle_arc->src)
                        {
                          arc = head->u.cycle.arc;
+                         head->u.cycle.arc = NULL;
                          head = arc->src;
                        }
                      /* Move on.  */
@@ -1722,7 +1724,7 @@ accumulate_line_counts (source_t *src)
     }
 }
 
-/* Ouput information about ARC number IX.  Returns nonzero if
+/* Output information about ARC number IX.  Returns nonzero if
    anything is output.  */
 
 static int
@@ -1775,7 +1777,7 @@ output_lines (FILE *gcov_file, const source_t *src)
   const line_t *line;           /* current line info ptr.  */
   char string[STRING_SIZE];     /* line buffer.  */
   char const *retval = "";     /* status of source file reading.  */
-  function_t *fn = src->functions;
+  function_t *fn = NULL;
 
   fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
   fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
@@ -1797,13 +1799,16 @@ output_lines (FILE *gcov_file, const source_t *src)
       if (!fstat (fileno (source_file), &status)
          && status.st_mtime > bbg_file_time)
        {
-         fnotice (stderr, "%s:source file is newer than graph file `%s'\n",
+         fnotice (stderr, "%s:source file is newer than graph file '%s'\n",
                   src->name, bbg_file_name);
          fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n",
                   "-", 0);
        }
     }
 
+  if (flag_branches)
+    fn = src->functions;
+
   for (line_num = 1, line = &src->lines[line_num];
        line_num < src->num_lines; line_num++, line++)
     {
@@ -1811,11 +1816,11 @@ output_lines (FILE *gcov_file, const source_t *src)
        {
          arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
          gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
-
+         
          for (; arc; arc = arc->pred_next)
            if (arc->fake)
              return_count -= arc->count;
-
+         
          fprintf (gcov_file, "function %s", fn->name);
          fprintf (gcov_file, " called %s",
                   format_gcov (fn->blocks[0].count, 0, -1));