* Makefile.in (LIB2FUNCS_ST): Remove _gcov.
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 27 Jan 2003 23:22:17 +0000 (23:22 +0000)
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 27 Jan 2003 23:22:17 +0000 (23:22 +0000)
(LIBGCOV): New variable.
(libgcc.mk): Add LIBGCOV.
(LIBGCC_DEPS): Add libgcov.c.
(libgcov.a): New target.
(clean): Remove libgcov.a.
(install-libgcc): Do libgcov too.
(stage1-start, stage2-start, stage3-start, stage4-start): Deal
with libgcov.a.
* libgcc2.c (L_gcov): Move into ...
* libgcov.c: ... here. New file.
* mklibgcc.in: Add libgcov rules.
* gcc.c (LINK_COMMAND_SPEC): Add -lgcov when profiling.

* doc/invoke.texi (profile-arcs, test-coverage): Update and
clarify.

* profile.c (index_counts_file): Remove duplicate check for open file.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@61905 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/Makefile.in
gcc/doc/invoke.texi
gcc/gcc.c
gcc/libgcc2.c
gcc/libgcov.c [new file with mode: 0644]
gcc/mklibgcc.in
gcc/profile.c

index 0d7452e..bb0804f 100644 (file)
@@ -1,3 +1,24 @@
+2003-01-27  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * Makefile.in (LIB2FUNCS_ST): Remove _gcov.
+       (LIBGCOV): New variable.
+       (libgcc.mk): Add LIBGCOV.
+       (LIBGCC_DEPS): Add libgcov.c.
+       (libgcov.a): New target.
+       (clean): Remove libgcov.a.
+       (install-libgcc): Do libgcov too.
+       (stage1-start, stage2-start, stage3-start, stage4-start): Deal
+       with libgcov.a.
+       * libgcc2.c (L_gcov): Move into ...
+       * libgcov.c: ... here. New file.
+       * mklibgcc.in: Add libgcov rules.
+       * gcc.c (LINK_COMMAND_SPEC): Add -lgcov when profiling.
+
+       * doc/invoke.texi (profile-arcs, test-coverage): Update and
+       clarify.
+       
+       * profile.c (index_counts_file): Remove duplicate check for open file.
+
 2003-01-27  Jerry Quinn  <jlquinn@optonline.net>
 
        * gcc/doc/invoke.texi (Optimization Options): Group together
index 572378e..4cb7de2 100644 (file)
@@ -825,7 +825,10 @@ LIB2FUNCS_2 = _floatdixf _fixunsxfsi _fixtfdi _fixunstfdi _floatditf \
     _addvdi3 _subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors
 
 # Defined in libgcc2.c, included only in the static library.
-LIB2FUNCS_ST = _eprintf _gcov __gcc_bcmp
+LIB2FUNCS_ST = _eprintf __gcc_bcmp
+
+# Defined in libgcov.c, included only in gcov library
+LIBGCOV = _gcov
 
 FPBIT_FUNCS = _pack_sf _unpack_sf _addsub_sf _mul_sf _div_sf \
     _fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \
