gcov.c: Comments updated.
authorTristan Gingold <gingold@adacore.com>
Tue, 12 Jun 2007 15:39:15 +0000 (15:39 +0000)
committerOlivier Hainque <hainque@gcc.gnu.org>
Tue, 12 Jun 2007 15:39:15 +0000 (15:39 +0000)
* gcov.c: Comments updated.
(source_info): Add file_time field.
(source_index): New variable.
(mutiple_files): New variable.
(generate_results): New function extracted from process_file.
(process_file): Save and restore chain of functions, generate
results and free structures only if not merging results.
(release_structures): File names are now freed in create_file_names
(create_file_names): Free previous file names.
(find_source): File date is now read here and modifications in
source files is checked here.
(read_graph_file): Only reverse order of functions for the current
object file.
(make_gcov_file_name): Do not generate long names if input_name is
NULL.
(output_lines): If merging results do not display graph, data and
runs informations.
Checking source file modification is done in find_source.

* doc/gcov.texi: Append an s to sourcefile.

From-SVN: r125649

gcc/ChangeLog
gcc/doc/gcov.texi
gcc/gcov.c

index 8d476fd81ad89aa0340be9a236053aa9ddba4bd6..06501a81bdead9571205bd8215bef6177dd08dd1 100644 (file)
@@ -1,3 +1,26 @@
+2007-06-12  Tristan Gingold  <gingold@adacore.com>
+
+       * gcov.c: Comments updated.
+       (source_info): Add file_time field.
+       (source_index): New variable.
+       (mutiple_files): New variable.
+       (generate_results): New function extracted from process_file.
+       (process_file): Save and restore chain of functions, generate
+       results and free structures only if not merging results.
+       (release_structures): File names are now freed in create_file_names
+       (create_file_names): Free previous file names.
+       (find_source): File date is now read here and modifications in
+       source files is checked here.
+       (read_graph_file): Only reverse order of functions for the current
+       object file.
+       (make_gcov_file_name): Do not generate long names if input_name is
+       NULL.
+       (output_lines): If merging results do not display graph, data and 
+       runs informations.
+       Checking source file modification is done in find_source.
+
+       * doc/gcov.texi: Append an s to sourcefile.
+
 2007-06-12  Bernd Schmidt  <bernd.schmidt@analog.com>
 
        * config/bfin/bfin.md (UNSPEC_NOP): New constant.
index 55c903c7630cd811f19b361f240b1477ae416ac7..1f9f5e80122843b3a06fafdc4d6b73dbe783664b 100644 (file)
@@ -113,7 +113,7 @@ compatible with any other profiling or test coverage mechanism.
 @section Invoking @command{gcov}
 
 @smallexample
-gcov @r{[}@var{options}@r{]} @var{sourcefile}
+gcov @r{[}@var{options}@r{]} @var{sourcefiles}
 @end smallexample
 
 @command{gcov} accepts the following options:
@@ -128,7 +128,7 @@ gcov [@option{-v}|@option{--version}] [@option{-h}|@option{--help}]
      [@option{-l}|@option{--long-file-names}]
      [@option{-p}|@option{--preserve-paths}]
      [@option{-f}|@option{--function-summaries}]
-     [@option{-o}|@option{--object-directory} @var{directory|file}] @var{sourcefile}
+     [@option{-o}|@option{--object-directory} @var{directory|file}] @var{sourcefiles}
      [@option{-u}|@option{--unconditional-branches}]
 @c man end
 @c man begin SEEALSO
index 3b249c7055b84ef11b00c1ce6b8953037ac73246..b177b53cf0f7cf4e5c04050e92c6de78515eb66a 100644 (file)
@@ -29,15 +29,6 @@ Boston, MA 02110-1301, USA.  */
 /* ??? Should have an option to print the number of basic blocks, and the
    percent of them that are covered.  */
 
-/* ??? Does not correctly handle the case where two .bb files refer to
-   the same included source file.  For example, if one has a short
-   file containing only inline functions, which is then included in
-   two other files, then there will be two .bb files which refer to
-   the include file, but there is no way to get the total execution
-   counts for the included file, can only get execution counts for one
-   or the other of the including files. this can be fixed by --ratios
-   --long-file-names --preserve-paths and perl.  */
-
 /* Need an option to show individual block counts, and show
    probabilities of fall through arcs.  */
 