@@ -1054,6 +1057,7 @@ libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) $(LIB2ADD_ST) xgcc$(exeext
        LIB2FUNCS_1='$(LIB2FUNCS_1)' \
        LIB2FUNCS_2='$(LIB2FUNCS_2)' \
        LIB2FUNCS_ST='$(LIB2FUNCS_ST)' \
+       LIBGCOV='$(LIBGCOV)' \
        LIB2ADD='$(LIB2ADD)' \
        LIB2ADD_ST='$(LIB2ADD_ST)' \
        LIB2ADDEH='$(LIB2ADDEH)' \
@@ -1082,12 +1086,14 @@ libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) $(LIB2ADD_ST) xgcc$(exeext
 
 # All the things that might cause us to want to recompile bits of libgcc.
 LIBGCC_DEPS = $(GCC_PASSES) $(LANGUAGES) stmp-int-hdrs $(STMP_FIXPROTO) \
-       libgcc.mk $(srcdir)/libgcc2.c $(TCONFIG_H) \
+       libgcc.mk $(srcdir)/libgcc2.c $(srcdir)/libgcov.c $(TCONFIG_H) \
        $(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs \
        tsystem.h $(FPBIT) $(DPBIT) $(TPBIT) $(LIB2ADD) \
        $(LIB2ADD_ST) $(LIB2ADDEH) $(LIB2ADDEHDEP) $(EXTRA_PARTS) \
        $(srcdir)/config/$(LIB1ASMSRC)
 
+libgcov.a: libgcc.a; @true
+
 libgcc.a: $(LIBGCC_DEPS)
        $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
          BUILD_PREFIX="$(BUILD_PREFIX)" BUILD_PREFIX_1="$(BUILD_PREFIX_1)" \
@@ -2728,7 +2734,8 @@ mostlyclean: $(INTL_MOSTLYCLEAN) lang.mostlyclean
 # that don't exist in the distribution.
 INTL_CLEAN = intl.clean
 clean: mostlyclean $(INTL_CLEAN) lang.clean
-       -rm -f libgcc.a libgcc_eh.a libgcc_s$(SHLIB_EXT) libgcc_s$(SHLIB_EXT).1
+       -rm -f libgcc.a libgcc_eh.a libgcov.a
+       -rm -f libgcc_s$(SHLIB_EXT) libgcc_s$(SHLIB_EXT).1
        -rm -f config.h tconfig.h bconfig.h tm_p.h tm.h
        -rm -f cs-*
        -rm -rf libgcc
@@ -2984,7 +2991,7 @@ install-man: installdirs $(GENERATED_MANPAGES) lang.install-man
        -chmod a-x $(DESTDIR)$(man7dir)/gpl$(man7ext)
 
 # Install the library.
-install-libgcc: libgcc.mk libgcc.a installdirs
+install-libgcc: libgcc.mk libgcc.a libgcov.a installdirs
        $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
          BUILD_PREFIX="$(BUILD_PREFIX)" BUILD_PREFIX_1="$(BUILD_PREFIX_1)" \
          AR_FOR_TARGET="$(AR_FOR_TARGET)" \
@@ -3004,7 +3011,7 @@ install-libgcc: libgcc.mk libgcc.a installdirs
          slibdir="$(slibdir)" \
          -f libgcc.mk install
 
-# Install multiple versions of libgcc.a.
+# Install multiple versions of libgcc.a, libgcov.a.
 install-multilib: stmp-multilib installdirs
        $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
          BUILD_PREFIX="$(BUILD_PREFIX)" BUILD_PREFIX_1="$(BUILD_PREFIX_1)" \
@@ -3611,9 +3618,11 @@ stage1-start:
        -if [ -f as$(exeext) ] ; then (cd stage1 && $(LN_S) ../as$(exeext) .) ; else true ; fi
        -if [ -f ld$(exeext) ] ; then (cd stage1 && $(LN_S) ../ld$(exeext) .) ; else true ; fi
        -if [ -f collect-ld$(exeext) ] ; then (cd stage1 && $(LN_S) ../collect-ld$(exeext) .) ; else true ; fi
-       -rm -f stage1/libgcc.a stage1/libgcc_eh.a
+       -rm -f stage1/libgcc.a stage1/libgcc_eh.a stage1/libgcov.a
        -cp libgcc.a stage1
        -$(RANLIB_FOR_TARGET) stage1/libgcc.a
+       -cp libgcov.a stage1
+       -$(RANLIB_FOR_TARGET) stage1/libgcov.a
        -if [ -f libgcc_eh.a ] ; then cp libgcc_eh.a stage1; \
           $(RANLIB_FOR_TARGET) stage1/libgcc_eh.a; \
        fi
@@ -3641,9 +3650,11 @@ stage2-start:
        -if [ -f as$(exeext) ] ; then (cd stage2 && $(LN_S) ../as$(exeext) .) ; else true ; fi
        -if [ -f ld$(exeext) ] ; then (cd stage2 && $(LN_S) ../ld$(exeext) .) ; else true ; fi
        -if [ -f collect-ld$(exeext) ] ; then (cd stage2 && $(LN_S) ../collect-ld$(exeext) .) ; else true ; fi
-       -rm -f stage2/libgcc.a stage2/libgcc_eh.a
+       -rm -f stage2/libgcc.a stage2/libgcov.a stage2/libgcc_eh.a
        -cp libgcc.a stage2
        -$(RANLIB_FOR_TARGET) stage2/libgcc.a
+       -cp libgcov.a stage2
+       -$(RANLIB_FOR_TARGET) stage2/libgcov.a
        -if [ -f libgcc_eh.a ] ; then cp libgcc_eh.a stage2; \
           $(RANLIB_FOR_TARGET) stage2/libgcc_eh.a; \
        fi
@@ -3667,9 +3678,11 @@ stage3-start:
        -if [ -f as$(exeext) ] ; then (cd stage3 && $(LN_S) ../as$(exeext) .) ; else true ; fi
        -if [ -f ld$(exeext) ] ; then (cd stage3 && $(LN_S) ../ld$(exeext) .) ; else true ; fi
        -if [ -f collect-ld$(exeext) ] ; then (cd stage3 && $(LN_S) ../collect-ld$(exeext) .) ; else true ; fi
-       -rm -f stage3/libgcc.a stage3/libgcc_eh.a
+       -rm -f stage3/libgcc.a stage3/libgcov.a stage3/libgcc_eh.a
        -cp libgcc.a stage3
        -$(RANLIB_FOR_TARGET) stage3/libgcc.a
+       -cp libgcov.a stage3
+       -$(RANLIB_FOR_TARGET) stage3/libgcov.a
        -if [ -f libgcc_eh.a ] ; then cp libgcc_eh.a stage3; \
           $(RANLIB_FOR_TARGET) stage3/libgcc_eh.a; \
        fi
@@ -3693,9 +3706,11 @@ stage4-start:
        -if [ -f as$(exeext) ] ; then (cd stage4 && $(LN_S) ../as$(exeext) .) ; else true ; fi
        -if [ -f ld$(exeext) ] ; then (cd stage4 && $(LN_S) ../ld$(exeext) .) ; else true ; fi
        -if [ -f collect-ld$(exeext) ] ; then (cd stage4 && $(LN_S) ../collect-ld$(exeext) .) ; else true ; fi
-       -rm -f stage4/libgcc.a stage4/libgcc_eh.a
+       -rm -f stage4/libgcc.a stage4/libgcov.a stage4/libgcc_eh.a
        -cp libgcc.a stage4
        -$(RANLIB_FOR_TARGET) stage4/libgcc.a
+       -cp libgcov.a stage4
+       -$(RANLIB_FOR_TARGET) stage4/libgcov.a
        -if [ -f libgcc_eh.a ] ; then cp libgcc_eh.a stage4; \
           $(RANLIB_FOR_TARGET) stage4/libgcc_eh.a; \
        fi
index f8a0396..e4c39c5 100644 (file)
@@ -3035,27 +3035,46 @@ allocation when it finishes.
 
 @item -fprofile-arcs
 @opindex fprofile-arcs
-Instrument @dfn{arcs} during compilation to generate coverage data or
-for profile-directed block ordering.  During execution the program
-records how many times each branch is executed and how many times it is
-taken.  When the compiled program exits it saves this data to a file
-called @file{@var{auxname}.da} for each source file.  @var{auxname} is
-generated from the name of the output file, if explicitly specified and
-it is not the final executable, otherwise it is the basename of the
-source file. In both cases any suffix is removed (e.g.  @file{foo.da}
-for input file @file{dir/foo.c}, or @file{dir/foo.da} for output file
-specified as @option{-o dir/foo.o}).
-
-For profile-directed block ordering, compile the program with
-@option{-fprofile-arcs} plus optimization and code generation options,
-generate the arc profile information by running the program on a
-selected workload, and then compile the program again with the same
-optimization and code generation options plus
+Add code so that program flow @dfn{arcs} are instrumented.  During
+execution the program records how many times each branch and call is
+executed and how many times it is taken or returns.  When the compiled
+program exits it saves this data to a file called
+@file{@var{auxname}.da} for each source file. The data may be used for
+profile-directed optimizations (@option{-fbranch-probabilities}), or for
+test coverage analysis (@option{-ftest-coverage}). Each object file's
+@var{auxname} is generated from the name of the output file, if
+explicitly specified and it is not the final executable, otherwise it is
+the basename of the source file. In both cases any suffix is removed
+(e.g.  @file{foo.da} for input file @file{dir/foo.c}, or
+@file{dir/foo.da} for output file specified as @option{-o dir/foo.o}).
+
+@itemize
+
+@item
+Compile the source files with @option{-fprofile-arcs} plus optimization
+and code generation options. For test coverage analysis, use the
+additional @option{-ftest-coverage} option. You do not need to profile
+every source file in a program.
+
+@item
+Link your object files as normal.
+
+@item
+Run the program on a representative workload to generate the arc profile
+information. This may be repeated any number of times.
+
+@item
+For profile-directed optimizations, compile the source files again with
+the same optimization and code generation options plus
 @option{-fbranch-probabilities} (@pxref{Optimize Options,,Options that
 Control Optimization}).
 
-The other use of @option{-fprofile-arcs} is for use with @command{gcov},
-when it is used with the @option{-ftest-coverage} option.
+@item
+For test coverage analysis, use @command{gcov} to produce human readable
+information from the @file{.bbg} and @file{.da} files. Refer to the
+@command{gcov} documentation for further information.
+
+@end itemize
 
 With @option{-fprofile-arcs}, for each function of your program GCC
 creates a program flow graph, then finds a spanning tree for the graph.
@@ -3068,34 +3087,13 @@ block must be created to hold the instrumentation code.
 @need 2000
 @item -ftest-coverage
 @opindex ftest-coverage
-Create data files for the @command{gcov} code-coverage utility
-(@pxref{Gcov,, @command{gcov}---a Test Coverage Program}).  See
-@option{-fprofile-arcs} option above for a description of @var{auxname}.
-
-@table @gcctabopt
-@item @var{auxname}.bb
-A mapping from basic blocks to line numbers, which @command{gcov} uses to
-associate basic block execution counts with line numbers.
-
-@item @var{auxname}.bbg
-A list of all arcs in the program flow graph.  This allows @command{gcov}
-to reconstruct the program flow graph, so that it can compute all basic
-block and arc execution counts from the information in the
-@file{@var{auxname}.da} file.
-@end table
-
-Use @option{-ftest-coverage} with @option{-fprofile-arcs}; the latter
-option adds instrumentation to the program, which then writes
-execution counts to another data file:
-
-@table @gcctabopt
-@item @var{auxname}.da
-Runtime arc execution counts, used in conjunction with the arc
-information in the file @file{@var{auxname}.bbg}.
-@end table
-
-Coverage data will map better to the source files if
-@option{-ftest-coverage} is used without optimization.
+Produce a graph file that the @command{gcov} code-coverage utility
+(@pxref{Gcov,, @command{gcov}---a Test Coverage Program}) can use to
+show program coverage. Each source file's data file is called
+@file{@var{auxname}.bbg}. Refer to the @option{-fprofile-arcs} option
+above for a description of @var{auxname} and instructions on how to
+generate test coverage data. Coverage data will match the source files
+more closely, if you do not optimize.
 
 @item -d@var{letters}
 @opindex d
index ca3a513..3a36d35 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -676,7 +676,8 @@ proper position among the other output files.  */
 %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
     %(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t}\
     %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
-    %{static:} %{L*} %(link_libgcc) %o %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}}\
+    %{static:} %{L*} %(link_libgcc) %o %{fprofile-arcs:-lgcov}\
+    %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}}\
     %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
 #endif
 
index a47dfd1..deb772f 100644 (file)
@@ -1235,445 +1235,6 @@ __eprintf (const char *string, const char *expression,
 #endif
 #endif
 
-#ifdef L_gcov
-
-/* Gcov profile dumper. Requires atexit and stdio.  */
-
-#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
-#include <stdio.h>
-
-#include "gcov-io.h"
-#include <string.h>
-#if defined (TARGET_HAS_F_SETLKW)
-#include <fcntl.h>
-#include <errno.h>
-#endif
-
-/* Chain of per-object gcov structures.  */
-static struct gcov_info *gcov_list;
-
-/* A program checksum allows us to distinguish program data for an
-   object file included in multiple programs.  */
-static unsigned gcov_crc32;
-
-static void
-gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
-{
-  unsigned expected = GCOV_VERSION;
-  unsigned ix;
-  char e[4], v[4];
-
-  for (ix = 4; ix--; expected >>= 8, version >>= 8)
-    {
-      e[ix] = expected;
-      v[ix] = version;
-    }
-  
-  fprintf (stderr,
-          "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
-          ptr->filename, e, v);
-}
-
-/* Dump the coverage counts. We merge with existing counts when
-   possible, to avoid growing the .da files ad infinitum. We use this
-   program's checksum to make sure we only accumulate whole program
-   statistics to the correct summary. An object file might be embedded
-   in two separate programs, and we must keep the two program
-   summaries separate.  */
-
-static void
-gcov_exit (void)
-{
-  struct gcov_info *ptr;
-  unsigned ix, jx;
-  struct gcov_summary program;
-  gcov_type program_max_one = 0;
-  gcov_type program_max_sum = 0;
-  gcov_type program_sum = 0;
-  unsigned program_arcs = 0;
-  
-#if defined (TARGET_HAS_F_SETLKW)
-  struct flock s_flock;
-
-  s_flock.l_type = F_WRLCK;
-  s_flock.l_whence = SEEK_SET;
-  s_flock.l_start = 0;
-  s_flock.l_len = 0; /* Until EOF.  */
-  s_flock.l_pid = getpid ();
-#endif
-
-  memset (&program, 0, sizeof (program));
-  program.checksum = gcov_crc32;
-  
-  for (ptr = gcov_list; ptr; ptr = ptr->next)
-    {
-      FILE *da_file;
-      struct gcov_summary object;
-      struct gcov_summary local_prg;
-      int merging = 0;
-      long base;
-      const struct function_info *fn_info;
-      gcov_type *count_ptr;
-      gcov_type object_max_one = 0;
-
-      ptr->wkspc = 0;
-      if (!ptr->filename)
-       continue;
-
-      for (ix = ptr->n_arc_counts, count_ptr = ptr->arc_counts; ix--;)
-       {
-         gcov_type count = *count_ptr++;
-
-         if (count > object_max_one)
-           object_max_one = count;
-       }
-      if (object_max_one > program_max_one)
-       program_max_one = object_max_one;
-      
-      memset (&local_prg, 0, sizeof (local_prg));
-      memset (&object, 0, sizeof (object));
-      
-      /* Open for modification */
-      if ((da_file = fopen (ptr->filename, "r+b")))
-       merging = 1;
-      else if ((da_file = fopen (ptr->filename, "w+b")))
-       ;
-      else
-       {
-         fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
-         ptr->filename = 0;
-         continue;
-       }
-
-#if defined (TARGET_HAS_F_SETLKW)
-      /* After a fork, another process might try to read and/or write
-         the same file simultaneously.  So if we can, lock the file to
-         avoid race conditions.  */
-      while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
-            && errno == EINTR)
-       continue;
-#endif
-      if (merging)
-       {
-         /* Merge data from file.  */
-         unsigned tag, length;
-             
-         if (gcov_read_unsigned (da_file, &tag) || tag != GCOV_DATA_MAGIC)
-           {
-             fprintf (stderr, "profiling:%s:Not a gcov data file\n",
-                      ptr->filename);
-           read_fatal:;
-             fclose (da_file);
-             ptr->filename = 0;
-             continue;
-           }
-         if (gcov_read_unsigned (da_file, &length) || length != GCOV_VERSION)
-           {
-             gcov_version_mismatch (ptr, length);
-             goto read_fatal;
-           }
-         
-         /* Merge execution counts for each function.  */
-         count_ptr = ptr->arc_counts;
-         for (ix = ptr->n_functions, fn_info = ptr->functions;
-              ix--; fn_info++)
-           {
-             if (gcov_read_unsigned (da_file, &tag)
-                 || gcov_read_unsigned (da_file, &length))
-               {
-               read_error:;
-                 fprintf (stderr, "profiling:%s:Error merging\n",
-                          ptr->filename);
-                 goto read_fatal;
-               }
-
-             /* Check function */
-             if (tag != GCOV_TAG_FUNCTION)
-               {
-               read_mismatch:;
-                 fprintf (stderr, "profiling:%s:Merge mismatch at %s\n",
-                          ptr->filename, fn_info->name);
-                 goto read_fatal;
-               }
-             {
-               unsigned flength, checksum;
-               
-               if (gcov_read_unsigned (da_file, &flength)
-                   || gcov_skip_string (da_file, flength)
-                   || gcov_read_unsigned (da_file, &checksum))
-                 goto read_error;
-               if (flength != strlen (fn_info->name)
-                   || checksum != fn_info->checksum)
-                 goto read_mismatch;
-             }
-             /* Check arc counts */
-             if (gcov_read_unsigned (da_file, &tag)
-                 || gcov_read_unsigned (da_file, &length))
-               goto read_error;
-             if (tag != GCOV_TAG_ARC_COUNTS
-                 || length / 8 != fn_info->n_arc_counts)
-               goto read_mismatch;
-             {
-               gcov_type count;
-               
-               for (jx = fn_info->n_arc_counts; jx--; count_ptr++)
-                 if (gcov_read_counter (da_file, &count))
-                   goto read_error;
-                 else
-                   *count_ptr += count;
-             }
-           }
-
-         /* Check object summary */
-         if (gcov_read_unsigned (da_file, &tag)
-             || gcov_read_unsigned (da_file, &length))
-           goto read_error;
-         if (tag != GCOV_TAG_OBJECT_SUMMARY)
-           goto read_mismatch;
-         if (gcov_read_summary (da_file, &object))
-           goto read_error;
-
-         /* Check program summary */
-         while (1)
-           {
-             long base = ftell (da_file);
-             
-             if (gcov_read_unsigned (da_file, &tag)
-                 || gcov_read_unsigned (da_file, &length))
-               {
-                 if (feof (da_file))
-                   break;
-                 goto read_error;
-               }
-             if (tag != GCOV_TAG_PROGRAM_SUMMARY
-                 && tag != GCOV_TAG_PLACEHOLDER_SUMMARY
-                 && tag != GCOV_TAG_INCORRECT_SUMMARY)
-               goto read_mismatch;
-             if (gcov_read_summary (da_file, &local_prg))
-               goto read_error;
-             if (local_prg.checksum != program.checksum)
-               continue;
-             if (tag == GCOV_TAG_PLACEHOLDER_SUMMARY)
-               {
-                 fprintf (stderr,
-                          "profiling:%s:Concurrent race detected\n",
-                          ptr->filename);
-                 goto read_fatal;
-               }
-             merging = -1;
-             if (tag != GCOV_TAG_PROGRAM_SUMMARY)
-               break;
-             
-             if (program.runs
-                 && memcmp (&program, &local_prg, sizeof (program)))
-               {
-                 fprintf (stderr, "profiling:%s:Invocation mismatch\n",
-                          ptr->filename);
-                 local_prg.runs = 0;
-               }
-             else
-               memcpy (&program, &local_prg, sizeof (program));
-             ptr->wkspc = base;
-             break;
-           }
-         fseek (da_file, 0, SEEK_SET);
-       }
-
-      object.runs++;
-      object.arcs = ptr->n_arc_counts;
-      object.arc_sum = 0;
-      if (object.arc_max_one < object_max_one)
-       object.arc_max_one = object_max_one;
-      object.arc_sum_max += object_max_one;
-      
-      /* Write out the data.  */
-      if (/* magic */
-         gcov_write_unsigned (da_file, GCOV_DATA_MAGIC)
-         /* version number */
-         || gcov_write_unsigned (da_file, GCOV_VERSION))
-       {
-       write_error:;
-         fclose (da_file);
-         fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
-         ptr->filename = 0;
-         continue;
-       }
-      
-      /* Write execution counts for each function.  */
-      count_ptr = ptr->arc_counts;
-      for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
-       {
-         /* Announce function.  */
-         if (gcov_write_unsigned (da_file, GCOV_TAG_FUNCTION)
-             || !(base = gcov_reserve_length (da_file))
-             /* function name */
-             || gcov_write_string (da_file, fn_info->name,
-                                   strlen (fn_info->name))
-             /* function checksum */
-             || gcov_write_unsigned (da_file, fn_info->checksum)
-             || gcov_write_length (da_file, base))
-           goto write_error;
-         
-         /* arc counts.  */
-         if (gcov_write_unsigned (da_file, GCOV_TAG_ARC_COUNTS)
-             || !(base = gcov_reserve_length (da_file)))
-           goto write_error;
-         
-         for (jx = fn_info->n_arc_counts; jx--;)
-           {
-             gcov_type count = *count_ptr++;
-             
-             object.arc_sum += count;
-             if (object.arc_max_sum < count)
-               object.arc_max_sum = count;
-             if (gcov_write_counter (da_file, count))
-               goto write_error; /* RIP Edsger Dijkstra */
-           }
-         if (gcov_write_length (da_file, base))
-           goto write_error;
-       }
-
-      /* Object file summary.  */
-      if (gcov_write_summary (da_file, GCOV_TAG_OBJECT_SUMMARY, &object))
-       goto write_error;
-
-      if (merging >= 0)
-       {
-         if (fseek (da_file, 0, SEEK_END))
-           goto write_error;
-         ptr->wkspc = ftell (da_file);
-         if (gcov_write_summary (da_file, GCOV_TAG_PLACEHOLDER_SUMMARY,
-                                 &program))
-           goto write_error;
-       }
-      else if (ptr->wkspc)
-       {
-         /* Zap trailing program summary */
-         if (fseek (da_file, ptr->wkspc, SEEK_SET))
-           goto write_error;
-         if (!local_prg.runs)
-           ptr->wkspc = 0;
-         if (gcov_write_unsigned (da_file,
-                            local_prg.runs ? GCOV_TAG_PLACEHOLDER_SUMMARY
-                            : GCOV_TAG_INCORRECT_SUMMARY))
-           goto write_error;
-       }
-      if (fflush (da_file))
-       goto write_error;
-
-      if (fclose (da_file))
-       {
-         fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
-         ptr->filename = 0;
-       }
-      else
-       {
-         program_arcs += ptr->n_arc_counts;
-         program_sum += object.arc_sum;
-         if (program_max_sum < object.arc_max_sum)
-           program_max_sum = object.arc_max_sum;
-       }
-    }
-
-  /* Generate whole program statistics.  */
-  program.runs++;
-  program.arcs = program_arcs;
-  program.arc_sum = program_sum;
-  if (program.arc_max_one < program_max_one)
-    program.arc_max_one = program_max_one;
-  if (program.arc_max_sum < program_max_sum)
-    program.arc_max_sum = program_max_sum;
-  program.arc_sum_max += program_max_one;
-  
-  /* Upate whole program statistics.  */
-  for (ptr = gcov_list; ptr; ptr = ptr->next)
-    if (ptr->filename && ptr->wkspc)
-      {
-       FILE *da_file;
-       
-       da_file = fopen (ptr->filename, "r+b");
-       if (!da_file)
-         {
-           fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
-           continue;
-         }
-       
-#if defined (TARGET_HAS_F_SETLKW)
-       while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
-              && errno == EINTR)
-         continue;
-#endif
-       if (fseek (da_file, ptr->wkspc, SEEK_SET)
-           || gcov_write_summary (da_file, GCOV_TAG_PROGRAM_SUMMARY, &program)
-           || fflush (da_file))
-         fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
-       if (fclose (da_file))
-         fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
-      }
-}
-
-/* Add a new object file onto the bb chain.  Invoked automatically
-   when running an object file's global ctors.  */
-
-void
-__gcov_init (struct gcov_info *info)
-{
-  if (!info->version)
-    return;
-  if (info->version != GCOV_VERSION)
-    gcov_version_mismatch (info, info->version);
-  else
-    {
-      const char *ptr = info->filename;
-      unsigned crc32 = gcov_crc32;
-  
-      do
-       {
-         unsigned ix;
-         unsigned value = *ptr << 24;
-
-         for (ix = 8; ix--; value <<= 1)
-           {
-             unsigned feedback;
-
-             feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
-             crc32 <<= 1;
-             crc32 ^= feedback;
-           }
-       }
-      while (*ptr++);
-      
-      gcov_crc32 = crc32;
-      
-      if (!gcov_list)
-       atexit (gcov_exit);
-      
-      info->next = gcov_list;
-      gcov_list = info;
-    }
-  info->version = 0;
-}
-
-/* Called before fork or exec - write out profile information gathered so
-   far and reset it to zero.  This avoids duplication or loss of the
-   profile information gathered so far.  */
-
-void
-__gcov_flush (void)
-{
-  struct gcov_info *ptr;
-
-  gcov_exit ();
-  for (ptr = gcov_list; ptr; ptr = ptr->next)
-    {
-      unsigned i;
-      
-      for (i = ptr->n_arc_counts; i--;)
-       ptr->arc_counts[i] = 0;
-    }
-}
-
-#endif /* L_gcov */
 \f
 #ifdef L_clear_cache
 /* Clear part of an instruction cache.  */