@@ -54,7 +45,7 @@ Boston, MA 02110-1301, USA.  */
 #include "gcov-io.h"
 #include "gcov-io.c"
 
-/* The bbg file is generated by -ftest-coverage option. The da file is
+/* The gcno file is generated by -ftest-coverage option. The gcda file is
    generated by a program compiled with -fprofile-arcs. Their formats
    are documented in gcov-io.h.  */
 
@@ -234,6 +225,7 @@ typedef struct source_info
   /* Name of source file.  */
   char *name;
   unsigned index;
+  time_t file_time;
 
   /* Array of line information.  */
   line_t *lines;
@@ -253,10 +245,15 @@ typedef struct source_info
 
 static function_t *functions;
 
-/* This points to the head of the sourcefile structure list.  */
+/* This points to the head of the sourcefile structure list.  New elements
+   are always prepended.  */
 
 static source_t *sources;
 
+/* Next index for a source file.  */
+
+static unsigned source_index;
+
 /* This holds data summary information.  */
 
 static struct gcov_summary object_summary;
@@ -281,6 +278,13 @@ static char *da_file_name;
 
 static int no_data_file;
 
+/* If there is several input files, compute and display results after
+   reading all data files.  This way if two or more gcda file refer to
+   the same source file (eg inline subprograms in a .h file), the
+   counts are added.  */
+
+static int multiple_files = 0;
+
 /* Output branch probabilities.  */
 
 static int flag_branches = 0;
@@ -330,6 +334,7 @@ static int process_args (int, char **);
 static void print_usage (int) ATTRIBUTE_NORETURN;
 static void print_version (void) ATTRIBUTE_NORETURN;
 static void process_file (const char *);
+static void generate_results (const char *);
 static void create_file_names (const char *);
 static source_t *find_source (const char *);
 static int read_graph_file (void);
@@ -360,12 +365,15 @@ main (int argc, char **argv)
   if (optind == argc)
     print_usage (true);
 
+  if (argc - argno > 1)
+    multiple_files = 1;
+
   for (; argno != argc; argno++)
-    {
-      release_structures ();
+    process_file (argv[argno]);
 
-      process_file (argv[argno]);
-    }
+  generate_results (multiple_files ? NULL : argv[argc - 1]);
+
+  release_structures ();
 
   return 0;
 }
@@ -389,7 +397,7 @@ print_usage (int error_p)
   FILE *file = error_p ? stderr : stdout;
   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
 
-  fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
+  fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE...\n\n");
   fnotice (file, "Print code coverage information.\n\n");
   fnotice (file, "  -h, --help                      Print this help, then exit\n");
   fnotice (file, "  -v, --version                   Print version number, then exit\n");
@@ -499,8 +507,14 @@ process_args (int argc, char **argv)
 static void
 process_file (const char *file_name)
 {
-  source_t *src;
   function_t *fn;
+  function_t *fn_p;
+  function_t *old_functions;
+
+  /* Save and clear the list of current functions.  They will be appended
+     later.  */
+  old_functions = functions;
+  functions = NULL;
 
   create_file_names (file_name);
   if (read_graph_file ())
@@ -515,8 +529,19 @@ process_file (const char *file_name)
   if (read_count_file ())
     return;
 
-  for (fn = functions; fn; fn = fn->next)
+  for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn->next)
     solve_flow_graph (fn);