diff --git a/gcc/libgcov.c b/gcc/libgcov.c
new file mode 100644 (file)
index 0000000..57bfb26
--- /dev/null
@@ -0,0 +1,473 @@
+/* Routines required for instrumenting a program.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003  Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* It is incorrect to include config.h here, because this file is being
+   compiled for the target, and hence definitions concerning only the host
+   do not apply.  */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+
+#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
+#include <stdio.h>
+
+#include "gcov-io.h"
+#include <string.h>
+#if defined (TARGET_HAS_F_SETLKW)
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+/* Chain of per-object gcov structures.  */
+static struct gcov_info *gcov_list;
+
+/* A program checksum allows us to distinguish program data for an
+   object file included in multiple programs.  */
+static unsigned gcov_crc32;
+
+static void
+gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
+{
+  unsigned expected = GCOV_VERSION;
+  unsigned ix;
+  char e[4], v[4];
+
+  for (ix = 4; ix--; expected >>= 8, version >>= 8)
+    {
+      e[ix] = expected;
+      v[ix] = version;
+    }
+  
+  fprintf (stderr,
+          "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
+          ptr->filename, e, v);
+}
+
+/* Dump the coverage counts. We merge with existing counts when
+   possible, to avoid growing the .da files ad infinitum. We use this
+   program's checksum to make sure we only accumulate whole program
+   statistics to the correct summary. An object file might be embedded
+   in two separate programs, and we must keep the two program
+   summaries separate.  */
+
+static void
+gcov_exit (void)
+{
+  struct gcov_info *ptr;
+  unsigned ix, jx;
+  struct gcov_summary program;
+  gcov_type program_max_one = 0;
+  gcov_type program_max_sum = 0;
+  gcov_type program_sum = 0;
+  unsigned program_arcs = 0;
+  
+#if defined (TARGET_HAS_F_SETLKW)
+  struct flock s_flock;
+
+  s_flock.l_type = F_WRLCK;
+  s_flock.l_whence = SEEK_SET;
+  s_flock.l_start = 0;
+  s_flock.l_len = 0; /* Until EOF.  */
+  s_flock.l_pid = getpid ();
+#endif
+
+  memset (&program, 0, sizeof (program));
+  program.checksum = gcov_crc32;
+  
+  for (ptr = gcov_list; ptr; ptr = ptr->next)
+    {
+      FILE *da_file;
+      struct gcov_summary object;
+      struct gcov_summary local_prg;
+      int merging = 0;
+      long base;
+      const struct function_info *fn_info;
+      gcov_type *count_ptr;
+      gcov_type object_max_one = 0;
+
+      ptr->wkspc = 0;
+      if (!ptr->filename)
+       continue;
+
+      for (ix = ptr->n_arc_counts, count_ptr = ptr->arc_counts; ix--;)
+       {
+         gcov_type count = *count_ptr++;
+
+         if (count > object_max_one)
+           object_max_one = count;
+       }
+      if (object_max_one > program_max_one)
+       program_max_one = object_max_one;
+      
+      memset (&local_prg, 0, sizeof (local_prg));
+      memset (&object, 0, sizeof (object));
+      
+      /* Open for modification */
+      if ((da_file = fopen (ptr->filename, "r+b")))
+       merging = 1;
+      else if ((da_file = fopen (ptr->filename, "w+b")))
+       ;
+      else
+       {
+         fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
+         ptr->filename = 0;
+         continue;
+       }
+
+#if defined (TARGET_HAS_F_SETLKW)
+      /* After a fork, another process might try to read and/or write
+         the same file simultaneously.  So if we can, lock the file to
+         avoid race conditions.  */
+      while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
+            && errno == EINTR)
+       continue;
+#endif
+      if (merging)
+       {
+         /* Merge data from file.  */
+         unsigned tag, length;
+             
+         if (gcov_read_unsigned (da_file, &tag) || tag != GCOV_DATA_MAGIC)
+           {
+             fprintf (stderr, "profiling:%s:Not a gcov data file\n",
+                      ptr->filename);
+           read_fatal:;
+             fclose (da_file);
+             ptr->filename = 0;
+             continue;
+           }
+         if (gcov_read_unsigned (da_file, &length) || length != GCOV_VERSION)
+           {
+             gcov_version_mismatch (ptr, length);
+             goto read_fatal;
+           }
+         
+         /* Merge execution counts for each function.  */
+         count_ptr = ptr->arc_counts;
+         for (ix = ptr->n_functions, fn_info = ptr->functions;
+              ix--; fn_info++)
+           {
+             if (gcov_read_unsigned (da_file, &tag)
+                 || gcov_read_unsigned (da_file, &length))
+               {
+               read_error:;
+                 fprintf (stderr, "profiling:%s:Error merging\n",
+                          ptr->filename);
+                 goto read_fatal;
+               }
+
+             /* Check function */
+             if (tag != GCOV_TAG_FUNCTION)
+               {
+               read_mismatch:;
+                 fprintf (stderr, "profiling:%s:Merge mismatch at %s\n",
+                          ptr->filename, fn_info->name);
+                 goto read_fatal;
+               }
+             {
+               unsigned flength, checksum;
+               
+               if (gcov_read_unsigned (da_file, &flength)
+                   || gcov_skip_string (da_file, flength)
+                   || gcov_read_unsigned (da_file, &checksum))
+                 goto read_error;
+               if (flength != strlen (fn_info->name)
+                   || checksum != fn_info->checksum)
+                 goto read_mismatch;
+             }
+             /* Check arc counts */
+             if (gcov_read_unsigned (da_file, &tag)
+                 || gcov_read_unsigned (da_file, &length))
+               goto read_error;
+             if (tag != GCOV_TAG_ARC_COUNTS
+                 || length / 8 != fn_info->n_arc_counts)
+               goto read_mismatch;
+             {
+               gcov_type count;
+               
+               for (jx = fn_info->n_arc_counts; jx--; count_ptr++)
+                 if (gcov_read_counter (da_file, &count))
+                   goto read_error;
+                 else
+                   *count_ptr += count;
+             }
+           }
+
+         /* Check object summary */
+         if (gcov_read_unsigned (da_file, &tag)
+             || gcov_read_unsigned (da_file, &length))
+           goto read_error;
+         if (tag != GCOV_TAG_OBJECT_SUMMARY)
+           goto read_mismatch;
+         if (gcov_read_summary (da_file, &object))
+           goto read_error;
+
+         /* Check program summary */
+         while (1)
+           {
+             long base = ftell (da_file);
+             
+             if (gcov_read_unsigned (da_file, &tag)
+                 || gcov_read_unsigned (da_file, &length))
+               {
+                 if (feof (da_file))
+                   break;
+                 goto read_error;
+               }
+             if (tag != GCOV_TAG_PROGRAM_SUMMARY
+                 && tag != GCOV_TAG_PLACEHOLDER_SUMMARY
+                 && tag != GCOV_TAG_INCORRECT_SUMMARY)
+               goto read_mismatch;
+             if (gcov_read_summary (da_file, &local_prg))
+               goto read_error;
+             if (local_prg.checksum != program.checksum)
+               continue;
+             if (tag == GCOV_TAG_PLACEHOLDER_SUMMARY)
+               {
+                 fprintf (stderr,
+                          "profiling:%s:Concurrent race detected\n",
+                          ptr->filename);
+                 goto read_fatal;
+               }
+             merging = -1;
+             if (tag != GCOV_TAG_PROGRAM_SUMMARY)
+               break;
+             
+             if (program.runs
+                 && memcmp (&program, &local_prg, sizeof (program)))
+               {
+                 fprintf (stderr, "profiling:%s:Invocation mismatch\n",
+                          ptr->filename);
+                 local_prg.runs = 0;
+               }
+             else
+               memcpy (&program, &local_prg, sizeof (program));
+             ptr->wkspc = base;
+             break;
+           }
+         fseek (da_file, 0, SEEK_SET);
+       }
+
+      object.runs++;
+      object.arcs = ptr->n_arc_counts;
+      object.arc_sum = 0;
+      if (object.arc_max_one < object_max_one)
+       object.arc_max_one = object_max_one;
+      object.arc_sum_max += object_max_one;
+      
+      /* Write out the data.  */
+      if (/* magic */
+         gcov_write_unsigned (da_file, GCOV_DATA_MAGIC)
+         /* version number */
+         || gcov_write_unsigned (da_file, GCOV_VERSION))
+       {
+       write_error:;
+         fclose (da_file);
+         fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
+         ptr->filename = 0;
+         continue;
+       }
+      
+      /* Write execution counts for each function.  */
+      count_ptr = ptr->arc_counts;
+      for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
+       {
+         /* Announce function.  */
+         if (gcov_write_unsigned (da_file, GCOV_TAG_FUNCTION)
+             || !(base = gcov_reserve_length (da_file))
+             /* function name */
+             || gcov_write_string (da_file, fn_info->name,
+                                   strlen (fn_info->name))
+             /* function checksum */
+             || gcov_write_unsigned (da_file, fn_info->checksum)
+             || gcov_write_length (da_file, base))
+           goto write_error;
+         
+         /* arc counts.  */
+         if (gcov_write_unsigned (da_file, GCOV_TAG_ARC_COUNTS)
+             || !(base = gcov_reserve_length (da_file)))
+           goto write_error;
+         
+         for (jx = fn_info->n_arc_counts; jx--;)
+           {
+             gcov_type count = *count_ptr++;
+             
+             object.arc_sum += count;
+             if (object.arc_max_sum < count)
+               object.arc_max_sum = count;
+             if (gcov_write_counter (da_file, count))
+               goto write_error; /* RIP Edsger Dijkstra */
+           }
+         if (gcov_write_length (da_file, base))
+           goto write_error;
+       }
+
+      /* Object file summary.  */
+      if (gcov_write_summary (da_file, GCOV_TAG_OBJECT_SUMMARY, &object))
+       goto write_error;
+
+      if (merging >= 0)
+       {
+         if (fseek (da_file, 0, SEEK_END))
+           goto write_error;
+         ptr->wkspc = ftell (da_file);
+         if (gcov_write_summary (da_file, GCOV_TAG_PLACEHOLDER_SUMMARY,
+                                 &program))
+           goto write_error;
+       }
+      else if (ptr->wkspc)
+       {
+         /* Zap trailing program summary */
+         if (fseek (da_file, ptr->wkspc, SEEK_SET))
+           goto write_error;
+         if (!local_prg.runs)
+           ptr->wkspc = 0;
+         if (gcov_write_unsigned (da_file,
+                            local_prg.runs ? GCOV_TAG_PLACEHOLDER_SUMMARY
+                            : GCOV_TAG_INCORRECT_SUMMARY))
+           goto write_error;
+       }
+      if (fflush (da_file))
+       goto write_error;
+
+      if (fclose (da_file))
+       {
+         fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
+         ptr->filename = 0;
+       }
+      else
+       {
+         program_arcs += ptr->n_arc_counts;
+         program_sum += object.arc_sum;
+         if (program_max_sum < object.arc_max_sum)
+           program_max_sum = object.arc_max_sum;
+       }
+    }
+
+  /* Generate whole program statistics.  */
+  program.runs++;
+  program.arcs = program_arcs;
+  program.arc_sum = program_sum;
+  if (program.arc_max_one < program_max_one)
+    program.arc_max_one = program_max_one;
+  if (program.arc_max_sum < program_max_sum)
+    program.arc_max_sum = program_max_sum;
+  program.arc_sum_max += program_max_one;
+  
+  /* Upate whole program statistics.  */
+  for (ptr = gcov_list; ptr; ptr = ptr->next)
+    if (ptr->filename && ptr->wkspc)
+      {
+       FILE *da_file;
+       
+       da_file = fopen (ptr->filename, "r+b");
+       if (!da_file)
+         {
+           fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
+           continue;
+         }
+       
+#if defined (TARGET_HAS_F_SETLKW)
+       while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
+              && errno == EINTR)
+         continue;
+#endif
+       if (fseek (da_file, ptr->wkspc, SEEK_SET)
+           || gcov_write_summary (da_file, GCOV_TAG_PROGRAM_SUMMARY, &program)
+           || fflush (da_file))
+         fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
+       if (fclose (da_file))
+         fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename);
+      }
+}
+
+/* Add a new object file onto the bb chain.  Invoked automatically
+   when running an object file's global ctors.  */
+
+void
+__gcov_init (struct gcov_info *info)
+{
+  if (!info->version)
+    return;
+  if (info->version != GCOV_VERSION)
+    gcov_version_mismatch (info, info->version);
+  else
+    {
+      const char *ptr = info->filename;
+      unsigned crc32 = gcov_crc32;
+  
+      do
+       {
+         unsigned ix;
+         unsigned value = *ptr << 24;
+
+         for (ix = 8; ix--; value <<= 1)
+           {
+             unsigned feedback;
+
+             feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
+             crc32 <<= 1;
+             crc32 ^= feedback;
+           }
+       }
+      while (*ptr++);
+      
+      gcov_crc32 = crc32;
+      
+      if (!gcov_list)
+       atexit (gcov_exit);
+      
+      info->next = gcov_list;
+      gcov_list = info;
+    }
+  info->version = 0;
+}
+
+/* Called before fork or exec - write out profile information gathered so
+   far and reset it to zero.  This avoids duplication or loss of the
+   profile information gathered so far.  */
+
+void
+__gcov_flush (void)
+{
+  struct gcov_info *ptr;
+
+  gcov_exit ();
+  for (ptr = gcov_list; ptr; ptr = ptr->next)
+    {
+      unsigned i;
+      
+      for (i = ptr->n_arc_counts; i--;)
+       ptr->arc_counts[i] = 0;
+    }
+}
index faa5a69..a18b8dd 100644 (file)
@@ -12,6 +12,7 @@
 # LIB2FUNCS_1
 # LIB2FUNCS_2
 # LIB2FUNCS_ST
+# LIBGCOV
 # LIB2ADD
 # LIB2ADD_ST 
 # LIB2ADDEH
@@ -65,6 +66,9 @@ make_compile='$(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
 # Dependencies for libgcc2.c
 libgcc2_c_dep='stmp-dirs $(srcdir)/libgcc2.c $(CONFIG_H) coretypes.h $(TM_H) $(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs tsystem.h'" $LIB2ADDEHDEP"
 
+# Dependencies for libgcov.c
+libgcov_c_dep='stmp-dirs $(srcdir)/libgcov.c $(CONFIG_H) coretypes.h $(TM_H) $(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs tsystem.h'
+
 # Dependencies for fp-bit.c
 fpbit_c_dep='stmp-dirs config.status tsystem.h'
 
@@ -249,6 +253,25 @@ for file in $LIB2ADD_ST; do
   libgcc2_st_objs="$libgcc2_st_objs ${oname}${objext}"
 done
 
+#
+# build libgcov components
+#
+
+libgcov_objs=""
+
+for name in $LIBGCOV; do
+  for ml in $MULTILIBS; do
+    dir=`echo ${ml} | sed -e 's/;.*$//' -e 's/=/$(EQ)/g'`
+    flags=`echo ${ml} | sed -e 's/^[^;]*;//' -e 's/@/ -/g'`;
+    out="libgcc/${dir}/${name}${objext}"
+
+    echo $out: $libgcov_c_dep
+    echo "     $gcc_compile" '$(MAYBE_USE_COLLECT2)' $flags -DL$name \
+      -c '$(srcdir)/libgcov.c' -o $out
+  done
+  libgcov_objs="$libgcov_objs ${name}${objext}"
+done
+
 # SHLIB_MKMAP
 # SHLIB_MKMAP_OPTS
 # SHLIB_MAPFILES