+
+  if (fn_p)
+    fn_p->next = old_functions;
+}
+
+static void
+generate_results (const char *file_name)
+{
+  source_t *src;
+  function_t *fn;
+
   for (src = sources; src; src = src->next)
     src->lines = XCNEWVEC (line_t, src->num_lines);
   for (fn = functions; fn; fn = fn->next)
@@ -569,12 +594,6 @@ release_structures (void)
   function_t *fn;
   source_t *src;
 
-  free (bbg_file_name);
-  free (da_file_name);
-  da_file_name = bbg_file_name = NULL;
-  bbg_file_time = 0;
-  bbg_stamp = 0;
-
   while ((src = sources))
     {
       sources = src->next;
@@ -620,6 +639,15 @@ create_file_names (const char *file_name)
   int length = strlen (file_name);
   int base;
 
+  /* Free previous file names.  */
+  if (bbg_file_name)
+    free (bbg_file_name);
+  if (da_file_name)
+    free (da_file_name);
+  da_file_name = bbg_file_name = NULL;
+  bbg_file_time = 0;
+  bbg_stamp = 0;
+
   if (object_directory && object_directory[0])
     {
       struct stat status;
@@ -673,20 +701,42 @@ static source_t *
 find_source (const char *file_name)
 {
   source_t *src;
+  struct stat status;
 
   if (!file_name)
     file_name = "<unknown>";
 
   for (src = sources; src; src = src->next)
     if (!strcmp (file_name, src->name))
-      return src;
+      break;
 
-  src = XCNEW (source_t);
-  src->name = xstrdup (file_name);
-  src->coverage.name = src->name;
-  src->index = sources ? sources->index + 1 : 1;
-  src->next = sources;
-  sources = src;
+  if (!src)
+    {
+      src = XCNEW (source_t);
+      src->name = xstrdup (file_name);
+      src->coverage.name = src->name;
+      src->index = source_index++;
+      src->next = sources;
+      sources = src;
+      
+      if (!stat (file_name, &status))
+       src->file_time = status.st_mtime;
+    }
+
+  if (src->file_time > bbg_file_time)
+    {
+      static int info_emitted;
+
+      fnotice (stderr, "%s:source file is newer than graph file '%s'\n",
+              src->name, bbg_file_name);
+      if (!info_emitted)
+       {
+         fnotice (stderr,
+                  "(the message is only displayed one per source file)\n");
+         info_emitted = 1;
+       }
+      src->file_time = 0;
+    }
 
   return src;
 }
@@ -699,6 +749,7 @@ read_graph_file (void)
   unsigned version;
   unsigned current_tag = 0;
   struct function_info *fn = NULL;
+  function_t *old_functions_head = functions;
   source_t *src = NULL;
   unsigned ix;
   unsigned tag;
@@ -920,7 +971,9 @@ read_graph_file (void)
   {
     function_t *fn, *fn_p, *fn_n;
 
-    for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn_n)
+    for (fn_p = old_functions_head, fn = functions;
+        fn != old_functions_head;
+        fn_p = fn, fn = fn_n)
       {
        unsigned ix;
 
@@ -1012,6 +1065,9 @@ read_count_file (void)
          unsigned ident = gcov_read_unsigned ();
          struct function_info *fn_n = functions;
 
+         /* Try to find the function in the list.
+            To speed up the search, first start from the last function
+            found.   */
          for (fn = fn ? fn->next : NULL; ; fn = fn->next)
            {
              if (fn)
@@ -1424,16 +1480,22 @@ static char *
 make_gcov_file_name (const char *input_name, const char *src_name)
 {
   char *cptr;
-  char *name = XNEWVEC (char, strlen (src_name) + strlen (input_name) + 10);
+  char *name;
 
-  name[0] = 0;
-  if (flag_long_names && strcmp (src_name, input_name))
+  if (flag_long_names && input_name && strcmp (src_name, input_name))
     {
+      name = XNEWVEC (char, strlen (src_name) + strlen (input_name) + 10);
+      name[0] = 0;
       /* Generate the input filename part.  */
       cptr = flag_preserve_paths ? NULL : strrchr (input_name, '/');
       strcat (name, cptr ? cptr + 1 : input_name);
       strcat (name, "##");
     }
+  else
+    {
+      name = XNEWVEC (char, strlen (src_name) + 10);
+      name[0] = 0;
+    }
 
   /* Generate the source filename part.  */
   cptr = flag_preserve_paths ? NULL : strrchr (src_name, '/');
@@ -1787,11 +1849,14 @@ output_lines (FILE *gcov_file, const source_t *src)
   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);
-  fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
-          no_data_file ? "-" : da_file_name);
-  fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
-          object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
+  if (!multiple_files)
+    {
+      fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
+      fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
+              no_data_file ? "-" : da_file_name);
+      fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
+              object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
+    }
   fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
 
   source_file = fopen (src->name, "r");
@@ -1800,19 +1865,8 @@ output_lines (FILE *gcov_file, const source_t *src)
       fnotice (stderr, "%s:cannot open source file\n", src->name);
       retval = NULL;
     }
-  else
-    {
-      struct stat status;
-
-      if (!fstat (fileno (source_file), &status)
-         && status.st_mtime > bbg_file_time)
-       {
-         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);
-       }
-    }
+  else if (src->file_time == 0)
+    fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0);
 
   if (flag_branches)
     fn = src->functions;