@@ -275,6 +298,11 @@ for ml in $MULTILIBS; do
     libgcc_st_objs="$libgcc_st_objs libgcc/${dir}/$o"
   done
 
+  libgcov_a_objs=""
+  for o in $libgcov_objs; do
+    libgcov_a_objs="$libgcov_a_objs libgcc/${dir}/$o"
+  done
+  
   if [ "$SHLIB_LINK" -a "$SHLIB_MKMAP" ]; then
     mapfile="libgcc/${dir}/libgcc.map"
     tmpmapfile="libgcc/${dir}/tmp-libgcc.map"
@@ -314,6 +342,12 @@ for ml in $MULTILIBS; do
   echo '       $(AR_CREATE_FOR_TARGET)' ${dir}/libgcc.a $libgcc_a_objs
   echo '       $(RANLIB_FOR_TARGET)' ${dir}/libgcc.a
 
+  echo ""
+  echo "${dir}/libgcov.a: $libgcov_a_objs"
+  echo "       -rm -rf ${dir}/libgcov.a"
+  echo '       $(AR_CREATE_FOR_TARGET)' ${dir}/libgcov.a $libgcov_a_objs
+  echo '       $(RANLIB_FOR_TARGET)' ${dir}/libgcov.a
+
   if [ "$SHLIB_LINK" ]; then
 
     echo ""
@@ -395,7 +429,7 @@ for ml in $MULTILIBS; do
   if [ $dir != . ]; then
     dirs="$dirs ${dir} libgcc/${dir}"
   fi
-  all="$all ${dir}/libgcc.a"
+  all="$all ${dir}/libgcc.a ${dir}/libgcov.a"
   if [ "$SHLIB_LINK" ]; then
     all="$all ${dir}/libgcc_eh.a"
     if [ -z "$SHLIB_MULTILIB" ]; then
@@ -456,6 +490,8 @@ for ml in $MULTILIBS; do
   fi
   echo '       $(INSTALL_DATA)' ${dir}/libgcc.a ${ldir}/
   echo '       $(RANLIB_FOR_TARGET)' ${ldir}/libgcc.a
+  echo '       $(INSTALL_DATA)' ${dir}/libgcov.a ${ldir}/
+  echo '       $(RANLIB_FOR_TARGET)' ${ldir}/libgcov.a
 
   if [ "$SHLIB_LINK" ]; then
     echo '     $(INSTALL_DATA)' ${dir}/libgcc_eh.a ${ldir}/
index 5ee790a..de2d309 100644 (file)
@@ -289,16 +289,12 @@ index_counts_file ()
   unsigned magic, version, ix, checksum;
   long *summary;
 
-  if (!da_file)
-    return 0;
-  counts_file_index = htab_create (10, htab_counts_index_hash, htab_counts_index_eq, htab_counts_index_del);
-
   /* No .da file, no data.  */
   if (!da_file)
     return 0;
+  counts_file_index = htab_create (10, htab_counts_index_hash, htab_counts_index_eq, htab_counts_index_del);
 
   /* Now index all profile sections.  */
-
   rewind (da_file);
 
   summary = NULL;